Install
envctl is a single Go binary. It needs Docker with the compose plugin on the machine it runs on. Nothing else runs in the background.
Requirements
Section titled “Requirements”| Requirement | Why |
|---|---|
Docker Engine with docker compose v2 | envctl renders a compose file and runs plain compose on it. |
| git | The feature name comes from the branch of the current worktree. |
jq | Only for the Claude Code hook scripts. |
On macOS, OrbStack is the best host: envctl detects it and reaches services by DNS instead of publishing host ports. Docker Desktop and Colima work too, with stable loopback ports from a registry.
Install with Homebrew
Section titled “Install with Homebrew”brew install sam-bretz/tap/envctlThis installs envctl, puts the two Claude Code worktree hooks on your PATH, and installs Lima for workflow VMs. Docker is not managed by Homebrew here: install OrbStack, Docker Desktop or Colima yourself. Homebrew builds are available for macOS and Linux on Apple silicon/arm64 and Intel/amd64.
Upgrade with brew upgrade envctl.
Install from source
Section titled “Install from source”go install github.com/sam-bretz/envctl/cmd/envctl@latestgo install puts envctl in $(go env GOPATH)/bin. Make sure that directory is on your PATH. The workflow runtime also needs Lima (brew install lima).
Check it:
envctl --versionInstall the hooks
Section titled “Install the hooks”Homebrew already puts the hooks on your PATH. From source, the Claude Code hooks are two shell scripts in hooks/claude/. Put them somewhere on PATH:
install -m 0755 hooks/claude/envctl-worktree-create hooks/claude/envctl-worktree-remove "$(go env GOPATH)/bin/"Then register them in a repo. See Agents.
Set up agent credentials (workflow runtime)
Section titled “Set up agent credentials (workflow runtime)”The experimental workflow runtime (envctl run, envctl ui) runs worker and supervisor agents inside local VMs. It also needs Lima 2.x (brew install lima). Each harness needs a credential that can be copied into those VMs safely. Do this once, before your first run.
Claude
Section titled “Claude”Claude workers need a long-lived token, not your normal Claude Code login. A claude.ai login carries a refresh token that rotates each time it’s used. If envctl copied it into a VM, the first refresh would revoke every other copy, which can log you out of Claude Code on your own machine. envctl refuses those logins and accepts only ANTHROPIC_API_KEY or a token from claude setup-token.
-
Open a normal terminal window.
claude setup-tokenis interactive, so it won’t work inside a Claude Code!command. -
Run
claude setup-token, finish the browser login, and copy thesk-ant-oat…token it prints. -
In the same terminal, save the token to a private file.
read -skeeps it off the screen and out of shell history; paste it at the prompt:Terminal window mkdir -p ~/.config/envctlumask 077read -rs "TOKEN?Token: " && printf '{"CLAUDE_CODE_OAUTH_TOKEN":"%s"}' "$TOKEN" > ~/.config/envctl/claude-token.json && unset TOKENThat
readprompt syntax is zsh. In bash, useread -rsp "Token: " TOKENinstead. -
Reference the file from the workflow configuration. Use an absolute path; relative paths resolve against the configuration’s directory, and
~isn’t expanded.agents:worker:kind: claudecredential: file:/Users/you/.config/envctl/claude-token.jsonsupervisor:kind: claudecredential: file:/Users/you/.config/envctl/claude-token.json
credential also accepts env:NAME for an API key and oauth-env:NAME for a setup token. With no credential, envctl uses ANTHROPIC_API_KEY, then CLAUDE_CODE_OAUTH_TOKEN. An environment variable must be set in the environment of the envctl coordinator, which is started by whichever envctl command runs first. A file reference avoids depending on that.
Codex workers need a long-lived credential too: a Codex access token, or an OpenAI API key. envctl refuses the ChatGPT login in ~/.codex/auth.json. Its refresh token rotates like Claude’s, and OpenAI says not to share one auth.json across machines or concurrent jobs.
Codex access token (the claude setup-token equivalent). Codex access tokens are available only in ChatGPT Business and Enterprise workspaces, and a workspace owner must first allow members to use them.
-
Create one at chatgpt.com/admin/access-tokens. Choose an expiry and rotate it like any automation secret.
-
Save it the same way as the Claude token, in your own terminal:
Terminal window read -rs "TOKEN?Token: " && printf '{"CODEX_ACCESS_TOKEN":"%s"}' "$TOKEN" > ~/.config/envctl/codex-token.json && unset TOKEN -
Reference it with
credential: file:/Users/you/.config/envctl/codex-token.jsonon each Codex agent.
API key (any OpenAI account). Use credential: env:OPENAI_API_KEY, or a file: reference to a JSON file containing OPENAI_API_KEY. Usage is billed to the API, not your ChatGPT plan.
credential also accepts access-env:NAME for an access token in an environment variable. With no credential, envctl uses OPENAI_API_KEY, then CODEX_ACCESS_TOKEN, from the coordinator’s environment.
When a job starts, envctl removes any login file an earlier envctl version copied into a VM’s agent home, for both Codex and Claude.
Upgrade
Section titled “Upgrade”With Homebrew, run brew upgrade envctl. From source, run go install github.com/sam-bretz/envctl/cmd/envctl@latest again. Rendered environments keep working; run envctl up in each worktree to re-render with the new version.
Where next
Section titled “Where next”- Quick start creates a manifest and starts your first environment.
- Configuration explains every manifest choice.