Reusable, provider-native operating kit for project-scale agentic software delivery across Codex, Claude Code, and other skill-capable hosts. cmux is an optional view/event layer; tmux is never a baseline requirement.
Install it. mise is the only bootstrap prerequisite. Read
mise.toml before step 2 — that step authorizes whatever it says at that moment:
git clone https://github.com/Codeseys-Labs/agentic-sdlc.git && cd agentic-sdlc
mise trust ./mise.toml # persistent, per-path, and needs your explicit approval
mise --locked install # 12 pinned tools, ~1.3 GB
mise run lifecycle:install -- --agent claude # or --agent codex; one plane per run, no defaultThe dispatcher is bin/ccodex in the tree you just cloned; run it from there, or let mise expose
it (see ccodex — the operator dispatcher). There is no
separate step that copies it into ~/.local/bin.
Then mise run lifecycle:status -- --agent claude should report N ok, 0 conflict, 0 absent. Full walkthrough with
the reasoning behind each step: Quickstart from a clean clone.
Every command with what it does: ccodex — the operator dispatcher
and the task table. Verified from nothing on a fresh
ubuntu:24.04 container against the public remote — docs/research/2026-08-08-fresh-host-install-verification.md
records the transcript, including two defects it found.
Architecture: an open plugin — the multi-host pattern, since no unified plugin standard
exists (verified 2026-07). The portable layer is the skills/ tree (the
Agent Skills format, natively read by Claude Code, Codex, Gemini
CLI, OpenCode, Cursor, Goose, Kiro, and ~40 hosts) + a root AGENTS.md router (read by
Codex/Gemini/OpenCode). On top sit THIN per-host manifests, all version-locked by
scripts/bump-version.sh:
| Host | Manifest |
|---|---|
| Claude Code | .claude-plugin/{plugin,marketplace}.json |
| Codex CLI | .codex-plugin/plugin.json + .agents/plugins/marketplace.json |
| Gemini CLI | gemini-extension.json (contextFileName → AGENTS.md) |
| OpenCode / Goose / Kiro / others | pure skills-tree discovery via the symlink installer |
Adding a skill means adding a skills/<name>/SKILL.md directory. The installer, validator, and
all distribution planes pick it up automatically. Never hand-edit one manifest's version.
scripts/bump-version.sh <x.y.z> writes all of them; --check gates drift in CI — the
validator reports a disagreeing manifest as an error, so the gate and CI fail closed on drift.
The baseline shape:
Agent entrypoint (Codex, Claude Code, or another capable host)
-> provider-native roles/subagents/workflows (or direct execution)
-> Seeds queue
-> git worktrees
-> tests/review
-> squash/rebase/PR
Optional adapters:
+ cmux for an already-active view/event layer
+ tmux only when an optional adapter uses it
Capability-negotiated baseline: a host may run the native Frame -> Ship loop only after the required Git, Seeds, gate, trust, and selected-adapter capabilities are present, pinned where applicable, and verified. Missing, untrusted, unpinned, or ambiguous required capability fails closed. An unselected optional adapter does not block the native path. Never install, start, or enable cmux or tmux merely to use this bundle.
The rule on third-party skill libraries has two parts, and the distinction between them is the whole point: this bundle never vendors a foreign library's bytes, and it can invoke a library's own installer on explicit request.
- Never vendored. No foreign library's bytes are copied into this repository's tree. That
is what would trigger a
NOTICEdonor obligation under ADR-0001, drag another licence into this distribution, freeze one snapshot of somebody else's catalog, and put entries this bundle did not author onto its own selection surface. Foreign ideas enter here by exactly one path: an adaptedreferences/*.mdfile with a rootNOTICEdonor entry landed in the same change, re-expressed in this bundle's own prose rather than copied. - Installable on request, from a closed catalog.
libraries:list,libraries:status, andlibraries:installsupport exactlymattpocock/skills, ECC (affaan-m/ECC), and hyperresearch through each library's own front door. Unlisted libraries—including gstack—are operator-owned foreign state until separately verified and onboarded; these tasks do not adopt, inspect for ownership, migrate, or remove them. Running a supported third party's installer copies nothing here: the bytes land in the operator's home, written by the library's own code, under its own name and licence, exactly as if the operator had typed the command. So no donor obligation attaches. These tasks are opt-in and collision-checked, and no gate leaf,contributor:setup, deprecatedsetup, orlifecycle:installpath reaches them —check's dependency closure isvalidate,test,self-test,secrets, andcontributor:setupcontains onlylifecycle:installplushooks:install. Installation is therefore a deliberate choice, never a side effect.
The installer's ownership model is what makes the two coexist: an entry this bundle does not
own is classified foreign and preserved rather than replaced. Decisions and evidence:
docs/adr/0009-external-skill-libraries-are-opt-in-through-their-own-front-doors.md (the
opt-in mechanism) and
docs/adr/0008-third-party-skill-libraries-are-the-operators-own-install.md (the
no-vendoring rule it refines), plus skills/external-skill-libraries/.
skills/agentic-sdlc/: the flagship, provider-native orchestration skill for any skill-capable CLI agent.skills/codex-research-os/: vendored research-team OS — a repo-scaffolding installer (scripts/install_research_os.py) that bootstraps a 17-role research organization (director + specialists), claim/experiment ledgers, greenfield/brownfield workflows, schemas, and Make validation gates into any target repo. Pairs with the flagship'sreferences/research-team.md(the distilled principles).skills/model-tier-rightsizing/: first-class model-routing skill. Load it before any model dispatch. Its four-tier policy pairs exact Sol/Fable for frontier derail work, Terra/Opus for judgment-workhorse silent-degrade work, and Luna/Sonnet for capable-volume visible-retry work; the mechanical floor selects the cheapest certified fully gated route. The canonical calibration records exact IDs, explicit requested effort, transport hazards, evidence boundaries, complements, controls, quotas, and roadmap lanes. Selection is by task fit, independent perspective, quota, and verified transport—not provider preference or artificial all-six representation. The flagship hands off throughreferences/tiered-orchestration.md.skills/dispatching-exact-ocx-models/: exact-route dispatch seam after rightsizing resolves aRuntimeAssignment. It distinguishes generatedocx-*Agent types from Workflowagent()injection, checks model-visible tool compatibility, and requires verified post-run identity.skills/reviewing-overengineering/: independent complexity/deletion audit for one immutable plan or diff. It pairs deletion pressure with a safety-preservation rebuttal and classifies work as essential safety complexity, accidental complexity removable now, or speculative deferral. Ponytail may complement it but is never required.skills/cmux-event-bus-messaging/: optional cmux-only event-bus pub/sub pattern (publish viacmux log --source msg:<topic>, subscribe viacmux eventswith replay/resume, the claim-check pattern, both race gotchas). Pairs withreferences/cmux-integration.mdandscripts/cmux-bus.sh.skills/repo-toolchain-gates/: the standard local gate stack — mise (pinned toolchain incl. CI-parity linter pins + task-runner;mise run check= THE gate), lefthook (pre-commit/pre-push enforcement, installed via mise[tools]), betterleaks (secrets gate incl. full-history scans). Includes the two verified worktree facts: hooks ARE shared into worktrees, mise trust is NOT. Pairs withreferences/seeds-worktrees.md.skills/stacked-prs/: the tool-agnostic stacked-PR methodology — ship a chain of small dependent PRs instead of one fat branch (small-batch rationale, stack structure, bottom-up merge, the restack discipline, when NOT to stack). The PR-landing strategy for dependent Seeds in a wave.skills/stacked-prs-gh-cli/: the same with ONLY plaingh+ git — no gt/spr/ghstack. gh has nostackcommand (v2.95); GitHub's primitives are--basetargeting + explicit retarget/requery/restack. Covers the squash-merge--ontorestack gotcha and--force-with-leasesafety. Pairs withstacked-prs.references/sdlc-loop.md— phase gates, backflow, done criteria.references/seeds-worktrees.md— Seeds queue, native worktree waves, PR flow, optional worker/view adapters, and the canonical in-workspace.worktrees/<seed-id>-<slug>/substrate rule (never a sibling directory).references/worktree-lifecycle.md— one wave worktree end to end, each step with its refusal and recovery: create, gate, review, integrate (squash-preferred, and why), reconcile through the conductor-only record seam, clean up. Includes the executed Git facts behind those refusals.references/cmux-integration.md— optional cmux view/event integration. Load only when cmux is already active or explicitly requested.references/delegation-planes.md— native-first per-provider decision matrices plus optional durable/mixed-engine adapters.references/worktree-integration.md— fan-in hazards: merge-base footprint, placeholder traps, re-gate-on-main, clean-apply ≠ semantic correctness, squash-scope discipline.references/mission-loop.md— the autonomous backlog-zero doctrine: 8-class milestone classification (only ACTIVE_MILESTONE executes), seeds-first no-inline-fixes, WIP caps, priority math, the concurrent critique team, honest definition of done.references/tiered-orchestration.md— model-tier assignment, honest provider/model resolution, the native-first capability ladder with optional adapters, bounded backflow, and worker lifecycle at scale.references/research-team.md— evidence-graded research teams for standing research efforts: the evidence ladder (promote slowly, downgrade quickly), role separation-of-powers (attacker ≠ fixer, writer ≠ originator), one-loop discipline with a recorded next-action, greenfield/brownfield loops, the cheapest-decisive- experiment rule, gates-as-executables (no decorative model pins).
agents/claude/sdlc-*.md+agents/codex/sdlc-*.toml: eight role agents in both CLI forms (symlinked globally) — cartographer (read-only Discover mapper), planner, implementer, reviewer, researcher (bounded unknown-resolution), critic (standing snapshot-only critique team), integrator (the only merging agent), documentarian (read-only documentation worker — evidence-linked doc proposals for conductor capture, writes only its own artifact). Full loop wiring: cartographers (parallel, per area) → planner → implementers → reviewers → integrator, critic concurrent, researchers on demand. Provider-neutral role definitions contain no static model/effort pin, never dispatch, and consume a conductor-supplied certifiedRuntimeAssignmentwith a certified exact model ID.resolution_statemust beresolved. Exact model/effort request injection is mandatory and immutable.resolved_providerandresolved_model_idrequire verified model identity; independently observed provider/model source may be unavailable only for a unique exact-ID mapping backed by immutable request/model evidence. Effective effort/context readback may be honestly unavailable; requested values never become readback. If the assignment is requested, inherited, unresolved, incomplete, or cannot inject both requested model and effort, the conductor stops before dispatch and returns one SeedProposal. Prompt prose does not enforce a Codex model or effort.agents/codex/research/: the 17-role research-team TOMLs (repo-scoped reference copies — NOT globally installed; see its README; scaffolded per-repo by codex-research-os).commands/sdlc-{init,frame,wave,mission,rightsize}.md: Claude Code slash commands —/sdlc-initactivates Agentic SDLC inside a repository without reinstalling global capabilities. It establishes a reviewed tracked Git baseline, Seeds queue, mise/lefthook/betterleaks gate stack, per-worktree trust policy, cross-hostAGENTS.mdguidance, and CI parity. It is a reviewed runbook: claims of idempotence or Git-wave readiness require observed evidence; it preserves existing project policy and stops on ambiguity./sdlc-frameframes one run,/sdlc-waveruns one Seeds-backed Git-worktree wave,/sdlc-missionruns an autonomous backlog-zero mission with concurrent critique and bounded backflow, and/sdlc-rightsizediscovers the operator's live OCX routes plus usable Claude-subscription passthrough, asks only environment-relevant source/model/task/budget questions, and produces a regenerable v2.agentic-sdlc/rightsize/model-task-map.json+.md+.evidence.jsontrio. Published benchmarks nominate candidates; only an explicitly approved, bounded target-local evaluation can recommendrole-qualified, and the checked-in runtime receipt policy still separately controls production admission.mise run rightsize:evaluate -- plan ...is read-only;evaluateconsumes provider/subscription capacity only with its exact displayed authorization digest. Neither a benchmark, local evaluation, nor map authorizes dispatch (seeskills/model-tier-rightsizing/references/model-task-map-schema.md,docs/adr/0015-local-evaluation-is-the-rightsizing-promotion-boundary.md, andskills/model-tier-rightsizing/references/workflow-prompt-budget.md)..claude-plugin/{plugin.json,marketplace.json}: the repo doubles as a Claude Code plugin/marketplace —claude plugin marketplace add <path-or-git-url>thenclaude plugin install agentic-sdlc@agentic-sdlcis an alternative to symlinks. The marketplace source may be this repository's public Git URL, so no clone is required first; see Install as a Claude Code plugin.plugin/is the marketplace entry'ssource: a directory holding the plugin manifest plus real copies ofskills/,agents/claude/,commands/,output-styles/, andworkflows/. It exists because Claude Code discovers agents only in a plugin root's ownagents/, and this repo nests the Claude roster one level down underagents/claude/; installing from the repo root therefore finds the skills but zero agents. Copies, not symlinks, and both shapes were measured on Claude Code 2.1.245 (agentic-sdlc-d0ab): a component directory that IS a symlink is read without being followed, soclaude plugin validate ./plugin --strictexited 1 with one warning per link, and a materialisation carrying only the plugin subtree — what agithuborarchivesource fetches, reproducible offline withgit archive HEAD plugin— left every link dangling and installed at exit 0 while reportingSkills (0) Agents (0). With copies, that same subtree install reportsSkills (18) Agents (8), andclaude plugin validate ./plugin --strictpasses with zero warnings. The argument form decides what is validated: a directory dispatches on the manifest it finds, soclaude plugin validate .validates the marketplace catalog and passes, whileclaude plugin validate .claude-plugin/plugin.jsonwalks the repo root AS a plugin and passes non-strict only — strict flags two deliberate repo files, the rootCLAUDE.mdand the Codex roster README. Pointing a manifest field at the shared tree instead is not available:"skills": "../skills"is refused as a path-traversal attempt.mise run validatere-derives every copy from its source and fails on any drift, so a staleplugin/is repaired withuv run --python 3.12.11 --script scripts/sync_plugin_tree.py --writerather than by hand. The manifest also declaresoutputStylesandworkflows— the two kinds no component walk discovers — and deliberately declares nohooks, because a plugin's hooks surface auto-enables with the plugin.scripts/check-agentic-sdlc-prereqs.sh: native-baseline preflight plus informational checks for optional adapters. Missing cmux or tmux never fails it.scripts/install-skill-bundle.sh: one-shot global install for every native agent CLI present (Claude Code skill+agents+commands, Codex skill+role TOMLs). Symlinks by default;--copyto copy. Never clobbers non-symlink files.scripts/validate-bundle.sh: pre-commit/CI gate — SKILL.md frontmatter, name==dirname, the 1024-char Codex description cap (silent-skip trap), broken references, TOML/JSON parses, shellbash -n, plugin manifest validation, secret/internal-hostname sweep.scripts/cmux-bus.sh: optional cmux-only event-bus helper (pub/sub/seq).
After the bundle is installed, start with one small, local change rather than a mission or a multi-worker plan. Three terms are enough for the first pass: Seeds is the project's durable work queue; a Frame is the short plan for one task; and a Wave is the reviewed worktree execution of ready Seeds.
-
In the target project, if its Seeds queue is absent, route to
/sdlc-initand stop. It is a reviewed activation runbook: it establishes evidence for the Git baseline, queue, gates, and guidance, or stops on a conflict. Do not use Frame or Wave to improvise activation. -
Frame one observable task, for example:
/sdlc-frame Add a hello command that prints "hello" and one test for it.The Frame records the done condition, scope, required gate, review point, queue state, and any outward operation that would need separate explicit approval.
-
If a certified delegation route is available, run the ready task through
/sdlc-wave. Every actual worker or model spawn still requires a conductor-supplied certifiedRuntimeAssignment; an inherited, unresolved, or unverified route stops before dispatch. -
If no certified delegation route exists, the Frame may choose exactly one bounded, non-delegated conductor execution instead. It runs in one clean, dedicated Git worktree with the same framed scope, acceptance criteria, gate, snapshot review, and conductor-only queue reconciliation as a Wave. It has zero workers, zero model spawns, and no
RuntimeAssignmentclaim. It is not a convenience fallback: stop rather than execute when the task needs another worker, another direct pass or retry, parallel work, or cannot be bounded and reviewed. -
Review the stable diff, run the named gate, and reconcile findings before describing the task as complete. A gate, review, queue state, or local status never authorizes a push, PR mutation, merge, publication, deployment, or another outward effect.
The detailed command flow lives in /sdlc-frame and
/sdlc-wave; both route an absent queue back to
/sdlc-init.
The commands below describe the current checkout-backed distribution, which stays the home
for customization, contribution, gates, and release building. A prerelease quick install exists
and is container-proven (2026-08-24, v0.7.4), EXACT-VERSION ONLY: declare
[tools."github:Codeseys-Labs/agentic-sdlc"] with version = "0.7.4" and prerelease = true,
run mise install, and the installed tree exposes exactly one command, ccodex. Running
mise trust on that tree's reviewed mise.toml is a persistent mutation needing your explicit
operation-specific approval; after it, ccodex bundle install --agent claude
activates the plugin. That spelling is retired now — it refuses at exit 2 naming
ccodex install --scope user --agent <claude|codex> — and the sentence keeps the verb it
executed because it records what the container proved, not what to type. Until the acquisition
half lands, mise run lifecycle:install -- --agent claude is the working equivalent on a release
tree: the top-level install is the receipted activation and refuses without an acquired
candidate. The unversioned mise use -g github:Codeseys-Labs/agentic-sdlc does not
resolve a prerelease and is not claimed to work. The release tree carries no .git; gates and
Seeds stay on the managed checkout. Contract, payload split, and boundaries:
docs/plans/2026-08-14T163833Z-Install-UX.md and
ADR-0011 as amended.
If you would rather not choose a directory or track where the tree lives,
scripts/bootstrap-agentic-sdlc.sh fetches this repository into a managed location and then
stops, printing the remaining commands instead of running them. Download it, read it, then run
it — in that order, because it is a script that clones:
curl -fsSL -o bootstrap-agentic-sdlc.sh \
https://raw.githubusercontent.com/Codeseys-Labs/agentic-sdlc/main/scripts/bootstrap-agentic-sdlc.sh
less bootstrap-agentic-sdlc.sh
bash bootstrap-agentic-sdlc.sh --dry-run
bash bootstrap-agentic-sdlc.sh--dry-run prints the exact git clone it would run and creates nothing. --remote <git-url>
selects the exact Git remote (rather than relying only on AGENTIC_SDLC_REMOTE), and --ref
selects its branch or tag. The managed clone lands in
${XDG_DATA_HOME:-$HOME/.local/share}/agentic-sdlc, reported by --print-path and overridable
with AGENTIC_SDLC_HOME; the resolved commit is recorded in
${XDG_STATE_HOME:-$HOME/.local/state}/agentic-sdlc/bootstrap-receipt.json. Its final handoff
prints the receipt, checkout commit, reviewed files, exact trust/toolchain commands, an explicit
Claude-or-Codex install choice, and the status verification command. Removing both paths removes
everything the script created. Re-running is idempotent: it reports the existing clone's ref and
commit, refuses rather than clobbering an unexpected remote, a dirty tree, or a ref mismatch, and
fetches only under --update. --help documents each of those flags without running a tool.
The script requires mise and git and installs neither, so it adds no bootstrap prerequisite. It
deliberately does not trust the config, resolve the toolchain, or install bundle entries: those
stay separate approvals against a tree you have read, and it prints them as steps 2 through 5
below. HTTPS authenticates the transport, not the contents — nothing here verifies a signature
over the fetched commit, so read the tree before trusting it. docs/adr/0011 records why the
clone is managed rather than eliminated: the tasks still come from a tree on disk, because every
task command and installed symlink resolves against one. For a genuinely tree-free install of the
plugin payload alone, see the marketplace plane below.
Five steps, in order, from an empty directory. Step 3 is a persistent mutation with its own approval gate; steps 2 and 3 are what a fresh clone otherwise fails on. The managed fetch above replaces step 1 only.
-
Clone the repository and enter it. Obtaining the source needs Git, which stays a runtime-readiness capability rather than a second bootstrap prerequisite:
git clone https://github.com/Codeseys-Labs/agentic-sdlc.git cd agentic-sdlc -
Review the two files that step 3 authorizes:
mise.toml(the pinned toolchain and every task command) andmise.lock(per-platform source URLs and SHA-256 checksums). Read them before trusting them; the trust decision covers whatever they say at that moment. -
Trust the reviewed config. This is a persistent per-path mutation. It requires explicit operation-specific approval for that exact config path; a general clone, run, or implementation approval never covers it:
mise trust ./mise.toml
Skipping this step is the first-run failure: every later
misecommand in the repository exits withconfig files are not trusted. To validate without persisting anything, usemise --no-config --cd . exec ...instead of trusting. -
Resolve the locked toolchain.
mise.lockpins 12 tools —uv,node,npm,bun,lefthook,jq,ripgrep,fd,gh,betterleaks,opencodex, andseeds-cli— for roughly 1.3 GB and about 30 seconds on a warm network. mise shipsauto_installenabled, so skipping this step does not avoid the cost: the firstmise run <task>installs all 12 without prompting.mise --locked install
-
Choose an install plane explicitly. Claude entries go under the configured Claude home (
~/.claudeby default); Codex entries go under the configured Codex home (~/.codexby default, orCODEX_HOME).--agentis REQUIRED on install, status, and uninstall — there is no default and no wildcard, and a selector-free run refuses at exit 2 naming both planes. To use non-default roots, pass--claude-home <path>and--codex-home <path>after--.mise run lifecycle:install -- --agent claude # or: mise run lifecycle:install -- --agent codex # inspect one plane without writing: mise run lifecycle:status -- --agent claude
A detected Claude marketplace install is reported once as a Claude-plane conflict and blocks only direct Claude installation; Codex continues. Use either the marketplace or direct installation for Claude, not both. Foreign or changed entries are preserved with a reason and a retry instruction; never delete a reported path merely to make the installer green.
-
Nothing further is needed to reach the dispatcher.
bin/ccodexis committed in the tree and self-locates its distribution root as the parent of its ownbin/, so<checkout>/bin/ccodexworks immediately and mise'sgithub:backend exposes exactly that one command on an installed release. There is no install step that writes a second copy into${XDG_BIN_HOME:-$HOME/.local/bin}— see the dispatcher section and, if you ran the retired installer on an earlier release, Retired: the operator-tools PATH plane.
Each bundle lifecycle action ends in a terminal summary. mise run lifecycle:status -- --agent <claude|codex> reports only
entries already present in the lifecycle ownership record: either
no owned entries for this host (run: mise run lifecycle:install)
or an N ok, M conflict, K absent summary — the empty-plane line quoted here in full, remedy hint
included, because the truncated paraphrase is a shape the product never prints
(agentic-sdlc-b97e; tests/test_verification_runbook_contract.py now binds both shapes to
status_summary()'s own returns). It does not inventory unowned names in a configured
collection. Before installation, or when a path may have been installed through another checkout,
use mise run lifecycle:install -- --agent <claude|codex> --dry-run; that read-only preview discovers
an occupied unowned destination, reports it as preserved, and never adopts, overwrites, or removes
it. Install and uninstall summaries separately name installed/removed, preserved, planned, and
conflict counts. mise run check runs the authoritative gate. Each command's exit code and output
are evidence about that run only; neither authorizes any outward effect.
Mise 2026.4.27 or newer is the only bootstrap prerequisite. It is the managed-tool bootstrap,
not the sole readiness prerequisite. The checked-in mise.toml pins uv. mise.lock records
source URLs and SHA-256 checksums for Linux, macOS, and Windows. uv supplies Python 3.12.11
for every authoritative Python entrypoint. Git, a verified Seeds distribution, supported trust
behavior, repository gates, and the selected adapter remain runtime-readiness capabilities, not
additional bootstrap prerequisites. Resolve and record the actual provider/model only when the
adapter proves it; otherwise record inherited or unresolved.
Every v1 dispatch receipt uses exactly requested_model_id, requested_effort,
requested_context_form, request-injection evidence, resolved provider/model identity evidence,
and effective effort/context readback status plus evidence. Request-injection evidence binds
canonical exact requested model/effort/context bytes, adapter identity/version/config digest, and
request-byte digest. It validates internal consistency only: it never proves external injection,
no-bypass enforcement, or spawned-worker identity. Effective effort/context may be unavailable
when the transport does not expose them; requested values never become readback. An external
harness calls receipt admission immediately before spawn and correlates its digest. It remains
responsible for injection, no-bypass, and spawn identity; this repository supplies no host
launcher. Only an admitted, certified tuple can reach spawn. Exact Claude [1m] forms remain
denied pending tuple-specific policy evidence; base Claude eligibility and calibration-supported
GPT [1m] tuples remain. A passing local status or gate never authorizes push, publication, PR
mutation, merge, deployment, credential, or other outward effect.
The flagship skill ships the portable Node-stdlib tools/seeds-launcher.mjs. From an exact clean
Git distribution root, run its explicit bootstrap --distribution <distribution-root> mode under
Node 22.23.2. Both bootstrap and inspect reject any other executing Node. Bootstrap rejects
nested, staged, dirty, untracked, or ignored distribution content, then alone runs reviewed
mise --locked install. That install isolates HOME, mise config/data/cache, hooks, npmrc, and
registry selection from ambient values. Only the reviewed root mise.toml/adjacent lock, the
fixed official npm registry, npm backend, and private empty configs select acquisition. It
resolves exact config-free Node 22.23.2, Bun 1.4.0, and Seeds npm:@os-eco/seeds-cli@0.5.15
roots. It accepts the released package's benign string engines.bun compatibility metadata
while rejecting actual config/macro/preload controls. It atomically publishes an exact Git
commit/tree and tool-hash receipt. The Seeds lock proves the exact version and npm backend, not
tarball or transitive dependency integrity. Neither that claim nor the receipt closes a same-UID
TOCTOU race between validation and execution.
Before any persistent mise trust operation—including the bootstrap below—obtain explicit
operation-specific approval for the exact reviewed config path. The same gate applies to
persistent Codex/global config edits, shell aliases, and credential writes; a general run or
implementation approval is insufficient. Process-scoped validation may instead use
mise --no-config --cd <repo> exec ... without persisting trust.
Bootstrap the repository and inspect the available lifecycle tasks:
mise -C <distribution-root> tasks
<exact-node-22.23.2-root>/bin/node <installed-flagship>/tools/seeds-launcher.mjs bootstrap --distribution <exact-clean-git-root>After explicit bootstrap, read-only Seeds operations use inspect --target <target> against only
the active receipt. Inspect never installs, networks, calls mise, or repairs state. It allows only
--version, prime, ready [--format json], and blocked [--format json]; all other input fails
before exact Bun starts. Exact Node uses shell:false to invoke only absolute recorded Bun and entry
paths. Bun receives --config=<trusted-empty-file>, --no-env-file, and --no-install; its
allowlisted environment isolates target bunfig, .env, package configuration, ambient BUN_*,
NODE_OPTIONS, npm/mise overrides, and unreviewed Seeds debug settings. PATH contains only the
independently recorded Git directory, with system/global Git config isolation.
Queue mutation uses record with --queue-writer conductor. A repository with no .seeds node may
use only --expect-queue absent init; the launcher rejects existing/partial/file/symlink/redirected
surfaces, snapshots .gitattributes, and refuses non-UTF-8 or exact-line/substr-match-ambiguous
prestates before mutation. It invokes exact pinned init --json and verifies exactly the five
initializer files plus only the precise missing merge-union append. Existing queues require an
exact sha256 and admit only verified create/update deltas. Standalone claim, close, delete, prune,
disposition, sync, and other mutation forms remain forbidden. The prerequisite checker exposes
separate exact-runtime inspect, init, and record front doors; the skill and
references/seeds-worktrees.md define their unambiguous contracts.
Mise trust is scoped to each absolute config path. Every linked worktree needs separate
explicit operation-specific approval before trusting its reviewed mise.toml, after reviewing
the diff. MISE_PARANOID=1 deliberately rejects an untrusted worktree. After that approval,
apply MISE_PARANOID=1 mise trust <worktree>/mise.toml, then rerun the command. Locked
resolution fails closed when the current platform is absent from mise.lock.
Every task this repository defines, so mise tasks never reveals an undocumented one:
| Task | Purpose |
|---|---|
lifecycle:install / lifecycle:status / lifecycle:uninstall |
Install, inspect, or remove entries for one plane on the current host. Each requires -- --agent claude or -- --agent codex; a selector-free run refuses at exit 2. |
lifecycle:install:claude |
Install only the Claude Code plane on the current host. |
lifecycle:install:codex |
Install only the Codex plane on the current host. |
lifecycle:install:all-hosts |
Install the current host and, from WSL, the native Windows host too. |
lifecycle:status:all-hosts |
Report current-host and native-Windows state when run from WSL. |
research-os:install |
Scaffold the repo-scoped research OS through pinned uv/Python; pass installer arguments after --. --target is required, so there is no implicit current-directory scaffold. |
claude:statusline:status / claude:statusline:activate / claude:statusline:deactivate |
Inspect or explicitly manage only Claude Code's statusLine fields. |
claude:hooks:status / claude:hooks:activate / claude:hooks:deactivate |
Inspect or explicitly wire one installed agent hook into your Claude settings, one owned hooks.<Event> array element at a time (-- --hook <name>, never "all"). Each activation is its own settings mutation, no lifecycle:* path reaches it, and a foreign or modified element is preserved and reported. |
release:build |
Build the deterministic unpublished-candidate archive of the committed HEAD tree into dist/. Refuses a dirty tree. A built archive is evidence of what was archived, never a release or a publication. |
release:smoke |
Run policy/release-smoke.v1.json against an EXTRACTED archive (-- --tree <extracted-root>). Every case asserts report content rather than a bare exit code, because exit 3 is a legitimate status here. A tree inside this checkout is refused rather than smoke-tested as the artifact. |
usage:report |
Advisory read-only usage projection over the local evidence stores. Subscription cost is always unpriced, the default output is dollar-free, refusals appear in the output itself, and there is no cross-store total because the two stores overlap unprovably. Never a gate leaf, and a report authorizes nothing. |
ocx:launch / ocx:ultracode |
Launch Claude Code through the gateway using your own ~/.claude login — native Claude models on your subscription, gateway models on their own providers — normally or with session-only Ultracode. Ordinary permissions are the default; a first --yolo is the explicit unsafe bypass profile. |
ocx:status / ocx:restart / ocx:configure |
Report opencodex gateway reachability, restart it cleanly, or configure providers through their own login flows. |
libraries:list / libraries:status |
List the installable external skill libraries with their front doors and surface cost, or report which are already present in this home. Read-only. |
libraries:install |
Install explicitly named external skill libraries through their own front doors; dry run unless --yes. Vendors nothing into this tree, and no gate leaf, contributor:setup, or deprecated setup path reaches it. |
libraries:migrate |
De-duplicate a name another channel holds for the same upstream: retire that channel's copies through its own removal path, then install. Dry run unless --yes; names at least one library, never migrates everything. |
mermaid:provision |
Provision the pinned Linux x64 Mermaid browser runtime. Downloads a pinned browser, so it is an explicit operator step and never a gate leaf. |
mermaid:linux-test |
Run the bounded Linux Mermaid renderer tests; they skip with named reasons when the runtime is absent. |
rightsize:evaluate |
Explicit non-gate rightsizing CLI: discover, plan, evaluate after digest-bound approval, or deterministically render prior evidence. Live evaluation may consume provider/subscription capacity and send the selected task-pack data outward. |
validate |
Run the portable bundle validator alone (the pre-commit hook's subset). |
test |
Run the installer test suite. |
self-test |
Exercise install/status/uninstall in an isolated home. |
secrets |
Scan tracked plus nonignored-untracked regular files with the pinned scanner and tracked extend-only config. Symlinks and paths beneath symlinked parents are not followed; ignored runtime state stays out, and history remains a separate consented step. |
check |
Run the authoritative validation, tests, self-test, and secrets gate. Last measured on Linux 2026-08-26: the test leaf ran 2426 tests in 426s (OK (skipped=13)), while validate and self-test each finished in under 5s and secrets scanned about 12 MB in 15s, so the suite dominates and 15 minutes is a reasonable budget — more on a loaded host, since gate runs contend for CPU and I/O. Treat both numbers as stale-by-design: the count grows with the suite, the clock varies by host, and the gate's verdict is the evidence. |
hooks:install |
Install the checked-in lefthook hooks. |
contributor:setup |
Install the configured bundle planes plus this repository's Git hooks. |
setup |
One-release deprecated forwarder to contributor:setup. |
A normal Unix install uses symlinks. On Windows, automatic mode uses directory junctions
for directories and file symlinks for files. When the host cannot create those links, it
falls back to copies. Strict link mode does not use that fallback. The installer records
per-entry ownership in the platform state directory (XDG_STATE_HOME on Unix,
LOCALAPPDATA on Windows). Lifecycle operations use that record to distinguish bundle
entries from user files. Write-capable lifecycle commands are serialized per state file.
Ownership is BYTE identity: a record carries the digest of the bytes this lifecycle published, and
nothing else identifies the destination. There is no birth-timestamp or device/inode requirement, so
there is no minimum libc and no filesystem that has to expose statx birth time — a host where
cp -r works can install. See "Ownership and lifecycle rules" below for what that costs.
mise run lifecycle:install -- --agent claude
mise run lifecycle:status -- --agent claude
mise run checkThe native Windows path runs the ordinary current-host task; it does not invoke WSL. When
lifecycle:install:all-hosts or lifecycle:status:all-hosts is run from WSL, it runs the WSL
current-host lifecycle first and then invokes the native Windows mise task. The two host
summaries remain separate, and the native task's arguments and exit code are preserved.
The Claude/Codex bundle installer and the plugin do not own shell aliases, PATH, or global Claude
settings, and no lifecycle here writes into a PATH directory at all. Writing your settings.json is
a persistent user-environment mutation that requires explicit operation-specific approval for that
exact file; a general install approval never covers it.
The packaged statusline is one bundle ledger row: lifecycle:install -- --agent claude publishes
assets/claude/statusline-command.sh to <claude-home>/.claude/statusline/agentic-sdlc-statusline
at mode 0755, and that owned path is the only place claude:statusline:activate will take a
command from — so a statusline that is absent, unowned, drifted, or unexecutable is a named refusal
rather than a statusLine.command pointing at bytes no lifecycle owns. Installing it does not
activate it; writing statusLine.type and statusLine.command into your settings is the separate
operation-specific grant below.
mise run lifecycle:install -- --agent claude # publishes the owned statusline command
mise run claude:statusline:status # read-only: active | inactive | unmanaged | conflictActivation, dry run, and removal are covered under Which login a launch uses, which is where the settings-mutation grant is described.
An earlier release shipped a separate Unix operator-tools lifecycle that rendered ccodex and
agentic-sdlc-statusline into ${XDG_BIN_HOME:-$HOME/.local/bin} and refused unless that directory
was already on PATH. It is deleted. bin/ccodex is committed, self-locating, and exposed
directly by mise, so a second dispatcher existed only to be placed on PATH by a lifecycle that
would not edit PATH.
Deleting the installer deleted operator-tools:uninstall with it, so if you ran it, you still own
those files and nothing here will remove them for you. ccodex doctor names the leftover
store whenever it is present. Remove them by hand:
rm -f "${XDG_BIN_HOME:-$HOME/.local/bin}/ccodex" \
"${XDG_BIN_HOME:-$HOME/.local/bin}/agentic-sdlc-statusline"
rm -rf "${XDG_STATE_HOME:-$HOME/.local/state}/agentic-sdlc-operator-tools"Two things worth checking while you are there. A stale ~/.local/bin/ccodex earlier on PATH than
mise's shim keeps answering as if nothing changed — type ccodex tells you which file wins. And if
you activated the statusline through the old plane, statusLine.command in your Claude settings
still points into ~/.local/bin; re-run claude:statusline:activate after a
lifecycle:install -- --agent claude so it names the owned ledger path instead. The historical
ocx-launch and ocx-ultracode aliases, if you have them, are removed the same manual way.
ccodex is the whole daily use surface without mise in the way. Plain claude remains the direct
Anthropic-routed CLI; ccodex launch adds the gateway to that same login, so one session serves
both catalogs — native claude ids pass through to Anthropic on your subscription and gateway ids
route to their own providers (ADR-0014). It is not a separate non-Anthropic-only route. Fresh
Nothing here creates ocx-launch or ocx-ultracode; if an old release left you copies, remove them
by hand (see the retirement section). Every gateway command remains reachable as
ccodex ocx <verb>, the low-level compatibility form; ccodex --help prints the surface at any time.
Gateway plane — running one Claude Code session that can reach both catalogs:
| Command | What it does |
|---|---|
ccodex ensure |
Ensure the gateway is healthy without launching Claude Code. |
ccodex launch [--yolo] [claude args...] |
Ensure the gateway is healthy — start it if down, restart once if half-up — then launch Claude Code in the caller's current workspace through the distribution's pinned gateway toolchain, using your own ~/.claude login. Native claude models pass through to Anthropic on your subscription while gateway models route to their own providers, in one session. Fails closed if the gateway never becomes healthy, and refuses (exit 3) when exported, persistent, or explicit --settings configuration would silently defeat the route. Accepted Claude arguments are forwarded unchanged. A first --yolo is consumed by ccodex and explicitly selects Claude Code's permission-bypass mode; it is unsafe outside an isolated, disposable environment. Use -- --yolo only to forward that spelling literally. |
ccodex launch --model <id> |
Pick any id in the running gateway's live catalog, including a namespaced one: --model muse/muse-spark-1.2. Run ccodex models for the list. |
ccodex ultracode [--yolo] [claude args...] |
The same fail-closed launch path with session Ultracode applied. Ordinary permissions remain the default. A first --yolo explicitly selects the same unsafe permission-bypass mode as ccodex launch --yolo; this is the ccodex equivalent of the historical ccode-ultracode alias. Ultracode owns the session --settings value and refuses a competing setting. |
ccodex status |
Read-only supervision view: pid, port, uptime, healthy/down, log location, configured providers each compared against the LIVE catalog, whether anything exported here or in the settings documents Claude Code reads for env would defeat the gateway route — the check NAMES the documents it read and what it did not read — and the attribution log command. Exit 0 means the gateway answered an identity-checked probe at that moment — evidence, not authorization. |
ccodex restart |
Stop the gateway cleanly, then ensure it is back up. Fails closed on an unclean stop. Interrupts in-flight turns in every routed session, and ocx rewrites shared ~/.codex config as part of its lifecycle. |
Providers and models — what a launched session can actually pick:
| Command | What it does |
|---|---|
ccodex providers |
Configured providers, and which are LIVE in the running gateway. A provider in the config file is not live until ccodex restart has published it — check here rather than trusting an add's success message. |
ccodex models |
The running gateway's flat live catalog. Muse models appear as ordinary namespaced entries, not as a separate plane. |
ccodex set-fast-model [<exact-model-id|->] |
With no argument, choose a Claude Code family or a model in the gateway's live OCX catalog, or clear the override to use the normal subscription Haiku slot. One argument preserves the exact noninteractive path; - clears. The write goes through OpenCodex and is not Auto mode's permission classifier. Claude families are entitlement-checked when used; only the OCX rows are proven live when the menu is built. |
ccodex configure |
With no arguments, print the admitted configuration surface in detail. |
ccodex configure provider add|edit|remove|set-default <name> ... |
Reviewed provider mutation for non-Anthropic providers. Writes the config file only — see the key sequence below. |
ccodex configure account add-key <name> |
Store a provider API key, read only from piped stdin. |
ccodex configure account list|current <name> |
Masked credential inspection. |
ccodex configure help <verb> |
Inspect the upstream ocx surface without running it. |
Experimental non-Claude Auto fallback, per launch only. Claude Code exposes no supported
classifierModel setting. The only documented indirect experiment is to exclude Sonnet 5 from one
launch, which makes current Claude Code fall back to the session model when that route is otherwise
eligible:
auto_settings='{"availableModels":["gpt-5.6-sol"]}'
ccodex launch --model gpt-5.6-sol --permission-mode auto --settings "$auto_settings"Use the same exact routed ID in both places and keep all inline settings in that one document.
availableModels constrains session, subagent, workflow, skill, and advisor selection for the
whole launch—not only Auto—and routed GPT/Muse Auto support is undocumented. This recipe is not an
identity claim; a real claim needs a separately approved bounded canary with request-correlated
gateway attribution. See
docs/research/2026-08-12-claude-code-auto-mode-controls.md.
Installed-bundle lifecycle — managing what is installed, without mise:
| Command | What it does |
|---|---|
ccodex install|status|update|uninstall --scope user|project --agent claude|codex |
The one lifecycle verb family. BOTH selectors are required on all four; a run missing either refuses at exit 2 naming the flag, and there is no default and no wildcard for either. --scope project [--project PATH] resolves ONE repository root — the named path, or a walk up from the working directory — and keys that plane by it, so two worktrees of one repository are two independent planes; project scope is copy-only, and an unresolvable, forbidden, or non-git root refuses at exit 3 by name with nothing written. --agent codex refuses project scope by name: its configured root IS its agent root, so it has no repository-local collection. Project scope places the whole selected plane's payload set, workflow bytes included: it is the ONE path that owns a repository's .claude/workflows/ since the per-file claude:workflows:* manager was deleted, so a placement there enables the workflow at the target's next session — every completed project-scope run says so — while hook bytes land inert, since wiring one into settings is its own grant. An already-enabled copy byte-identical to the payload's own bytes is adopted as removable; a drifted one is preserved and named. |
ccodex doctor [--json] |
The whole-box read: every state store, by absolute path, with a verdict each. No selectors — "what is on this machine" spans every scope by definition. Six rows today, each carrying a component, a live/retired kind, and present/absent/unreadable; an absent store is still named, so the count is a fact about this distribution rather than about your machine. This sentence was aspirational until 2026-08-26 — a populated host used to read out three of the six — and it is now checked by a test that re-derives the store set from the source (gh #8 acceptance 9). Naming a store never creates it, and only a retired one carries a removal remedy. |
ccodex recover --dry-run [--json] / --apply <plan-sha256> |
Propose the one pending transition this host can carry and render the digest that approves exactly that plan, or resume it. The approval IS the digest. |
ccodex bundle … / ccodex sdlc … |
Retired. Both refuse at exit 2 with the replacement invocation named. The checkout tasks that shared the bundle name are lifecycle:* now. |
ccodex libraries list|status |
List installable external skill libraries with their front doors and surface cost, or report which are already in this home. Read-only. |
ccodex libraries install <name> [--yes] |
Install a named external library through its own front door. Dry run unless --yes; vendors nothing into this tree. |
ccodex libraries migrate <name> [--yes] |
Retire another channel's copies of the same upstream through that channel's own removal path, then install. Dry run unless --yes. |
ccodex statusline status|activate|deactivate |
Inspect or explicitly manage only Claude Code's statusLine fields. Inactive until you activate it. |
ccodex version |
This command's resolved repository root and runtime dependencies. |
Help, and how to reach the wrapped tool's help. ccodex <verb> --help prints that verb's own
help and runs nothing — no gateway, no session state, no constructed settings. To reach the
help of the tool behind a launch verb, end this command's options with --:
ccodex launch --help # this verb's help; prepares nothing, launches nothing
ccodex launch -- --help # `--` forwards verbatim: Claude Code's OWN help
ccodex launch -- --print "prompt" # any Claude Code argument, through a prepared session
# Claude Code's own help, only if gateway is already healthyproviders and models are the two exceptions: they take no options of their own, so they run
the query rather than printing a help page, and models exits 1 when the gateway is down because
an unanswerable query is a failure rather than a refusal.
Exit codes, uniform across every route: 0 ok · 1 failure or unhealthy · 2 usage ·
3 refused, meaning a boundary declined the operation rather than failing at it.
Only the use surface is installed. The maintenance tasks — test, validate, check,
secrets, self-test, mermaid:*, hooks:install — are deliberately absent, because they
belong to working on this repository rather than to using what it installed; run those with
mise run <task> inside the checkout. One owned dispatcher rather than a dozen named commands
means one ownership record, one place a new verb appears, and no PATH namespace land-grab.
A shell function or alias named ccodex will shadow this command. Bash resolves functions
and aliases before PATH, so a leftover definition silently wins and the installed dispatcher is
never reached — the symptom is ccodex --help printing the wrapped tool's help instead of the
table above. Diagnose with type ccodex: it must report a file inside a distribution tree's own
bin/ — a checkout's, or mise's install directory for the version you selected — not a function, not
an alias, and not a leftover copy in ${XDG_BIN_HOME:-$HOME/.local/bin} from the retired PATH plane.
which ccodex is not enough, since it reports the file that a function is hiding.
provider add writes the provider's SHAPE only. It accepts no key — it has no --api-key
flag and it does not read stdin, so a key piped to it is silently dropped and every later request
fails with 401 invalid_api_key while the routing itself looks correct in the attribution log.
The key goes in through a different verb, and the gateway must already be running and already
restarted when it does. Measured end to end in one clean run on 2026-08-23:
# 1. the gateway must be UP: add-key stores nothing against a stopped proxy.
ccodex ensure
# 2. the provider's shape. No key here.
ccodex configure provider add muse --adapter openai-responses \
--base-url https://api.meta.ai/v1 --default-model muse-spark-1.2
# 3. the PUBLISH step: step 2 wrote the config file, not the running catalog.
ccodex restart
# 4. the key, read only from piped stdin -- never argv, which `ps` exposes host-wide.
printf '%s' "$YOUR_KEY" | ccodex configure account add-key muse --label my-key
# 5. confirm, then use it.
ccodex providers # muse should be LIVE, not merely configured
ccodex launch --model muse/muse-spark-1.2After step 4 the provider carries apiKey and apiKeyPool; before it, only adapter, baseUrl,
and defaultModel. Check with ccodex providers rather than trusting step 2's success message.
Step 3 is the publish step, and step 4 is why it has to come first. add-key validates the
provider against what the RUNNING gateway serves rather than against the config file, so run
between steps 2 and 3 it fails Error: unknown provider for a provider ccodex providers listed
as configured one command earlier, and against a stopped proxy it fails Proxy not reachable.
Measured 2026-08-23 in one container with no Codex installed and ocx sync never run: the restart
alone took the live catalog from 7 ids serving none of the new provider to 420 serving 413 of it,
and the key then stored on the first try. Both constraints are upstream opencodex behavior,
reproduced against the raw pinned binary, and neither is in the configure help — the message says
unknown provider where it means configured but not yet published. What add-key needs is a
running gateway whose catalog already includes the provider, and a restart after the provider add
is the only order that guarantees it. The older 2026-08-08 sequence in
docs/research/2026-08-08-fresh-host-install-verification.md
stored a key before its restart because its ensure came after the provider add and started a
gateway that was down — a cold start rather than a stale one.
Two upstream notes. ocx sync — which the post-mutation notice names — needs Codex installed and
reports Codex config not found on a host without it; the gateway still starts and still routes,
so the restart path above is sufficient. And ocx ensure may log
Provider model discovery ... failed with HTTP 401 [fallback=configured] for a key-authenticated
provider: that is ocx not sending the key on its discovery probe, it is harmless, and the
configured model id is used instead.
Reasoning models need a real token budget. muse-spark-1.2 spent 163 of 176 completion tokens
on reasoning for a two-word answer. A max_tokens that looks generous for the visible reply
returns content: null with finish_reason: "length" — which reads exactly like a broken
credential and is not. Size the budget for the reasoning trace.
A distribution tree is required, and ccodex resolves every tool through that tree's own pins.
ccodex is a thin entry point rather than a self-contained copy: its launcher and Python lifecycle
scripts live in the tree beside it, and it resolves ocx, jq, uv, and the pinned CPython through
that tree's reviewed mise.toml + mise.lock at the moment a verb needs them. Nothing is bound at
install time any more — the retired operator-tools plane was the only thing that ever rendered
absolute tool paths into a dispatcher, and deleting it removed both the binding step and the refresh
step that kept it current. The consequence to know is that the pinned toolchain must be resolvable
in the tree the dispatcher located, and mise itself is found on PATH because it is this
repository's documented sole bootstrap prerequisite. Launch and Ultracode start Claude Code in the
caller's physical current workspace; the tree selects code and runtime identity, not the project
Claude works on. $AGENTIC_SDLC_OCX and $AGENTIC_SDLC_JQ remain caller-supplied exact-absolute
overrides, admitted only as absolute paths, and nothing shipped here sets either.
No shell startup file or PATH value is edited. Every launch route delegates to
scripts/opencodex-claude.sh, so identity-checked supervision and the route-integrity
refusals remain mandatory, including validation of every explicit --settings value before the
gateway starts. The ADR-0005 credential refusal, the environment scrub, and the
separate Claude config dir are GONE from this launcher (ADR-0014): it uses your own ~/.claude
so Claude Code can present its existing login to the gateway. ccodex ultracode refuses a
competing --settings; on either launch form, --yolo refuses competing permission controls.
Launch/restart still carries
opencodex's documented shared ~/.codex
configuration side effect.
There is no muse launcher and no muse:* task. Muse Spark is one provider registered in the
gateway, exactly like the openai/codex provider, and the running gateway serves a single flat
catalog in which its models appear as ordinary namespaced ids. Verified 2026-08-07 against the
live gateway: GET /v1/models returned ten entries — seven gpt-* ids plus
muse/muse-spark-1.1, muse/muse-spark-1.2, and muse/muse-spark-1.2-contributor. So a session
launched with ccodex launch selects a muse model the same way it selects a gpt one, per request
or through the /model picker. Run ccodex models to see exactly what a launched session can
pick; that view reads the gateway's live catalog rather than the configured list, because the two
disagree and only the live one answers the question. Adding a provider goes through the reviewed
configure route with muse as the worked example — nothing about it is special-cased in code.
ccodex launch uses your OWN ~/.claude — configuration, plugins, agents, and login. That is
what lets Claude Code present its existing claude.ai session to the gateway, which is the whole
point of the route (ADR-0014). One session then serves both catalogs, because the gateway decides
per request: a genuine claude*/anthropic* id that no alias or modelMap claims is forwarded
verbatim to api.anthropic.com on your subscription, and every gateway id routes to its own
provider on that provider's credential. No Anthropic credential is used for the routed turns.
Anthropic's gateway documentation describes this
configuration: with ANTHROPIC_BASE_URL set and no gateway credential, "a saved claude.ai
login remains the active credential, so its usage limits and billing apply", and such gateways
"must forward the OAuth capability in anthropic-beta" — which opencodex does, stripping only
hop-by-hop headers plus host, content-length, accept-encoding, x-opencodex-api-key, and
origin. The same page states Anthropic "doesn't support routing Claude Code to non-Claude models
through any gateway", so the routed half is permitted but unsupported. The restriction in
legal and compliance binds third-party
developers routing "on behalf of their users", not an operator routing their own credential
through their own local hop.
Until 2026-08-11 this launcher did the opposite — isolated config dir, full ANTHROPIC_*/
CLAUDE_*/AWS_* scrub, and four refusals aimed at keeping a subscription credential out of
scope. That machinery, the ccodex session verbs, and the separately named
ccodex claude-subscription route are all gone. scripts/muse-claude.sh still keeps its own
isolated plane, so ADR-0010's inheritance and environment-variable policy still govern it, and
ADR-0014 changed nothing inside assets/claude/session-inheritance.sh. That helper did change on
2026-08-18, for ADR-0010's own Amendment A: the CLAUDE_* allow-by-name half is now implemented and
is scripts/muse-claude.sh's only scrub, so a deliberately-set inert flag such as
CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC survives the deny sweep by name (Amendment A.1).
Three route-integrity refusal channels remain, for billing honesty rather than prohibition. A launch exits 3 when the gateway route would not actually be used. None edits anything to fix it: changing a persistent settings file is a mutation that needs explicit operation-specific approval for that exact path, so the launcher reports the blocker and stops instead.
| Refused | Why it matters |
|---|---|
A provider-routing key — CLAUDE_CODE_USE_BEDROCK/USE_VERTEX/USE_FOUNDRY, AWS_BEARER_TOKEN_BEDROCK, ANTHROPIC_BEDROCK_BASE_URL, ANTHROPIC_VERTEX_BASE_URL — exported or in a persistent settings env, or an apiKeyHelper there |
It outranks the gateway. Under Bedrock the client consults ANTHROPIC_BEDROCK_BASE_URL and never ANTHROPIC_BASE_URL, so the session bills the cloud account while the launcher prints a gateway banner. Measured on a real host on 2026-08-10: the request never reached a local capture listener and was still answered. |
An sk-ant-api* Console key in ANTHROPIC_API_KEY/ANTHROPIC_AUTH_TOKEN |
It satisfies opencodex's bare sk-ant- passthrough gate, so it takes the same native branch and bills API credits while looking like subscription traffic. The prefix is the only distinguishing signal. |
An explicit --settings value that is missing, not one JSON object or a readable file containing one, or carries either blocker above |
Claude merges selected settings after the process environment. A local two-listener probe on 2026-08-13 showed selected env.ANTHROPIC_BASE_URL taking every request away from the gateway. Every occurrence is inspected before gateway startup; accepted arguments are forwarded unchanged. |
An sk-ant-oat* login is accepted — carrying it is the point. The checks inspect the minimum needed
names, prefixes, and selected settings bytes; no credential value or selected settings path is
printed, copied, or persisted. ccodex status reports persistent/exported blockers; launch-time
--settings values are checked only on that launch.
Keep a cloud-provider route in a per-command wrapper of your own rather than in the global
settings document, so the two do not fight. ocx claude writes its ocx-*.md roster agents and
the gateway model cache into ~/.claude; that cache write is load-bearing rather than incidental,
because Claude Code only refreshes it while holding a credential, so without it the /model
picker would never list the routed ids.
Help is never a side-effecting operation. ccodex <verb> --help prints that verb's own help
and prepares nothing — it starts no gateway and writes nothing. To reach the help of the tool
behind a launch verb, end the wrapper's options with -- (ccodex launch -- --help).
Mutating your global Claude settings still requires explicit operation-specific approval for that exact file, and no launcher does it: the global document is read, never written, copied, or linked.
The packaged statusline is offline, uses approximate built-in model-family prices only for its advisory subagent breakdown, and is not activated by installation. Changing global Claude settings requires explicit operation-specific approval for that exact settings file:
mise run claude:statusline:activate -- --dry-run
mise run claude:statusline:activate
mise run claude:statusline:status
mise run claude:statusline:deactivateActivation verifies the exact owned executable and mutates only statusLine.type and
statusLine.command; unrelated settings are preserved. A foreign statusline or later operator
edit is preserved and reported as a conflict. This initial surface supports Linux, WSL, and
macOS; native Windows activation fails with a named unsupported verdict.
Inspect ownership, then act:
mise run lifecycle:status -- --agent claude
mise run lifecycle:install -- --agent claude --dry-run
mise run checkOwnership is byte identity. An ownership record names its destination, its mode, and the digest
of the bytes this lifecycle published there. A destination you MODIFIED is refused and preserved,
because your content changes the tree digest or the link target. A destination you replaced with a
byte-identical copy of the bundle's own payload is treated as owned and will be removed by
lifecycle:uninstall — that is a deliberate, bounded weakening (the bytes removed are the bundle's own),
and it is what lets the installer run on filesystems that expose no birth timestamp. AGENTS.md
records the full doctrine.
The installer admits exactly one ownership schema. A document written by another generation is
refused by name — it tells you the version it found and the remedy, which is to remove the state file
and reinstall — and its bytes are never rewritten. There is no --migrate-state flag: the physical
identity witnesses and the transaction journal those older documents carried no longer exist, so
there is nothing a migration could faithfully convert. Diagnose an unowned destination with
lifecycle:install -- --agent <claude|codex> --dry-run and resolve its ownership deliberately.
Crash consistency is one armed pending transition: a write records what it intends durably, moves
the bytes, then commits, and a later run resolves it by comparing the live bytes to the recorded
before/after. Bytes matching neither are reported and preserved. A copy-mode tree swap is a
rename-aside pair rather than one atomic replace, so an interruption inside it can park the previous
tree in a named .<name>.old-* sibling; every such leftover is named in the report for you to remove
by hand and is never deleted for you.
Linux and macOS require their supported namespace durability barriers; failures stop the operation.
macOS uses F_FULLFSYNC for the state document and directory fsync for namespace changes; staged
copy content is not fsynced tree-wide, so a copy-mode install is process-crash consistent rather than
power-loss durable. Native Windows supports process-crash recovery but does not claim
sudden-power-loss durability for namespace transitions. Concurrent external mutation of managed paths
during a write command is unsupported; detected content changes are preserved and reported as
conflicts.
Collection directories are never replaced, and a collection replaced with a link is refused by name rather than followed. An exact legacy bundle link or byte-identical copy may be adopted into ownership. Foreign entries, retargeted links, and modified copies are preserved and reported as conflicts. Uninstall removes only owned entries and leaves conflicts and foreign files in place.
For Claude Code, choose exactly one distribution plane per machine. Use either the direct
bundle install or the Claude marketplace install (claude plugin marketplace add followed
by claude plugin install). Marketplace overlap blocks only the Claude plane; other host
planes can still be managed. Do not register both, because the same skill would appear once
as a bare skill and again under the plugin namespace.
This is the alternative Claude plane described above. It needs no mise, no toolchain trust step,
and no clone you manage yourself — but git is a prerequisite, because marketplace add clones
the catalog for you: its --sparse option is documented as git sparse-checkout, and on a PATH
without git the add fails with Failed to clone marketplace repository. Two commands, from any
directory:
claude plugin marketplace add https://github.com/Codeseys-Labs/agentic-sdlc.git
claude plugin install agentic-sdlc@agentic-sdlcThe first command writes an extraKnownMarketplaces entry to user settings and clones the
catalog; the second copies plugin/ into the versioned plugin cache and writes
enabledPlugins. Claude Code then serves the skills under their own names and the eight SDLC
roles under the plugin namespace (agentic-sdlc:sdlc-planner and its seven peers). The bundled
output style appears as agentic-sdlc:BLUF, taking its name from the file's frontmatter rather
than its filename. Confirm what a given install actually contributes with
claude plugin details agentic-sdlc@agentic-sdlc, which prints the component inventory and a
per-session token estimate.
Add --sparse .claude-plugin plugin to the marketplace add command to limit the catalog clone
to the directories the plugin needs. Those two are now sufficient, and the longer recipe this
sentence used to carry was also a hazard: plugin/ holds its own copies, so nothing in it points
outside itself, where the earlier list omitted workflows and left a link dangling. The installed
plugin is identical either way; only the cached catalog is smaller.
This plane installs context and roles. It does not install the repository gate, the pinned
toolchain, the Seeds launcher, or anything on PATH, so it is not a substitute for the bundle
install when you intend to develop this repository or run its waves.
To remove both records:
claude plugin uninstall agentic-sdlc@agentic-sdlc
claude plugin marketplace remove agentic-sdlcInstalling a plugin is an install-time decision about your own machine, not authorization for any outward effect the plugin's guidance later describes.
hooks:install installs the lefthook subsets from this repository: pre-commit runs
mise run validate; pre-push runs mise run test, mise run self-test, and
mise run secrets. These hooks are best-effort convenience only; mise run check remains the
complete local gate and the command CI mirrors.
scripts/install-skill-bundle.sh remains a compatibility wrapper for existing automation.
It requires mise and invokes the pinned uv/Python installer. It forwards supported arguments
and retains positional status, uninstall, and self-test plus legacy --copy behavior.
cmux and tmux are never prerequisites.
The native host path is available only after capability probes and trust checks succeed:
Use $agentic-sdlc to frame this task and run a bounded,
Seeds-backed worktree wave using the host's native agents.
A capability probe or local status is evidence about that run only; it does not grant authority for an outward effect. Push, tag, PR, merge, deployment, ruleset, credential, and external evidence-store operations each require explicit operation-specific authorization.
Use the native Frame/Wave/Mission flow. cmux remains an independent view/event layer only when it is already active or explicitly requested; tmux is never required. Adapter capability and model resolution must be read back; configuration alone is not proof.
Native host agents, provider-native roles, subagents, workflows, teams, and background tasks are the supported execution mechanisms after capability and trust verification. cmux and tmux are optional integrations, not setup steps or hidden dependencies.