Skip to content
codyw912Public

About

Project-scoped isolation for coding-agent CLIs

Resources

Stars

2 stars

Watchers

0 watching

Forks

Repository files navigation

Fortlet

Fortlet runs coding-agent CLIs inside project-scoped MicroSandbox capsules while preserving their ordinary terminal experience. The host workspace stays live, provider credentials are brokered rather than mounted, and failure to establish the isolation boundary prevents the agent from starting.

Fortlet is an early Rust prototype. It supports explicit Codex and Tact launches, optional transparent command shims, and project-scoped capsule status, stop, and reset commands.

Quick start

The reproducible Nix package includes the matching MicroSandbox host runtime:

nix run . -- doctor
nix run . -- prepare codex
nix run . -- run codex --
nix run . -- run tact --
nix run . -- list
nix run . -- status
nix run . -- stop codex
nix run . -- reset codex

Fortlet resolves the nearest Jujutsu, Git, or recognized development- environment root and preserves a launch from its subdirectories. A selected home directory or filesystem root uses Fortlet's persistent scratch workspace by default, including when selected with --project. Exposing either broad root requires the separate, deliberate --allow-broad-mount flag.

Nix is the current reproducible alpha installation path, not an intended general-user requirement. Fortlet's release distribution should also provide standalone platform artifacts; Nix remains an optional first-class path for users who prefer it.

For local Rust development:

nix develop
cargo test
cargo clippy --all-targets --all-features -- -D warnings
cargo run -- doctor

For a bounded opt-in command where codex or tact uses Fortlet, execute it through the named shell explicitly:

nix develop .#agents -c codex
nix develop .#agents -c tact

The shell is minimal: it adds fortlet and the package-owned shim directory, but no project toolchain. Plain nix develop remains Fortlet's Rust development shell and does not activate the shims.

Do not wrap every daily command in nix develop path:/path/to/fortlet#agents. An unlocked local path input is snapshotted into the Nix store on each fresh evaluation and is too slow for that loop. For daily project use, compose the two outputs into devenv as shown below so direnv evaluates once and reuses its cached environment. Explicit fortlet run codex -- and fortlet run tact -- remain available without shim activation.

MicroSandbox must be usable on the execution host. Codex authentication is read from a file-backed host ChatGPT login; keyring-backed login, API keys, and other authentication modes are not yet supported. Fortlet renews a near-expiry Codex token with the host refresh token, atomically updates the host login, and rotates the access token through MicroSandbox's credential broker. The guest sees only stable placeholders and an empty refresh field. The credential file itself must remain outside all guest mounts; run codex login on the host when Fortlet reports a permanent refresh failure.

Fortlet-managed Codex 0.147.0 launches disable the built-in Apps connector client because its separate authorization contract is not available inside the capsule. This does not disable user-configured MCP servers or local plugin skills. Connector-backed live Excel control and Sites hosting are unavailable through Fortlet; use native Codex explicitly if either capability is needed.

When stdin or stdout is not a terminal, Fortlet closes harness stdin, streams stdout and stderr without allocating a PTY, and returns the exact guest exit status. Managed Codex commands have a ten-minute inactivity ceiling that renews on output; expiry kills only that command and preserves the reusable capsule. Use interactive managed Codex for work that may legitimately remain silent longer. Tact, interactive sessions, and fortlet native have no such ceiling.

fortlet prepare <harness> is an optional eager warm-up. It ensures the base, selected harness, and optional project-tool layers without reading provider credentials, creating a reusable project capsule or persistent harness home, or attaching a terminal. If it is omitted, fortlet run and the optional shims perform the same preparation automatically on first launch. A successful preparation prints <harness><TAB>ready; a verified cache hit performs no provisioning or network contact.

Project tool environments

A repository opts into project tools with two fixed files at its resolved root: .fortlet/environment.json and .fortlet/environment.sh. The manifest declares layer-relative PATH entries and literal environment variables. The adjacent POSIX recipe installs tools beneath $FORTLET_OUTPUT.

Fortlet reads and hashes both exact files on the host but never executes the recipe there. On first use, it runs the snapshotted recipe in a dedicated MicroSandbox capsule with public network access, no live project mount, no persistent home, and no provider, SSH, signing, publication, or registry credentials. The validated output is content-digested, published atomically, and mounted read-only at /opt/fortlet/project. A repository without the manifest keeps the existing base-plus-harness environment.

Changing either file selects a new immutable layer. If an old capsule exists, run fortlet stop <harness> and fortlet reset <harness> before launching the new environment. A failed build leaves the prior layer and capsule intact; the old environment can be selected again by restoring its two files. Public downloads can drift unless the recipe pins and verifies them.

This repository's recipe pins Rust, Cargo, Jujutsu, and the Linux development library needed to build Fortlet. It serves as the first project-environment fixture; Nix remains the host development and package-reproduction system. Fortlet also restores the managed tool PATH for non-interactive Bash login shells through a package-owned process environment hook. It does not write a user .profile, .bashrc, fish configuration, or other startup file.

Product direction

Users may explicitly activate Fortlet's package-owned shim directory so normal use remains the native harness commands:

codex
tact

The shims are optional; fortlet run remains fully usable without them. Fortlet provides one capsule per project and harness and can list every owned capsule across projects. Its repository uses an explicit host-side publication boundary; an automated publication command, private project overlays, explicit workload leases, and standalone distribution remain future work. Local execution comes first; remote execution requires its own architecture.

Projects that already use devenv can opt in without a Fortlet shell hook. Add Fortlet as a pinned flake input (following the project's nixpkgs when appropriate), then include both outputs in devenv.nix:

# flake.nix
fortlet = {
  url = "github:codyw912/fortlet";
  inputs.nixpkgs.follows = "nixpkgs";
};

# devenv.nix
packages = [
  inputs.fortlet.packages.${pkgs.system}.fortlet
  inputs.fortlet.packages.${pkgs.system}.shim-activation
];

The separate activation output contains no second launcher implementation: its bin resolves to the immutable shim directory in the Fortlet package. Remove that one output from the project environment to return codex and tact to their prior resolution. On a normal fresh project entry, direnv applies the cached environment after fish startup; manual PATH mutation in a long-lived shell can desynchronize shell-manager state and should be cleared with a fresh terminal before evaluating activation behavior.

The first managed command for an absent project capsule must start that capsule and can take several seconds. Experiment 0042 observed approximately nine seconds for codex --version from absence on Apple silicon. That experiment did not measure attachment to an already-running capsule.

See OVERVIEW.md for durable product scope and GOAL.md for the current mission.

Workflow

This repository uses the SPAWN.md workflow. Fresh agent sessions start with GOAL.md, then experiments/HANDOFF.md, then governance/CHARTER.md. Significant design changes require an accepted Fortlet Improvement Proposal (FIP) before implementation.

License

Fortlet is licensed under either Apache-2.0 or MIT, at your option.

About

Project-scoped isolation for coding-agent CLIs

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages