Skip to content

refactor(engines): migrate codex and scheduled-agents onto the capture core - #67

Merged
imran-siddique merged 1 commit into
mainfrom
feat/migrate-codex-scheduled-v2
Jul 31, 2026
Merged

refactor(engines): migrate codex and scheduled-agents onto the capture core#67
imran-siddique merged 1 commit into
mainfrom
feat/migrate-codex-scheduled-v2

Conversation

@imran-siddique

Copy link
Copy Markdown
Contributor

Completes the migration begun for claude-code in #66. All three engines now delegate hashing, component tree digests, the exclusion denylist, comparison shapes, observed and scope gating, and state read/write to the shared core, each with the vendored fallback so a bare install still works.

Net -64 lines across the two engines, and one implementation of the logic that previously carried the same bypass in two places (#63, #65).

The proof it is behaviour-preserving

Test files are untouched in all three engines. That is the point: the contract does not move, so identical behaviour is demonstrated rather than asserted.

Suite Result
claude-code 59 passed
agentrust-codex 25 passed
scheduled-agents 21 passed
capture-core 45 passed

The one Codex failure is the pre-existing TRACE conformance check that fix/codex-trace-pins addresses.

Four things I deliberately did NOT unify

Each because unifying would have been silently wrong rather than merely different. This is the interesting part of the diff.

codex._safe_hash rejects symlinks; the core's does not. Codex resolves instructions and policy from per-workspace paths, so a cloned repo could point a symlink at a file outside the tree and have its contents recorded as if they belonged to the workspace. The stricter version stays local, with the reason in the docstring.

codex._atomic_write writes 0o600, because the same helper writes the Ed25519 signing key. Rather than lose that, the core gained an optional mode parameter, applied before the replace so the file is never briefly readable at wider permissions.

codex._save keeps sorted keys and a trailing newline. Switching to the core's format would rewrite every existing state file for no behavioural gain. The digest is computed over the mapping, not the bytes, so the formats are interchangeable in meaning.

scheduled-agents._sha_obj takes arbitrary objects, not just mappings: it is called on lists of allowed tools and MCP server names.

Same reasoning as _sha_tree in #66. A shared core is only worth having if the things that genuinely differ are allowed to differ, and are documented where they do.

Not included

Baseline sealing for codex and scheduled-agents. Both lack it and both would benefit, and it is now nearly free via core.save_baseline. But it is a feature addition rather than a migration, and it touches their report layouts and hook messages, so it stays separate to keep this PR reviewable as a pure refactor.

Test plan

  • All four suites pass, no test file edited.
  • ruff check --target-version py39 clean across all three engines, the package, and scripts/.
  • Vendored sync check passes after re-syncing the mode addition.
  • Bare-install path: with the core not installed, all three engines import and use the vendored copy.

…e core

Completes the migration begun for claude-code. All three engines now delegate
hashing, component tree digests, the exclusion denylist, comparison shapes,
observed and scope gating, and state read/write to the shared core, with the
vendored fallback so a bare install still works.

Test files are untouched in all three engines. That is the point of the exercise:
behaviour is proven identical by not moving the contract. claude-code 59, codex 25,
scheduled-agents 21, core 45.

Four behaviours deliberately stayed local, each because unifying would have been
silently wrong rather than merely different:

  codex _safe_hash rejects symlinks and the core's does not. Codex resolves
  instructions and policy from per-workspace paths, so a cloned repo could point a
  symlink at a file outside the tree and have its contents recorded as if they
  belonged to the workspace. The stricter version stays.

  codex _atomic_write writes 0o600, because the same helper writes the Ed25519
  signing key. Rather than lose that, the core gained an optional mode parameter
  applied before the replace, so the file is never briefly readable at wider
  permissions.

  codex _save keeps sorted keys and a trailing newline. Switching to the core's
  format would rewrite every existing state file for no behavioural gain; the
  digest is over the mapping, not the bytes.

  scheduled-agents _sha_obj takes arbitrary objects, not just mappings: it is
  called on lists of allowed tools and MCP names.

The core also gained the mode parameter noted above; the vendored copies are
re-synced and the sync check passes.

Not included: baseline sealing for codex and scheduled-agents. Both lack it and
both would benefit, but that is a feature addition rather than a migration, and it
touches their report layouts and hook messages. Kept separate so this PR is
reviewable as a pure refactor.

ruff clean at py39 across all three engines, the package and the scripts.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Imran Siddique <imran.siddique@opaque.co>
@imran-siddique
imran-siddique merged commit 903a0de into main Jul 31, 2026
26 checks passed
@imran-siddique
imran-siddique deleted the feat/migrate-codex-scheduled-v2 branch July 31, 2026 23:49
imran-siddique added a commit that referenced this pull request Aug 1, 2026
#67 added the mode parameter to core.atomic_write while this branch was open, so
the copilot vendored copy was a version behind. Caught by the vendored-in-sync
job against the merge with main, which is exactly what that check is for.

Signed-off-by: Imran Siddique <imran.siddique@opaque.co>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant