SpecsCLICodex TypeScript MCP
Codex TypeScript MCP: execution plan
Codex TypeScript MCP execution plan
Authority and current state
The user authorized Full Delivery on 2026-09-28. The scope is the retained SPEC (commit d52cf6de) and ARCHITECTURE (commit 3f0809e3), plus GitHub issues #239, #240, #241 and #242. Everything lands on branch spec/codex-typescript-mcp in PR #243. Issue #231 is out of scope: its fix is already on main (ffee129a) and only a release is pending.
- task_identity_mode: provider-task. Typegraph tasks are Linear tasks. Bug tasks are GitHub issues.
- Backlog projection (Linear, workspace Devpunks, Root
HARNESS INTELLIGENCE, Project CLI). The user approved this placement on 2026-09-28.- Initiative IP-456 was reused. Epic IP-476 was created. Milestone
V4.5 Codex TypeScript Semantic Readswas created. - Stories: IP-477 (runtime), IP-478 (entries), IP-479 (health).
- Tasks: IP-480, IP-481, IP-482, IP-483, IP-484.
- Blockers: IP-480 → IP-481 → IP-482 → IP-483. IP-484 is blocked by IP-481 and IP-482.
- All of the above was read back.
- Initiative IP-456 was reused. Epic IP-476 was created. Milestone
- Open product decisions: none. Spike evidence recorded below replaces the unknowns listed in the architecture.
Spike evidence (2026-09-28, Linux x86_64, Node 24.19.0, codex-cli 0.156.1)
- An exact install reproduces the tested dependency set: Typegraph 0.9.56, TypeScript 7.0.2,
@effect/tsgo0.36.5 and MCP SDK 1.30.1.- Command:
npm install --ignore-scriptswith overrides pinning@effect/tsgoand the SDK. - Result: 110 packages, 216 MB. The lock is 88,844 bytes.
- Command:
- The load probe calls Typegraph's
ApiClient.create({projectRoot, tsconfig}), thenprojectFiles().apps/clipasses with 225 files in 187 ms;packages/contractpasses with 8 files.- The root
tsconfig.jsonfails with "0 source files".
- Codex runs
sh -c 'TYPEGRAPH_PROJECT_ROOT="$(git rev-parse --show-toplevel)" exec node <runtime>/node_modules/typegraph-mcp/dist/server.cjs'withTYPEGRAPH_TSCONFIGset.ts_type_inforeturnedstringincodex exec. - Approval mode:
default_tools_approval_modeaccepted"approve","prompt"and unset. All three completed under the globalapproval_policy = "never"incodex exec.- Vendor docs say
approvemeans "Tools execute without user intervention". - Decision: generated entries use
default_tools_approval_mode = "approve". Interactive desktop prompting is not observable on this headless host; it goes in the runbook as a limitation (AC-023).
Locked design
- D1 Registry pin: new Registry item
typegraph-runtime(kind: "tools", no files).- Its
meta.hi.toolRuntimeholds{ id, version, node, server, manifest, lockfile }, wheremanifestandlockfileare exact JSON text. pack-typescriptlists it inregistryDependencies, so the Pack is the only selector (Q10, C4).- Source data lives in
apps/cli/src/data/tool-runtimes/typegraph-mcp/{package.json,package-lock.json}. - Older 6.0.x CLIs ignore the extra meta field (the decode is verified by a test).
cliVersionRangestays unchanged. - The data stores no digest (HI-CLI-004).
- Its
- D2 Tool Runtime: installed at
<dataHome>/hi-tools/typegraph-mcp/<version>, wheredataHomeis$XDG_DATA_HOMEor~/.local/share.- A receipt
.hi-runtime.jsonrecords the SHA-256 of the lock, computed at install time. - A match (same receipt hash and
serverpresent) is reused with no writes (AC-006). - Otherwise: write the manifest and lock to a sibling temp dir, run
npm ci --ignore-scripts --no-audit --no-fund, write the receipt, then atomic rename. - Preconditions:
nodemust be ≥22.18 andnpmmust be on the command environment PATH. A failure returns a reason (AC-005). - Project files are never touched. Nothing deletes the runtime (AC-007).
- A receipt
- D3 Discovery: candidates are
git ls-files -z --cached --others --exclude-standardentries whose basename istsconfig.json.- Excluded: the Recorded Shape
wikiRootsubtree, and solution-only configs (files: []with noinclude). - If one candidate's directory contains another's, both are ambiguous: they are reported and get no entry.
- The settings override
typescript.compilerProjects: string[]replaces discovery with the listed tsconfig paths (AC-010). - Files are parsed read-only as JSONC (AC-011).
- Excluded: the Recorded Shape
- D4 Probe:
node --input-type=module -e <probe>runs withcwdset to the runtime dir, one project at a time, bounded to 4 in parallel with a 60 s timeout each.- It prints one JSON line:
{ok, files, reason?}. - No process outlives the call (AC-031).
- It prints one JSON line:
- D5 Codex entries: HI owns a fenced block in
.codex/config.toml:# BEGIN hi typegraph (generated by hi update; edits are restored)…# END hi typegraph.- The block has one table
[mcp_servers.typegraph_<slug>]per probe-passing project. The slug is the tsconfig dir with non-alphanumerics mapped to_; the root maps toroot. - Fields:
command = "sh"andargs = ["-c", 'TYPEGRAPH_PROJECT_ROOT="$(git rev-parse --show-toplevel)" exec node "${XDG_DATA_HOME:-$HOME/.local/share}/hi-tools/typegraph-mcp/<version>/node_modules/typegraph-mcp/dist/server.cjs"']. The path is portable: no absolute home path. - Also:
env = { TYPEGRAPH_TSCONFIG = "<path>" },enabled_tools= the five reads,default_tools_approval_mode = "approve",startup_timeout_sec = 20,tool_timeout_sec = 60. - Every byte outside the block is preserved. If the block is missing, it is appended. With no eligible projects or the Pack deselected, the block is removed.
- A user table outside the block with the same name is a conflict: it is reported and skipped.
- No top-level
approval_policyis written, and~/.codexis never touched (AC-022).
- The block has one table
- D6 Pipeline step: new STEP between the Installed Record (012) and managed lint (013) in
registry/pipeline.ts, behind an injectable runner.- When
typegraph-runtimeis in the resolved items: runtime → discovery → probe → block. - When it is not: remove the block only (Q20).
- The outcome is attached to
UpdateReportand rendered by lifecycle presentation.
- When
- D7
hi check: optionalsemanticReadsoutput, present when the Installed Record liststypegraph-runtime.- Fields:
runtime {installed, version, path, reason?},registered {servers[], count},compilerProjects[{tsconfig, server, probe: "pass"|"fail"|"ambiguous", registered, reason?}]. - Human output shows them as three distinct lines. Registry
statusis independent (AC-024 to AC-026).
- Fields:
- D8 Guidance (AC-030): a TypeScript-Pack-conditional section in the Built handoff template. It says the five reads are available, and that a tsconfig, dependency or branch change needs a new Codex session. The runbook gets the same text.
Bug fixes (root causes from readonly investigation, 2026-09-28)
- #239:
tools-command.tsnever passes a runtime.tool-management.ts:158defaults tomakeToolCommandRuntime({}), whose empty env has no PATH.- Fix: pass
makeToolCommandRuntime(runtime.commandEnvironment), makeruntimerequired, and deletedefaultRuntime.
- Fix: pass
- #240:
features/operator-skill/target.ts:21-24still hasmaximumExclusive: "6.0.0".- Fix: derive the range from the running CLI major (
<major>.0.0up to<major+1>.0.0), and add a guard test usingversion.
- Fix: derive the range from the running CLI major (
- #241: surface Packs (
frontend,backend) carry no technologies, sopacksForWorkspacenever matches them. Default Packs are also added to every workspace scope.- Fix: in
builders/prompts.ts, gate surface Packs per workspace using the same surface signalsshape.tsuses. Publish the catalog's existingpromptSurfacesinto Pack meta, and route default Packs by it.
- Fix: in
- #242:
- Detection walks the filesystem without git ignore rules. Fix: make
repository-detector.tsandshape.tsevidence skip git-ignored paths, falling back to the current skip list outside git. docsSpecis hard-coded todocs/AGENTS.md. Fix: render it only when adocs/directory exists; the Recorded Shape gets an optionaldocsRoot.hi updatealready re-detects the shape (the claim about a sticky shape is disproved). Stale Software Scopes stay in settings;hi updatenever edits them (remove by hand).
- Detection walks the filesystem without git ignore rules. Fix: make
Tasks and waves
| Task | Identity | Owner (subagent) | Active write scope | Depends on | RED target |
|---|---|---|---|---|---|
| T1 | GitHub #239 | apps-cli-src | cli/tools-command.ts, integrations/tool-management.ts(+test), features/tool-ensure/*, cli/command-surface.test.ts | — | command-surface.test.ts: hi tools ensure --json with fake gh on PATH has no tool-install-failed |
| T2 | GitHub #240 | apps-cli-src | features/operator-skill/target.ts, features/operator-skill/*target*.test.ts, integrations/skills-cli-target-delegation.test.ts | — | policy accepts active version → Resolved |
| T3 | GitHub #241, #242 | apps-cli-src | integrations/repository-detector.ts(+test), registry/shape.ts(+test), registry/builders/prompts.ts(+test), registry/publisher/sources/packs.ts(+test), registry/model.ts (RecordedShape.docsRoot, HiPackMeta.promptSurfaces only), data/catalog/packs.ts read-only | — | React/Next workspace gets frontend skills; misc not in workspace scopes; ignored output/** manifests and .py skipped; no docs.md spec without docs/ |
| T4 | IP-480 (+ probe half of IP-481) | apps-cli-src | new features/typescript-semantic-reads/runtime.ts, probe.ts (+tests), new data/tool-runtimes/typegraph-mcp/* | — | matching receipt → no reinstall; Node <22.18 → reason; probe of files: [] → fail reason |
| T5 | IP-481 discovery + IP-482 block | apps-cli-src | new features/typescript-semantic-reads/discovery.ts, codex-config.ts (+tests) | — | this-repo-shaped fixture → 10 projects, none for root/wiki; block splice preserves outside bytes; restore after edit; remove on empty |
| T6 | IP-480/481/482 wiring | apps-cli-src | registry/model.ts (toolRuntime), registry/publisher/sources/{packs,tools}.ts or new typegraph-runtime.ts, registry/publisher/source.ts, registry/settings.ts, registry/pipeline.ts(+test), cli/lifecycle.ts, data/registry/handoff/AGENT-HANDOFF.md.tmpl, registry/builders/prompts.ts (handoff flag only) | T3, T4, T5 | pipeline.test.ts: TS Pack → block written; no Pack → no runtime/no table; deselect → block removed, runtime kept |
| T7 | IP-484 | apps-cli-src | registry/check.ts(+test), cli/check-command.ts, cli/command-surface.test.ts | T1, T4, T5, T6 | runtime installed + zero tables → installed true, registered false, status current |
| T8 | IP-483 | parent | none (evidence only) | T6, T7 | live hi update on this repo; Codex witnesses AC-027..029; two worktrees AC-019; measurements AC-032 |
| T9 | docs | docs | docs/runbooks/codex-typescript-mcp.md, docs/runbooks/hi-cli-scaffolding.md, docs/README.md, wiki mirrors via sync, IMPLEMENTATION-NOTES.md, CHANGELOG.md, BASELINE_CHANGELOG.md, apps/cli/package.json version | T8 | wiki check:content + tests; release:classify passes |
Waves:
- W1 = T1, T2, T3, T4, T5. Their write scopes are disjoint. T4 and T5 add only new files.
- W2 = T6, then T7. They are sequential because T7 reads T6's pipeline and settings schema, and both touch the report surface.
- W3 = T8, then T9.
- Review follows W3:
review-phase/ autoreview on the branch diff.
Validation gates (shared-machine ceiling on every heavy command)
- Per task: the focused
vitestfiles named above, viasystemd-run --user --scope -p MemoryMax=16G -p CPUQuota=400% nice -n 10 bun run --cwd apps/cli test -- <files>. - After W2:
bun run --cwd apps/cli check-typesbun run --cwd apps/cli lintbun run --cwd apps/cli test:sourcebun run --cwd apps/cli registry:build(HI-CLI-004: items validate, no Managed Artifact hash)
- Docs:
bun run --cwd apps/wiki check:contentplus wiki tests, andgit diff --check. - Release:
bun run release:classify -- --base origin/main --head HEAD.
Rules activated
HI-CLI-001, HI-CLI-002 (version bump), HI-CLI-003, HI-CLI-004, HI-DOCS-001, HI-WIKI-001, HI-WIKI-003, HI-REPO-004 (not applicable: no skill source edits). Each is evaluated in IMPLEMENTATION-NOTES.