Skip to content

feat(cli): environment spike#381

Closed
wyattjoh wants to merge 10 commits into
mainfrom
wyattjoh/branching-only
Closed

feat(cli): environment spike#381
wyattjoh wants to merge 10 commits into
mainfrom
wyattjoh/branching-only

Conversation

@wyattjoh

@wyattjoh wyattjoh commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

No description provided.

wyattjoh added 10 commits July 10, 2026 10:38
Redefine the dev root as the null-parent instance so a named `main` root and
its forks classify correctly (ADR-0003/0010):

- isPrimaryInstance tests parent_instance_id only; scope the guardless
  development finders in deploy/status, autolink, and link to the null-parent
  root so a fork is never mistaken for the root.
- Collapse target resolution to one chain (ADR-0011): explicit
  --instance/--branch, else the worktree active pointer, else the development
  root. Remove the forced >1-instance disambiguation prompt from the users
  instance context.
- clerk open joins the chain: it honors the pointer, accepts --instance and
  --branch, and labels via the resolved instance label instead of always
  opening the dev root.
- Reject a branch name (including `main`) passed to the environment lens
  --instance with a `use --branch <name>` hint (ADR-0002); register --branch in
  shell completion so its value returns NO_FILE rather than filenames.
- ActiveEntry gains an additive branch_name field, written on switch, so status
  can report the branch without a second fetch (ADR-0008).

Update affected fixtures/tests to the new model (forks carry parent_instance_id;
no forced picker).
- branch list becomes a pure branch view (ADR-0005): `main` (the null-parent
  branch) is pinned at the top with its forks nested as a box-drawing tree, and
  production is removed from both human and JSON output.
- Restructure branch list --json from {trunks, branches} to a single `branches`
  list: `main` first (parent_instance_id null), forks carrying their parent, plus
  active_instance_id/active_instance_missing. No default flag; `main` is the
  null-parent branch.
- switch no-arg picker becomes the two-stage selector (ADR-0006): stage 1 picks
  the environment (Development/Production), stage 2 picks the branch (`main` +
  forks). Any single-option stage is skipped: no production skips stage 1, a lone
  `main` skips stage 2, and production never reaches stage 2. Positional/flag args
  bypass the stages.

Rework the shared branch-tree model (developmentBranches/buildBranchTable) to the
pinned-main-plus-forks shape shared by both surfaces, and update the branch list
and shared unit tests to the new model.
Change instanceLabel from `branch_name || environment_type` to the env-qualified
glyph form `<environment> ⎇ <branch>` (else `<environment>`), living in lib/config
so lib-layer resolvers share it (ADR-0007). A nameless dev root renders
`development`, the named root `development ⎇ main`, a fork `development ⎇ feature`,
production `production`.

Fan out the glyph:

- resolveAppContext instance labels feed the ` · on <label>` command suffixes,
  env pull echoes, switch outros, and BAPI error hints (all read ctx.instanceLabel).
- switch writes the glyph label to the pointer; fork messages use the bare parent
  name (`Forking main → <name>`); branch delete's active-branch hint points at
  `clerk switch main`.
- status: active label uses the glyph form, the annotation is slimmed to just
  `(default branch)` for main (forks/production get none), and status --json
  gains an additive branch_name.
- apps list ENVIRONMENTS is deduped to unique environment_types (never branch
  names); the users picker (buildInstancePickerChoices) adopts the glyph label.
- The two-stage switch branch picker keeps bare branch names (the environment is
  chosen in stage 1).

Rewrite the branch and status README/help text off the old `trunk` terminology.
Add self-serve branching activation and gate the fork commands (ADR-0013/0015):

- `clerk enable branches` / `clerk disable branches` join the verb-first
  enable/disable (toggles) family, calling the Platform
  `PATCH /v1/platform/applications/{appId}/branch_settings` route with
  `{enabled}`. Enabling names the dev root main (server-side); disabling is
  refused server-side while forks exist. There is deliberately no
  `clerk branch enable` subcommand.
- Passive gate: `clerk branch create` and `clerk switch --create` read the
  serialized app-level `branches_available` / `branches_enabled` and refuse to
  fork with a hint — `clerk enable branches` when available-but-not-enabled, a
  not-available message otherwise — identically in interactive and
  non-interactive shells. Switching to an existing instance is never gated.
- plapi: add the `branches_available` / `branches_enabled` fields to the
  Application payload and the `updateBranchSettings` route helper.

branch create now forks from the named `main` and reports it with the bare parent
name. Update fixtures/mocks to carry the enablement state.
- Delete buildInstancePickerChoices and its test: the users interactive instance
  picker was removed with the forced-disambiguation prompt (ADR-0011), leaving
  this helper with no runtime caller. Dead-code removal, not a lost feature.
- Surface the branch gate error codes distinctly: development_branches_not_available,
  development_branches_not_enabled, and cannot_disable_branches_with_live_forks
  carry their actionable detail (the enable hint, the live-fork count) in
  long_message rather than meta, so formatStructuredError now appends it beneath
  the headline for these codes.
`clerk branch create --name <n> --switch` (`-s`) forks the branch and then
activates it for the current worktree in one step. It delegates to branchSwitch
so the pointer update, .env sync, and output stay identical to
`clerk switch <branch>`. In agent mode branchSwitch emits the lone "switched"
JSON object and the human-facing "Forked" line is suppressed.
Refresh the branching-only changeset so the summary covers the cumulative
branch featureset: create with --switch, list/delete/switch management, the
enable/disable branch gate, and --branch targeting. Bump stays minor.
`clerk branch create` with no arguments now runs interactively in human mode:
it prompts for the branch name via Clack and then offers to switch the worktree
to the new branch. `--name` becomes optional, and the branching-enabled gate is
checked before prompting so the user is never asked for a name we cannot use.
Agent mode cannot be prompted, so it fails fast with a usage error directing the
caller to pass --name. Refreshes the branching changeset to describe the
interactive flow.
Add branchNameError/assertValidBranchName in the branch command's shared module,
mirroring clerk_go's ValidateBranchName + IsReservedBranchName and the dashboard.
`clerk branch create` validates --name up front (all modes) and enforces the
same rules in its interactive prompt; `clerk switch --create` validates its name
before the fork round-trip. Malformed or reserved names fail with a usage error
listing the allowed characters. Refreshes the branching changeset.
@changeset-bot

changeset-bot Bot commented Jul 14, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 7acacd0

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
clerk Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@wyattjoh

Copy link
Copy Markdown
Contributor Author

Stack: branching-only

Part of a stacked-prs chain. Do not merge manually.

@wyattjoh wyattjoh changed the title wyattjoh/branching only feat(cli): add standalone instance branching Jul 14, 2026
@wyattjoh wyattjoh closed this Jul 14, 2026
@wyattjoh wyattjoh deleted the wyattjoh/branching-only branch July 14, 2026 03:43
@wyattjoh wyattjoh changed the title feat(cli): add standalone instance branching feat(cli): environment spike Jul 14, 2026
@coderabbitai

coderabbitai Bot commented Jul 14, 2026

Copy link
Copy Markdown

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 54b46d07-2022-4367-bf6b-64110e48cbdd

📥 Commits

Reviewing files that changed from the base of the PR and between 8bd481d and 7acacd0.

⛔ Files ignored due to path filters (1)
  • bun.lock is excluded by !**/*.lock
📒 Files selected for processing (94)
  • .changeset/branching-only.md
  • README.md
  • packages/cli-core/package.json
  • packages/cli-core/src/cli-program.test.ts
  • packages/cli-core/src/cli-program.ts
  • packages/cli-core/src/commands/api/README.md
  • packages/cli-core/src/commands/api/fapi.test.ts
  • packages/cli-core/src/commands/api/fapi.ts
  • packages/cli-core/src/commands/api/index.ts
  • packages/cli-core/src/commands/apps/create.test.ts
  • packages/cli-core/src/commands/apps/list.ts
  • packages/cli-core/src/commands/billing/README.md
  • packages/cli-core/src/commands/billing/index.test.ts
  • packages/cli-core/src/commands/billing/index.ts
  • packages/cli-core/src/commands/branch/README.md
  • packages/cli-core/src/commands/branch/create.test.ts
  • packages/cli-core/src/commands/branch/create.ts
  • packages/cli-core/src/commands/branch/delete.test.ts
  • packages/cli-core/src/commands/branch/delete.ts
  • packages/cli-core/src/commands/branch/enable.test.ts
  • packages/cli-core/src/commands/branch/enable.ts
  • packages/cli-core/src/commands/branch/index.ts
  • packages/cli-core/src/commands/branch/list.test.ts
  • packages/cli-core/src/commands/branch/list.ts
  • packages/cli-core/src/commands/branch/shared.test.ts
  • packages/cli-core/src/commands/branch/shared.ts
  • packages/cli-core/src/commands/branch/switch.test.ts
  • packages/cli-core/src/commands/branch/switch.ts
  • packages/cli-core/src/commands/completion/__complete.ts
  • packages/cli-core/src/commands/config/README.md
  • packages/cli-core/src/commands/config/index.ts
  • packages/cli-core/src/commands/config/pull.test.ts
  • packages/cli-core/src/commands/config/pull.ts
  • packages/cli-core/src/commands/config/push.test.ts
  • packages/cli-core/src/commands/config/push.ts
  • packages/cli-core/src/commands/config/schema.ts
  • packages/cli-core/src/commands/deploy/status.ts
  • packages/cli-core/src/commands/env/README.md
  • packages/cli-core/src/commands/env/index.ts
  • packages/cli-core/src/commands/env/pull-branch.test.ts
  • packages/cli-core/src/commands/env/pull.test.ts
  • packages/cli-core/src/commands/env/pull.ts
  • packages/cli-core/src/commands/impersonate/README.md
  • packages/cli-core/src/commands/impersonate/impersonate.test.ts
  • packages/cli-core/src/commands/impersonate/impersonate.ts
  • packages/cli-core/src/commands/impersonate/index.ts
  • packages/cli-core/src/commands/impersonate/revoke.test.ts
  • packages/cli-core/src/commands/impersonate/revoke.ts
  • packages/cli-core/src/commands/link/index.test.ts
  • packages/cli-core/src/commands/link/index.ts
  • packages/cli-core/src/commands/open/index.test.ts
  • packages/cli-core/src/commands/open/index.ts
  • packages/cli-core/src/commands/orgs/README.md
  • packages/cli-core/src/commands/orgs/index.test.ts
  • packages/cli-core/src/commands/orgs/index.ts
  • packages/cli-core/src/commands/status/README.md
  • packages/cli-core/src/commands/status/index.ts
  • packages/cli-core/src/commands/status/status.test.ts
  • packages/cli-core/src/commands/status/status.ts
  • packages/cli-core/src/commands/switch-env/index.test.ts
  • packages/cli-core/src/commands/switch/README.md
  • packages/cli-core/src/commands/switch/index.ts
  • packages/cli-core/src/commands/toggles/README.md
  • packages/cli-core/src/commands/toggles/index.ts
  • packages/cli-core/src/commands/users/README.md
  • packages/cli-core/src/commands/users/create-wizard.test.ts
  • packages/cli-core/src/commands/users/create-wizard.ts
  • packages/cli-core/src/commands/users/create.test.ts
  • packages/cli-core/src/commands/users/create.ts
  • packages/cli-core/src/commands/users/index.ts
  • packages/cli-core/src/commands/users/interactive/instance-context.test.ts
  • packages/cli-core/src/commands/users/interactive/instance-context.ts
  • packages/cli-core/src/commands/users/lifecycle-runner.ts
  • packages/cli-core/src/commands/users/list.test.ts
  • packages/cli-core/src/commands/users/list.ts
  • packages/cli-core/src/commands/users/menu.test.ts
  • packages/cli-core/src/commands/users/open.test.ts
  • packages/cli-core/src/commands/users/open.ts
  • packages/cli-core/src/commands/users/registry.ts
  • packages/cli-core/src/lib/autolink.ts
  • packages/cli-core/src/lib/bapi-command.test.ts
  • packages/cli-core/src/lib/bapi-command.ts
  • packages/cli-core/src/lib/config.test.ts
  • packages/cli-core/src/lib/config.ts
  • packages/cli-core/src/lib/errors.ts
  • packages/cli-core/src/lib/git.ts
  • packages/cli-core/src/lib/plapi.ts
  • packages/cli-core/src/lib/spinner.ts
  • packages/cli-core/src/lib/time.test.ts
  • packages/cli-core/src/lib/time.ts
  • packages/cli-core/src/test/integration/completion.test.ts
  • packages/cli-core/src/test/integration/lib/harness.ts
  • packages/cli-core/src/test/integration/users-commands.test.ts
  • packages/cli-core/src/test/lib/stubs.ts

Disabled knowledge base sources:

  • Linear integration is disabled

You can enable these sources in your CodeRabbit configuration.


📝 Walkthrough

Walkthrough

This PR adds development-instance branching to the Clerk CLI. It introduces clerk branch (create/list/delete/switch), a top-level switch alias, and clerk status, plus per-application enable/disable branches toggles. A persisted per-worktree "active instance" pointer is added to config, alongside branch name validation, a tree-based branch picker, and BAPI target resolution with source attribution (flags/env/env-file/active-pointer). A new --branch <name> option is threaded through most existing commands (api, config, env, impersonate, users, orgs, billing, open, link) to target branch instances directly.

Estimated code review effort: 5 (Critical) | ~150 minutes

Suggested reviewers: rafa-thayto

✨ Finishing Touches
⚔️ Resolve merge conflicts
  • Resolve merge conflict in branch wyattjoh/branching-only

Comment @coderabbitai help to get the list of available commands.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant