Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Latest commit

 

History

252 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Foundry

A command-line tool for managing AI agent workspaces using git worktrees and terminal automation.

Foundry automates the full lifecycle of parallel development workspaces: creating feature branches, setting up worktrees, opening terminal layouts with your tools, and cleaning up when you're done.

Installation

cargo install --path .

Or build manually:

cargo build --release
# Binary is at target/release/foundry

Quick Start

# From inside a git repo:
foundry start my-feature

This will:

  1. Create a branch (my-feature, or yourprefix/my-feature if configured)
  2. Create a worktree at ~/.foundry/worktrees/<project>/my-feature
  3. Run any configured setup scripts
  4. Open a new terminal tab with your configured pane layout

When you're done:

# Merge to main and clean up:
foundry finish

# Or push and create a GitHub PR first:
foundry pr

# Then finish when CI passes (automatically merges the PR):
foundry finish

# Or discard without merging:
foundry discard

Commands

Command Description
foundry start <name> Create branch, worktree, run setup, open workspace
foundry start --issue <number> Start from a GitHub issue (auto-generates name and prompt)
foundry start <name> --prompt "..." Start with a prompt passed to the AI agent
foundry start <name> --fetch Fetch and fast-forward main before branching
foundry open [name] Reopen workspace (resumes agent conversation if available)
foundry open --all Reopen all active workspaces for the project
foundry pr [name] Push branch and create a GitHub PR
foundry pr [name] --title "..." Create PR with a custom title
foundry finish [name] Finish workspace: merge PR (if created) or merge locally
foundry finish [name] --local Force local merge, ignoring any associated PR
foundry discard [name] Teardown and clean up without merging
foundry discard [name] --force Discard even if the branch has unmerged commits
foundry switch [name] Switch to a workspace's terminal tab
foundry restore [branch] Restore workspace from an archived branch
foundry status Show status dashboard of all workspaces (use --watch/-w to continuously refresh)
foundry diff [name] Show changes in a workspace vs main
foundry diff [name] --stat Show file change summary vs main
foundry history Show workspace activity history
foundry list List all active workspaces across all projects
foundry trust [path] Review and approve a project's .foundry.toml
foundry trust [path] --revoke Withdraw a previous approval
foundry projects list List registered projects
foundry projects add <name> <path> Register a project
foundry projects remove <name> Unregister a project
foundry completions <shell> Generate shell completions (bash, zsh, fish)

Global Flags

Flag Description
--project <name> Specify project explicitly (otherwise inferred from cwd)
--verbose Show detailed output for each step
--yes Skip confirmation prompts
--version Show version

Command Details

foundry start <name> is idempotent — if the worktree already exists, it skips creation and opens the workspace.

foundry pr [name] pushes the feature branch to the remote and creates a GitHub PR via the gh CLI. If a PR already exists for the branch (created manually on GitHub), foundry links it instead of creating a duplicate. The workspace stays open so you can fix issues if CI fails. The PR title is auto-generated from the branch name unless --title is provided.

foundry finish [name] checks whether a PR was created (via foundry pr). If so, it merges the PR on GitHub, fetches to sync local refs, and cleans up. If not, it merges locally using the configured strategy (fast-forward only by default). Branches with commits are archived (e.g., archive/my-feature-20260321); branches with no commits are simply deleted. foundry merge is an alias for foundry finish.

If the associated PR was closed or merged outside of foundry, finish will report an error with instructions to either reopen the PR or run foundry finish --local to merge locally instead.

foundry finish [name] and foundry discard [name] can infer the workspace name from your current directory if you're inside a worktree.

foundry restore [branch] accepts a full branch name (archive/my-feature-20260321) or just the branch name without the archive prefix. Run with no arguments to see available archived branches.

foundry open resumes the agent's previous conversation (e.g., claude --continue) when reopening a workspace that has conversation history. If a new --prompt is provided, it starts a fresh conversation instead. --all reopens all active workspaces for the project, skipping any that are already open.

foundry discard requires --force (or -f) if the branch has unmerged commits, similar to git branch -D. Workspaces with no commits can be discarded freely.

foundry history shows recent workspace lifecycle events (started, finished, discarded, restored) with timestamps and metadata. Use --limit to control how many events are shown (default: 20).

foundry status displays a dashboard of all active workspaces with their current state. The dashboard includes git status (clean/dirty), commit count vs main, and agent activity. Use --watch / -w to continuously refresh the display every 2 seconds, useful for monitoring progress while agents work. For Claude workspaces, the dashboard shows rich activity info: the current tool being used while working, the last message from the agent when idle, and error details (rate limit, auth failure, etc.) when an error occurs.

Configuration

Foundry uses two levels of TOML configuration:

  • Global config at ~/.foundry/config.toml — defaults for all projects
  • Project config at .foundry.toml in each repo root — project-specific overrides

Everything foundry keeps under ~/.foundry (config, project registry, workspace state, history, hooks) moves to another directory if you set FOUNDRY_HOME to it. worktree_dir still defaults to ~/.foundry/worktrees; set it explicitly to move worktrees too.

Global Config

# ~/.foundry/config.toml

# Optional prefix for branch names (omit for no prefix)
# "my-feature" becomes "xiphux/my-feature"
branch_prefix = "xiphux"

# Default AI agent: "claude" (default), "codex", "every-code", "gemini",
# "aider", "copilot", "kiro", "opencode", "crush", "nanocoder", "pi", or "custom"
agent = "claude"

# Starting port for dynamic port allocation (default: 10000)
# port_range_start = 20000

# Automatically fetch and fast-forward main before branching (default: false)
# auto_fetch = true

# Remote to fetch from (default: "origin")
# fetch_remote = "upstream"

# Remote to push to for PR commands (default: auto-detect)
# If there's one remote, uses it. If multiple, defaults to "origin".
# pr_remote = "origin"

# Bypass all permission checks and sandbox constraints (default: false).
# Agents use their most permissive mode (YOLO/auto-approve-all).
# Use with caution — this grants agents unrestricted system access.
# unrestricted_permissions = true

# Prefix for archived branches (default: "archive")
archive_prefix = "archive"

# Merge strategy: "ff-only" (default) or "merge"
merge_strategy = "ff-only"

# Base directory for worktrees (default: "~/.foundry/worktrees")
worktree_dir = "~/.foundry/worktrees"

Default Pane Layout

If no [[panes]] are configured, foundry uses a simple default layout — the agent on the left and a plain shell on the right:

┌──────────────┬──────────────┐
│              │              │
│    agent     │    shell     │
│              │              │
└──────────────┴──────────────┘

Custom Pane Layout

You can define your own layout in the global config. The first pane becomes the initial tab. Subsequent panes split from a named parent pane in the given direction.

# ~/.foundry/config.toml

[[panes]]
name = "agent"
agent = "claude"
# Per-pane environment variables (optional)
[panes.env]
SOME_VAR = "value"

[[panes]]
name = "git"
command = "lazygit"
split_from = "agent"
direction = "right"

[[panes]]
name = "shell"
split_from = "git"
direction = "down"

# Optional panes are only included if the project opts in
[[panes]]
name = "server"
split_from = "shell"
direction = "right"
optional = true

Multi-Agent Layout

You can run multiple different agents in a single workspace by setting agent on different panes. Each agent type can only appear once per workspace.

[[panes]]
name = "developer"
agent = "claude"

[[panes]]
name = "reviewer"
agent = "codex"
split_from = "developer"
direction = "right"

[[panes]]
name = "shell"
split_from = "developer"
direction = "down"

This produces the following layout (with server pane only if the project opts in):

┌──────────────┬──────────────┐
│              │   lazygit    │
│              ├───────┬──────┤
│    agent     │ shell │ dev  │
│              │       │server│
└──────────────┴───────┴──────┘

Pane Configuration

Field Required Description
name Yes Unique name for this pane
agent No Agent to run in this pane (auto-generates command with permissions and prompt passthrough)
command No Command to run (empty = shell prompt, ignored if agent is set)
split_from No* Name of the pane to split from
direction No* Split direction: "right" or "down"
optional No If true, only included when the project opts in (default: false)
[panes.env] No Environment variables to set for this pane

* Required for all panes except the first (which becomes the tab).

Important: Always use agent instead of command for AI coding agents. Using agent = "claude" ensures foundry sets up permissions, status tracking, and prompt passthrough. If you use command = "claude" directly, foundry will warn you to switch to the agent field.

Project Config

# .foundry.toml (in repo root)

# Setup scripts run after worktree creation (in order)
[[scripts.setup]]
name = "Copy env file"
command = "cp {source}/.env {worktree}/.env"

[[scripts.setup]]
name = "Install dependencies"
command = "npm install"
working_dir = "{worktree}"
deferred = true  # runs in the shell pane after the workspace opens

# Teardown scripts run before worktree deletion (in order)
[[scripts.teardown]]
name = "Stop containers"
command = "docker compose down"
working_dir = "{worktree}"

# Allocate unique ports per workspace (available as env vars in all panes)
ports = ["VITE_PORT", "API_PORT"]

# Additional context injected into the agent's session (supports port variables)
# context = "The dev server runs at http://localhost:{VITE_PORT}"

# Opt in to optional panes and/or override pane commands
[panes.server]
command = "npm run dev"

Project config can also override global scalar values:

# Override the default agent for this project
agent = "codex"

# Override the merge strategy for this project
merge_strategy = "merge"

Deferred Setup Scripts

Setup scripts marked with deferred = true run in the shell pane after the workspace opens, rather than blocking before it opens. This lets you start working while slower scripts (like npm install) run in the background.

Deferred scripts are chained together with && and sent to the first pane that has no command configured (typically the "shell" pane). Non-deferred scripts run in order before the workspace opens, as usual.

Dynamic Port Allocation

When running multiple workspaces in parallel, dev servers compete for the same ports. Foundry can allocate unique ports per workspace and expose them as environment variables.

Add a ports array to your project config listing the environment variable names:

# .foundry.toml
ports = ["VITE_PORT", "API_PORT", "DYNAMODB_PORT"]

Each workspace gets a contiguous block of ports (starting from 10000 by default). The variables $VITE_PORT, $API_PORT, $DYNAMODB_PORT are available in all panes and setup scripts. Ports are assigned once at foundry start and remain stable for the life of the workspace.

Configure your dev servers to use these variables instead of hardcoded ports (e.g., vite --port $VITE_PORT).

Worktree Context

Foundry automatically injects workspace context into agents that support it (currently Claude via a SessionStart hook). This context tells the agent:

  • That it's working in an isolated worktree (safe to make changes freely)
  • What panes the user started the workspace with (e.g., "server": npm run dev)
  • Allocated port values

You can append project-specific context with the context field in .foundry.toml. Port variables are expanded automatically:

# .foundry.toml
context = """
The Vite dev server runs at http://localhost:{VITE_PORT}.
The API server runs at http://localhost:{API_PORT}.
Run tests with: npm test
"""

This is useful for giving agents information they can't easily discover on their own, such as where the dev server is running (since it runs in a separate pane with a dynamically allocated port).

To customize the starting port, set port_range_start in your global config:

# ~/.foundry/config.toml
port_range_start = 20000

Template Variables

The following variables can be used in command and working_dir fields in scripts and pane commands:

Variable Description
{source} Absolute path to the main repo checkout
{worktree} Absolute path to the worktree
{branch} Full branch name (with prefix if configured)
{name} Short name (without prefix)
{project} Project name

Config Merging Rules

  • Scalar values (branch_prefix, agent_command, etc.): project overrides global
  • Pane layout: global defines the structure; project can override command and env for existing panes by name, and opt in to optional panes
  • Scripts: project-only (no global scripts)

Trusting Project Configs

.foundry.toml lives in the repo root and is checked into version control, so its contents come from whoever wrote the repository. Several keys are executable: setup and teardown scripts run through sh -c, pane command overrides are typed into a shell, and agent_command runs verbatim.

The first time foundry uses a project config containing any of those, it shows exactly what would run and asks for approval:

/path/to/repo/.foundry.toml contains commands that foundry will run:
  - setup script 'install': pnpm install

This file comes from the repository, not from your own configuration.
Only approve it if you trust this repo.
Trust this project config? [y/N]

Approval is recorded per project in ~/.foundry/trust.toml, keyed to a hash of the file, and is requested again whenever the file changes. Configs with no executable content never prompt.

Approve ahead of time — or in a script, where foundry refuses to prompt and fails instead — with foundry trust:

foundry trust                    # approve the current repo
foundry trust /path/to/repo      # approve a specific repo
foundry trust --revoke           # withdraw approval

Project Registry

Foundry automatically registers projects the first time you run a command inside a git repo. The project name is derived from the directory name.

Projects are stored in ~/.foundry/projects.toml. You can manage them manually:

foundry projects list
foundry projects add myapp /path/to/myapp
foundry projects remove myapp

Agent Support

Foundry supports multiple AI coding agents. The agent is configured via agent in your global or project config.

Agent Config value Default With unrestricted_permissions Prompt Resume
Claude claude Auto mode (worktree-scoped) Bypass all prompts Positional --continue
Codex codex Sandbox (built-in) Same Positional --resume
Every Code every-code Sandbox (built-in) Same Positional --resume
Gemini CLI gemini Sandbox (worktree-scoped) No sandbox, YOLO -p flag --resume
Aider aider Ask for permission --yes (auto-approve) Interactive No
GitHub Copilot copilot Ask for permission --yolo (auto-approve) -p flag No
Kiro kiro Ask for permission --trust-all-tools Positional --resume
OpenCode opencode Ask for permission --auto (auto-approve) --prompt flag --continue
Crush crush Ask for permission --yolo (auto-approve) No --continue
Nanocoder nanocoder Ask for permission No Positional No
Pi pi No permission prompts Same (no flag) Positional --continue
Custom custom N/A N/A N/A N/A

Permission Levels

By default, foundry uses the safest available permission level for each agent:

  • Auto mode (Claude): Claude launches with --permission-mode auto, where a model analyzes each permission request and auto-approves the ones it judges safe, falling back to a prompt otherwise. Worktree-scoped allow/deny rules still apply on top.
  • Worktree-scoped sandbox (Codex, Every Code, Gemini): The agent can read/write freely within the worktree, but OS-level sandboxing prevents modifications outside it. Commands are auto-approved within sandbox boundaries.
  • Ask for permission (Aider, Copilot, Kiro, OpenCode, Crush, Nanocoder): The agent launches with standard permissions and prompts the user before taking actions.
  • No permission prompts (Pi): Pi executes tools without approval prompts by design and offers no flag to change this. Foundry runs Pi inside the isolated worktree; for stronger isolation, Pi's docs recommend running it in a container.

Setting unrestricted_permissions = true in your config bumps agents to their most permissive mode — auto-approving all actions without sandbox constraints. Use with caution. This key is read from the global config only: a project's .foundry.toml can turn it off, but cannot turn it on.

What worktree scoping is and isn't

For Claude, foundry writes worktree-scoped rules into the workspace's .claude/settings.local.json — allowing reads and writes under the worktree, and denying git push and git checkout main.

Treat these as guardrails against accident, not as a security boundary. They stop an agent from wandering out of its workspace by mistake. They are not a sandbox, and they do not contain an agent that is actively trying to get out: a deny rule like Bash(git push*) is pattern matching on the command string, so git -C <path> push, extra whitespace, a shell alias, or writing to .git directly all sidestep it.

For actual isolation, use an agent with OS-level sandboxing (Codex, Every Code, Gemini) or run the agent in a container.

Agent Details

Claude gets the richest integration: foundry copies your source repo's .claude/settings.local.json into the worktree and merges in status-tracking hooks and worktree-scoped permissions (auto-approve file operations within the worktree, deny git push and checkout main). Claude launches in auto permission mode, which uses model analysis to auto-approve most permission requests.

Codex and Every Code use --full-auto for autonomous operation with a built-in OS sandbox scoped to the workspace.

Gemini CLI launches with --sandbox --approval-mode=yolo — the sandbox restricts writes to the project directory while YOLO mode auto-approves within those boundaries. Note: Gemini may prompt to trust the worktree directory on first use. To avoid this for every workspace, trust the parent worktree directory (e.g., ~/.foundry/worktrees/).

Aider launches as an interactive REPL. Since Aider auto-exits after processing --message, foundry launches it interactively and lets you type prompts directly.

GitHub Copilot launches with standard permissions by default. Note: Copilot may prompt to trust the worktree directory on first use. You can choose "Remember this folder" when prompted.

Kiro (formerly Amazon Q Developer CLI) launches with kiro-cli chat. Prompts are passed as positional arguments and sessions can be resumed with --resume.

OpenCode launches as an interactive TUI. Prompts are passed via --prompt and sessions can be resumed with --continue. With unrestricted_permissions, it launches with --auto, which approves every permission not explicitly denied in opencode.json. Auto-approval can also be configured persistently there ("permission": "allow").

Crush (by Charmbracelet, the original project OpenCode was forked from) launches as an interactive TUI. Sessions can be resumed with --continue. Use --yolo for auto-approve mode. No interactive prompt passthrough.

Nanocoder is a local-first coding agent. Prompts are passed as positional arguments. No session resume or auto-approve CLI flags are currently available.

Pi (pi.dev) is a minimal terminal coding agent. Prompts are passed as positional arguments and sessions can be resumed with --continue. Pi has no permission popups by design — it executes tools directly — and provides no auto-approve flag, so unrestricted_permissions has no effect.

Custom agents use whatever command you specify in agent_command. Foundry runs it as-is without additional configuration.

Terminal Support

Foundry detects the terminal automatically from the TERM_PROGRAM environment variable.

Terminal Platform Mechanism
Ghostty macOS AppleScript
iTerm2 macOS AppleScript
WezTerm macOS, Linux, Windows wezterm cli
Windows Terminal Windows wt.exe
Zellij (fallback) macOS, Linux zellij CLI
tmux (fallback) macOS, Linux tmux CLI
Bare (fallback) any single pane, no splits

Native terminal backends open a new tab with splits. If no native backend is detected, foundry falls back to Zellij or tmux (whichever is available), which take over the current terminal with a multiplexer session. If neither is available, bare mode runs the first agent command in the current terminal with no splits.

To skip detection, set FOUNDRY_TERMINAL to one of ghostty, iterm2, wezterm, windows-terminal, zellij, tmux or bare (for example, to use tmux from inside Ghostty).

Windows Terminal does not support run_in_pane (deferred pane commands) or focus_tab due to wt.exe limitations.

Shell Configuration

On Windows Terminal, you can specify which shell to use in panes:

# ~/.foundry/config.toml
shell = "C:/Program Files/Git/bin/bash.exe"

Supported values: "powershell", "pwsh", or a path to bash.exe. If you specify git-bash.exe, foundry automatically resolves it to the embeddable bin/bash.exe in the same Git installation. Other terminal backends use their default shell and ignore this setting.

Shell Completions

Generate completions for your shell:

# Zsh
foundry completions zsh > ~/.zfunc/_foundry

# Bash
foundry completions bash > /etc/bash_completion.d/foundry

# Fish
foundry completions fish > ~/.config/fish/completions/foundry.fish

About

A command-line tool for managing AI agent workspaces using git worktrees and terminal automation

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages