Skip to content

Your first workflow

This walkthrough takes one change from an objective to a draft pull request. Agents do the work inside a dedicated virtual machine, and you review at every checkpoint.

The workflow runtime is experimental. It has been exercised on macOS on Apple silicon with Lima; other hosts are untested. See the roadmap for what is proven and what is not.

You needWhy
envctl v0.2.0 or later, Docker, and LimaThe coordinator, your services, and the VM
A long-lived agent credentialAgents run in the VM; see Install
A git repository with a Compose fileIts services run beside the agents
gh auth login, for pull request outputThe coordinator pushes and opens the PR

Everything runs on your machine. Nothing is sent anywhere except the agent’s own model calls and, at the end, the pull request.

Add envctl.yaml at the repository root. Version 2 selects the workflow runtime:

version: 2
project: shop
repositories:
- id: app
url: https://github.com/you/shop.git
ref: main
stack:
files: [compose.yaml]
workflow:
template: feature
nodes:
qa:
checks:
- name: unit
command: [npm, test]
agents:
worker:
kind: claude
credential: file:/Users/you/.config/envctl/claude-token.json
supervisor:
kind: claude
credential: file:/Users/you/.config/envctl/claude-token.json

Three things matter here.

The repository is cloned into the VM from url at ref, not copied from your working tree. Your uncommitted edits are not used, and nothing the agents do can touch your checkout. Push the branch you want them to start from.

QA needs real checks. The feature template gives you the six stages, but its QA stage has no commands, and envctl refuses to accept a QA checkpoint without executable checks. The nodes.qa block above merges into the template. A check runs in the VM, in the repository’s directory.

Small changes can skip stages. Add a named workflow for them. The built-in small template runs Plan, then Build, which writes the code and runs its checks, then the approved change:

workflows:
small:
template: small
nodes:
build:
checks:
- name: unit
command: [npm, test]

Choose it when you create a run with --workflow small, or with tab in the dashboard. See Workflows.

Agents need a credential that is safe to place in a VM. A file: path must be absolute.

Check it before you start anything:

Terminal window
envctl run validate

That prints the complete configuration, including every default it filled in: the Lima provider, a dedicated VM, CPU, memory and disk, and the pinned harness version.

Terminal window
envctl run create --task "Add CSV export to the orders report" --name "orders csv export"

Add --workflow small to use a named workflow instead of the default; envctl run workflows lists them. In the dashboard, press n, then tab to change the workflow.

This returns immediately with a run ID like run_8f0c…. A coordinator starts in the background if one isn’t already running, provisions the VM, clones the repository at an exact commit, and starts the first stage. The first run on a machine also downloads the VM image, which takes a while.

Terminal window
envctl ui

The dashboard shows the stage strip, your in-flight runs, and a focused panel:

KeyAction
Move between runs
Move between stages
tabCycle panels: Conversation, Checkpoint, Changes, Tests, Services, Readiness, Graph, History
iWrite to the agent; s switches between worker and supervisor
dDiff the stage; b sets a comparison base, B clears it
oOpen the selected artifact; , and . select
[ ]Browse revision history
r a xRewind, approve, cancel
gOpen the run’s pull request in your browser
TPick a color theme, with live preview
qDetach; execution continues

Closing the dashboard never stops the run. For scripts, envctl run show <run> --json has the same information.

Prefer a browser? envctl web serves the same dashboard on this machine and opens it:

Terminal window
envctl web

Runs are grouped by what they need from you. Each run says in one sentence what it needs next, with the button for it, such as Review and approve or Rewind to plan. Pick a stage to see its Chat, Result, Changes and Log. Documents open in a reading pane. The same keys work there (? lists them).

Plan is a gate, not a document. It cannot complete while a capability the workflow needs is unresolved: a missing agent connection, no Compose stack, an unreachable database, or no pull request destination. envctl probes each one for real.

Terminal window
envctl run readiness <run> --json

If something is missing, the run says so instead of failing three stages later. Two ways out:

  • Fix the environment, for example authenticate gh so publication.pr can pass.

  • Attach a plugin that supplies the capability, which reopens Plan in a new revision:

    Terminal window
    envctl run plugin add <run> --file browser.yaml

Downstream stages start only after the actual probe passes. A worker claiming “done” cannot move Plan.

Agents report progress continuously: the phase, the current check, and their recent activity. To redirect one mid-task:

Terminal window
envctl run message <run> --node code --to worker --text "Use the existing CSV writer in lib/export.ts"

This reaches the running agent within seconds. envctl interrupts its turn and resumes the same session with your message, keeping the work it has already done. The supervisor also sees your messages and should reject work that ignores them. Each message shows its status: delivered live, or queued for the next attempt.

Every stage ends in an immutable checkpoint: the agent’s output, the source commits, check results, and an independent supervisor review.

Terminal window
envctl run checkpoints <run>
envctl run diff <run> --node code
envctl run artifact <digest> --output ./plan.md

Diffs come from retained bundles, so they still work after the VM is gone.

Rewind to any earlier stage. Work already running finishes into history rather than being killed, and the new attempt restores that stage’s exact inputs:

Terminal window
envctl run rewind <run> --to design --task "Export XLSX as well as CSV"

Rewinding creates a new revision. The old one stays reviewable under [ and ], and its results can never overwrite the new one.

The final stage is a human gate. Nothing is pushed until you approve the exact reviewed result. In the dashboard, press a: from any other stage it first moves to the stage awaiting approval, so press a again there to approve. From a shell:

Terminal window
envctl run approve <run>

With one change awaiting approval, that approves the result envctl run show displays. Pass --digest to pin the exact result you reviewed.

envctl then pushes a revision branch and opens a draft pull request whose body lists the validated commits and the QA evidence. If the change adds Git LFS files or moves a submodule, those objects are published first, and the pull request says which submodule pull requests must merge first.

Press g in the dashboard, or run envctl run pr <run> --open, to open the pull request in your browser. Without --open the command prints the link.

To stop a run and release its VM:

Terminal window
envctl run cancel <run>

Services in the VM are private to it. To open one from your machine, opt in:

preview:
service: web
port: 8080

envctl run show then prints a 127.0.0.1 preview URL while the service answers. Agents and checks always reach services through ENVCTL_SERVICE_<NAME>_URL inside the VM.

Each executing revision gets its own VM, and parallel branches get their own as well; limits.vms caps them. Agent work bills to whatever credential you configured, and a plan’s usage limit stops a worker mid-stage.

Agents use a lot of tokens: a single feature run through Code has measured at 10M to 13M, mostly cache reads. envctl run show and the dashboard show each run’s total, and every run has a token ceiling of 40M by default. At the ceiling, envctl stops the agents and waits for you. Set your own with limits.run_tokens, or cap the reported cost with limits.run_cost_usd. See Token usage and ceilings.