Skip to content

v0.53.0

Choose a tag to compare

@elkaix elkaix released this 11 Oct 14:09
· 23 commits to main since this release

Security

  • @modelcontextprotocol/sdk 1.30.0 → 1.32.1 (its OAuth client could send credentials to an authorization server chosen by the MCP server), plus lockfile updates for the fast-uri, ip-address, hono, qs, proxy-addr, and source-map-js advisories; npm audit reports 0 vulnerabilities. CodeQL actions 4.37.7 → 4.38.3; @types/node 26.2.0 → 26.6.5; vitest 4.1.11 → 5.0.3.
  • Producer-authored bytes can no longer steer Git. Diff-family commands always run with --no-textconv and --no-ext-diff; review diffs read attributes from the trusted base with --attr-source=<base> (Git 2.40+, reported by doctor as git-too-old below that), so a committed .gitattributes cannot hide source as binary; Git calls inside a managed worktree pin GIT_DIR, GIT_COMMON_DIR, and GIT_WORK_TREE, so a rewritten .git pointer is ignored; and truncated Git output is a failure everywhere through one gitChecked/gitSucceeded pair.
  • On macOS, project verification runs under Seatbelt with a private scratch TMPDIR, and its evidence records confinement: "macos-seatbelt". The Seatbelt profile denies reads of credential stores under $HOME (.ssh, .aws, .gnupg, .kube, .docker, .netrc, .git-credentials, .config/gh, .config/gcloud, .azure).
  • Autonomous acceptance is stricter. It requires every executed verification command to have run under a known OS confinement backend (a missing policy record fails closed, so off macOS every decision needs a person), and a plain delegate candidate that changes verification inputs — tests, test or build configuration, dependency manifests and lockfiles, .gitattributes/.gitignore/.gitmodules — needs a person too. The decision advisory shown to a human is now exactly the autonomous verdict's reasons.
  • integrateCandidate refuses an acceptance that names no artifact (a legacy record without candidateManifestHash) with decision-artifact-mismatch instead of falling through.
  • Autopilot honors CLAUDE_ARCHITECT_DECISION_AUTHORITY=human: it refuses to start (decision-authority-human), refuses to resume a workflow that still promotes, and the promoter records no autopilot-policy acceptance under it. The acceptance is written only after the exact bytes are staged.
  • A spec's environment can no longer override variables the platform sets (HOME, PATH, TMPDIR, …), and every adapter- or spec-supplied value except absolute paths is redacted from output.
  • The watchdog keeps the Producer in its process group and escalates SIGTERM to SIGKILL on the whole group when the supervisor dies or the child exits, so grandchildren cannot outlive a run. bootstrap.mjs ignores relative PATH entries when locating Node.
  • Dependency inheritance runs cp by absolute path and treats lockfiles over 64 MiB or of different sizes as non-matching.
  • delegation-spec.v1.json bounds every array (maxItems), so an oversized spec is rejected at validation.
  • Review patches in the review snapshot are sanitized (binary payload omitted, redacted), and Git stderr in pipeline errors is redacted.

Changed

  • Plugin renamed claude-architect → architect. Claude Code now reserves plugin names starting with claude-, so claude plugin validate refused the old name. CLAUDE.md moved to .claude/CLAUDE.md, because strict validation rejects it at the plugin root. Install with claude plugin install architect@claude-architect; commands are /architect:delegate, /architect:codex, and /architect:subagent-driven-delegation, and MCP tools are mcp__plugin_architect_runtime__*. The marketplace maps the old name to the new one. The marketplace name, repository, environment variables, Git ref namespace, and .worktrees/claude-architect/ layout are unchanged.

  • Protocol 2.0.0 → 3.0.0. autopilotStart no longer accepts pullRequest, and Autopilot specs and workflow states are v2. Callers pinned to 2.0.0 get an explicit protocol version mismatch diagnostic. Run archives are bound to the protocol major, so runs recorded under 2.x are refused as incompatible; decide and integrate them before upgrading.

  • Final Branch Report v2: the passing status is ready-for-human-review, matching the terminal state, instead of ready-to-ship. A v1 report is refused on resume with an explicit version diagnostic.

  • Autopilot ends at a final-reviewed local branch. It no longer pushes, opens a draft PR, polls required checks, or marks a PR ready; that belongs to the repository's delivery gate (No Mistakes here). Autopilot Spec v2 drops shipping, and Workflow State v2 replaces shipping/ciObservations with branch and drops the pushing, creating-draft-pr, waiting-required-checks, and marking-ready phases; v1 specs and states are refused with explicit version diagnostics. Cleanup keeps the reviewed branch and removes only the worktree and the private base ref.

  • Promotion commits carry the user's own Git author and committer, dated now, instead of a fixed runtime identity dated 2000-01-01. Autopilot refuses to start without a configured identity (git-identity-missing).

  • One state machine owns an Autopilot workflow: start bootstraps and then runs the same resume path, and startup recovery reports an abandoned cleaning-up workflow as resume (the finalize disposition is gone) instead of finishing it with a second proof of the same crash window. Finish it with autopilotResume.

  • Autopilot reads the remote only at create. Revalidation before each promotion and the final review no longer runs ls-remote or re-resolves the remote URL, so a busy upstream main no longer fails a workflow (remote-base-changed and remote-identity-changed are gone), and the workflow runs offline after create. The local base ref still pins the base.

  • Managed worktrees live in each repository's main checkout under .worktrees/claude-architect/<id>, a self-ignoring namespace recorded in the plugin data root so recovery finds it; the legacy state-directory location is still swept.

  • Every pipeline writer, each fixer included, starts in a fresh worktree at the current candidate; its commits are validated and imported into the shared object store before the worktree is removed. A failed promotion now distinguishes a missing candidate commit (sandbox-violation) from a host failure (environment-defect).

  • Optional Jev screen: with CLAUDE_ARCHITECT_JEV=on and TYPESAFE_API_KEY, an otherwise autonomous acceptance is screened by the TypeSafe API over the redacted patch and changed paths. A concern routes the decision to a person; an outage or clear result leaves the deterministic verdict unchanged. It never grants autonomy.

  • Minor and nit findings never block the pipeline gate; every undispositioned blocker or major still requires a human.

  • Weakened-test detection covers Python, Go, Rust, JVM, .NET, and RSpec path conventions and skip markers.

  • Autopilot eligibility is derived directly from the pipeline result, review snapshot, and advisor report, so no self-derived projection is re-checked against itself; a missing candidate is reported as pipeline result has no candidate.

  • The final branch review freezes only the refs it needs (task logs/ transcripts excluded), embeds verification once, and is crash-resumable: evidence files are replaceable, the report is immutable, and a report already published for the same artifact is returned on resume.

  • Lock contention during promotion reports checkout-busy instead of branch-identity-changed.

  • The ls-files output bound is 512 MiB; other Git output stays bounded at 8 MB.

  • macOS bound-directory cleanup removes directories in batches of 64 with one lsof per batch (a 2,040-directory tree went from over 120 s to about 26 s).

  • A checkout-lease release failure after a finished integration keeps the result and appends ; checkout lock release failed instead of discarding it.

  • The slice lifecycle moved out of runPipelineWithLease into SliceRunner (src/pipeline/slice-runner.ts): plan wave, create worktree, launch Producer, freeze, verify, review, compose, release anchor. Run-scoped facts travel as a RunContext value instead of a shared closure, so pipeline-runtime.ts fell from 2464 to ~1540 lines and slice behaviour can be exercised without driving a whole pipeline.

  • One implementation of the slice phase. SliceRunner.run superseded the callback-driven runSlicePhase/SlicePhaseDeps pair, which stayed behind as a second routing loop that nothing called but a test suite still exercised — so the suite proved nothing about the code that runs. The superseded loop is deleted and its evidence-isolation and hard-blocker cases now drive the real runner.

  • One implementation of the managed-worktree lifecycle. withManagedWorktree lives beside WorktreeManager in src/runtime/worktree-manager.ts, and the pipeline, the slice runner, and candidate verification all borrow through it — so creation serialization and the cleanup-failure disposition cannot drift apart, and verification worktrees gain the git worktree add serialization they previously lacked.

  • The slice ref namespace has a single declaration (src/git/ref-namespace.ts). The pipeline wrote refs/claude-architect/slices/ while recovery swept the same literal from its own copy; one declaration makes a silent divergence — refs created but never reclaimed — impossible.

  • Unified candidate evaluation into RunDecision (src/runtime/run-decision.ts). readRunDecisionSnapshot loads a run's result, manifest, review snapshot, gate clearance, and decision once and checks their cross-file coherence in one place; evaluate returns a typed RunVerdict — accepted (autonomous), human-required, rejected, incomplete, or invalid — replacing the accept-only rule that was written twice, in mcp/server.ts and mcp/tools.ts. The decide path now reads the archive once: loadArchivedRun carries the snapshot it read, and the provenance resolver judges that snapshot through the pure verdictFor rather than re-reading five files per caller.

  • pipelineGateCleared is a versioned artifact next to CandidateDecisionV2, with its own canonical schema at runtime/schemas/pipeline-gate-cleared.v1.json. The artifact store validates every durable record against that schema on both read and write, so a malformed clearance is an invalid verdict with a reason rather than a shape-sniffed warning string, and a record that reached disk malformed never reads back as "absent".

  • Acceptance verification takes a named mode — candidate, composed-slice, or final-branch — instead of an injected structural verifier. MODE_STRUCTURAL_FAILURES declares the failure classes each mode may report and now drives structuralVerify, which skips the work that proves a class the mode cannot report. The pipeline's IGNORED_STRUCTURAL_FAILURES filter, the final branch reviewer's substitute verifier and its private finalPathAllowed copy, and the second scope-violation glob in verifyCandidate are all gone: one scope rule, one symlink rule, one manifest recomputation across every mode.

  • runPipelineWithLease is 345 lines, down from 1048. The increment loop, the review rounds, candidate promotion, the halted-slice path, the salvage and archive paths, and the final gate are named functions over one explicit PipelineRunState value, and each phase returns continue or a terminal PipelineResult instead of writing into a shared closure. Status lines after the slice wave default to the last slice index through RunContext rather than a pipeline-local emitter.

  • ArtifactStore is descriptor-driven. One ArtifactDescriptor per archived kind names the file, the read validator, the write-side redaction and validation, and the write mode; every typed façade is one line over a shared readArtifact/writeArtifact pair, and writeArtifact is built on PlatformSafety.writeAtomic. Reads go through the same traversal and identity guards as readEvidence, so no façade carries its own copy of them. tests/runtime/artifact-store-bytes.test.ts pins the archive bytes with hashes recorded from the hand-written façades, so the rewrite is proven byte-identical.

  • The store is bound to its run once. ArtifactStore validated the run id at construction and then took it again on every read; the read façades (readManifest(), readResult(), readDecision(), …) now take no run id, and the ToolArtifactStore, ReviewSnapshotStore, RunDecisionStore, and advisor-stage store interfaces follow. Prune reads each candidate run through a store bound to that run rather than through the caller's.

  • RecoveryDependencies drops requestCooperativeTermination, delayMs, and graceMs, which were retained for input compatibility and did nothing, and takes platformServices whole. recoverStaleRuns no longer rebuilds a PlatformServices by grafting a caller's three methods onto the selected platform — production code that existed only to complete an incomplete test double. Recovery never took a checkout lease through that object; leases come from platformSafety.withRecoveryLease.

  • src/runtime/recovery-manager.ts (3,880 lines, nine concerns) is split into one module per concern: recovery-runs, recovery-prune-journal, recovery-quarantine, recovery-worktree-removals, recovery-worktree-sweep, and recovery-autopilot, over a recovery-shared leaf. recovery-manager keeps only recoverStaleRuns, which sequences them. The declarations moved verbatim, and the modules import in one direction.

  • CI pins every GitHub Action to a commit SHA with its version as a comment, and pins the Claude Code CLI it installs. A wiring test enforces both.

  • Internal deepening (no protocol or on-disk format change): one Cleanup Journal module owns cleanup.ndjson; one Checkout Lock module owns every checkout, recovery and cleanup-journal lock under the owned (link-publish, handle-verified) protocol, with transient Windows errors retried inside the deadline; one Candidate Decisions module owns provenance-to-authority mapping, idempotency and conflicts, anchor removal and the integration and Autopilot acceptance checks (MCP handlers only resolve provenance); one Run Evidence loader gives Autopilot's promoter and final reviewer the union of their former evidence checks; one Worktree Transaction module owns the version-1 manifest, phases and replay (the removal coordinator is gone); durable append, exclusive publish and directory move are shared primitives; roleRunner is the only role-run injection seam; Producer adapters are built from descriptors. Two identity checks are stricter than the plan to leave birth-time comparison where it was, both failing closed: live checkout locks now need a locks directory that reports a birth time, as recovery already did, and report locks directory lacks stable birth-time identity when it does not; and the workflow store's durable write session compares the workflow directory's birth time as well as its device and inode. The cleanup journal's append, which may truncate a torn tail, likewise refuses a runs root without a birth time. On Windows flushDirectory cannot flush a directory handle and is a no-op, so cleanup-journal and workflow-store writes there fsync the file but not its directory entry.

Fixed

  • On Windows, a sliced run in a long worktree path threw git diff failed: … Filename too long instead of recording its halt. Git checks whether each revision argument before -- names a file, and that check exceeded MAX_PATH. Every runtime git diff, diff-tree, log, rev-list, and show call that takes revisions now ends its revisions with --.
  • A pipeline that failed after its candidate passed verification (review cancelled, fixer or adoption failure, an unexpected error) on an unsliced run used to leave an archive a person could accept and integrate; every terminal exit now goes through one terminal recorder that demotes the result with the failure classification, removes the candidate anchor (except for a verification failure), always writes pipeline/pipeline-result.json, and releases authority only after its files are written. Crash recovery archives an interrupted unsliced pipeline the same way.
  • Crash recovery's cleanup-journal appends now go through the same redacting serializer and directory flush as live prunes, and an append after another process crashed mid-write repairs the torn final line first instead of corrupting the journal.
  • A checkout-lock release can no longer delete a lock another holder published in its place, and a dead holder's lock left with its temporary record still linked (a crash between publish and cleanup) is reclaimed instead of staying locked across restarts.
  • A worktree manifest naming the never-written creation-root-changed phase is rejected as malformed (recovery fails closed).
  • Re-sending an identical rejection after its candidate anchor was removed now succeeds against real Git (show-ref --verify exits 128 for an absent ref, which the old check misread).
  • When salvage promoted a candidate and its re-verification then threw, the fallback demoted the pre-promotion attempt and failed to remove the promoted anchor.
  • Directory identity checks use exact 64-bit device/inode values, and wherever birth time is compared it is compared exactly (a recorded zero birth time no longer matches a directory that has one); the archive store, run-start records and the workflow store's directory-identity check still compare device and inode only.
  • An atomic write whose temporary-file cleanup also fails reports both failures, primary first, instead of swallowing the cleanup error.
  • A descriptor-driven Producer adapter with no probe hook reports the edit lane unavailable instead of eligible.
  • The rejected decision advisory for a failed pipeline carries the recorded (redacted) failure reason after its classification, not the classification alone.

Removed

  • The GitHub shipping adapter (src/ship/, about 1,190 lines), the Autopilot v1 spec and workflow-state schemas, and the doctor checks autopilot-remote-recovery-required and autopilot-pr-recovery-required.
  • Duplicate primitives: ten errorCode/isMissing copies (now src/util/errors.ts), three hot-path directory flushes (now flushDirectory), strict identity comparisons (now sameDirectoryIdentity), three workflow-store stable-read copies (now readSingleLinkFile), about a dozen per-file Git success helpers (now src/git/checked-git.ts), the LOCK_NAME/reclaimLocks aliases, the last six NodeJS.ErrnoException casts, and the unused SpecInvalidError, SpawnFailureError, and workflowOwnershipClaimsWorktree.

Documentation

  • The lane docs name current models. The direct Codex skill defaults to gpt-6.1-sol and lists GPT-6 models (gpt-6.1-sol, gpt-6-astra, gpt-6-sol, gpt-6-luna), with the GPT-5.6 models moved to legacy and the max/ultra effort rules restated for GPT-6; the README example, the delegate skill's Codex lane default and the presentation templates name GPT-6.1 Sol; the Pi lane gives xai/grok-4.7 as an example of the model configured in Pi; the Claude Code lane maps opus/sonnet/fable to Opus 5.5, Sonnet 5.5 and Fable 5.1; and the claude-advisor agent names Fable 5.1.
  • AGENTS.md, README.md, docs/SECURITY_MODEL.md, docs/THREAT_MODEL.md, docs/decision-authority.md, the delegate skill, and docs/autopilot-terminal-states.md describe the confinement and verification-input rules for autonomy, the opt-in Jev screen, the .worktrees/ layout, the Git 2.40 floor, and Autopilot ending at a local branch handed to No Mistakes.
  • tests/README.md maps every test file to the module and exported interface it crosses and lists the tests that reach past an interface, with the disposition of each.
  • docs/README.md indexes every document under docs/ as current, historical, or superseded, naming the superseding document where one exists.
  • docs/ARCHITECTURE.md maps each AGENTS.md trust invariant to exactly one owning subsystem and file; SECURITY_MODEL.md, TRUST_BOUNDARIES.md, and THREAT_MODEL.md point at that mapping.
  • docs/MARKETPLACE_REVIEW.md states edit-lane confinement evidence per lane and platform, and says plainly that no lane has native Windows edit evidence and none is claimed — five of the six lanes are unsupported for editing off macOS because macos-seatbelt declares no Linux or Windows platform at all.
  • The delegate skill is 35% shorter (5417 → ~3520 words) with no rule removed: the autopilot and manual lifecycles are one section, the two presentation sections are one, and the sliced pipeline, backgrounded-run monitoring, presentation templates, decision-authority policy, and verification-preflight reference moved to docs/. subagent-driven-delegation no longer restates the spec-authoring, lane-correlation, and decision rules it shares with delegate; it points at them.