Environment identity
Status: named local environments and branch metadata implemented 10 September 2026. Remote storage and CI behavior below remain proposals. The workflow runtime plan adds separate run/revision identities and a daemon; this note describes the existing environment lifecycle, not the complete future workflow model.
Problem
Section titled “Problem”Milestone 1 makes the git branch the identity of an environment. That is right for the common case and wrong for three things the team wants: a remote environment that outlives a branch, an environment that can be re-pointed at a different branch, and more than one environment for one branch.
Decision
Section titled “Decision”An environment is named. The name is the identity everywhere: compose project, rendered directory, labels, EC2 tags, DNS. The branch is an attribute called the linked branch. It says which branch’s pushes update the environment and which checkout envctl operates on locally.
The default name is the branch slug, so envctl up in a worktree behaves exactly as it does today. Nothing in the manifest changes.
envctl up # env named after the branch, linked to itenvctl up --env scratch # a second env on this branch, unlinkedenvctl env create preview-billing --branch feat/billingenvctl env link preview-billing feat/billing-v2 # re-point; next push updates itenvctl env unlink preview-billing # keep it, stop following any branchenvctl env list # name, backend, linked branch, dataset, stateenvctl env rm preview-billing # destroy--env replaces --feature; --feature stays as a deprecated alias for one release. Names follow the same slug rules as today: lowercase, a-z0-9-, at most 40 characters, unique per project prefix per backend.
What is recorded
Section titled “What is recorded”| Where | What |
|---|---|
.envctl/<env>/env.json (local) | name, backend, linked branch, dataset, parent env, created at |
| EC2 tags (vm) | envctl:project, envctl:env, envctl:branch |
s3://<bucket>/envs/<env>/env.json (vm) | the same document, so state survives an instance rebuild |
| Container labels | dev.envctl.env replaces dev.envctl.feature; the old label is written too for one release |
The existing local lifecycle has no server. Remote tag reconciliation is planned. Workflow runs will use the daemon and registry described in the workflow runtime plan.
How linking drives CI
Section titled “How linking drives CI”The preview workflow keys on environment name, not branch. On a push to branch B it asks which environments are linked to B and runs envctl up --backend vm --env <name> --tag <sha> for each. A PR labelled preview with no linked environment gets one named after the branch. Merge or close destroys environments linked to that branch unless they were explicitly created with env create, which marks them as kept; those are only removed by env rm or the reaper’s staleness rule.
Consequences for the current code
Section titled “Consequences for the current code”provider.Spec.FeaturebecomesEnv;feature.Detectbecomes the default-name resolver.- The rendered directory stays
.envctl/<env>/. - Labels gain
dev.envctl.env. - The
WorktreeCreatehook is unchanged: a Claude worktree gets an environment named after its branch.
The local rename is implemented. Workflow runs build on this environment metadata with separate run/revision IDs; they do not use branch linking to change pinned inputs during execution.