codetools / Deploy
codetools deploy
codetools deploys itself with its own deploy engine, the deploy package (SPEC-012). The deployed copy lives in /opt/codetools. Every other consumer runs that copy, never the checkout: Claude's MCP server, the codebase-map hook, orchestrata's realize output and the packages/contracts tests. The checkout is ~/workspace/orchestrata.codetools. This page describes the engine, the launcher that drives it, and the state measured on 2026-10-23. For how this deployment sits among the others on the host, see Deployment.
Sources:
codetools deploy --help;- the
deploymodule docstrings ata5c419f5, read through the AST toolkit; ~/bin/ct-installand~/bin/ct-smoke;/opt/codetools/audit.logand the install logsreports/ct8-install69..75.log;ls,duandreadlinkof/opt/codetools.
Release layout on disk
| Item | Measured 2026-10-23 |
|---|---|
current |
/opt/codetools/releases/58dc55ce7d9ba893/ |
VERSION |
commit a5c419f5720972267039adaf5efc932b19f835a4, repo . |
| release content | the whole repository tree at the commit (src/, tests/, specs/, plans/, reports/, plugins/, uv.lock, ...), plus .venv/ and artifact.json |
| release venv | pyvenv.cfg home = ~/.local/share/uv/python/cpython-3.14+freethreaded-linux-x86_64-gnu/bin; the interpreter resolves to uv's cpython-3.14.7+freethreaded |
| releases kept | 52 directories |
| prefix size | 9.3 GB on /dev/nvme0n1p2, the root NVMe |
entry points in bin/ |
codetools, plus the console scripts of its dependencies (coverage, debugpy, dulwich, mcp, ruff, uvicorn, ...); no orchestrata entry point |
The engine: codetools deploy install
install(repo, ref, prefix, python="python3.14t") "deploys the committed content of a git ref - never the working tree - into prefix/releases/<hash>, with a uv venv built and smoke-checked at that final release path before current ever points at it, then links prefix/.venv, prefix/VERSION and prefix/bin through current/...; an already-current sha is a no-op" (deploy/install.py).
The pipeline has four phases, each a stage with its own gate (deploy/pipeline.py):
- build: a hash-pinned artifact with a deterministic content hash.
- verify: a real SPEC-005 pytest run and SPEC-006 coverage capture against the artifact. It blocks promotion on red tests or on a coverage regression. The full suite is the default;
--affected-scopeopts into affected-set selection, which is marked EXPERIMENTAL. - promote: "atomic: a fully-built staging directory moves into
releases/<hash>with oneos.renameand thecurrentsymlink flips with one moreos.rename; nothing is ever streamed into the live tree; exactly one audit line per switch". A flippedcurrentalso renders the.mcp.jsonfragment (REQ-007-007). - rollback: "restores the exact previous artifact (from the audit log) and re-verifies its content hash".
More rules from the docstrings:
- A verifying promote first checks the source repo's declared toolchain (REQ-012-019,
prerequisites.assert_verify_requires). - Every
uvsubprocess crosses an explicit environment allowlist (ADR-0008), so "ambient toolchain pollution and secrets never reach a build". - A prefix's first release skips verify, because there is no baseline (REQ-012-018, ADR-0003).
- An installed prefix never verifies under
sys.executable(D14).
Identity: codetools deploy verify-identity
"Health is not identity: a unit can report active mid-restart race; verify_identity proves the running units ARE the deployed release" (deploy/identity.py). It checks:
- that
VERSIONagrees with the audit log; - the entry-point shas;
- the live
/procidentity of each unit; - oneshot units, through a sibling timer;
- that no path leaks into
/home/*/workspace.
Every check reports its own name and reason. With --mcp-json, it also requires the registered codetools command to resolve inside the current release.
The launcher: ct-install (the Hermes model, 2026-10-22)
~/bin/ct-install <label> [ref] is the approved way to deploy codetools. It runs without a permission prompt through an allow rule in settings.local.json. On 2026-10-22, Mohamed said "make the installer like hermes". Since then, the launcher builds the release from its lockfile and promotes it with --no-verify, so no test-suite gate runs at deploy time. It then proves the result through the installed command, and rolls the promote back if either proof fails.
What the launcher does, step by step:
- Refusals. It refuses when a
codetools deploy installprocess is already running (RUL-032: one run per code state), whenreports/ct8-install<label>.logalready exists, or when the working tree is dirty. Its own logs and.claude/are the only exceptions to the clean-tree rule. - Environment. It unsets
PYTHONPATHandPYTEST_ADDOPTS. Install 68 died because the scope inheritedPYTHONPATH=/opt/orchestrata-tools/shimfrom the Claude shell, and the suite's import-shadow guard rejected it (commit6979a4ad). It setsPYINFRA_VENV,CC=/usr/bin/gccandCXX=/usr/bin/g++. - Install. It runs
uv run codetools deploy install --repo . --ref <sha> --prefix /opt/codetools --python python3.14t --no-verifyinside a detachedsystemd-run --user --scope, logging toreports/ct8-install<label>.log. - Proof. It runs
/opt/codetools/bin/codetools deploy verify-identity --prefix /opt/codetools --expect-commit <sha>, thenct-smoke <sha>. - Rollback. If either proof fails, it runs
codetools deploy rollback --prefix /opt/codetools, printsROLLED-BACK after a failed post-promote check, and exits 12. - Markers. The log ends with
WALL <seconds>sandINSTALL-EXIT <code>.
ct-smoke <commit> makes three live calls through the installed command:
codetools --versionmust name the commit;ast mapof a two-class scratch repo must report"symbols": 3and writeclass Child(Base)intoCODEBASE_MAP_FULL.md;mcp listmust carry anast maptool.
It prints SMOKE-OK <commit>, or SMOKE-FAIL <check> and exits 1.
The suite-gated verify is still available: run codetools deploy install by hand, without --no-verify. The launcher's comment gives the reason for skipping it: the full verify takes minutes, and on install 72 even --affected-scope "spent 60 s selecting, then ran 8 shards for 3+ min".
Install record, 2026-10-22 and 2026-10-23
| Install | Ref | Outcome |
|---|---|---|
| 69 | 6979a4ad |
stopped by Mohamed ("stop install 69, run the fast install") |
| 70, 71 | 6979a4ad |
INSTALL-EXIT 8: test collection refused the tmpfs /tmp basetemp; fixed by e1ffbc36 |
| 72 | e1ffbc36 |
stopped by Mohamed ("make the installer like hermes") after 60 s of selection |
| 73 | e1ffbc36 |
INSTALL-EXIT 0, 26 s; release a37fbde65c97813a |
| 74 | b518f88a |
INSTALL-EXIT 0, 27 s; release 6ab0e3036ce3f300 |
| 75 | a5c419f5 |
INSTALL-EXIT 0, 43 s; release 58dc55ce7d9ba893; IDENTITY OK a5c419f57209 ยท 0 unit(s) proven; SMOKE-OK |
The audit log holds 52 promote lines. The last three promotes record verify=skipped. The last two verified baseline entries (2026-10-18) were full-scope and red, with 20 and 28 failed tests.
How the codetools deploy relates to orchestrata
- The templates generate orchestrata's components.
codetools realizescaffolds the component packages of orchestrata'spackages/tree into.realize-out*directories. Inwt-MAP-PRECOMMITat8a2cb42ad, 2,882 tracked files sit under.realize-outpaths: contracts 766, kernel 744, volks 447, governance 423, knowledge_graph 270, gateway 134, session 98.packages/contracts/pyproject.tomlsays it was "scaffolded from codetools realize's .realize-out/pyproject.toml". - Generated code imports codetools. The generated tests carry
@tracesfromcodetools.rtm(from codetools.rtm import traces; the decorator is SPEC-015 REQ-015-015). The AST toolkit'swho-imports codetools.rtmoverwt-MAP-PRECOMMIT/packagesfound 2,114 import sites. 2,041 of them are in.realize-out*directories; the other 73 are inpackages/contracts(design26,tests46,increments1). - orchestrata depends on the deployed copy by path. The
packages/contractstestgroup listscodetools, withcodetools = { path = "/opt/codetools/current", editable = true }. It is an editable install of whatever releasecurrentpoints at. - codetools no longer depends on orchestrata (commit
a5c419f5, 2026-10-23 00:01).read_requirementstakes the OpenSpec provider as a parameter and defaults toresolve_openspec(). That function importsorchestrata_tools.openspec, thenorchestrata_ultimate.openspec, and refuses with a message namingcodetools[openspec]when neither is installed.orchestrata-ultimatemoved from a hard dependency to theopenspecextra and the dev group. The commit message records that in an environment without the extra, "codetools --version and ast map both run with 0 orchestrata packages installed". - orchestrata's config deploy registers codetools.
install-claude-config.shrenders the MCP fragment, registers it and proves identity (see codetools MCP). - Every project's codebase map comes from codetools. The user-level hook
codemap_refresh.sh(SessionStart and SubagentStart) runsenv -u PYTHONPATH /opt/codetools/bin/codetools ast map <root> --with-fullin a repo that opts in with a[tool.codetools.map]table. It logs to~/.local/state/codetools/codemap-hook.log.
Open question: where codetools is hosted
The codetools repository has no git remote (git remote -v is empty on 2026-10-23). Everything that consumes it reaches it by local path:
- the plugin marketplace is a
directorysource at~/workspace/orchestrata.codetools; ct-installinstalls from--repo ., andVERSIONrecordsrepo .;- orchestrata's
packages/contractspins/opt/codetools/current.
Nothing is backed up off this machine, and no other machine can install codetools from a ref. The question is open and has not been ruled:
| Option | What changes | For | Against |
|---|---|---|---|
A. A GitLab remote for orchestrata.codetools (the MSamy GitLab, like hermes and the orchestrata repo) |
push master and tags. The plugin marketplace becomes a git source, like the orchestrata plugin. ct-install and orchestrata pin a commit of the remote. |
codetools stays a separate, project-agnostic tool with its own release engine and ADR log (ADR-0020, ADR-0030, ADR-0038). Matches how hermes and the orchestrata plugin are deployed. Gives an off-machine copy. | Two repos to keep in step. orchestrata's realize output still pins a codetools release by path until a published wheel or a git pin replaces it. |
B. packages/codetools inside the orchestrata repo |
codetools becomes one more component of orchestrata's packages/ tree and ships with orchestrata's ship. |
One repo and one ship. The realize output and its codetools.rtm dependency live beside each other. |
codetools is used outside orchestrata: by the codemap hook in every project, and by the plugin, which its README describes as "for a work computer whose only agent is Claude Code". Its separate release engine, its /opt/codetools deploy and its 44 ADRs would have to fold into orchestrata's. The role of packages/ is itself still disputed. |
Recommendation: A. It keeps codetools project-agnostic, matches the existing GitLab-sourced deployments, and closes the no-remote gap without moving code. This is a recommendation only. It becomes a decision when Mohamed rules on it, and then an ADR in docs/adr/.