Development and release verification¶
bridge_CC-Codex is a standalone Python 3.10+ plugin package. Its normalized plugin identifier is bridge; both manifests must keep that name and the same version. Its Claude Code manifest is .claude-plugin/plugin.json; its Codex manifest is .codex-plugin/plugin.json; its Codex reverse-transport declaration is .codex-mcp.json. Claude Code has no MCP declaration at all -- the plugin ships no .mcp.json, since Claude Code auto-discovers any file by that literal name at a plugin's root and the Claude-to-Codex direction needs no MCP.
Source layout¶
bin/bridge_call.pyowns request normalization, peer command construction, supervision, compact-result validation, artifacts, and health logging. Implement requests are write-capable; review requests use read-only general Codex execution with an explicit adversarial-review prompt rather than Codex's native review subcommand.bin/bridge_mcp.pyowns the stdio MCP protocol and the five Codex-facing toolsbridge_implement,bridge_advise,bridge_review, the zero-providerbridge_statussession/workspace evidence tool, andbridge_bind_workspace.bin/bridge_diagnose.pyowns static host-surface checks and optional live diagnosis. The baseline is deliberately flag-only — it pins no CLI version number, because a depended-on flag disappearing from--helpis the failure that actually breaks dispatch — and the free static check reports without appending health records; only completed bridge requests writehealth.jsonllines.bin/bridge_setup.pyowns deterministic setup argument parsing, capability inspection, expiring one-use action approvals, user-scoped locks and credential-free records, post-configuration reinspection, provider-owned no-capture authentication, and approval-bound live verification. Host skills own decision flow and prompts; the planner never accepts credentials or model-selected workspace overrides.schemas/contains the model-core, harness-envelope, MCP input, and setup-result contracts. The setup-result schema is not a model-run envelope and must not gain transcript, token, cost, or model-verb fields.rules/contains the effort, prompting, recursion, envelope, and recovery policies used by both host integrations.claude-skills/contains Claude Code commands;codex-skills/contains Codex commands. Both host trees exposeimplement,advise,review, and the approval-boundsetuplifecycle.tests/proves runtime, contract, setup approval/no-capture boundaries, cross-platform, and install-shaped package behavior.
Keep public names, schemas, manifests, skills, and README examples synchronized when a user-facing behavior changes. Do not make the package depend on a source checkout, another plugin, or a private workspace path.
Local checks¶
Run the focused plugin suite:
Format and lint changed Markdown through the pinned pre-commit hook:
pre-commit run mdformat --files plugins/bridge_cc-codex/README.md plugins/bridge_cc-codex/docs/architecture.md plugins/bridge_cc-codex/docs/security.md plugins/bridge_cc-codex/docs/operations.md plugins/bridge_cc-codex/docs/development.md plugins/bridge_cc-codex/CHANGELOG.md
Check whitespace and build an install-shaped package outside the source tree on Linux or macOS:
git diff --check -- plugins/bridge_cc-codex
disposable_parent_directory="$(mktemp -d)"
python plugins/bridge_cc-codex/scripts/build_package.py --output "$disposable_parent_directory/bridge"
python plugins/bridge_cc-codex/scripts/validate_package.py "$disposable_parent_directory/bridge"
Use the native PowerShell equivalents on Windows:
git diff --check -- plugins/bridge_cc-codex
$disposableParentDirectory = Join-Path ([System.IO.Path]::GetTempPath()) ("bridge-" + [System.Guid]::NewGuid())
New-Item -ItemType Directory -Path $disposableParentDirectory | Out-Null
$disposablePackageDirectory = Join-Path $disposableParentDirectory "bridge"
& python plugins/bridge_cc-codex/scripts/build_package.py --output $disposablePackageDirectory
& python plugins/bridge_cc-codex/scripts/validate_package.py $disposablePackageDirectory
The package validator rejects symlinks, private artifact directories, private absolute paths, malformed JSON, missing runtime closure, unresolved manifest paths, and version mismatches. The disposable build excludes tests, caches, .DS_Store, and temporary bridge state. The public envelope must remain compact: decisions, blockers, and remaining work belong in public fields, while bounded peer details belong only in the bounded transcript with workspace-relative transcript and incident references returned as metadata. The setup result is validated independently and carries only credential-free lifecycle evidence; sensitive authentication output is never an artifact.
Behavioral verification¶
When changing the bridge runtime, add or update a public-contract test that would fail under a plausible incorrect implementation, then run the complete plugin suite. Exercise both directions where the change affects transport, and inspect the compact returned envelope plus .temp/bridge artifacts for timeout, refusal, authentication, and partial-result behavior. For setup changes, test the default all/peer/auto/prompt plan; exact action/workspace/state binding; expiry and success/failure replay rejection; cross-workspace locking; non-symlink user-state records; post-configuration reinspection; safe denial; no-capture authentication; approval-bound live verification; rollback boundaries; bridge_status; explicit two-form workspace binding, stale binding identities, cancellation, directory retargeting, installed cache guards; and sync's static-only dispatch. Live setup probes are optional and require explicit operator approval because they invoke authenticated provider inference; static setup alone does not verify provider or schema compatibility.
Before a release, verify both host manifests, the .codex-mcp.json plugin-relative cwd: "." and bin/bridge_mcp.py script arguments, that no .mcp.json ships at the plugin root, the five MCP tool schemas, the setup-result schema, the version in CHANGELOG.md, and the install-shaped package. Confirm ordinary sync invokes only the direct static doctor and that no setup path stores authentication material. Remote marketplace publication and host installation remain operator-owned actions after these local gates pass.
The standalone bin/bridge_consent.py stage tests native user configuration only in disposable homes: absent/check/decline and unapproved noninteractive paths never grant; explicit grant --approve works with closed stdin, preserves unrelated TOML and is recognized by the next check; the flag is rejected with check or revoke, even when consent exists. Repeated grant is idempotent; interactive revoke removes only the owned block; drift and unsafe files fail closed. The installed-shape scenario also grants with the explicit flag and checks the resulting consent. Skill contract tests retain explicit user-flag provenance and separate setup approvals. The repository policy-sync regression grants, synchronizes, revokes and synchronizes again to prove consent preservation without resurrection. These local checks do not establish a live native reviewer decision.