Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save arikon/7637501a7187db747d73c978e5c039ad to your computer and use it in GitHub Desktop.

Select an option

Save arikon/7637501a7187db747d73c978e5c039ad to your computer and use it in GitHub Desktop.
Cumulative experimental native Ultragoal receipt transport patch against dev@73cb50c1, head d20a357e; includes nested review-blocker resolver-chain reconciliation
diff --git a/AGENTS.md b/AGENTS.md
new file mode 100644
index 0000000000000000000000000000000000000000..b3140ed57e0e037bd5e9ebc7c555ac0796921ffb
--- /dev/null
+++ b/AGENTS.md
@@ -0,0 +1,144 @@
+# Local development rules
+
+## Test a local OMX build through the installed runtime
+
+For acceptance checks, test the packed installation that Codex hooks actually execute. Do not use a symlink, `npm link`, a source-tree wrapper, or an `OMX_SESSION_ID`/`CODEX_THREAD_ID` override.
+
+1. Finish build, focused tests, lint, no-unused checks, independent review, and `git diff --check` before packaging. Do not run tests concurrently with `npm pack`: prepack rebuilds `dist`.
+ Session/state tests must save, clear, and restore ambient `CODEX_THREAD_ID`, `OMX_SESSION_ID`, and `OMX_NATIVE_ULTRAGOAL_BACKEND` when they exercise another authority branch. Tests launched from Codex inherit real thread/config context; leaving it ambient can silently select the App-native recovery path instead of the branch under test.
+2. Pack into a new directory with a new npm cache. Reusing the same tarball path/cache can reinstall stale bytes for an unchanged package version.
+3. Invoke npm with the intended Node runtime and pass the intended global prefix explicitly. Calling an NVM `npm` symlink is insufficient when its `#!/usr/bin/env node` resolves Homebrew Node.
+
+Run build and npm scripts through the pinned Node/npm pair as well. An ambient `npm run build` can execute under another Node version even when the NVM npm path looks correct.
+
+```sh
+node_prefix=/Users/arikon/.nvm/versions/node/v24.18.0
+
+"$node_prefix/bin/node" \
+ "$node_prefix/lib/node_modules/npm/bin/npm-cli.js" \
+ --prefix "$PWD" run build
+
+"$node_prefix/bin/node" --test \
+ --test-name-pattern='<focused regression>' \
+ dist/<test-file>.test.js
+```
+
+```sh
+node_prefix=/Users/arikon/.nvm/versions/node/v24.18.0
+pack_dir="$(mktemp -d /private/tmp/omx-pack.XXXXXX)"
+
+"$node_prefix/bin/node" \
+ "$node_prefix/lib/node_modules/npm/bin/npm-cli.js" \
+ pack --pack-destination "$pack_dir" --cache "$pack_dir/pack-cache"
+
+"$node_prefix/bin/node" \
+ "$node_prefix/lib/node_modules/npm/bin/npm-cli.js" \
+ install -g "$pack_dir/oh-my-codex-0.20.3.tgz" \
+ --prefix "$node_prefix" \
+ --cache "$pack_dir/install-cache" \
+ --force
+```
+
+The npm install updates the package runtime but does not refresh setup-owned copies under `~/.codex/skills`, `~/.codex/prompts`, `~/.codex/agents`, or `~/.codex/hooks.json`. Refresh them from a disposable working directory so user scope cannot rewrite the repository's `AGENTS.md`:
+
+```sh
+setup_dir="$(mktemp -d /private/tmp/omx-user-setup.XXXXXX)"
+(
+ cd "$setup_dir"
+ PATH="$node_prefix/bin:$PATH" \
+ "$node_prefix/bin/omx" setup \
+ --force --scope user --legacy --no-merge-agents --verbose
+)
+
+PATH="/Applications/ChatGPT.app/Contents/Resources:$node_prefix/bin:$PATH" \
+ "$node_prefix/bin/omx" doctor
+```
+
+Keep the application bundle and Node prefix in `PATH` for `doctor`; otherwise it can report a false missing Codex CLI or inspect OMX under an unrelated Homebrew Node.
+
+The version in the tarball filename must match `package.json`; do not copy this example version blindly after a bump.
+
+After installation, prove that the target is a normal directory and that behavior-bearing files match the fresh build. Checking only `dist/cli/omx.js` or the hook is insufficient because those entrypoints may be unchanged while imported modules differ.
+
+```sh
+install_dir=/Users/arikon/.nvm/versions/node/v24.18.0/lib/node_modules/oh-my-codex
+test ! -L "$install_dir"
+
+shasum -a 256 \
+ dist/cli/state.js "$install_dir/dist/cli/state.js" \
+ dist/state/operations.js "$install_dir/dist/state/operations.js" \
+ dist/ultragoal/native-bootstrap.js "$install_dir/dist/ultragoal/native-bootstrap.js" \
+ dist/scripts/codex-native-hook.js "$install_dir/dist/scripts/codex-native-hook.js"
+
+diff -u skills/code-review/SKILL.md "$install_dir/skills/code-review/SKILL.md"
+diff -u skills/ultragoal/SKILL.md "$install_dir/skills/ultragoal/SKILL.md"
+
+# setup normalizes the installed description to an `[OMX]` prefix; compare
+# the behavior-bearing body after frontmatter separately.
+tail -n +5 skills/code-review/SKILL.md | shasum -a 256
+tail -n +5 "$HOME/.codex/skills/code-review/SKILL.md" | shasum -a 256
+tail -n +5 skills/ultragoal/SKILL.md | shasum -a 256
+tail -n +5 "$HOME/.codex/skills/ultragoal/SKILL.md" | shasum -a 256
+```
+
+Also verify that `~/.codex/hooks.json` names this exact install root and intended Node binary. `nativeUltragoal.backend=local-experimental` belongs in `~/.omx/config.json` for the native acceptance flow.
+Because `omx setup --force` rewrites setup-owned surfaces, re-read `~/.omx/config.json` after every setup and prove that `nativeUltragoal.backend` is still `local-experimental` before starting acceptance.
+
+## Live Codex CLI acceptance
+
+Use the application-bundled CLI directly:
+
+```sh
+node_prefix=/Users/arikon/.nvm/versions/node/v24.18.0
+
+env -u CODEX_THREAD_ID \
+ -u OMX_SESSION_ID \
+ -u TMUX \
+ -u TMUX_PANE \
+ -u GIT_PAGER \
+ -u PAGER \
+ -u GIT_EXTERNAL_DIFF \
+ -u GIT_EXEC_PATH \
+ -u GIT_CONFIG_COUNT \
+ -u 'BASH_FUNC_git%%' \
+ PATH="$node_prefix/bin:$PATH" \
+ /Applications/ChatGPT.app/Contents/Resources/codex \
+ -a on-request \
+ exec \
+ -C /private/tmp/<fresh-smoke-directory> \
+ -s workspace-write \
+ --dangerously-bypass-hook-trust \
+ --json - < /private/tmp/<fresh-smoke-directory>/prompt.txt
+```
+
+- Start acceptance with the explicit top-level `-a on-request` option before
+ `exec`. Do not use `-a never` or
+ `--dangerously-bypass-approvals-and-sandbox`: managed Codex installations can
+ reject the implied `Never` policy and fall back to `UnlessTrusted`; in
+ non-interactive `codex exec`, that fallback cannot service approval requests
+ and rejects otherwise valid OMX commands before they start. Under
+ `on-request`, keep the acceptance prompt free of escalation requests so the
+ tested commands run inside the declared `workspace-write` sandbox.
+- Use a fresh canonical `/private/tmp/...` git repository for every run. `/tmp` may normalize differently on macOS.
+- Clear inherited `TMUX` and `TMUX_PANE` at the `codex exec` boundary. A Desktop-launched CLI can inherit an unrelated OMX tmux context; acceptance must prove transcript-bound native bootstrap behavior, not accidentally select the tmux workflow lane.
+- The bundled CLI must be able to write its own `~/.codex/state_*.sqlite` and session files. `attempt to write a readonly database` or `failed to initialize in-process app-server client: Operation not permitted` before normal turn execution is a harness sandbox failure, not an OMX acceptance result; rerun from a boundary that permits the normal Codex home writes.
+- Put the installed runtime's `bin` directory first in the parent `PATH` before starting Codex. The npm-installed `omx` launcher uses `#!/usr/bin/env node`; without the pinned `PATH`, bare `omx` may be missing and an absolute launcher can silently run under an unrelated Homebrew Node.
+- In the acceptance prompt, require the agent to invoke `/Users/arikon/.nvm/versions/node/v24.18.0/bin/omx` explicitly. The Codex tool subprocess may not preserve the parent shell's command lookup even when the outer `codex exec` process received the right `PATH`; the absolute command also makes hook classification deterministic.
+- Start the acceptance process without inherited Git helper/runtime overrides such as `GIT_PAGER`, `PAGER`, `GIT_EXTERNAL_DIFF`, `GIT_EXEC_PATH`, or `GIT_CONFIG_*`, and without imported `BASH_FUNC_git%%`. The Conductor classifier intentionally fails closed on those values because a syntactically read-only `git` command could otherwise execute caller-controlled helpers. The example explicitly removes both pager variables commonly injected by automation shells.
+- Native review children remain read-only without an executor assignment. In active Conductor mode, prefer native read tools. For Bash evidence on macOS use only classifier-modeled root-owned absolute readers; `/bin/cat` is the least ambiguous choice. `find` must use one of the bounded modeled forms, and Git evidence must use the exact hardened command below. Do not treat bare Homebrew/NVM tools such as `rg` as authoritative: their executable path is user-writable and can be shadowed.
+- For executor status evidence, do not use plain `git status --short`: Codex tool subprocesses may inject Git runtime variables, so the hook correctly cannot prove that spelling read-only. Use the exact hardened form `GIT_ATTR_NOSYSTEM=1 GIT_CONFIG_COUNT=0 GIT_CONFIG_GLOBAL=/dev/null GIT_CONFIG_NOSYSTEM=1 GIT_CONFIG_SYSTEM=/dev/null GIT_EDITOR= GIT_EXTERNAL_DIFF= GIT_PAGER= GIT_SEQUENCE_EDITOR= PAGER= /usr/bin/git --no-pager --no-optional-locks -c core.fsmonitor=false -c core.untrackedCache=false -c pager.status=false status --short --branch --untracked-files=normal --ignore-submodules=all --no-renames`.
+- The live `omx state write` artifact is intentionally minimal: `ultragoal-state.json` normally persists `active`, `current_phase`, and `run_outcome`; routing-only `mode` and session aliases may be stripped. Validators must derive authority from the pinned session path plus transcript/pointer/bootstrap/assignment evidence and reject conflicting optional aliases, not require routing fields to be re-persisted.
+- For Codex tool calls that execute bare `omx`, use the non-login shell path (`login:false` when the shell tool exposes it). A macOS `zsh -lc` login shell can rebuild `PATH` after `codex exec` starts and discard the NVM prefix even though the parent Codex process inherited the correct `PATH`; `zsh -c` preserves the pinned runtime path.
+- Put a long prompt in a file and redirect stdin. Nested shell quoting can silently corrupt JSON, and PTY `Ctrl-D` handling is unreliable for this check.
+- Treat the `thread.started.thread_id` event as the acceptance session id. Inspect its transcript under `~/.codex/sessions` and the matching `.omx/state/sessions/<id>` artifacts.
+- Do not repair the flow with exported `OMX_SESSION_ID`, manual pointer edits, raw state-file edits, or source-tree commands. Those actions bypass the behavior being tested.
+- Keep the acceptance run in `workspace-write`. On macOS this sandbox can make `kill(pid, 0)` return an indeterminate result for the live Codex owner process. Re-running an OMX command with escalated sandbox permissions may diagnose that boundary, but it does not prove the Codex App flow and must not be counted as acceptance success.
+- A successful native Ultragoal run proves: one typed executor first waits without tool calls; `native-bootstrap authorize --child-path` resolves its canonical child id; the unmodified canonical activation command succeeds; bootstrap becomes `active`; `followup_task` starts the authorized work; Codex goal creation/completion and OMX checkpointing succeed; Stop/cleanup is session-scoped; no foreign session state appears.
+- When spawning a typed child with an explicit role, use `fork_turns:"none"`; a full-history fork inherits the parent agent type and rejects an explicit `agent_type` before creating a child.
+- While Conductor is active, leader-owned Ultragoal metadata must use exact, statically bounded OMX commands. Never add shell chaining, dynamic expansion, `--force`, positional briefs, stdin/file briefs, or unreviewed options merely to get past the guard.
+- The pre-review ledger transport is the exact static form `omx ultragoal steer --kind annotate_ledger --evidence '<chronology>' --rationale '<reason>' --json` (with optional `--target-goal-id`). Quoted punctuation, JSON-style escaped text, and quoted glob characters are data; unquoted glob expansion, command substitution, redirection, or shell chaining must remain blocked.
+- In Conductor mode, `--json` is mandatory on every `omx ultragoal checkpoint` status, even though the general CLI help presents it as optional. Exact absolute installed-CLI and absolute artifact paths are supported when they resolve to the trusted runtime and current workspace; do not add shell indirection or chaining. Each `architectureInvariantGate.invariants[].source` must exactly equal one entry in `architectureInvariantGate.sourceArtifacts`, not a decorative provenance label.
+- The terminal write is intentionally ordered after a successful aggregate checkpoint and bootstrap revoke. Its exact transport is `omx state write --input '{"mode":"ultragoal","active":false,"current_phase":"complete"}' --json`; the hook and CLI both require a completed aggregate plan, the pinned `checkpointing` state, a revoked matching bootstrap, no ready executor assignment, and the exact native root session.
+- Do not accept the agent's final table as terminal-state proof. Codex runs Stop before the post-turn notify callback; Stop records the completed turn in root `.omx/state/native-stop-state.json`, then notify replays the original `$ultragoal` input. The notify hook must bind that replay to `ordinary_no_progress_guard.last_turn_id` and preserve the no-`mode` terminal file. Always inspect `ultragoal-state.json`, `skill-active-state.json`, `native-ultragoal-bootstrap.json`, `native-stop-state.json`, and the session-directory set after the `codex exec` process exits.
+- Root transcript acceptance must tolerate a task moving between workspaces: `session_meta.cwd` is immutable creation history, while current authority is bound to the exact latest `turn_context.turn_id` and `turn_context.cwd`. Include a single-turn transcript with more than 64 MiB of records after `turn_context` in Stop regressions; a fixed-size tail is not sufficient evidence for tool-heavy App turns.
+- If live behavior disagrees with source tests, compare the packed and installed internal module hashes first. Do not assume the intended prefix was updated.
diff --git a/docs/codex-native-hooks.md b/docs/codex-native-hooks.md
index 75f72bcca1e70fcdea8459f36d0f1596d887c3a7..d950b87fa3fd5d256340e97a9d5ed8cf737c46f0 100644
--- a/docs/codex-native-hooks.md
+++ b/docs/codex-native-hooks.md
@@ -101,6 +101,30 @@ uninspected script fail closed. For statically inspectable source, ordinary arra
object reads and benign reflection do not become mutation authority through broad
raw-command matching.
+Codex Desktop may run two live user chats in the same workspace while the
+compatibility `session.json` pointer names only one of them. For an exact
+identityless payload with an exact `session_id`, the hook may recover Main-root
+identity from the unique matching live rollout under
+`$CODEX_HOME/sessions`. The first `session_meta` record must bind that exact id
+and canonical cwd, declare `thread_source: "user"`, `source: "vscode"` or
+`source: "exec"`, and
+`originator: "Codex Desktop"`, and contain no subagent source. The rollout must
+be a regular, unlinked, non-group/world-writable file with a bounded first
+record. Identity and capability come from one pinned per-dispatch snapshot;
+post-read device, inode, mode, link-count, size, mtime, and ctime must remain
+unchanged. Conflicting snake/camel aliases, archived, ambiguous, malformed,
+linked, writable, child, mutated, or spoofed rollouts fail closed and do not
+weaken tracker or child-provenance checks.
+
+The hook payload may omit `thread_id`/`threadId`. If either alias is present,
+every present alias must be a non-empty string and all values must reduce to the
+exact root `session_id`; malformed, empty, null, numeric, or conflicting claims
+fail closed. UserPromptSubmit and PreToolUse additionally require one valid
+payload turn claim matching the latest complete `turn_context` record and its
+canonical cwd. An unterminated final JSONL record invalidates turn authority and
+typed-spawn capability instead of falling back to an older context. Stop remains
+turn-independent only on the stale-dead, exact-cwd, session-scoped path.
+
Official Team worker roots may omit both `agent_id` and legacy `thread_id`.
After Main-root exclusion, OMX preserves their established exemption only when
the Team environment agrees with the durable worker identity, Team config, and
@@ -120,8 +144,20 @@ while the Conductor boundary is active.
Planning boundaries (`ralplan`, `deep-interview`) remain fail-closed for mutation
transports: only their documented planning artifact paths and non-deactivating
-state operations are allowed. No assignment-backed grant, prompt-derived scope,
-or child-write allowance exists in this Option C implementation.
+state operations are allowed. They do not accept an Ultragoal assignment-backed
+grant, prompt-derived scope, or child-write allowance.
+
+Standalone Ultragoal on a native Codex surface outside tmux has three configured
+backends: `off`, `host`, and `local-experimental`. `off` preserves the no-owner
+activation block. `host` is the production-safe integration point, but it fails
+closed because Codex does not currently expose a documented host-issued native
+executor receipt API. `local-experimental` requires an ordered bootstrap:
+typed executor spawn, root authorization through
+`omx ultragoal native-bootstrap authorize`, then activation. The assignment is
+a short-lived same-user guardrail, not host authentication or an ADR 3212
+hostile-child boundary. See
+[`native-subagent-assignments.md`](native-subagent-assignments.md) for exact
+configuration, lifecycle, reconciliation, and recovery behavior.
### Exact direct-cancel recovery exception
@@ -242,9 +278,9 @@ operator to clear incompatible state explicitly via `omx state ...` or the
`omx_state.*` MCP tools before retrying. See
`docs/contracts/multi-state-transition-contract.md`.
-## Codex 0.144.5 and same-user native-child boundary (#3194, #3212)
+## Codex 0.144.5–0.145.0 and same-user native-child boundary (#3194, #3212, #3358)
-Codex CLI **0.144.5** documented hook payloads do not provide a positive proof that a `PreToolUse` event belongs to the root leader required by adapted Ralplan. Same-user native children are fully hostile: sandbox labels, environment, local files, session/thread IDs, pointers, transcripts, trackers, markers, task names, prompts, and absent child evidence are not authentication. OMX does not infer, repair, or synthesize authority from them.
+Official Codex CLI **0.144.5** and **0.145.0** source contracts include `turn_id` and optional `agent_id`/`agent_type` fields for `ThreadSpawn` subagents, but they do not provide positive proof that a `PreToolUse` event belongs to the root leader required by adapted Ralplan or Team authority. Omission of those optional child fields is shared by other session-source classes and is not positive Main-root proof. The payloads have no issuer, nonce, replay protection, canonical root-thread claim, or host-verifiable receipt. Same-user native children are fully hostile: sandbox labels, environment, local files, session/thread/turn IDs, pointers, transcripts, trackers, markers, task names, prompts, and absent child evidence are not authentication. OMX does not infer, repair, or synthesize authority from them.
Typed native role routing remains the preferred path when the task surface exposes `agent_type`. `agent_type`, `agent_role`, tracker fields, lifecycle records, and plugin launch routing are non-authoritative routing or diagnostic data; they can select or describe work but cannot release consensus. The documented-leader preflight applies only when both conditions hold: native role routing reports `role_routing_unavailable`, and the caller attempts adapted Ralplan Planner, Architect, or Critic authority, adapted role-intent, or adapted consensus authority. Only then run `omx ralplan preflight --json`. Preflight may neutralize only an exact current keyword-seeded Ralplan routing state; direct hook and CLI denials are zero-write. It then fails closed with:
@@ -263,6 +299,15 @@ Ordinary native planning, lifecycle, state, status, health, HUD, runtime, setup,
Ralplan consensus additionally requires an official host-issued receipt verified through a documented host integration. No such integration exists today, so production consensus fails closed with `documented_host_consensus_receipt_unavailable`; native Architect/Critic lifecycle evidence alone cannot release `ralplan -> ultragoal`. The packaged plugin's `OMX_CODEX_LAUNCH_ID` and `plugin-hook-routing` record are a spoofable routing-only discriminator, not a secret, signed claim, or authority source. See [ADR 3194](./adr/3194-codex-01445-documented-leader-proof.md), [ADR 3212](./adr/3212-same-user-native-child-auth-boundary.md), and the [consensus gate contract](./contracts/ralplan-consensus-gate.md).
+Exact Team launch therefore remains denied on Codex 0.145.0 unless a future documented host verifier supplies non-user-mintable Main-root/session/root-thread proof before any Team state, worktree, tmux, mailbox, worker, or process effect. Exact command grammar and local Ultragoal/task/session state may restrict a request, but they cannot authorize it. Native children remain limited to positively classified reads and verification/advice. Child-to-leader collaboration reporting also remains denied because 0.145.0 does not bind the caller to a host-authenticated direct parent and target; local subagent trackers cannot authorize that relation.
+
+During an active Conductor workflow, bare `git status --short --branch` remains denied because plain-looking argv does not suppress configured pagers, fsmonitor, filters, external diff helpers, submodules, or optional index writes. The admitted POSIX form is one direct, literal invocation with an authenticated Git executable and command-local neutralizers:
+
+```sh
+GIT_ATTR_NOSYSTEM=1 GIT_CONFIG_COUNT=0 GIT_CONFIG_GLOBAL=/dev/null GIT_CONFIG_NOSYSTEM=1 GIT_CONFIG_SYSTEM=/dev/null GIT_EDITOR= GIT_EXTERNAL_DIFF= GIT_PAGER= GIT_SEQUENCE_EDITOR= PAGER= git --no-pager --no-optional-locks -c core.fsmonitor=false -c core.untrackedCache=false -c pager.status=false status --short --branch --untracked-files=normal --ignore-submodules=all --no-renames
+```
+
+Windows uses `NUL` instead of `/dev/null`. OMX denies the invocation when the command-local `PATH` does not resolve the authenticated Git binary, any other `GIT_*` input apart from benign `GIT_TERMINAL_PROMPT=0` is active, repository configuration exposes aliases/includes/pagers/fsmonitor/hooks/external diff/filter/submodule helpers, an active `.gitattributes` file applies to tracked content, a submodule entry or gitlink is tracked, or `.git/info/attributes` is active. Bounded `find` is likewise admitted only as one literal command whose executable resolves through the authenticated command-local `PATH`, whose existing starting paths canonically resolve inside the workspace, and whose static numeric `-maxdepth` is between 0 and 32; wrappers, functions, aliases, substitutions, brace/pathname/extglob/tilde expansion, escapes, pipelines, chaining, redirects, `-exec`, `-delete`, output-file predicates, dynamic values, and unmodeled predicates remain denied.
## UserPromptSubmit: session provenance
diff --git a/docs/native-subagent-assignments.md b/docs/native-subagent-assignments.md
new file mode 100644
index 0000000000000000000000000000000000000000..53d862dd4a8b0fc8ad271e39a87495fc38f78259
--- /dev/null
+++ b/docs/native-subagent-assignments.md
@@ -0,0 +1,260 @@
+# Native subagent assignments
+
+The Codex native hook keeps typed native children read-only unless the active
+root Conductor establishes an exact, session-scoped assignment. This transport
+does not grant Team-worker identity or authority.
+
+## Backends
+
+Configure the transport in `~/.omx/config.json`:
+
+```json
+{
+ "nativeUltragoal": {
+ "backend": "local-experimental",
+ "assignmentTtlSeconds": 900
+ }
+}
+```
+
+`assignmentTtlSeconds` accepts an integer from 30 through 3600 and defaults to
+900. `OMX_NATIVE_ULTRAGOAL_BACKEND` overrides the configured backend. The
+override is fail-closed: a present non-empty invalid value resolves to `off`
+instead of falling back to a configured authority backend. The
+legacy `OMX_NATIVE_SUBAGENT_ASSIGNMENTS=on` setting maps to
+`local-experimental` only when neither the new environment override nor an
+explicit configured backend is present.
+
+The available backends are:
+
+- `off` (default): native Ultragoal activation outside tmux remains blocked
+ because no authorized executor is available.
+- `host`: reserved for a documented, unforgeable receipt issued by the Codex
+ host. OMX has no such host receipt API today, so this backend fails closed
+ with `OMX-ULTRAGOAL-HOST-RECEIPT-UNAVAILABLE`.
+- `local-experimental`: enables short-lived local assignments after OMX checks
+ the native tracker. This is a bounded same-user workflow guardrail, not host
+ authentication and not an ADR 3212 hostile-child boundary.
+
+## Ordered bootstrap
+
+On Codex native surfaces outside tmux, a fresh standalone `$ultragoal`
+activation stays inactive until the executor assignment is ready. Use this
+order:
+
+1. Invoke `$ultragoal`, then make one exact canonical Ultragoal state-activation
+ attempt. The PreToolUse hook can now verify typed `spawn_agent` support from
+ the latest root transcript, creates a session bootstrap, and returns
+ `OMX-ULTRAGOAL-BOOTSTRAP-REQUIRED` without activating Conductor mode. Read
+ the issued generation with `omx ultragoal native-bootstrap status
+ --session-id <session-id> --json`.
+2. Spawn one direct native child with `agent_type: "executor"`, instructing it
+ to wait without tool calls for a follow-up after activation. When the native
+ API returns only its stable `agent_path`, retain that exact path; OMX can
+ resolve the canonical child ID from the live rollout receipt.
+3. Authorize only the required paths and actions:
+
+ ```sh
+ omx ultragoal native-bootstrap authorize \
+ --session-id <session-id> \
+ --root-thread-id <root-thread-id> \
+ --bootstrap-generation <generation-from-bootstrap-required> \
+ --child-path /root/<typed-executor-agent-path> \
+ --path-prefix <repo-relative-path> \
+ --json
+ ```
+
+ Repeat `--path-prefix` for additional scopes. Add `--path-write-only` to
+ omit `bash-write`. Use `--ttl-seconds <30-3600>` only when the configured
+ TTL is unsuitable. Every `native-bootstrap` action requires an explicit
+ `--session-id` equal to the canonical current runtime session; pointer-only
+ or cross-session commands fail closed. `--bootstrap-generation` is the exact
+ generation printed by the bootstrap-required response; stale commands cannot
+ authorize a replacement generation. `--child-id` remains available when the
+ native API exposes the canonical ID directly. Exactly one of `--child-id`
+ and `--child-path` is accepted.
+4. Retry the canonical Ultragoal activation. `PreToolUse` moves the receipt to
+ `activating`; only a successful activation `PostToolUse` publishes `active`.
+ The hook proceeds only after the
+ bootstrap generation, assignment, tracker session, root thread, exact child
+ ID, direct parent, role, status, lifetime, and path scope all validate. Then
+ start the authorized executor work with `followup_task` for the retained
+ agent path.
+
+Main-root owns `.omx/ultragoal` plan, handoff, and checkpoint commands. The
+authorized executor owns only the scoped substantive product writes; do not
+ask it to create or mutate the durable Ultragoal plan.
+
+The child remains read-only until activation is confirmed. A crash before the
+activation tool runs leaves `ready`; a rejected or interrupted activation leaves
+`activating`. Both are safe and retryable while the assignment and tracked
+executor remain valid. If the receipt is revoked, expires, or loses tracker
+authority before confirmation, the hook revokes the grant and terminalizes the
+new Ultragoal state as `failed` instead of leaving Conductor active without an
+executor.
+
+## Location
+
+The bootstrap for root session `<session-id>` is stored at:
+
+```text
+.omx/state/sessions/<session-id>/native-ultragoal-bootstrap.json
+```
+
+The assignment for child `<child-agent-id>` is stored at:
+
+```text
+.omx/state/sessions/<session-id>/native-assignments/<encodeURIComponent(child-agent-id)>.json
+```
+
+`omx ultragoal native-bootstrap authorize` is the supported writer. The native
+hook rejects the canonical command when a tracked child invokes it and rejects
+child writes to bootstrap or `native-assignments` paths, even when ordinary
+path scope would otherwise match. This is still a same-user experimental
+boundary: the CLI cannot authenticate an arbitrary local OS process as
+Main-root without a host-issued receipt.
+
+## Active assignment schema
+
+The JSON object must contain exactly these keys:
+
+```json
+{
+ "schema_version": 1,
+ "kind": "native-subagent-assignment",
+ "lifecycle": "active",
+ "root_session_id": "exact-root-session-id",
+ "root_thread_id": "exact-root-thread-id",
+ "child_agent_id": "exact-canonical-child-agent-id",
+ "agent_type": "executor",
+ "allowed_actions": ["path-write", "bash-write"],
+ "path_prefixes": ["tmp/native-probe"],
+ "issued_at": "2026-07-23T20:00:00.000Z",
+ "expires_at": "2026-07-23T20:10:00.000Z",
+ "bootstrap_generation": "exact-bootstrap-generation"
+}
+```
+
+The hook checks the root session and leader thread against the active session.
+A directly attested child must be `kind: "subagent"`, carry `mode: "executor"`,
+`provenance_kind: "native_subagent"`, and exact `direct_child_parent_id` /
+`direct_child_root_id` bindings to Main-root. With the `local-experimental`
+backend only, Codex App v2 may instead use the unique live child rollout
+`session_meta` as assignment-local evidence when SessionStart did not persist a
+direct-child attestation. The tracker must still contain the exact root session
+and Main-root leader binding. The receipt must be under the live `sessions`
+tree, fall within the current bootstrap lifetime without a future timestamp,
+and bind the exact child, root session, direct parent, canonical cwd, depth `1`,
+and `executor` role.
+Archived, stale, ambiguous, writable, linked, malformed, or oversized receipts
+fail closed. This fallback creates only a descriptive tracker entry; it does not
+grant persisted reopen authority or synthesize child availability.
+
+`--child-path` is a receipt lookup transport, never an authority claim. OMX
+scans only the live `CODEX_HOME/sessions` tree and requires one safe unique
+rollout whose `session_meta` binds the exact path, canonical child UUID,
+session/root alias, direct root parent, depth `1`, `executor` role, canonical
+workspace cwd, and timestamp within the current bootstrap window. The rollout
+filename must end in that same child UUID. Missing, duplicate, stale, foreign,
+wrong-role, wrong-depth, wrong-cwd, group/other-writable, symlinked, or
+hard-linked candidates fail closed. The resolved UUID is then passed through
+the same assignment and activation validation as an explicit `--child-id`;
+the path itself is never persisted as child authority.
+
+For the independent Codex Desktop root chat itself, the same safe live-rollout
+boundary may also supply missing typed-spawn capability evidence from the latest
+bounded `turn_context`. Its exact current `turn_id` and canonical cwd must match
+the hook payload, with `multi_agent_mode: "explicitRequestOnly"` and
+`multi_agent_version: "v2"`. `session_meta.dynamic_tools` is not capability
+authority. All snake/camel aliases must reduce to one non-empty value, and the
+same pinned per-dispatch transcript snapshot supplies both root identity and
+capability. This fallback does not accept archived, ambiguous, or concurrently
+mutated rollouts and never supplies child provenance. Session-scoped prompt
+handling uses that exact root id, so an inactive terminal marker belonging to a
+different live workspace chat is not reused by the bootstrap guard.
+
+Any tracker contradiction remains an unconditional veto: revoked reopen
+authority, completion, a non-available explicit status, a non-`executor` role,
+or foreign parent/root evidence cannot be repaired by transcript fallback.
+The live tool payload must independently provide one unambiguous top-level
+`executor` role through the native `agent_role`/`agent_type` aliases.
+Nested-only role evidence or conflicting aliases cannot authorize an assignment.
+The filename must encode that same canonical child ID, and
+`bootstrap_generation` must match the current session bootstrap.
+
+Assignments are fail-closed when unreadable, malformed, expired, issued too far
+in the future, longer than 24 hours, symlinked, hard-linked, larger than 64 KiB,
+or writable by group/other. Unknown keys, duplicate actions or prefixes,
+ambiguous paths, symlink traversal, `.omx`, and `.git` scopes are rejected.
+Deleting the file or changing `lifecycle` away from `active` revokes the grant.
+
+## Lifecycle, revocation, and recovery
+
+Inspect and reconcile the current bootstrap with:
+
+```sh
+omx ultragoal native-bootstrap status --session-id <session-id> --json
+```
+
+Status reconciliation returns readiness only while the exact assignment and
+its direct tracker attestation or generation-bound live App receipt remain
+valid. An expired assignment cannot authorize a mutation. Reconciliation
+revokes an active assignment when the child evidence is missing, archived,
+stale, completed, unavailable, foreign to the root, or has the wrong role.
+Fresh activation also reconciles before it proceeds.
+
+All lifecycle mutations for one session are serialized by a session-scoped
+lock. Activation revalidates tracker authority, generation, file identity,
+schema, scope, and expiry under that lock and returns a positive receipt before
+the hook permits state activation. Concurrent revoke cannot be overwritten by
+a stale authorize or activation write. Revoked and expired generations require
+an explicit new bootstrap before another authorization; authorization never
+rotates a generation implicitly. An already-active receipt is idempotently
+revalidated so a rejected or interrupted state write can be retried safely.
+
+Explicitly revoke the bootstrap and its assignment with:
+
+```sh
+omx ultragoal native-bootstrap revoke \
+ --session-id <session-id> \
+ --child-id <child-agent-id> \
+ --reason <reason> \
+ --json
+```
+
+`--child-id` is optional when the bootstrap already records the child. After
+revocation, expiry, or tracker invalidation, the child returns to the normal
+read-only policy. Re-run `authorize` with the explicit current `--session-id`,
+root thread, and a live strictly tracked executor to renew or replace the lease;
+when standalone Ultragoal state is still active, the CLI restores bootstrap
+status to `active` only after revalidation. Terminal `Stop`, exact root
+cancellation, and a new fresh run revoke or rotate the old generation. An
+assignment from an older generation cannot be reused.
+
+## Actions
+
+- `path-write`: direct file-edit tools within `path_prefixes`.
+- `bash-write`: one statically analyzable shell mutation within
+ `path_prefixes`.
+
+Assignments never authorize VCS, PR, network, deployment, state, orchestration,
+goal, assignment, or Team-worker operations. A `"."` prefix still excludes
+`.git` and `.omx`. Shell substitution,
+unresolved arithmetic, dynamic nested execution, unsafe heredocs, unsafe
+nameref/allexport state, arbitrary PATH mutation, unresolved interpreter
+writes, and path/symlink escapes remain blocked.
+
+Without a valid assignment, typed native children continue to receive
+`OWNER_CONFIRMATION_REQUIRED`.
+
+## Root orchestration transports
+
+An active, session-bound Main-root Conductor may write the existing bounded
+metadata roots, including `.omx/state`, `.omx/ultragoal`, `.omx/ralph`,
+`.omx/team`, `.omx/mailbox`, `.omx/handoff`, `.omx/handoffs`, `.omx/goals`,
+`.omx/notepad`, `.omx/wiki`, and `.beads`.
+
+The hook structurally recognizes canonical `omx state read`, `omx state write`,
+`omx state clear`, and `omx ultragoal checkpoint` commands before generic shell
+mutation analysis. Exact session/cwd/mode binding and all existing injection,
+PATH, symlink, and protected-state-gate checks still apply.
diff --git a/docs/ultragoal.md b/docs/ultragoal.md
index d22b573d75d41ffc9a24656648375cad4fecc5b9..e5358d7f66b0c75e86e4b3dc5c02d268dad76c3c 100644
--- a/docs/ultragoal.md
+++ b/docs/ultragoal.md
@@ -53,7 +53,7 @@ The command marks the next pending OMX story `in_progress`, appends a ledger ent
For intermediate stories, do **not** call `update_goal`; checkpoint the OMX story with a fresh `get_goal` snapshot whose objective matches `codexObjective` and whose status is still `active`:
```sh
-omx ultragoal checkpoint --goal-id G001-example --status complete --evidence "npm test passed; docs updated" --codex-goal-json ./get-goal.json
+omx ultragoal checkpoint --goal-id G001-example --status complete --evidence "npm test passed; docs updated" --codex-goal-json ./get-goal.json --json
```
For the final story, run the whole-run audit plus the mandatory final `ai-slop-cleaner`, post-cleaner verification, architecture-invariant audit, and independent `$code-review` gate. If review is clean (`APPROVE` + `CLEAR` with distinct `code-reviewer` and `architect` subagent evidence) and every required architecture/domain invariant from the brief/spec/planning artifacts is proved with implementation, test, and review evidence, call `update_goal({status: "complete"})`, call `get_goal` again, and checkpoint with the fresh complete aggregate snapshot plus `--quality-gate-json`. If review is non-clean or any invariant is unproved, do not call `update_goal`; use `omx ultragoal record-review-blockers` to append a durable blocker-resolution story and continue.
@@ -62,7 +62,7 @@ For the final story, run the whole-run audit plus the mandatory final `ai-slop-c
Failure handling:
```sh
-omx ultragoal checkpoint --goal-id G001-example --status failed --evidence "blocked on missing credential"
+omx ultragoal checkpoint --goal-id G001-example --status failed --evidence "blocked on missing credential" --json
omx ultragoal complete-goals --retry-failed
```
@@ -77,7 +77,7 @@ runtime mode.
Completed legacy thread-goal blocker handling:
```sh
-omx ultragoal checkpoint --goal-id G001-example --status blocked --evidence "completed legacy Codex goal blocks create_goal in this thread" --codex-goal-json ./get-goal.json
+omx ultragoal checkpoint --goal-id G001-example --status blocked --evidence "completed legacy Codex goal blocks create_goal in this thread" --codex-goal-json ./get-goal.json --json
```
`--status blocked` is a non-terminal ledger checkpoint. Use it in two cases: (1) legacy per-story or pre-aggregate sessions where a previous, different Codex thread goal is already `complete` and the current `get_goal`/`create_goal` tool surface has no reset/new-goal operation that can clear that completed goal from the same thread; (2) when the matching Codex goal for the active ultragoal objective is truthfully `blocked` and you need to persist a non-terminal `goal_blocked` receipt with evidence. Both cases write a `goal_blocked` event, preserve the ultragoal as `in_progress`, and keep recovery finite without treating the microgoal as complete or failed.
@@ -127,7 +127,7 @@ Use ultragoal and team together when one durable Ultragoal story needs parallel
The leader checkpoints Ultragoal from Team evidence only after reconciling the Codex goal state. For an intermediate aggregate story, the leader calls `get_goal`, confirms the aggregate objective is still `active`, then runs:
```sh
-omx ultragoal checkpoint --goal-id <id> --status complete --evidence "<team evidence mentioning .omx/ultragoal and <id>>" --codex-goal-json <fresh-get_goal-json-or-path>
+omx ultragoal checkpoint --goal-id <id> --status complete --evidence "<team evidence mentioning .omx/ultragoal and <id>>" --codex-goal-json <fresh-get_goal-json-or-path> --json
```
For the final aggregate story, run the mandatory final cleanup/review gate first, call `update_goal({status: "complete"})` only when it is clean, call `get_goal` again, and checkpoint with `--quality-gate-json`.
@@ -156,7 +156,7 @@ The final ultragoal story is not complete until the active agent has run the fin
```sh
- omx ultragoal checkpoint --goal-id <id> --status complete --evidence "<tests/files/review evidence>" --codex-goal-json <fresh-complete-get-goal-json-or-path> --quality-gate-json <quality-gate-json-or-path>
+ omx ultragoal checkpoint --goal-id <id> --status complete --evidence "<tests/files/review evidence>" --codex-goal-json <fresh-complete-get-goal-json-or-path> --quality-gate-json <quality-gate-json-or-path> --json
```
`--quality-gate-json` must include:
diff --git a/plugins/oh-my-codex/skills/code-review/SKILL.md b/plugins/oh-my-codex/skills/code-review/SKILL.md
index 06bb78dad79dd993471fc1dc45862586744c674c..c28800e92e64675e0863fd99924392d48e473c9d 100644
--- a/plugins/oh-my-codex/skills/code-review/SKILL.md
+++ b/plugins/oh-my-codex/skills/code-review/SKILL.md
@@ -33,6 +33,7 @@ Delegates to the `code-reviewer` and `architect` agents in parallel for a two-la
- **`architect` lane** - owns the devil's-advocate / design-tradeoff perspective
- Both lanes run in parallel on a clean context with explicit scope and artifacts, and produce distinct outputs before final synthesis
- If either lane cannot be launched or does not return evidence, report `independent review unavailable`; do **not** substitute the current/authoring lane, and do **not** approve or mark the review merge-ready.
+ - Inside an active Conductor workflow, collect evidence through native read-only tools. If a Bash fallback is necessary on macOS, use root-owned absolute readers such as `/bin/cat`, `/usr/bin/find ... -print`, `/usr/bin/sed` with a read-only program, or `/usr/bin/git --no-pager diff --no-ext-diff --no-textconv -- .`. Do not use a bare Homebrew/NVM command such as `rg`: a user-writable `PATH` entry cannot provide fail-closed executable identity.
3. **Review Categories**
- **Security** - Hardcoded secrets, injection risks, XSS, CSRF
@@ -98,6 +99,8 @@ Review code changes for quality, security, and maintainability.
This is the code/spec/security lane. Do not absorb architectural ownership.
+Conductor read-only constraint: prefer native read tools. If Bash is necessary on macOS, use only root-owned absolute readers such as `/bin/cat`, `/usr/bin/find ... -print`, read-only `/usr/bin/sed`, or `/usr/bin/git --no-pager diff --no-ext-diff --no-textconv -- .`. Never use bare/Homebrew `rg`, `nl`, unsafe Git forms, shell chaining, or memory lookup. If the leader supplied sufficient empty-diff evidence, review that evidence directly without extra tool calls.
+
Scope: [git diff or specific files]
Review Checklist:
@@ -121,6 +124,8 @@ task(
Review the same code changes from the architecture/tradeoff perspective.
+Conductor read-only constraint: prefer native read tools. If Bash is necessary on macOS, use only root-owned absolute readers such as `/bin/cat`, `/usr/bin/find ... -print`, read-only `/usr/bin/sed`, or `/usr/bin/git --no-pager diff --no-ext-diff --no-textconv -- .`. Never use bare/Homebrew `rg`, `nl`, unsafe Git forms, shell chaining, or memory lookup. If the leader supplied sufficient empty-diff evidence, review that evidence directly without extra tool calls.
+
Scope: [git diff or specific files]
Focus:
diff --git a/plugins/oh-my-codex/skills/plan/SKILL.md b/plugins/oh-my-codex/skills/plan/SKILL.md
index 311ef4d8bb884ae6deee652017acb0e4390937e9..163fd436515c4e8c92cbdf1e4a19a6bc384363df 100644
--- a/plugins/oh-my-codex/skills/plan/SKILL.md
+++ b/plugins/oh-my-codex/skills/plan/SKILL.md
@@ -80,8 +80,8 @@ Jumping into code without understanding requirements leads to rework, scope cree
- **Request changes** — return to step 1 with user feedback incorporated
- **Skip review** — go directly to final approval (step 7)
If NOT running with `--interactive`, automatically proceed to review (step 3).
-3. **Architect** reviews for architectural soundness as a dedicated subsequent `Architect` subagent with the full task, current plan text/path, RALPLAN-DR summary, and relevant artifact context. Architect review **MUST** include: strongest steelman counterargument (antithesis) against the favored option, at least one meaningful tradeoff tension, and (when possible) a synthesis path. In deliberate mode, Architect should explicitly flag principle violations. **Wait for this step to complete before proceeding to step 4.** Do NOT run steps 3 and 4 in parallel. Do NOT substitute a default/improvised subagent prompt for the role-specific `Architect` prompt.
-4. **Critic** evaluates against quality criteria as a dedicated subsequent `Critic` subagent with the full task, current plan text/path, RALPLAN-DR summary, artifact context, and the completed `Architect` result. Critic **MUST** verify principle-option consistency, fair alternative exploration, risk mitigation clarity, testable acceptance criteria, and concrete verification steps. Critic **MUST** explicitly reject shallow alternatives, driver contradictions, vague risks, or weak verification. In deliberate mode, Critic **MUST** reject missing/weak pre-mortem or missing/weak expanded test plan. Run only after step 3 is complete. Do NOT let the `Architect` response self-approve the Critic gate.
+3. **Architect** reviews for architectural soundness as a dedicated subsequent `Architect` subagent with the full task, current plan text/path, RALPLAN-DR summary, and relevant artifact context. In active standalone Ralplan, first write the exact session-bound phase payload `{"mode":"ralplan","active":true,"current_phase":"architect-review","session_id":"<canonical-session-id>","workingDirectory":"<absolute-canonical-cwd>"}` through `omx state write --input '<payload>' --json`; do not use underscore phase aliases or add arbitrary review/artifact objects to this phase-only write. Spawn Architect with `fork_turns:"none"`. Keep the reviewer repo-local: do not ask it to re-read global skills or memory. Tell it to prefer native read tools and, when shell inspection is necessary, to use separate positively classified read-only calls such as `/usr/bin/sed -n '<range>p' <repo-file>` or `/usr/bin/find . -maxdepth <N> -type f -print`, never compound loops or bare `rg`/`ls`. Architect review **MUST** include: strongest steelman counterargument (antithesis) against the favored option, at least one meaningful tradeoff tension, and (when possible) a synthesis path. In deliberate mode, Architect should explicitly flag principle violations. **Wait for this step to complete before proceeding to step 4.** Do NOT run steps 3 and 4 in parallel. Do NOT substitute a default/improvised subagent prompt for the role-specific `Architect` prompt.
+4. **Critic** evaluates against quality criteria as a dedicated subsequent `Critic` subagent with the full task, current plan text/path, RALPLAN-DR summary, artifact context, and the completed `Architect` result. After the non-empty completed Architect artifact is durable under `.omx/plans/`, write the exact session-bound `current_phase:"critic-review"` payload with lifecycle-only `ralplan_consensus_gate.complete:false` plus `ralplan_architect_review` fields `agent_role`, `verdict`, repo-relative `artifact_path`, and a strict integer `sequence_index` equal to the current full review iteration (`1..5`), then spawn Critic with `fork_turns:"none"`. Repeat the same repo-local, positively classified read-only inspection constraints from the Architect prompt. This locally mintable trace proves ordering only and never authorizes execution. Critic **MUST** verify principle-option consistency, fair alternative exploration, risk mitigation clarity, testable acceptance criteria, and concrete verification steps. Critic **MUST** explicitly reject shallow alternatives, driver contradictions, vague risks, or weak verification. In deliberate mode, Critic **MUST** reject missing/weak pre-mortem or missing/weak expanded test plan. Run only after step 3 is complete. Do NOT let the `Architect` response self-approve the Critic gate.
5. **Re-review loop** (max 5 iterations): If Critic rejects or iterates, execute this closed loop:
a. Collect all feedback from Architect + Critic
b. Pass feedback to Planner to produce a revised plan
@@ -103,9 +103,11 @@ Jumping into code without understanding requirements leads to rework, scope cree
- **Start goal-mode follow-up** — proceed via `$ultragoal` by default, or `$autoresearch-goal` / `$performance-goal` when the approved plan specifically fits research validation or measurable optimization
- **Request changes** — return to step 1 with user feedback
- **Reject** — discard the plan entirely
+ In consensus mode while standalone Ralplan is active, these choices record requested future execution intent only. They do not authorize a workflow handoff. Unless an official non-user-mintable host receipt has been verified, preserve the requested lane in the plan, keep `ralplan_consensus_gate.complete:false`, and terminalize Ralplan as `active:false,current_phase:"blocked"` with `blocked_reason:"documented_host_consensus_receipt_unavailable"`.
If NOT running with `--interactive`, output the final approved plan and stop. Do NOT auto-execute.
8. *(--interactive only)* User chooses via the structured question UI (never ask for approval in plain text when a structured surface is available)
9. On user approval (--interactive only):
+ - **Consensus/Ralplan receipt gate:** Before invoking any execution or goal workflow below, verify the official host-issued Ralplan consensus receipt. Without it, do not invoke `$ultragoal`, `$team`, `$ralph`, `$autoresearch-goal`, or `$performance-goal`; record the selected lane as future guidance and perform the non-authorizing blocked terminalization from step 7.
- **Approve durable goal execution**: **MUST** invoke `$ultragoal` with the approved plan path from `.omx/plans/` as context **plus the explicit available-agent-types roster, suggested reasoning levels, concrete role allocation guidance, and direct launch hints for Ultragoal follow-up work**. Use `$team` alongside Ultragoal when parallel lanes are warranted. Do NOT implement directly. Do NOT edit source code files in the planning agent. Ralph is not the default follow-up; only invoke `$ralph` when the user explicitly selects a legacy/persistent single-owner execution lane.
- **Approve and implement via team**: **MUST** invoke `$team` with the approved plan path from `.omx/plans/` as context **plus the explicit available-agent-types roster, suggested reasoning levels, concrete staffing / worker-role allocation guidance, explicit `omx team` / `$team` launch hints, and the team verification path**. Do NOT implement directly. The team skill coordinates parallel agents across the staged pipeline for faster execution on large tasks.
- **Start goal-mode follow-up**: **MUST** invoke the selected goal workflow with the approved plan path and appropriate success context: `$ultragoal` as the default goal-mode path, `$autoresearch-goal` for research projects, or `$performance-goal` for optimization/performance projects with measurable evaluator criteria. Do NOT implement directly in the planning agent.
diff --git a/plugins/oh-my-codex/skills/ralplan/SKILL.md b/plugins/oh-my-codex/skills/ralplan/SKILL.md
index 72110044ab681e3d81bb4b2e4843be2fc25c7af9..5d80ed9a15273ad4ad616f4e996745b90565a932 100644
--- a/plugins/oh-my-codex/skills/ralplan/SKILL.md
+++ b/plugins/oh-my-codex/skills/ralplan/SKILL.md
@@ -53,8 +53,8 @@ The consensus workflow:
**Native role-routing rule:** When the native surface exposes `agent_type` role routing, set `agent_type` to an installed OMX role and never omit it for OMX work. When it does not (`role_routing_unavailable`), do not fabricate `agent_type`. On documented Codex 0.144.5, adapted Ralplan Planner, Architect, Critic, role-intent, and consensus authority are unavailable because they lack documented root proof; do not silently weaken routing with a prompt role label or inferred carrier. Use a Codex surface with documented root proof or a reviewed alternative workflow for that authority. A direct `omx ralplan role-intent write` attempt is denied with machine reason `unsupported_documented_leader_proof`.
-3. **Architect** reviews for architectural soundness and must provide the strongest steelman antithesis, at least one real tradeoff tension, and (when possible) synthesis — **await completion before step 4**. Launch this as a subsequent role-specific `Architect` subagent and pass the full task statement, context snapshot, PRD/test-spec paths, and relevant prior findings; do not substitute an unvalidated reviewer identity or a short improvised reviewer prompt. In deliberate mode, Architect should explicitly flag principle violations.
-4. **Critic** evaluates against quality criteria — run only after step 3 completes. Launch this as a subsequent role-specific `Critic` subagent with the full task statement, context snapshot, PRD/test-spec paths, and the completed Architect review; do not ask the Architect subagent to perform the Critic gate and do not substitute an unvalidated reviewer identity or a short improvised reviewer prompt. Critic must enforce principle-option consistency, fair alternatives, risk mitigation clarity, testable acceptance criteria, and concrete verification steps. In deliberate mode, Critic must reject missing/weak pre-mortem or expanded test plan.
+3. **Architect** reviews for architectural soundness and must provide the strongest steelman antithesis, at least one real tradeoff tension, and (when possible) synthesis — **await completion before step 4**. After the draft PRD and test spec exist, set the observable review phase with the exact session-bound command `omx state write --input '{"mode":"ralplan","active":true,"current_phase":"architect-review","session_id":"<canonical-session-id>","workingDirectory":"<absolute-canonical-cwd>"}' --json`, then launch a subsequent role-specific `Architect` subagent with `fork_turns:"none"`. Pass the full task statement, context snapshot, PRD/test-spec paths, and relevant prior findings; do not substitute an unvalidated reviewer identity or a short improvised reviewer prompt. Keep the reviewer repo-local: do not ask it to re-read global skills or memory. Tell it to prefer native read tools and, when shell inspection is necessary, to use separate positively classified read-only calls such as `/usr/bin/sed -n '<range>p' <repo-file>` or `/usr/bin/find . -maxdepth <N> -type f -print`, never compound loops or bare `rg`/`ls`. In deliberate mode, Architect should explicitly flag principle violations.
+4. **Critic** evaluates against quality criteria — run only after step 3 completes. Persist the non-empty completed Architect review under `.omx/plans/`, then set `current_phase:"critic-review"` with the exact session-bound state command while adding lifecycle-only `ralplan_consensus_gate:{"complete":false,"ralplan_architect_review":{"agent_role":"architect","verdict":"<APPROVE|ITERATE|REJECT>","artifact_path":".omx/plans/<architect-review>.md","sequence_index":<iteration>}}`, where `<iteration>` is the strict integer `1..5` for the current full Architect → Critic pass. This trace is locally mintable and is not execution authority; it only proves the required review order to the hook. Then launch the subsequent role-specific `Critic` subagent with `fork_turns:"none"`. Pass the full task statement, context snapshot, PRD/test-spec paths, and the completed Architect review; repeat the same repo-local, positively classified read-only inspection constraints from the Architect prompt. Do not ask the Architect subagent to perform the Critic gate and do not substitute an unvalidated reviewer identity or a short improvised reviewer prompt. Critic must enforce principle-option consistency, fair alternatives, risk mitigation clarity, testable acceptance criteria, and concrete verification steps. In deliberate mode, Critic must reject missing/weak pre-mortem or expanded test plan.
5. **Re-review loop** (max 5 iterations): Any non-`APPROVE` Critic verdict (`ITERATE` or `REJECT`) MUST run the same full closed loop:
a. Collect Architect and Critic feedback
b. Revise the plan with Planner
@@ -64,7 +64,7 @@ The consensus workflow:
f. If 5 iterations are reached without `APPROVE`, present the best version to the user
6. On Critic approval *(--interactive only)*: present the plan for review, change requests, rejection, or selection of a **requested future execution lane**. A local Critic approval is lifecycle-only and must not offer or begin an execution handoff while the host receipt verifier is unavailable.
7. *(--interactive only)* Record the user's planning disposition and any requested future execution lane; do not invoke `$ultragoal`, `$team`, `$ralph`, or another implementation lane without a verified official host receipt.
-8. On local Architect→Critic approval, preserve the plan and reviews with `ralplan_consensus_gate.complete:false` and `blocked_reason:"documented_host_consensus_receipt_unavailable"`. Report the host blocker and stop rather than implementing directly.
+8. On local Architect→Critic approval, preserve the plan and reviews with `ralplan_consensus_gate.complete:false` and `blocked_reason:"documented_host_consensus_receipt_unavailable"`. Terminalize this non-authorizing planning lifecycle with exactly `active:false,current_phase:"blocked",blocked_reason:"documented_host_consensus_receipt_unavailable"` (not `complete`) and `ralplan_consensus_gate:{"complete":false,"blocked_reason":"documented_host_consensus_receipt_unavailable"}` in the session-bound `omx state write ... --json` payload. The state backend deep-merges this minimal terminal gate so the existing Architect lifecycle evidence remains durable. Report the host blocker and stop rather than implementing directly. A clean `current_phase:"complete"` remains reserved for a verified official host receipt.
> **Important:** Steps 3 and 4 MUST run sequentially as role-specific subagents. Do NOT issue both agent calls in the same parallel batch. Always await the subsequent `Architect` result before invoking the subsequent `Critic`; their completed approvals establish local lifecycle evidence only and cannot satisfy the durable execution gate.
diff --git a/plugins/oh-my-codex/skills/team/SKILL.md b/plugins/oh-my-codex/skills/team/SKILL.md
index 3980988ef61ea4e616d8a5d3d9cca80428df2661..dcb61e20812ca64b5f8e57146a5ff44b721aa1d8 100644
--- a/plugins/oh-my-codex/skills/team/SKILL.md
+++ b/plugins/oh-my-codex/skills/team/SKILL.md
@@ -77,7 +77,7 @@ ATEM fit: treat this as agile teamwork support for transition/action/interperson
Use `$ultragoal` for durable leader-owned goal/ledger tracking and `$team` for parallel execution lanes. When Team is launched with an active `.omx/ultragoal/goals.json`, worker inboxes/status may include leader-owned Ultragoal context: `.omx/ultragoal/goals.json`, `.omx/ultragoal/ledger.jsonl`, the active goal id, Codex goal mode, and the `fresh_leader_get_goal_required` checkpoint policy.
-Workers provide task status and verification evidence only. They do not own Ultragoal goal state, create worker ledgers, mutate `.omx/ultragoal`, auto-launch Team from Ultragoal, or perform hidden Codex goal mutation. The leader uses terminal Team evidence plus a fresh `get_goal` snapshot to run `omx ultragoal checkpoint --goal-id <id> --status complete --evidence "<team evidence mentioning .omx/ultragoal and <id>>" --codex-goal-json <fresh-get_goal-json-or-path>`.
+Workers provide task status and verification evidence only. They do not own Ultragoal goal state, create worker ledgers, mutate `.omx/ultragoal`, auto-launch Team from Ultragoal, or perform hidden Codex goal mutation. The leader uses terminal Team evidence plus a fresh `get_goal` snapshot to run `omx ultragoal checkpoint --goal-id <id> --status complete --evidence "<team evidence mentioning .omx/ultragoal and <id>>" --codex-goal-json <fresh-get_goal-json-or-path> --json`.
### Claude teammates (v0.6.0+)
diff --git a/plugins/oh-my-codex/skills/ultragoal/SKILL.md b/plugins/oh-my-codex/skills/ultragoal/SKILL.md
index 3a22a0ed97f882793d6970a073d386368025a83e..4b0c4127bc87c2a17115d7d6dd339386fde15bea 100644
--- a/plugins/oh-my-codex/skills/ultragoal/SKILL.md
+++ b/plugins/oh-my-codex/skills/ultragoal/SKILL.md
@@ -22,8 +22,9 @@ Existing aggregate plans with the legacy enumerated objective are migrated to th
Ultragoal is both a tracked workflow skill and the Autopilot durable-implementation child phase. Keep the phase/HUD contract explicit at workflow boundaries:
-- **Standalone `$ultragoal` activation**: ensure `.omx/state[/sessions/<session>]/ultragoal-state.json` exists with `mode:"ultragoal"`, `active:true`, and a non-empty `current_phase` such as `planning` before or while goals are created. This state is a lightweight HUD/runtime declaration; `.omx/ultragoal/goals.json` and `ledger.jsonl` remain the durable goal source of truth.
+- **Standalone `$ultragoal` activation**: route the write with `mode:"ultragoal"` and ensure `.omx/state[/sessions/<session>]/ultragoal-state.json` exists with `active:true` and a non-empty `current_phase` such as `planning` before or while goals are created. The state backend may omit the routing-only `mode` field from the persisted JSON; the canonical filename supplies that identity, while a present conflicting `mode` is invalid. This state is a lightweight HUD/runtime declaration; `.omx/ultragoal/goals.json` and `ledger.jsonl` remain the durable goal source of truth.
- **During execution**: update `current_phase` to the smallest accurate phase (`planning`, `executing`, `verifying`, `reviewing`, `checkpointing`, or `blocked`) when the visible workflow phase changes.
+- **Codex App outside tmux**: `nativeUltragoal.backend` defaults to `off`. `host` remains fail-closed until Codex exposes a documented host-issued native executor receipt API. `local-experimental` is an explicit same-user guardrail, not host authentication or an ADR 3212 hostile-child boundary. When typed `spawn_agent` support is advertised, keep Ultragoal inactive while Main-root follows the ordered bootstrap: invoke `$ultragoal`; make one exact canonical Ultragoal state-activation attempt so the latest root transcript can seed the bootstrap (expect `OMX-ULTRAGOAL-BOOTSTRAP-REQUIRED`, not an active workflow); read the generation with `omx ultragoal native-bootstrap status --session-id <session-id> --json`; spawn one exact typed `executor` instructed to wait without tool calls for a post-activation follow-up; retain its returned `agent_path`; run `omx ultragoal native-bootstrap authorize --session-id <session-id> --root-thread-id <root-thread-id> --bootstrap-generation <generation> --child-path <agent-path> --path-prefix <repo-relative-path> --json`; retry the canonical Ultragoal activation; then start the authorized work with `followup_task`. Main-root owns `create-goals`, `complete-goals`, checkpoint, and other `.omx/ultragoal` metadata commands; delegate only substantive product writes to the executor. Use `--child-id` only when the host directly exposes the canonical child ID. Keep paths/actions minimal; use `omx ultragoal native-bootstrap status` to reconcile/recover and `omx ultragoal native-bootstrap revoke` when the executor is no longer needed. Follow `docs/native-subagent-assignments.md` for configuration and lifecycle details.
- **Inside active Autopilot**: keep `mode:"autopilot"` active and set the supervised phase to `current_phase:"ultragoal"`; do not start a peer Autopilot replacement. Ultragoal's own mode state may still exist as child-phase detail, but Autopilot owns the parent phase.
- **On handoff to code-review**: persist implementation/test/ledger evidence under Autopilot `handoff_artifacts.ultragoal`, then set Autopilot `current_phase:"code-review"`.
- **On completion/blocker**: set standalone Ultragoal `active:false,current_phase:"complete"` only when all durable goals are complete; otherwise keep it active with a blocker/review-blocked phase and ledger evidence.
@@ -61,12 +62,12 @@ Loop until `omx ultragoal status` reports all goals complete:
6. Run a completion audit against the story objective and real artifacts/tests.
7. In aggregate mode, do **not** call `update_goal` for intermediate stories; checkpoint with a fresh `get_goal` snapshot whose aggregate objective is still `active`. On the final story only, first run the mandatory final cleanup/review gate below; call `update_goal({status: "complete"})` only after that gate is clean, then call `get_goal` again for a fresh `complete` snapshot.
8. Checkpoint the durable ledger with that snapshot. Intermediate aggregate checkpoints use only `--codex-goal-json`; final clean checkpoints also require `--quality-gate-json`:
- `omx ultragoal checkpoint --goal-id <id> --status complete --evidence "<evidence>" --codex-goal-json <get_goal-json-or-path> [--quality-gate-json <quality-gate-json-or-path>]`
+ `omx ultragoal checkpoint --goal-id <id> --status complete --evidence "<evidence>" --codex-goal-json <get_goal-json-or-path> [--quality-gate-json <quality-gate-json-or-path>] --json`
9. If blocked or failed, checkpoint failure:
- `omx ultragoal checkpoint --goal-id <id> --status failed --evidence "<blocker/evidence>"`
+ `omx ultragoal checkpoint --goal-id <id> --status failed --evidence "<blocker/evidence>" --json`
10. For non-terminal blockers, use blocked checkpoints:
- - legacy different completed goal: `omx ultragoal checkpoint --goal-id <id> --status blocked --evidence "<completed legacy Codex goal blocks create_goal in this thread>" --codex-goal-json <get_goal-json-or-path>`
- - matching native Codex `blocked` status: `omx ultragoal checkpoint --goal-id <id> --status blocked --evidence "<blocker evidence>" --codex-goal-json <matching-blocked-get_goal-json-or-path>`
+ - legacy different completed goal: `omx ultragoal checkpoint --goal-id <id> --status blocked --evidence "<completed legacy Codex goal blocks create_goal in this thread>" --codex-goal-json <get_goal-json-or-path> --json`
+ - matching native Codex `blocked` status: `omx ultragoal checkpoint --goal-id <id> --status blocked --evidence "<blocker evidence>" --codex-goal-json <matching-blocked-get_goal-json-or-path> --json`
11. Resume failed goals with `omx ultragoal complete-goals --retry-failed`.
## Dynamic steering
@@ -106,7 +107,7 @@ Use ultragoal and team together for a durable Ultragoal story that benefits from
The leader checkpoints Ultragoal from Team evidence with a fresh `get_goal` snapshot:
```sh
-omx ultragoal checkpoint --goal-id <id> --status complete --evidence "<team evidence mentioning .omx/ultragoal and <id>>" --codex-goal-json <fresh-get_goal-json-or-path>
+omx ultragoal checkpoint --goal-id <id> --status complete --evidence "<team evidence mentioning .omx/ultragoal and <id>>" --codex-goal-json <fresh-get_goal-json-or-path> --json
```
Workers do not own ultragoal goal state, do not create worker ultragoal ledgers, and do not checkpoint Ultragoal. Team launch remains explicit; Ultragoal does not auto-launch Team and performs no hidden Codex goal mutation.
@@ -133,7 +134,7 @@ The final ultragoal story is not complete until the active agent has run the fin
```sh
- omx ultragoal checkpoint --goal-id <id> --status complete --evidence "<tests/files/review evidence>" --codex-goal-json <fresh-complete-get-goal-json-or-path> --quality-gate-json <quality-gate-json-or-path>
+ omx ultragoal checkpoint --goal-id <id> --status complete --evidence "<tests/files/review evidence>" --codex-goal-json <fresh-complete-get-goal-json-or-path> --quality-gate-json <quality-gate-json-or-path> --json
```
`--quality-gate-json` must include:
diff --git a/skills/code-review/SKILL.md b/skills/code-review/SKILL.md
index 06bb78dad79dd993471fc1dc45862586744c674c..c28800e92e64675e0863fd99924392d48e473c9d 100644
--- a/skills/code-review/SKILL.md
+++ b/skills/code-review/SKILL.md
@@ -33,6 +33,7 @@ Delegates to the `code-reviewer` and `architect` agents in parallel for a two-la
- **`architect` lane** - owns the devil's-advocate / design-tradeoff perspective
- Both lanes run in parallel on a clean context with explicit scope and artifacts, and produce distinct outputs before final synthesis
- If either lane cannot be launched or does not return evidence, report `independent review unavailable`; do **not** substitute the current/authoring lane, and do **not** approve or mark the review merge-ready.
+ - Inside an active Conductor workflow, collect evidence through native read-only tools. If a Bash fallback is necessary on macOS, use root-owned absolute readers such as `/bin/cat`, `/usr/bin/find ... -print`, `/usr/bin/sed` with a read-only program, or `/usr/bin/git --no-pager diff --no-ext-diff --no-textconv -- .`. Do not use a bare Homebrew/NVM command such as `rg`: a user-writable `PATH` entry cannot provide fail-closed executable identity.
3. **Review Categories**
- **Security** - Hardcoded secrets, injection risks, XSS, CSRF
@@ -98,6 +99,8 @@ Review code changes for quality, security, and maintainability.
This is the code/spec/security lane. Do not absorb architectural ownership.
+Conductor read-only constraint: prefer native read tools. If Bash is necessary on macOS, use only root-owned absolute readers such as `/bin/cat`, `/usr/bin/find ... -print`, read-only `/usr/bin/sed`, or `/usr/bin/git --no-pager diff --no-ext-diff --no-textconv -- .`. Never use bare/Homebrew `rg`, `nl`, unsafe Git forms, shell chaining, or memory lookup. If the leader supplied sufficient empty-diff evidence, review that evidence directly without extra tool calls.
+
Scope: [git diff or specific files]
Review Checklist:
@@ -121,6 +124,8 @@ task(
Review the same code changes from the architecture/tradeoff perspective.
+Conductor read-only constraint: prefer native read tools. If Bash is necessary on macOS, use only root-owned absolute readers such as `/bin/cat`, `/usr/bin/find ... -print`, read-only `/usr/bin/sed`, or `/usr/bin/git --no-pager diff --no-ext-diff --no-textconv -- .`. Never use bare/Homebrew `rg`, `nl`, unsafe Git forms, shell chaining, or memory lookup. If the leader supplied sufficient empty-diff evidence, review that evidence directly without extra tool calls.
+
Scope: [git diff or specific files]
Focus:
diff --git a/skills/plan/SKILL.md b/skills/plan/SKILL.md
index 311ef4d8bb884ae6deee652017acb0e4390937e9..163fd436515c4e8c92cbdf1e4a19a6bc384363df 100644
--- a/skills/plan/SKILL.md
+++ b/skills/plan/SKILL.md
@@ -80,8 +80,8 @@ Jumping into code without understanding requirements leads to rework, scope cree
- **Request changes** — return to step 1 with user feedback incorporated
- **Skip review** — go directly to final approval (step 7)
If NOT running with `--interactive`, automatically proceed to review (step 3).
-3. **Architect** reviews for architectural soundness as a dedicated subsequent `Architect` subagent with the full task, current plan text/path, RALPLAN-DR summary, and relevant artifact context. Architect review **MUST** include: strongest steelman counterargument (antithesis) against the favored option, at least one meaningful tradeoff tension, and (when possible) a synthesis path. In deliberate mode, Architect should explicitly flag principle violations. **Wait for this step to complete before proceeding to step 4.** Do NOT run steps 3 and 4 in parallel. Do NOT substitute a default/improvised subagent prompt for the role-specific `Architect` prompt.
-4. **Critic** evaluates against quality criteria as a dedicated subsequent `Critic` subagent with the full task, current plan text/path, RALPLAN-DR summary, artifact context, and the completed `Architect` result. Critic **MUST** verify principle-option consistency, fair alternative exploration, risk mitigation clarity, testable acceptance criteria, and concrete verification steps. Critic **MUST** explicitly reject shallow alternatives, driver contradictions, vague risks, or weak verification. In deliberate mode, Critic **MUST** reject missing/weak pre-mortem or missing/weak expanded test plan. Run only after step 3 is complete. Do NOT let the `Architect` response self-approve the Critic gate.
+3. **Architect** reviews for architectural soundness as a dedicated subsequent `Architect` subagent with the full task, current plan text/path, RALPLAN-DR summary, and relevant artifact context. In active standalone Ralplan, first write the exact session-bound phase payload `{"mode":"ralplan","active":true,"current_phase":"architect-review","session_id":"<canonical-session-id>","workingDirectory":"<absolute-canonical-cwd>"}` through `omx state write --input '<payload>' --json`; do not use underscore phase aliases or add arbitrary review/artifact objects to this phase-only write. Spawn Architect with `fork_turns:"none"`. Keep the reviewer repo-local: do not ask it to re-read global skills or memory. Tell it to prefer native read tools and, when shell inspection is necessary, to use separate positively classified read-only calls such as `/usr/bin/sed -n '<range>p' <repo-file>` or `/usr/bin/find . -maxdepth <N> -type f -print`, never compound loops or bare `rg`/`ls`. Architect review **MUST** include: strongest steelman counterargument (antithesis) against the favored option, at least one meaningful tradeoff tension, and (when possible) a synthesis path. In deliberate mode, Architect should explicitly flag principle violations. **Wait for this step to complete before proceeding to step 4.** Do NOT run steps 3 and 4 in parallel. Do NOT substitute a default/improvised subagent prompt for the role-specific `Architect` prompt.
+4. **Critic** evaluates against quality criteria as a dedicated subsequent `Critic` subagent with the full task, current plan text/path, RALPLAN-DR summary, artifact context, and the completed `Architect` result. After the non-empty completed Architect artifact is durable under `.omx/plans/`, write the exact session-bound `current_phase:"critic-review"` payload with lifecycle-only `ralplan_consensus_gate.complete:false` plus `ralplan_architect_review` fields `agent_role`, `verdict`, repo-relative `artifact_path`, and a strict integer `sequence_index` equal to the current full review iteration (`1..5`), then spawn Critic with `fork_turns:"none"`. Repeat the same repo-local, positively classified read-only inspection constraints from the Architect prompt. This locally mintable trace proves ordering only and never authorizes execution. Critic **MUST** verify principle-option consistency, fair alternative exploration, risk mitigation clarity, testable acceptance criteria, and concrete verification steps. Critic **MUST** explicitly reject shallow alternatives, driver contradictions, vague risks, or weak verification. In deliberate mode, Critic **MUST** reject missing/weak pre-mortem or missing/weak expanded test plan. Run only after step 3 is complete. Do NOT let the `Architect` response self-approve the Critic gate.
5. **Re-review loop** (max 5 iterations): If Critic rejects or iterates, execute this closed loop:
a. Collect all feedback from Architect + Critic
b. Pass feedback to Planner to produce a revised plan
@@ -103,9 +103,11 @@ Jumping into code without understanding requirements leads to rework, scope cree
- **Start goal-mode follow-up** — proceed via `$ultragoal` by default, or `$autoresearch-goal` / `$performance-goal` when the approved plan specifically fits research validation or measurable optimization
- **Request changes** — return to step 1 with user feedback
- **Reject** — discard the plan entirely
+ In consensus mode while standalone Ralplan is active, these choices record requested future execution intent only. They do not authorize a workflow handoff. Unless an official non-user-mintable host receipt has been verified, preserve the requested lane in the plan, keep `ralplan_consensus_gate.complete:false`, and terminalize Ralplan as `active:false,current_phase:"blocked"` with `blocked_reason:"documented_host_consensus_receipt_unavailable"`.
If NOT running with `--interactive`, output the final approved plan and stop. Do NOT auto-execute.
8. *(--interactive only)* User chooses via the structured question UI (never ask for approval in plain text when a structured surface is available)
9. On user approval (--interactive only):
+ - **Consensus/Ralplan receipt gate:** Before invoking any execution or goal workflow below, verify the official host-issued Ralplan consensus receipt. Without it, do not invoke `$ultragoal`, `$team`, `$ralph`, `$autoresearch-goal`, or `$performance-goal`; record the selected lane as future guidance and perform the non-authorizing blocked terminalization from step 7.
- **Approve durable goal execution**: **MUST** invoke `$ultragoal` with the approved plan path from `.omx/plans/` as context **plus the explicit available-agent-types roster, suggested reasoning levels, concrete role allocation guidance, and direct launch hints for Ultragoal follow-up work**. Use `$team` alongside Ultragoal when parallel lanes are warranted. Do NOT implement directly. Do NOT edit source code files in the planning agent. Ralph is not the default follow-up; only invoke `$ralph` when the user explicitly selects a legacy/persistent single-owner execution lane.
- **Approve and implement via team**: **MUST** invoke `$team` with the approved plan path from `.omx/plans/` as context **plus the explicit available-agent-types roster, suggested reasoning levels, concrete staffing / worker-role allocation guidance, explicit `omx team` / `$team` launch hints, and the team verification path**. Do NOT implement directly. The team skill coordinates parallel agents across the staged pipeline for faster execution on large tasks.
- **Start goal-mode follow-up**: **MUST** invoke the selected goal workflow with the approved plan path and appropriate success context: `$ultragoal` as the default goal-mode path, `$autoresearch-goal` for research projects, or `$performance-goal` for optimization/performance projects with measurable evaluator criteria. Do NOT implement directly in the planning agent.
diff --git a/skills/ralplan/SKILL.md b/skills/ralplan/SKILL.md
index 72110044ab681e3d81bb4b2e4843be2fc25c7af9..5d80ed9a15273ad4ad616f4e996745b90565a932 100644
--- a/skills/ralplan/SKILL.md
+++ b/skills/ralplan/SKILL.md
@@ -53,8 +53,8 @@ The consensus workflow:
**Native role-routing rule:** When the native surface exposes `agent_type` role routing, set `agent_type` to an installed OMX role and never omit it for OMX work. When it does not (`role_routing_unavailable`), do not fabricate `agent_type`. On documented Codex 0.144.5, adapted Ralplan Planner, Architect, Critic, role-intent, and consensus authority are unavailable because they lack documented root proof; do not silently weaken routing with a prompt role label or inferred carrier. Use a Codex surface with documented root proof or a reviewed alternative workflow for that authority. A direct `omx ralplan role-intent write` attempt is denied with machine reason `unsupported_documented_leader_proof`.
-3. **Architect** reviews for architectural soundness and must provide the strongest steelman antithesis, at least one real tradeoff tension, and (when possible) synthesis — **await completion before step 4**. Launch this as a subsequent role-specific `Architect` subagent and pass the full task statement, context snapshot, PRD/test-spec paths, and relevant prior findings; do not substitute an unvalidated reviewer identity or a short improvised reviewer prompt. In deliberate mode, Architect should explicitly flag principle violations.
-4. **Critic** evaluates against quality criteria — run only after step 3 completes. Launch this as a subsequent role-specific `Critic` subagent with the full task statement, context snapshot, PRD/test-spec paths, and the completed Architect review; do not ask the Architect subagent to perform the Critic gate and do not substitute an unvalidated reviewer identity or a short improvised reviewer prompt. Critic must enforce principle-option consistency, fair alternatives, risk mitigation clarity, testable acceptance criteria, and concrete verification steps. In deliberate mode, Critic must reject missing/weak pre-mortem or expanded test plan.
+3. **Architect** reviews for architectural soundness and must provide the strongest steelman antithesis, at least one real tradeoff tension, and (when possible) synthesis — **await completion before step 4**. After the draft PRD and test spec exist, set the observable review phase with the exact session-bound command `omx state write --input '{"mode":"ralplan","active":true,"current_phase":"architect-review","session_id":"<canonical-session-id>","workingDirectory":"<absolute-canonical-cwd>"}' --json`, then launch a subsequent role-specific `Architect` subagent with `fork_turns:"none"`. Pass the full task statement, context snapshot, PRD/test-spec paths, and relevant prior findings; do not substitute an unvalidated reviewer identity or a short improvised reviewer prompt. Keep the reviewer repo-local: do not ask it to re-read global skills or memory. Tell it to prefer native read tools and, when shell inspection is necessary, to use separate positively classified read-only calls such as `/usr/bin/sed -n '<range>p' <repo-file>` or `/usr/bin/find . -maxdepth <N> -type f -print`, never compound loops or bare `rg`/`ls`. In deliberate mode, Architect should explicitly flag principle violations.
+4. **Critic** evaluates against quality criteria — run only after step 3 completes. Persist the non-empty completed Architect review under `.omx/plans/`, then set `current_phase:"critic-review"` with the exact session-bound state command while adding lifecycle-only `ralplan_consensus_gate:{"complete":false,"ralplan_architect_review":{"agent_role":"architect","verdict":"<APPROVE|ITERATE|REJECT>","artifact_path":".omx/plans/<architect-review>.md","sequence_index":<iteration>}}`, where `<iteration>` is the strict integer `1..5` for the current full Architect → Critic pass. This trace is locally mintable and is not execution authority; it only proves the required review order to the hook. Then launch the subsequent role-specific `Critic` subagent with `fork_turns:"none"`. Pass the full task statement, context snapshot, PRD/test-spec paths, and the completed Architect review; repeat the same repo-local, positively classified read-only inspection constraints from the Architect prompt. Do not ask the Architect subagent to perform the Critic gate and do not substitute an unvalidated reviewer identity or a short improvised reviewer prompt. Critic must enforce principle-option consistency, fair alternatives, risk mitigation clarity, testable acceptance criteria, and concrete verification steps. In deliberate mode, Critic must reject missing/weak pre-mortem or expanded test plan.
5. **Re-review loop** (max 5 iterations): Any non-`APPROVE` Critic verdict (`ITERATE` or `REJECT`) MUST run the same full closed loop:
a. Collect Architect and Critic feedback
b. Revise the plan with Planner
@@ -64,7 +64,7 @@ The consensus workflow:
f. If 5 iterations are reached without `APPROVE`, present the best version to the user
6. On Critic approval *(--interactive only)*: present the plan for review, change requests, rejection, or selection of a **requested future execution lane**. A local Critic approval is lifecycle-only and must not offer or begin an execution handoff while the host receipt verifier is unavailable.
7. *(--interactive only)* Record the user's planning disposition and any requested future execution lane; do not invoke `$ultragoal`, `$team`, `$ralph`, or another implementation lane without a verified official host receipt.
-8. On local Architect→Critic approval, preserve the plan and reviews with `ralplan_consensus_gate.complete:false` and `blocked_reason:"documented_host_consensus_receipt_unavailable"`. Report the host blocker and stop rather than implementing directly.
+8. On local Architect→Critic approval, preserve the plan and reviews with `ralplan_consensus_gate.complete:false` and `blocked_reason:"documented_host_consensus_receipt_unavailable"`. Terminalize this non-authorizing planning lifecycle with exactly `active:false,current_phase:"blocked",blocked_reason:"documented_host_consensus_receipt_unavailable"` (not `complete`) and `ralplan_consensus_gate:{"complete":false,"blocked_reason":"documented_host_consensus_receipt_unavailable"}` in the session-bound `omx state write ... --json` payload. The state backend deep-merges this minimal terminal gate so the existing Architect lifecycle evidence remains durable. Report the host blocker and stop rather than implementing directly. A clean `current_phase:"complete"` remains reserved for a verified official host receipt.
> **Important:** Steps 3 and 4 MUST run sequentially as role-specific subagents. Do NOT issue both agent calls in the same parallel batch. Always await the subsequent `Architect` result before invoking the subsequent `Critic`; their completed approvals establish local lifecycle evidence only and cannot satisfy the durable execution gate.
diff --git a/skills/team/SKILL.md b/skills/team/SKILL.md
index 3980988ef61ea4e616d8a5d3d9cca80428df2661..dcb61e20812ca64b5f8e57146a5ff44b721aa1d8 100644
--- a/skills/team/SKILL.md
+++ b/skills/team/SKILL.md
@@ -77,7 +77,7 @@ ATEM fit: treat this as agile teamwork support for transition/action/interperson
Use `$ultragoal` for durable leader-owned goal/ledger tracking and `$team` for parallel execution lanes. When Team is launched with an active `.omx/ultragoal/goals.json`, worker inboxes/status may include leader-owned Ultragoal context: `.omx/ultragoal/goals.json`, `.omx/ultragoal/ledger.jsonl`, the active goal id, Codex goal mode, and the `fresh_leader_get_goal_required` checkpoint policy.
-Workers provide task status and verification evidence only. They do not own Ultragoal goal state, create worker ledgers, mutate `.omx/ultragoal`, auto-launch Team from Ultragoal, or perform hidden Codex goal mutation. The leader uses terminal Team evidence plus a fresh `get_goal` snapshot to run `omx ultragoal checkpoint --goal-id <id> --status complete --evidence "<team evidence mentioning .omx/ultragoal and <id>>" --codex-goal-json <fresh-get_goal-json-or-path>`.
+Workers provide task status and verification evidence only. They do not own Ultragoal goal state, create worker ledgers, mutate `.omx/ultragoal`, auto-launch Team from Ultragoal, or perform hidden Codex goal mutation. The leader uses terminal Team evidence plus a fresh `get_goal` snapshot to run `omx ultragoal checkpoint --goal-id <id> --status complete --evidence "<team evidence mentioning .omx/ultragoal and <id>>" --codex-goal-json <fresh-get_goal-json-or-path> --json`.
### Claude teammates (v0.6.0+)
diff --git a/skills/ultragoal/SKILL.md b/skills/ultragoal/SKILL.md
index 3a22a0ed97f882793d6970a073d386368025a83e..4b0c4127bc87c2a17115d7d6dd339386fde15bea 100644
--- a/skills/ultragoal/SKILL.md
+++ b/skills/ultragoal/SKILL.md
@@ -22,8 +22,9 @@ Existing aggregate plans with the legacy enumerated objective are migrated to th
Ultragoal is both a tracked workflow skill and the Autopilot durable-implementation child phase. Keep the phase/HUD contract explicit at workflow boundaries:
-- **Standalone `$ultragoal` activation**: ensure `.omx/state[/sessions/<session>]/ultragoal-state.json` exists with `mode:"ultragoal"`, `active:true`, and a non-empty `current_phase` such as `planning` before or while goals are created. This state is a lightweight HUD/runtime declaration; `.omx/ultragoal/goals.json` and `ledger.jsonl` remain the durable goal source of truth.
+- **Standalone `$ultragoal` activation**: route the write with `mode:"ultragoal"` and ensure `.omx/state[/sessions/<session>]/ultragoal-state.json` exists with `active:true` and a non-empty `current_phase` such as `planning` before or while goals are created. The state backend may omit the routing-only `mode` field from the persisted JSON; the canonical filename supplies that identity, while a present conflicting `mode` is invalid. This state is a lightweight HUD/runtime declaration; `.omx/ultragoal/goals.json` and `ledger.jsonl` remain the durable goal source of truth.
- **During execution**: update `current_phase` to the smallest accurate phase (`planning`, `executing`, `verifying`, `reviewing`, `checkpointing`, or `blocked`) when the visible workflow phase changes.
+- **Codex App outside tmux**: `nativeUltragoal.backend` defaults to `off`. `host` remains fail-closed until Codex exposes a documented host-issued native executor receipt API. `local-experimental` is an explicit same-user guardrail, not host authentication or an ADR 3212 hostile-child boundary. When typed `spawn_agent` support is advertised, keep Ultragoal inactive while Main-root follows the ordered bootstrap: invoke `$ultragoal`; make one exact canonical Ultragoal state-activation attempt so the latest root transcript can seed the bootstrap (expect `OMX-ULTRAGOAL-BOOTSTRAP-REQUIRED`, not an active workflow); read the generation with `omx ultragoal native-bootstrap status --session-id <session-id> --json`; spawn one exact typed `executor` instructed to wait without tool calls for a post-activation follow-up; retain its returned `agent_path`; run `omx ultragoal native-bootstrap authorize --session-id <session-id> --root-thread-id <root-thread-id> --bootstrap-generation <generation> --child-path <agent-path> --path-prefix <repo-relative-path> --json`; retry the canonical Ultragoal activation; then start the authorized work with `followup_task`. Main-root owns `create-goals`, `complete-goals`, checkpoint, and other `.omx/ultragoal` metadata commands; delegate only substantive product writes to the executor. Use `--child-id` only when the host directly exposes the canonical child ID. Keep paths/actions minimal; use `omx ultragoal native-bootstrap status` to reconcile/recover and `omx ultragoal native-bootstrap revoke` when the executor is no longer needed. Follow `docs/native-subagent-assignments.md` for configuration and lifecycle details.
- **Inside active Autopilot**: keep `mode:"autopilot"` active and set the supervised phase to `current_phase:"ultragoal"`; do not start a peer Autopilot replacement. Ultragoal's own mode state may still exist as child-phase detail, but Autopilot owns the parent phase.
- **On handoff to code-review**: persist implementation/test/ledger evidence under Autopilot `handoff_artifacts.ultragoal`, then set Autopilot `current_phase:"code-review"`.
- **On completion/blocker**: set standalone Ultragoal `active:false,current_phase:"complete"` only when all durable goals are complete; otherwise keep it active with a blocker/review-blocked phase and ledger evidence.
@@ -61,12 +62,12 @@ Loop until `omx ultragoal status` reports all goals complete:
6. Run a completion audit against the story objective and real artifacts/tests.
7. In aggregate mode, do **not** call `update_goal` for intermediate stories; checkpoint with a fresh `get_goal` snapshot whose aggregate objective is still `active`. On the final story only, first run the mandatory final cleanup/review gate below; call `update_goal({status: "complete"})` only after that gate is clean, then call `get_goal` again for a fresh `complete` snapshot.
8. Checkpoint the durable ledger with that snapshot. Intermediate aggregate checkpoints use only `--codex-goal-json`; final clean checkpoints also require `--quality-gate-json`:
- `omx ultragoal checkpoint --goal-id <id> --status complete --evidence "<evidence>" --codex-goal-json <get_goal-json-or-path> [--quality-gate-json <quality-gate-json-or-path>]`
+ `omx ultragoal checkpoint --goal-id <id> --status complete --evidence "<evidence>" --codex-goal-json <get_goal-json-or-path> [--quality-gate-json <quality-gate-json-or-path>] --json`
9. If blocked or failed, checkpoint failure:
- `omx ultragoal checkpoint --goal-id <id> --status failed --evidence "<blocker/evidence>"`
+ `omx ultragoal checkpoint --goal-id <id> --status failed --evidence "<blocker/evidence>" --json`
10. For non-terminal blockers, use blocked checkpoints:
- - legacy different completed goal: `omx ultragoal checkpoint --goal-id <id> --status blocked --evidence "<completed legacy Codex goal blocks create_goal in this thread>" --codex-goal-json <get_goal-json-or-path>`
- - matching native Codex `blocked` status: `omx ultragoal checkpoint --goal-id <id> --status blocked --evidence "<blocker evidence>" --codex-goal-json <matching-blocked-get_goal-json-or-path>`
+ - legacy different completed goal: `omx ultragoal checkpoint --goal-id <id> --status blocked --evidence "<completed legacy Codex goal blocks create_goal in this thread>" --codex-goal-json <get_goal-json-or-path> --json`
+ - matching native Codex `blocked` status: `omx ultragoal checkpoint --goal-id <id> --status blocked --evidence "<blocker evidence>" --codex-goal-json <matching-blocked-get_goal-json-or-path> --json`
11. Resume failed goals with `omx ultragoal complete-goals --retry-failed`.
## Dynamic steering
@@ -106,7 +107,7 @@ Use ultragoal and team together for a durable Ultragoal story that benefits from
The leader checkpoints Ultragoal from Team evidence with a fresh `get_goal` snapshot:
```sh
-omx ultragoal checkpoint --goal-id <id> --status complete --evidence "<team evidence mentioning .omx/ultragoal and <id>>" --codex-goal-json <fresh-get_goal-json-or-path>
+omx ultragoal checkpoint --goal-id <id> --status complete --evidence "<team evidence mentioning .omx/ultragoal and <id>>" --codex-goal-json <fresh-get_goal-json-or-path> --json
```
Workers do not own ultragoal goal state, do not create worker ultragoal ledgers, and do not checkpoint Ultragoal. Team launch remains explicit; Ultragoal does not auto-launch Team and performs no hidden Codex goal mutation.
@@ -133,7 +134,7 @@ The final ultragoal story is not complete until the active agent has run the fin
```sh
- omx ultragoal checkpoint --goal-id <id> --status complete --evidence "<tests/files/review evidence>" --codex-goal-json <fresh-complete-get-goal-json-or-path> --quality-gate-json <quality-gate-json-or-path>
+ omx ultragoal checkpoint --goal-id <id> --status complete --evidence "<tests/files/review evidence>" --codex-goal-json <fresh-complete-get-goal-json-or-path> --quality-gate-json <quality-gate-json-or-path> --json
```
`--quality-gate-json` must include:
diff --git a/src/cli/__tests__/state.test.ts b/src/cli/__tests__/state.test.ts
index 9cd8028de2b1dbd5653043343f4e7babacf0bec3..b3cb8b08bb87df3db1c3ebeca532b55d7add0beb 100644
--- a/src/cli/__tests__/state.test.ts
+++ b/src/cli/__tests__/state.test.ts
@@ -1,10 +1,105 @@
import { describe, it } from 'node:test';
import assert from 'node:assert/strict';
-import { mkdtemp, rm, writeFile } from 'node:fs/promises';
+import { mkdir, mkdtemp, readFile, rm, writeFile } from 'node:fs/promises';
import { tmpdir } from 'node:os';
import { join } from 'node:path';
import { stateCommand } from '../state.js';
+import { __setWritableStateScopeTestHooksForTests } from '../../mcp/state-paths.js';
+import { recordNativeSubagentAuthorityObservation } from '../../subagents/tracker.js';
+import {
+ beginNativeUltragoalBootstrap,
+ findReadyLocalNativeExecutorAssignment,
+ issueLocalNativeExecutorAssignment,
+ markNativeUltragoalBootstrapActive,
+ NATIVE_ULTRAGOAL_BOOTSTRAP_FILE,
+ prepareNativeUltragoalBootstrapActivation,
+ readNativeUltragoalBootstrap,
+ revokeLocalNativeExecutorAssignment,
+} from '../../ultragoal/native-bootstrap.js';
+
+async function withNativeUltragoalActivationFixture<T>(
+ run: (fixture: { cwd: string; stateDir: string; sessionId: string; childAgentId: string }) => Promise<T>,
+ options: { activating?: boolean; pointerLiveness?: 'identity-indeterminate' | 'stale-dead' } = {},
+): Promise<T> {
+ const temporaryCwd = await mkdtemp(join(tmpdir(), 'omx-state-native-activation-'));
+ const previousCwd = process.cwd();
+ const envNames = [
+ 'CODEX_THREAD_ID',
+ 'CODEX_SESSION_ID',
+ 'SESSION_ID',
+ 'OMX_SESSION_ID',
+ 'OMX_TEAM_WORKER',
+ 'OMX_TEAM_INTERNAL_WORKER',
+ ] as const;
+ const previousEnv = Object.fromEntries(envNames.map((name) => [name, process.env[name]]));
+ const previousExitCode = process.exitCode;
+ try {
+ process.chdir(temporaryCwd);
+ const cwd = process.cwd();
+ for (const name of envNames) delete process.env[name];
+ const sessionId = 'native-activation-root';
+ const childAgentId = 'native-activation-child';
+ process.env.CODEX_THREAD_ID = sessionId;
+ const stateDir = join(cwd, '.omx', 'state');
+ await mkdir(stateDir, { recursive: true });
+ const bootstrap = await beginNativeUltragoalBootstrap({
+ cwd,
+ stateDir,
+ sessionId,
+ rootThreadId: sessionId,
+ backend: 'local-experimental',
+ ttlSeconds: 300,
+ });
+ recordNativeSubagentAuthorityObservation(cwd, {
+ sessionIds: [sessionId],
+ childThreadId: childAgentId,
+ parentThreadId: sessionId,
+ rootNativeSessionId: sessionId,
+ authorityEvidence: 'valid',
+ mode: 'executor',
+ });
+ await issueLocalNativeExecutorAssignment({
+ cwd,
+ stateDir,
+ sessionId,
+ rootThreadId: sessionId,
+ childAgentId,
+ expectedGeneration: bootstrap.generation,
+ pathPrefixes: ['src'],
+ ttlSeconds: 300,
+ });
+ if (options.activating !== false) {
+ const prepared = await prepareNativeUltragoalBootstrapActivation({
+ cwd,
+ stateDir,
+ sessionId,
+ childAgentId,
+ });
+ assert.equal(prepared.ok, true);
+ }
+ await writeFile(join(stateDir, 'session.json'), JSON.stringify({
+ session_id: sessionId,
+ native_session_id: sessionId,
+ cwd,
+ state_root: stateDir,
+ ...(options.pointerLiveness === 'stale-dead'
+ ? { pid: 2_147_483_647 }
+ : { pid_start_ticks: 1 }),
+ }));
+ process.exitCode = undefined;
+ return await run({ cwd, stateDir, sessionId, childAgentId });
+ } finally {
+ process.chdir(previousCwd);
+ process.exitCode = previousExitCode;
+ for (const name of envNames) {
+ const value = previousEnv[name];
+ if (typeof value === 'string') process.env[name] = value;
+ else delete process.env[name];
+ }
+ await rm(temporaryCwd, { recursive: true, force: true });
+ }
+}
describe('stateCommand', () => {
it('prints help for empty args', async () => {
@@ -226,4 +321,355 @@ describe('stateCommand', () => {
},
);
});
+
+ it('binds canonical native Ultragoal activation to exact indeterminate and stale root sessions', async () => {
+ for (const pointerLiveness of ['identity-indeterminate', 'stale-dead'] as const) {
+ await withNativeUltragoalActivationFixture(async ({ stateDir, sessionId }) => {
+ const stdout: string[] = [];
+ const stderr: string[] = [];
+ await stateCommand([
+ 'write',
+ '--input',
+ JSON.stringify({ mode: 'ultragoal', active: true, current_phase: 'planning' }),
+ '--json',
+ ], {
+ stdout: (line) => stdout.push(line),
+ stderr: (line) => stderr.push(line),
+ });
+
+ assert.equal(process.exitCode, undefined);
+ assert.deepEqual(stderr, []);
+ assert.equal(stdout.length, 1);
+ const state = JSON.parse(await readFile(
+ join(stateDir, 'sessions', sessionId, 'ultragoal-state.json'),
+ 'utf-8',
+ )) as Record<string, unknown>;
+ assert.equal(state.active, true);
+ assert.equal(state.current_phase, 'planning');
+ }, { pointerLiveness });
+ }
+ });
+
+ it('allows an exact active-session planning to executing update after bootstrap activation', async () => {
+ await withNativeUltragoalActivationFixture(async ({ cwd, stateDir, sessionId, childAgentId }) => {
+ const write = async (payload: Record<string, unknown>): Promise<string[]> => {
+ process.exitCode = undefined;
+ const stderr: string[] = [];
+ await stateCommand(['write', '--input', JSON.stringify(payload), '--json'], {
+ stdout: () => undefined,
+ stderr: (line) => stderr.push(line),
+ });
+ return stderr;
+ };
+
+ assert.deepEqual(await write({
+ mode: 'ultragoal',
+ active: true,
+ current_phase: 'planning',
+ }), []);
+ assert.equal((await markNativeUltragoalBootstrapActive({
+ cwd,
+ stateDir,
+ sessionId,
+ childAgentId,
+ })).ok, true);
+
+ assert.deepEqual(await write({
+ mode: 'ultragoal',
+ active: true,
+ current_phase: 'executing',
+ session_id: sessionId,
+ }), []);
+ const state = JSON.parse(await readFile(
+ join(stateDir, 'sessions', sessionId, 'ultragoal-state.json'),
+ 'utf-8',
+ )) as Record<string, unknown>;
+ assert.equal(state.active, true);
+ assert.equal(state.current_phase, 'executing');
+
+ const foreignSessionId = 'foreign-active-update';
+ const foreignError = await write({
+ mode: 'ultragoal',
+ active: true,
+ current_phase: 'executing',
+ session_id: foreignSessionId,
+ });
+ assert.equal(process.exitCode, 1);
+ assert.match(foreignError.join('\n'), /native_ultragoal_activation_receipt_invalid/);
+ await assert.rejects(
+ readFile(join(stateDir, 'sessions', foreignSessionId, 'ultragoal-state.json')),
+ /ENOENT/,
+ );
+ });
+ });
+
+ it('binds the exact terminal write to a completed aggregate checkpoint and revoked executor', async () => {
+ await withNativeUltragoalActivationFixture(async ({ cwd, stateDir, sessionId, childAgentId }) => {
+ const write = async (payload: Record<string, unknown>): Promise<string[]> => {
+ process.exitCode = undefined;
+ const stderr: string[] = [];
+ await stateCommand(['write', '--input', JSON.stringify(payload), '--json'], {
+ stdout: () => undefined,
+ stderr: (line) => stderr.push(line),
+ });
+ return stderr;
+ };
+ assert.deepEqual(await write({ mode: 'ultragoal', active: true, current_phase: 'planning' }), []);
+ assert.equal((await markNativeUltragoalBootstrapActive({
+ cwd,
+ stateDir,
+ sessionId,
+ childAgentId,
+ })).ok, true);
+ assert.deepEqual(await write({ mode: 'ultragoal', active: true, current_phase: 'checkpointing' }), []);
+ await mkdir(join(cwd, '.omx', 'ultragoal'), { recursive: true });
+ await writeFile(join(cwd, '.omx', 'ultragoal', 'goals.json'), JSON.stringify({
+ version: 1,
+ goals: [{ id: 'G001-terminal', status: 'complete' }],
+ aggregateCompletion: { status: 'complete', evidence: 'проверки пройдены' },
+ }));
+
+ const terminal = { mode: 'ultragoal', active: false, current_phase: 'complete' };
+ assert.match((await write(terminal)).join('\n'), /native_ultragoal_terminal_receipt_invalid/);
+ await revokeLocalNativeExecutorAssignment({ stateDir, sessionId, reason: 'aggregate_complete' });
+ assert.equal((await readNativeUltragoalBootstrap(stateDir, sessionId))?.status, 'revoked');
+ assert.equal(await findReadyLocalNativeExecutorAssignment({
+ cwd,
+ stateDir,
+ sessionId,
+ rootThreadId: sessionId,
+ }), null);
+ let mutated = false;
+ __setWritableStateScopeTestHooksForTests({
+ beforeScopeRevalidation: async () => {
+ if (mutated) return;
+ mutated = true;
+ await writeFile(join(cwd, '.omx', 'ultragoal', 'goals.json'), JSON.stringify({
+ version: 1,
+ goals: [{ id: 'G001-terminal', status: 'in_progress' }],
+ aggregateCompletion: { status: 'complete' },
+ }));
+ },
+ });
+ try {
+ assert.match((await write(terminal)).join('\n'), /native_ultragoal_terminal_receipt_invalid/);
+ assert.equal((JSON.parse(await readFile(
+ join(stateDir, 'sessions', sessionId, 'ultragoal-state.json'),
+ 'utf-8',
+ )) as Record<string, unknown>).current_phase, 'checkpointing');
+ } finally {
+ __setWritableStateScopeTestHooksForTests({});
+ }
+ await writeFile(join(cwd, '.omx', 'ultragoal', 'goals.json'), JSON.stringify({
+ version: 1,
+ goals: [{ id: 'G001-terminal', status: 'complete' }],
+ aggregateCompletion: { status: 'complete', evidence: 'проверки пройдены' },
+ }));
+ assert.deepEqual(await write(terminal), []);
+ const state = JSON.parse(await readFile(
+ join(stateDir, 'sessions', sessionId, 'ultragoal-state.json'),
+ 'utf-8',
+ )) as Record<string, unknown>;
+ assert.equal(state.active, false);
+ assert.equal(state.current_phase, 'complete');
+ });
+ });
+
+ it('does not authorize arbitrary state fields through the native activation fallback', async () => {
+ await withNativeUltragoalActivationFixture(async ({ stateDir, sessionId }) => {
+ const stderr: string[] = [];
+ await stateCommand([
+ 'write',
+ '--input',
+ JSON.stringify({
+ mode: 'ultragoal',
+ active: true,
+ current_phase: 'planning',
+ state: { arbitrary: true },
+ }),
+ '--json',
+ ], {
+ stdout: () => undefined,
+ stderr: (line) => stderr.push(line),
+ });
+
+ assert.equal(process.exitCode, 1);
+ assert.match(stderr.join('\n'), /native_ultragoal_activation_receipt_invalid/);
+ await assert.rejects(
+ readFile(join(stateDir, 'sessions', sessionId, 'ultragoal-state.json')),
+ /ENOENT/,
+ );
+ });
+ });
+
+ it('requires an activating bootstrap with a valid ready assignment', async () => {
+ await withNativeUltragoalActivationFixture(async ({ stateDir, sessionId }) => {
+ const stderr: string[] = [];
+ await stateCommand([
+ 'write',
+ '--input',
+ JSON.stringify({ mode: 'ultragoal', active: true, current_phase: 'planning' }),
+ '--json',
+ ], {
+ stdout: () => undefined,
+ stderr: (line) => stderr.push(line),
+ });
+
+ assert.equal(process.exitCode, 1);
+ assert.match(stderr.join('\n'), /native_ultragoal_activation_receipt_invalid/);
+ await assert.rejects(
+ readFile(join(stateDir, 'sessions', sessionId, 'ultragoal-state.json')),
+ /ENOENT/,
+ );
+ }, { activating: false });
+ });
+
+ it('rejects mismatched root-thread and Team-worker activation fallback identities', async () => {
+ for (const configure of [
+ () => { process.env.CODEX_THREAD_ID = 'foreign-root-thread'; },
+ () => { process.env.OMX_TEAM_WORKER = 'native-team/worker-1'; },
+ ]) {
+ await withNativeUltragoalActivationFixture(async ({ stateDir, sessionId }) => {
+ configure();
+ const stderr: string[] = [];
+ await stateCommand([
+ 'write',
+ '--input',
+ JSON.stringify({ mode: 'ultragoal', active: true, current_phase: 'planning' }),
+ '--json',
+ ], {
+ stdout: () => undefined,
+ stderr: (line) => stderr.push(line),
+ });
+
+ assert.equal(process.exitCode, 1);
+ assert.match(stderr.join('\n'), /native_ultragoal_activation_receipt_invalid/);
+ await assert.rejects(
+ readFile(join(stateDir, 'sessions', sessionId, 'ultragoal-state.json')),
+ /ENOENT/,
+ );
+ });
+ }
+ });
+
+ it('never lets a foreign explicit session_id bypass native activation verification', async () => {
+ await withNativeUltragoalActivationFixture(async ({ stateDir }) => {
+ const foreignSessionId = 'foreign-explicit-session';
+ const payloads = [
+ {
+ mode: 'ultragoal',
+ active: true,
+ current_phase: 'planning',
+ session_id: foreignSessionId,
+ },
+ {
+ mode: 'ultragoal',
+ active: true,
+ current_phase: 'planning',
+ session_id: foreignSessionId,
+ extra: 'bypass-attempt',
+ },
+ {
+ mode: 'ultragoal',
+ session_id: foreignSessionId,
+ state: { active: true, current_phase: 'planning' },
+ },
+ {
+ mode: 'ultragoal',
+ active: true,
+ current_phase: 'executing',
+ session_id: foreignSessionId,
+ },
+ {
+ mode: 'ultragoal',
+ session_id: foreignSessionId,
+ state: { active: true, currentPhase: 'executing' },
+ },
+ ];
+ for (const payload of payloads) {
+ process.exitCode = undefined;
+ const stderr: string[] = [];
+ await stateCommand([
+ 'write',
+ '--input',
+ JSON.stringify(payload),
+ '--json',
+ ], {
+ stdout: () => undefined,
+ stderr: (line) => stderr.push(line),
+ });
+
+ assert.equal(process.exitCode, 1);
+ assert.match(stderr.join('\n'), /native_ultragoal_activation_receipt_invalid/);
+ }
+ await assert.rejects(
+ readFile(join(stateDir, 'sessions', foreignSessionId, 'ultragoal-state.json')),
+ /ENOENT/,
+ );
+ });
+ });
+
+ it('preserves existing explicit-session behavior for non-activation writes', async () => {
+ const input = {
+ mode: 'ultragoal',
+ active: false,
+ current_phase: 'complete',
+ session_id: 'existing-explicit-session',
+ };
+ let captured: Record<string, unknown> | undefined;
+ await stateCommand(['write', '--input', JSON.stringify(input), '--json'], {
+ stdout: () => undefined,
+ stderr: () => undefined,
+ execute: async (_operation, rawInput) => {
+ captured = rawInput;
+ return { payload: { success: true } };
+ },
+ });
+ assert.deepEqual(captured, input);
+ });
+
+ it('revalidates revoke and expiry races under the native lifecycle lock before commit', async () => {
+ for (const mutation of ['revoke', 'expire'] as const) {
+ await withNativeUltragoalActivationFixture(async ({ stateDir, sessionId }) => {
+ const bootstrapPath = join(
+ stateDir,
+ 'sessions',
+ sessionId,
+ NATIVE_ULTRAGOAL_BOOTSTRAP_FILE,
+ );
+ let mutated = false;
+ __setWritableStateScopeTestHooksForTests({
+ beforeScopeRevalidation: async () => {
+ if (mutated) return;
+ mutated = true;
+ const bootstrap = JSON.parse(await readFile(bootstrapPath, 'utf-8')) as Record<string, unknown>;
+ await writeFile(bootstrapPath, JSON.stringify(mutation === 'revoke'
+ ? { ...bootstrap, status: 'revoked' }
+ : { ...bootstrap, expires_at: '2000-01-01T00:00:00.000Z' }));
+ },
+ });
+ try {
+ const stderr: string[] = [];
+ await stateCommand([
+ 'write',
+ '--input',
+ JSON.stringify({ mode: 'ultragoal', active: true, current_phase: 'planning' }),
+ '--json',
+ ], {
+ stdout: () => undefined,
+ stderr: (line) => stderr.push(line),
+ });
+
+ assert.equal(process.exitCode, 1);
+ assert.match(stderr.join('\n'), /native_ultragoal_activation_receipt_invalid/);
+ await assert.rejects(
+ readFile(join(stateDir, 'sessions', sessionId, 'ultragoal-state.json')),
+ /ENOENT/,
+ );
+ } finally {
+ __setWritableStateScopeTestHooksForTests({});
+ }
+ });
+ }
+ });
});
diff --git a/src/cli/__tests__/team.test.ts b/src/cli/__tests__/team.test.ts
index 4260428cca238e885b4d147a3537185bf824ffab..1a2783b2fbe335102327a552127b28c93e2a3e01 100644
--- a/src/cli/__tests__/team.test.ts
+++ b/src/cli/__tests__/team.test.ts
@@ -3118,6 +3118,7 @@ exit 1
assert.equal(payload.ultragoal_checkpoint_guidance?.checkpoint_policy, 'fresh_leader_get_goal_required');
assert.match(payload.ultragoal_checkpoint_guidance?.checkpoint_command_template ?? '', /omx ultragoal checkpoint/);
assert.match(payload.ultragoal_checkpoint_guidance?.checkpoint_command_template ?? '', /--codex-goal-json/);
+ assert.match(payload.ultragoal_checkpoint_guidance?.checkpoint_command_template ?? '', /--json$/);
assert.ok(payload.ultragoal_checkpoint_guidance?.evidence_requirements?.some((item) => item.includes('.omx/ultragoal artifacts')));
} finally {
console.log = originalLog;
diff --git a/src/cli/__tests__/ultragoal.test.ts b/src/cli/__tests__/ultragoal.test.ts
index 74c6d1f2457e75733cd677dd1b6c462d7ac794ae..72cbb3a9bbfd585865c613831af38da8062b5b96 100644
--- a/src/cli/__tests__/ultragoal.test.ts
+++ b/src/cli/__tests__/ultragoal.test.ts
@@ -14,6 +14,10 @@ import {
NATIVE_SUBAGENT_ROLE_ROUTING_MARKER_FILE,
writeRoleRoutingMarker,
} from '../../subagents/role-routing-marker.js';
+import {
+ beginNativeUltragoalBootstrap,
+ nativeExecutorAssignmentPath,
+} from '../../ultragoal/native-bootstrap.js';
import { ultragoalCommand, ULTRAGOAL_HELP } from '../ultragoal.js';
async function withCwd<T>(run: (cwd: string) => Promise<T>): Promise<T> {
@@ -67,6 +71,33 @@ async function capture(run: () => Promise<void>): Promise<{ stdout: string[]; st
}
}
+async function withNativeBootstrapEnv(
+ values: Partial<Record<'CODEX_HOME' | 'CODEX_THREAD_ID' | 'CODEX_SESSION_ID' | 'SESSION_ID' | 'OMX_SESSION_ID' | 'OMX_TEAM_WORKER' | 'OMX_TEAM_INTERNAL_WORKER', string>>,
+ run: () => Promise<void>,
+): Promise<void> {
+ const names = [
+ 'CODEX_HOME',
+ 'CODEX_THREAD_ID',
+ 'CODEX_SESSION_ID',
+ 'SESSION_ID',
+ 'OMX_SESSION_ID',
+ 'OMX_TEAM_WORKER',
+ 'OMX_TEAM_INTERNAL_WORKER',
+ ] as const;
+ const previous = Object.fromEntries(names.map((name) => [name, process.env[name]]));
+ try {
+ for (const name of names) delete process.env[name];
+ for (const [name, value] of Object.entries(values)) process.env[name] = value;
+ await run();
+ } finally {
+ for (const name of names) {
+ const value = previous[name];
+ if (typeof value === 'string') process.env[name] = value;
+ else delete process.env[name];
+ }
+ }
+}
+
describe('cli/ultragoal', () => {
it('does not create durable artifacts when OMX_SESSION_ID is unbound', async () => {
await withCwd(async (cwd) => {
@@ -144,6 +175,7 @@ describe('cli/ultragoal', () => {
['next'],
['start-next'],
['checkpoint', '--goal-id', 'G001-first', '--status', 'complete', '--evidence', 'worker evidence'],
+ ['native-bootstrap', 'revoke', '--session-id', 'worker-session'],
];
const envCases: Array<[string, string]> = [
['OMX_TEAM_WORKER', 'display-team/worker-1'],
@@ -214,6 +246,337 @@ describe('cli/ultragoal', () => {
assert.match(ULTRAGOAL_HELP, /quality-gate-json/);
assert.match(ULTRAGOAL_HELP, /ai-slop-cleaner/);
assert.match(ULTRAGOAL_HELP, /code-review/);
+ assert.match(ULTRAGOAL_HELP, /native-bootstrap <authorize\|status\|revoke>/);
+ assert.match(ULTRAGOAL_HELP, /--child-id <id> \| --child-path <agent-path>/);
+ });
+
+ it('authorizes, reports, and revokes an experimental native executor bootstrap', async () => {
+ await withCwd(async (cwd) => {
+ const previousBackend = process.env.OMX_NATIVE_ULTRAGOAL_BACKEND;
+ process.env.OMX_NATIVE_ULTRAGOAL_BACKEND = 'local-experimental';
+ const stateDir = join(cwd, '.omx', 'state');
+ const sessionId = 'native-cli-session';
+ const rootThreadId = 'native-cli-root';
+ const childAgentId = '019faf84-1111-7000-8000-000000000001';
+ const childAgentPath = '/root/native_cli_executor';
+ const codexHome = join(cwd, 'codex-home');
+ try {
+ await mkdir(stateDir, { recursive: true });
+ await writeFile(join(stateDir, 'session.json'), `${JSON.stringify({
+ session_id: sessionId,
+ native_session_id: rootThreadId,
+ cwd,
+ })}\n`);
+ await writeFile(join(stateDir, 'subagent-tracking.json'), `${JSON.stringify({
+ schemaVersion: 1,
+ sessions: {
+ [sessionId]: {
+ session_id: sessionId,
+ leader_thread_id: rootThreadId,
+ updated_at: new Date().toISOString(),
+ threads: {
+ [rootThreadId]: {
+ thread_id: rootThreadId,
+ kind: 'leader',
+ first_seen_at: new Date().toISOString(),
+ last_seen_at: new Date().toISOString(),
+ turn_count: 1,
+ },
+ [childAgentId]: {
+ thread_id: childAgentId,
+ kind: 'subagent',
+ first_seen_at: new Date().toISOString(),
+ last_seen_at: new Date().toISOString(),
+ turn_count: 1,
+ mode: 'executor',
+ status: 'available',
+ provenance_kind: 'native_subagent',
+ direct_child_parent_id: rootThreadId,
+ direct_child_root_id: rootThreadId,
+ },
+ },
+ },
+ },
+ }, null, 2)}\n`);
+ const initialBootstrap = await beginNativeUltragoalBootstrap({
+ cwd,
+ stateDir,
+ sessionId,
+ rootThreadId,
+ backend: 'local-experimental',
+ ttlSeconds: 900,
+ });
+ const rolloutDir = join(codexHome, 'sessions', '2026', '07', '29');
+ await mkdir(rolloutDir, { recursive: true });
+ await writeFile(join(rolloutDir, `rollout-test-${childAgentId}.jsonl`), `${JSON.stringify({
+ timestamp: initialBootstrap.created_at,
+ type: 'session_meta',
+ payload: {
+ id: childAgentId,
+ session_id: sessionId,
+ cwd,
+ source: {
+ subagent: {
+ thread_spawn: {
+ parent_thread_id: rootThreadId,
+ depth: 1,
+ agent_path: childAgentPath,
+ agent_role: 'executor',
+ },
+ },
+ },
+ },
+ })}\n`);
+
+ await withNativeBootstrapEnv({ CODEX_HOME: codexHome, CODEX_THREAD_ID: rootThreadId }, async () => {
+ const crossSession = await capture(() => ultragoalCommand([
+ 'native-bootstrap', 'status', '--session-id', 'foreign-session', '--json',
+ ]));
+ assert.equal(crossSession.exitCode, 1);
+ assert.match(crossSession.stderr.join('\n'), /does not match the canonical current runtime session/);
+ const omittedSession = await capture(() => ultragoalCommand([
+ 'native-bootstrap', 'status', '--json',
+ ]));
+ assert.equal(omittedSession.exitCode, 1);
+ assert.match(omittedSession.stderr.join('\n'), /require an explicit --session-id/);
+
+ const missingChild = await capture(() => ultragoalCommand([
+ 'native-bootstrap', 'authorize',
+ '--session-id', sessionId,
+ '--root-thread-id', rootThreadId,
+ '--bootstrap-generation', initialBootstrap.generation,
+ '--path-prefix', 'src',
+ ]));
+ assert.equal(missingChild.exitCode, 1);
+ assert.match(missingChild.stderr.join('\n'), /exactly one of --child-id or --child-path/);
+
+ const conflictingChild = await capture(() => ultragoalCommand([
+ 'native-bootstrap', 'authorize',
+ '--session-id', sessionId,
+ '--root-thread-id', rootThreadId,
+ '--child-id', childAgentId,
+ '--child-path', childAgentPath,
+ '--bootstrap-generation', initialBootstrap.generation,
+ '--path-prefix', 'src',
+ ]));
+ assert.equal(conflictingChild.exitCode, 1);
+ assert.match(conflictingChild.stderr.join('\n'), /exactly one of --child-id or --child-path/);
+
+ const authorized = await capture(() => ultragoalCommand([
+ 'native-bootstrap', 'authorize',
+ '--session-id', sessionId,
+ '--root-thread-id', rootThreadId,
+ '--child-path', childAgentPath,
+ '--bootstrap-generation', initialBootstrap.generation,
+ '--path-prefix', 'src',
+ '--json',
+ ]));
+ assert.equal(authorized.exitCode, undefined, authorized.stderr.join('\n'));
+ assert.equal(JSON.parse(authorized.stdout.join('\n')).assignment.child_agent_id, childAgentId);
+ assert.equal(existsSync(nativeExecutorAssignmentPath(stateDir, sessionId, childAgentId)), true);
+
+ const status = await capture(() => ultragoalCommand([
+ 'native-bootstrap', 'status', '--session-id', sessionId, '--json',
+ ]));
+ const statusPayload = JSON.parse(status.stdout.join('\n')) as {
+ bootstrap: { status: string };
+ readiness: { ready: boolean };
+ };
+ assert.equal(statusPayload.bootstrap.status, 'ready');
+ assert.equal(statusPayload.readiness.ready, true);
+
+ const revoked = await capture(() => ultragoalCommand([
+ 'native-bootstrap', 'revoke', '--session-id', sessionId, '--json',
+ ]));
+ assert.equal(revoked.exitCode, undefined);
+ assert.equal(JSON.parse(revoked.stdout.join('\n')).status, 'revoked');
+
+ await mkdir(join(stateDir, 'sessions', sessionId), { recursive: true });
+ await writeFile(join(stateDir, 'sessions', sessionId, 'ultragoal-state.json'), `${JSON.stringify({
+ mode: 'ultragoal',
+ active: true,
+ current_phase: 'executing',
+ session_id: sessionId,
+ })}\n`);
+ const recoveryBootstrap = await beginNativeUltragoalBootstrap({
+ cwd,
+ stateDir,
+ sessionId,
+ rootThreadId,
+ backend: 'local-experimental',
+ ttlSeconds: 900,
+ });
+ const recovered = await capture(() => ultragoalCommand([
+ 'native-bootstrap', 'authorize',
+ '--session-id', sessionId,
+ '--root-thread-id', rootThreadId,
+ '--child-id', childAgentId,
+ '--bootstrap-generation', recoveryBootstrap.generation,
+ '--path-prefix', 'src',
+ '--json',
+ ]));
+ assert.equal(recovered.exitCode, undefined);
+ const recoveredStatus = await capture(() => ultragoalCommand([
+ 'native-bootstrap', 'status', '--session-id', sessionId, '--json',
+ ]));
+ assert.equal(JSON.parse(recoveredStatus.stdout.join('\n')).bootstrap.status, 'active');
+ });
+ } finally {
+ if (typeof previousBackend === 'string') process.env.OMX_NATIVE_ULTRAGOAL_BACKEND = previousBackend;
+ else delete process.env.OMX_NATIVE_ULTRAGOAL_BACKEND;
+ }
+ });
+ });
+
+ it('uses an exact CODEX_THREAD_ID binding for native-bootstrap with an identity-indeterminate pointer', async () => {
+ await withCwd(async () => {
+ const sessionId = 'native-bootstrap-indeterminate';
+ const runtimeCwd = process.cwd();
+ const stateDir = join(runtimeCwd, '.omx', 'state');
+ await mkdir(stateDir, { recursive: true });
+ await writeFile(join(stateDir, 'session.json'), `${JSON.stringify({
+ session_id: sessionId,
+ native_session_id: sessionId,
+ cwd: runtimeCwd,
+ state_root: stateDir,
+ pid_start_ticks: 1,
+ })}\n`);
+
+ await withNativeBootstrapEnv({ CODEX_THREAD_ID: sessionId }, async () => {
+ const result = await capture(() => ultragoalCommand([
+ 'native-bootstrap', 'status', '--session-id', sessionId, '--json',
+ ]));
+
+ assert.equal(result.exitCode, undefined, result.stderr.join('\n'));
+ assert.equal(JSON.parse(result.stdout.join('\n')).bootstrap, null);
+ });
+ });
+ });
+
+ it('rejects the native-bootstrap fallback when CODEX_THREAD_ID does not match', async () => {
+ await withCwd(async () => {
+ const sessionId = 'native-bootstrap-thread-owner';
+ const runtimeCwd = process.cwd();
+ const stateDir = join(runtimeCwd, '.omx', 'state');
+ await mkdir(stateDir, { recursive: true });
+ await writeFile(join(stateDir, 'session.json'), `${JSON.stringify({
+ session_id: sessionId,
+ native_session_id: sessionId,
+ cwd: runtimeCwd,
+ state_root: stateDir,
+ pid_start_ticks: 1,
+ })}\n`);
+
+ await withNativeBootstrapEnv({ CODEX_THREAD_ID: 'native-bootstrap-child-thread' }, async () => {
+ const result = await capture(() => ultragoalCommand([
+ 'native-bootstrap', 'status', '--session-id', sessionId, '--json',
+ ]));
+
+ assert.equal(result.exitCode, 1);
+ assert.match(result.stderr.join('\n'), /canonical current runtime session/);
+ });
+ });
+ });
+
+ it('rejects the native-bootstrap fallback when CODEX_THREAD_ID is absent', async () => {
+ await withCwd(async () => {
+ const sessionId = 'native-bootstrap-missing-thread';
+ const runtimeCwd = process.cwd();
+ const stateDir = join(runtimeCwd, '.omx', 'state');
+ await mkdir(stateDir, { recursive: true });
+ await writeFile(join(stateDir, 'session.json'), `${JSON.stringify({
+ session_id: sessionId,
+ native_session_id: sessionId,
+ cwd: runtimeCwd,
+ state_root: stateDir,
+ pid_start_ticks: 1,
+ })}\n`);
+
+ await withNativeBootstrapEnv({}, async () => {
+ const result = await capture(() => ultragoalCommand([
+ 'native-bootstrap', 'status', '--session-id', sessionId, '--json',
+ ]));
+
+ assert.equal(result.exitCode, 1);
+ assert.match(result.stderr.join('\n'), /canonical current runtime session/);
+ });
+ });
+ });
+
+ it('rejects the native-bootstrap fallback when native_session_id does not match', async () => {
+ await withCwd(async () => {
+ const sessionId = 'native-bootstrap-native-owner';
+ const runtimeCwd = process.cwd();
+ const stateDir = join(runtimeCwd, '.omx', 'state');
+ await mkdir(stateDir, { recursive: true });
+ await writeFile(join(stateDir, 'session.json'), `${JSON.stringify({
+ session_id: sessionId,
+ native_session_id: 'foreign-native-session',
+ cwd: runtimeCwd,
+ state_root: stateDir,
+ pid_start_ticks: 1,
+ })}\n`);
+
+ await withNativeBootstrapEnv({ CODEX_THREAD_ID: sessionId }, async () => {
+ const result = await capture(() => ultragoalCommand([
+ 'native-bootstrap', 'status', '--session-id', sessionId, '--json',
+ ]));
+
+ assert.equal(result.exitCode, 1);
+ assert.match(result.stderr.join('\n'), /canonical current runtime session/);
+ });
+ });
+ });
+
+ it('rejects the native-bootstrap fallback when the pointer cwd does not match exactly', async () => {
+ await withCwd(async () => {
+ const sessionId = 'native-bootstrap-cwd-owner';
+ const runtimeCwd = process.cwd();
+ const stateDir = join(runtimeCwd, '.omx', 'state');
+ await mkdir(stateDir, { recursive: true });
+ await writeFile(join(stateDir, 'session.json'), `${JSON.stringify({
+ session_id: sessionId,
+ native_session_id: sessionId,
+ cwd: join(runtimeCwd, 'nested'),
+ state_root: stateDir,
+ })}\n`);
+
+ await withNativeBootstrapEnv({ CODEX_THREAD_ID: sessionId }, async () => {
+ const result = await capture(() => ultragoalCommand([
+ 'native-bootstrap', 'status', '--session-id', sessionId, '--json',
+ ]));
+
+ assert.equal(result.exitCode, 1);
+ assert.match(result.stderr.join('\n'), /canonical current runtime session/);
+ });
+ });
+ });
+
+ it('rejects the native-bootstrap fallback from a Team worker identity', async () => {
+ await withCwd(async () => {
+ const sessionId = 'native-bootstrap-team-owner';
+ const runtimeCwd = process.cwd();
+ const stateDir = join(runtimeCwd, '.omx', 'state');
+ await mkdir(stateDir, { recursive: true });
+ await writeFile(join(stateDir, 'session.json'), `${JSON.stringify({
+ session_id: sessionId,
+ native_session_id: sessionId,
+ cwd: runtimeCwd,
+ state_root: stateDir,
+ })}\n`);
+
+ await withNativeBootstrapEnv({
+ CODEX_THREAD_ID: sessionId,
+ OMX_TEAM_WORKER: 'native-team/worker-1',
+ }, async () => {
+ const result = await capture(() => ultragoalCommand([
+ 'native-bootstrap', 'status', '--session-id', sessionId, '--json',
+ ]));
+
+ assert.equal(result.exitCode, 1);
+ assert.match(result.stderr.join('\n'), /leader-owned/i);
+ });
+ });
});
it('creates and starts goals through the command surface', async () => {
diff --git a/src/cli/state.ts b/src/cli/state.ts
index 79298ade3c57cd4d7b93bcd24e02e4a1dc7db3b7..508f0d1155f77a6c57d3c0389e533b62fe3abc31 100644
--- a/src/cli/state.ts
+++ b/src/cli/state.ts
@@ -1,6 +1,16 @@
-import { readFile } from 'node:fs/promises';
+import { constants as fsConstants } from 'node:fs';
+import { lstat, open, readFile } from 'node:fs/promises';
+import { join } from 'node:path';
+import { classifySessionStateLiveness, isSessionStateAuthoritativeForCwd, type SessionState } from '../hooks/session.js';
+import { getBaseStateDirWithSource, normalizeSessionId, resolveWorkingDirectoryForState } from '../mcp/state-paths.js';
import { executeStateOperation, type StateOperationName } from '../state/operations.js';
+import {
+ findReadyLocalNativeExecutorAssignment,
+ readNativeUltragoalBootstrap,
+ withNativeUltragoalActivationAuthorization,
+} from '../ultragoal/native-bootstrap.js';
+import { sameFilePath } from '../utils/paths.js';
const STATE_HELP = `Usage: omx state <read|write|clear|list-active|get-status> [--input <json> | --input-file <path>] [--mode <mode>] [--json]
@@ -64,6 +74,242 @@ function parseStateInputJson(
return { ...(parsed as Record<string, unknown>) };
}
+async function readSafeSelectedSessionPointer(path: string): Promise<SessionState | null> {
+ const metadata = await lstat(path).catch(() => null);
+ if (
+ !metadata
+ || !metadata.isFile()
+ || metadata.isSymbolicLink()
+ || metadata.nlink !== 1
+ || (metadata.mode & 0o022) !== 0
+ || metadata.size > 64 * 1024
+ ) return null;
+
+ const handle = await open(path, fsConstants.O_RDONLY | (fsConstants.O_NOFOLLOW ?? 0)).catch(() => null);
+ if (!handle) return null;
+ try {
+ const openedMetadata = await handle.stat();
+ if (
+ !openedMetadata.isFile()
+ || openedMetadata.dev !== metadata.dev
+ || openedMetadata.ino !== metadata.ino
+ || openedMetadata.nlink !== 1
+ || (openedMetadata.mode & 0o022) !== 0
+ || openedMetadata.size > 64 * 1024
+ ) return null;
+ const contents = await handle.readFile('utf-8');
+ const finalMetadata = await handle.stat();
+ if (
+ finalMetadata.dev !== openedMetadata.dev
+ || finalMetadata.ino !== openedMetadata.ino
+ || finalMetadata.nlink !== 1
+ || (finalMetadata.mode & 0o022) !== 0
+ || finalMetadata.size !== openedMetadata.size
+ || finalMetadata.mtimeMs !== openedMetadata.mtimeMs
+ || finalMetadata.ctimeMs !== openedMetadata.ctimeMs
+ ) return null;
+ const parsed = JSON.parse(contents) as unknown;
+ return parsed && typeof parsed === 'object' && !Array.isArray(parsed)
+ ? parsed as SessionState
+ : null;
+ } catch {
+ return null;
+ } finally {
+ await handle.close().catch(() => {});
+ }
+}
+
+async function readSafeJsonRecord(path: string): Promise<Record<string, unknown> | null> {
+ const value = await readSafeSelectedSessionPointer(path);
+ return value as Record<string, unknown> | null;
+}
+
+function isCanonicalNativeUltragoalActivation(input: Record<string, unknown>): boolean {
+ const keys = Object.keys(input).sort().join(',');
+ return (keys === 'active,current_phase,mode' || keys === 'active,current_phase,mode,session_id')
+ && typeof input.current_phase === 'string'
+ && isNativeUltragoalActivationIntent(input);
+}
+
+function isNativeUltragoalActivationIntent(input: Record<string, unknown>): boolean {
+ const nested = input.state && typeof input.state === 'object' && !Array.isArray(input.state)
+ ? input.state as Record<string, unknown>
+ : {};
+ const active = Object.prototype.hasOwnProperty.call(nested, 'active')
+ ? nested.active
+ : input.active;
+ const phase = nested.current_phase
+ ?? nested.currentPhase
+ ?? input.current_phase
+ ?? input.currentPhase;
+ const normalizedPhase = typeof phase === 'string' ? phase.trim().toLowerCase() : '';
+ return input.mode === 'ultragoal'
+ && active === true
+ && normalizedPhase !== ''
+ && !['complete', 'completed', 'cancelled', 'canceled', 'failed', 'cleared'].includes(normalizedPhase);
+}
+
+function isCanonicalNativeUltragoalTerminalIntent(input: Record<string, unknown>): boolean {
+ const keys = Object.keys(input).sort().join(',');
+ return keys === 'active,current_phase,mode'
+ && input.mode === 'ultragoal'
+ && input.active === false
+ && input.current_phase === 'complete';
+}
+
+function hasTeamWorkerIdentity(): boolean {
+ return Boolean(process.env.OMX_TEAM_WORKER?.trim() || process.env.OMX_TEAM_INTERNAL_WORKER?.trim());
+}
+
+async function sessionHasActiveUltragoalState(
+ stateDir: string,
+ sessionId: string,
+): Promise<boolean> {
+ try {
+ const state = JSON.parse(await readFile(
+ join(stateDir, 'sessions', sessionId, 'ultragoal-state.json'),
+ 'utf-8',
+ )) as Record<string, unknown>;
+ const phase = typeof state.current_phase === 'string' ? state.current_phase.trim().toLowerCase() : '';
+ return state.active === true
+ && phase !== ''
+ && !['complete', 'completed', 'cancelled', 'canceled', 'failed', 'cleared'].includes(phase);
+ } catch {
+ return false;
+ }
+}
+
+async function resolveNativeUltragoalActivationSession(
+ input: Record<string, unknown>,
+): Promise<{
+ cwd: string;
+ stateDir: string;
+ sessionId: string;
+ childAgentId: string;
+ bootstrapStatus: 'activating' | 'active';
+} | null> {
+ if (!isCanonicalNativeUltragoalActivation(input) || hasTeamWorkerIdentity()) return null;
+ const threadId = process.env.CODEX_THREAD_ID;
+ if (!threadId || normalizeSessionId(threadId) !== threadId) return null;
+ if (
+ Object.prototype.hasOwnProperty.call(input, 'session_id')
+ && input.session_id !== threadId
+ ) return null;
+
+ const cwd = resolveWorkingDirectoryForState();
+ const { baseStateDir } = getBaseStateDirWithSource(cwd);
+ const pointer = await readSafeSelectedSessionPointer(join(baseStateDir, 'session.json'));
+ if (
+ !pointer
+ || pointer.session_id !== threadId
+ || normalizeSessionId(pointer.session_id) !== threadId
+ || pointer.native_session_id !== threadId
+ || normalizeSessionId(pointer.native_session_id) !== threadId
+ || !isSessionStateAuthoritativeForCwd(pointer, cwd)
+ || !['identity-indeterminate', 'stale-dead'].includes(classifySessionStateLiveness(pointer))
+ ) return null;
+ const pointerStateRoot = typeof pointer.state_root === 'string'
+ ? pointer.state_root
+ : join(cwd, '.omx', 'state');
+ if (!sameFilePath(pointerStateRoot, baseStateDir)) return null;
+
+ const existingActiveState = await sessionHasActiveUltragoalState(baseStateDir, threadId);
+ const bootstrapStatus = existingActiveState ? 'active' : 'activating';
+ if (bootstrapStatus === 'activating' && input.current_phase !== 'planning') return null;
+ const bootstrapBefore = await readNativeUltragoalBootstrap(baseStateDir, threadId);
+ if (
+ !bootstrapBefore
+ || bootstrapBefore.status !== bootstrapStatus
+ || bootstrapBefore.session_id !== threadId
+ || bootstrapBefore.root_thread_id !== threadId
+ || !bootstrapBefore.child_agent_id
+ ) return null;
+ const assignment = await findReadyLocalNativeExecutorAssignment({
+ cwd,
+ stateDir: baseStateDir,
+ sessionId: threadId,
+ rootThreadId: threadId,
+ });
+ if (!assignment || assignment.child_agent_id !== bootstrapBefore.child_agent_id) return null;
+ const bootstrapAfter = await readNativeUltragoalBootstrap(baseStateDir, threadId);
+ if (
+ !bootstrapAfter
+ || bootstrapAfter.status !== bootstrapStatus
+ || bootstrapAfter.generation !== bootstrapBefore.generation
+ || bootstrapAfter.child_agent_id !== bootstrapBefore.child_agent_id
+ ) return null;
+ return {
+ cwd,
+ stateDir: baseStateDir,
+ sessionId: threadId,
+ childAgentId: assignment.child_agent_id,
+ bootstrapStatus,
+ };
+}
+
+async function resolveNativeUltragoalTerminalSession(
+ input: Record<string, unknown>,
+ allowPersistedTerminal = false,
+): Promise<{ sessionId: string } | null> {
+ if (!isCanonicalNativeUltragoalTerminalIntent(input) || hasTeamWorkerIdentity()) return null;
+ const threadId = process.env.CODEX_THREAD_ID;
+ if (!threadId || normalizeSessionId(threadId) !== threadId) return null;
+
+ const cwd = resolveWorkingDirectoryForState();
+ const { baseStateDir } = getBaseStateDirWithSource(cwd);
+ const pointer = await readSafeSelectedSessionPointer(join(baseStateDir, 'session.json'));
+ if (
+ !pointer
+ || pointer.session_id !== threadId
+ || pointer.native_session_id !== threadId
+ || !isSessionStateAuthoritativeForCwd(pointer, cwd)
+ || !['usable', 'identity-indeterminate'].includes(classifySessionStateLiveness(pointer))
+ ) return null;
+ const pointerStateRoot = typeof pointer.state_root === 'string'
+ ? pointer.state_root
+ : join(cwd, '.omx', 'state');
+ if (!sameFilePath(pointerStateRoot, baseStateDir)) return null;
+
+ const state = await readSafeJsonRecord(join(baseStateDir, 'sessions', threadId, 'ultragoal-state.json'));
+ const persistedStateIsAuthorized = Boolean(
+ state
+ && (
+ (state.active === true && state.current_phase === 'checkpointing')
+ || (allowPersistedTerminal && state.active === false && state.current_phase === 'complete')
+ )
+ && (typeof state.session_id !== 'string' || state.session_id === threadId),
+ );
+ if (!persistedStateIsAuthorized) return null;
+ const plan = await readSafeJsonRecord(join(cwd, '.omx', 'ultragoal', 'goals.json'));
+ const goals = Array.isArray(plan?.goals) ? plan.goals : [];
+ const aggregateCompletion = plan?.aggregateCompletion && typeof plan.aggregateCompletion === 'object'
+ && !Array.isArray(plan.aggregateCompletion)
+ ? plan.aggregateCompletion as Record<string, unknown>
+ : null;
+ if (
+ goals.length === 0
+ || goals.some((goal) => !goal || typeof goal !== 'object' || Array.isArray(goal)
+ || (goal as Record<string, unknown>).status !== 'complete')
+ || aggregateCompletion?.status !== 'complete'
+ ) return null;
+
+ const bootstrap = await readNativeUltragoalBootstrap(baseStateDir, threadId);
+ if (
+ !bootstrap
+ || bootstrap.status !== 'revoked'
+ || bootstrap.session_id !== threadId
+ || bootstrap.root_thread_id !== threadId
+ || !bootstrap.child_agent_id
+ ) return null;
+ const assignment = await findReadyLocalNativeExecutorAssignment({
+ cwd,
+ stateDir: baseStateDir,
+ sessionId: threadId,
+ rootThreadId: threadId,
+ });
+ return assignment ? null : { sessionId: threadId };
+}
+
export async function stateCommand(
args: string[],
deps: StateCommandDependencies = {},
@@ -164,7 +410,57 @@ export async function stateCommand(
input = { ...input, mode: modeValue };
}
- const result = await execute(operation, input);
+ let result;
+ if (operation === 'state_write' && isNativeUltragoalActivationIntent(input)) {
+ const authorization = await resolveNativeUltragoalActivationSession(input);
+ if (!authorization) {
+ result = {
+ payload: { error: 'native_ultragoal_activation_receipt_invalid' },
+ isError: true,
+ };
+ } else {
+ const activation = await withNativeUltragoalActivationAuthorization(
+ authorization,
+ async (assertNativeAuthorized) => {
+ const assertAuthorized = async (): Promise<void> => {
+ await assertNativeAuthorized();
+ if (
+ authorization.bootstrapStatus === 'active'
+ && !await sessionHasActiveUltragoalState(authorization.stateDir, authorization.sessionId)
+ ) throw new Error('native_ultragoal_activation_receipt_invalid');
+ };
+ await assertAuthorized();
+ return execute(operation, {
+ ...input,
+ session_id: authorization.sessionId,
+ }, {
+ beforeStateWriteCommit: assertAuthorized,
+ });
+ },
+ );
+ result = activation.ok
+ ? activation.value
+ : {
+ payload: { error: 'native_ultragoal_activation_receipt_invalid' },
+ isError: true,
+ };
+ }
+ } else if (operation === 'state_write' && isCanonicalNativeUltragoalTerminalIntent(input)) {
+ const authorization = await resolveNativeUltragoalTerminalSession(input);
+ let terminalStateCommitObserved = false;
+ result = authorization
+ ? await execute(operation, { ...input, session_id: authorization.sessionId }, {
+ beforeStateWriteCommit: async () => {
+ if (!await resolveNativeUltragoalTerminalSession(input, terminalStateCommitObserved)) {
+ throw new Error('native_ultragoal_terminal_receipt_invalid');
+ }
+ terminalStateCommitObserved = true;
+ },
+ })
+ : { payload: { error: 'native_ultragoal_terminal_receipt_invalid' }, isError: true };
+ } else {
+ result = await execute(operation, input);
+ }
const body = JSON.stringify(result.payload, null, json ? 0 : 2);
if (result.isError) {
diff --git a/src/cli/ultragoal.ts b/src/cli/ultragoal.ts
index 64d2e356e55c29abd5aeb3611f1ba36472fa2b10..38b034a2d68bf0207cdab58194bbe4c8a2d46ea4 100644
--- a/src/cli/ultragoal.ts
+++ b/src/cli/ultragoal.ts
@@ -11,8 +11,11 @@ import {
NATIVE_SUBAGENT_SUPPORT_BLOCKER_FILE,
resolveNativeSubagentSupportStatus,
} from '../leader/contract.js';
-import { resolveRuntimeStateScope } from '../mcp/state-paths.js';
+import { isSessionStateAuthoritativeForCwd, type SessionState } from '../hooks/session.js';
+import { normalizeSessionId, resolveRuntimeStateScope } from '../mcp/state-paths.js';
+import { resolveNativeUltragoalConfig } from '../config/native-ultragoal.js';
import { readRoleRoutingMarker } from '../subagents/role-routing-marker.js';
+import { sameFilePath } from '../utils/paths.js';
import {
addUltragoalGoal,
buildCodexGoalInstruction,
@@ -33,6 +36,32 @@ import {
ULTRAGOAL_STEERING_SOURCES,
UltragoalError,
} from '../ultragoal/artifacts.js';
+import {
+ issueLocalNativeExecutorAssignment,
+ markNativeUltragoalBootstrapActive,
+ prepareNativeUltragoalBootstrapActivation,
+ readNativeUltragoalBootstrap,
+ reconcileLocalNativeExecutorAssignments,
+ resolveLocalNativeExecutorChildReceipt,
+ revokeLocalNativeExecutorAssignment,
+} from '../ultragoal/native-bootstrap.js';
+
+async function sessionHasActiveStandaloneUltragoal(stateDir: string, sessionId: string): Promise<boolean> {
+ try {
+ const parsed = JSON.parse(await readFile(
+ join(stateDir, 'sessions', sessionId, 'ultragoal-state.json'),
+ 'utf-8',
+ )) as Record<string, unknown>;
+ const phase = String(parsed.current_phase ?? parsed.currentPhase ?? '').trim().toLowerCase();
+ return parsed.mode === 'ultragoal'
+ && parsed.active === true
+ && parsed.session_id === sessionId
+ && phase !== ''
+ && !['complete', 'completed', 'cancelled', 'failed'].includes(phase);
+ } catch {
+ return false;
+ }
+}
export const ULTRAGOAL_HELP = `omx ultragoal - Durable repo-native multi-goal workflow over Codex goal mode
@@ -46,6 +75,8 @@ Usage:
omx ultragoal steer --directive-json <json-or-path> [--json]
omx ultragoal checkpoint --goal-id <id> --status <complete|failed|blocked> [--evidence <text>] [--codex-goal-json <json-or-path>] [--quality-gate-json <json-or-path>] [--json]
omx ultragoal status [--codex-goal-json <json-or-path>] [--json]
+ omx ultragoal native-bootstrap <authorize|status|revoke> [options] [--json]
+ omx ultragoal native-bootstrap authorize --session-id <id> --root-thread-id <id> (--child-id <id> | --child-path <agent-path>) --bootstrap-generation <id> --path-prefix <path> [--json]
Aliases:
create -> create-goals, complete|next|start-next -> complete-goals
@@ -336,6 +367,7 @@ const ULTRAGOAL_MUTATING_COMMANDS = new Set([
'next',
'start-next',
'checkpoint',
+ 'native-bootstrap',
]);
function readTeamWorkerIdentity(env: NodeJS.ProcessEnv = process.env): string | null {
@@ -345,6 +377,37 @@ function readTeamWorkerIdentity(env: NodeJS.ProcessEnv = process.env): string |
return internalIdentity || null;
}
+async function resolveNativeBootstrapRuntimeScope(cwd: string, requestedSessionId: string) {
+ const scope = await resolveRuntimeStateScope(cwd);
+ if (scope.sessionId || readTeamWorkerIdentity()) return scope;
+
+ const codexThreadId = process.env.CODEX_THREAD_ID;
+ if (
+ codexThreadId !== requestedSessionId
+ || normalizeSessionId(codexThreadId) !== requestedSessionId
+ ) return scope;
+
+ const pointer = await readJsonIfExists<Record<string, unknown>>(join(scope.baseStateDir, 'session.json'));
+ if (
+ !pointer
+ || Array.isArray(pointer)
+ || pointer.session_id !== requestedSessionId
+ || normalizeSessionId(pointer.session_id) !== requestedSessionId
+ || pointer.native_session_id !== requestedSessionId
+ || normalizeSessionId(pointer.native_session_id) !== requestedSessionId
+ || !isSessionStateAuthoritativeForCwd(pointer as unknown as SessionState, scope.cwd)
+ ) {
+ return scope;
+ }
+
+ const pointerStateRoot = typeof pointer.state_root === 'string'
+ ? pointer.state_root
+ : join(scope.cwd, '.omx', 'state');
+ if (!sameFilePath(pointerStateRoot, scope.baseStateDir)) return scope;
+
+ return resolveRuntimeStateScope(cwd, requestedSessionId);
+}
+
function assertUltragoalMutationAllowedFromCurrentProcess(command: string): void {
if (!ULTRAGOAL_MUTATING_COMMANDS.has(command)) return;
const workerIdentity = readTeamWorkerIdentity();
@@ -374,6 +437,133 @@ export async function ultragoalCommand(args: string[], deps: UltragoalCommandDep
assertUltragoalMutationAllowedFromCurrentProcess(command);
+ if (command === 'native-bootstrap') {
+ const action = rest[0] ?? 'status';
+ const actionArgs = rest.slice(1);
+ const config = resolveNativeUltragoalConfig();
+ const requestedSessionId = readValue(actionArgs, '--session-id');
+ if (!requestedSessionId) {
+ throw new UltragoalError('Native bootstrap commands require an explicit --session-id.');
+ }
+ const scope = await resolveNativeBootstrapRuntimeScope(cwd, requestedSessionId);
+ if (!scope.sessionId) {
+ throw new UltragoalError('Native bootstrap requires a canonical current runtime session.');
+ }
+ if (requestedSessionId !== scope.sessionId) {
+ throw new UltragoalError('Requested --session-id does not match the canonical current runtime session.');
+ }
+ const sessionId = scope.sessionId;
+ const rootThreadId = readValue(actionArgs, '--root-thread-id');
+
+ if (action === 'authorize') {
+ if (config.backend !== 'local-experimental') {
+ throw new UltragoalError('native-bootstrap authorize requires nativeUltragoal.backend="local-experimental".');
+ }
+ const requestedChildAgentId = readValue(actionArgs, '--child-id');
+ const childAgentPath = readValue(actionArgs, '--child-path');
+ const bootstrapGeneration = readValue(actionArgs, '--bootstrap-generation');
+ const pathPrefixes = readRepeated(actionArgs, '--path-prefix');
+ if (!rootThreadId) throw new UltragoalError('Missing --root-thread-id.');
+ if (Boolean(requestedChildAgentId) === Boolean(childAgentPath)) {
+ throw new UltragoalError('Pass exactly one of --child-id or --child-path.');
+ }
+ if (!bootstrapGeneration) throw new UltragoalError('Missing --bootstrap-generation.');
+ if (pathPrefixes.length === 0) throw new UltragoalError('Pass at least one --path-prefix.');
+ let childAgentId = requestedChildAgentId;
+ if (childAgentPath) {
+ const receiptBootstrap = await readNativeUltragoalBootstrap(scope.baseStateDir, sessionId);
+ if (
+ !receiptBootstrap
+ || receiptBootstrap.generation !== bootstrapGeneration
+ || receiptBootstrap.root_thread_id !== rootThreadId
+ ) throw new UltragoalError('child_transcript_receipt_unbound');
+ const resolvedChild = await resolveLocalNativeExecutorChildReceipt({
+ cwd: scope.cwd,
+ sessionId,
+ rootThreadId,
+ agentPath: childAgentPath,
+ receiptNotBefore: receiptBootstrap.created_at,
+ receiptNotAfter: receiptBootstrap.expires_at,
+ });
+ if (!resolvedChild.ok) throw new UltragoalError(resolvedChild.reason);
+ childAgentId = resolvedChild.childAgentId;
+ }
+ if (!childAgentId) throw new UltragoalError('Unable to resolve native executor child identity.');
+ const ttlRaw = readValue(actionArgs, '--ttl-seconds');
+ const ttlSeconds = ttlRaw === undefined ? config.assignmentTtlSeconds : Number(ttlRaw);
+ try {
+ const assignment = await issueLocalNativeExecutorAssignment({
+ cwd: scope.cwd,
+ stateDir: scope.baseStateDir,
+ sessionId,
+ rootThreadId,
+ childAgentId,
+ expectedGeneration: bootstrapGeneration,
+ pathPrefixes,
+ ttlSeconds,
+ allowedActions: hasFlag(actionArgs, '--path-write-only')
+ ? ['path-write']
+ : ['path-write', 'bash-write'],
+ });
+ if (await sessionHasActiveStandaloneUltragoal(scope.baseStateDir, sessionId)) {
+ const currentBootstrap = await readNativeUltragoalBootstrap(scope.baseStateDir, sessionId);
+ if (currentBootstrap?.status !== 'active') {
+ const prepared = await prepareNativeUltragoalBootstrapActivation({
+ cwd: scope.cwd,
+ stateDir: scope.baseStateDir,
+ sessionId,
+ childAgentId,
+ });
+ if (!prepared.ok) throw new UltragoalError('native_ultragoal_activation_receipt_invalid');
+ const confirmed = await markNativeUltragoalBootstrapActive({
+ cwd: scope.cwd,
+ stateDir: scope.baseStateDir,
+ sessionId,
+ childAgentId,
+ });
+ if (!confirmed.ok) throw new UltragoalError('native_ultragoal_activation_receipt_invalid');
+ }
+ }
+ if (json) printJson({ ok: true, backend: config.backend, assignment });
+ else console.log(`native Ultragoal executor authorized: ${assignment.child_agent_id}`);
+ } catch (error) {
+ throw new UltragoalError(error instanceof Error ? error.message : String(error));
+ }
+ return;
+ }
+
+ if (action === 'revoke') {
+ await revokeLocalNativeExecutorAssignment({
+ stateDir: scope.baseStateDir,
+ sessionId,
+ childAgentId: readValue(actionArgs, '--child-id'),
+ reason: readValue(actionArgs, '--reason') ?? 'root_requested_revoke',
+ });
+ if (json) printJson({ ok: true, sessionId, status: 'revoked' });
+ else console.log(`native Ultragoal bootstrap revoked: ${sessionId}`);
+ return;
+ }
+
+ if (action === 'status') {
+ const bootstrap = await readNativeUltragoalBootstrap(scope.baseStateDir, sessionId);
+ const readiness = bootstrap?.root_thread_id
+ ? await reconcileLocalNativeExecutorAssignments({
+ cwd: scope.cwd,
+ stateDir: scope.baseStateDir,
+ sessionId,
+ rootThreadId: bootstrap.root_thread_id,
+ })
+ : { ready: false };
+ if (json) printJson({ backend: config.backend, bootstrap, readiness });
+ else console.log(bootstrap
+ ? `native Ultragoal bootstrap: ${bootstrap.status}${readiness.ready ? ' (ready)' : ''}`
+ : 'native Ultragoal bootstrap: absent');
+ return;
+ }
+
+ throw new UltragoalError('Invalid native-bootstrap action; expected authorize, status, or revoke.');
+ }
+
if (command === 'create' || command === 'create-goals') {
const briefFile = readValue(rest, '--brief-file');
const brief = readValue(rest, '--brief')
diff --git a/src/config/__tests__/native-ultragoal.test.ts b/src/config/__tests__/native-ultragoal.test.ts
new file mode 100644
index 0000000000000000000000000000000000000000..e4bb6532653adcda6298a29180443d58aceab072
--- /dev/null
+++ b/src/config/__tests__/native-ultragoal.test.ts
@@ -0,0 +1,95 @@
+import assert from 'node:assert/strict';
+import { mkdir, mkdtemp, rm, writeFile } from 'node:fs/promises';
+import { tmpdir } from 'node:os';
+import { join } from 'node:path';
+import { describe, it } from 'node:test';
+import { resolveNativeUltragoalConfig } from '../native-ultragoal.js';
+
+describe('native Ultragoal config', () => {
+ it('defaults off and reads the explicit global config', async () => {
+ const homeDir = await mkdtemp(join(tmpdir(), 'omx-native-ultragoal-config-'));
+ try {
+ assert.deepEqual(resolveNativeUltragoalConfig({ homeDir, env: {} }), {
+ backend: 'off',
+ assignmentTtlSeconds: 900,
+ source: 'default',
+ });
+ await mkdir(join(homeDir, '.omx'), { recursive: true });
+ await writeFile(join(homeDir, '.omx', 'config.json'), JSON.stringify({
+ nativeUltragoal: {
+ backend: 'local-experimental',
+ assignmentTtlSeconds: 300,
+ },
+ }));
+ assert.deepEqual(resolveNativeUltragoalConfig({ homeDir, env: {} }), {
+ backend: 'local-experimental',
+ assignmentTtlSeconds: 300,
+ source: 'config',
+ });
+ } finally {
+ await rm(homeDir, { recursive: true, force: true });
+ }
+ });
+
+ it('keeps invalid config fail-closed and preserves explicit env precedence', async () => {
+ const homeDir = await mkdtemp(join(tmpdir(), 'omx-native-ultragoal-config-invalid-'));
+ try {
+ await mkdir(join(homeDir, '.omx'), { recursive: true });
+ await writeFile(join(homeDir, '.omx', 'config.json'), JSON.stringify({
+ nativeUltragoal: { backend: 'local', assignmentTtlSeconds: 1 },
+ }));
+ assert.equal(resolveNativeUltragoalConfig({ homeDir, env: {} }).backend, 'off');
+ assert.deepEqual(resolveNativeUltragoalConfig({
+ homeDir,
+ env: { OMX_NATIVE_ULTRAGOAL_BACKEND: 'host' },
+ }), {
+ backend: 'host',
+ assignmentTtlSeconds: 900,
+ source: 'env',
+ });
+ assert.equal(resolveNativeUltragoalConfig({
+ homeDir,
+ env: { OMX_NATIVE_SUBAGENT_ASSIGNMENTS: 'on' },
+ }).backend, 'off');
+ await writeFile(join(homeDir, '.omx', 'config.json'), '{ malformed');
+ assert.deepEqual(resolveNativeUltragoalConfig({
+ homeDir,
+ env: { OMX_NATIVE_SUBAGENT_ASSIGNMENTS: 'on' },
+ }), {
+ backend: 'off',
+ assignmentTtlSeconds: 900,
+ source: 'config',
+ });
+ } finally {
+ await rm(homeDir, { recursive: true, force: true });
+ }
+ });
+
+ it('keeps explicit new config ahead of the legacy assignment opt-in', async () => {
+ const homeDir = await mkdtemp(join(tmpdir(), 'omx-native-ultragoal-config-legacy-'));
+ try {
+ await mkdir(join(homeDir, '.omx'), { recursive: true });
+ await writeFile(join(homeDir, '.omx', 'config.json'), JSON.stringify({
+ nativeUltragoal: { backend: 'host', assignmentTtlSeconds: 120 },
+ }));
+ assert.deepEqual(resolveNativeUltragoalConfig({
+ homeDir,
+ env: { OMX_NATIVE_SUBAGENT_ASSIGNMENTS: 'on' },
+ }), {
+ backend: 'host',
+ assignmentTtlSeconds: 120,
+ source: 'config',
+ });
+ assert.deepEqual(resolveNativeUltragoalConfig({
+ homeDir,
+ env: { OMX_NATIVE_ULTRAGOAL_BACKEND: 'local' },
+ }), {
+ backend: 'off',
+ assignmentTtlSeconds: 120,
+ source: 'env',
+ });
+ } finally {
+ await rm(homeDir, { recursive: true, force: true });
+ }
+ });
+});
diff --git a/src/config/native-ultragoal.ts b/src/config/native-ultragoal.ts
new file mode 100644
index 0000000000000000000000000000000000000000..83da9374c711c4217d54be1dabcea8638eb162b3
--- /dev/null
+++ b/src/config/native-ultragoal.ts
@@ -0,0 +1,125 @@
+import { existsSync, readFileSync } from 'node:fs';
+import { homedir } from 'node:os';
+import { join } from 'node:path';
+
+export type NativeUltragoalBackend = 'off' | 'host' | 'local-experimental';
+
+export interface NativeUltragoalRuntimeConfig {
+ backend: NativeUltragoalBackend;
+ assignmentTtlSeconds: number;
+ source: 'default' | 'config' | 'env' | 'legacy-env';
+}
+
+interface NativeUltragoalConfigFile {
+ nativeUltragoal?: {
+ backend?: unknown;
+ assignmentTtlSeconds?: unknown;
+ };
+}
+
+const DEFAULT_ASSIGNMENT_TTL_SECONDS = 15 * 60;
+const MIN_ASSIGNMENT_TTL_SECONDS = 30;
+const MAX_ASSIGNMENT_TTL_SECONDS = 60 * 60;
+
+function normalizeBackend(value: unknown): NativeUltragoalBackend | null {
+ if (typeof value !== 'string') return null;
+ const normalized = value.trim().toLowerCase();
+ if (normalized === 'off' || normalized === 'host' || normalized === 'local-experimental') return normalized;
+ return null;
+}
+
+function normalizeAssignmentTtlSeconds(value: unknown): number | null {
+ if (typeof value !== 'number' || !Number.isInteger(value)) return null;
+ if (value < MIN_ASSIGNMENT_TTL_SECONDS || value > MAX_ASSIGNMENT_TTL_SECONDS) return null;
+ return value;
+}
+
+function readConfigFile(homeDir: string):
+ | { status: 'absent' }
+ | { status: 'invalid' }
+ | { status: 'valid'; value: NativeUltragoalConfigFile } {
+ const path = join(homeDir, '.omx', 'config.json');
+ if (!existsSync(path)) return { status: 'absent' };
+ try {
+ const parsed = JSON.parse(readFileSync(path, 'utf-8')) as unknown;
+ return parsed && typeof parsed === 'object' && !Array.isArray(parsed)
+ ? { status: 'valid', value: parsed as NativeUltragoalConfigFile }
+ : { status: 'invalid' };
+ } catch {
+ return { status: 'invalid' };
+ }
+}
+
+export function resolveNativeUltragoalConfig(options: {
+ homeDir?: string;
+ env?: NodeJS.ProcessEnv;
+} = {}): NativeUltragoalRuntimeConfig {
+ const env = options.env ?? process.env;
+ const configResult = readConfigFile(options.homeDir ?? homedir());
+ const config = configResult.status === 'valid' ? configResult.value : null;
+ const hasExplicitConfiguredBackend = config?.nativeUltragoal?.backend !== undefined;
+ const configuredBackend = normalizeBackend(config?.nativeUltragoal?.backend);
+ const assignmentTtlSeconds = normalizeAssignmentTtlSeconds(
+ config?.nativeUltragoal?.assignmentTtlSeconds,
+ ) ?? DEFAULT_ASSIGNMENT_TTL_SECONDS;
+ const rawEnvBackend = env.OMX_NATIVE_ULTRAGOAL_BACKEND;
+ const explicitEnvBackend = normalizeBackend(rawEnvBackend);
+ if (explicitEnvBackend) {
+ return {
+ backend: explicitEnvBackend,
+ assignmentTtlSeconds,
+ source: 'env',
+ };
+ }
+ if (typeof rawEnvBackend === 'string' && rawEnvBackend.trim() !== '') {
+ return {
+ backend: 'off',
+ assignmentTtlSeconds,
+ source: 'env',
+ };
+ }
+
+ if (configResult.status === 'invalid') {
+ return {
+ backend: 'off',
+ assignmentTtlSeconds,
+ source: 'config',
+ };
+ }
+
+ if (configuredBackend) {
+ return {
+ backend: configuredBackend,
+ assignmentTtlSeconds,
+ source: 'config',
+ };
+ }
+
+ if (hasExplicitConfiguredBackend) {
+ return {
+ backend: 'off',
+ assignmentTtlSeconds,
+ source: 'config',
+ };
+ }
+
+ if (String(env.OMX_NATIVE_SUBAGENT_ASSIGNMENTS ?? '').trim().toLowerCase() === 'on') {
+ return {
+ backend: 'local-experimental',
+ assignmentTtlSeconds,
+ source: 'legacy-env',
+ };
+ }
+
+ return {
+ backend: 'off',
+ assignmentTtlSeconds,
+ source: 'default',
+ };
+}
+
+export function nativeUltragoalBackendIsLocalExperimental(
+ options: Parameters<typeof resolveNativeUltragoalConfig>[0] = {},
+): boolean {
+ return resolveNativeUltragoalConfig(options).backend === 'local-experimental';
+}
diff --git a/src/hooks/__tests__/notify-hook-auto-nudge.test.ts b/src/hooks/__tests__/notify-hook-auto-nudge.test.ts
index 44fd9f87e010565ff7bea286c25982a45c4d436b..d50bfccfd805d1d9f0ab10fb4153ff2b3f57c032 100644
--- a/src/hooks/__tests__/notify-hook-auto-nudge.test.ts
+++ b/src/hooks/__tests__/notify-hook-auto-nudge.test.ts
@@ -2383,6 +2383,120 @@ exit 0
});
});
+ it('does not reactivate completed ultragoal from the same completed-turn input replay', async () => {
+ await withTempWorkingDir(async (cwd) => {
+ const omxDir = join(cwd, '.omx');
+ const stateDir = join(omxDir, 'state');
+ const logsDir = join(omxDir, 'logs');
+ const codexHome = join(cwd, 'codex-home');
+ const fakeBinDir = join(cwd, 'fake-bin');
+ const sessionStateDir = join(stateDir, 'sessions', 'sess-managed');
+ const terminalCompletedAt = '2026-07-30T00:06:49.168Z';
+
+ await mkdir(logsDir, { recursive: true });
+ await mkdir(sessionStateDir, { recursive: true });
+ await mkdir(codexHome, { recursive: true });
+ await mkdir(fakeBinDir, { recursive: true });
+
+ await writeJson(join(codexHome, '.omx-config.json'), {
+ autoNudge: { enabled: true, delaySec: 0, stallMs: 0 },
+ });
+ await writeManagedSessionState(stateDir, cwd);
+ await writeJson(join(sessionStateDir, 'ultragoal-state.json'), {
+ active: false,
+ current_phase: 'complete',
+ run_outcome: 'finished',
+ completed_at: terminalCompletedAt,
+ });
+ await writeJson(join(stateDir, 'native-stop-state.json'), {
+ sessions: {
+ 'sess-managed': {
+ ordinary_no_progress_guard: {
+ last_turn_id: 'turn-ultragoal-complete',
+ last_thread_id: null,
+ },
+ },
+ },
+ });
+
+ await writeFile(join(fakeBinDir, 'tmux'), buildFakeTmux(join(cwd, 'tmux.log')));
+ await chmod(join(fakeBinDir, 'tmux'), 0o755);
+
+ const result = runNotifyHook(cwd, fakeBinDir, codexHome, {
+ type: 'agent-turn-complete',
+ 'thread-id': 'thread-ultragoal-complete',
+ 'turn-id': 'turn-ultragoal-complete',
+ 'input-messages': ['$ultragoal Выполни полный native acceptance.'],
+ 'last-assistant-message': 'Native Ultragoal acceptance завершён до terminal completion.',
+ });
+ assert.equal(result.status, 0, `hook failed: ${result.stderr || result.stdout}`);
+
+ const ultragoalState = JSON.parse(await readFile(join(sessionStateDir, 'ultragoal-state.json'), 'utf-8')) as {
+ mode?: string;
+ active: boolean;
+ current_phase: string;
+ started_at?: string;
+ completed_at?: string;
+ run_outcome?: string;
+ };
+ assert.equal(ultragoalState.mode, undefined, 'notify must preserve the CLI state-file shape without reseeding mode');
+ assert.equal(ultragoalState.active, false);
+ assert.equal(ultragoalState.current_phase, 'complete');
+ assert.equal(ultragoalState.run_outcome, 'finished');
+ assert.equal(ultragoalState.completed_at, terminalCompletedAt);
+ assert.equal(ultragoalState.started_at, undefined, 'notify must not create a new planning run');
+ });
+ });
+
+ it('allows a later ultragoal prompt after completed state to reach normal activation', async () => {
+ await withTempWorkingDir(async (cwd) => {
+ const stateDir = join(cwd, '.omx', 'state');
+ const sessionId = 'sess-ultragoal-restart';
+ const sessionStateDir = join(stateDir, 'sessions', sessionId);
+ await mkdir(sessionStateDir, { recursive: true });
+ await writeJson(join(sessionStateDir, 'ultragoal-state.json'), {
+ mode: 'ultragoal',
+ active: false,
+ current_phase: 'complete',
+ completed_at: '2026-07-30T00:06:49.168Z',
+ session_id: sessionId,
+ });
+ await writeJson(join(stateDir, 'native-stop-state.json'), {
+ sessions: {
+ [sessionId]: {
+ ordinary_no_progress_guard: {
+ last_turn_id: 'turn-ultragoal-complete',
+ },
+ },
+ },
+ });
+
+ let writerCalls = 0;
+ const result = await recordNotifySkillActivation({
+ stateDir,
+ sourceCwd: cwd,
+ text: '$ultragoal Запусти следующую задачу.',
+ sessionId,
+ threadId: 'thread-ultragoal-complete',
+ turnId: 'turn-ultragoal-restart',
+ payload: {
+ type: 'agent-turn-complete',
+ 'thread-id': 'thread-ultragoal-complete',
+ 'turn-id': 'turn-ultragoal-restart',
+ 'last-assistant-message': 'Starting the next Ultragoal run.',
+ },
+ }, {
+ recordSkillActivation: async () => {
+ writerCalls += 1;
+ return null;
+ },
+ });
+
+ assert.equal(result, null);
+ assert.equal(writerCalls, 1, 'a different turn must not be mistaken for terminal replay');
+ });
+ });
+
it('fails a later fresh autopilot prompt after completed autopilot state when receipt verification is unavailable', async () => {
await withTempWorkingDir(async (cwd) => {
const omxDir = join(cwd, '.omx');
diff --git a/src/mcp/__tests__/state-paths.test.ts b/src/mcp/__tests__/state-paths.test.ts
index cd01715c64d765af70e80090c4c8cb9475d03067..863a644ba3b47d585e3f2f1a7f749345529c5b2e 100644
--- a/src/mcp/__tests__/state-paths.test.ts
+++ b/src/mcp/__tests__/state-paths.test.ts
@@ -43,7 +43,9 @@ const isolatedEnvKeys = [
'OMX_ROOT',
'OMX_STATE_ROOT',
'OMX_TEAM_STATE_ROOT',
+ 'OMX_TEAM_WORKER',
'OMX_SESSION_ID',
+ 'CODEX_THREAD_ID',
'CODEX_SESSION_ID',
'SESSION_ID',
'TMUX',
@@ -1063,6 +1065,144 @@ describe('state paths', () => {
await rm(wd, { recursive: true, force: true });
}
});
+ it('recovers an App-native identity-indeterminate pointer from an exact host CODEX_THREAD_ID', async () => {
+ const wd = await mkRealTemp('omx-writable-indeterminate-codex-root-');
+ __setSessionPointerTransactionDependenciesForTests({ probePid: () => 'indeterminate' });
+ try {
+ const stateDir = getBaseStateDir(wd);
+ const sessionId = '019faf7d-ffbb-70d2-b58f-9bb83e752007';
+ const nativeRootId = sessionId;
+ await mkdir(stateDir, { recursive: true });
+ const pointerBody = JSON.stringify({
+ session_id: sessionId,
+ native_session_id: nativeRootId,
+ cwd: wd,
+ pid: 8388607,
+ });
+ await writeFile(join(stateDir, 'session.json'), pointerBody);
+ process.env.CODEX_THREAD_ID = nativeRootId;
+
+ await assert.rejects(
+ () => resolveWritableStateScope(wd),
+ (error: unknown) => (error as Error).message === WRITABLE_STATE_SCOPE_ERRORS.unusableSession,
+ );
+ await assert.rejects(
+ () => resolveWritableStateScope(wd, undefined, { nativeUltragoalBackend: 'host' }),
+ (error: unknown) => (error as Error).message === WRITABLE_STATE_SCOPE_ERRORS.unusableSession,
+ );
+ assert.deepEqual(await resolveWritableStateScope(wd, undefined, {
+ nativeUltragoalBackend: 'local-experimental',
+ }), {
+ source: 'session',
+ sessionId,
+ stateDir: join(stateDir, 'sessions', sessionId),
+ });
+ assert.equal(await readFile(join(stateDir, 'session.json'), 'utf8'), pointerBody);
+ } finally {
+ __resetSessionPointerTransactionDependenciesForTests();
+ await rm(wd, { recursive: true, force: true });
+ }
+ });
+
+ it('uses session_id as the App-native root only when native_session_id is absent', async () => {
+ const wd = await mkRealTemp('omx-writable-indeterminate-codex-session-');
+ __setSessionPointerTransactionDependenciesForTests({ probePid: () => 'indeterminate' });
+ try {
+ const stateDir = getBaseStateDir(wd);
+ const sessionId = '019faf7e-0002-7000-8000-000000000002';
+ await mkdir(stateDir, { recursive: true });
+ await writeFile(join(stateDir, 'session.json'), JSON.stringify({
+ session_id: sessionId,
+ cwd: wd,
+ pid: 8388607,
+ }));
+ process.env.CODEX_THREAD_ID = sessionId;
+ assert.equal((await resolveWritableStateScope(wd, undefined, {
+ nativeUltragoalBackend: 'local-experimental',
+ })).sessionId, sessionId);
+
+ await writeFile(join(stateDir, 'session.json'), JSON.stringify({
+ session_id: sessionId,
+ native_session_id: '',
+ cwd: wd,
+ pid: 8388607,
+ }));
+ await assert.rejects(
+ () => resolveWritableStateScope(wd, undefined, { nativeUltragoalBackend: 'local-experimental' }),
+ (error: unknown) => (error as Error).message === WRITABLE_STATE_SCOPE_ERRORS.unusableSession,
+ );
+ } finally {
+ __resetSessionPointerTransactionDependenciesForTests();
+ await rm(wd, { recursive: true, force: true });
+ }
+ });
+
+ it('rejects child, malformed, conflicting, override, and non-exact-cwd native claims', async () => {
+ const wd = await mkRealTemp('omx-writable-indeterminate-codex-deny-');
+ __setSessionPointerTransactionDependenciesForTests({ probePid: () => 'indeterminate' });
+ try {
+ const stateDir = getBaseStateDir(wd);
+ const sessionId = '019faf7e-0003-7000-8000-000000000003';
+ const nativeRootId = sessionId;
+ const childId = '019faf7e-0005-7000-8000-000000000005';
+ await mkdir(stateDir, { recursive: true });
+ await writeFile(join(stateDir, 'session.json'), JSON.stringify({
+ session_id: sessionId,
+ native_session_id: nativeRootId,
+ cwd: wd,
+ pid: 8388607,
+ }));
+
+ for (const claim of [childId, 'not-a-uuid', nativeRootId.toUpperCase()]) {
+ process.env.CODEX_THREAD_ID = claim;
+ await assert.rejects(
+ () => resolveWritableStateScope(wd, undefined, { nativeUltragoalBackend: 'local-experimental' }),
+ (error: unknown) => (error as Error).message === WRITABLE_STATE_SCOPE_ERRORS.unusableSession,
+ claim,
+ );
+ }
+
+ process.env.CODEX_THREAD_ID = nativeRootId;
+ process.env.OMX_SESSION_ID = childId;
+ await assert.rejects(
+ () => resolveWritableStateScope(wd, undefined, { nativeUltragoalBackend: 'local-experimental' }),
+ (error: unknown) => (error as Error).message === WRITABLE_STATE_SCOPE_ERRORS.unusableSession,
+ );
+ delete process.env.OMX_SESSION_ID;
+
+ process.env.OMX_ROOT = wd;
+ await assert.rejects(
+ () => resolveWritableStateScope(wd, undefined, { nativeUltragoalBackend: 'local-experimental' }),
+ (error: unknown) => (error as Error).message === WRITABLE_STATE_SCOPE_ERRORS.unusableSession,
+ );
+ delete process.env.OMX_ROOT;
+
+ process.env.OMX_TEAM_WORKER = 'team/worker-1';
+ await assert.rejects(
+ () => resolveWritableStateScope(wd, undefined, { nativeUltragoalBackend: 'local-experimental' }),
+ (error: unknown) => (error as Error).message === WRITABLE_STATE_SCOPE_ERRORS.unusableSession,
+ );
+ delete process.env.OMX_TEAM_WORKER;
+
+ const nested = join(wd, 'nested');
+ const nestedStateDir = join(nested, '.omx', 'state');
+ await mkdir(nestedStateDir, { recursive: true });
+ await writeFile(join(nestedStateDir, 'session.json'), JSON.stringify({
+ session_id: sessionId,
+ native_session_id: nativeRootId,
+ cwd: wd,
+ state_root: nestedStateDir,
+ pid: 8388607,
+ }));
+ await assert.rejects(
+ () => resolveWritableStateScope(nested, undefined, { nativeUltragoalBackend: 'local-experimental' }),
+ (error: unknown) => (error as Error).message === WRITABLE_STATE_SCOPE_ERRORS.unusableSession,
+ );
+ } finally {
+ __resetSessionPointerTransactionDependenciesForTests();
+ await rm(wd, { recursive: true, force: true });
+ }
+ });
it('fails closed for an identity-indeterminate pointer even with an env binding', async () => {
const wd = await mkRealTemp('omx-writable-indeterminate-env-');
__setSessionPointerTransactionDependenciesForTests({ probePid: () => 'indeterminate' });
@@ -1194,21 +1334,22 @@ describe('writable state scope recovery and revalidation', () => {
const stateDir = getBaseStateDir(wd);
const sessionPath = join(stateDir, 'session.json');
await mkdir(stateDir, { recursive: true });
- await writeFile(sessionPath, JSON.stringify({ session_id: 'sess-indeterminate', cwd: wd, pid: 8388607 }));
- process.env.OMX_SESSION_ID = 'sess-indeterminate';
+ const sessionId = '019faf7e-0006-7000-8000-000000000006';
+ await writeFile(sessionPath, JSON.stringify({ session_id: sessionId, native_session_id: sessionId, cwd: wd, pid: 8388607 }));
+ process.env.CODEX_THREAD_ID = sessionId;
__setWritableStateScopeTestHooksForTests({
beforeRecoveryReread: async () => {
- await writeFile(sessionPath, JSON.stringify({ session_id: 'sess-indeterminate', cwd: wd, pid: 9999999 }));
+ await writeFile(sessionPath, JSON.stringify({ session_id: sessionId, native_session_id: sessionId, cwd: wd, pid: 9999999 }));
},
});
await assert.rejects(
- () => resolveWritableStateScope(wd),
+ () => resolveWritableStateScope(wd, undefined, { nativeUltragoalBackend: 'local-experimental' }),
(error: unknown) => {
assert.equal((error as Error).message, WRITABLE_STATE_SCOPE_ERRORS.unusableSession);
return true;
},
);
- assert.equal(existsSync(join(stateDir, 'sessions', 'sess-indeterminate')), false);
+ assert.equal(existsSync(join(stateDir, 'sessions', sessionId)), false);
} finally {
__setWritableStateScopeTestHooksForTests({});
__resetSessionPointerTransactionDependenciesForTests();
diff --git a/src/mcp/__tests__/state-server-schema.test.ts b/src/mcp/__tests__/state-server-schema.test.ts
index bf7450fb7da5aa933adc548a4361ff3a905eaf44..1990e67dccbe8fd31ce51e4d4d055277c4b53652 100644
--- a/src/mcp/__tests__/state-server-schema.test.ts
+++ b/src/mcp/__tests__/state-server-schema.test.ts
@@ -41,4 +41,19 @@ describe("state-server schema validation", () => {
);
}
});
+
+ it("advertises ultragoal only on the read surface", async () => {
+ process.env.OMX_STATE_SERVER_DISABLE_AUTO_START = "1";
+ const { buildStateServerTools } = await import("../state-server.js");
+ const tools = buildStateServerTools() as Array<{
+ name: string;
+ inputSchema?: { properties?: { mode?: { enum?: string[] } } };
+ }>;
+ const modeEnum = (name: string) => tools.find((tool) => tool.name === name)
+ ?.inputSchema?.properties?.mode?.enum ?? [];
+
+ assert.equal(modeEnum("state_read").includes("ultragoal"), true);
+ assert.equal(modeEnum("state_write").includes("ultragoal"), false);
+ assert.equal(modeEnum("state_clear").includes("ultragoal"), false);
+ });
});
diff --git a/src/mcp/state-paths.ts b/src/mcp/state-paths.ts
index 1e0c6395fb91aad082e26c833aa5d77a6bc4b885..94d9205cf75bbf2e16687b6ebb1e5615511dd8ee 100644
--- a/src/mcp/state-paths.ts
+++ b/src/mcp/state-paths.ts
@@ -17,6 +17,8 @@ const OMX_ROOT_ENV = 'OMX_ROOT';
const OMX_STATE_ROOT_ENV = 'OMX_STATE_ROOT';
const OMX_TEAM_STATE_ROOT_ENV = 'OMX_TEAM_STATE_ROOT';
const OMX_SESSION_ID_ENV = 'OMX_SESSION_ID';
+const CODEX_THREAD_ID_ENV = 'CODEX_THREAD_ID';
+const CANONICAL_CODEX_THREAD_ID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/;
export const WRITABLE_STATE_SCOPE_ERRORS = {
unusableSession: 'Cannot resolve writable state scope: session.json is present but unusable.',
@@ -595,6 +597,10 @@ export interface WritableStateScopeTestHooks {
onRecoveryStabilityReread?: (event: Readonly<{ ordinal: number; raw: string | undefined }>) => void;
}
+export interface WritableStateScopeOptions {
+ nativeUltragoalBackend?: 'off' | 'host' | 'local-experimental';
+}
+
let selectedPointerRecoveryHookForTests: (() => Promise<void>) | undefined;
let writableScopeRevalidationHookForTests: WritableStateScopeTestHooks['beforeScopeRevalidation'];
let selectedDecisionSnapshotReadHookForTests: WritableStateScopeTestHooks['onSelectedDecisionSnapshotRead'];
@@ -625,6 +631,7 @@ export function __setWritableStateScopeTestHooksForTests(hooks: WritableStateSco
export async function resolveWritableStateScope(
workingDirectory?: string,
explicitSessionId?: string,
+ options: WritableStateScopeOptions = {},
): Promise<ResolvedStateScope> {
const cwd = resolveWorkingDirectoryForState(workingDirectory);
const baseStateDir = getBaseStateDir(cwd);
@@ -656,13 +663,55 @@ export async function resolveWritableStateScope(
raw: snapshot.raw,
});
}
- if (snapshot && envSessionId) {
+ if (snapshot) {
const canonicalPointerSessionId = normalizeSessionId(snapshot.state.session_id);
+ const rawOmxSessionId = process.env[OMX_SESSION_ID_ENV];
+ const explicitOmxSessionIdPresent = typeof rawOmxSessionId === 'string' && rawOmxSessionId.trim() !== '';
+ const outsideTmux = !(process.env.TMUX?.trim());
+ const rawCodexThreadId = process.env[CODEX_THREAD_ID_ENV];
+ const codexThreadClaimPresent = typeof rawCodexThreadId === 'string' && rawCodexThreadId.trim() !== '';
+ const codexThreadId = typeof rawCodexThreadId === 'string'
+ && CANONICAL_CODEX_THREAD_ID_PATTERN.test(rawCodexThreadId.trim())
+ ? rawCodexThreadId.trim()
+ : undefined;
+ const pointerSessionIsCanonicalCodexThread = typeof snapshot.state.session_id === 'string'
+ && CANONICAL_CODEX_THREAD_ID_PATTERN.test(snapshot.state.session_id.trim());
+ const pointerHasNativeSessionId = Object.prototype.hasOwnProperty.call(snapshot.state, 'native_session_id');
+ const nativeRootThreadId = pointerHasNativeSessionId
+ ? (typeof snapshot.state.native_session_id === 'string'
+ && snapshot.state.native_session_id.trim() === canonicalPointerSessionId
+ ? snapshot.state.native_session_id.trim()
+ : undefined)
+ : canonicalPointerSessionId;
+ const hasStateRootOverride = [OMX_TEAM_STATE_ROOT_ENV, OMX_ROOT_ENV, OMX_STATE_ROOT_ENV]
+ .some((key) => typeof process.env[key] === 'string' && process.env[key]!.trim() !== '');
+ const exactCodexNativeRecovery = Boolean(
+ liveness === 'identity-indeterminate'
+ && options.nativeUltragoalBackend === 'local-experimental'
+ && outsideTmux
+ && !(process.env.OMX_TEAM_WORKER?.trim())
+ && codexThreadClaimPresent
+ && codexThreadId
+ && nativeRootThreadId
+ && canonicalPointerSessionId
+ && pointerSessionIsCanonicalCodexThread
+ && codexThreadId === canonicalPointerSessionId
+ && nativeRootThreadId === canonicalPointerSessionId
+ && canonicalizeExistingPath(resolvePath(cwd)) === snapshot.recordedCwd
+ && !hasStateRootOverride
+ && (!explicitOmxSessionIdPresent || envSessionId === canonicalPointerSessionId),
+ );
+ const exactLegacyIndeterminateRecovery = Boolean(
+ liveness === 'identity-indeterminate'
+ && envSessionId === canonicalPointerSessionId
+ && (!outsideTmux || !codexThreadClaimPresent),
+ );
const recoveryEligible = Boolean(
canonicalPointerSessionId
&& (
- liveness === 'stale-dead'
- || (liveness === 'identity-indeterminate' && envSessionId === canonicalPointerSessionId)
+ (liveness === 'stale-dead' && envSessionId)
+ || exactLegacyIndeterminateRecovery
+ || exactCodexNativeRecovery
),
);
if (recoveryEligible) {
@@ -678,10 +727,14 @@ export async function resolveWritableStateScope(
});
}
if (reread === snapshot.raw) {
+ const recoveredSessionId = exactCodexNativeRecovery
+ ? canonicalPointerSessionId
+ : envSessionId;
+ if (!recoveredSessionId) throw new Error(WRITABLE_STATE_SCOPE_ERRORS.unusableSession);
return {
source: 'session',
- sessionId: envSessionId,
- stateDir: join(baseStateDir, 'sessions', envSessionId),
+ sessionId: recoveredSessionId,
+ stateDir: join(baseStateDir, 'sessions', recoveredSessionId),
};
}
}
diff --git a/src/mcp/state-server.ts b/src/mcp/state-server.ts
index e997e6b2aa67cbd8c8964a9db808f00f144525ac..585f1ad78b4ac63fecfa6d996ad3f7ce08fd3c27 100644
--- a/src/mcp/state-server.ts
+++ b/src/mcp/state-server.ts
@@ -28,6 +28,8 @@ const SUPPORTED_MODES = [
"skill-active",
] as const;
+const SUPPORTED_READ_MODES = [...SUPPORTED_MODES, "ultragoal"] as const;
+
const STATE_TOOL_NAMES = new Set([
"state_read",
"state_write",
@@ -53,7 +55,7 @@ export function buildStateServerTools() {
properties: {
mode: {
type: "string",
- enum: [...SUPPORTED_MODES],
+ enum: [...SUPPORTED_READ_MODES],
description: "The mode to read state for",
},
workingDirectory: {
diff --git a/src/scripts/__tests__/codex-native-assignment.test.ts b/src/scripts/__tests__/codex-native-assignment.test.ts
new file mode 100644
index 0000000000000000000000000000000000000000..20c579dd6224fa6cb4e41a5135b7ac3f8f6c6155
--- /dev/null
+++ b/src/scripts/__tests__/codex-native-assignment.test.ts
@@ -0,0 +1,461 @@
+import assert from "node:assert/strict";
+import { chmod, mkdir, mkdtemp, rm, symlink, writeFile } from "node:fs/promises";
+import { tmpdir } from "node:os";
+import { dirname, join, resolve } from "node:path";
+import { afterEach, beforeEach, describe, it } from "node:test";
+import { dispatchCodexNativeHook } from "../codex-native-hook.js";
+
+async function writeJson(path: string, value: unknown): Promise<void> {
+ await mkdir(dirname(path), { recursive: true });
+ await writeFile(path, `${JSON.stringify(value, null, 2)}\n`, "utf-8");
+}
+
+async function createActiveConductorFixture(phase = "executing"): Promise<{
+ cwd: string;
+ stateDir: string;
+ sessionId: string;
+ leaderThreadId: string;
+ childAgentId: string;
+}> {
+ const cwd = await mkdtemp(join(tmpdir(), "omx-native-assignment-"));
+ const stateDir = join(cwd, ".omx", "state");
+ const sessionId = "sess-native-assignment";
+ const leaderThreadId = "thread-native-assignment-leader";
+ const childAgentId = "agent-native-assignment-executor";
+ const now = new Date().toISOString();
+ const bootstrapGeneration = "bootstrap-generation-native-assignment";
+
+ await writeJson(join(stateDir, "session.json"), {
+ session_id: sessionId,
+ native_session_id: leaderThreadId,
+ cwd,
+ });
+ await writeJson(join(stateDir, "subagent-tracking.json"), {
+ schemaVersion: 1,
+ sessions: {
+ [sessionId]: {
+ session_id: sessionId,
+ leader_thread_id: leaderThreadId,
+ updated_at: now,
+ threads: {
+ [leaderThreadId]: {
+ thread_id: leaderThreadId,
+ kind: "leader",
+ first_seen_at: now,
+ last_seen_at: now,
+ turn_count: 1,
+ },
+ [childAgentId]: {
+ thread_id: childAgentId,
+ kind: "subagent",
+ mode: "executor",
+ status: "available",
+ provenance_kind: "native_subagent",
+ direct_child_parent_id: leaderThreadId,
+ direct_child_root_id: leaderThreadId,
+ leader_thread_id: leaderThreadId,
+ first_seen_at: now,
+ last_seen_at: now,
+ turn_count: 1,
+ },
+ },
+ },
+ },
+ });
+ await writeJson(join(stateDir, "sessions", sessionId, "skill-active-state.json"), {
+ active: true,
+ skill: "ultragoal",
+ phase,
+ session_id: sessionId,
+ active_skills: [
+ { skill: "ultragoal", phase, active: true, session_id: sessionId },
+ ],
+ });
+ await writeJson(join(stateDir, "sessions", sessionId, "ultragoal-state.json"), {
+ active: true,
+ mode: "ultragoal",
+ current_phase: phase,
+ session_id: sessionId,
+ });
+ await writeJson(join(stateDir, "sessions", sessionId, "native-ultragoal-bootstrap.json"), {
+ schema_version: 1,
+ kind: "native-ultragoal-bootstrap",
+ generation: bootstrapGeneration,
+ backend: "local-experimental",
+ status: "active",
+ session_id: sessionId,
+ root_thread_id: leaderThreadId,
+ child_agent_id: childAgentId,
+ created_at: now,
+ updated_at: now,
+ expires_at: new Date(Date.now() + 10 * 60_000).toISOString(),
+ });
+
+ return { cwd, stateDir, sessionId, leaderThreadId, childAgentId };
+}
+
+function preToolUse(
+ cwd: string,
+ sessionId: string,
+ identity: Record<string, unknown>,
+ toolName: string,
+ toolInput: Record<string, unknown>,
+) {
+ return dispatchCodexNativeHook({
+ hook_event_name: "PreToolUse",
+ cwd,
+ session_id: sessionId,
+ ...identity,
+ tool_name: toolName,
+ tool_input: toolInput,
+ }, { cwd });
+}
+
+describe("native Conductor assignment transport", () => {
+ const originalAssignmentOptIn = process.env.OMX_NATIVE_SUBAGENT_ASSIGNMENTS;
+
+ beforeEach(() => {
+ process.env.OMX_NATIVE_SUBAGENT_ASSIGNMENTS = "on";
+ });
+
+ afterEach(() => {
+ if (originalAssignmentOptIn === undefined) delete process.env.OMX_NATIVE_SUBAGENT_ASSIGNMENTS;
+ else process.env.OMX_NATIVE_SUBAGENT_ASSIGNMENTS = originalAssignmentOptIn;
+ });
+
+ it("requires typed tracker authority and rejects missing or conflicting role evidence", async () => {
+ const fixture = await createActiveConductorFixture();
+ const { cwd, stateDir, sessionId, leaderThreadId, childAgentId } = fixture;
+ const assignmentPath = join(
+ stateDir,
+ "sessions",
+ sessionId,
+ "native-assignments",
+ `${encodeURIComponent(childAgentId)}.json`,
+ );
+ const issuedAt = new Date();
+ const expiresAt = new Date(issuedAt.getTime() + 10 * 60_000);
+ const trackingPath = join(stateDir, "subagent-tracking.json");
+ const trackedChild = {
+ thread_id: childAgentId,
+ kind: "subagent",
+ leader_thread_id: leaderThreadId,
+ first_seen_at: issuedAt.toISOString(),
+ last_seen_at: issuedAt.toISOString(),
+ turn_count: 1,
+ };
+
+ try {
+ await writeJson(assignmentPath, {
+ schema_version: 1,
+ kind: "native-subagent-assignment",
+ lifecycle: "active",
+ root_session_id: sessionId,
+ root_thread_id: leaderThreadId,
+ child_agent_id: childAgentId,
+ agent_type: "executor",
+ allowed_actions: ["path-write"],
+ path_prefixes: ["src/assigned"],
+ issued_at: issuedAt.toISOString(),
+ expires_at: expiresAt.toISOString(),
+ bootstrap_generation: "bootstrap-generation-native-assignment",
+ });
+ await writeJson(trackingPath, {
+ schemaVersion: 1,
+ sessions: {
+ [sessionId]: {
+ session_id: sessionId,
+ leader_thread_id: leaderThreadId,
+ updated_at: issuedAt.toISOString(),
+ threads: {
+ [leaderThreadId]: { thread_id: leaderThreadId, kind: "leader" },
+ [childAgentId]: trackedChild,
+ },
+ },
+ },
+ });
+
+ const realTypedChild = await preToolUse(
+ cwd,
+ sessionId,
+ { agent_id: childAgentId, agent_type: "executor" },
+ "Write",
+ { file_path: "src/assigned/real-typed-child.txt", content: "ok\n" },
+ );
+ assert.equal(realTypedChild.outputJson?.decision, "block");
+ assert.match(String(realTypedChild.outputJson?.reason ?? ""), /OWNER_CONFIRMATION_REQUIRED/);
+
+ const missingTypedRole = await preToolUse(
+ cwd,
+ sessionId,
+ {
+ agent_id: childAgentId,
+ source: { subagent: { thread_spawn: { agent_role: "executor" } } },
+ },
+ "Write",
+ { file_path: "src/assigned/missing-role.txt", content: "must-not-write\n" },
+ );
+ assert.equal(missingTypedRole.outputJson?.decision, "block");
+ assert.match(String(missingTypedRole.outputJson?.reason ?? ""), /OWNER_CONFIRMATION_REQUIRED/);
+
+ const conflictingTypedAliases = await preToolUse(
+ cwd,
+ sessionId,
+ { agent_id: childAgentId, agent_role: "executor", agent_type: "writer" },
+ "Write",
+ { file_path: "src/assigned/conflicting-aliases.txt", content: "must-not-write\n" },
+ );
+ assert.equal(conflictingTypedAliases.outputJson?.decision, "block");
+ assert.match(String(conflictingTypedAliases.outputJson?.reason ?? ""), /OWNER_CONFIRMATION_REQUIRED/);
+
+ await writeJson(trackingPath, {
+ schemaVersion: 1,
+ sessions: {
+ [sessionId]: {
+ session_id: sessionId,
+ leader_thread_id: leaderThreadId,
+ updated_at: issuedAt.toISOString(),
+ threads: {
+ [leaderThreadId]: { thread_id: leaderThreadId, kind: "leader" },
+ [childAgentId]: { ...trackedChild, mode: "writer" },
+ },
+ },
+ },
+ });
+ const conflictingTrackerRole = await preToolUse(
+ cwd,
+ sessionId,
+ { agent_id: childAgentId, agent_role: "executor" },
+ "Write",
+ { file_path: "src/assigned/conflicting-role.txt", content: "must-not-write\n" },
+ );
+ assert.equal(conflictingTrackerRole.outputJson?.decision, "block");
+ assert.match(String(conflictingTrackerRole.outputJson?.reason ?? ""), /OWNER_CONFIRMATION_REQUIRED/);
+ } finally {
+ await rm(cwd, { recursive: true, force: true });
+ }
+ });
+
+ it("allows only an exact live typed-child path grant and keeps all negative contracts fail-closed", async () => {
+ const fixture = await createActiveConductorFixture();
+ const { cwd, stateDir, sessionId, leaderThreadId, childAgentId } = fixture;
+ const assignmentPath = join(
+ stateDir,
+ "sessions",
+ sessionId,
+ "native-assignments",
+ `${encodeURIComponent(childAgentId)}.json`,
+ );
+ const issuedAt = new Date();
+ const expiresAt = new Date(issuedAt.getTime() + 10 * 60_000);
+
+ try {
+ await writeJson(assignmentPath, {
+ schema_version: 1,
+ kind: "native-subagent-assignment",
+ lifecycle: "active",
+ root_session_id: sessionId,
+ root_thread_id: leaderThreadId,
+ child_agent_id: childAgentId,
+ agent_type: "executor",
+ allowed_actions: ["path-write"],
+ path_prefixes: ["src/assigned"],
+ issued_at: issuedAt.toISOString(),
+ expires_at: expiresAt.toISOString(),
+ bootstrap_generation: "bootstrap-generation-native-assignment",
+ });
+
+ const exactChild = { agent_id: childAgentId, agent_role: "executor" };
+ const allowed = await preToolUse(
+ cwd,
+ sessionId,
+ exactChild,
+ "Write",
+ { file_path: "src/assigned/result.txt", content: "ok\n" },
+ );
+ assert.equal(allowed.outputJson, null);
+
+ for (const [name, identity, filePath] of [
+ ["outside-scope", exactChild, "src/outside.txt"],
+ ["assignment-self-mutation", exactChild, assignmentPath],
+ ["foreign-child", { agent_id: "agent-native-assignment-foreign", agent_role: "executor" }, "src/assigned/result.txt"],
+ ["role-mismatch", { agent_id: childAgentId, agent_role: "writer" }, "src/assigned/result.txt"],
+ ["ungranted-writer", { agent_id: "agent-native-assignment-writer", agent_role: "writer" }, "src/assigned/result.txt"],
+ ] as const) {
+ const denied = await preToolUse(
+ cwd,
+ sessionId,
+ identity,
+ "Write",
+ { file_path: filePath, content: `${name}\n` },
+ );
+ assert.equal(denied.outputJson?.decision, "block", name);
+ assert.match(String(denied.outputJson?.reason ?? ""), /OWNER_CONFIRMATION_REQUIRED/, name);
+ }
+
+ await writeJson(assignmentPath, {
+ schema_version: 1,
+ kind: "native-subagent-assignment",
+ lifecycle: "active",
+ root_session_id: "foreign-session",
+ root_thread_id: leaderThreadId,
+ child_agent_id: childAgentId,
+ agent_type: "executor",
+ allowed_actions: ["path-write"],
+ path_prefixes: ["src/assigned"],
+ issued_at: issuedAt.toISOString(),
+ expires_at: expiresAt.toISOString(),
+ bootstrap_generation: "bootstrap-generation-native-assignment",
+ unexpected_scope_expansion: true,
+ });
+ const malformed = await preToolUse(
+ cwd,
+ sessionId,
+ exactChild,
+ "Write",
+ { file_path: "src/assigned/malformed.txt", content: "malformed\n" },
+ );
+ assert.equal(malformed.outputJson?.decision, "block");
+ assert.match(String(malformed.outputJson?.reason ?? ""), /OWNER_CONFIRMATION_REQUIRED/);
+
+ await mkdir(join(cwd, "src", "assigned"), { recursive: true });
+ const escapedTarget = await mkdtemp(join(tmpdir(), "omx-native-assignment-escape-"));
+ await symlink(escapedTarget, join(cwd, "src", "assigned", "link"));
+ await writeJson(assignmentPath, {
+ schema_version: 1,
+ kind: "native-subagent-assignment",
+ lifecycle: "active",
+ root_session_id: sessionId,
+ root_thread_id: leaderThreadId,
+ child_agent_id: childAgentId,
+ agent_type: "executor",
+ allowed_actions: ["path-write", "bash-write"],
+ path_prefixes: ["src/assigned"],
+ issued_at: issuedAt.toISOString(),
+ expires_at: expiresAt.toISOString(),
+ bootstrap_generation: "bootstrap-generation-native-assignment",
+ });
+ const allowedBash = await preToolUse(
+ cwd,
+ sessionId,
+ exactChild,
+ "Bash",
+ { command: "printf ok > src/assigned/bash.txt" },
+ );
+ assert.equal(allowedBash.outputJson, null);
+ for (const [name, command] of [
+ ["bash-outside-scope", "printf no > src/outside-bash.txt"],
+ ["bash-symlink-escape", "printf no > src/assigned/link/escaped.txt"],
+ ["bash-substitution-poison", "printf \"$(printf no)\" > src/assigned/poison.txt"],
+ ] as const) {
+ const denied = await preToolUse(cwd, sessionId, exactChild, "Bash", { command });
+ assert.equal(denied.outputJson?.decision, "block", name);
+ assert.match(String(denied.outputJson?.reason ?? ""), /OWNER_CONFIRMATION_REQUIRED/, name);
+ }
+ await rm(escapedTarget, { recursive: true, force: true });
+
+ await writeJson(assignmentPath, {
+ schema_version: 1,
+ kind: "native-subagent-assignment",
+ lifecycle: "active",
+ root_session_id: sessionId,
+ root_thread_id: leaderThreadId,
+ child_agent_id: childAgentId,
+ agent_type: "executor",
+ allowed_actions: ["path-write"],
+ path_prefixes: ["src/assigned"],
+ issued_at: new Date(issuedAt.getTime() - 20 * 60_000).toISOString(),
+ expires_at: new Date(issuedAt.getTime() - 10 * 60_000).toISOString(),
+ });
+ const stale = await preToolUse(
+ cwd,
+ sessionId,
+ exactChild,
+ "Write",
+ { file_path: "src/assigned/stale.txt", content: "stale\n" },
+ );
+ assert.equal(stale.outputJson?.decision, "block");
+ assert.match(String(stale.outputJson?.reason ?? ""), /OWNER_CONFIRMATION_REQUIRED/);
+
+ await writeJson(assignmentPath, {
+ schema_version: 1,
+ kind: "native-subagent-assignment",
+ lifecycle: "active",
+ root_session_id: sessionId,
+ root_thread_id: leaderThreadId,
+ child_agent_id: childAgentId,
+ agent_type: "executor",
+ allowed_actions: ["path-write", "bash-write"],
+ path_prefixes: ["."],
+ issued_at: issuedAt.toISOString(),
+ expires_at: expiresAt.toISOString(),
+ bootstrap_generation: "bootstrap-generation-native-assignment",
+ });
+ for (const [name, toolName, toolInput] of [
+ ["git-path", "Write", { file_path: ".git/config", content: "must-not-write\n" }],
+ ["omx-goal-path", "Write", { file_path: ".omx/ultragoal/goals.json", content: "{}\n" }],
+ ["git-bash", "Bash", { command: "printf no > .git/config" }],
+ ["omx-goal-bash", "Bash", { command: "printf no > .omx/ultragoal/goals.json" }],
+ ] as const) {
+ const denied = await preToolUse(cwd, sessionId, exactChild, toolName, toolInput);
+ assert.equal(denied.outputJson?.decision, "block", name);
+ assert.match(String(denied.outputJson?.reason ?? ""), /OWNER_CONFIRMATION_REQUIRED/, name);
+ }
+
+ await writeJson(assignmentPath, {
+ schema_version: 1,
+ kind: "native-subagent-assignment",
+ lifecycle: "active",
+ root_session_id: sessionId,
+ root_thread_id: leaderThreadId,
+ child_agent_id: childAgentId,
+ agent_type: "executor",
+ allowed_actions: ["path-write"],
+ path_prefixes: ["src/assigned"],
+ issued_at: issuedAt.toISOString(),
+ expires_at: expiresAt.toISOString(),
+ });
+ await chmod(assignmentPath, 0o666);
+ const writableByOthers = await preToolUse(
+ cwd,
+ sessionId,
+ exactChild,
+ "Write",
+ { file_path: "src/assigned/world-writable-grant.txt", content: "must-not-write\n" },
+ );
+ assert.equal(writableByOthers.outputJson?.decision, "block");
+ assert.match(String(writableByOthers.outputJson?.reason ?? ""), /OWNER_CONFIRMATION_REQUIRED/);
+ } finally {
+ await rm(cwd, { recursive: true, force: true });
+ }
+ });
+
+ it("allows only Main-root to issue an assignment in the exact active session scope", async () => {
+ const fixture = await createActiveConductorFixture();
+ const { cwd, sessionId, leaderThreadId } = fixture;
+
+ try {
+ const root = { agent_id: leaderThreadId, thread_id: leaderThreadId };
+
+ const rootAssignment = await preToolUse(cwd, sessionId, root, "Write", {
+ file_path: `.omx/state/sessions/${sessionId}/native-assignments/root-created.json`,
+ content: "{}\n",
+ });
+ assert.equal(rootAssignment.outputJson, null, "root-assignment-create");
+ const foreignSessionAssignment = await preToolUse(cwd, sessionId, root, "Write", {
+ file_path: ".omx/state/sessions/foreign-session/native-assignments/root-created.json",
+ content: "{}\n",
+ });
+ assert.equal(foreignSessionAssignment.outputJson?.decision, "block", "foreign-session-assignment");
+ const protectedGate = await preToolUse(cwd, sessionId, root, "Write", {
+ file_path: `.omx/state/sessions/${sessionId}/ultragoal-state.json`,
+ content: "{}\n",
+ });
+ assert.equal(protectedGate.outputJson?.decision, "block", "protected-state-gate");
+
+ } finally {
+ await rm(cwd, { recursive: true, force: true });
+ }
+ });
+
+});
diff --git a/src/scripts/__tests__/codex-native-hook.test.ts b/src/scripts/__tests__/codex-native-hook.test.ts
index 59ae97fc562b8d373f93117a88be1272386cb93e..7ec48d789f7e7f8a144129efe70202bb358802a5 100644
--- a/src/scripts/__tests__/codex-native-hook.test.ts
+++ b/src/scripts/__tests__/codex-native-hook.test.ts
@@ -2774,8 +2774,19 @@ PY`,
const sessionDir = join(cwd, ".omx", "state", "sessions", sessionId);
const skillStatePath = join(sessionDir, "skill-active-state.json");
const expectsAutopilotDenial = testCase.expectedSkill === "autopilot";
- if (testCase.expectedSkill === null) {
+ const expectsNativeUltragoalOwnerDenial = testCase.expectedSkill === "ultragoal";
+ if (testCase.expectedSkill === null || expectsNativeUltragoalOwnerDenial) {
assert.equal(existsSync(skillStatePath), false, testCase.name);
+ if (expectsNativeUltragoalOwnerDenial) {
+ assert.equal(submit.skillState?.active, false, testCase.name);
+ assert.equal(submit.skillState?.skill, "ultragoal", testCase.name);
+ assert.match(String(submit.skillState?.transition_error ?? ""), /OMX-ULTRAGOAL-NO-OWNER/, testCase.name);
+ assert.match(
+ String((submit.outputJson as { hookSpecificOutput?: { additionalContext?: string } } | null)?.hookSpecificOutput?.additionalContext ?? ""),
+ /OMX-ULTRAGOAL-NO-OWNER/,
+ testCase.name,
+ );
+ }
} else {
const skillState = JSON.parse(await readFile(skillStatePath, "utf-8")) as { active?: boolean; skill?: string; phase?: string; error?: string; deferred_skills?: string[]; active_skills?: Array<{ skill?: string }> };
if (expectsAutopilotDenial) {
@@ -2818,7 +2829,7 @@ PY`,
thread_id: `thread-${testCase.name}`,
turn_id: `stop-${testCase.name}`,
}, { cwd });
- if (testCase.expectedSkill === null || expectsAutopilotDenial) {
+ if (testCase.expectedSkill === null || expectsAutopilotDenial || expectsNativeUltragoalOwnerDenial) {
assert.equal(stop.outputJson, null, testCase.name);
} else if ("expectedStopBlock" in testCase && !testCase.expectedStopBlock) {
assert.notEqual((stop.outputJson as { decision?: string } | null)?.decision, "block", testCase.name);
@@ -3267,10 +3278,16 @@ PY`,
const sessionDir = join(cwd, ".omx", "state", "sessions", sessionId);
const skillStatePath = join(sessionDir, "skill-active-state.json");
const expectsAutopilotDenial = testCase.expectedSkill === "autopilot";
- if (testCase.expectedSkill === null) {
+ const expectsNativeUltragoalOwnerDenial = testCase.expectedSkill === "ultragoal";
+ if (testCase.expectedSkill === null || expectsNativeUltragoalOwnerDenial) {
assert.equal(existsSync(skillStatePath), false, testCase.name);
assert.equal(existsSync(join(sessionDir, "ralplan-state.json")), false, testCase.name);
assert.equal(existsSync(join(sessionDir, "autopilot-state.json")), false, testCase.name);
+ if (expectsNativeUltragoalOwnerDenial) {
+ const guidance = String((submit.hookSpecificOutput as { additionalContext?: string } | undefined)?.additionalContext ?? "");
+ assert.match(guidance, /OMX-ULTRAGOAL-NO-OWNER/, testCase.name);
+ assert.equal(existsSync(join(sessionDir, "ultragoal-state.json")), false, testCase.name);
+ }
} else {
assert.equal(existsSync(skillStatePath), true, testCase.name);
const skillState = JSON.parse(await readFile(skillStatePath, "utf-8")) as {
@@ -3321,7 +3338,9 @@ PY`,
thread_id: `thread-${caseIndex}`,
turn_id: `stop-${caseIndex}`,
}, { cwd, env }));
- if (testCase.expectedSkill === null || expectsAutopilotDenial) assert.deepEqual(stop, {}, testCase.name);
+ if (testCase.expectedSkill === null || expectsAutopilotDenial || expectsNativeUltragoalOwnerDenial) {
+ assert.deepEqual(stop, {}, testCase.name);
+ }
else if ("expectedStopBlock" in testCase && !testCase.expectedStopBlock) {
assert.notEqual(stop.decision, "block", testCase.name);
} else assert.equal(stop.decision, "block", testCase.name);
@@ -4200,7 +4219,7 @@ PY`,
process.env.OMX_SESSION_ID = sessionId;
assert.equal(await neutralizeOwnedRoutingRalplan(cwd), true);
const result = await dispatchCodexNativeHook({ hook_event_name: 'SessionStart', cwd, session_id: sessionId }, { cwd });
- const context = String((result.outputJson as { hookSpecificOutput?: { additionalContext?: string } }).hookSpecificOutput?.additionalContext ?? '');
+ const context = String((result.outputJson as { hookSpecificOutput?: { additionalContext?: string } } | null)?.hookSpecificOutput?.additionalContext ?? '');
assert.doesNotMatch(context, /- ralplan phase:/);
} finally {
previousSessionId === undefined ? delete process.env.OMX_SESSION_ID : process.env.OMX_SESSION_ID = previousSessionId;
@@ -18940,6 +18959,68 @@ exit 0
);
assert.equal(allowedModeFlagTerminal.outputJson, null);
+ const allowedModeFlagBlockedTerminal = await dispatchCodexNativeHook(
+ {
+ hook_event_name: "PreToolUse",
+ cwd,
+ session_id: "sess-ralplan-input-file",
+ thread_id: leaderThreadId,
+ agent_id: leaderThreadId,
+ tool_name: "Bash",
+ tool_use_id: "tool-ralplan-state-mode-flag-blocked-terminal-allowed",
+ tool_input: {
+ command: `omx state write --mode ralplan --input '${JSON.stringify({
+ active: false,
+ current_phase: "blocked",
+ blocked_reason: "documented_host_consensus_receipt_unavailable",
+ ralplan_consensus_gate: {
+ complete: false,
+ blocked_reason: "documented_host_consensus_receipt_unavailable",
+ },
+ session_id: "sess-ralplan-input-file",
+ workingDirectory: cwd,
+ })}' --json`,
+ },
+ },
+ { cwd },
+ );
+ assert.equal(allowedModeFlagBlockedTerminal.outputJson, null);
+ for (const [name, input] of [
+ ['missing blocked reason', {
+ active: false,
+ current_phase: 'blocked',
+ ralplan_consensus_gate: { complete: false, blocked_reason: 'documented_host_consensus_receipt_unavailable' },
+ session_id: 'sess-ralplan-input-file',
+ workingDirectory: cwd,
+ }],
+ ['missing blocked gate', {
+ active: false,
+ current_phase: 'blocked',
+ blocked_reason: 'documented_host_consensus_receipt_unavailable',
+ session_id: 'sess-ralplan-input-file',
+ workingDirectory: cwd,
+ }],
+ ['approving blocked gate', {
+ active: false,
+ current_phase: 'blocked',
+ blocked_reason: 'documented_host_consensus_receipt_unavailable',
+ ralplan_consensus_gate: { complete: true, blocked_reason: 'documented_host_consensus_receipt_unavailable' },
+ session_id: 'sess-ralplan-input-file',
+ workingDirectory: cwd,
+ }],
+ ] as const) {
+ const blocked = await dispatchCodexNativeHook({
+ hook_event_name: 'PreToolUse',
+ cwd,
+ session_id: 'sess-ralplan-input-file',
+ thread_id: leaderThreadId,
+ agent_id: leaderThreadId,
+ tool_name: 'Bash',
+ tool_input: { command: `omx state write --mode ralplan --input '${JSON.stringify(input)}' --json` },
+ }, { cwd });
+ assert.equal(blocked.outputJson?.decision, 'block', name);
+ }
+
const ralplanTerminalPayload = JSON.stringify({ active: false, current_phase: "complete", session_id: "sess-ralplan-input-file", workingDirectory: cwd });
for (const [name, command] of [
["node require", `node --require .omx/context/preload.cjs dist/cli/omx.js state write --mode ralplan --input '${ralplanTerminalPayload}' --json`],
@@ -22067,7 +22148,7 @@ PY`,
}
}
});
- it("#3316: allows a registered child to message its owning leader via collaboration.send_message during active deep-interview", async () => {
+ it("#3316: denies collaboration.send_message during active deep-interview without host-authenticated caller-parent-target proof", async () => {
const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-3316-di-send-message-"));
try {
const stateDir = join(cwd, ".omx", "state");
@@ -22143,15 +22224,15 @@ PY`,
{ cwd },
);
- // Registered leader -> registered child: already allowed today (main-root actor bypasses the gate).
const leaderToChild = await sendMessage(leaderThreadId, leaderThreadId, childThreadId);
- assert.equal(leaderToChild.outputJson, null, "leader-to-child");
+ assert.equal(leaderToChild.outputJson?.decision, "block", "leader-to-child");
+ assert.match(String(leaderToChild.outputJson?.reason ?? ""), /not a recognized read-only or explicitly authorized deep-interview mutation transport|documented host-authenticated Main-root authority/, "leader-to-child");
- // Registered child -> its owning leader, same authoritative session, target relation proven: now allowed.
const childToLeader = await sendMessage(childThreadId, childThreadId, leaderThreadId);
- assert.equal(childToLeader.outputJson, null, "child-to-leader");
+ assert.equal(childToLeader.outputJson?.decision, "block", "child-to-leader");
+ assert.match(String(childToLeader.outputJson?.reason ?? ""), /OWNER_CONFIRMATION_REQUIRED/, "child-to-leader");
- // The flattened Codex CLI tool-name form must canonicalize identically.
+ // Flattened tool names remain equally denied without a host-authenticated caller-parent-target relation.
const flattenedChildToLeader = await dispatchCodexNativeHook(
{
hook_event_name: "PreToolUse",
@@ -22164,7 +22245,8 @@ PY`,
},
{ cwd },
);
- assert.equal(flattenedChildToLeader.outputJson, null, "flattened-child-to-leader");
+ assert.equal(flattenedChildToLeader.outputJson?.decision, "block", "flattened-child-to-leader");
+ assert.match(String(flattenedChildToLeader.outputJson?.reason ?? ""), /OWNER_CONFIRMATION_REQUIRED/, "flattened-child-to-leader");
// spawn/close/interrupt/followup/wait remain gated for the same registered child: no namespace-wide loosening.
for (const toolName of [
@@ -22230,8 +22312,7 @@ PY`,
assert.match(String(malformed.outputJson?.reason ?? ""), /OWNER_CONFIRMATION_REQUIRED/, `malformed-target-${label}`);
}
- // No command/path execution rides along on message content: shell-metacharacter-laden
- // message text from the registered child to its owning leader stays inert and allowed.
+ // Message content is inert, but transport authority is still absent and must fail closed.
const messageWithShellPayload = await dispatchCodexNativeHook(
{
hook_event_name: "PreToolUse",
@@ -22244,13 +22325,14 @@ PY`,
},
{ cwd },
);
- assert.equal(messageWithShellPayload.outputJson, null, "shell-payload-message-content");
+ assert.equal(messageWithShellPayload.outputJson?.decision, "block", "shell-payload-message-content");
+ assert.match(String(messageWithShellPayload.outputJson?.reason ?? ""), /OWNER_CONFIRMATION_REQUIRED/, "shell-payload-message-content");
} finally {
await rm(cwd, { recursive: true, force: true });
}
});
- it("#3316: allows a registered child to message its owning leader via collaboration.send_message during active ralplan", async () => {
+ it("#3316: denies collaboration.send_message during active ralplan without host-authenticated caller-parent-target proof", async () => {
const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-3316-ralplan-send-message-"));
try {
const stateDir = join(cwd, ".omx", "state");
@@ -22306,10 +22388,12 @@ PY`,
);
const leaderToChild = await sendMessage(leaderThreadId, childThreadId);
- assert.equal(leaderToChild.outputJson, null, "ralplan-leader-to-child");
+ assert.equal(leaderToChild.outputJson?.decision, "block", "ralplan-leader-to-child");
+ assert.match(String(leaderToChild.outputJson?.reason ?? ""), /not a recognized read-only or explicitly authorized planning mutation transport|documented host-authenticated Main-root authority/, "ralplan-leader-to-child");
const childToLeader = await sendMessage(childThreadId, leaderThreadId);
- assert.equal(childToLeader.outputJson, null, "ralplan-child-to-leader");
+ assert.equal(childToLeader.outputJson?.decision, "block", "ralplan-child-to-leader");
+ assert.match(String(childToLeader.outputJson?.reason ?? ""), /OWNER_CONFIRMATION_REQUIRED/, "ralplan-child-to-leader");
const spawnAgentStillGated = await dispatchCodexNativeHook(
{
@@ -22423,7 +22507,7 @@ PY`,
return { sessionId, leaderThreadId, stateDir };
};
- it("allows flattened known collaboration tools under active ralplan while unknown flattened names stay blocked", async () => {
+ it("denies flattened collaboration tools under active ralplan without documented host authority", async () => {
const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-flattened-collab-ralplan-"));
try {
const { sessionId, leaderThreadId } = await writeFlattenedCollaborationRalplanFixture(cwd);
@@ -22444,7 +22528,12 @@ PY`,
tool_name,
tool_input,
}, { cwd });
- assert.equal(result.outputJson, null, tool_name);
+ assert.equal(result.outputJson?.decision, "block", tool_name);
+ assert.match(
+ String(result.outputJson?.reason ?? ""),
+ /not a recognized read-only or explicitly authorized planning mutation transport|OWNER_CONFIRMATION_REQUIRED/,
+ tool_name,
+ );
}
const blocked = await dispatchCodexNativeHook({
@@ -22457,8 +22546,7 @@ PY`,
}, { cwd });
assert.equal(blocked.outputJson?.decision, "block");
const reason = String(blocked.outputJson?.reason ?? "");
- assert.match(reason, /not a recognized read-only or explicitly authorized planning mutation transport/);
- assert.match(reason, /collaborationbogus_thing/);
+ assert.match(reason, /not a recognized read-only or explicitly authorized planning mutation transport|OWNER_CONFIRMATION_REQUIRED/);
} finally {
await rm(cwd, { recursive: true, force: true });
}
@@ -32805,6 +32893,385 @@ PY`,
}
});
+ it("issue #3358 keeps Team and update_plan denied while hardening exact read-only discovery", async () => {
+ const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-3358-transport-"));
+ try {
+ const stateDir = join(cwd, ".omx", "state");
+ const sessionId = "sess-3358-transport";
+ const leaderThreadId = "thread-3358-transport";
+ const childThreadId = "child-3358-transport";
+ execFileSync("git", ["init", "-q"], {
+ cwd,
+ env: {
+ ...process.env,
+ GIT_CONFIG_COUNT: "0",
+ GIT_CONFIG_GLOBAL: process.platform === "win32" ? "NUL" : "/dev/null",
+ GIT_CONFIG_NOSYSTEM: "1",
+ GIT_CONFIG_SYSTEM: process.platform === "win32" ? "NUL" : "/dev/null",
+ },
+ });
+ await writeNativeMappedSessionState(cwd, stateDir, sessionId, sessionId, leaderThreadId);
+ await writeJson(join(stateDir, "subagent-tracking.json"), {
+ schemaVersion: 1,
+ sessions: {
+ [sessionId]: {
+ session_id: sessionId,
+ leader_thread_id: leaderThreadId,
+ threads: {
+ [leaderThreadId]: { thread_id: leaderThreadId, kind: "leader" },
+ [childThreadId]: { thread_id: childThreadId, kind: "subagent", parent_thread_id: leaderThreadId },
+ },
+ },
+ },
+ });
+ await writeSessionSkillActiveState(stateDir, sessionId, "ultragoal", "planning");
+ await writeJson(join(stateDir, "sessions", sessionId, "ultragoal-state.json"), {
+ active: true,
+ mode: "ultragoal",
+ current_phase: "planning",
+ session_id: sessionId,
+ workingDirectory: cwd,
+ });
+
+ await withCleanAmbientNodeRuntimeEnvironment(async () => {
+ await withTrustedWorkspaceOmxCli(cwd, async (_omxCommand, trustedPath) => {
+ const previousPath = process.env.PATH;
+ process.env.PATH = trustedPath;
+ try {
+ const rootPayload = (toolName: string, toolInput: Record<string, unknown>, overrides: Record<string, unknown> = {}) => ({
+ hook_event_name: "PreToolUse",
+ cwd,
+ session_id: sessionId,
+ turn_id: "turn-3358-transport",
+ tool_name: toolName,
+ tool_use_id: `tool-3358-${Math.random()}`,
+ tool_input: toolInput,
+ ...overrides,
+ });
+ const runBash = (command: string, overrides: Record<string, unknown> = {}) => dispatchCodexNativeHook(
+ rootPayload("Bash", { command }, overrides),
+ { cwd },
+ );
+ const safeGitEnvironment = {
+ GIT_ATTR_NOSYSTEM: "1",
+ GIT_CONFIG_COUNT: "0",
+ GIT_CONFIG_GLOBAL: process.platform === "win32" ? "NUL" : "/dev/null",
+ GIT_CONFIG_NOSYSTEM: "1",
+ GIT_CONFIG_SYSTEM: process.platform === "win32" ? "NUL" : "/dev/null",
+ GIT_EDITOR: "",
+ GIT_EXTERNAL_DIFF: "",
+ GIT_PAGER: "",
+ GIT_SEQUENCE_EDITOR: "",
+ PAGER: "",
+ };
+ const assignmentWord = (name: string, value: string) => value === "" ? `${name}=` : `${name}=${JSON.stringify(value)}`;
+ const hardenedGitStatus = (overrides: Record<string, string> = {}, extraAssignments: string[] = []) => {
+ const environment = { ...safeGitEnvironment, ...overrides };
+ return [
+ ...Object.entries(environment).map(([name, value]) => assignmentWord(name, value)),
+ ...extraAssignments,
+ "git --no-pager --no-optional-locks -c core.fsmonitor=false -c core.untrackedCache=false -c pager.status=false status --short --branch --untracked-files=normal --ignore-submodules=all --no-renames",
+ ].join(" ");
+ };
+ const runFixtureGit = (args: string[]) => execFileSync("git", args, {
+ cwd,
+ env: {
+ ...process.env,
+ GIT_CONFIG_COUNT: "0",
+ GIT_CONFIG_GLOBAL: process.platform === "win32" ? "NUL" : "/dev/null",
+ GIT_CONFIG_NOSYSTEM: "1",
+ GIT_CONFIG_SYSTEM: process.platform === "win32" ? "NUL" : "/dev/null",
+ GIT_EXTERNAL_DIFF: "",
+ GIT_PAGER: "",
+ PAGER: "",
+ },
+ });
+ const assertAllowed = async (name: string, command: string) => {
+ const result = await runBash(command);
+ assert.equal(result.outputJson, null, `${name}: ${JSON.stringify(result)}`);
+ };
+ const assertBlocked = async (name: string, command: string) => {
+ const result = await runBash(command);
+ assert.equal(result.outputJson?.decision, "block", `${name}: ${JSON.stringify(result)}`);
+ };
+
+ await assertAllowed("hardened git status", hardenedGitStatus());
+ await assertAllowed("hardened git status command-local PATH", hardenedGitStatus({}, [assignmentWord("PATH", trustedPath)]));
+ const inheritedPager = process.env.PAGER;
+ process.env.PAGER = "cat";
+ try {
+ await assertBlocked("plain git status under inherited pager", "git status --short");
+ await assertAllowed(
+ "hardened git status neutralizes inherited pager",
+ process.platform === "win32"
+ ? hardenedGitStatus()
+ : hardenedGitStatus().replace(/\bgit /, "/usr/bin/git "),
+ );
+ } finally {
+ if (inheritedPager === undefined) delete process.env.PAGER;
+ else process.env.PAGER = inheritedPager;
+ }
+ await assertAllowed("bounded find files", "find . -maxdepth 2 -type f");
+ await assertAllowed("bounded find command-local PATH", `${assignmentWord("PATH", trustedPath)} find . -maxdepth 2 -type f`);
+ await assertAllowed("bounded find directories", "find . -mindepth 1 -maxdepth 3 -type d -print");
+ // The CI image does not guarantee ripgrep; assert the real trusted binary only when the authenticated PATH contains it.
+ if (existsSync("/usr/bin/rg") || existsSync("/bin/rg")) {
+ await assertAllowed("real rg", "rg -n \"transport\" README.md");
+ }
+
+ for (const [name, command] of [
+ ["plain git status", "git status --short --branch"],
+ ["git status path operand", `${hardenedGitStatus()} src`],
+ ["git status unmodeled option", "git status --porcelain"],
+ ["git status chain", `${hardenedGitStatus()}; true`],
+ ["git status redirect", `${hardenedGitStatus()} > status.txt`],
+ ["git status pipeline", `${hardenedGitStatus()} | cat`],
+ ["git status substituted executable", hardenedGitStatus().replace(/\bgit /, "$(printf git) ")],
+ ["git status wrapper", hardenedGitStatus().replace(/\bgit /, "command git ")],
+ ["git status function", `git() { printf x > pwned; }; ${hardenedGitStatus()}`],
+ ["git status alias", `shopt -s expand_aliases; alias git='printf x > pwned'; ${hardenedGitStatus()}`],
+ ["git status nested shell", `bash -c ${JSON.stringify(hardenedGitStatus())}`],
+ ["find exec", "find . -type f -exec sh -c 'printf x > pwned' \\;"],
+ ["find delete", "find . -type f -delete"],
+ ["find file output", "find . -type f -fprint pwned"],
+ ["find dynamic depth", "find . -maxdepth \"$DEPTH\" -type f"],
+ ["unbounded find", "find . -type f"],
+ ["outside workspace find", "find .. -maxdepth 2 -type f"],
+ ["absolute workspace escape find", "find /tmp -maxdepth 2 -type f"],
+ ["excessive find depth", "find . -maxdepth 33 -type f"],
+ ["huge find depth", "find . -maxdepth 999999999 -type f"],
+ ["find wrapper", "command find . -maxdepth 2 -type f"],
+ ["find function", "find() { printf x > pwned; }; find . -maxdepth 2 -type f"],
+ ["find alias", "shopt -s expand_aliases; alias find='printf x > pwned'; find . -maxdepth 2 -type f"],
+ ["find nested shell", "bash -c 'find . -maxdepth 2 -type f'"],
+ ["find chain", "find . -maxdepth 2 -type f; true"],
+ ["find redirect", "find . -maxdepth 2 -type f > files.txt"],
+ ["find pipeline", "find . -maxdepth 2 -type f | cat"],
+ ["find substitution", "find \"$(printf .)\" -maxdepth 2 -type f"],
+ ["find brace expansion", "find . {-exec,sh,-c,'touch pwned',';'} -maxdepth 0"],
+ ["find pathname expansion", "find . -maxdepth 2 -name *"],
+ ["find extglob expansion", "find . -maxdepth 2 -name @(src|docs)"],
+ ] as const) await assertBlocked(name, command);
+
+ const outsideFindRoot = await mkdtemp(join(tmpdir(), "omx-3358-find-outside-"));
+ const outsideFindLink = join(cwd, "outside-find-link");
+ try {
+ await mkdir(join(outsideFindRoot, "nested"), { recursive: true });
+ await symlink(outsideFindRoot, outsideFindLink, process.platform === "win32" ? "junction" : "dir");
+ await assertBlocked("symlinked find workspace escape", "find outside-find-link/nested -maxdepth 2 -type f");
+ } finally {
+ await rm(outsideFindLink, { force: true });
+ await rm(outsideFindRoot, { recursive: true, force: true });
+ }
+
+ process.env["BASH_FUNC_git%%"] = "() { printf x > pwned; }";
+ process.env["BASH_FUNC_find%%"] = "() { printf x > pwned; }";
+ try {
+ await assertBlocked("exported git function", hardenedGitStatus());
+ await assertBlocked("exported find function", "find . -maxdepth 2 -type f");
+ } finally {
+ delete process.env["BASH_FUNC_git%%"];
+ delete process.env["BASH_FUNC_find%%"];
+ }
+
+ for (const [name, overrides] of [
+ ["GIT_PAGER override", { GIT_PAGER: "cat" }],
+ ["PAGER override", { PAGER: "cat" }],
+ ["external diff override", { GIT_EXTERNAL_DIFF: "sh -c 'printf x > pwned'" }],
+ ["config count override", { GIT_CONFIG_COUNT: "1" }],
+ ["GIT_DIR override", { GIT_DIR: join(cwd, "foreign-git-dir") }],
+ ] as const) await assertBlocked(name, hardenedGitStatus(overrides));
+
+ const previousExternalDiff = process.env.GIT_EXTERNAL_DIFF;
+ const previousGitPager = process.env.GIT_PAGER;
+ process.env.GIT_EXTERNAL_DIFF = "sh -c 'printf x > pwned'";
+ process.env.GIT_PAGER = "sh -c 'printf x > pwned'";
+ try {
+ await assertBlocked(
+ "append external diff neutralizer",
+ hardenedGitStatus().replace("GIT_EXTERNAL_DIFF=", "GIT_EXTERNAL_DIFF+="),
+ );
+ await assertBlocked(
+ "append pager neutralizer",
+ hardenedGitStatus().replace("GIT_PAGER=", "GIT_PAGER+="),
+ );
+ } finally {
+ if (previousExternalDiff === undefined) delete process.env.GIT_EXTERNAL_DIFF;
+ else process.env.GIT_EXTERNAL_DIFF = previousExternalDiff;
+ if (previousGitPager === undefined) delete process.env.GIT_PAGER;
+ else process.env.GIT_PAGER = previousGitPager;
+ }
+
+ const configPath = join(cwd, ".git", "config");
+ const originalGitConfig = await readFile(configPath, "utf-8");
+ for (const [name, config] of [
+ ["git alias config", "[alias]\n status-safe = !printf x > pwned\n"],
+ ["core pager config", "[core]\n pager = sh -c 'printf x > pwned'\n"],
+ ["core fsmonitor config", "[core]\n fsmonitor = sh -c 'printf x > pwned'\n"],
+ ["core worktree config", `[core]\n worktree = ${join(cwd, "foreign-worktree")}\n`],
+ ["core excludes config", `[core]\n excludesFile = ${join(cwd, "foreign-excludes")}\n`],
+ ["core hooks config", `[core]\n hooksPath = ${join(cwd, "foreign-hooks")}\n`],
+ ["core attributes config", `[core]\n attributesFile = ${join(cwd, "foreign-attributes")}\n`],
+ ["include config", `[include]\n path = ${join(cwd, "foreign-config")}\n`],
+ ["conditional include config", `[includeIf \"gitdir:${cwd}/\"]\n path = ${join(cwd, "foreign-config")}\n`],
+ ["interactive diff filter config", "[interactive]\n diffFilter = sh -c 'printf x > pwned'\n"],
+ ["status submodule summary config", "[status]\n submoduleSummary = true\n"],
+ ["diff driver command config", "[diff \"evil\"]\n command = sh -c 'printf x > pwned'\n"],
+ ["diff textconv config", "[diff \"evil\"]\n textconv = sh -c 'printf x > pwned'\n"],
+ ["external diff config", "[diff]\n external = sh -c 'printf x > pwned'\n"],
+ ["filter helper config", "[filter \"evil\"]\n clean = sh -c 'printf x > pwned'\n"],
+ ["submodule helper config", "[submodule \"child\"]\n update = !printf x > pwned\n"],
+ ] as const) {
+ await writeFile(configPath, `${originalGitConfig}\n${config}`);
+ await assertBlocked(name, hardenedGitStatus());
+ await writeFile(configPath, originalGitConfig);
+ }
+
+ await writeFile(join(cwd, ".gitmodules"), "[submodule \"child\"]\n path = child\n url = ./child\n");
+ runFixtureGit(["add", "--", ".gitmodules"]);
+ await assertBlocked("gitmodules submodule", hardenedGitStatus());
+ runFixtureGit(["rm", "--cached", "-q", "--", ".gitmodules"]);
+ await rm(join(cwd, ".gitmodules"), { force: true });
+ await writeFile(join(cwd, ".gitattributes"), "*.txt filter=evil\n");
+ await assertBlocked("untracked worktree attributes helper", hardenedGitStatus());
+ runFixtureGit(["add", "--", ".gitattributes"]);
+ await assertBlocked("tracked worktree attributes helper", hardenedGitStatus());
+ runFixtureGit(["rm", "--cached", "-q", "--", ".gitattributes"]);
+ await rm(join(cwd, ".gitattributes"), { force: true });
+ await mkdir(join(cwd, "nested"), { recursive: true });
+ await writeFile(join(cwd, "nested", "tracked.txt"), "tracked\n");
+ runFixtureGit(["add", "--", "nested/tracked.txt"]);
+ await writeFile(join(cwd, "nested", ".gitattributes"), "*.txt filter=evil\n");
+ await assertBlocked("nested untracked worktree attributes helper", hardenedGitStatus());
+ await rm(join(cwd, "nested", ".gitattributes"), { force: true });
+ runFixtureGit(["rm", "--cached", "-q", "--", "nested/tracked.txt"]);
+ await rm(join(cwd, "nested"), { recursive: true, force: true });
+ await mkdir(join(cwd, ".git", "info"), { recursive: true });
+ await writeFile(join(cwd, ".git", "info", "attributes"), "*.txt diff=evil\n");
+ await assertBlocked("git info attributes helper", hardenedGitStatus());
+ await rm(join(cwd, ".git", "info", "attributes"), { force: true });
+
+ const attackerDir = await mkdtemp(join(tmpdir(), "omx-3358-discovery-shadow-"));
+ try {
+ for (const commandName of ["git", "find"]) {
+ await writeFile(join(attackerDir, commandName), "#!/bin/sh\nprintf x > pwned\n");
+ await chmod(join(attackerDir, commandName), 0o755);
+ }
+ const shadowedPath = `${attackerDir}:${trustedPath}`;
+ await assertBlocked("PATH-shadowed git", hardenedGitStatus({}, [assignmentWord("PATH", shadowedPath)]));
+ await assertBlocked("foreign absolute git", hardenedGitStatus().replace(/\bgit /, `${join(attackerDir, "git")} `));
+ await assertBlocked("PATH-shadowed find", `${assignmentWord("PATH", shadowedPath)} find . -maxdepth 2 -type f`);
+ await assertBlocked("foreign absolute find", `${join(attackerDir, "find")} . -maxdepth 2 -type f`);
+ } finally {
+ await rm(attackerDir, { recursive: true, force: true });
+ }
+
+ const trimPrefixDir = await mkdtemp(join(tmpdir(), "omx-3358-trim-prefix-"));
+ try {
+ for (const [name, prefix] of [["BOM", "\uFEFF"], ["NBSP", "\u00A0"], ["CR", "\r"]] as const) {
+ for (const executableName of [`${prefix}find`, `${prefix}GIT_ATTR_NOSYSTEM=1`]) {
+ await writeFile(join(trimPrefixDir, executableName), "#!/bin/sh\nprintf x > pwned\n");
+ await chmod(join(trimPrefixDir, executableName), 0o755);
+ }
+ process.env.PATH = `${trimPrefixDir}:${trustedPath}`;
+ await assertBlocked(`${name}-prefixed find`, `${prefix}find . -maxdepth 2 -type f`);
+ await assertBlocked(`${name}-prefixed git environment`, `${prefix}${hardenedGitStatus()}`);
+ }
+ } finally {
+ process.env.PATH = trustedPath;
+ await rm(trimPrefixDir, { recursive: true, force: true });
+ }
+
+ const updatePlan = await dispatchCodexNativeHook(
+ rootPayload("update_plan", {
+ explanation: "bounded metadata",
+ plan: [{ step: "reproduce transports", status: "in_progress" }],
+ }),
+ { cwd },
+ );
+ assert.equal(updatePlan.outputJson?.decision, "block", JSON.stringify(updatePlan));
+ assert.match(String(updatePlan.outputJson?.reason ?? ""), /not a recognized read-only or explicitly authorized Conductor mutation transport/);
+
+ const foreignUpdatePlan = await dispatchCodexNativeHook(
+ rootPayload("update_plan", { plan: [{ step: "foreign", status: "pending" }] }, { session_id: "foreign-session" }),
+ { cwd },
+ );
+ assert.equal(foreignUpdatePlan.outputJson?.decision, "block", JSON.stringify(foreignUpdatePlan));
+ assert.match(String(foreignUpdatePlan.outputJson?.reason ?? ""), /PROVENANCE_DENIED/);
+
+ const exactTeam = await runBash('omx team 1:executor "Implement the bounded issue 3358 slice"');
+ assert.equal(exactTeam.outputJson?.decision, "block", JSON.stringify(exactTeam));
+
+ for (const [toolName, toolInput] of [
+ ["collaboration.spawn_agent", { agent_type: "executor", message: "forged root spawn" }],
+ ["collaboration.send_message", { agent_id: childThreadId, message: "forged root report" }],
+ ["create_goal", { objective: "forged root lifecycle" }],
+ ["update_goal", { status: "complete" }],
+ ["mcp__omx_team__start", { workers: 1, role: "executor", task: "forged root team" }],
+ ] as const) {
+ const forgedLeader = await dispatchCodexNativeHook(
+ rootPayload(toolName, toolInput, {
+ agent_id: leaderThreadId,
+ thread_id: leaderThreadId,
+ }),
+ { cwd },
+ );
+ assert.equal(forgedLeader.outputJson?.decision, "block", `${toolName}: ${JSON.stringify(forgedLeader)}`);
+ }
+
+ const childWrite = await dispatchCodexNativeHook(
+ rootPayload("apply_patch", {
+ command: "*** Begin Patch\n*** Add File: src/child.ts\n+export {};\n*** End Patch",
+ }, {
+ agent_id: childThreadId,
+ agent_type: "executor",
+ turn_id: "turn-3358-child",
+ }),
+ { cwd },
+ );
+ assert.equal(childWrite.outputJson?.decision, "block", JSON.stringify(childWrite));
+ assert.match(String(childWrite.outputJson?.reason ?? ""), /OWNER_CONFIRMATION_REQUIRED/);
+
+ const ownLeaderReport = await dispatchCodexNativeHook(
+ rootPayload("collaboration.send_message", {
+ agent_id: leaderThreadId,
+ message: "Verification complete; no mutation attempted.",
+ }, {
+ agent_id: childThreadId,
+ agent_type: "verifier",
+ turn_id: "turn-3358-child-report",
+ }),
+ { cwd },
+ );
+ assert.equal(ownLeaderReport.outputJson?.decision, "block", JSON.stringify(ownLeaderReport));
+ assert.match(String(ownLeaderReport.outputJson?.reason ?? ""), /OWNER_CONFIRMATION_REQUIRED/);
+
+ for (const [name, overrides, targetAgentId] of [
+ ["cross-child report", { agent_id: childThreadId, agent_type: "verifier" }, childThreadId],
+ ["unregistered child report", { agent_id: "unknown-child", agent_type: "verifier" }, leaderThreadId],
+ ["foreign-session child report", { agent_id: childThreadId, agent_type: "verifier", session_id: "foreign-session" }, leaderThreadId],
+ ["contradictory parent report", {
+ agent_id: childThreadId,
+ agent_type: "verifier",
+ source: { subagent: { thread_spawn: { parent_thread_id: "foreign-parent" } } },
+ }, leaderThreadId],
+ ] as const) {
+ const result = await dispatchCodexNativeHook(
+ rootPayload("collaboration.send_message", { agent_id: targetAgentId, message: name }, overrides),
+ { cwd },
+ );
+ assert.equal(result.outputJson?.decision, "block", `${name}: ${JSON.stringify(result)}`);
+ }
+ } finally {
+ if (previousPath === undefined) delete process.env.PATH;
+ else process.env.PATH = previousPath;
+ }
+ });
+ });
+ } finally {
+ await rm(cwd, { recursive: true, force: true });
+ }
+ });
it("allows trusted omx state read with structured input under ultragoal conductor planning (#3343)", async () => {
const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-3343-state-read-"));
try {
@@ -32882,25 +33349,28 @@ PY`,
process.env.PATH = `${attackerDir}:${trustedPath}`;
try {
const payload = JSON.stringify({ mode: "ultragoal", session_id: sessionId, workingDirectory: cwd });
- const result = await dispatchCodexNativeHook(
- {
- hook_event_name: "PreToolUse",
- cwd,
- session_id: sessionId,
- thread_id: leaderThreadId,
- agent_id: leaderThreadId,
- tool_name: "Bash",
- tool_use_id: "tool-3343-untrusted-shim-state-read-input",
- tool_input: {
- command: `omx state read --input '${payload}' --json`,
+ for (const command of [
+ `omx state read --input '${payload}' --json`,
+ "omx state list-active --json",
+ ]) {
+ const result = await dispatchCodexNativeHook(
+ {
+ hook_event_name: "PreToolUse",
+ cwd,
+ session_id: sessionId,
+ thread_id: leaderThreadId,
+ agent_id: leaderThreadId,
+ tool_name: "Bash",
+ tool_use_id: "tool-3343-untrusted-shim-state-read-input",
+ tool_input: { command },
},
- },
- { cwd },
- );
+ { cwd },
+ );
- assert.notEqual(result.outputJson, null);
- assert.equal(result.outputJson?.decision, "block");
- assert.match(JSON.stringify(result.outputJson), /PATH/);
+ assert.notEqual(result.outputJson, null, command);
+ assert.equal(result.outputJson?.decision, "block", command);
+ assert.match(JSON.stringify(result.outputJson), /PATH/, command);
+ }
} finally {
if (inheritedPath === undefined) delete process.env.PATH;
else process.env.PATH = inheritedPath;
@@ -33684,6 +34154,144 @@ PY`,
}
});
+ it("allows only exact leader-owned Ultragoal metadata CLI commands", async () => withCleanAmbientNodeRuntimeEnvironment(async () => {
+ const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-ultragoal-leader-metadata-"));
+ const originalPath = process.env.PATH;
+ const originalOmxEnvironment = Object.fromEntries(
+ Object.entries(process.env).filter(([name]) => /^(?:OMX|GJC)_/.test(name)),
+ );
+ try {
+ for (const name of Object.keys(process.env)) {
+ if (/^(?:OMX|GJC)_/.test(name)) delete process.env[name];
+ }
+ const stateDir = join(cwd, ".omx", "state");
+ const sessionId = "sess-ultragoal-leader-metadata";
+ const leaderThreadId = "thread-ultragoal-leader-metadata";
+ await mkdir(join(stateDir, "sessions", sessionId), { recursive: true });
+ await writeCanonicalLeaderFixture(stateDir, sessionId, leaderThreadId, cwd);
+ await writeSessionSkillActiveState(stateDir, sessionId, "ultragoal", "planning");
+ await writeJson(join(stateDir, "sessions", sessionId, "ultragoal-state.json"), {
+ active: true,
+ mode: "ultragoal",
+ current_phase: "planning",
+ session_id: sessionId,
+ });
+ const trustedPackageBin = join(cwd, "node_modules", ".bin", "omx");
+ await mkdir(dirname(trustedPackageBin), { recursive: true });
+ await symlink(realpathSync(resolve(process.cwd(), "dist", "cli", "omx.js")), trustedPackageBin);
+ const lookalikeOmx = join(cwd, "lookalike", "bin", "omx");
+ await mkdir(dirname(lookalikeOmx), { recursive: true });
+ await writeFile(lookalikeOmx, "#!/bin/sh\nexit 0\n", "utf-8");
+ await chmod(lookalikeOmx, 0o755);
+ process.env.PATH = `${dirname(trustedPackageBin)}:${dirname(process.execPath)}:/usr/bin:/bin`;
+ process.env.OMX_ROOT = cwd;
+
+ const dispatchBash = (command: string, child = false) => dispatchCodexNativeHook({
+ hook_event_name: "PreToolUse",
+ cwd,
+ session_id: sessionId,
+ thread_id: child ? "thread-ultragoal-metadata-child" : leaderThreadId,
+ agent_id: child ? "thread-ultragoal-metadata-child" : leaderThreadId,
+ ...(child ? { agent_role: "executor" } : {}),
+ tool_name: "Bash",
+ tool_input: { command },
+ }, { cwd });
+
+ for (const command of [
+ "omx ultragoal create-goals --brief 'Ship the scoped change' --goal 'Implement::Make the change' --goal 'Verify::Run tests' --codex-goal-mode per-story --json",
+ `${trustedPackageBin} ultragoal create-goals --brief 'Ship the scoped change through the installed CLI' --json`,
+ "omx ultragoal create --brief='Ship the scoped change' --json",
+ "omx ultragoal complete-goals --retry-failed --json",
+ "omx ultragoal complete --json",
+ "omx ultragoal next",
+ "omx ultragoal start-next --retry-failed",
+ "omx ultragoal status --codex-goal-json .omx/ultragoal/codex-goal.json --json",
+ "omx ultragoal steer --kind annotate_ledger --evidence 'executor and verification completed' --rationale 'make completed chronology durable before review' --json",
+ "omx ultragoal steer --kind=annotate_ledger --target-goal-id G001-safe --evidence 'executor and verification completed' --rationale 'make completed chronology durable before review' --json",
+ 'omx ultragoal steer --kind annotate_ledger --evidence "planning activated; stdout UTF-8 JSON string was ?? prompt.txt followed by newline; exit code was 0" --rationale "make evidence durable before review" --json',
+ 'omx ultragoal steer --kind annotate_ledger --evidence "stdout UTF-8 JSON string \\"?? prompt.txt\\\\n\\" with exit code 0" --rationale "make evidence durable before review" --json',
+ "omx ultragoal checkpoint --goal-id G001-safe --status complete --evidence 'tests and reviews passed' --codex-goal-json .omx/ultragoal/codex-goal.json --quality-gate-json .omx/ultragoal/quality-gate.json --json",
+ "omx ultragoal checkpoint --goal-id G001-safe --status complete --evidence 'intermediate story verified while aggregate goal remains active' --codex-goal-json .omx/ultragoal/codex-goal-active.json --json",
+ "omx ultragoal checkpoint --goal-id G001-safe --status blocked --evidence 'matching native goal is blocked' --codex-goal-json .omx/ultragoal/codex-goal-blocked.json --json",
+ "omx ultragoal checkpoint --goal-id G001-safe --status failed --evidence 'executor command was blocked' --json",
+ ]) {
+ const result = await dispatchBash(command);
+ assert.equal(result.outputJson, null, command);
+ }
+
+ const originalShellopts = process.env.SHELLOPTS;
+ const originalBashopts = process.env.BASHOPTS;
+ delete process.env.SHELLOPTS;
+ delete process.env.BASHOPTS;
+ try {
+ const liveHookEnvironment = await dispatchBash(
+ `${trustedPackageBin} ultragoal create-goals --brief 'Live hook omits shell option exports' --json`,
+ );
+ assert.equal(liveHookEnvironment.outputJson, null);
+ } finally {
+ if (originalShellopts === undefined) delete process.env.SHELLOPTS;
+ else process.env.SHELLOPTS = originalShellopts;
+ if (originalBashopts === undefined) delete process.env.BASHOPTS;
+ else process.env.BASHOPTS = originalBashopts;
+ }
+
+ const child = await dispatchBash("omx ultragoal create-goals --brief 'Child must not create' --json", true);
+ assert.equal(child.outputJson?.decision, "block");
+ assert.match(String(child.outputJson?.reason ?? ""), /OWNER_CONFIRMATION_REQUIRED/);
+
+ for (const command of [
+ "omx ultragoal create-goals --brief 'Forced overwrite' --force --json",
+ "omx ultragoal create-goals --brief-file plan.md --json",
+ "omx ultragoal create-goals positional-brief --json",
+ "omx ultragoal create-goals --brief 'Unknown option' --unknown --json",
+ "omx ultragoal create-goals --brief legit --goal --force --json",
+ "omx ultragoal create-goals --brief --force --json",
+ "omx ultragoal create-goals --brief legit --codex-goal-mode --force --json",
+ "omx ultragoal create-goals --brief \"$(touch src/pwned.ts)\" --json",
+ "omx ultragoal create-goals --brief 'Chained' --json; touch src/pwned.ts",
+ "PATH=/usr/bin:/bin omx ultragoal create-goals --brief 'Prefixed' --json",
+ "./omx ultragoal create-goals --brief 'Impostor' --json",
+ `${lookalikeOmx} ultragoal create-goals --brief 'Absolute impostor' --json`,
+ "omx ultragoal complete-goals --force --json",
+ "omx ultragoal complete-goals --retry-failed=1 --json",
+ "omx ultragoal status --codex-goal-json --json",
+ "omx ultragoal status --codex-goal-json $(touch src/pwned.ts) --json",
+ "omx ultragoal steer --kind add_subgoal --evidence evidence --rationale rationale --json",
+ "omx ultragoal steer --kind annotate_ledger --evidence evidence --json",
+ "omx ultragoal steer --kind annotate_ledger --evidence \"$(touch src/pwned.ts)\" --rationale rationale --json",
+ "omx ultragoal steer --kind annotate_ledger --evidence ?? --rationale rationale --json",
+ "omx ultragoal steer --kind annotate_ledger --evidence evidence --rationale rationale --json; touch src/pwned.ts",
+ "omx ultragoal checkpoint --goal-id G001-unsafe --status complete --evidence incomplete --codex-goal-json .omx/ultragoal/codex-goal.json",
+ "omx ultragoal checkpoint --goal-id G001-unsafe --status blocked --evidence bad --codex-goal-json .omx/ultragoal/codex-goal.json --quality-gate-json .omx/ultragoal/quality-gate.json --json",
+ "omx ultragoal checkpoint --goal-id G001-unsafe --status failed --evidence bad --quality-gate-json .omx/ultragoal/quality-gate.json --json",
+ "omx ultragoal checkpoint --goal-id G001-unsafe --status unexpected --evidence bad --json",
+ ]) {
+ const result = await dispatchBash(command);
+ assert.equal(result.outputJson?.decision, "block", command);
+ assert.match(String(result.outputJson?.reason ?? ""), /Main-root Conductor mode is active/, command);
+ }
+
+ const rawWrite = await dispatchCodexNativeHook({
+ hook_event_name: "PreToolUse",
+ cwd,
+ session_id: sessionId,
+ thread_id: leaderThreadId,
+ agent_id: leaderThreadId,
+ tool_name: "Write",
+ tool_input: { file_path: "src/pwned.ts", content: "owned\n" },
+ }, { cwd });
+ assert.equal(rawWrite.outputJson?.decision, "block");
+ } finally {
+ for (const name of Object.keys(process.env)) {
+ if (/^(?:OMX|GJC)_/.test(name)) delete process.env[name];
+ }
+ Object.assign(process.env, originalOmxEnvironment);
+ if (originalPath === undefined) delete process.env.PATH;
+ else process.env.PATH = originalPath;
+ await rm(cwd, { recursive: true, force: true });
+ }
+ }));
+
it("allows the exact installed omx CLI by absolute path for Main-root read-only commands (#3333)", async () => {
const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-absolute-cli-readonly-"));
const installRoot = await mkdtemp(join(tmpdir(), "omx-native-hook-user-install-"));
@@ -33714,17 +34322,23 @@ PY`,
await mkdir(dirname(absoluteOmx), { recursive: true });
await symlink(realpathSync(resolve(process.cwd(), "dist", "cli", "omx.js")), absoluteOmx);
- const result = await dispatchCodexNativeHook({
- hook_event_name: "PreToolUse",
- cwd,
- session_id: sessionId,
- thread_id: leaderThreadId,
- agent_id: leaderThreadId,
- tool_name: "Bash",
- tool_input: { command: `${absoluteOmx} ultragoal status --json` },
- }, { cwd });
+ for (const command of [
+ `${absoluteOmx} ultragoal status --json`,
+ `${absoluteOmx} state read --input '${JSON.stringify({ mode: "ultragoal", session_id: sessionId, workingDirectory: cwd })}' --json`,
+ `${absoluteOmx} state list-active --json`,
+ ]) {
+ const result = await dispatchCodexNativeHook({
+ hook_event_name: "PreToolUse",
+ cwd,
+ session_id: sessionId,
+ thread_id: leaderThreadId,
+ agent_id: leaderThreadId,
+ tool_name: "Bash",
+ tool_input: { command },
+ }, { cwd });
- assert.equal(result.outputJson, null);
+ assert.equal(result.outputJson, null, command);
+ }
process.env.BASH_ENV = join(installRoot, "inherited-bash-env");
const checkpoint = await dispatchCodexNativeHook({
@@ -33744,16 +34358,22 @@ PY`,
await mkdir(dirname(lookalikeOmx), { recursive: true });
await writeFile(lookalikeOmx, "#!/usr/bin/env node\n", "utf-8");
await chmod(lookalikeOmx, 0o755);
- const lookalike = await dispatchCodexNativeHook({
- hook_event_name: "PreToolUse",
- cwd,
- session_id: sessionId,
- thread_id: leaderThreadId,
- agent_id: leaderThreadId,
- tool_name: "Bash",
- tool_input: { command: `${lookalikeOmx} ultragoal status --json` },
- }, { cwd });
- assert.equal(lookalike.outputJson?.decision, "block");
+ for (const command of [
+ `${lookalikeOmx} ultragoal status --json`,
+ `${lookalikeOmx} state read --json`,
+ `${lookalikeOmx} state list-active --json`,
+ ]) {
+ const lookalike = await dispatchCodexNativeHook({
+ hook_event_name: "PreToolUse",
+ cwd,
+ session_id: sessionId,
+ thread_id: leaderThreadId,
+ agent_id: leaderThreadId,
+ tool_name: "Bash",
+ tool_input: { command },
+ }, { cwd });
+ assert.equal(lookalike.outputJson?.decision, "block", command);
+ }
const nested = await dispatchCodexNativeHook({
hook_event_name: "PreToolUse",
@@ -33779,7 +34399,7 @@ PY`,
}
});
- it("allows finite Codex goal tools under Main-root Ultragoal checkpointing while near-misses stay unknown-denied (#3300)", async () => {
+ it("allows finite Codex goal reads but denies lifecycle mutation without documented Main-root proof (#3300)", async () => {
const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-3300-goal-tool-transport-"));
try {
const stateDir = join(cwd, ".omx", "state");
@@ -33825,6 +34445,12 @@ PY`,
["get_goal", {}],
["functions.get_goal", {}],
["functionsget_goal", {}],
+ ] as const) {
+ const result = await dispatch(tool_name, tool_input);
+ assert.equal(result.outputJson, null, tool_name);
+ }
+
+ for (const [tool_name, tool_input] of [
["create_goal", { objective: "complete the ultragoal plan" }],
["update_goal", { status: "complete" }],
["functions.create_goal", { objective: "complete the ultragoal plan" }],
@@ -33833,15 +34459,15 @@ PY`,
["functionsupdate_goal", { status: "complete" }],
] as const) {
const result = await dispatch(tool_name, tool_input);
- assert.equal(result.outputJson, null, tool_name);
+ assert.equal(result.outputJson?.decision, "block", tool_name);
+ assert.match(String(result.outputJson?.reason ?? ""), /OWNER_CONFIRMATION_REQUIRED|documented host-authenticated Main-root authority/, tool_name);
}
for (const tool_name of ["getgoal", "get_goals", "updateGoal", "createGoal", "functions.get_goals"]) {
const blocked = await dispatch(tool_name, {});
assert.equal(blocked.outputJson?.decision, "block", tool_name);
const reason = String(blocked.outputJson?.reason ?? "");
- assert.match(reason, /Main-root Conductor mode is active \(ultragoal phase: checkpointing\)/);
- assert.match(reason, /not a recognized read-only or explicitly authorized Conductor mutation transport/);
+ assert.match(reason, /OWNER_CONFIRMATION_REQUIRED|not a recognized read-only or explicitly authorized Conductor mutation transport/);
assert.match(reason, new RegExp(tool_name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")));
}
@@ -33861,25 +34487,30 @@ PY`,
}
});
- it("allows session-scoped omx cancel under active ultragoal conductor while impostors stay blocked", async () => {
+ it("hook-owns session-scoped omx cancel under active ultragoal conductor while impostors stay blocked", async () => {
const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-ultragoal-conductor-cancel-"));
try {
const stateDir = join(cwd, ".omx", "state");
const sessionId = "sess-ultragoal-conductor-cancel";
const leaderThreadId = "thread-ultragoal-conductor-cancel";
- await mkdir(join(stateDir, "sessions", sessionId), { recursive: true });
+ const sessionDir = join(stateDir, "sessions", sessionId);
+ const ultragoalPath = join(sessionDir, "ultragoal-state.json");
+ await mkdir(sessionDir, { recursive: true });
await writeJson(join(stateDir, "session.json"), {
session_id: sessionId,
native_session_id: leaderThreadId,
});
await writeJson(join(stateDir, "subagent-tracking.json"), { schemaVersion: 1, sessions: { [sessionId]: { session_id: sessionId, leader_thread_id: leaderThreadId, threads: { [leaderThreadId]: { thread_id: leaderThreadId, kind: "leader" } } } } });
- await writeSessionSkillActiveState(stateDir, sessionId, "ultragoal", "planning");
- await writeJson(join(stateDir, "sessions", sessionId, "ultragoal-state.json"), {
- active: true,
- mode: "ultragoal",
- current_phase: "planning",
- session_id: sessionId,
- });
+ const resetUltragoal = async () => {
+ await writeSessionSkillActiveState(stateDir, sessionId, "ultragoal", "planning");
+ await writeJson(ultragoalPath, {
+ active: true,
+ mode: "ultragoal",
+ current_phase: "planning",
+ session_id: sessionId,
+ });
+ };
+ await resetUltragoal();
const bash = (command: string) => dispatchCodexNativeHook({
hook_event_name: "PreToolUse",
@@ -33890,55 +34521,18 @@ PY`,
tool_name: "Bash",
tool_input: { command },
}, { cwd });
-
- const workspacePackageCli = realpathSync(resolve(process.cwd(), "dist", "cli", "omx.js"));
- const trustedPackageBin = join(cwd, "node_modules", ".bin", "omx");
- await mkdir(dirname(trustedPackageBin), { recursive: true });
- await symlink(workspacePackageCli, trustedPackageBin);
- const trustedPackagePath = `${dirname(trustedPackageBin)}:${dirname(process.execPath)}`;
- const bashTrusted = async (command: string) => {
- const inheritedPath = process.env.PATH;
- process.env.PATH = trustedPackagePath;
- try {
- return await bash(command);
- } finally {
- if (inheritedPath === undefined) delete process.env.PATH;
- else process.env.PATH = inheritedPath;
- }
+ const assertHandled = async (command: string, label: string) => {
+ await resetUltragoal();
+ const result = await bash(command);
+ assert.equal(result.outputJson?.decision, "block", label);
+ assert.match(JSON.stringify(result.outputJson), /cancelled_exact_session/, label);
+ assert.equal(JSON.parse(await readFile(ultragoalPath, "utf8")).active, false, label);
};
- const cleanPositives = await withCleanRunnerNodeEnvironment(async () => ({
- plain: await bashTrusted("omx cancel"),
- force: await bashTrusted("omx cancel --force"),
- }));
- assert.equal(cleanPositives.plain.outputJson, null);
- assert.equal(cleanPositives.force.outputJson, null);
- const inheritedCaPositives = await withCleanRunnerNodeEnvironment(async () => {
- process.env.NODE_EXTRA_CA_CERTS = "/nonexistent/enterprise-ca.pem";
- return {
- plain: await bashTrusted("omx cancel"),
- force: await bashTrusted("omx cancel --force"),
- };
+ await withCleanRunnerNodeEnvironment(async () => {
+ await assertHandled("omx cancel", "plain cancellation");
+ await assertHandled("omx cancel --force", "force cancellation");
});
- assert.equal(inheritedCaPositives.plain.outputJson, null);
- assert.equal(inheritedCaPositives.force.outputJson, null);
- assert.equal((await bash("omx cancel")).outputJson?.decision, "block",
- "ambient non-package omx resolution is not trusted");
-
- for (const [label, command] of [
- ["openssl config injection", "OPENSSL_CONF=/tmp/evil.cnf omx cancel"],
- ["path override", "PATH=/tmp/attacker omx cancel"],
- ["path-qualified impostor", "/tmp/omx cancel --force"],
- ["chained cancellation", "omx cancel --force && rm -rf x"],
- ["omx root override", "OMX_ROOT=/tmp/other omx cancel"],
- ["byte-order-mark lookalike executable", "\ufeffomx cancel"],
- ["carriage-return suffix lookalike", "omx cancel\r"],
- ["unicode nbsp separator", "omx\u00a0cancel"],
- ] as const) {
- const impostor = await bashTrusted(command);
- assert.equal(impostor.outputJson?.decision, "block", label);
- }
-
for (const [label, envName, envValue] of [
["inherited bash startup file", "BASH_ENV", "/tmp/prelude.sh"],
["imported omx function shadow", "BASH_FUNC_omx%%", "() { printf owned > src/pwned.ts; }"],
@@ -33949,35 +34543,32 @@ PY`,
] as const) {
const previousValue = process.env[envName];
process.env[envName] = envValue;
- const previousCa = process.env.NODE_EXTRA_CA_CERTS;
- process.env.NODE_EXTRA_CA_CERTS = "/nonexistent/enterprise-ca.pem";
try {
- const poisoned = await bashTrusted("omx cancel");
- assert.equal(poisoned.outputJson?.decision, "block", `${label} with inherited CA`);
+ await assertHandled("omx cancel --force", label);
} finally {
if (previousValue === undefined) delete process.env[envName];
else process.env[envName] = previousValue;
- if (previousCa === undefined) delete process.env.NODE_EXTRA_CA_CERTS;
- else process.env.NODE_EXTRA_CA_CERTS = previousCa;
}
}
- const shadowBinDir = join(cwd, "shadow-bin");
- await mkdir(shadowBinDir, { recursive: true });
- await writeFile(join(shadowBinDir, "omx"), "#!/bin/sh\ntouch src/path-shadow-owned.ts\n", "utf-8");
- await chmod(join(shadowBinDir, "omx"), 0o755);
- {
- const inheritedPath = process.env.PATH;
- process.env.PATH = `${shadowBinDir}:${trustedPackagePath}`;
- try {
- const shadowed = await bash("omx cancel");
- assert.equal(shadowed.outputJson?.decision, "block", "PATH-shadowed omx executable");
- } finally {
- if (inheritedPath === undefined) delete process.env.PATH;
- else process.env.PATH = inheritedPath;
- }
+ for (const [label, command] of [
+ ["openssl config injection", "OPENSSL_CONF=/tmp/evil.cnf omx cancel"],
+ ["path override", "PATH=/tmp/attacker omx cancel"],
+ ["path-qualified impostor", "/tmp/omx cancel --force"],
+ ["chained cancellation", "omx cancel --force && rm -rf x"],
+ ["omx root override", "OMX_ROOT=/tmp/other omx cancel"],
+ ["byte-order-mark lookalike executable", "\ufeffomx cancel"],
+ ["carriage-return suffix lookalike", "omx cancel\r"],
+ ["unicode nbsp separator", "omx\u00a0cancel"],
+ ] as const) {
+ await resetUltragoal();
+ const impostor = await bash(command);
+ assert.equal(impostor.outputJson?.decision, "block", label);
+ assert.doesNotMatch(JSON.stringify(impostor.outputJson), /cancelled_exact_session/, label);
+ assert.equal(JSON.parse(await readFile(ultragoalPath, "utf8")).active, true, label);
}
+ await resetUltragoal();
const stateClear = await bash("omx state clear --force --mode ultragoal --json");
assert.equal(stateClear.outputJson?.decision, "block");
} finally {
@@ -34391,7 +34982,7 @@ PY`,
assert.doesNotMatch(String(metadataBash.outputJson?.reason ?? ""), /Main-root/, command);
}
- const readOnlyBash = await dispatchCodexNativeHook(
+ const dispatchChildBash = (command: string) => dispatchCodexNativeHook(
{
hook_event_name: "PreToolUse",
cwd,
@@ -34399,11 +34990,38 @@ PY`,
thread_id: childThreadId,
agent_role: "executor",
tool_name: "Bash",
- tool_input: { command: "cat src/conductor-owned.ts" },
+ tool_input: { command },
},
{ cwd },
);
- assert.equal(readOnlyBash.outputJson, null);
+ const inheritedGitRuntime = Object.entries(process.env).filter(([name]) => (
+ name === "BASH_FUNC_git%%" || name === "PAGER" || name.startsWith("GIT_")
+ ));
+ for (const [name] of inheritedGitRuntime) delete process.env[name];
+ try {
+ for (const command of [
+ "cat src/conductor-owned.ts",
+ "/usr/bin/sed -n '1,28{=;p;}' .omx/ultragoal/goals.json",
+ "/usr/bin/find .omx -maxdepth 4 -type f -print",
+ "/usr/bin/find . -maxdepth 4 -type f -print",
+ "/usr/bin/git --no-pager diff --no-ext-diff --no-textconv -- .",
+ ]) {
+ assert.equal((await dispatchChildBash(command)).outputJson, null, command);
+ }
+ for (const command of [
+ "rg --files -uu .omx",
+ "rg -n -i 'goal|review' .omx/ultragoal",
+ "sed -i '' -e 's/a/b/' prompt.txt",
+ "/usr/bin/find .omx -type f -print",
+ "/usr/bin/find . -path ./.git -prune -o -path ./.omx -prune -o -type f -print",
+ "find .omx -type f -exec sh -c 'printf pwn > prompt.txt' \\;",
+ "/usr/bin/git --no-pager diff --no-ext-diff --no-textconv -- .; git reset --hard",
+ ]) {
+ assert.equal((await dispatchChildBash(command)).outputJson?.decision, "block", command);
+ }
+ } finally {
+ for (const [name, value] of inheritedGitRuntime) process.env[name] = value;
+ }
} finally {
if (originalOmxRoot === undefined) delete process.env.OMX_ROOT;
else process.env.OMX_ROOT = originalOmxRoot;
@@ -35294,7 +35912,7 @@ PY`,
);
assert.equal(result.outputJson?.decision, "block");
- assert.match(String(result.outputJson?.reason ?? ""), /Main-root Conductor mode is active \(ultragoal phase: executing\)/);
+ assert.match(String(result.outputJson?.reason ?? ""), /PROVENANCE_DENIED: Conductor mode is active \(ultragoal phase: executing\)/);
} finally {
if (originalOmxRoot === undefined) delete process.env.OMX_ROOT;
else process.env.OMX_ROOT = originalOmxRoot;
@@ -35627,7 +36245,7 @@ PY`,
);
assert.equal(result.outputJson?.decision, "block");
- assert.match(String(result.outputJson?.reason ?? ""), /Main-root Conductor mode is active \(ultragoal phase: executing\)/);
+ assert.match(String(result.outputJson?.reason ?? ""), /PROVENANCE_DENIED: Conductor mode is active \(ultragoal phase: executing\)/);
} finally {
if (originalOmxRoot === undefined) delete process.env.OMX_ROOT;
else process.env.OMX_ROOT = originalOmxRoot;
@@ -36057,7 +36675,7 @@ PY`,
assert.match(String(noProvenance.outputJson?.reason ?? ""), /OWNER_CONFIRMATION_REQUIRED/);
assert.doesNotMatch(String(noProvenance.outputJson?.reason ?? ""), /Main-root/);
- // (c) The positive leader anchor retains Main-root authority despite self-spawn provenance.
+ // (c) Self-spawn provenance conflicts with the leader claim and must fail closed.
const leaderSelfSpawn = await dispatchCodexNativeHook(
{
hook_event_name: "PreToolUse",
@@ -36076,7 +36694,7 @@ PY`,
{ cwd },
);
assert.equal(leaderSelfSpawn.outputJson?.decision, "block");
- assert.match(String(leaderSelfSpawn.outputJson?.reason ?? ""), /Main-root Conductor mode is active \(ralph phase: executing\)/);
+ assert.match(String(leaderSelfSpawn.outputJson?.reason ?? ""), /PROVENANCE_DENIED: Conductor mode is active \(ralph phase: executing\)/);
} finally {
await rm(cwd, { recursive: true, force: true });
}
diff --git a/src/scripts/__tests__/issue-3311-ultragoal-native-outside-tmux.test.ts b/src/scripts/__tests__/issue-3311-ultragoal-native-outside-tmux.test.ts
index bc832ed9a27fd0c032545a6d3b0b6bf728b5fcd7..d5d472a90fd5ef579228f0d9673ee37d316e2054 100644
--- a/src/scripts/__tests__/issue-3311-ultragoal-native-outside-tmux.test.ts
+++ b/src/scripts/__tests__/issue-3311-ultragoal-native-outside-tmux.test.ts
@@ -1,18 +1,32 @@
import assert from "node:assert/strict";
-import { existsSync, readFileSync } from "node:fs";
-import { mkdir, mkdtemp, rm, writeFile } from "node:fs/promises";
+import { existsSync, readFileSync, realpathSync } from "node:fs";
+import { appendFile, chmod, mkdir, mkdtemp, rm, symlink, writeFile } from "node:fs/promises";
import { tmpdir } from "node:os";
-import { dirname, join } from "node:path";
-import { afterEach, describe, it } from "node:test";
-import { dispatchCodexNativeHook } from "../codex-native-hook.js";
+import { dirname, join, resolve } from "node:path";
+import { afterEach, beforeEach, describe, it } from "node:test";
+import {
+ __isAuthorizedActiveUltragoalPhaseTransitionFallbackForTests,
+ buildConductorPreToolUseWriteGuardOutput,
+ dispatchCodexNativeHook,
+} from "../codex-native-hook.js";
+import {
+ beginNativeUltragoalBootstrap,
+ findReadyLocalNativeExecutorAssignment,
+ issueLocalNativeExecutorAssignment,
+ markNativeUltragoalBootstrapActive,
+ prepareNativeUltragoalBootstrapActivation,
+ readNativeUltragoalBootstrap,
+ revokeLocalNativeExecutorAssignment,
+ validateLocalNativeExecutorIdentity,
+} from "../../ultragoal/native-bootstrap.js";
// Regression coverage for OMX #3311: on native Codex App / native-hook
// surfaces outside tmux, standalone Ultragoal must not activate an
// execution-blocking Main-root Conductor state when no authorized executor
-// will ever be reachable (Team is tmux-only; native child/descendant
-// provenance intentionally grants no write authority per #3127). The guard
-// under test refuses the *activation* write itself; it must never affect
-// already-active sessions, non-ultragoal modes, non-native launchers, or
+// will ever be reachable. Team is tmux-only; native child/descendant provenance
+// grants no write authority unless the root issues an exact scoped assignment.
+// The guard under test refuses the *activation* write itself; it must never
+// affect already-active sessions, non-ultragoal modes, non-native launchers, or
// attached-tmux transport.
async function writeJson(path: string, value: unknown): Promise<void> {
@@ -35,7 +49,10 @@ async function writeLeaderSessionFixture(
await writeJson(join(stateDir, "session.json"), {
session_id: sessionId,
native_session_id: leaderThreadId,
+ owner_codex_session_id: sessionId,
+ target_session_id: sessionId,
cwd,
+ state_root: stateDir,
});
await writeJson(join(stateDir, "subagent-tracking.json"), {
schemaVersion: 1,
@@ -43,20 +60,89 @@ async function writeLeaderSessionFixture(
[sessionId]: {
session_id: sessionId,
leader_thread_id: leaderThreadId,
+ updated_at: "2026-07-29T16:54:54.000Z",
threads: {
- [leaderThreadId]: { thread_id: leaderThreadId, kind: "leader" },
+ [leaderThreadId]: {
+ thread_id: leaderThreadId,
+ kind: "leader",
+ first_seen_at: "2026-07-29T16:54:54.000Z",
+ last_seen_at: "2026-07-29T16:54:54.000Z",
+ turn_count: 1,
+ },
},
},
},
});
}
+function rootTranscriptRecord(
+ sessionId: string,
+ cwd: string,
+ turnId: string,
+ overrides: Record<string, unknown> = {},
+ turnOverrides: Record<string, unknown> = {},
+): string {
+ return `${JSON.stringify({
+ type: "session_meta",
+ payload: {
+ id: sessionId,
+ cwd,
+ thread_source: "user",
+ source: "vscode",
+ originator: "Codex Desktop",
+ dynamic_tools: [
+ { name: "codex_app" },
+ { name: "plugin_management" },
+ ],
+ ...overrides,
+ },
+ })}\n${JSON.stringify({
+ type: "turn_context",
+ payload: {
+ turn_id: turnId,
+ cwd,
+ collaboration_mode: { mode: "default", settings: { model: "gpt-5.6-sol" } },
+ multi_agent_mode: "explicitRequestOnly",
+ multi_agent_version: "v2",
+ ...turnOverrides,
+ },
+ })}\n`;
+}
+
+async function writeRootTranscript(codexHome: string, sessionId: string, content: string): Promise<string> {
+ const path = join(codexHome, "sessions", "2026", "07", "29", `rollout-2026-07-29T20-00-00-${sessionId}.jsonl`);
+ await mkdir(dirname(path), { recursive: true });
+ await writeFile(path, content);
+ return path;
+}
+
describe("issue-3311: standalone Ultragoal native-App outside-tmux activation guard", () => {
const originalTmux = process.env.TMUX;
+ const originalAssignmentOptIn = process.env.OMX_NATIVE_SUBAGENT_ASSIGNMENTS;
+ const originalCodexHome = process.env.CODEX_HOME;
+ const originalBackend = process.env.OMX_NATIVE_ULTRAGOAL_BACKEND;
+ const originalCodexThreadId = process.env.CODEX_THREAD_ID;
+ const originalOmxSessionId = process.env.OMX_SESSION_ID;
+
+ beforeEach(() => {
+ process.env.OMX_NATIVE_ULTRAGOAL_BACKEND = "off";
+ delete process.env.CODEX_THREAD_ID;
+ delete process.env.OMX_SESSION_ID;
+ });
afterEach(() => {
if (originalTmux === undefined) delete process.env.TMUX;
else process.env.TMUX = originalTmux;
+ if (originalAssignmentOptIn === undefined) delete process.env.OMX_NATIVE_SUBAGENT_ASSIGNMENTS;
+ else process.env.OMX_NATIVE_SUBAGENT_ASSIGNMENTS = originalAssignmentOptIn;
+ if (originalCodexHome === undefined) delete process.env.CODEX_HOME;
+ else process.env.CODEX_HOME = originalCodexHome;
+ if (originalBackend === undefined) delete process.env.OMX_NATIVE_ULTRAGOAL_BACKEND;
+ else process.env.OMX_NATIVE_ULTRAGOAL_BACKEND = originalBackend;
+ if (originalCodexThreadId === undefined) delete process.env.CODEX_THREAD_ID;
+ else process.env.CODEX_THREAD_ID = originalCodexThreadId;
+ if (originalOmxSessionId === undefined) delete process.env.OMX_SESSION_ID;
+ else process.env.OMX_SESSION_ID = originalOmxSessionId;
});
it("blocks fresh standalone-ultragoal Conductor activation on native App outside tmux (Bash state write)", async () => {
@@ -88,8 +174,73 @@ describe("issue-3311: standalone Ultragoal native-App outside-tmux activation gu
(result.outputJson as { hookSpecificOutput?: { additionalContext?: string } } | null)
?.hookSpecificOutput?.additionalContext || "",
);
- assert.match(context, /native child\/descendant provenance does not grant write authority/);
- assert.doesNotMatch(context, /write-assignment|assignment-backed|scoped native .*grant/i);
+ assert.match(context, /typed native spawn surface backed by scoped write assignments/);
+ } finally {
+ await rm(cwd, { recursive: true, force: true });
+ }
+ });
+
+ it("keeps fresh activation inactive until the advertised executor is authorized", async () => {
+ delete process.env.TMUX;
+ process.env.OMX_NATIVE_SUBAGENT_ASSIGNMENTS = "on";
+ process.env.OMX_NATIVE_ULTRAGOAL_BACKEND = "local-experimental";
+ const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-3319-supported-bash-"));
+ try {
+ const stateDir = join(cwd, ".omx", "state");
+ const sessionId = "sess-3319-supported-bash";
+ const leaderThreadId = "thread-3319-supported-bash";
+ await writeLeaderSessionFixture(stateDir, sessionId, leaderThreadId, cwd);
+
+ const result = await dispatchCodexNativeHook(
+ {
+ hook_event_name: "PreToolUse",
+ cwd,
+ session_id: sessionId,
+ thread_id: leaderThreadId,
+ agent_id: leaderThreadId,
+ source: "native",
+ available_tools: ["collaboration.spawn_agent"],
+ tool_name: "Bash",
+ tool_input: { command: `omx state write --input '${ACTIVATION_INPUT}' --json` },
+ },
+ { cwd },
+ );
+
+ assert.equal(result.outputJson?.decision, "block");
+ assert.match(String(result.outputJson?.reason ?? ""), /OMX-ULTRAGOAL-BOOTSTRAP-REQUIRED/);
+ } finally {
+ await rm(cwd, { recursive: true, force: true });
+ }
+ });
+
+ it("keeps fresh activation blocked when native subagents are advertised without typed role routing", async () => {
+ delete process.env.TMUX;
+ process.env.OMX_NATIVE_SUBAGENT_ASSIGNMENTS = "on";
+ process.env.OMX_NATIVE_ULTRAGOAL_BACKEND = "local-experimental";
+ const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-3319-untyped-bash-"));
+ try {
+ const stateDir = join(cwd, ".omx", "state");
+ const sessionId = "sess-3319-untyped-bash";
+ const leaderThreadId = "thread-3319-untyped-bash";
+ await writeLeaderSessionFixture(stateDir, sessionId, leaderThreadId, cwd);
+
+ const result = await dispatchCodexNativeHook(
+ {
+ hook_event_name: "PreToolUse",
+ cwd,
+ session_id: sessionId,
+ thread_id: leaderThreadId,
+ agent_id: leaderThreadId,
+ source: "native",
+ capabilities: { native_subagents: true },
+ tool_name: "Bash",
+ tool_input: { command: `omx state write --input '${ACTIVATION_INPUT}' --json` },
+ },
+ { cwd },
+ );
+
+ assert.equal(result.outputJson?.decision, "block");
+ assert.match(String(result.outputJson?.reason ?? ""), /OMX-ULTRAGOAL-(?:NO-OWNER|BOOTSTRAP-REQUIRED)/);
} finally {
await rm(cwd, { recursive: true, force: true });
}
@@ -124,8 +275,7 @@ describe("issue-3311: standalone Ultragoal native-App outside-tmux activation gu
(result.outputJson as { hookSpecificOutput?: { additionalContext?: string } } | null)
?.hookSpecificOutput?.additionalContext || "",
);
- assert.match(context, /native child\/descendant provenance does not grant write authority/);
- assert.doesNotMatch(context, /write-assignment|assignment-backed|scoped native .*grant/i);
+ assert.match(context, /typed native spawn surface backed by scoped write assignments/);
} finally {
await rm(cwd, { recursive: true, force: true });
}
@@ -163,8 +313,7 @@ describe("issue-3311: standalone Ultragoal native-App outside-tmux activation gu
(result.outputJson as { hookSpecificOutput?: { additionalContext?: string } } | null)
?.hookSpecificOutput?.additionalContext || "",
);
- assert.match(context, /native child\/descendant provenance does not grant write authority/);
- assert.doesNotMatch(context, /write-assignment|assignment-backed|scoped native .*grant/i);
+ assert.match(context, /typed native spawn surface backed by scoped write assignments/);
} finally {
await rm(cwd, { recursive: true, force: true });
}
@@ -336,6 +485,130 @@ describe("issue-3311: standalone Ultragoal native-App outside-tmux activation gu
}
});
+ it("does not let a tracked native child authorize its own bootstrap assignment", async () => {
+ delete process.env.TMUX;
+ const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-bootstrap-self-auth-"));
+ try {
+ const stateDir = join(cwd, ".omx", "state");
+ const sessionId = "sess-bootstrap-self-auth";
+ const leaderThreadId = "thread-bootstrap-self-auth-root";
+ const childThreadId = "thread-bootstrap-self-auth-child";
+ await writeLeaderSessionFixture(stateDir, sessionId, leaderThreadId, cwd);
+ await writeJson(join(stateDir, "subagent-tracking.json"), {
+ schemaVersion: 1,
+ sessions: {
+ [sessionId]: {
+ session_id: sessionId,
+ leader_thread_id: leaderThreadId,
+ threads: {
+ [leaderThreadId]: { thread_id: leaderThreadId, kind: "leader" },
+ [childThreadId]: {
+ thread_id: childThreadId,
+ kind: "subagent",
+ mode: "executor",
+ status: "available",
+ provenance_kind: "native_subagent",
+ direct_child_parent_id: leaderThreadId,
+ direct_child_root_id: leaderThreadId,
+ },
+ },
+ },
+ },
+ });
+
+ const result = await dispatchCodexNativeHook(
+ {
+ hook_event_name: "PreToolUse",
+ cwd,
+ session_id: sessionId,
+ thread_id: childThreadId,
+ agent_id: childThreadId,
+ agent_type: "executor",
+ source: "native",
+ tool_name: "Bash",
+ tool_input: {
+ command: `omx ultragoal native-bootstrap authorize --session-id ${sessionId} --root-thread-id ${leaderThreadId} --child-id ${childThreadId} --path-prefix src`,
+ },
+ },
+ { cwd },
+ );
+
+ assert.equal(result.outputJson?.decision, "block");
+ assert.match(String(result.outputJson?.reason ?? ""), /OWNER_CONFIRMATION_REQUIRED/);
+ assert.match(String(result.outputJson?.reason ?? ""), /root-owned/);
+ } finally {
+ await rm(cwd, { recursive: true, force: true });
+ }
+ });
+
+ it("keeps the spawned executor read-only while the bootstrap is awaiting authorization", async () => {
+ delete process.env.TMUX;
+ process.env.OMX_NATIVE_SUBAGENT_ASSIGNMENTS = "on";
+ process.env.OMX_NATIVE_ULTRAGOAL_BACKEND = "local-experimental";
+ const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-bootstrap-pending-child-"));
+ try {
+ const stateDir = join(cwd, ".omx", "state");
+ const sessionId = "sess-bootstrap-pending-child";
+ const leaderThreadId = "thread-bootstrap-pending-root";
+ const childThreadId = "thread-bootstrap-pending-child";
+ await writeLeaderSessionFixture(stateDir, sessionId, leaderThreadId, cwd);
+ await dispatchCodexNativeHook(
+ {
+ hook_event_name: "UserPromptSubmit",
+ cwd,
+ session_id: sessionId,
+ thread_id: leaderThreadId,
+ source: "native",
+ available_tools: ["collaboration.spawn_agent"],
+ prompt: "$ultragoal execute this plan",
+ },
+ { cwd },
+ );
+ await writeJson(join(stateDir, "subagent-tracking.json"), {
+ schemaVersion: 1,
+ sessions: {
+ [sessionId]: {
+ session_id: sessionId,
+ leader_thread_id: leaderThreadId,
+ threads: {
+ [leaderThreadId]: { thread_id: leaderThreadId, kind: "leader" },
+ [childThreadId]: {
+ thread_id: childThreadId,
+ kind: "subagent",
+ mode: "executor",
+ status: "available",
+ provenance_kind: "native_subagent",
+ direct_child_parent_id: leaderThreadId,
+ direct_child_root_id: leaderThreadId,
+ },
+ },
+ },
+ },
+ });
+
+ const result = await dispatchCodexNativeHook(
+ {
+ hook_event_name: "PreToolUse",
+ cwd,
+ session_id: sessionId,
+ thread_id: childThreadId,
+ agent_id: childThreadId,
+ agent_type: "executor",
+ source: "native",
+ tool_name: "Write",
+ tool_input: { file_path: join(cwd, "src", "pending-write.ts"), content: "blocked" },
+ },
+ { cwd },
+ );
+
+ assert.equal(result.outputJson?.decision, "block");
+ assert.match(String(result.outputJson?.reason ?? ""), /bootstrap is not active/);
+ assert.match(String(result.outputJson?.reason ?? ""), /remain read-only/);
+ } finally {
+ await rm(cwd, { recursive: true, force: true });
+ }
+ });
+
it("does not block autopilot-supervised ultragoal activation (mode is autopilot, not standalone ultragoal)", async () => {
delete process.env.TMUX;
const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-3311-autopilot-"));
@@ -427,163 +700,2504 @@ describe("issue-3311: standalone Ultragoal native-App outside-tmux activation gu
}
});
- it("allows the primary '$ultragoal' UserPromptSubmit activation when attached to tmux (Team is reachable)", async () => {
- process.env.TMUX = "/tmp/tmux-3311-prompt,12345,0";
- const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-3311-prompt-tmux-"));
+ it("keeps '$ultragoal' prompt activation inactive until the advertised executor is authorized", async () => {
+ delete process.env.TMUX;
+ process.env.OMX_NATIVE_SUBAGENT_ASSIGNMENTS = "on";
+ process.env.OMX_NATIVE_ULTRAGOAL_BACKEND = "local-experimental";
+ const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-3319-supported-prompt-"));
try {
await mkdir(join(cwd, ".omx", "state"), { recursive: true });
-
const result = await dispatchCodexNativeHook(
{
hook_event_name: "UserPromptSubmit",
cwd,
- session_id: "sess-3311-prompt-tmux",
- thread_id: "thread-3311-prompt-tmux",
- turn_id: "turn-3311-prompt-tmux",
+ session_id: "sess-3319-supported-prompt",
+ thread_id: "thread-3319-supported-prompt",
+ turn_id: "turn-3319-supported-prompt",
source: "native",
+ available_tools: ["collaboration.spawn_agent"],
prompt: "$ultragoal split this launch into durable goals",
},
{ cwd },
);
- assert.equal(result.skillState?.skill, "ultragoal");
- assert.equal(result.skillState?.initialized_mode, "ultragoal");
- assert.equal(result.skillState?.transition_error, undefined);
+ assert.notEqual(result.skillState?.initialized_mode, "ultragoal");
+ assert.match(String(result.skillState?.transition_error ?? result.outputJson?.reason ?? ""), /BOOTSTRAP|inactive|authorization/i);
assert.equal(
- existsSync(join(cwd, ".omx", "state", "sessions", "sess-3311-prompt-tmux", "ultragoal-state.json")),
- true,
+ existsSync(join(cwd, ".omx", "state", "sessions", "sess-3319-supported-prompt", "ultragoal-state.json")),
+ false,
);
} finally {
await rm(cwd, { recursive: true, force: true });
}
});
- it("does not re-block continuation of an already-active '$ultragoal' UserPromptSubmit session outside tmux", async () => {
+ it("recognizes the Codex CLI v2 multi-agent marker when mode and tool inventory are omitted", async () => {
delete process.env.TMUX;
- const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-3311-prompt-continue-"));
+ process.env.OMX_NATIVE_SUBAGENT_ASSIGNMENTS = "on";
+ process.env.OMX_NATIVE_ULTRAGOAL_BACKEND = "local-experimental";
+ const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-app-v2-prompt-"));
try {
const stateDir = join(cwd, ".omx", "state");
- const sessionId = "sess-3311-prompt-continue";
- const leaderThreadId = "thread-3311-prompt-continue";
- await writeLeaderSessionFixture(stateDir, sessionId, leaderThreadId, cwd);
- await writeJson(join(stateDir, "sessions", sessionId, "skill-active-state.json"), {
- active: true,
- skill: "ultragoal",
- phase: "planning",
- session_id: sessionId,
- active_skills: [{ skill: "ultragoal", phase: "planning", active: true, session_id: sessionId }],
- });
- await writeJson(join(stateDir, "sessions", sessionId, "ultragoal-state.json"), {
- active: true,
- mode: "ultragoal",
- current_phase: "planning",
- session_id: sessionId,
- });
+ const sessionId = "sess-app-v2-prompt";
+ const rootThreadId = "thread-app-v2-root";
+ await writeLeaderSessionFixture(stateDir, sessionId, rootThreadId, cwd);
const result = await dispatchCodexNativeHook(
{
hook_event_name: "UserPromptSubmit",
cwd,
session_id: sessionId,
- thread_id: leaderThreadId,
- turn_id: "turn-3311-prompt-continue",
+ thread_id: rootThreadId,
source: "native",
- prompt: "$ultragoal continue with the next milestone",
+ multi_agent_version: "v2",
+ prompt: "$ultragoal execute the durable plan",
},
{ cwd },
);
- assert.doesNotMatch(String(result.skillState?.transition_error ?? ""), /OMX-ULTRAGOAL-NO-OWNER/);
+ assert.equal(result.skillState?.active, false);
+ assert.match(String(result.skillState?.transition_error ?? ""), /OMX-ULTRAGOAL-BOOTSTRAP-REQUIRED/);
+ const bootstrap = await readNativeUltragoalBootstrap(stateDir, sessionId);
+ assert.equal(bootstrap?.status, "awaiting-executor");
+ assert.equal(bootstrap?.root_thread_id, rootThreadId);
} finally {
await rm(cwd, { recursive: true, force: true });
}
});
- it("does not block the primary '$ultragoal' UserPromptSubmit activation from a non-native (CLI) launcher outside tmux", async () => {
+ it("keeps missing, older, conflicting, and explicitly unsupported multi-agent claims fail closed", async () => {
delete process.env.TMUX;
- const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-3311-prompt-cli-"));
- try {
- await mkdir(join(cwd, ".omx", "state"), { recursive: true });
-
- const result = await dispatchCodexNativeHook(
- {
+ process.env.OMX_NATIVE_SUBAGENT_ASSIGNMENTS = "on";
+ process.env.OMX_NATIVE_ULTRAGOAL_BACKEND = "local-experimental";
+ for (const [name, marker] of [
+ ["missing-version", {}],
+ ["older-version", { multi_agent_version: "v1" }],
+ ["malformed-version", { multi_agent_version: 2 }],
+ ["unsupported-mode", { multi_agent_version: "v2", multi_agent_mode: "automatic" }],
+ ["malformed-mode", { multi_agent_version: "v2", multi_agent_mode: true }],
+ ["conflicting-version", { multi_agent_version: "v2", multiAgentVersion: "v1" }],
+ ["conflicting-mode", {
+ multi_agent_version: "v2",
+ multi_agent_mode: "explicitRequestOnly",
+ multiAgentMode: "automatic",
+ }],
+ ] as const) {
+ const cwd = await mkdtemp(join(tmpdir(), `omx-native-hook-app-marker-${name}-`));
+ try {
+ const stateDir = join(cwd, ".omx", "state");
+ const sessionId = `sess-app-marker-${name}`;
+ await writeLeaderSessionFixture(stateDir, sessionId, sessionId, cwd);
+ const result = await dispatchCodexNativeHook({
hook_event_name: "UserPromptSubmit",
cwd,
- session_id: "sess-3311-prompt-cli",
- thread_id: "thread-3311-prompt-cli",
- turn_id: "turn-3311-prompt-cli",
- source: "cli",
- prompt: "$ultragoal split this launch into durable goals",
- },
- { cwd },
- );
+ session_id: sessionId,
+ thread_id: sessionId,
+ source: "native",
+ ...marker,
+ prompt: "$ultragoal execute the durable plan",
+ }, { cwd });
- assert.equal(result.skillState?.initialized_mode, "ultragoal");
- assert.equal(result.skillState?.transition_error, undefined);
- } finally {
- await rm(cwd, { recursive: true, force: true });
+ assert.doesNotMatch(String(result.skillState?.transition_error ?? ""), /OMX-ULTRAGOAL-BOOTSTRAP-REQUIRED/, name);
+ assert.equal(await readNativeUltragoalBootstrap(stateDir, sessionId), null, name);
+ } finally {
+ await rm(cwd, { recursive: true, force: true });
+ }
}
});
- // --- Autopilot-supervised child recognition must not be intercepted ---
- // #3311 repair-2: the prompt guard must refuse only a truly *standalone*
- // fresh Ultragoal activation. When Autopilot is already active and
- // supervising a child phase (e.g. ralplan), a "$ultragoal" prompt is a
- // supervised-child transition handled entirely by recordSkillActivation's
- // own isAutopilotSupervisedChildSkill branch; it must remain reachable on
- // native App outside tmux exactly as it was on the pre-#3311-fix baseline.
-
- it("does not intercept Autopilot-supervised '$ultragoal' child-phase recognition on native App outside tmux", async () => {
+ it("uses an exact safe root transcript despite a competing live workspace pointer", async () => {
delete process.env.TMUX;
- const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-3311-autopilot-supervised-"));
+ process.env.OMX_NATIVE_SUBAGENT_ASSIGNMENTS = "on";
+ process.env.OMX_NATIVE_ULTRAGOAL_BACKEND = "local-experimental";
+ const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-root-transcript-pointer-"));
try {
const stateDir = join(cwd, ".omx", "state");
- const sessionId = "sess-3311-autopilot-supervised";
- const threadId = "thread-3311-autopilot-supervised";
- await mkdir(join(stateDir, "sessions", sessionId), { recursive: true });
+ const sessionId = "019faf7e-1001-7000-8000-000000000001";
+ const turnId = "019f-root-transcript-turn";
+ const foreignSessionId = "019faf7e-1002-7000-8000-000000000002";
+ process.env.CODEX_HOME = join(cwd, "codex-home");
+ await writeJson(join(stateDir, "session.json"), {
+ session_id: foreignSessionId,
+ native_session_id: foreignSessionId,
+ cwd,
+ pid: process.pid,
+ });
+ await writeJson(join(stateDir, "sessions", foreignSessionId, "skill-active-state.json"), {
+ version: 1,
+ active: false,
+ skill: "ultragoal",
+ phase: "complete",
+ session_id: foreignSessionId,
+ active_skills: [],
+ transition_error: "foreign terminal marker",
+ });
+ await writeRootTranscript(
+ process.env.CODEX_HOME,
+ sessionId,
+ rootTranscriptRecord(
+ sessionId,
+ cwd,
+ turnId,
+ { source: "exec", cli_version: "0.146.0", session_id: sessionId },
+ { multi_agent_mode: undefined },
+ ),
+ );
+
+ const prompt = await dispatchCodexNativeHook({
+ hook_event_name: "UserPromptSubmit",
+ cwd,
+ session_id: sessionId,
+ turn_id: turnId,
+ source: "native",
+ prompt: "$ultragoal execute the durable plan",
+ }, { cwd });
+
+
+ assert.equal(prompt.skillState?.active, false);
+ assert.match(String(prompt.skillState?.transition_error ?? ""), /OMX-ULTRAGOAL-BOOTSTRAP-REQUIRED/);
+ assert.doesNotMatch(JSON.stringify(prompt), /foreign terminal marker/);
+ const bootstrap = await readNativeUltragoalBootstrap(stateDir, sessionId);
+ assert.equal(bootstrap?.root_thread_id, sessionId);
+ assert.equal(bootstrap?.status, "awaiting-executor");
+
+ const bootstrapStatus = await dispatchCodexNativeHook({
+ hook_event_name: "PreToolUse",
+ cwd,
+ session_id: sessionId,
+ turn_id: turnId,
+ tool_name: "Bash",
+ tool_input: { command: "omx ultragoal native-bootstrap status --json" },
+ }, { cwd });
+ assert.equal(bootstrapStatus.outputJson, null);
+
await writeJson(join(stateDir, "sessions", sessionId, "skill-active-state.json"), {
+ version: 1,
active: true,
- skill: "autopilot",
- phase: "ralplan",
+ skill: "ultragoal",
+ phase: "executing",
session_id: sessionId,
- active_skills: [{ skill: "autopilot", phase: "ralplan", active: true, session_id: sessionId }],
+ thread_id: sessionId,
+ active_skills: [{ skill: "ultragoal", active: true, phase: "executing", session_id: sessionId }],
});
- await writeJson(join(stateDir, "sessions", sessionId, "autopilot-state.json"), {
+ await writeJson(join(stateDir, "sessions", sessionId, "ultragoal-state.json"), {
active: true,
- mode: "autopilot",
- current_phase: "ralplan",
+ mode: "ultragoal",
+ current_phase: "executing",
session_id: sessionId,
- state: {
- handoff_artifacts: {
- ralplan_consensus_gate: { required: true, complete: false },
- },
- },
});
+ const write = await dispatchCodexNativeHook({
+ hook_event_name: "PreToolUse",
+ cwd,
+ session_id: sessionId,
+ turn_id: turnId,
+ tool_name: "Edit",
+ tool_input: { file_path: "src/root-write.ts" },
+ }, { cwd });
+ assert.equal(write.outputJson?.decision, "block");
+ assert.match(String(write.outputJson?.reason ?? ""), /Main-root Conductor mode is active/);
+ for (const [name, identityClaim] of [
+ ["agent-id", { agent_id: "claimed-agent" }],
+ ["agent-id-camel", { agentId: "claimed-agent" }],
+ ["owner", { owner_codex_thread_id: sessionId }],
+ ["agent-role", { agent_role: "executor" }],
+ ["agent-role-camel", { agentRole: "executor" }],
+ ["agent-type", { agent_type: "executor" }],
+ ["agent-type-camel", { agentType: "executor" }],
+ ["thread-number", { thread_id: 42 }],
+ ["thread-empty", { thread_id: "" }],
+ ["thread-null", { thread_id: null }],
+ ] as const) {
+ const claimed = await dispatchCodexNativeHook({
+ hook_event_name: "PreToolUse",
+ cwd,
+ session_id: sessionId,
+ thread_id: sessionId,
+ turn_id: turnId,
+ tool_name: "Edit",
+ tool_input: { file_path: "src/claimed-root-write.ts" },
+ ...identityClaim,
+ }, { cwd });
+ assert.equal(claimed.outputJson?.decision, "block", name);
+ assert.doesNotMatch(String(claimed.outputJson?.reason ?? ""), /Main-root Conductor mode is active/, name);
+ }
+ } finally {
+ await rm(cwd, { recursive: true, force: true });
+ }
+ });
- const result = await dispatchCodexNativeHook(
- {
+ it("accepts Codex Desktop exec root transcripts and rejects unknown source or originator", async () => {
+ delete process.env.TMUX;
+ process.env.OMX_NATIVE_SUBAGENT_ASSIGNMENTS = "on";
+ process.env.OMX_NATIVE_ULTRAGOAL_BACKEND = "local-experimental";
+ const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-root-exec-source-"));
+ try {
+ process.env.CODEX_HOME = join(cwd, "codex-home");
+ const stateDir = join(cwd, ".omx", "state");
+ await writeJson(join(stateDir, "session.json"), {
+ session_id: "019faf7e-1007-7000-8000-000000000007",
+ native_session_id: "019faf7e-1007-7000-8000-000000000007",
+ cwd,
+ pid: process.pid,
+ });
+ for (const [name, sessionId, transcriptOverrides, accepted] of [
+ ["exec", "019faf7e-1003-7000-8000-000000000003", { source: "exec" }, true],
+ ["unknown", "019faf7e-1004-7000-8000-000000000004", { source: "unknown" }, false],
+ ["wrong-originator", "019faf7e-1005-7000-8000-000000000005", { source: "exec", originator: "Other Client" }, false],
+ ] as const) {
+ const turnId = `019f-root-source-${name}-turn`;
+ await writeRootTranscript(process.env.CODEX_HOME, sessionId, rootTranscriptRecord(
+ sessionId,
+ cwd,
+ turnId,
+ transcriptOverrides,
+ ));
+ const result = await dispatchCodexNativeHook({
hook_event_name: "UserPromptSubmit",
cwd,
session_id: sessionId,
- thread_id: threadId,
- turn_id: "turn-3311-autopilot-supervised",
+ turn_id: turnId,
source: "native",
- prompt: "$ultragoal turn the approved plan into durable goals",
- },
- { cwd },
- );
+ prompt: "$ultragoal execute",
+ }, { cwd });
+ if (accepted) {
+ assert.match(String(result.skillState?.transition_error ?? ""), /OMX-ULTRAGOAL-BOOTSTRAP-REQUIRED/, name);
+ assert.equal((await readNativeUltragoalBootstrap(stateDir, sessionId))?.root_thread_id, sessionId, name);
+ } else {
+ assert.doesNotMatch(String(result.skillState?.transition_error ?? ""), /OMX-ULTRAGOAL-BOOTSTRAP-REQUIRED/, name);
+ assert.equal(await readNativeUltragoalBootstrap(stateDir, sessionId), null, name);
+ }
+ }
+ } finally {
+ await rm(cwd, { recursive: true, force: true });
+ }
+ });
- assert.equal(result.omxEventName, "keyword-detector");
- assert.equal(result.skillState?.active, true);
- assert.equal(result.skillState?.skill, "autopilot");
- assert.equal(result.skillState?.supervised_child_skill, "ultragoal");
- assert.equal(result.skillState?.transition_error, undefined);
- assert.doesNotMatch(String(result.skillState?.transition_error ?? ""), /OMX-ULTRAGOAL-NO-OWNER/);
- const message = String(
- (result.outputJson as { hookSpecificOutput?: { additionalContext?: string } } | null)
- ?.hookSpecificOutput?.additionalContext || "",
- );
- assert.doesNotMatch(message, /OMX-ULTRAGOAL-NO-OWNER/);
+ it("rejects child, spoofed, ambiguous, and archived root transcript fallbacks", async () => {
+ delete process.env.TMUX;
+ process.env.OMX_NATIVE_SUBAGENT_ASSIGNMENTS = "on";
+ process.env.OMX_NATIVE_ULTRAGOAL_BACKEND = "local-experimental";
+ const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-root-transcript-reject-"));
+ try {
+ process.env.CODEX_HOME = join(cwd, "codex-home");
+ const cases = [
+ ["child", { source: { subagent: { thread_spawn: { parent_thread_id: "parent" } } } }],
+ ["spoof", { cwd: join(cwd, "foreign") }],
+ ] as const;
+ for (const [name, overrides] of cases) {
+ const sessionId = `019f-root-${name}`;
+ const turnId = `019f-root-${name}-turn`;
+ await writeRootTranscript(process.env.CODEX_HOME, sessionId, rootTranscriptRecord(sessionId, cwd, turnId, overrides));
+ const result = await dispatchCodexNativeHook({
+ hook_event_name: "UserPromptSubmit",
+ cwd,
+ session_id: sessionId,
+ thread_id: sessionId,
+ turn_id: turnId,
+ source: "native",
+ prompt: "$ultragoal execute",
+ }, { cwd });
+ assert.doesNotMatch(String(result.skillState?.transition_error ?? ""), /OMX-ULTRAGOAL-BOOTSTRAP-REQUIRED/, name);
+ assert.equal(await readNativeUltragoalBootstrap(join(cwd, ".omx", "state"), sessionId), null, name);
+ }
+
+ const ambiguousId = "019f-root-ambiguous";
+ const ambiguousTurnId = "019f-root-ambiguous-turn";
+ await writeRootTranscript(process.env.CODEX_HOME, ambiguousId, rootTranscriptRecord(ambiguousId, cwd, ambiguousTurnId));
+ const duplicate = join(process.env.CODEX_HOME, "sessions", "duplicate", `rollout-copy-${ambiguousId}.jsonl`);
+ await mkdir(dirname(duplicate), { recursive: true });
+ await writeFile(duplicate, rootTranscriptRecord(ambiguousId, cwd, ambiguousTurnId));
+ const archivedId = "019f-root-archived";
+ const archivedTurnId = "019f-root-archived-turn";
+ const archived = join(process.env.CODEX_HOME, "archived_sessions", `rollout-${archivedId}.jsonl`);
+ await mkdir(dirname(archived), { recursive: true });
+ await writeFile(archived, rootTranscriptRecord(archivedId, cwd, archivedTurnId));
+
+ for (const [name, sessionId] of [["ambiguous", ambiguousId], ["archived", archivedId]] as const) {
+ const result = await dispatchCodexNativeHook({
+ hook_event_name: "UserPromptSubmit",
+ cwd,
+ session_id: sessionId,
+ thread_id: sessionId,
+ turn_id: name === "ambiguous" ? ambiguousTurnId : archivedTurnId,
+ source: "native",
+ prompt: "$ultragoal execute",
+ }, { cwd });
+ assert.doesNotMatch(String(result.skillState?.transition_error ?? ""), /OMX-ULTRAGOAL-BOOTSTRAP-REQUIRED/, name);
+ assert.equal(await readNativeUltragoalBootstrap(join(cwd, ".omx", "state"), sessionId), null, name);
+ }
+ } finally {
+ await rm(cwd, { recursive: true, force: true });
+ }
+ });
+
+ it("does not trust session_meta dynamic tools or a stale turn_context", async () => {
+ delete process.env.TMUX;
+ process.env.OMX_NATIVE_SUBAGENT_ASSIGNMENTS = "on";
+ process.env.OMX_NATIVE_ULTRAGOAL_BACKEND = "local-experimental";
+ const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-root-turn-context-reject-"));
+ try {
+ process.env.CODEX_HOME = join(cwd, "codex-home");
+ const sessionId = "019f-root-stale-context";
+ const turnId = "019f-root-current-turn";
+ await writeRootTranscript(process.env.CODEX_HOME, sessionId, rootTranscriptRecord(
+ sessionId,
+ cwd,
+ "019f-root-stale-turn",
+ { dynamic_tools: [{ name: "collaboration.spawn_agent" }] },
+ ));
+ const result = await dispatchCodexNativeHook({
+ hook_event_name: "UserPromptSubmit",
+ cwd,
+ session_id: sessionId,
+ thread_id: sessionId,
+ turn_id: turnId,
+ source: "native",
+ prompt: "$ultragoal execute",
+ }, { cwd });
+ assert.doesNotMatch(String(result.skillState?.transition_error ?? ""), /OMX-ULTRAGOAL-BOOTSTRAP-REQUIRED/);
+ assert.equal(await readNativeUltragoalBootstrap(join(cwd, ".omx", "state"), sessionId), null);
+ } finally {
+ await rm(cwd, { recursive: true, force: true });
+ }
+ });
+
+ it("requires the exact latest turn_context for root Prompt and PreTool authority", async () => {
+ delete process.env.TMUX;
+ process.env.OMX_NATIVE_SUBAGENT_ASSIGNMENTS = "on";
+ process.env.OMX_NATIVE_ULTRAGOAL_BACKEND = "local-experimental";
+ const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-root-current-turn-reject-"));
+ try {
+ process.env.CODEX_HOME = join(cwd, "codex-home");
+ const stateDir = join(cwd, ".omx", "state");
+ await writeJson(join(stateDir, "session.json"), {
+ session_id: "019f-competing-current-turn",
+ native_session_id: "019f-competing-current-turn",
+ cwd,
+ pid: process.pid,
+ });
+ for (const name of ["missing", "mismatched", "malformed-companion", "stale-latest", "partial-newer"] as const) {
+ const sessionId = `019f-root-turn-${name}`;
+ const currentTurnId = `019f-root-turn-${name}-current`;
+ let transcript = rootTranscriptRecord(sessionId, cwd, currentTurnId);
+ if (name === "stale-latest") {
+ transcript += `${JSON.stringify({
+ type: "turn_context",
+ payload: {
+ turn_id: `${currentTurnId}-newer`,
+ cwd,
+ multi_agent_mode: "explicitRequestOnly",
+ multi_agent_version: "v2",
+ },
+ })}\n`;
+ } else if (name === "partial-newer") {
+ transcript += "{\"type\":\"turn_context\",\"payload\":{";
+ }
+ await writeRootTranscript(process.env.CODEX_HOME, sessionId, transcript);
+ const turnClaim = name === "missing"
+ ? {}
+ : name === "malformed-companion"
+ ? { turn_id: currentTurnId, turnId: 42 }
+ : { turn_id: name === "mismatched" ? `${currentTurnId}-foreign` : currentTurnId };
+ const prompt = await dispatchCodexNativeHook({
+ hook_event_name: "UserPromptSubmit",
+ cwd,
+ session_id: sessionId,
+ ...turnClaim,
+ source: "native",
+ prompt: "$ultragoal execute",
+ }, { cwd });
+ assert.doesNotMatch(String(prompt.skillState?.transition_error ?? ""), /OMX-ULTRAGOAL-BOOTSTRAP-REQUIRED/, name);
+
+ await writeJson(join(stateDir, "sessions", sessionId, "skill-active-state.json"), {
+ version: 1,
+ active: true,
+ skill: "ultragoal",
+ phase: "executing",
+ session_id: sessionId,
+ active_skills: [{ skill: "ultragoal", active: true, phase: "executing", session_id: sessionId }],
+ });
+ await writeJson(join(stateDir, "sessions", sessionId, "ultragoal-state.json"), {
+ active: true,
+ mode: "ultragoal",
+ current_phase: "executing",
+ session_id: sessionId,
+ });
+
+ const preTool = await dispatchCodexNativeHook({
+ hook_event_name: "PreToolUse",
+ cwd,
+ session_id: sessionId,
+ ...turnClaim,
+ tool_name: "Edit",
+ tool_input: { file_path: "src/untrusted-root.ts" },
+ }, { cwd });
+ assert.equal(preTool.outputJson?.decision, "block", name);
+ assert.doesNotMatch(String(preTool.outputJson?.reason ?? ""), /Main-root Conductor mode is active/, name);
+ }
+ } finally {
+ await rm(cwd, { recursive: true, force: true });
+ }
+ });
+
+ it("fails closed on conflicting root transcript aliases", async () => {
+ delete process.env.TMUX;
+ process.env.OMX_NATIVE_SUBAGENT_ASSIGNMENTS = "on";
+ process.env.OMX_NATIVE_ULTRAGOAL_BACKEND = "local-experimental";
+ const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-root-alias-conflict-"));
+ try {
+ process.env.CODEX_HOME = join(cwd, "codex-home");
+ const cases = [
+ ["session", { session_id: "same", sessionId: "foreign" }, {}],
+ ["session-malformed", { session_id: "same", sessionId: null }, {}],
+ ["thread-source", { threadSource: "subagent" }, {}],
+ ["thread-source-malformed", { threadSource: null }, {}],
+ ["turn", {}, { turnId: "foreign" }],
+ ["mode", {}, { multiAgentMode: "disabled" }],
+ ["version", {}, { multiAgentVersion: "disabled" }],
+ ] as const;
+ for (const [name, sessionOverrides, turnOverrides] of cases) {
+ const sessionId = `019f-root-alias-${name}`;
+ const turnId = `019f-root-alias-${name}-turn`;
+ const effectiveSessionOverrides = name.startsWith("session")
+ ? { ...sessionOverrides, session_id: sessionId }
+ : sessionOverrides;
+ await writeRootTranscript(process.env.CODEX_HOME, sessionId, rootTranscriptRecord(
+ sessionId,
+ cwd,
+ turnId,
+ effectiveSessionOverrides,
+ turnOverrides,
+ ));
+ const result = await dispatchCodexNativeHook({
+ hook_event_name: "UserPromptSubmit",
+ cwd,
+ session_id: sessionId,
+ thread_id: sessionId,
+ turn_id: turnId,
+ source: "native",
+ prompt: "$ultragoal execute",
+ }, { cwd });
+ assert.doesNotMatch(String(result.skillState?.transition_error ?? ""), /OMX-ULTRAGOAL-BOOTSTRAP-REQUIRED/, name);
+ assert.equal(await readNativeUltragoalBootstrap(join(cwd, ".omx", "state"), sessionId), null, name);
+ }
+ } finally {
+ await rm(cwd, { recursive: true, force: true });
+ }
+ });
+
+ it("rejects a root transcript mutated after its pinned read", async () => {
+ delete process.env.TMUX;
+ process.env.OMX_NATIVE_SUBAGENT_ASSIGNMENTS = "on";
+ process.env.OMX_NATIVE_ULTRAGOAL_BACKEND = "local-experimental";
+ const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-root-pinned-race-"));
+ try {
+ process.env.CODEX_HOME = join(cwd, "codex-home");
+ const sessionId = "019f-root-pinned-race";
+ const turnId = "019f-root-pinned-race-turn";
+ await writeRootTranscript(process.env.CODEX_HOME, sessionId, rootTranscriptRecord(sessionId, cwd, turnId));
+ let postReadCalls = 0;
+ const result = await dispatchCodexNativeHook({
+ hook_event_name: "UserPromptSubmit",
+ cwd,
+ session_id: sessionId,
+ thread_id: sessionId,
+ turn_id: turnId,
+ source: "native",
+ prompt: "$ultragoal execute",
+ }, {
+ cwd,
+ rootTranscriptPostReadHook: async (path) => {
+ postReadCalls += 1;
+ await appendFile(path, `${JSON.stringify({ type: "event_msg", payload: { type: "mutation" } })}\n`);
+ },
+ });
+ assert.equal(postReadCalls, 1);
+ assert.doesNotMatch(String(result.skillState?.transition_error ?? ""), /OMX-ULTRAGOAL-BOOTSTRAP-REQUIRED/);
+ assert.equal(await readNativeUltragoalBootstrap(join(cwd, ".omx", "state"), sessionId), null);
+ } finally {
+ await rm(cwd, { recursive: true, force: true });
+ }
+ });
+
+ it("fails closed when root transcript traversal errors or exhausts its entry cap", async () => {
+ delete process.env.TMUX;
+ process.env.OMX_NATIVE_SUBAGENT_ASSIGNMENTS = "on";
+ process.env.OMX_NATIVE_ULTRAGOAL_BACKEND = "local-experimental";
+ const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-root-scan-incomplete-"));
+ try {
+ process.env.CODEX_HOME = join(cwd, "codex-home");
+ for (const name of ["error", "cap"] as const) {
+ const sessionId = `019f-root-scan-${name}`;
+ const turnId = `019f-root-scan-${name}-turn`;
+ await writeRootTranscript(process.env.CODEX_HOME, sessionId, rootTranscriptRecord(sessionId, cwd, turnId));
+ const result = await dispatchCodexNativeHook({
+ hook_event_name: "UserPromptSubmit",
+ cwd,
+ session_id: sessionId,
+ turn_id: turnId,
+ source: "native",
+ prompt: "$ultragoal execute",
+ }, name === "error" ? {
+ cwd,
+ rootTranscriptBeforeReadDirHook: () => {
+ throw new Error("injected_readdir_error");
+ },
+ } : {
+ cwd,
+ rootTranscriptScanMaxEntries: 1,
+ });
+ assert.doesNotMatch(String(result.skillState?.transition_error ?? ""), /OMX-ULTRAGOAL-BOOTSTRAP-REQUIRED/, name);
+ assert.equal(await readNativeUltragoalBootstrap(join(cwd, ".omx", "state"), sessionId), null, name);
+ }
+ } finally {
+ await rm(cwd, { recursive: true, force: true });
+ }
+ });
+
+ it("authorizes an exact root Stop against an exact-cwd legacy stale-dead pointer without state_root", async () => {
+ const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-root-stop-stale-pointer-"));
+ try {
+ process.env.CODEX_HOME = join(cwd, "codex-home");
+ const stateDir = join(cwd, ".omx", "state");
+ const sessionId = "019f-root-stop-live";
+ const turnId = "019f-root-stop-turn";
+ await writeJson(join(stateDir, "session.json"), {
+ session_id: "019f-dead-competing-pointer",
+ native_session_id: "019f-dead-competing-pointer",
+ started_at: "2026-01-01T00:00:00.000Z",
+ cwd,
+ pid: 999_999,
+ platform: process.platform,
+ });
+ await writeJson(join(stateDir, "sessions", sessionId, "skill-active-state.json"), {
+ version: 1,
+ active: true,
+ skill: "autopilot",
+ phase: "executing",
+ session_id: sessionId,
+ thread_id: sessionId,
+ active_skills: [{ skill: "autopilot", active: true, phase: "executing", session_id: sessionId }],
+ });
+ await writeJson(join(stateDir, "sessions", sessionId, "autopilot-state.json"), {
+ active: true,
+ mode: "autopilot",
+ current_phase: "executing",
+ session_id: sessionId,
+ });
+ await writeRootTranscript(process.env.CODEX_HOME, sessionId, rootTranscriptRecord(sessionId, cwd, turnId));
+
+ const result = await dispatchCodexNativeHook({
+ hook_event_name: "Stop",
+ cwd,
+ session_id: sessionId,
+ turn_id: turnId,
+ }, { cwd });
+
+ assert.equal(result.outputJson?.decision, "block");
+ assert.doesNotMatch(String(result.outputJson?.reason ?? ""), /selected session pointer is stale-dead/);
+ assert.match(String(result.outputJson?.reason ?? result.outputJson?.systemMessage ?? ""), /autopilot/i);
+ } finally {
+ await rm(cwd, { recursive: true, force: true });
+ }
+ });
+
+ it("keeps same-session stale-dead Stop turn-independent for a legacy pointer without state_root", async () => {
+ const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-root-stop-no-turn-"));
+ try {
+ process.env.CODEX_HOME = join(cwd, "codex-home");
+ const stateDir = join(cwd, ".omx", "state");
+ const sessionId = "019f-root-stop-no-turn";
+ await writeJson(join(stateDir, "session.json"), {
+ session_id: "omx-canonical-root-stop",
+ native_session_id: sessionId,
+ owner_omx_session_id: "omx-owner-root-stop",
+ owner_codex_session_id: sessionId,
+ started_at: "2026-01-01T00:00:00.000Z",
+ cwd,
+ state_root: join(cwd, "foreign-state"),
+ pid: 999_999,
+ platform: process.platform,
+ });
+ await writeJson(join(stateDir, "sessions", sessionId, "skill-active-state.json"), {
+ version: 1,
+ active: true,
+ skill: "autopilot",
+ phase: "executing",
+ session_id: sessionId,
+ thread_id: sessionId,
+ active_skills: [{ skill: "autopilot", active: true, phase: "executing", session_id: sessionId }],
+ });
+ await writeJson(join(stateDir, "sessions", sessionId, "autopilot-state.json"), {
+ active: true,
+ mode: "autopilot",
+ current_phase: "executing",
+ session_id: sessionId,
+ });
+ await writeRootTranscript(
+ process.env.CODEX_HOME,
+ sessionId,
+ rootTranscriptRecord(sessionId, cwd, "019f-root-stop-unclaimed-turn"),
+ );
+
+ const rejected = await dispatchCodexNativeHook({
+ hook_event_name: "Stop",
+ cwd,
+ session_id: sessionId,
+ }, { cwd });
+ assert.equal(rejected.outputJson?.decision, "block");
+ assert.match(String(rejected.outputJson?.reason ?? ""), /selected session pointer is stale-dead/);
+ for (const malformedStateRoot of ["", " ", null, 42, {}]) {
+ await writeJson(join(stateDir, "session.json"), {
+ session_id: sessionId,
+ native_session_id: sessionId,
+ started_at: "2026-01-01T00:00:00.000Z",
+ cwd,
+ state_root: malformedStateRoot,
+ pid: 999_999,
+ platform: process.platform,
+ });
+ const malformed = await dispatchCodexNativeHook({
+ hook_event_name: "Stop",
+ cwd,
+ session_id: sessionId,
+ }, { cwd });
+ assert.equal(malformed.outputJson?.decision, "block");
+ assert.match(String(malformed.outputJson?.reason ?? ""), /selected session pointer is stale-dead/);
+ }
+ await writeJson(join(stateDir, "session.json"), {
+ session_id: sessionId,
+ native_session_id: sessionId,
+ owner_codex_session_id: "foreign-session",
+ started_at: "2026-01-01T00:00:00.000Z",
+ cwd,
+ pid: 999_999,
+ platform: process.platform,
+ });
+ const conflictingAlias = await dispatchCodexNativeHook({
+ hook_event_name: "Stop",
+ cwd,
+ session_id: sessionId,
+ }, { cwd });
+ assert.equal(conflictingAlias.outputJson?.decision, "block");
+ assert.match(String(conflictingAlias.outputJson?.reason ?? ""), /selected session pointer is stale-dead/);
+ await writeJson(join(stateDir, "session.json"), {
+ session_id: "omx-canonical-root-stop",
+ native_session_id: sessionId,
+ owner_omx_session_id: "omx-owner-root-stop",
+ owner_codex_session_id: sessionId,
+ started_at: "2026-01-01T00:00:00.000Z",
+ cwd,
+ pid: 999_999,
+ platform: process.platform,
+ });
+
+ const result = await dispatchCodexNativeHook({
+ hook_event_name: "Stop",
+ cwd,
+ session_id: sessionId,
+ }, { cwd });
+
+ assert.equal(result.outputJson?.decision, "block");
+ assert.doesNotMatch(String(result.outputJson?.reason ?? ""), /selected session pointer is stale-dead/);
+ assert.match(String(result.outputJson?.reason ?? result.outputJson?.systemMessage ?? ""), /autopilot/i);
+ } finally {
+ await rm(cwd, { recursive: true, force: true });
+ }
+ });
+
+ it("keeps spoofed root Stop transcripts fail closed against a stale-dead pointer", async () => {
+ const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-root-stop-reject-"));
+ try {
+ process.env.CODEX_HOME = join(cwd, "codex-home");
+ const stateDir = join(cwd, ".omx", "state");
+ await writeJson(join(stateDir, "session.json"), {
+ session_id: "019f-dead-stop-pointer",
+ native_session_id: "019f-dead-stop-pointer",
+ started_at: "2026-01-01T00:00:00.000Z",
+ cwd,
+ state_root: stateDir,
+ pid: 999_999,
+ platform: process.platform,
+ });
+ const cases = [
+ ["spoof", { id: "foreign-root" }, {}],
+ ["child", { source: { subagent: { thread_spawn: { parent_thread_id: "parent" } } } }, {}],
+ ["aliases", { threadSource: "subagent" }, {}],
+ ["payload-aliases", {}, { sessionId: "foreign-session" }],
+ ["payload-session-malformed", {}, { sessionId: null }],
+ ["thread-mismatch", {}, { thread_id: "foreign-thread" }],
+ ["thread-conflict", {}, { thread_id: "__SESSION__", threadId: "foreign-thread" }],
+ ["thread-number", {}, { thread_id: 42 }],
+ ["thread-empty", {}, { thread_id: "" }],
+ ["thread-null", {}, { thread_id: null }],
+ ["agent-id", {}, { agent_id: "claimed-agent" }],
+ ["agent-id-camel", {}, { agentId: "claimed-agent" }],
+ ["agent-empty", {}, { agent_id: "" }],
+ ["agent-null", {}, { agent_id: null }],
+ ["agent-object", {}, { agent_id: { id: "claimed-agent" } }],
+ ["owner", {}, { owner_codex_thread_id: "claimed-owner" }],
+ ["owner-empty", {}, { owner_codex_thread_id: "" }],
+ ["owner-null", {}, { owner_codex_thread_id: null }],
+ ["owner-object", {}, { owner_codex_thread_id: { id: "claimed-owner" } }],
+ ["agent-role", {}, { agent_role: "executor" }],
+ ["agent-role-camel", {}, { agentRole: "executor" }],
+ ["agent-role-malformed", {}, { agent_role: null }],
+ ["agent-type", {}, { agent_type: "executor" }],
+ ["agent-type-camel", {}, { agentType: "executor" }],
+ ["agent-type-malformed", {}, { agent_type: { type: "executor" } }],
+ ["cwd", { cwd: join(cwd, "foreign") }, {}],
+ ] as const;
+ for (const [name, overrides, payloadOverrides] of cases) {
+ const sessionId = `019f-root-stop-${name}`;
+ const turnId = `019f-root-stop-${name}-turn`;
+ const effectivePayloadOverrides = Object.fromEntries(
+ Object.entries(payloadOverrides).map(([key, value]) => [key, value === "__SESSION__" ? sessionId : value]),
+ );
+ await writeRootTranscript(process.env.CODEX_HOME, sessionId, rootTranscriptRecord(sessionId, cwd, turnId, overrides));
+ const result = await dispatchCodexNativeHook({
+ hook_event_name: "Stop",
+ cwd,
+ session_id: sessionId,
+ thread_id: sessionId,
+ turn_id: turnId,
+ ...effectivePayloadOverrides,
+ }, { cwd });
+ assert.equal(result.outputJson?.decision, "block", name);
+ assert.match(String(result.outputJson?.reason ?? ""), /selected session pointer is stale-dead/, name);
+ }
+ } finally {
+ await rm(cwd, { recursive: true, force: true });
+ }
+ });
+
+ it("authorizes exact root Stop against an identity-indeterminate current pointer", async () => {
+ const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-root-stop-identity-indeterminate-"));
+ try {
+ process.env.CODEX_HOME = join(cwd, "codex-home");
+ const stateDir = join(cwd, ".omx", "state");
+ const sessionId = "019fafca-1e7e-7372-9399-dffb68fc354e";
+ const turnId = "019fafca-stop-turn";
+ await writeJson(join(stateDir, "session.json"), {
+ session_id: sessionId,
+ native_session_id: sessionId,
+ started_at: new Date().toISOString(),
+ cwd,
+ pid: process.pid,
+ platform: "linux",
+ });
+ await writeJson(join(stateDir, "sessions", sessionId, "skill-active-state.json"), {
+ version: 1,
+ active: true,
+ skill: "autopilot",
+ phase: "executing",
+ session_id: sessionId,
+ thread_id: sessionId,
+ active_skills: [{ skill: "autopilot", active: true, phase: "executing", session_id: sessionId }],
+ });
+ await writeJson(join(stateDir, "sessions", sessionId, "autopilot-state.json"), {
+ active: true,
+ mode: "autopilot",
+ current_phase: "executing",
+ session_id: sessionId,
+ });
+ await writeRootTranscript(process.env.CODEX_HOME, sessionId, rootTranscriptRecord(sessionId, cwd, turnId, { source: "exec" }));
+
+ const missingTurn = await dispatchCodexNativeHook({
+ hook_event_name: "Stop",
+ cwd,
+ session_id: sessionId,
+ }, { cwd });
+ assert.equal(missingTurn.outputJson?.decision, "block");
+ assert.match(String(missingTurn.outputJson?.reason ?? ""), /identity-indeterminate/);
+
+ const result = await dispatchCodexNativeHook({
+ hook_event_name: "Stop",
+ cwd,
+ session_id: sessionId,
+ turn_id: turnId,
+ }, { cwd });
+
+ assert.equal(result.outputJson?.decision, "block");
+ assert.doesNotMatch(String(result.outputJson?.reason ?? ""), /identity-indeterminate/);
+ assert.match(String(result.outputJson?.reason ?? result.outputJson?.systemMessage ?? ""), /autopilot/i);
+ } finally {
+ await rm(cwd, { recursive: true, force: true });
+ }
+ });
+
+ it("authorizes exact root Stop after a workspace move and a turn longer than the legacy transcript tail", async () => {
+ const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-root-stop-long-moved-turn-"));
+ try {
+ process.env.CODEX_HOME = join(cwd, "codex-home");
+ const stateDir = join(cwd, ".omx", "state");
+ const sessionId = "019f-root-stop-long-moved-turn";
+ const turnId = "019f-root-stop-long-moved-turn-context";
+ const originalCwd = join(cwd, "original-workspace");
+ await writeJson(join(stateDir, "session.json"), {
+ session_id: sessionId,
+ native_session_id: sessionId,
+ started_at: new Date().toISOString(),
+ cwd,
+ state_root: stateDir,
+ pid: process.pid,
+ platform: "linux",
+ });
+ await writeJson(join(stateDir, "sessions", sessionId, "skill-active-state.json"), {
+ version: 1,
+ active: true,
+ skill: "autopilot",
+ phase: "executing",
+ session_id: sessionId,
+ thread_id: sessionId,
+ active_skills: [{ skill: "autopilot", active: true, phase: "executing", session_id: sessionId }],
+ });
+ await writeJson(join(stateDir, "sessions", sessionId, "autopilot-state.json"), {
+ active: true,
+ mode: "autopilot",
+ current_phase: "executing",
+ session_id: sessionId,
+ });
+ const laterRecords = Array.from({ length: 260 }, (_, sequence) => JSON.stringify({
+ type: "event_msg",
+ payload: { sequence, padding: "x".repeat(256 * 1024) },
+ })).join("\n");
+ await writeRootTranscript(
+ process.env.CODEX_HOME,
+ sessionId,
+ `${rootTranscriptRecord(
+ sessionId,
+ originalCwd,
+ "019f-root-stop-original-turn-context",
+ { source: "exec" },
+ )}${JSON.stringify({
+ type: "turn_context",
+ payload: {
+ turn_id: turnId,
+ cwd,
+ multi_agent_mode: "explicitRequestOnly",
+ multi_agent_version: "v2",
+ },
+ })}\n${laterRecords}\n`,
+ );
+
+ const result = await dispatchCodexNativeHook({
+ hook_event_name: "Stop",
+ cwd,
+ session_id: sessionId,
+ turn_id: turnId,
+ }, { cwd });
+
+ assert.equal(result.outputJson?.decision, "block");
+ assert.doesNotMatch(String(result.outputJson?.reason ?? ""), /identity-indeterminate/);
+ assert.match(String(result.outputJson?.reason ?? result.outputJson?.systemMessage ?? ""), /autopilot/i);
+ } finally {
+ await rm(cwd, { recursive: true, force: true });
+ }
+ });
+
+ it("rejects malformed root transcript records before the latest exact turn context", async () => {
+ const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-root-stop-malformed-before-latest-turn-"));
+ try {
+ process.env.CODEX_HOME = join(cwd, "codex-home");
+ const stateDir = join(cwd, ".omx", "state");
+ const sessionId = "019f-root-stop-malformed-before-latest-turn";
+ const turnId = "019f-root-stop-latest-exact-turn";
+ await writeJson(join(stateDir, "session.json"), {
+ session_id: sessionId,
+ native_session_id: sessionId,
+ started_at: new Date().toISOString(),
+ cwd,
+ state_root: stateDir,
+ pid: process.pid,
+ platform: "linux",
+ });
+ await writeRootTranscript(
+ process.env.CODEX_HOME,
+ sessionId,
+ `${rootTranscriptRecord(sessionId, cwd, "019f-root-stop-earlier-turn", { source: "exec" })}`
+ + `{malformed-json\n${JSON.stringify({
+ type: "turn_context",
+ payload: {
+ turn_id: turnId,
+ cwd,
+ multi_agent_mode: "explicitRequestOnly",
+ multi_agent_version: "v2",
+ },
+ })}\n`,
+ );
+
+ const result = await dispatchCodexNativeHook({
+ hook_event_name: "Stop",
+ cwd,
+ session_id: sessionId,
+ turn_id: turnId,
+ }, { cwd });
+
+ assert.equal(result.outputJson?.decision, "block");
+ assert.match(String(result.outputJson?.reason ?? ""), /identity-indeterminate/);
+ } finally {
+ await rm(cwd, { recursive: true, force: true });
+ }
+ });
+
+ it("does not let an exact root transcript override a competing identity-indeterminate pointer", async () => {
+ const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-root-stop-competing-indeterminate-"));
+ try {
+ process.env.CODEX_HOME = join(cwd, "codex-home");
+ const stateDir = join(cwd, ".omx", "state");
+ const sessionId = "019fafca-1e7e-7372-9399-dffb68fc354e";
+ const turnId = "019fafca-competing-stop-turn";
+ await writeJson(join(stateDir, "session.json"), {
+ session_id: "019fb20d-caff-7022-9759-1ccb0033d801",
+ native_session_id: "019fb20d-caff-7022-9759-1ccb0033d801",
+ started_at: new Date().toISOString(),
+ cwd,
+ state_root: stateDir,
+ pid: process.pid,
+ platform: "linux",
+ });
+ await writeRootTranscript(process.env.CODEX_HOME, sessionId, rootTranscriptRecord(sessionId, cwd, turnId, { source: "exec" }));
+
+ const result = await dispatchCodexNativeHook({
+ hook_event_name: "Stop",
+ cwd,
+ session_id: sessionId,
+ turn_id: turnId,
+ }, { cwd });
+
+ assert.equal(result.outputJson?.decision, "block");
+ assert.match(String(result.outputJson?.reason ?? ""), /identity-indeterminate/);
+ } finally {
+ await rm(cwd, { recursive: true, force: true });
+ }
+ });
+
+ it("rejects mismatched and ambiguous Codex App transcript receipts", async () => {
+ const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-app-v2-receipt-deny-"));
+ try {
+ const stateDir = join(cwd, ".omx", "state");
+ const sessionId = "sess-app-v2-receipt-deny";
+ const rootThreadId = "thread-app-v2-receipt-root";
+ const wrongRoleChildId = "thread-app-v2-wrong-role";
+ const conflictingRoleChildId = "thread-app-v2-conflicting-role";
+ const ambiguousChildId = "thread-app-v2-ambiguous";
+ const archivedChildId = "thread-app-v2-archived";
+ const futureChildId = "thread-app-v2-future";
+ const missingSessionChildId = "thread-app-v2-missing-session";
+ process.env.CODEX_HOME = join(cwd, "codex-home");
+ await writeLeaderSessionFixture(stateDir, sessionId, rootThreadId, cwd);
+
+ const receiptNotBefore = "2026-07-29T16:54:54.000Z";
+ const receiptNotAfter = "2026-07-30T16:54:54.000Z";
+ const transcript = (
+ childAgentId: string,
+ role: string,
+ timestamp = receiptNotBefore,
+ transcriptSessionId = sessionId,
+ ) => `${JSON.stringify({
+ timestamp,
+ type: "session_meta",
+ payload: {
+ id: childAgentId,
+ session_id: transcriptSessionId,
+ cwd,
+ source: {
+ subagent: {
+ thread_spawn: {
+ parent_thread_id: rootThreadId,
+ depth: 1,
+ agent_role: role,
+ },
+ },
+ },
+ },
+ })}\n`;
+ const wrongRolePath = join(process.env.CODEX_HOME, "sessions", `rollout-${wrongRoleChildId}.jsonl`);
+ await mkdir(dirname(wrongRolePath), { recursive: true });
+ await writeFile(wrongRolePath, transcript(wrongRoleChildId, "reviewer"));
+ assert.deepEqual(await validateLocalNativeExecutorIdentity({
+ cwd,
+ sessionId,
+ rootThreadId,
+ childAgentId: wrongRoleChildId,
+ receiptNotBefore,
+ receiptNotAfter,
+ }), { ok: false, reason: "child_transcript_receipt_mismatch" });
+
+ const conflictingRolePath = join(process.env.CODEX_HOME, "sessions", `rollout-${conflictingRoleChildId}.jsonl`);
+ await writeFile(conflictingRolePath, transcript(conflictingRoleChildId, "executor"));
+ const tracking = JSON.parse(readFileSync(join(stateDir, "subagent-tracking.json"), "utf-8")) as {
+ sessions: Record<string, { threads: Record<string, Record<string, unknown>> }>;
+ };
+ tracking.sessions[sessionId]!.threads[conflictingRoleChildId] = {
+ thread_id: conflictingRoleChildId,
+ kind: "subagent",
+ mode: "reviewer",
+ first_seen_at: receiptNotBefore,
+ last_seen_at: receiptNotBefore,
+ turn_count: 1,
+ };
+ await writeJson(join(stateDir, "subagent-tracking.json"), tracking);
+ assert.deepEqual(await validateLocalNativeExecutorIdentity({
+ cwd,
+ sessionId,
+ rootThreadId,
+ childAgentId: conflictingRoleChildId,
+ receiptNotBefore,
+ receiptNotAfter,
+ }), { ok: false, reason: "child_role_mismatch" });
+
+ const livePath = join(process.env.CODEX_HOME, "sessions", "live", `rollout-${ambiguousChildId}.jsonl`);
+ const duplicatePath = join(process.env.CODEX_HOME, "sessions", "duplicate", `rollout-${ambiguousChildId}.jsonl`);
+ await mkdir(dirname(livePath), { recursive: true });
+ await mkdir(dirname(duplicatePath), { recursive: true });
+ await writeFile(livePath, transcript(ambiguousChildId, "executor"));
+ await writeFile(duplicatePath, transcript(ambiguousChildId, "executor"));
+ assert.deepEqual(await validateLocalNativeExecutorIdentity({
+ cwd,
+ sessionId,
+ rootThreadId,
+ childAgentId: ambiguousChildId,
+ receiptNotBefore,
+ receiptNotAfter,
+ }), { ok: false, reason: "child_transcript_receipt_ambiguous" });
+
+ const archivedPath = join(process.env.CODEX_HOME, "archived_sessions", `rollout-${archivedChildId}.jsonl`);
+ await mkdir(dirname(archivedPath), { recursive: true });
+ await writeFile(archivedPath, transcript(archivedChildId, "executor"));
+ assert.deepEqual(await validateLocalNativeExecutorIdentity({
+ cwd,
+ sessionId,
+ rootThreadId,
+ childAgentId: archivedChildId,
+ receiptNotBefore,
+ receiptNotAfter,
+ }), { ok: false, reason: "child_transcript_receipt_missing" });
+
+ const futurePath = join(process.env.CODEX_HOME, "sessions", `rollout-${futureChildId}.jsonl`);
+ await writeFile(futurePath, transcript(futureChildId, "executor", "9999-01-01T00:00:00.000Z"));
+ assert.deepEqual(await validateLocalNativeExecutorIdentity({
+ cwd,
+ sessionId,
+ rootThreadId,
+ childAgentId: futureChildId,
+ receiptNotBefore,
+ receiptNotAfter: "9999-12-31T23:59:59.999Z",
+ }), { ok: false, reason: "child_transcript_receipt_mismatch" });
+
+ const missingSessionPath = join(process.env.CODEX_HOME, "sessions", `rollout-${missingSessionChildId}.jsonl`);
+ await writeFile(missingSessionPath, transcript(
+ missingSessionChildId,
+ "executor",
+ receiptNotBefore,
+ "missing-session",
+ ));
+ assert.deepEqual(await validateLocalNativeExecutorIdentity({
+ cwd,
+ sessionId: "missing-session",
+ rootThreadId,
+ childAgentId: missingSessionChildId,
+ receiptNotBefore,
+ receiptNotAfter,
+ }), { ok: false, reason: "leader_session_mismatch" });
+ } finally {
+ await rm(cwd, { recursive: true, force: true });
+ }
+ });
+
+ it("completes prompt bootstrap through typed assignment, activation, and scoped executor write", async () => {
+ delete process.env.TMUX;
+ process.env.OMX_NATIVE_SUBAGENT_ASSIGNMENTS = "on";
+ process.env.OMX_NATIVE_ULTRAGOAL_BACKEND = "local-experimental";
+ const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-bootstrap-e2e-"));
+ try {
+ const stateDir = join(cwd, ".omx", "state");
+ const sessionId = "019fb20d-caff-7022-9759-1ccb0033d801";
+ const rootThreadId = sessionId;
+ const childThreadId = "019fb20e-031e-7bf0-b557-707fce59e652";
+ const turnId = "019fb20d-caff-7022-9759-1ccb0033d801-turn";
+ process.env.CODEX_HOME = join(cwd, "codex-home");
+ await writeLeaderSessionFixture(stateDir, sessionId, rootThreadId, cwd);
+ await writeRootTranscript(process.env.CODEX_HOME, sessionId, rootTranscriptRecord(sessionId, cwd, turnId));
+ const firstPrompt = await dispatchCodexNativeHook(
+ {
+ hook_event_name: "UserPromptSubmit",
+ cwd,
+ session_id: sessionId,
+ thread_id: rootThreadId,
+ turn_id: turnId,
+ source: "native",
+ available_tools: ["collaboration.spawn_agent"],
+ prompt: "$ultragoal execute the durable plan",
+ },
+ { cwd },
+ );
+ assert.equal(firstPrompt.skillState?.active, false);
+ const bootstrap = await readNativeUltragoalBootstrap(stateDir, sessionId);
+ assert.ok(bootstrap);
+
+ const childTranscriptPath = join(
+ process.env.CODEX_HOME,
+ "sessions",
+ "2026",
+ "07",
+ "29",
+ `rollout-2026-07-29T18-56-08-${childThreadId}.jsonl`,
+ );
+ await mkdir(dirname(childTranscriptPath), { recursive: true });
+ await writeFile(childTranscriptPath, `${JSON.stringify({
+ timestamp: bootstrap.created_at,
+ type: "session_meta",
+ payload: {
+ id: childThreadId,
+ session_id: sessionId,
+ cwd,
+ source: {
+ subagent: {
+ thread_spawn: {
+ parent_thread_id: rootThreadId,
+ depth: 1,
+ agent_path: "/root/ultragoal_executor",
+ agent_role: "executor",
+ },
+ },
+ },
+ },
+ })}\n`);
+ const tracking = JSON.parse(
+ readFileSync(join(stateDir, "subagent-tracking.json"), "utf-8"),
+ ) as { sessions?: Record<string, { threads?: Record<string, Record<string, unknown>> }> };
+ assert.equal(
+ tracking.sessions?.[sessionId]?.threads?.[childThreadId],
+ undefined,
+ "assignment-local transcript evidence must not grant persisted reopen authority",
+ );
+ const preAuthorizedWrite = await dispatchCodexNativeHook(
+ {
+ hook_event_name: "PreToolUse",
+ cwd,
+ session_id: sessionId,
+ turn_id: "child-preauth-turn",
+ transcript_path: childTranscriptPath,
+ source: "native",
+ tool_name: "exec",
+ tool_input: { file_path: join(cwd, "src", "native-flow", "preauth.ts"), content: "no" },
+ },
+ { cwd },
+ );
+ assert.equal(preAuthorizedWrite.outputJson?.decision, "block");
+ assert.match(String(preAuthorizedWrite.outputJson?.reason ?? ""), /OWNER_CONFIRMATION_REQUIRED/);
+ await issueLocalNativeExecutorAssignment({
+ cwd,
+ stateDir,
+ sessionId,
+ rootThreadId,
+ childAgentId: childThreadId,
+ expectedGeneration: bootstrap.generation,
+ pathPrefixes: ["src/native-flow"],
+ ttlSeconds: 300,
+ });
+ const assignedTracking = JSON.parse(
+ readFileSync(join(stateDir, "subagent-tracking.json"), "utf-8"),
+ ) as { sessions?: Record<string, { threads?: Record<string, Record<string, unknown>> }> };
+ const descriptiveChild = assignedTracking.sessions?.[sessionId]?.threads?.[childThreadId];
+ assert.equal(descriptiveChild?.mode, "executor");
+ assert.equal(descriptiveChild?.status, undefined);
+ assert.equal(descriptiveChild?.provenance_kind, undefined);
+ assert.equal(descriptiveChild?.direct_child_parent_id, undefined);
+ assert.deepEqual(await validateLocalNativeExecutorIdentity({
+ cwd,
+ sessionId,
+ rootThreadId,
+ childAgentId: childThreadId,
+ receiptNotBefore: bootstrap.created_at,
+ receiptNotAfter: bootstrap.expires_at,
+ }), { ok: true });
+
+ const activated = await dispatchCodexNativeHook(
+ {
+ hook_event_name: "UserPromptSubmit",
+ cwd,
+ session_id: sessionId,
+ thread_id: rootThreadId,
+ turn_id: turnId,
+ source: "native",
+ available_tools: ["collaboration.spawn_agent"],
+ prompt: "$ultragoal execute the durable plan",
+ },
+ { cwd },
+ );
+ assert.equal(activated.skillState?.active, true);
+ assert.equal(activated.skillState?.initialized_mode, "ultragoal");
+ assert.equal(
+ (await findReadyLocalNativeExecutorAssignment({ cwd, stateDir, sessionId, rootThreadId }))?.child_agent_id,
+ childThreadId,
+ );
+
+ const goalLifecyclePayload = {
+ hook_event_name: "PreToolUse",
+ cwd,
+ session_id: sessionId,
+ turn_id: turnId,
+ source: "native",
+ tool_name: "create_goal",
+ tool_input: { objective: "complete the accepted native Ultragoal" },
+ };
+ await writeJson(join(stateDir, "session.json"), {
+ session_id: sessionId,
+ native_session_id: rootThreadId,
+ owner_codex_session_id: "foreign-session",
+ target_session_id: sessionId,
+ cwd,
+ pid: process.pid,
+ platform: process.platform === "linux" ? "darwin" : "linux",
+ });
+ assert.equal(
+ (await dispatchCodexNativeHook(goalLifecyclePayload, { cwd })).outputJson?.decision,
+ "block",
+ "a legacy pointer with conflicting session aliases must not authorize the root control plane",
+ );
+ await writeJson(join(stateDir, "session.json"), {
+ session_id: sessionId,
+ native_session_id: rootThreadId,
+ owner_codex_session_id: sessionId,
+ target_session_id: sessionId,
+ cwd,
+ state_root: join(cwd, "foreign-state"),
+ pid: process.pid,
+ platform: process.platform === "linux" ? "darwin" : "linux",
+ });
+ assert.equal(
+ (await dispatchCodexNativeHook(goalLifecyclePayload, { cwd })).outputJson?.decision,
+ "block",
+ "an explicit foreign state_root must not authorize the root control plane",
+ );
+ // Long-lived Codex App tasks can retain the pre-state_root pointer schema
+ // after OMX is upgraded. Exact root transcript/session/cwd evidence must
+ // keep the native control plane usable once all declared aliases agree.
+ await writeJson(join(stateDir, "session.json"), {
+ session_id: "omx-canonical-ultragoal",
+ native_session_id: rootThreadId,
+ owner_omx_session_id: "omx-owner-ultragoal",
+ owner_codex_session_id: sessionId,
+ target_session_id: sessionId,
+ cwd,
+ pid: process.pid,
+ platform: process.platform === "linux" ? "darwin" : "linux",
+ });
+
+ const goalLifecycle = await dispatchCodexNativeHook(goalLifecyclePayload, { cwd });
+ assert.equal(goalLifecycle.outputJson, null);
+ await writeJson(join(stateDir, "session.json"), {
+ session_id: sessionId,
+ native_session_id: rootThreadId,
+ owner_codex_session_id: sessionId,
+ target_session_id: sessionId,
+ cwd,
+ state_root: stateDir,
+ });
+
+ const activeBootstrap = await readNativeUltragoalBootstrap(stateDir, sessionId);
+ assert.ok(activeBootstrap?.child_agent_id);
+ await writeJson(
+ join(stateDir, "sessions", sessionId, "native-ultragoal-bootstrap.json"),
+ { ...activeBootstrap, status: "activating" },
+ );
+
+ const followup = await dispatchCodexNativeHook(
+ {
+ hook_event_name: "PreToolUse",
+ cwd,
+ session_id: sessionId,
+ turn_id: turnId,
+ source: "native",
+ tool_name: "collaborationfollowup_task",
+ tool_input: { target: "/root/native_executor", message: "start the authorized assignment" },
+ },
+ { cwd },
+ );
+ assert.equal(followup.outputJson, null);
+ assert.equal((await readNativeUltragoalBootstrap(stateDir, sessionId))?.status, "active");
+
+ const liveShapeWrite = await dispatchCodexNativeHook(
+ {
+ hook_event_name: "PreToolUse",
+ cwd,
+ session_id: sessionId,
+ turn_id: "child-active-turn",
+ transcript_path: childTranscriptPath,
+ source: "native",
+ tool_name: "Write",
+ tool_input: { file_path: join(cwd, "src", "native-flow", "live-result.ts"), content: "ok" },
+ },
+ { cwd },
+ );
+ assert.equal(liveShapeWrite.outputJson, null);
+
+ const write = await dispatchCodexNativeHook(
+ {
+ hook_event_name: "PreToolUse",
+ cwd,
+ session_id: sessionId,
+ thread_id: childThreadId,
+ agent_id: childThreadId,
+ agent_type: "executor",
+ source: "native",
+ tool_name: "Write",
+ tool_input: { file_path: join(cwd, "src", "native-flow", "result.ts"), content: "ok" },
+ },
+ { cwd },
+ );
+ assert.equal(write.outputJson, null);
+
+ await writeJson(join(stateDir, "sessions", sessionId, "ultragoal-state.json"), {
+ mode: "ultragoal",
+ active: false,
+ current_phase: "complete",
+ session_id: sessionId,
+ });
+ const terminalWrite = await dispatchCodexNativeHook(
+ {
+ hook_event_name: "PreToolUse",
+ cwd,
+ session_id: sessionId,
+ thread_id: childThreadId,
+ agent_id: childThreadId,
+ agent_type: "executor",
+ source: "native",
+ tool_name: "Write",
+ tool_input: { file_path: join(cwd, "src", "native-flow", "late.ts"), content: "no" },
+ },
+ { cwd },
+ );
+ assert.equal(terminalWrite.outputJson?.decision, "block");
+ assert.equal((await readNativeUltragoalBootstrap(stateDir, sessionId))?.status, "revoked");
+ await dispatchCodexNativeHook(
+ {
+ hook_event_name: "Stop",
+ cwd,
+ session_id: sessionId,
+ thread_id: rootThreadId,
+ source: "native",
+ },
+ { cwd },
+ );
+ assert.equal((await readNativeUltragoalBootstrap(stateDir, sessionId))?.status, "revoked");
+ } finally {
+ await rm(cwd, { recursive: true, force: true });
+ }
+ });
+
+ it("keeps the executor read-only until successful activation PostToolUse", async () => {
+ delete process.env.TMUX;
+ process.env.OMX_NATIVE_SUBAGENT_ASSIGNMENTS = "on";
+ process.env.OMX_NATIVE_ULTRAGOAL_BACKEND = "local-experimental";
+ const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-bootstrap-two-phase-"));
+ try {
+ const stateDir = join(cwd, ".omx", "state");
+ const sessionId = "sess-bootstrap-two-phase";
+ const rootThreadId = "thread-bootstrap-two-phase-root";
+ const childThreadId = "thread-bootstrap-two-phase-child";
+ await writeLeaderSessionFixture(stateDir, sessionId, rootThreadId, cwd);
+ const activationPayload = {
+ cwd,
+ session_id: sessionId,
+ thread_id: rootThreadId,
+ agent_id: rootThreadId,
+ source: "native",
+ available_tools: ["collaboration.spawn_agent"],
+ tool_name: "Bash",
+ tool_input: { command: `omx state write --input '${ACTIVATION_INPUT}' --json` },
+ };
+ await dispatchCodexNativeHook({ hook_event_name: "PreToolUse", ...activationPayload }, { cwd });
+ const bootstrap = await readNativeUltragoalBootstrap(stateDir, sessionId);
+ assert.ok(bootstrap);
+ await writeJson(join(stateDir, "subagent-tracking.json"), {
+ schemaVersion: 1,
+ sessions: {
+ [sessionId]: {
+ session_id: sessionId,
+ leader_thread_id: rootThreadId,
+ updated_at: "2026-07-29T16:54:54.000Z",
+ threads: {
+ [rootThreadId]: {
+ thread_id: rootThreadId,
+ kind: "leader",
+ first_seen_at: "2026-07-29T16:54:54.000Z",
+ last_seen_at: "2026-07-29T16:54:54.000Z",
+ turn_count: 1,
+ },
+ [childThreadId]: {
+ thread_id: childThreadId,
+ kind: "subagent",
+ mode: "executor",
+ status: "available",
+ first_seen_at: "2026-07-29T16:54:54.000Z",
+ last_seen_at: "2026-07-29T16:54:54.000Z",
+ turn_count: 1,
+ provenance_kind: "native_subagent",
+ direct_child_parent_id: rootThreadId,
+ direct_child_root_id: rootThreadId,
+ },
+ },
+ },
+ },
+ });
+ await issueLocalNativeExecutorAssignment({
+ cwd,
+ stateDir,
+ sessionId,
+ rootThreadId,
+ childAgentId: childThreadId,
+ expectedGeneration: bootstrap.generation,
+ pathPrefixes: ["src/native-flow"],
+ ttlSeconds: 300,
+ });
+
+ const prepared = await dispatchCodexNativeHook(
+ { hook_event_name: "PreToolUse", ...activationPayload },
+ { cwd },
+ );
+ assert.equal(prepared.outputJson, null);
+ assert.equal((await readNativeUltragoalBootstrap(stateDir, sessionId))?.status, "activating");
+ const prematureWrite = await dispatchCodexNativeHook({
+ hook_event_name: "PreToolUse",
+ cwd,
+ session_id: sessionId,
+ thread_id: childThreadId,
+ agent_id: childThreadId,
+ agent_type: "executor",
+ source: "native",
+ tool_name: "Write",
+ tool_input: { file_path: join(cwd, "src", "native-flow", "premature.ts"), content: "no" },
+ }, { cwd });
+ assert.equal(prematureWrite.outputJson?.decision, "block");
+
+ await writeJson(join(stateDir, "sessions", sessionId, "ultragoal-state.json"), {
+ active: true,
+ current_phase: "executing",
+ run_outcome: "continue",
+ });
+ await dispatchCodexNativeHook({ hook_event_name: "PostToolUse", ...activationPayload }, { cwd });
+ assert.equal((await readNativeUltragoalBootstrap(stateDir, sessionId))?.status, "active");
+
+ await revokeLocalNativeExecutorAssignment({
+ stateDir,
+ sessionId,
+ reason: "activation_receipt_race",
+ });
+ await writeJson(join(stateDir, "sessions", sessionId, "ultragoal-state.json"), {
+ mode: "ultragoal",
+ active: true,
+ current_phase: "executing",
+ session_id: sessionId,
+ });
+ await dispatchCodexNativeHook({ hook_event_name: "PostToolUse", ...activationPayload }, { cwd });
+ const failedState = JSON.parse(readFileSync(
+ join(stateDir, "sessions", sessionId, "ultragoal-state.json"),
+ "utf-8",
+ )) as { active: boolean; current_phase: string; error?: string };
+ assert.equal(failedState.active, false);
+ assert.equal(failedState.current_phase, "failed");
+ assert.equal(failedState.error, "native_ultragoal_activation_receipt_invalid");
+ } finally {
+ await rm(cwd, { recursive: true, force: true });
+ }
+ });
+
+ it("allows exact root phase transitions for an active session when pointer PID identity is indeterminate", async () => {
+ delete process.env.TMUX;
+ process.env.OMX_NATIVE_SUBAGENT_ASSIGNMENTS = "on";
+ process.env.OMX_NATIVE_ULTRAGOAL_BACKEND = "local-experimental";
+ const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-active-phase-fallback-"));
+ try {
+ const stateDir = join(cwd, ".omx", "state");
+ const sessionId = "019faf7e-1006-7000-8000-000000000006";
+ const turnId = "turn-active-phase-fallback";
+ const childThreadId = "thread-active-phase-fallback-child";
+ process.env.CODEX_HOME = join(cwd, "codex-home");
+ await writeJson(join(stateDir, "session.json"), {
+ session_id: sessionId,
+ native_session_id: sessionId,
+ owner_codex_session_id: sessionId,
+ target_session_id: sessionId,
+ cwd,
+ state_root: stateDir,
+ pid: process.pid,
+ platform: "linux",
+ });
+ await writeRootTranscript(process.env.CODEX_HOME, sessionId, rootTranscriptRecord(sessionId, cwd, turnId));
+ const bootstrap = await beginNativeUltragoalBootstrap({
+ cwd,
+ stateDir,
+ sessionId,
+ rootThreadId: sessionId,
+ backend: "local-experimental",
+ ttlSeconds: 300,
+ });
+ await writeJson(join(stateDir, "subagent-tracking.json"), {
+ schemaVersion: 1,
+ sessions: {
+ [sessionId]: {
+ session_id: sessionId,
+ leader_thread_id: sessionId,
+ updated_at: bootstrap.created_at,
+ threads: {
+ [sessionId]: {
+ thread_id: sessionId,
+ kind: "leader",
+ first_seen_at: bootstrap.created_at,
+ last_seen_at: bootstrap.created_at,
+ turn_count: 1,
+ },
+ [childThreadId]: {
+ thread_id: childThreadId,
+ kind: "subagent",
+ mode: "executor",
+ status: "available",
+ first_seen_at: bootstrap.created_at,
+ last_seen_at: bootstrap.created_at,
+ turn_count: 1,
+ provenance_kind: "native_subagent",
+ direct_child_parent_id: sessionId,
+ direct_child_root_id: sessionId,
+ },
+ },
+ },
+ },
+ });
+ const childTranscriptPath = join(
+ process.env.CODEX_HOME,
+ "sessions",
+ "2026",
+ "07",
+ "29",
+ `rollout-2026-07-29T20-00-01-${childThreadId}.jsonl`,
+ );
+ await mkdir(dirname(childTranscriptPath), { recursive: true });
+ await writeFile(childTranscriptPath, `${JSON.stringify({
+ timestamp: bootstrap.created_at,
+ type: "session_meta",
+ payload: {
+ id: childThreadId,
+ session_id: sessionId,
+ cwd,
+ source: {
+ subagent: {
+ thread_spawn: {
+ parent_thread_id: sessionId,
+ depth: 1,
+ agent_path: "/root/active_phase_executor",
+ agent_role: "executor",
+ },
+ },
+ },
+ },
+ })}\n`);
+ await issueLocalNativeExecutorAssignment({
+ cwd,
+ stateDir,
+ sessionId,
+ rootThreadId: sessionId,
+ childAgentId: childThreadId,
+ expectedGeneration: bootstrap.generation,
+ pathPrefixes: ["src"],
+ ttlSeconds: 300,
+ });
+ assert.equal((await prepareNativeUltragoalBootstrapActivation({
+ cwd,
+ stateDir,
+ sessionId,
+ childAgentId: childThreadId,
+ })).ok, true);
+ assert.equal((await markNativeUltragoalBootstrapActive({
+ cwd,
+ stateDir,
+ sessionId,
+ childAgentId: childThreadId,
+ })).ok, true);
+ await writeJson(join(stateDir, "sessions", sessionId, "ultragoal-state.json"), {
+ active: true,
+ current_phase: "executing",
+ run_outcome: "continue",
+ });
+ await writeJson(join(stateDir, "sessions", sessionId, "skill-active-state.json"), {
+ version: 1,
+ active: true,
+ skill: "ultragoal",
+ phase: "executing",
+ session_id: sessionId,
+ thread_id: sessionId,
+ active_skills: [{ skill: "ultragoal", active: true, phase: "executing", session_id: sessionId }],
+ });
+
+ const exactPhasePayload = {
+ hook_event_name: "PreToolUse",
+ cwd,
+ session_id: sessionId,
+ turn_id: turnId,
+ source: "native",
+ tool_name: "Bash",
+ tool_input: {
+ command: `omx state write --input '${JSON.stringify({
+ mode: "ultragoal",
+ active: true,
+ current_phase: "verifying",
+ })}' --json`,
+ },
+ };
+ const trustedPackageBin = join(cwd, "node_modules", ".bin", "omx");
+ await mkdir(dirname(trustedPackageBin), { recursive: true });
+ const packageCli = realpathSync(resolve(process.cwd(), "dist", "cli", "omx.js"));
+ await symlink(packageCli, trustedPackageBin);
+ const exactAbsolutePhasePayload = {
+ ...exactPhasePayload,
+ tool_input: {
+ command: `${trustedPackageBin} state write --input '${JSON.stringify({
+ mode: "ultragoal",
+ active: true,
+ current_phase: "verifying",
+ })}' --json`,
+ },
+ };
+ const untrustedWorkspaceBin = join(cwd, "local-bin", "omx");
+ await mkdir(dirname(untrustedWorkspaceBin), { recursive: true });
+ await symlink(packageCli, untrustedWorkspaceBin);
+ const untrustedWorkspacePhasePayload = {
+ ...exactPhasePayload,
+ tool_input: {
+ command: `${untrustedWorkspaceBin} state write --input '${JSON.stringify({
+ mode: "ultragoal",
+ active: true,
+ current_phase: "verifying",
+ })}' --json`,
+ },
+ };
+ const identityIndeterminatePointer = {
+ status: "identity-indeterminate" as const,
+ state: {
+ session_id: sessionId,
+ native_session_id: sessionId,
+ cwd,
+ state_root: stateDir,
+ pid: process.pid,
+ platform: "darwin" as const,
+ started_at: bootstrap.created_at,
+ },
+ };
+ const rootTranscript = { sessionId, hasExactTurnContext: true, hasTypedNativeSpawn: true };
+ const stillBlockedWithoutFallbackPointer = await buildConductorPreToolUseWriteGuardOutput(
+ exactPhasePayload,
+ cwd,
+ stateDir,
+ sessionId,
+ cwd,
+ rootTranscript,
+ );
+ assert.equal(stillBlockedWithoutFallbackPointer?.decision, "block");
+ assert.equal(await buildConductorPreToolUseWriteGuardOutput(
+ exactPhasePayload,
+ cwd,
+ stateDir,
+ sessionId,
+ cwd,
+ rootTranscript,
+ identityIndeterminatePointer,
+ ), null);
+ assert.equal(await buildConductorPreToolUseWriteGuardOutput(
+ exactPhasePayload,
+ cwd,
+ stateDir,
+ sessionId,
+ cwd,
+ rootTranscript,
+ { ...identityIndeterminatePointer, status: "usable" as const },
+ ), null);
+ assert.equal(await buildConductorPreToolUseWriteGuardOutput(
+ exactAbsolutePhasePayload,
+ cwd,
+ stateDir,
+ sessionId,
+ cwd,
+ rootTranscript,
+ identityIndeterminatePointer,
+ ), null);
+ assert.equal((await buildConductorPreToolUseWriteGuardOutput(
+ untrustedWorkspacePhasePayload,
+ cwd,
+ stateDir,
+ sessionId,
+ cwd,
+ rootTranscript,
+ identityIndeterminatePointer,
+ ))?.decision, "block");
+
+ const dispatchPhase = async (
+ phase: string,
+ extraPayload: Record<string, unknown> = {},
+ identity: Record<string, unknown> = {},
+ ) => dispatchCodexNativeHook({
+ hook_event_name: "PreToolUse",
+ cwd,
+ session_id: sessionId,
+ turn_id: turnId,
+ source: "native",
+ ...identity,
+ tool_name: "Bash",
+ tool_input: {
+ command: `omx state write --input '${JSON.stringify({
+ mode: "ultragoal",
+ active: true,
+ current_phase: phase,
+ ...extraPayload,
+ })}' --json`,
+ },
+ }, { cwd });
+
+ for (const phase of ["planning", "executing", "verifying", "reviewing", "checkpointing", "blocked"]) {
+ assert.equal((await dispatchPhase(phase)).outputJson, null, `root phase ${phase} must be allowed`);
+ }
+
+ const unsafe = await dispatchPhase("verifying", { reason: "smuggled" });
+ assert.equal(unsafe.outputJson?.decision, "block");
+ assert.match(String(unsafe.outputJson?.reason ?? ""), /Main-root Conductor mode is active/);
+
+ const child = await dispatchPhase("verifying", {}, {
+ agent_id: childThreadId,
+ agent_type: "executor",
+ thread_id: childThreadId,
+ });
+ assert.equal(child.outputJson?.decision, "block");
+
+ const childGitPayload = {
+ hook_event_name: "PreToolUse",
+ cwd,
+ session_id: sessionId,
+ turn_id: turnId,
+ source: "native",
+ agent_id: childThreadId,
+ agent_type: "executor",
+ thread_id: childThreadId,
+ tool_name: "Bash",
+ };
+ const dispatchChildGit = (command: string) => dispatchCodexNativeHook({
+ ...childGitPayload,
+ tool_input: { command },
+ }, { cwd });
+ const childBoundedFind = await dispatchChildGit("find . -maxdepth 2 -type f");
+ assert.equal(childBoundedFind.outputJson, null);
+
+ for (const command of [
+ "git reset --hard",
+ "git status --short; git reset --hard",
+ "git status --short$(printf x)",
+ "git status --short\ngit reset --hard",
+ ]) {
+ assert.equal((await dispatchChildGit(command)).outputJson?.decision, "block", command);
+ }
+
+ await writeJson(join(stateDir, "sessions", sessionId, "ultragoal-state.json"), {
+ active: true,
+ current_phase: "checkpointing",
+ run_outcome: "continue",
+ });
+ await writeJson(join(cwd, ".omx", "ultragoal", "goals.json"), {
+ version: 1,
+ goals: [{ id: "G001-terminal", status: "complete" }],
+ aggregateCompletion: {
+ status: "complete",
+ completedAt: "2026-07-29T20:10:00.000Z",
+ evidence: "tests and independent reviews passed",
+ },
+ });
+ const terminalPayload = (input: Record<string, unknown>, identity: Record<string, unknown> = {}) => ({
+ hook_event_name: "PreToolUse",
+ cwd,
+ session_id: sessionId,
+ turn_id: turnId,
+ source: "native",
+ ...identity,
+ tool_name: "Bash",
+ tool_input: {
+ command: `omx state write --input '${JSON.stringify(input)}' --json`,
+ },
+ });
+ const exactTerminalInput = {
+ mode: "ultragoal",
+ active: false,
+ current_phase: "complete",
+ };
+ assert.equal(
+ (await dispatchCodexNativeHook(terminalPayload(exactTerminalInput), { cwd })).outputJson?.decision,
+ "block",
+ "terminal transition must remain blocked until executor authority is revoked",
+ );
+ await revokeLocalNativeExecutorAssignment({
+ stateDir,
+ sessionId,
+ reason: "aggregate_complete",
+ });
+ assert.equal(
+ (await dispatchCodexNativeHook(terminalPayload(exactTerminalInput), { cwd })).outputJson,
+ null,
+ "exact root terminal transition must be allowed after aggregate checkpoint and executor revocation",
+ );
+ await writeJson(join(cwd, ".omx", "ultragoal", "goals.json"), {
+ version: 1,
+ goals: [{ id: "G001-terminal", status: "in_progress" }],
+ aggregateCompletion: { status: "complete" },
+ });
+ assert.equal(
+ (await dispatchCodexNativeHook(terminalPayload(exactTerminalInput), { cwd })).outputJson?.decision,
+ "block",
+ "terminal transition must remain blocked when any repo-native goal is incomplete",
+ );
+ await writeJson(join(cwd, ".omx", "ultragoal", "goals.json"), {
+ version: 1,
+ goals: [{ id: "G001-terminal", status: "complete" }],
+ aggregateCompletion: { status: "complete", evidence: "проверки пройдены" },
+ });
+ assert.equal(
+ (await dispatchCodexNativeHook(terminalPayload(exactTerminalInput), { cwd })).outputJson,
+ null,
+ "UTF-8 aggregate evidence must not invalidate byte-size pinning",
+ );
+ assert.equal(
+ (await dispatchCodexNativeHook(terminalPayload({ ...exactTerminalInput, reason: "smuggled" }), { cwd })).outputJson?.decision,
+ "block",
+ );
+ assert.equal(
+ (await dispatchCodexNativeHook(terminalPayload(exactTerminalInput, {
+ agent_id: childThreadId,
+ agent_type: "executor",
+ thread_id: childThreadId,
+ }), { cwd })).outputJson?.decision,
+ "block",
+ );
+
+ await writeJson(join(stateDir, "sessions", sessionId, "ultragoal-state.json"), {
+ mode: "ultragoal",
+ active: false,
+ current_phase: "complete",
+ session_id: sessionId,
+ });
+ const terminal = await dispatchPhase("verifying");
+ assert.equal(terminal.outputJson?.decision, "block");
+ assert.match(String(terminal.outputJson?.reason ?? ""), /OMX-ULTRAGOAL-BOOTSTRAP-REQUIRED/);
+
+ assert.equal(await __isAuthorizedActiveUltragoalPhaseTransitionFallbackForTests({
+ payload: {
+ hook_event_name: "PreToolUse",
+ cwd,
+ session_id: sessionId,
+ turn_id: turnId,
+ source: "native",
+ tool_name: "Bash",
+ tool_input: { command: `omx state write --input '${ACTIVATION_INPUT}' --json` },
+ },
+ policyCwd: cwd,
+ stateDir,
+ sessionId,
+ pointer: {
+ status: "identity-indeterminate",
+ state: {
+ session_id: "foreign-active-phase-session",
+ native_session_id: "foreign-active-phase-session",
+ cwd,
+ state_root: stateDir,
+ pid: process.pid,
+ platform: "linux",
+ started_at: bootstrap.created_at,
+ },
+ },
+ rootTranscript: { sessionId, hasExactTurnContext: true, hasTypedNativeSpawn: true },
+ }), false);
+ } finally {
+ await rm(cwd, { recursive: true, force: true });
+ }
+ });
+
+ it("uses native bootstrap for an exact Codex Desktop root even when TMUX is inherited", async () => {
+ process.env.TMUX = "/tmp/tmux-3311-prompt,12345,0";
+ process.env.OMX_NATIVE_ULTRAGOAL_BACKEND = "local-experimental";
+ const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-3311-prompt-tmux-"));
+ try {
+ const stateDir = join(cwd, ".omx", "state");
+ const sessionId = "019fafca-1e7e-7372-9399-dffb68fc354e";
+ const turnId = "019fafca-tmux-inherited-turn";
+ process.env.CODEX_HOME = join(cwd, "codex-home");
+ await mkdir(stateDir, { recursive: true });
+ await writeRootTranscript(process.env.CODEX_HOME, sessionId, rootTranscriptRecord(
+ sessionId,
+ cwd,
+ turnId,
+ { source: "exec" },
+ ));
+
+ const result = await dispatchCodexNativeHook(
+ {
+ hook_event_name: "UserPromptSubmit",
+ cwd,
+ session_id: sessionId,
+ turn_id: turnId,
+ source: "native",
+ prompt: "$ultragoal split this launch into durable goals",
+ },
+ { cwd },
+ );
+
+ assert.equal(result.skillState?.active, false);
+ assert.equal(result.skillState?.skill, "ultragoal");
+ assert.equal(result.skillState?.phase, "bootstrap");
+ assert.match(String(result.skillState?.transition_error ?? ""), /OMX-ULTRAGOAL-BOOTSTRAP-REQUIRED/);
+ assert.equal((await readNativeUltragoalBootstrap(stateDir, sessionId))?.status, "awaiting-executor");
+ assert.equal(existsSync(join(stateDir, "sessions", sessionId, "ultragoal-state.json")), false);
+ } finally {
+ await rm(cwd, { recursive: true, force: true });
+ }
+ });
+
+ it("repairs an auxiliary notify tracker leader during exact App prompt bootstrap", async () => {
+ delete process.env.TMUX;
+ process.env.OMX_NATIVE_ULTRAGOAL_BACKEND = "local-experimental";
+ const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-app-auxiliary-leader-"));
+ try {
+ const stateDir = join(cwd, ".omx", "state");
+ const sessionId = "019fb294-0056-7a52-b4a0-e5141947b6d2";
+ const auxiliaryThreadId = "019fb294-4b7c-7a51-88aa-f919cee2e6d5";
+ const turnId = "019fb294-4b9f-7f90-a281-b3e1b056c21d";
+ process.env.CODEX_HOME = join(cwd, "codex-home");
+ await writeJson(join(stateDir, "session.json"), {
+ session_id: sessionId,
+ native_session_id: sessionId,
+ owner_codex_session_id: sessionId,
+ target_session_id: sessionId,
+ cwd,
+ state_root: stateDir,
+ pid: process.pid,
+ platform: process.platform,
+ });
+ await writeRootTranscript(process.env.CODEX_HOME, sessionId, rootTranscriptRecord(sessionId, cwd, turnId));
+ await writeJson(join(stateDir, "subagent-tracking.json"), {
+ schemaVersion: 1,
+ sessions: {
+ [sessionId]: {
+ session_id: sessionId,
+ leader_thread_id: auxiliaryThreadId,
+ updated_at: "2026-07-30T10:31:39.523Z",
+ threads: {
+ [auxiliaryThreadId]: {
+ thread_id: auxiliaryThreadId,
+ kind: "leader",
+ first_seen_at: "2026-07-30T10:31:39.523Z",
+ last_seen_at: "2026-07-30T10:31:39.523Z",
+ last_turn_id: "019fb294-4bd7-7e60-b398-289391b1f34b",
+ turn_count: 1,
+ },
+ },
+ },
+ },
+ });
+
+ const prompt = await dispatchCodexNativeHook({
+ hook_event_name: "UserPromptSubmit",
+ cwd,
+ session_id: sessionId,
+ turn_id: turnId,
+ source: "native",
+ available_tools: ["collaboration.spawn_agent"],
+ prompt: "$ultragoal continue the existing durable plan",
+ }, { cwd });
+ assert.equal(prompt.skillState?.active, false);
+ assert.match(String(prompt.skillState?.transition_error ?? ""), /OMX-ULTRAGOAL-BOOTSTRAP-REQUIRED/);
+ const promptBootstrap = await readNativeUltragoalBootstrap(stateDir, sessionId);
+ assert.equal(promptBootstrap?.root_thread_id, sessionId);
+
+ const tracking = JSON.parse(readFileSync(join(stateDir, "subagent-tracking.json"), "utf-8")) as {
+ sessions: Record<string, { leader_thread_id: string; threads: Record<string, unknown> }>;
+ };
+ assert.equal(tracking.sessions[sessionId]?.leader_thread_id, sessionId);
+ assert.equal(tracking.sessions[sessionId]?.threads[auxiliaryThreadId], undefined);
+ } finally {
+ await rm(cwd, { recursive: true, force: true });
+ }
+ });
+
+ it("repairs an auxiliary notify tracker leader during direct App activation retry", async () => {
+ delete process.env.TMUX;
+ process.env.OMX_NATIVE_ULTRAGOAL_BACKEND = "local-experimental";
+ const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-app-auxiliary-retry-"));
+ try {
+ const stateDir = join(cwd, ".omx", "state");
+ const sessionId = "019fb294-0056-7a52-b4a0-e5141947b6d2";
+ const auxiliaryThreadId = "019fb294-4b7c-7a51-88aa-f919cee2e6d5";
+ const turnId = "019fb294-4b9f-7f90-a281-b3e1b056c21d";
+ process.env.CODEX_HOME = join(cwd, "codex-home");
+ await writeJson(join(stateDir, "session.json"), {
+ session_id: sessionId,
+ native_session_id: sessionId,
+ owner_codex_session_id: sessionId,
+ target_session_id: sessionId,
+ cwd,
+ state_root: stateDir,
+ pid: process.pid,
+ platform: process.platform,
+ });
+ await writeRootTranscript(process.env.CODEX_HOME, sessionId, rootTranscriptRecord(sessionId, cwd, turnId));
+ await writeJson(join(stateDir, "subagent-tracking.json"), {
+ schemaVersion: 1,
+ sessions: {
+ [sessionId]: {
+ session_id: sessionId,
+ leader_thread_id: auxiliaryThreadId,
+ updated_at: "2026-07-30T10:31:39.523Z",
+ threads: {
+ [auxiliaryThreadId]: {
+ thread_id: auxiliaryThreadId,
+ kind: "leader",
+ first_seen_at: "2026-07-30T10:31:39.523Z",
+ last_seen_at: "2026-07-30T10:31:39.523Z",
+ last_turn_id: "019fb294-4bd7-7e60-b398-289391b1f34b",
+ turn_count: 1,
+ },
+ },
+ },
+ },
+ });
+
+ const result = await dispatchCodexNativeHook({
+ hook_event_name: "PreToolUse",
+ cwd,
+ session_id: sessionId,
+ turn_id: turnId,
+ source: "native",
+ available_tools: ["collaboration.spawn_agent"],
+ tool_name: "Bash",
+ tool_input: { command: `omx state write --input '${ACTIVATION_INPUT}' --json` },
+ }, { cwd });
+
+ assert.equal(result.outputJson?.decision, "block");
+ assert.match(String(result.outputJson?.reason ?? ""), /OMX-ULTRAGOAL-BOOTSTRAP-REQUIRED/);
+ const activationBootstrap = await readNativeUltragoalBootstrap(stateDir, sessionId);
+ assert.equal(activationBootstrap?.root_thread_id, sessionId);
+ const tracking = JSON.parse(readFileSync(join(stateDir, "subagent-tracking.json"), "utf-8")) as {
+ sessions: Record<string, { leader_thread_id: string; threads: Record<string, unknown> }>;
+ };
+ assert.equal(tracking.sessions[sessionId]?.leader_thread_id, sessionId);
+ assert.equal(tracking.sessions[sessionId]?.threads[auxiliaryThreadId], undefined);
+ } finally {
+ await rm(cwd, { recursive: true, force: true });
+ }
+ });
+
+ it("does not re-block continuation of an already-active '$ultragoal' UserPromptSubmit session outside tmux", async () => {
+ delete process.env.TMUX;
+ const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-3311-prompt-continue-"));
+ try {
+ const stateDir = join(cwd, ".omx", "state");
+ const sessionId = "sess-3311-prompt-continue";
+ const leaderThreadId = "thread-3311-prompt-continue";
+ await writeLeaderSessionFixture(stateDir, sessionId, leaderThreadId, cwd);
+ await writeJson(join(stateDir, "sessions", sessionId, "skill-active-state.json"), {
+ active: true,
+ skill: "ultragoal",
+ phase: "planning",
+ session_id: sessionId,
+ active_skills: [{ skill: "ultragoal", phase: "planning", active: true, session_id: sessionId }],
+ });
+ await writeJson(join(stateDir, "sessions", sessionId, "ultragoal-state.json"), {
+ active: true,
+ mode: "ultragoal",
+ current_phase: "planning",
+ session_id: sessionId,
+ });
+
+ const result = await dispatchCodexNativeHook(
+ {
+ hook_event_name: "UserPromptSubmit",
+ cwd,
+ session_id: sessionId,
+ thread_id: leaderThreadId,
+ turn_id: "turn-3311-prompt-continue",
+ source: "native",
+ prompt: "$ultragoal continue with the next milestone",
+ },
+ { cwd },
+ );
+
+ assert.doesNotMatch(String(result.skillState?.transition_error ?? ""), /OMX-ULTRAGOAL-NO-OWNER/);
+ } finally {
+ await rm(cwd, { recursive: true, force: true });
+ }
+ });
+
+ it("allows only the exact standalone Ralplan root review control plane", async () => {
+ delete process.env.TMUX;
+ const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-ralplan-root-review-"));
+ const installRoot = await mkdtemp(join(tmpdir(), "omx-native-hook-ralplan-install-"));
+ try {
+ const stateDir = join(cwd, ".omx", "state");
+ const sessionId = "019fb315-a6a4-7363-b35e-142f4141139e";
+ const turnId = "turn-ralplan-root-review";
+ process.env.CODEX_HOME = join(cwd, "codex-home");
+ await writeJson(join(stateDir, "session.json"), {
+ session_id: sessionId,
+ native_session_id: sessionId,
+ owner_codex_session_id: sessionId,
+ target_session_id: sessionId,
+ cwd,
+ state_root: stateDir,
+ pid: process.pid,
+ platform: process.platform,
+ started_at: new Date().toISOString(),
+ });
+ await writeRootTranscript(process.env.CODEX_HOME, sessionId, rootTranscriptRecord(sessionId, cwd, turnId));
+ await writeJson(join(stateDir, "sessions", sessionId, "skill-active-state.json"), {
+ active: true,
+ skill: "ralplan",
+ phase: "planning",
+ session_id: sessionId,
+ active_skills: [{ skill: "ralplan", phase: "planning", active: true, session_id: sessionId }],
+ });
+ await writeJson(join(stateDir, "sessions", sessionId, "ralplan-state.json"), {
+ active: true,
+ mode: "ralplan",
+ current_phase: "planning",
+ session_id: sessionId,
+ workingDirectory: cwd,
+ });
+ await writeJson(join(stateDir, "subagent-tracking.json"), {
+ schemaVersion: 1,
+ sessions: {
+ [sessionId]: {
+ session_id: sessionId,
+ leader_thread_id: sessionId,
+ threads: { [sessionId]: { thread_id: sessionId, kind: "leader" } },
+ },
+ },
+ });
+ await mkdir(join(cwd, ".omx", "plans"), { recursive: true });
+ await mkdir(join(cwd, ".omx", "specs"), { recursive: true });
+ await writeFile(join(cwd, ".omx", "plans", "ralplan-draft.md"), "# Draft\n");
+ await writeFile(join(cwd, ".omx", "specs", "ralplan-tests.md"), "# Tests\n");
+
+ const dispatch = (toolName: string, toolInput: unknown, identity: Record<string, unknown> = {}) =>
+ dispatchCodexNativeHook({
+ hook_event_name: "PreToolUse",
+ cwd,
+ session_id: sessionId,
+ turn_id: turnId,
+ source: "native",
+ ...identity,
+ tool_name: toolName,
+ tool_input: toolInput,
+ }, { cwd });
+ const architect = {
+ agent_type: "architect",
+ fork_turns: "none",
+ message: "Review the bounded Ralplan draft and report findings only.",
+ task_name: "ralplan_architect_review",
+ };
+ const absoluteOmx = join(installRoot, "bin", "omx");
+ await mkdir(dirname(absoluteOmx), { recursive: true });
+ await symlink(realpathSync(resolve(process.cwd(), "dist", "cli", "omx.js")), absoluteOmx);
+ for (const command of [
+ `${absoluteOmx} state read --input '${JSON.stringify({ mode: "ralplan", session_id: sessionId, workingDirectory: cwd })}' --json`,
+ `${absoluteOmx} state list-active --json`,
+ ]) {
+ assert.equal((await dispatch("Bash", { command })).outputJson, null, command);
+ }
+
+ assert.equal((await dispatch("collaboration.spawn_agent", architect)).outputJson?.decision, "block");
+ await writeJson(join(stateDir, "sessions", sessionId, "ralplan-state.json"), {
+ active: true,
+ mode: "ralplan",
+ current_phase: "architect-review",
+ session_id: sessionId,
+ workingDirectory: cwd,
+ });
+ await writeJson(join(stateDir, "session.json"), {
+ session_id: sessionId,
+ native_session_id: sessionId,
+ owner_codex_session_id: sessionId,
+ target_session_id: sessionId,
+ cwd,
+ state_root: join(cwd, "foreign-state"),
+ pid: process.pid,
+ platform: process.platform,
+ started_at: new Date().toISOString(),
+ });
+ assert.equal((await dispatch("collaboration.spawn_agent", architect)).outputJson?.decision, "block");
+ await writeJson(join(stateDir, "session.json"), {
+ session_id: sessionId,
+ native_session_id: sessionId,
+ owner_codex_session_id: "foreign-session",
+ target_session_id: sessionId,
+ cwd,
+ pid: process.pid,
+ platform: process.platform === "linux" ? "darwin" : "linux",
+ started_at: new Date().toISOString(),
+ });
+ assert.equal((await dispatch("collaboration.spawn_agent", architect)).outputJson?.decision, "block");
+ await writeJson(join(stateDir, "session.json"), {
+ session_id: "omx-canonical-ralplan",
+ native_session_id: sessionId,
+ owner_omx_session_id: "omx-owner-ralplan",
+ owner_codex_session_id: sessionId,
+ target_session_id: sessionId,
+ cwd,
+ pid: process.pid,
+ platform: process.platform === "linux" ? "darwin" : "linux",
+ started_at: new Date().toISOString(),
+ });
+ assert.equal((await dispatch("collaboration.spawn_agent", architect)).outputJson, null);
+ await writeJson(join(stateDir, "session.json"), {
+ session_id: sessionId,
+ native_session_id: sessionId,
+ owner_codex_session_id: sessionId,
+ target_session_id: sessionId,
+ cwd,
+ state_root: stateDir,
+ pid: process.pid,
+ platform: process.platform,
+ started_at: new Date().toISOString(),
+ });
+ assert.equal((await dispatch("collaboration.list_agents", {})).outputJson, null);
+ assert.equal((await dispatch("collaboration.wait_agent", { timeout_ms: 10000 })).outputJson, null);
+ assert.equal((await dispatch("collaboration.list_agents", { extra: true })).outputJson?.decision, "block");
+ for (const malformedInput of [undefined, null, "invalid", 42, []]) {
+ assert.equal((await dispatch("collaboration.list_agents", malformedInput)).outputJson?.decision, "block");
+ assert.equal((await dispatch("collaboration.wait_agent", malformedInput)).outputJson?.decision, "block");
+ }
+ for (const timeoutMs of [undefined, 9_999, 3_600_001, "10000", true]) {
+ const input = timeoutMs === undefined ? {} : { timeout_ms: timeoutMs };
+ assert.equal((await dispatch("collaboration.wait_agent", input)).outputJson?.decision, "block");
+ }
+
+ for (const unsafe of [
+ { ...architect, fork_turns: "all" },
+ { ...architect, agent_type: "executor" },
+ { ...architect, extra: true },
+ ]) {
+ assert.equal((await dispatch("collaboration.spawn_agent", unsafe)).outputJson?.decision, "block");
+ }
+ assert.equal((await dispatch("collaboration.spawn_agent", architect, {
+ agent_id: "foreign-child",
+ agent_type: "architect",
+ thread_id: "foreign-child",
+ })).outputJson?.decision, "block");
+
+ await writeJson(join(stateDir, "sessions", sessionId, "ralplan-state.json"), {
+ active: true,
+ mode: "ralplan",
+ current_phase: "critic-review",
+ session_id: sessionId,
+ workingDirectory: cwd,
+ });
+ const critic = {
+ agent_type: "critic",
+ fork_turns: "none",
+ message: "Review the Ralplan draft after the architect pass and report findings only.",
+ task_name: "ralplan_critic_review",
+ };
+ assert.equal((await dispatch("collaboration.spawn_agent", critic)).outputJson?.decision, "block");
+ await writeFile(join(cwd, ".omx", "plans", "ralplan-architect-review.md"), "# Architect review\nPASS\n");
+ const validArchitectReview = {
+ agent_role: "architect",
+ verdict: "APPROVE",
+ artifact_path: ".omx/plans/ralplan-architect-review.md",
+ sequence_index: 1,
+ };
+ for (const invalidGate of [
+ { complete: false, ralplan_architect_review: { ...validArchitectReview, sequence_index: "1" } },
+ { complete: false, ralplan_architect_review: { ...validArchitectReview, sequence_index: true } },
+ { complete: false, ralplan_architect_review: { ...validArchitectReview, sequence_index: 0 } },
+ { complete: false, ralplan_architect_review: { ...validArchitectReview, sequence_index: 6 } },
+ { complete: true, ralplan_architect_review: validArchitectReview },
+ {
+ complete: false,
+ ralplan_architect_review: validArchitectReview,
+ ralplan_critic_review: { agent_role: "critic", verdict: "APPROVE", sequence_index: 2 },
+ },
+ ]) {
+ await writeJson(join(stateDir, "sessions", sessionId, "ralplan-state.json"), {
+ active: true,
+ mode: "ralplan",
+ current_phase: "critic-review",
+ session_id: sessionId,
+ workingDirectory: cwd,
+ ralplan_consensus_gate: invalidGate,
+ });
+ assert.equal((await dispatch("collaboration.spawn_agent", critic)).outputJson?.decision, "block");
+ }
+ for (const sequenceIndex of [1, 5]) {
+ await writeJson(join(stateDir, "sessions", sessionId, "ralplan-state.json"), {
+ active: true,
+ mode: "ralplan",
+ current_phase: "critic-review",
+ session_id: sessionId,
+ workingDirectory: cwd,
+ ralplan_consensus_gate: {
+ complete: false,
+ ralplan_architect_review: { ...validArchitectReview, sequence_index: sequenceIndex },
+ },
+ });
+ assert.equal((await dispatch("collaboration.spawn_agent", {
+ ...critic,
+ task_name: `ralplan_critic_review_iteration_${sequenceIndex}`,
+ })).outputJson, null);
+ }
+ } finally {
+ await rm(cwd, { recursive: true, force: true });
+ await rm(installRoot, { recursive: true, force: true });
+ }
+ });
+
+ it("does not block the primary '$ultragoal' UserPromptSubmit activation from a non-native (CLI) launcher outside tmux", async () => {
+ delete process.env.TMUX;
+ const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-3311-prompt-cli-"));
+ try {
+ await mkdir(join(cwd, ".omx", "state"), { recursive: true });
+
+ const result = await dispatchCodexNativeHook(
+ {
+ hook_event_name: "UserPromptSubmit",
+ cwd,
+ session_id: "sess-3311-prompt-cli",
+ thread_id: "thread-3311-prompt-cli",
+ turn_id: "turn-3311-prompt-cli",
+ source: "cli",
+ prompt: "$ultragoal split this launch into durable goals",
+ },
+ { cwd },
+ );
+
+ assert.equal(result.skillState?.initialized_mode, "ultragoal");
+ assert.equal(result.skillState?.transition_error, undefined);
+ } finally {
+ await rm(cwd, { recursive: true, force: true });
+ }
+ });
+
+ // --- Autopilot-supervised child recognition must not be intercepted ---
+ // #3311 repair-2: the prompt guard must refuse only a truly *standalone*
+ // fresh Ultragoal activation. When Autopilot is already active and
+ // supervising a child phase (e.g. ralplan), a "$ultragoal" prompt is a
+ // supervised-child transition handled entirely by recordSkillActivation's
+ // own isAutopilotSupervisedChildSkill branch; it must remain reachable on
+ // native App outside tmux exactly as it was on the pre-#3311-fix baseline.
+
+ it("does not intercept Autopilot-supervised '$ultragoal' child-phase recognition on native App outside tmux", async () => {
+ delete process.env.TMUX;
+ const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-3311-autopilot-supervised-"));
+ try {
+ const stateDir = join(cwd, ".omx", "state");
+ const sessionId = "sess-3311-autopilot-supervised";
+ const threadId = "thread-3311-autopilot-supervised";
+ await mkdir(join(stateDir, "sessions", sessionId), { recursive: true });
+ await writeJson(join(stateDir, "sessions", sessionId, "skill-active-state.json"), {
+ active: true,
+ skill: "autopilot",
+ phase: "ralplan",
+ session_id: sessionId,
+ active_skills: [{ skill: "autopilot", phase: "ralplan", active: true, session_id: sessionId }],
+ });
+ await writeJson(join(stateDir, "sessions", sessionId, "autopilot-state.json"), {
+ active: true,
+ mode: "autopilot",
+ current_phase: "ralplan",
+ session_id: sessionId,
+ state: {
+ handoff_artifacts: {
+ ralplan_consensus_gate: { required: true, complete: false },
+ },
+ },
+ });
+
+ const result = await dispatchCodexNativeHook(
+ {
+ hook_event_name: "UserPromptSubmit",
+ cwd,
+ session_id: sessionId,
+ thread_id: threadId,
+ turn_id: "turn-3311-autopilot-supervised",
+ source: "native",
+ prompt: "$ultragoal turn the approved plan into durable goals",
+ },
+ { cwd },
+ );
+
+ assert.equal(result.omxEventName, "keyword-detector");
+ assert.equal(result.skillState?.active, true);
+ assert.equal(result.skillState?.skill, "autopilot");
+ assert.equal(result.skillState?.supervised_child_skill, "ultragoal");
+ assert.equal(result.skillState?.transition_error, undefined);
+ assert.doesNotMatch(String(result.skillState?.transition_error ?? ""), /OMX-ULTRAGOAL-NO-OWNER/);
+ const message = String(
+ (result.outputJson as { hookSpecificOutput?: { additionalContext?: string } } | null)
+ ?.hookSpecificOutput?.additionalContext || "",
+ );
+ assert.doesNotMatch(message, /OMX-ULTRAGOAL-NO-OWNER/);
+ } finally {
+ await rm(cwd, { recursive: true, force: true });
+ }
+ });
+
+ it("keeps a completed standalone Ralplan to Ultragoal handoff inactive until executor authorization", async () => {
+ delete process.env.TMUX;
+ process.env.OMX_NATIVE_SUBAGENT_ASSIGNMENTS = "on";
+ process.env.OMX_NATIVE_ULTRAGOAL_BACKEND = "local-experimental";
+ const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-ralplan-ultragoal-bootstrap-"));
+ try {
+ const stateDir = join(cwd, ".omx", "state");
+ const sessionId = "sess-ralplan-ultragoal-bootstrap";
+ const threadId = "thread-ralplan-ultragoal-bootstrap";
+ await writeLeaderSessionFixture(stateDir, sessionId, threadId, cwd);
+ await writeJson(join(stateDir, "sessions", sessionId, "skill-active-state.json"), {
+ active: false,
+ skill: "ralplan",
+ phase: "complete",
+ session_id: sessionId,
+ owner_codex_session_id: sessionId,
+ target_session_id: sessionId,
+ active_skills: [{
+ skill: "ralplan",
+ phase: "complete",
+ active: false,
+ session_id: sessionId,
+ owner_codex_session_id: sessionId,
+ }],
+ });
+ await writeJson(join(stateDir, "sessions", sessionId, "ralplan-state.json"), {
+ active: false,
+ mode: "ralplan",
+ current_phase: "complete",
+ session_id: sessionId,
+ owner_codex_session_id: sessionId,
+ target_session_id: sessionId,
+ });
+
+ const result = await dispatchCodexNativeHook(
+ {
+ hook_event_name: "UserPromptSubmit",
+ cwd,
+ session_id: sessionId,
+ thread_id: threadId,
+ source: "native",
+ available_tools: ["collaboration.spawn_agent"],
+ prompt: "$ultragoal execute the approved plan",
+ },
+ { cwd },
+ );
+
+ assert.equal(result.skillState?.active, false);
+ assert.equal(result.skillState?.skill, "ultragoal");
+ assert.match(String(result.skillState?.transition_error ?? ""), /OMX-ULTRAGOAL-BOOTSTRAP-REQUIRED/);
+ assert.equal(
+ existsSync(join(stateDir, "sessions", sessionId, "ultragoal-state.json")),
+ false,
+ );
} finally {
await rm(cwd, { recursive: true, force: true });
}
diff --git a/src/scripts/codex-native-hook.ts b/src/scripts/codex-native-hook.ts
index 8c74a5d4875240cdd4c9dd28b4bfd442bc824f59..0076c8b3b8f160f1d41a94a708a0139014e49347 100644
--- a/src/scripts/codex-native-hook.ts
+++ b/src/scripts/codex-native-hook.ts
@@ -1,6 +1,6 @@
import { execFileSync } from "child_process";
-import { accessSync, closeSync, constants as fsConstants, existsSync, lstatSync, openSync, readFileSync, readSync, readdirSync, realpathSync, statSync } from "fs";
-import { appendFile, lstat, mkdir, open, readFile, readdir, stat, unlink, writeFile } from "fs/promises";
+import { accessSync, closeSync, constants as fsConstants, existsSync, lstatSync, openSync, readFileSync, readSync, readdirSync, realpathSync, statSync, type Dirent } from "fs";
+import { appendFile, lstat, mkdir, open, readFile, readdir, stat, unlink, writeFile, type FileHandle } from "fs/promises";
import { basename, delimiter, dirname, extname, isAbsolute, join, relative, resolve } from "path";
import { createHash } from "crypto";
@@ -39,6 +39,7 @@ import {
resolveWorkerTeamStateRootPath,
} from "../team/state-root.js";
import { inferTerminalLifecycleOutcome } from "../runtime/run-outcome.js";
+import { syncRegularFile } from "../utils/file-durability.js";
import {
appendPromptSessionProvenanceRejection,
appendToLog,
@@ -54,6 +55,7 @@ import {
reconcileNativeSessionStart,
resolveSessionPointerContext,
type SessionStartOptions,
+ type SessionPointerReadResult,
writeNativeSessionOwner,
type SessionState,
} from "../hooks/session.js";
@@ -76,6 +78,7 @@ import {
import { parseTeamNoticeLedgerPrompt, reconcileTeamNoticeLedger } from "../team/notice-ledger.js";
import {
canonicalizeComparablePath,
+ codexHome,
omxNotepadPath,
resolveProjectMemoryPath,
sameFilePath,
@@ -97,6 +100,7 @@ import {
} from "../hooks/keyword-detector.js";
import { buildDeepInterviewConfigInstruction } from "../hooks/deep-interview-config-instruction.js";
import { readTeamModeConfig } from "../config/team-mode.js";
+import { resolveNativeUltragoalConfig } from "../config/native-ultragoal.js";
import {
detectNativeStopStallPattern,
loadAutoNudgeConfig,
@@ -165,6 +169,20 @@ import {
steerUltragoal,
type UltragoalSteeringProposal,
} from "../ultragoal/artifacts.js";
+import {
+ beginNativeUltragoalBootstrap,
+ DOCUMENTED_HOST_RECEIPT_UNAVAILABLE,
+ findReadyLocalNativeExecutorAssignment,
+ markNativeUltragoalBootstrapActive,
+ NATIVE_ASSIGNMENT_DIRECTORY,
+ nativeExecutorAssignmentFileIsSafe,
+ parseActiveLocalNativeExecutorAssignment,
+ prepareNativeUltragoalBootstrapActivation,
+ readNativeUltragoalBootstrap,
+ reconcileLocalNativeExecutorAssignments,
+ revokeLocalNativeExecutorAssignment,
+ validateLocalNativeExecutorIdentity,
+} from "../ultragoal/native-bootstrap.js";
import { triagePrompt } from "../hooks/triage-heuristic.js";
import { readTriageConfig } from "../hooks/triage-config.js";
import {
@@ -206,6 +224,11 @@ interface NativeHookDispatchOptions {
/** @internal Scoped deterministic SessionStart durability seam for native-hook tests. */
sessionStartOptions?: Pick<SessionStartOptions, 'platform' | 'regularFileSync'>;
reconcileHudForPromptSubmitFn?: typeof reconcileHudForPromptSubmit;
+ /** @internal Deterministic pinned-transcript race seam for native-hook tests. */
+ rootTranscriptPostReadHook?: (path: string) => void | Promise<void>;
+ /** @internal Deterministic transcript traversal seams for native-hook tests. */
+ rootTranscriptBeforeReadDirHook?: (path: string) => void | Promise<void>;
+ rootTranscriptScanMaxEntries?: number;
}
export interface NativeHookDispatchResult {
@@ -281,6 +304,11 @@ const RALPH_INTENT_STOPWORDS = new Set([
"ralph", "continue", "resume", "finish", "complete", "fix", "issue",
]);
const MAX_SESSION_META_LINE_BYTES = 256 * 1024;
+const MAX_ROOT_TRANSCRIPT_FIRST_LINE_BYTES = 64 * 1024;
+const ROOT_TRANSCRIPT_REVERSE_SCAN_CHUNK_BYTES = 1024 * 1024;
+const MAX_ROOT_TRANSCRIPT_INITIAL_TURN_SCAN_BYTES = 16 * 1024 * 1024;
+const MAX_ROOT_TRANSCRIPT_RECORD_BYTES = 16 * 1024 * 1024;
+const MAX_ROOT_TRANSCRIPT_SCAN_ENTRIES = 10_000;
function safeString(value: unknown): string {
return typeof value === "string" ? value : "";
@@ -428,6 +456,297 @@ function readBoundedFirstLineSync(path: string): string {
}
}
+interface SafeRootTranscriptMetadata {
+ sessionId: string;
+ hasExactTurnContext: boolean;
+ hasTypedNativeSpawn: boolean;
+}
+
+async function readInitialRootTurnContext(
+ handle: FileHandle,
+ fileSize: number,
+ startOffset: number,
+): Promise<Record<string, unknown> | null> {
+ let cursor = startOffset;
+ let scannedBytes = 0;
+ let partialRecord = Buffer.alloc(0);
+ while (cursor < fileSize && scannedBytes < MAX_ROOT_TRANSCRIPT_INITIAL_TURN_SCAN_BYTES) {
+ const readBytes = Math.min(
+ ROOT_TRANSCRIPT_REVERSE_SCAN_CHUNK_BYTES,
+ fileSize - cursor,
+ MAX_ROOT_TRANSCRIPT_INITIAL_TURN_SCAN_BYTES - scannedBytes,
+ );
+ const chunk = Buffer.alloc(readBytes);
+ const read = await handle.read(chunk, 0, readBytes, cursor);
+ if (read.bytesRead !== readBytes) return null;
+ const combined = partialRecord.length > 0
+ ? Buffer.concat([partialRecord, chunk])
+ : chunk;
+ let recordStart = 0;
+ for (let index = 0; index < combined.length; index += 1) {
+ if (combined[index] !== 0x0a) continue;
+ if (index > recordStart) {
+ if (index - recordStart > MAX_ROOT_TRANSCRIPT_RECORD_BYTES) return null;
+ try {
+ const candidate = safeObject(JSON.parse(combined.subarray(recordStart, index).toString("utf8")));
+ if (safeString(candidate?.type).trim() === "turn_context") return candidate;
+ } catch {
+ return null;
+ }
+ }
+ recordStart = index + 1;
+ }
+ partialRecord = Buffer.from(combined.subarray(recordStart));
+ if (partialRecord.length > MAX_ROOT_TRANSCRIPT_RECORD_BYTES) return null;
+ cursor += readBytes;
+ scannedBytes += readBytes;
+ }
+ return null;
+}
+
+async function readLatestRootTurnContext(
+ handle: FileHandle,
+ fileSize: number,
+): Promise<Record<string, unknown> | null> {
+ if (fileSize <= 0) return null;
+ const finalByte = Buffer.alloc(1);
+ const finalRead = await handle.read(finalByte, 0, 1, fileSize - 1);
+ if (finalRead.bytesRead !== 1 || finalByte[0] !== 0x0a) return null;
+
+ let cursor = fileSize;
+ let partialRecord = Buffer.alloc(0);
+ let latestTurnContext: Record<string, unknown> | null = null;
+ while (cursor > 0) {
+ const readBytes = Math.min(ROOT_TRANSCRIPT_REVERSE_SCAN_CHUNK_BYTES, cursor);
+ const start = cursor - readBytes;
+ const chunk = Buffer.alloc(readBytes);
+ const read = await handle.read(chunk, 0, readBytes, start);
+ if (read.bytesRead !== readBytes) return null;
+ const combined = partialRecord.length > 0
+ ? Buffer.concat([chunk, partialRecord])
+ : chunk;
+
+ const newlineOffsets: number[] = [];
+ for (let index = 0; index < combined.length; index += 1) {
+ if (combined[index] === 0x0a) newlineOffsets.push(index);
+ }
+ const firstCompleteRecord = start > 0 ? 1 : 0;
+ const boundaries = [-1, ...newlineOffsets, combined.length];
+ for (let index = boundaries.length - 2; index >= firstCompleteRecord; index -= 1) {
+ const recordStart = boundaries[index]! + 1;
+ const recordEnd = boundaries[index + 1]!;
+ if (recordEnd <= recordStart) continue;
+ if (recordEnd - recordStart > MAX_ROOT_TRANSCRIPT_RECORD_BYTES) return null;
+ try {
+ const candidate = safeObject(JSON.parse(combined.subarray(recordStart, recordEnd).toString("utf8")));
+ if (!latestTurnContext && safeString(candidate?.type).trim() === "turn_context") {
+ latestTurnContext = candidate;
+ }
+ } catch {
+ return null;
+ }
+ }
+
+ const incompleteEnd = newlineOffsets[0] ?? combined.length;
+ partialRecord = Buffer.from(combined.subarray(0, incompleteEnd));
+ if (partialRecord.length > MAX_ROOT_TRANSCRIPT_RECORD_BYTES) return null;
+ cursor = start;
+ }
+ return latestTurnContext;
+}
+
+function readStrictStringAliasClaim(
+ record: Record<string, unknown>,
+ keys: readonly string[],
+): { present: boolean; valid: boolean; values: string[] } {
+ const presentKeys = keys.filter((key) => Object.prototype.hasOwnProperty.call(record, key));
+ if (presentKeys.length === 0) return { present: false, valid: true, values: [] };
+ const values: string[] = [];
+ for (const key of presentKeys) {
+ const value = record[key];
+ if (typeof value !== "string" || !value.trim()) return { present: true, valid: false, values: [] };
+ values.push(value.trim());
+ }
+ return { present: true, valid: new Set(values).size === 1, values: [...new Set(values)] };
+}
+
+async function findLiveRootTranscriptPaths(
+ sessionId: string,
+ options: {
+ beforeReadDirHook?: (path: string) => void | Promise<void>;
+ maxEntries?: number;
+ } = {},
+): Promise<string[] | null> {
+ const suffix = `-${sessionId}.jsonl`;
+ const matches: string[] = [];
+ const pending = [{ path: join(codexHome(), "sessions"), depth: 0 }];
+ const maxEntries = options.maxEntries ?? MAX_ROOT_TRANSCRIPT_SCAN_ENTRIES;
+ let visited = 0;
+
+ while (pending.length > 0 && visited < maxEntries) {
+ const current = pending.shift()!;
+ let entries: Dirent[];
+ try {
+ if (options.beforeReadDirHook) await options.beforeReadDirHook(current.path);
+ entries = await readdir(current.path, { withFileTypes: true });
+ } catch {
+ return null;
+ }
+ if (visited + entries.length > maxEntries) return null;
+ visited += entries.length;
+ for (const entry of entries) {
+ const path = join(current.path, entry.name);
+ if (entry.isDirectory() && current.depth < 4) {
+ pending.push({ path, depth: current.depth + 1 });
+ } else if (entry.isFile() && entry.name.endsWith(suffix)) {
+ matches.push(path);
+ if (matches.length > 1) return matches;
+ }
+ }
+ }
+ return pending.length === 0 ? matches : null;
+}
+
+async function readSafeRootTranscriptMetadata(
+ payload: CodexHookPayload,
+ cwd: string,
+ postReadHook?: (path: string) => void | Promise<void>,
+ scanOptions: {
+ beforeReadDirHook?: (path: string) => void | Promise<void>;
+ maxEntries?: number;
+ } = {},
+): Promise<SafeRootTranscriptMetadata | null> {
+ const hasAnyAlias = (keys: readonly string[]): boolean => keys.some((key) => (
+ Object.prototype.hasOwnProperty.call(payload, key)
+ ));
+ if (
+ payloadHasConflictingIdentityAliases(payload)
+ || hasSubagentThreadSpawnProvenance(payload)
+ || hasAnyAlias([
+ "owner_codex_thread_id",
+ "owner_omx_session_id",
+ "owner_codex_session_id",
+ "native_owner_session_id",
+ ])
+ || hasAnyAlias([
+ "agent_id",
+ "agentId",
+ "agent_role",
+ "agentRole",
+ "agent_type",
+ "agentType",
+ ])
+ ) return null;
+ const sessionClaim = readStrictStringAliasClaim(payload, ["session_id", "sessionId"]);
+ const sessionId = sessionClaim.values[0] ?? "";
+ const threadClaim = readStrictStringAliasClaim(payload, ["thread_id", "threadId"]);
+ if (
+ !sessionClaim.valid
+ || !sessionClaim.present
+ || !sessionId
+ || !threadClaim.valid
+ || (threadClaim.present && threadClaim.values[0] !== sessionId)
+ ) return null;
+
+ const paths = await findLiveRootTranscriptPaths(sessionId, scanOptions);
+ if (!paths || paths.length !== 1) return null;
+ const path = paths[0]!;
+ const metadata = await lstat(path).catch(() => null);
+ if (
+ !metadata
+ || !metadata.isFile()
+ || metadata.isSymbolicLink()
+ || metadata.nlink !== 1
+ || (metadata.mode & 0o022) !== 0
+ ) return null;
+
+ const handle = await open(path, fsConstants.O_RDONLY | (fsConstants.O_NOFOLLOW ?? 0)).catch(() => null);
+ if (!handle) return null;
+ try {
+ const openedMetadata = await handle.stat();
+ if (
+ !openedMetadata.isFile()
+ || openedMetadata.nlink !== 1
+ || (openedMetadata.mode & 0o022) !== 0
+ || openedMetadata.dev !== metadata.dev
+ || openedMetadata.ino !== metadata.ino
+ ) return null;
+ const snapshot = await (async (): Promise<SafeRootTranscriptMetadata | null> => {
+ const buffer = Buffer.alloc(MAX_ROOT_TRANSCRIPT_FIRST_LINE_BYTES);
+ const { bytesRead } = await handle.read(buffer, 0, buffer.length, 0);
+ const newline = buffer.subarray(0, bytesRead).indexOf(0x0a);
+ if (newline < 0) return null;
+ const record = safeObject(JSON.parse(buffer.subarray(0, newline).toString("utf8")));
+ if (safeString(record?.type).trim() !== "session_meta") return null;
+ const transcriptPayload = safeObject(record?.payload);
+ if (!transcriptPayload || safeString(transcriptPayload.id).trim() !== sessionId) return null;
+ const transcriptSessionClaim = readStrictStringAliasClaim(transcriptPayload, ["session_id", "sessionId"]);
+ if (!transcriptSessionClaim.valid || (transcriptSessionClaim.present && transcriptSessionClaim.values[0] !== sessionId)) return null;
+ const threadSourceClaim = readStrictStringAliasClaim(transcriptPayload, ["thread_source", "threadSource"]);
+ if (!threadSourceClaim.valid || !threadSourceClaim.present || threadSourceClaim.values[0] !== "user") return null;
+ const source = transcriptPayload.source;
+ if (!["vscode", "exec"].includes(safeString(source).trim())) return null;
+ if (safeString(transcriptPayload.originator).trim() !== "Codex Desktop") return null;
+ const sourceObject = safeObject(source);
+ if (sourceObject && Object.prototype.hasOwnProperty.call(sourceObject, "subagent")) return null;
+ const transcriptCwd = safeString(transcriptPayload.cwd).trim();
+ if (!transcriptCwd || !isAbsolute(transcriptCwd)) return null;
+ if (!sameFilePath(transcriptCwd, cwd)) {
+ const initialTurnContext = await readInitialRootTurnContext(handle, openedMetadata.size, newline + 1);
+ const initialTurnCwd = safeString(safeObject(initialTurnContext?.payload)?.cwd).trim();
+ if (!initialTurnCwd || !sameFilePath(initialTurnCwd, transcriptCwd)) return null;
+ }
+
+ const latestTurnContext = await readLatestRootTurnContext(handle, openedMetadata.size);
+ const turnContextPayload = safeObject(latestTurnContext?.payload);
+ const payloadTurnClaim = readStrictStringAliasClaim(payload, ["turn_id", "turnId"]);
+ const contextTurnClaim = readStrictStringAliasClaim(turnContextPayload ?? {}, ["turn_id", "turnId"]);
+ const multiAgentModeClaim = readStrictStringAliasClaim(turnContextPayload ?? {}, ["multi_agent_mode", "multiAgentMode"]);
+ const multiAgentVersionClaim = readStrictStringAliasClaim(turnContextPayload ?? {}, ["multi_agent_version", "multiAgentVersion"]);
+ const contextCwd = safeString(turnContextPayload?.cwd).trim();
+ let exactContextCwd = false;
+ try {
+ exactContextCwd = realpathSync(contextCwd) === realpathSync(cwd);
+ } catch {
+ exactContextCwd = false;
+ }
+ const hasExactTurnContext = payloadTurnClaim.valid
+ && payloadTurnClaim.present
+ && contextTurnClaim.valid
+ && contextTurnClaim.present
+ && contextTurnClaim.values[0] === payloadTurnClaim.values[0]
+ && exactContextCwd;
+ // Codex CLI 0.146 writes only multi_agent_version="v2" in the
+ // host-owned turn_context. Older Desktop builds also wrote the mode.
+ // Treat an absent mode as the v2 default, but reject malformed,
+ // conflicting, or explicitly different mode claims.
+ const hasTypedNativeSpawn = hasExactTurnContext
+ && multiAgentModeClaim.valid
+ && (!multiAgentModeClaim.present || multiAgentModeClaim.values[0] === "explicitRequestOnly")
+ && multiAgentVersionClaim.valid
+ && multiAgentVersionClaim.present
+ && multiAgentVersionClaim.values[0] === "v2";
+ return { sessionId, hasExactTurnContext, hasTypedNativeSpawn };
+ })();
+ if (postReadHook) await postReadHook(path);
+ const postReadMetadata = await handle.stat();
+ if (
+ postReadMetadata.dev !== openedMetadata.dev
+ || postReadMetadata.ino !== openedMetadata.ino
+ || postReadMetadata.mode !== openedMetadata.mode
+ || postReadMetadata.nlink !== openedMetadata.nlink
+ || postReadMetadata.size !== openedMetadata.size
+ || postReadMetadata.mtimeMs !== openedMetadata.mtimeMs
+ || postReadMetadata.ctimeMs !== openedMetadata.ctimeMs
+ ) return null;
+ return snapshot;
+ } catch {
+ return null;
+ } finally {
+ await handle.close().catch(() => {});
+ }
+}
+
@@ -2616,6 +2935,23 @@ function isNativeOutsideTmuxUserPrompt(cwd: string, payload: CodexHookPayload, s
return environment.launcher === "native" && environment.transport === "outside-tmux";
}
+function isNativeUltragoalBootstrapSurface(
+ cwd: string,
+ payload: CodexHookPayload,
+ sessionId?: string,
+ rootTranscript: SafeRootTranscriptMetadata | null = null,
+): boolean {
+ if (resolveNativeUltragoalConfig().backend === "off") return false;
+ if (rootTranscript?.hasExactTurnContext && rootTranscript.sessionId === sessionId) return true;
+ const environment = resolveExecutionEnvironment(cwd, {
+ hookEventName: safeString(payload.hook_event_name).trim() as CodexHookEventName,
+ payload,
+ canonicalSessionId: sessionId ?? "",
+ nativeSessionId: safeString(payload.session_id ?? payload.sessionId).trim(),
+ });
+ return environment.launcher === "native";
+}
+
function buildNativeOutsideTmuxTeamPromptBlockState(
classification: KeywordInputClassification,
cwd: string,
@@ -2661,6 +2997,62 @@ function buildNativeOutsideTmuxTeamPromptBlockState(
// of an already-active standalone Ultragoal session) are left untouched, so
// resumption, prior-plan continuation, and non-standalone Ultragoal remain
// exactly as before.
+function nativeSubagentAssignmentsOptedIn(): boolean {
+ return resolveNativeUltragoalConfig().backend === "local-experimental";
+}
+
+function payloadAdvertisesCodexAppV2NativeSpawn(payload: CodexHookPayload): boolean {
+ const modeClaim = readStrictStringAliasClaim(payload, ["multi_agent_mode", "multiAgentMode"]);
+ const versionClaim = readStrictStringAliasClaim(payload, ["multi_agent_version", "multiAgentVersion"]);
+ return modeClaim.valid
+ && (!modeClaim.present || modeClaim.values[0].toLowerCase() === "explicitrequestonly")
+ && versionClaim.valid
+ && versionClaim.present
+ && versionClaim.values[0].toLowerCase() === "v2";
+}
+
+function payloadAdvertisesTypedNativeSpawn(
+ payload: CodexHookPayload,
+ rootTranscript: SafeRootTranscriptMetadata | null = null,
+): boolean {
+ const capabilities = safeObject(payload.omx_runtime_capabilities ?? payload.capabilities);
+ const nativeSubagents = capabilities?.native_subagents ?? capabilities?.nativeSubagents;
+ const multiAgent = capabilities?.multi_agent_v1 ?? capabilities?.multiAgentV1;
+ const roleRouting = capabilities?.role_routing ?? capabilities?.roleRouting;
+ if (roleRouting === true && (nativeSubagents === true || multiAgent === true)) return true;
+
+ // Codex App v2 exposes typed collaboration tools to the model while its
+ // native hook payload omits the legacy available_tools/capabilities inventory.
+ // Treat the exact host-issued v2 marker as positive surface evidence. The
+ // current CLI omits multi_agent_mode; if present it must still be the one
+ // supported value. Missing version or older versions remain fail-closed.
+ if (payloadAdvertisesCodexAppV2NativeSpawn(payload)) return true;
+
+ const availableTools = payload.available_tools ?? payload.availableTools ?? payload.tools;
+ if (Array.isArray(availableTools) && availableTools.some((tool) => {
+ const record = safeObject(tool);
+ const name = typeof tool === "string"
+ ? tool
+ : safeString(record?.name ?? record?.tool_name ?? record?.toolName).trim();
+ return isNativeSubagentSpawnToolName(name);
+ })) return true;
+ return rootTranscript?.hasTypedNativeSpawn === true;
+}
+
+function resolveNativeUltragoalRootThreadId(
+ sessionId: string,
+ payload: CodexHookPayload,
+ rootTranscript: SafeRootTranscriptMetadata | null,
+ explicitThreadId?: string,
+): string {
+ if (rootTranscript?.hasExactTurnContext && rootTranscript.sessionId === sessionId) {
+ return rootTranscript.sessionId;
+ }
+ return safeString(explicitThreadId ?? readPayloadThreadId(payload)).trim()
+ || rootTranscript?.sessionId
+ || "";
+}
+
async function buildNativeOutsideTmuxUltragoalPromptBlockState(
classification: KeywordInputClassification,
cwd: string,
@@ -2669,10 +3061,14 @@ async function buildNativeOutsideTmuxUltragoalPromptBlockState(
sessionId?: string,
threadId?: string,
turnId?: string,
+ rootTranscript: SafeRootTranscriptMetadata | null = null,
): Promise<SkillActiveState | null> {
const match = classification.matches.find((entry) => entry.skill === "ultragoal") ?? null;
if (!match) return null;
- if (!isNativeOutsideTmuxUserPrompt(cwd, payload, sessionId)) return null;
+ if (
+ !isNativeOutsideTmuxUserPrompt(cwd, payload, sessionId)
+ && !isNativeUltragoalBootstrapSurface(cwd, payload, sessionId, rootTranscript)
+ ) return null;
if (!sessionId) return null;
// Any already-active tracked skill for this session — including autopilot
@@ -2686,12 +3082,99 @@ async function buildNativeOutsideTmuxUltragoalPromptBlockState(
// planning guards). Fall through unchanged to recordSkillActivation's own
// transition/continuation/supervision logic.
const canonicalState = await readVisibleSkillActiveStateForStateDir(stateDir, sessionId);
- const hasAnyActiveTrackedSkill = canonicalState
- ? listActiveSkills(canonicalState).some((entry) => (
+ const activeTrackedSkills = canonicalState
+ ? listActiveSkills(canonicalState).filter((entry) => (
matchesSkillStopContext(entry, canonicalState, sessionId, threadId ?? "")
))
- : false;
- if (hasAnyActiveTrackedSkill) return null;
+ : [];
+ if (activeTrackedSkills.length > 0) return null;
+
+ const rootThreadId = resolveNativeUltragoalRootThreadId(
+ sessionId,
+ payload,
+ rootTranscript,
+ threadId,
+ );
+ const nativeConfig = resolveNativeUltragoalConfig();
+ const nativeSupport = resolveNativeSubagentSupportStatus({
+ payload,
+ persistedSupportBlocker: await readJsonIfExists(nativeSubagentSupportBlockerPath(stateDir)),
+ persistedRoleRoutingMarker: readRoleRoutingMarker(stateDir, { cwd, sessionId }),
+ persistedCapacityBlocker: await readJsonIfExists(nativeSubagentCapacityBlockerPath(stateDir)),
+ cwd,
+ sessionId,
+ });
+ if (nativeConfig.backend === "local-experimental" && rootThreadId) {
+ const ready = await reconcileLocalNativeExecutorAssignments({
+ cwd,
+ stateDir,
+ sessionId,
+ rootThreadId,
+ });
+ if (ready.ready && ready.childAgentId) return null;
+ if (
+ payloadAdvertisesTypedNativeSpawn(payload, rootTranscript)
+ && (
+ nativeSupport.status === "supported"
+ || payloadAdvertisesCodexAppV2NativeSpawn(payload)
+ || rootTranscript?.hasTypedNativeSpawn === true
+ )
+ ) {
+ const bootstrap = await beginNativeUltragoalBootstrap({
+ cwd,
+ stateDir,
+ sessionId,
+ rootThreadId,
+ backend: nativeConfig.backend,
+ ttlSeconds: nativeConfig.assignmentTtlSeconds,
+ });
+ const nowIso = new Date().toISOString();
+ return {
+ version: 1,
+ active: false,
+ skill: "ultragoal",
+ keyword: match.keyword,
+ phase: "bootstrap",
+ activated_at: nowIso,
+ updated_at: nowIso,
+ source: "keyword-detector",
+ session_id: sessionId,
+ thread_id: rootThreadId,
+ turn_id: turnId,
+ active_skills: [],
+ transition_error: buildNativeUltragoalBootstrapRequiredReason(
+ sessionId,
+ rootThreadId,
+ bootstrap.generation,
+ ),
+ };
+ }
+ } else if (nativeConfig.backend === "host" && rootThreadId) {
+ await beginNativeUltragoalBootstrap({
+ cwd,
+ stateDir,
+ sessionId,
+ rootThreadId,
+ backend: nativeConfig.backend,
+ ttlSeconds: nativeConfig.assignmentTtlSeconds,
+ });
+ const nowIso = new Date().toISOString();
+ return {
+ version: 1,
+ active: false,
+ skill: "ultragoal",
+ keyword: match.keyword,
+ phase: "bootstrap",
+ activated_at: nowIso,
+ updated_at: nowIso,
+ source: "keyword-detector",
+ session_id: sessionId,
+ thread_id: rootThreadId,
+ turn_id: turnId,
+ active_skills: [],
+ transition_error: ULTRAGOAL_HOST_RECEIPT_UNAVAILABLE_REASON,
+ };
+ }
const nowIso = new Date().toISOString();
return {
@@ -2711,6 +3194,40 @@ async function buildNativeOutsideTmuxUltragoalPromptBlockState(
};
}
+async function revokeTerminalNativeUltragoalBootstrap(
+ cwd: string,
+ stateDir: string,
+ sessionId: string,
+): Promise<void> {
+ if (!sessionId) return;
+ const bootstrap = await readNativeUltragoalBootstrap(stateDir, sessionId);
+ if (!bootstrap || bootstrap.status === "revoked") return;
+ const state = await readStopSessionPinnedState("ultragoal-state.json", cwd, sessionId, stateDir);
+ const phase = safeString(state?.current_phase ?? state?.currentPhase).trim().toLowerCase();
+ if (state?.active === false || TERMINAL_MODE_PHASES.has(phase)) {
+ await revokeLocalNativeExecutorAssignment({
+ stateDir,
+ sessionId,
+ reason: `ultragoal_${phase || "inactive"}`,
+ });
+ }
+}
+
+async function failNativeUltragoalActivation(
+ cwd: string,
+ stateDir: string,
+ sessionId: string,
+ reason: string,
+): Promise<void> {
+ await revokeLocalNativeExecutorAssignment({ stateDir, sessionId, reason });
+ await updateModeState("ultragoal", {
+ active: false,
+ current_phase: "failed",
+ error: reason,
+ last_turn_at: new Date().toISOString(),
+ }, cwd, sessionId);
+}
+
function buildSkillStateCliInstruction(mode: string, statePath: string): string {
return `skill: ${mode} activated and initial state initialized at ${statePath}; use CLI-first state updates via \`omx state write/read/clear --input '<json>' --json\`; use omx_state MCP only when explicit MCP compatibility is enabled.`;
}
@@ -3527,8 +4044,8 @@ async function findActiveGoalWorkflowReconciliationRequirement(cwd: string): Pro
remediation: [
`If get_goal returns a completed task-scoped objective for the same aggregate ultragoal plan, checkpoint ${goalId} with evidence naming ${goalId} plus .omx/ultragoal/goals.json or ledger.jsonl and pass final quality-gate JSON; OMX will reconcile the completed planned scope without mutating Codex goal state.`,
`If get_goal instead returns a different completed legacy objective and complete checkpointing fails, do not repeat --status complete in this thread.`,
- `Record the non-terminal blocker with: omx ultragoal checkpoint --goal-id ${goalId} --status blocked --codex-goal-json '<different completed get_goal JSON or path>' --quality-gate-json '<quality-gate JSON or path>' --evidence '<completed legacy Codex goal blocks create_goal in this thread>' --json.`,
- `If get_goal itself is unavailable with a Codex DB/schema/context error such as "no such table: thread_goals", record an auditable safe-recovery blocker instead: omx ultragoal checkpoint --goal-id ${goalId} --status blocked --codex-goal-json '<unavailable get_goal error JSON or path>' --quality-gate-json '<quality-gate JSON or path>' --evidence '<get_goal unavailable due to Codex DB/schema/context error; safe recovery requires a working Codex goal context>' --json.`,
+ `Record the non-terminal blocker with: omx ultragoal checkpoint --goal-id ${goalId} --status blocked --codex-goal-json '<different completed get_goal JSON or path>' --evidence '<completed legacy Codex goal blocks create_goal in this thread>' --json.`,
+ `If get_goal itself is unavailable with a Codex DB/schema/context error such as "no such table: thread_goals", record an auditable safe-recovery blocker instead: omx ultragoal checkpoint --goal-id ${goalId} --status blocked --codex-goal-json '<unavailable get_goal error JSON or path>' --evidence '<get_goal unavailable due to Codex DB/schema/context error; safe recovery requires a working Codex goal context>' --json.`,
"Then continue only from a Codex goal context with no active/completed conflicting goal in the same repo/worktree and create the intended goal there.",
].join(" "),
};
@@ -3815,6 +4332,13 @@ function readPayloadThreadId(payload: CodexHookPayload): string {
function readPayloadAgentId(payload: CodexHookPayload): string {
return safeString(payload.agent_id).trim();
}
+
+function readPayloadTranscriptChildId(payload: CodexHookPayload): string {
+ const claim = readStrictStringAliasClaim(payload, ["transcript_path", "transcriptPath"]);
+ if (!claim.valid || !claim.present || claim.values.length !== 1) return "";
+ const match = basename(claim.values[0] ?? "").match(/-([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})\.jsonl$/i);
+ return normalizeSessionId(match?.[1] ?? "") ?? "";
+}
interface PreToolUseSessionBinding {
canonicalSessionId: string;
valid: boolean;
@@ -3836,12 +4360,83 @@ async function resolvePreToolUseSessionBinding(
stateDir: string,
payload: CodexHookPayload,
allowSharedTeamRoot = false,
+ rootTranscript: SafeRootTranscriptMetadata | null = null,
+ pointer: SessionPointerReadResult | null = null,
): Promise<PreToolUseSessionBinding> {
+ const aliases = payloadAliasValues(payload, ["session_id", "sessionId"]);
+ if (
+ rootTranscript?.hasExactTurnContext
+ && aliases.length === 1
+ && aliases[0] === rootTranscript.sessionId
+ && !payloadHasConflictingIdentityAliases(payload)
+ ) {
+ return {
+ canonicalSessionId: rootTranscript.sessionId,
+ missing: false,
+ valid: true,
+ };
+ }
+ if (
+ pointer?.status === "identity-indeterminate"
+ && pointer.state
+ && aliases.length === 1
+ && sessionPointerAliases(pointer.state).has(aliases[0] ?? "")
+ && isSessionStateAuthoritativeForCwd(pointer.state, cwd)
+ && !payloadHasConflictingIdentityAliases(payload)
+ ) {
+ const tracked = await readSubagentTrackingState(cwd).catch(() => null);
+ const trackedSession = tracked?.sessions?.[safeString(pointer.state.session_id).trim()];
+ const actorIds = uniqueNonEmpty([readPayloadAgentId(payload), readPayloadThreadId(payload)]);
+ if (trackedSession && actorIds.some((actorId) => isTrustedSubagentThread(trackedSession, actorId))) {
+ return {
+ canonicalSessionId: safeString(pointer.state.session_id).trim(),
+ missing: false,
+ valid: true,
+ };
+ }
+ }
+ if (
+ pointer
+ && (pointer.status === "usable" || pointer.status === "identity-indeterminate")
+ && pointer.state
+ && aliases.length === 1
+ && !payloadHasConflictingIdentityAliases(payload)
+ && isSessionStateAuthoritativeForCwd(pointer.state, cwd)
+ ) {
+ const rootSessionId = safeString(pointer.state.session_id).trim();
+ const payloadTranscriptChildId = readPayloadTranscriptChildId(payload);
+ const childAgentId = payloadTranscriptChildId
+ || ((aliases[0] ?? "") !== rootSessionId ? aliases[0] ?? "" : "");
+ const bootstrap = rootSessionId
+ ? await readNativeUltragoalBootstrap(stateDir, rootSessionId)
+ : null;
+ if (
+ childAgentId
+ && childAgentId !== rootSessionId
+ && bootstrap
+ && !["revoked", "expired", "host-receipt-unavailable"].includes(bootstrap.status)
+ && bootstrap.session_id === rootSessionId
+ && bootstrap.root_thread_id
+ && (await validateLocalNativeExecutorIdentity({
+ cwd,
+ sessionId: rootSessionId,
+ rootThreadId: bootstrap.root_thread_id,
+ childAgentId,
+ receiptNotBefore: bootstrap.created_at,
+ receiptNotAfter: bootstrap.expires_at,
+ })).ok
+ ) {
+ return {
+ canonicalSessionId: rootSessionId,
+ missing: false,
+ valid: true,
+ };
+ }
+ }
const currentSession = allowSharedTeamRoot
? await readRootSessionStateFromStateDir(stateDir).catch(() => null)
: await readUsableSessionStateFromStateDir(cwd, stateDir).catch(() => null);
const canonicalSessionId = safeString(currentSession?.session_id).trim();
- const aliases = payloadAliasValues(payload, ["session_id", "sessionId"]);
const knownAliases = sessionPointerAliases(currentSession);
return {
canonicalSessionId,
@@ -3895,36 +4490,129 @@ function hookCancelObject(bytes: Buffer): Record<string, unknown> | null {
try { const value = JSON.parse(bytes.toString("utf8")); return value && typeof value === "object" && !Array.isArray(value) ? value as Record<string, unknown> : null; } catch { return null; }
}
function hookCancelString(value: unknown): string { return typeof value === "string" ? value.trim() : ""; }
-function hookCancelCwdMatches(value: Record<string, unknown>, canonicalCwd: string): boolean {
- const recorded = hookCancelString(value.cwd) || hookCancelString(value.workingDirectory);
- try { return !recorded || sameFilePath(recorded, canonicalCwd); } catch { return false; }
-}
-function hookCancelSessionMatches(value: Record<string, unknown>, sessionId: string, cwd: string): boolean {
- const recorded = hookCancelString(value.session_id);
- return (!recorded || recorded === sessionId) && hookCancelCwdMatches(value, cwd);
-}
-function hookCancelAutopilotMatches(value: Record<string, unknown>, sessionId: string, cwd: string): boolean {
- return value.active === true && hookCancelString(value.mode).toLowerCase() === "autopilot" && normalizeAutopilotPhase(hookCancelString(value.current_phase)) === "deep-interview" && hookCancelSessionMatches(value, sessionId, cwd);
+type HookCancelIdentityPolicy = {
+ allowMissingCwd: boolean;
+ allowSupervisedAutopilotMirror: boolean;
+};
+const STRICT_HOOK_CANCEL_IDENTITY: HookCancelIdentityPolicy = {
+ allowMissingCwd: false,
+ allowSupervisedAutopilotMirror: false,
+};
+const AUTHENTICATED_HOOK_CANCEL_IDENTITY: HookCancelIdentityPolicy = {
+ allowMissingCwd: true,
+ allowSupervisedAutopilotMirror: true,
+};
+function hookCancelRequiredStringAliasesMatch(
+ value: Record<string, unknown>,
+ aliases: readonly string[],
+ matches: (candidate: string) => boolean,
+ allowMissing = false,
+): boolean {
+ let found = false;
+ for (const alias of aliases) {
+ if (!Object.prototype.hasOwnProperty.call(value, alias)) continue;
+ const raw = value[alias];
+ if (typeof raw !== "string" || raw.trim() === "") return false;
+ found = true;
+ if (!matches(raw.trim())) return false;
+ }
+ return found || allowMissing;
}
-function hookCancelSkillMatches(value: Record<string, unknown>, sessionId: string, cwd: string): boolean {
- if (!hookCancelSessionMatches(value, sessionId, cwd)) return false;
+function hookCancelCwdMatches(value: Record<string, unknown>, canonicalCwd: string, policy = STRICT_HOOK_CANCEL_IDENTITY): boolean {
+ try {
+ return hookCancelRequiredStringAliasesMatch(
+ value,
+ ["cwd", "workingDirectory"],
+ (candidate) => sameFilePath(candidate, canonicalCwd),
+ policy.allowMissingCwd,
+ );
+ } catch { return false; }
+}
+function hookCancelSessionMatches(value: Record<string, unknown>, sessionId: string, cwd: string, policy = STRICT_HOOK_CANCEL_IDENTITY): boolean {
+ return hookCancelRequiredStringAliasesMatch(value, ["session_id", "sessionId"], (candidate) => candidate === sessionId)
+ && hookCancelCwdMatches(value, cwd, policy);
+}
+function hookCancelAutopilotIsActive(value: Record<string, unknown>): boolean {
+ return value.active === true
+ && hookCancelString(value.mode).toLowerCase() === "autopilot"
+ && normalizeAutopilotPhase(hookCancelString(value.current_phase)) === "deep-interview";
+}
+function hookCancelAutopilotMatches(value: Record<string, unknown>, sessionId: string, cwd: string, policy = STRICT_HOOK_CANCEL_IDENTITY): boolean {
+ return hookCancelAutopilotIsActive(value) && hookCancelSessionMatches(value, sessionId, cwd, policy);
+}
+function hookCancelSupervisingAutopilotMatches(value: Record<string, unknown>, sessionId: string, cwd: string, policy: HookCancelIdentityPolicy): boolean {
+ return value.active === true
+ && hookCancelString(value.mode).toLowerCase() === "autopilot"
+ && normalizeAutopilotPhase(hookCancelString(value.current_phase)) === "ultragoal"
+ && hookCancelSessionMatches(value, sessionId, cwd, policy);
+}
+function hookCancelUltragoalIsActive(value: Record<string, unknown>): boolean {
+ const phase = hookCancelString(value.current_phase).toLowerCase();
+ return value.active === true
+ && hookCancelString(value.mode).toLowerCase() === "ultragoal"
+ && phase !== "completing"
+ && isNonTerminalPhase(phase);
+}
+function hookCancelUltragoalMatches(value: Record<string, unknown>, sessionId: string, cwd: string, policy = STRICT_HOOK_CANCEL_IDENTITY): boolean {
+ return hookCancelUltragoalIsActive(value) && hookCancelSessionMatches(value, sessionId, cwd, policy);
+}
+function hookCancelSkillEntryIsActive(value: unknown): boolean {
+ return value === undefined || value === true;
+}
+function hookCancelSkillEntryMatches(entry: Record<string, unknown>, workflow: HookCancelWorkflow, policy: HookCancelIdentityPolicy): boolean {
+ const skill = hookCancelString(entry.skill).toLowerCase();
+ return skill === workflow
+ || (policy.allowSupervisedAutopilotMirror
+ && workflow === "ultragoal"
+ && skill === "autopilot"
+ && hookCancelString(entry.phase).toLowerCase() === "ultragoal");
+}
+function hookCancelUsesSupervisedAutopilotMirror(value: Record<string, unknown>, sessionId: string, cwd: string, policy: HookCancelIdentityPolicy): boolean {
+ if (!policy.allowSupervisedAutopilotMirror
+ || !hookCancelSkillEntryIsActive(value.active)
+ || hookCancelString(value.skill).toLowerCase() !== "autopilot"
+ || hookCancelString(value.phase).toLowerCase() !== "ultragoal"
+ || !hookCancelSessionMatches(value, sessionId, cwd, policy)) return false;
const entries = Array.isArray(value.active_skills) ? value.active_skills : [value];
return entries.some((candidate) => {
if (!candidate || typeof candidate !== "object" || Array.isArray(candidate)) return false;
const entry = candidate as Record<string, unknown>;
return hookCancelString(entry.skill).toLowerCase() === "autopilot"
- && entry.active !== false
- && (!hookCancelString(entry.session_id) || hookCancelString(entry.session_id) === sessionId)
- && hookCancelCwdMatches(entry, cwd);
+ && hookCancelString(entry.phase).toLowerCase() === "ultragoal"
+ && hookCancelSkillEntryIsActive(entry.active)
+ && hookCancelSessionMatches(entry, sessionId, cwd, policy);
+ });
+}
+function hookCancelSkillMatches(value: Record<string, unknown>, workflow: HookCancelWorkflow, sessionId: string, cwd: string, policy = STRICT_HOOK_CANCEL_IDENTITY): boolean {
+ if (!hookCancelSkillEntryIsActive(value.active) || !hookCancelSessionMatches(value, sessionId, cwd, policy)) return false;
+ const entries = Array.isArray(value.active_skills) ? value.active_skills : [value];
+ return entries.some((candidate) => {
+ if (!candidate || typeof candidate !== "object" || Array.isArray(candidate)) return false;
+ const entry = candidate as Record<string, unknown>;
+ return hookCancelSkillEntryMatches(entry, workflow, policy)
+ && hookCancelSkillEntryIsActive(entry.active)
+ && hookCancelSessionMatches(entry, sessionId, cwd, policy);
});
}
+function hookCancelPlatform(): NodeJS.Platform {
+ const testPlatform = process.env.NODE_ENV === "test" ? process.env.OMX_NATIVE_HOOK_TEST_PLATFORM : undefined;
+ return testPlatform === "win32" ? "win32" : process.platform;
+}
+function hookCancelOwnerMatches(stat: Awaited<ReturnType<typeof lstat>>): boolean {
+ // Windows exposes no uid. The authenticated canonical session path, ACL-gated
+ // open, single-link regular-file shape, and lstat/open identity checks below
+ // form the platform ownership proof instead of silently disabling the path.
+ if (hookCancelPlatform() === "win32") return true;
+ return typeof process.getuid === "function" && stat.uid === process.getuid();
+}
async function hookCancelFsyncDirectory(path: string): Promise<void> {
+ if (hookCancelPlatform() === "win32") return;
const handle = await open(path, "r"); try { await handle.sync(); } finally { await handle.close(); }
}
async function hookCancelPinnedRead(path: string): Promise<HookCancelPinnedFile | null> {
let before: Awaited<ReturnType<typeof lstat>>;
try { before = await lstat(path); } catch { return null; }
- if (!before.isFile() || before.isSymbolicLink() || before.nlink !== 1 || before.uid !== process.getuid?.()) return null;
+ if (!before.isFile() || before.isSymbolicLink() || before.nlink !== 1 || !hookCancelOwnerMatches(before)) return null;
let handle: Awaited<ReturnType<typeof open>>;
try { handle = await open(path, fsConstants.O_RDONLY | fsConstants.O_NOFOLLOW); } catch { return null; }
try {
@@ -3936,44 +4624,80 @@ async function hookCancelPinnedRead(path: string): Promise<HookCancelPinnedFile
const value = hookCancelObject(bytes); return value ? { path, bytes, identity: hookCancelIdentity(after), value } : null;
} catch { return null; } finally { await handle.close(); }
}
-function hookCancelPreparedAutopilot(value: Record<string, unknown>, nowIso: string): Record<string, unknown> {
+function hookCancelPreparedWorkflow(value: Record<string, unknown>, nowIso: string): Record<string, unknown> {
return { ...value, active: false, current_phase: "cancelled", completed_at: nowIso, last_turn_at: nowIso };
}
-function hookCancelPreparedSkill(value: Record<string, unknown>, sessionId: string, nowIso: string): Record<string, unknown> {
+function hookCancelPreparedSkill(value: Record<string, unknown>, workflow: HookCancelWorkflow, sessionId: string, cwd: string, nowIso: string, policy = STRICT_HOOK_CANCEL_IDENTITY): Record<string, unknown> {
const sourceEntries = Array.isArray(value.active_skills) ? value.active_skills : [value]; let cancelled = false;
const entries = sourceEntries.map((candidate) => {
if (!candidate || typeof candidate !== "object" || Array.isArray(candidate)) return candidate;
const entry = candidate as Record<string, unknown>;
- const matches = hookCancelString(entry.skill).toLowerCase() === "autopilot"
- && entry.active !== false
- && (!hookCancelString(entry.session_id) || hookCancelString(entry.session_id) === sessionId);
+ const matches = hookCancelSkillEntryMatches(entry, workflow, policy)
+ && hookCancelSkillEntryIsActive(entry.active)
+ && hookCancelSessionMatches(entry, sessionId, cwd, policy);
if (!matches) return entry; cancelled = true; return { ...entry, active: false, phase: "cancelled", updated_at: nowIso };
});
if (!cancelled) return value;
- const activeEntries = entries.filter((entry) => entry && typeof entry === "object" && !Array.isArray(entry) && (entry as Record<string, unknown>).active !== false) as Record<string, unknown>[];
+ const activeEntries = entries.filter((entry) => entry && typeof entry === "object" && !Array.isArray(entry) && hookCancelSkillEntryIsActive((entry as Record<string, unknown>).active)) as Record<string, unknown>[];
const primary = activeEntries[0];
- return { ...value, active: activeEntries.length > 0, skill: primary ? hookCancelString(primary.skill) : "autopilot", phase: primary ? hookCancelString(primary.phase) : "cancelled", updated_at: nowIso, active_skills: entries };
+ const terminalSkill = hookCancelString(value.skill).toLowerCase() || workflow;
+ return { ...value, active: activeEntries.length > 0, skill: primary ? hookCancelString(primary.skill) : terminalSkill, phase: primary ? hookCancelString(primary.phase) : "cancelled", updated_at: nowIso, active_skills: entries };
}
function hookCancelInjectFailure(boundary: string): void {
if (process.env.NODE_ENV === "test" && process.env.OMX_NATIVE_HOOK_TEST_CANCEL_TRANSACTION_FAIL_AFTER === boundary) throw new Error("test-induced hook cancellation transaction failure");
}
-async function hookCancelWriteExact(handle: Awaited<ReturnType<typeof open>>, bytes: Buffer): Promise<void> { await handle.write(bytes, 0, bytes.length, 0); await handle.truncate(bytes.length); await handle.sync(); }
-async function hookCancelWriteTarget(path: string, identity: HookCancelTargetIdentity, expected: Buffer, next: Buffer): Promise<void> {
+async function hookCancelWriteExact(handle: Awaited<ReturnType<typeof open>>, bytes: Buffer): Promise<void> {
+ let offset = 0;
+ while (offset < bytes.length) {
+ const { bytesWritten } = await handle.write(bytes, offset, bytes.length - offset, offset);
+ if (bytesWritten <= 0) throw new Error("target write made no progress");
+ offset += bytesWritten;
+ }
+ await handle.truncate(bytes.length);
+ await syncRegularFile(handle, hookCancelPlatform());
+}
+class HookCancelTargetRollbackError extends Error {}
+async function hookCancelWriteTarget(path: string, identity: HookCancelTargetIdentity, expected: Buffer, next: Buffer, boundary: string): Promise<void> {
const handle = await open(path, fsConstants.O_RDWR | fsConstants.O_NOFOLLOW);
- try { const current = await handle.stat(); if (!current.isFile() || !hookCancelTargetMatches(identity, hookCancelIdentity(current))) throw new Error("target identity changed"); const bytes = await handle.readFile(); if (!bytes.equals(expected)) throw new Error("target content changed"); await hookCancelWriteExact(handle, next); } finally { await handle.close(); }
+ let writeStarted = false;
+ try {
+ const current = await handle.stat();
+ if (!current.isFile() || !hookCancelTargetMatches(identity, hookCancelIdentity(current))) throw new Error("target identity changed");
+ const bytes = await handle.readFile();
+ if (!bytes.equals(expected)) throw new Error("target content changed");
+ writeStarted = true;
+ if (process.env.NODE_ENV === "test" && process.env.OMX_NATIVE_HOOK_TEST_CANCEL_TRANSACTION_FAIL_AFTER === `partial-${boundary}`) {
+ const partialLength = Math.max(1, Math.floor(next.length / 2));
+ await handle.write(next, 0, partialLength, 0);
+ await syncRegularFile(handle, hookCancelPlatform());
+ throw new Error("test-induced partial target write");
+ }
+ await hookCancelWriteExact(handle, next);
+ } catch (error) {
+ if (writeStarted) {
+ try { await hookCancelWriteExact(handle, expected); } catch { throw new HookCancelTargetRollbackError(); }
+ }
+ throw error;
+ } finally { try { await handle.close(); } catch {} }
}
async function hookCancelRestoreTarget(path: string, identity: HookCancelTargetIdentity, original: Buffer): Promise<void> {
const handle = await open(path, fsConstants.O_RDWR | fsConstants.O_NOFOLLOW);
try { const current = await handle.stat(); if (!current.isFile() || !hookCancelTargetMatches(identity, hookCancelIdentity(current))) throw new Error("rollback identity changed"); await hookCancelWriteExact(handle, original); } finally { await handle.close(); }
}
+function hookCancelSessionIdIsSafe(value: string): boolean {
+ return value !== "" && value !== "." && value !== ".." && basename(value) === value;
+}
export async function readHookCancelTransactionRecoveryState(input: { stateDir: string; canonicalSessionId: string }): Promise<HookCancelTransactionFailureReason | null> {
- if (!input.canonicalSessionId || basename(input.canonicalSessionId) !== input.canonicalSessionId) return "invalid_target";
+ if (!hookCancelSessionIdIsSafe(input.canonicalSessionId)) return "invalid_target";
try { const journal = hookCancelObject(await readFile(join(input.stateDir, "sessions", input.canonicalSessionId, HOOK_CANCEL_JOURNAL_FILE))); return journal?.phase === "prepared" ? "recovery_required" : "cleanup_failed"; } catch (error) { return (error as NodeJS.ErrnoException).code === "ENOENT" ? null : "cleanup_failed"; }
}
-export async function terminalizeExactAutopilotSessionForHookCancel(input: { stateDir: string; canonicalSessionId: string; cwd: string; nowIso: string }): Promise<HookCancelTransactionResult> {
+type HookCancelWorkflow = "autopilot" | "ultragoal";
+type HookCancelWorkflowInput = { stateDir: string; canonicalSessionId: string; cwd: string; nowIso: string };
+
+async function terminalizeExactWorkflowSessionForHookCancel(input: HookCancelWorkflowInput, workflow: HookCancelWorkflow, policy = STRICT_HOOK_CANCEL_IDENTITY): Promise<HookCancelTransactionResult> {
let canonicalStateDir: string; let canonicalCwd: string;
try { canonicalStateDir = realpathSync(input.stateDir); canonicalCwd = realpathSync(input.cwd); } catch { return { ok: false, reason: "invalid_target" }; }
- if (!input.canonicalSessionId || basename(input.canonicalSessionId) !== input.canonicalSessionId) return { ok: false, reason: "invalid_target" };
+ if (!hookCancelSessionIdIsSafe(input.canonicalSessionId)) return { ok: false, reason: "invalid_target" };
const sessionsDir = join(canonicalStateDir, "sessions"); const sessionDir = join(sessionsDir, input.canonicalSessionId);
try {
const [sessionsStats, sessionStats, resolvedSessionDir] = await Promise.all([lstat(sessionsDir), lstat(sessionDir), import("fs/promises").then(({ realpath }) => realpath(sessionDir))]);
@@ -3981,27 +4705,79 @@ export async function terminalizeExactAutopilotSessionForHookCancel(input: { sta
} catch { return { ok: false, reason: "invalid_target" }; }
const recovery = await readHookCancelTransactionRecoveryState({ stateDir: canonicalStateDir, canonicalSessionId: input.canonicalSessionId }); if (recovery) return { ok: false, reason: recovery };
const lockPath = join(sessionDir, HOOK_CANCEL_LOCK_FILE); const journalPath = join(sessionDir, HOOK_CANCEL_JOURNAL_FILE); let lock: Awaited<ReturnType<typeof open>>;
- try { lock = await open(lockPath, "wx", 0o600); await lock.sync(); await hookCancelFsyncDirectory(sessionDir); } catch { return { ok: false, reason: "lock_held" }; }
+ try { lock = await open(lockPath, "wx", 0o600); } catch { return { ok: false, reason: "lock_held" }; }
+ try { hookCancelInjectFailure("lock-acquire"); await syncRegularFile(lock, hookCancelPlatform()); await hookCancelFsyncDirectory(sessionDir); }
+ catch {
+ try { await lock.close(); await unlink(lockPath); await hookCancelFsyncDirectory(sessionDir); } catch {}
+ return { ok: false, reason: "lock_held" };
+ }
try {
- const [autopilot, skill] = await Promise.all([hookCancelPinnedRead(join(sessionDir, "autopilot-state.json")), hookCancelPinnedRead(join(sessionDir, "skill-active-state.json"))]);
- if (!autopilot || !skill) return { ok: false, reason: "preflight_failed" };
- if (!hookCancelAutopilotMatches(autopilot.value, input.canonicalSessionId, canonicalCwd) || !hookCancelSkillMatches(skill.value, input.canonicalSessionId, canonicalCwd)) return { ok: false, reason: "state_mismatch" };
- const nextAutopilot = Buffer.from(JSON.stringify(hookCancelPreparedAutopilot(autopilot.value, input.nowIso), null, 2)); const nextSkill = Buffer.from(JSON.stringify(hookCancelPreparedSkill(skill.value, input.canonicalSessionId, input.nowIso), null, 2));
- const journal = Buffer.from(JSON.stringify({ version: 1, session_id: input.canonicalSessionId, phase: "prepared", targets: { autopilot: { identity: autopilot.identity, old_sha256: hookCancelDigest(autopilot.bytes), new_sha256: hookCancelDigest(nextAutopilot) }, skill_active: { identity: skill.identity, old_sha256: hookCancelDigest(skill.bytes), new_sha256: hookCancelDigest(nextSkill) } } }));
+ const workflowStateFile = workflow === "autopilot" ? "autopilot-state.json" : "ultragoal-state.json";
+ const [workflowState, skill, parentAutopilot] = await Promise.all([
+ hookCancelPinnedRead(join(sessionDir, workflowStateFile)),
+ hookCancelPinnedRead(join(sessionDir, "skill-active-state.json")),
+ workflow === "ultragoal" ? hookCancelPinnedRead(join(sessionDir, "autopilot-state.json")) : Promise.resolve(null),
+ ]);
+ if (!workflowState || !skill) return { ok: false, reason: "preflight_failed" };
+ const workflowMatches = workflow === "autopilot"
+ ? hookCancelAutopilotMatches(workflowState.value, input.canonicalSessionId, canonicalCwd, policy)
+ : hookCancelUltragoalMatches(workflowState.value, input.canonicalSessionId, canonicalCwd, policy);
+ const supervisedAutopilot = workflow === "ultragoal"
+ && hookCancelUsesSupervisedAutopilotMirror(skill.value, input.canonicalSessionId, canonicalCwd, policy);
+ if (!workflowMatches || !hookCancelSkillMatches(skill.value, workflow, input.canonicalSessionId, canonicalCwd, policy)) return { ok: false, reason: "state_mismatch" };
+ if (supervisedAutopilot && (!parentAutopilot || !hookCancelSupervisingAutopilotMatches(parentAutopilot.value, input.canonicalSessionId, canonicalCwd, policy))) {
+ return { ok: false, reason: "state_mismatch" };
+ }
+ const nextWorkflowState = Buffer.from(JSON.stringify(hookCancelPreparedWorkflow(workflowState.value, input.nowIso), null, 2));
+ const nextSkill = Buffer.from(JSON.stringify(hookCancelPreparedSkill(skill.value, workflow, input.canonicalSessionId, canonicalCwd, input.nowIso, policy), null, 2));
+ const targets: Array<{ journalKey: string; file: HookCancelPinnedFile; next: Buffer; boundary: string }> = [];
+ if (supervisedAutopilot && parentAutopilot) {
+ targets.push({
+ journalKey: "parent_autopilot",
+ file: parentAutopilot,
+ next: Buffer.from(JSON.stringify(hookCancelPreparedWorkflow(parentAutopilot.value, input.nowIso), null, 2)),
+ boundary: "parent-data-write",
+ });
+ }
+ targets.push(
+ { journalKey: "workflow_state", file: workflowState, next: nextWorkflowState, boundary: "first-data-write" },
+ { journalKey: "skill_active", file: skill, next: nextSkill, boundary: "second-data-write" },
+ );
+ const journalTargets = Object.fromEntries(targets.map((target) => [target.journalKey, {
+ identity: target.file.identity,
+ old_sha256: hookCancelDigest(target.file.bytes),
+ new_sha256: hookCancelDigest(target.next),
+ }]));
+ const journal = Buffer.from(JSON.stringify({ version: 1, session_id: input.canonicalSessionId, workflow, phase: "prepared", targets: journalTargets }));
if (journal.length > HOOK_CANCEL_MAX_STATE_BYTES) return { ok: false, reason: "journal_failed" };
- const journalHandle = await open(journalPath, "wx", 0o600); try { await journalHandle.writeFile(journal); await journalHandle.sync(); } finally { await journalHandle.close(); }
+ const journalHandle = await open(journalPath, "wx", 0o600); try { await journalHandle.writeFile(journal); await syncRegularFile(journalHandle, hookCancelPlatform()); } finally { await journalHandle.close(); }
await hookCancelFsyncDirectory(sessionDir); hookCancelInjectFailure("journal-fsync");
- let autopilotWritten = false; let skillWritten = false;
- try { await hookCancelWriteTarget(autopilot.path, autopilot.identity, autopilot.bytes, nextAutopilot); autopilotWritten = true; hookCancelInjectFailure("first-data-write"); await hookCancelWriteTarget(skill.path, skill.identity, skill.bytes, nextSkill); skillWritten = true; hookCancelInjectFailure("second-data-write"); }
- catch {
- try { if (skillWritten) await hookCancelRestoreTarget(skill.path, skill.identity, skill.bytes); if (autopilotWritten) await hookCancelRestoreTarget(autopilot.path, autopilot.identity, autopilot.bytes); await hookCancelFsyncDirectory(sessionDir); } catch { return { ok: false, reason: "rollback_failed" }; }
+ const written: typeof targets = [];
+ try {
+ for (const target of targets) {
+ await hookCancelWriteTarget(target.file.path, target.file.identity, target.file.bytes, target.next, target.boundary);
+ written.push(target);
+ hookCancelInjectFailure(target.boundary);
+ }
+ } catch (error) {
+ try {
+ for (const target of [...written].reverse()) await hookCancelRestoreTarget(target.file.path, target.file.identity, target.file.bytes);
+ await hookCancelFsyncDirectory(sessionDir);
+ } catch { return { ok: false, reason: "rollback_failed" }; }
+ if (error instanceof HookCancelTargetRollbackError) return { ok: false, reason: "rollback_failed" };
await unlink(journalPath); await hookCancelFsyncDirectory(sessionDir); return { ok: false, reason: "write_failed" };
}
- const [verifiedAutopilot, verifiedSkill] = await Promise.all([readFile(autopilot.path), readFile(skill.path)]);
- if (!verifiedAutopilot.equals(nextAutopilot) || !verifiedSkill.equals(nextSkill)) return { ok: false, reason: "verification_failed" };
+ const verified = await Promise.all(targets.map((target) => readFile(target.file.path))).catch(() => null);
+ if (!verified || verified.some((bytes, index) => !bytes.equals(targets[index]?.next))) {
+ try {
+ for (const target of [...targets].reverse()) await hookCancelRestoreTarget(target.file.path, target.file.identity, target.file.bytes);
+ await hookCancelFsyncDirectory(sessionDir); await unlink(journalPath); await hookCancelFsyncDirectory(sessionDir);
+ } catch { return { ok: false, reason: "rollback_failed" }; }
+ return { ok: false, reason: "verification_failed" };
+ }
hookCancelInjectFailure("verification");
const committed = Buffer.from(JSON.stringify({ ...JSON.parse(journal.toString("utf8")), phase: "committed" })); const committedHandle = await open(journalPath, fsConstants.O_WRONLY | fsConstants.O_NOFOLLOW);
- try { await committedHandle.write(committed, 0, committed.length, 0); await committedHandle.truncate(committed.length); await committedHandle.sync(); } finally { await committedHandle.close(); }
+ try { await committedHandle.write(committed, 0, committed.length, 0); await committedHandle.truncate(committed.length); await syncRegularFile(committedHandle, hookCancelPlatform()); } finally { await committedHandle.close(); }
hookCancelInjectFailure("journal-commit"); await unlink(journalPath); await hookCancelFsyncDirectory(sessionDir); hookCancelInjectFailure("unlink");
return { ok: true };
} catch { return { ok: false, reason: "journal_failed" }; }
@@ -4010,6 +4786,14 @@ export async function terminalizeExactAutopilotSessionForHookCancel(input: { sta
}
}
+export async function terminalizeExactAutopilotSessionForHookCancel(input: HookCancelWorkflowInput): Promise<HookCancelTransactionResult> {
+ return terminalizeExactWorkflowSessionForHookCancel(input, "autopilot");
+}
+
+export async function terminalizeExactUltragoalSessionForHookCancel(input: HookCancelWorkflowInput): Promise<HookCancelTransactionResult> {
+ return terminalizeExactWorkflowSessionForHookCancel(input, "ultragoal");
+}
+
interface ConductorPolicyRootResolution {
cwd: string;
@@ -4049,6 +4833,15 @@ function resolveConductorPolicyRoot(stateDir: string, fallbackCwd: string): Cond
return { cwd: canonicalFallback, valid: !statePresent, statePresent, externalStateRoot: statePresent };
}
+function readDirectPayloadAgentRole(payload: CodexHookPayload): string {
+ const roles = [...new Set([
+ "agent_role",
+ "agentRole",
+ "agent_type",
+ "agentType",
+ ].map((key) => safeString(payload[key]).trim().toLowerCase()).filter(Boolean))];
+ return roles.length === 1 ? roles[0] ?? "" : "";
+}
function readPayloadAgentRole(payload: CodexHookPayload): string {
const directRole = safeString(
@@ -5426,6 +6219,15 @@ const CONDUCTOR_ORCHESTRATION_TOOL_NAMES = new Set([
"multi_agent_v1.spawn_agent",
"multi_agent_v1.close_agent",
]);
+const NATIVE_ULTRAGOAL_ROOT_ORCHESTRATION_TOOL_NAMES = new Set([
+ "collaboration.spawn_agent",
+ "collaboration.close_agent",
+ "collaboration.list_agents",
+ "collaboration.followup_task",
+ "collaboration.wait_agent",
+ "collaboration.send_message",
+ "collaboration.interrupt_agent",
+]);
// Finite native Codex goal-tool identities for Ultragoal reconciliation.
// Canonicalize ONLY exact known host-emitted forms (bare, functions.*, and known
@@ -5465,11 +6267,16 @@ function classifyPreToolUseMutationTransport(
): PreToolUseMutationTransport {
if (toolName === "Bash") {
const command = readPreToolUseCommand(payload);
+ const rawCommand = readPreToolUseRawCommand(payload);
if (
- readPreToolUseRawCommand(payload) === command
+ rawCommand === command
&& (isAllowedOmxReadOnlyCommand(command, cwd) || isAllowedGhReadOnlyCommand(command) || isAllowedVersionProbeCommand(command))
) return "read-only";
- return commandHasDeepInterviewWriteIntent(command, 0, cwd) || collectOmxStateCommandOperations(command, "write").length > 0 || commandHasNestedCliMutationIntent(command) || classifyConductorExecutableRuntime(command, 0, cwd) !== null
+ return rawCommand !== command
+ || commandHasDeepInterviewWriteIntent(command, 0, cwd)
+ || collectOmxStateCommandOperations(command, "write").length > 0
+ || commandHasNestedCliMutationIntent(command)
+ || classifyConductorExecutableRuntime(command, 0, cwd) !== null
? "bash"
: "read-only";
}
@@ -5487,7 +6294,6 @@ function classifyPreToolUseMutationTransport(
return "goal-lifecycle";
}
const canonicalToolName = canonicalizeNativeCollaborationToolName(toolName);
-
if (
CONDUCTOR_ORCHESTRATION_TOOL_NAMES.has(canonicalToolName)
|| canonicalToolName.startsWith("collaboration.")
@@ -9243,7 +10049,17 @@ function isCompleteRalplanTerminalWritePayload(
const mode = safeString(payload.mode).trim().toLowerCase();
if (mode !== "ralplan") return false;
const phase = safeString(payload.current_phase ?? payload.currentPhase).trim().toLowerCase();
- if (payload.active !== false || phase !== "complete") return false;
+ if (payload.active !== false || !new Set(["complete", "blocked", "failed", "cancelled"]).has(phase)) return false;
+ const consensusGate = safeObject(payload.ralplan_consensus_gate);
+ if (phase !== "complete" && consensusGate?.complete === true) return false;
+ if (phase === "blocked") {
+ const expectedBlockedReason = "documented_host_consensus_receipt_unavailable";
+ if (safeString(payload.blocked_reason).trim() !== expectedBlockedReason) return false;
+ if (
+ consensusGate?.complete !== false
+ || safeString(consensusGate.blocked_reason).trim() !== expectedBlockedReason
+ ) return false;
+ }
const payloadSessionId = safeString(payload.session_id).trim();
const activeSessionId = safeString(
@@ -9443,6 +10259,39 @@ function isSingleLiteralShellInvocation(command: string): boolean {
return splitShellCommandSegments(stripHeredocBodiesForCommandScan(normalizedCommand)).length === 1;
}
+function hasUnquotedShellFilenameExpansion(command: string): boolean {
+ let quote: "'" | '"' | null = null;
+ let braceDepth = 0;
+ let braceHasComma = false;
+ for (let index = 0; index < command.length; index += 1) {
+ const char = command[index] ?? "";
+ if (char === "\\" && quote !== "'") {
+ index += 1;
+ continue;
+ }
+ if (char === "'" || char === '"') {
+ quote = quote === char ? null : quote ?? char;
+ continue;
+ }
+ if (quote) continue;
+ if (char === "*" || char === "?" || char === "[") return true;
+ if (char === "{") {
+ braceDepth += 1;
+ if (braceDepth === 1) braceHasComma = false;
+ continue;
+ }
+ if (char === "," && braceDepth > 0) {
+ braceHasComma = true;
+ continue;
+ }
+ if (char === "}" && braceDepth > 0) {
+ braceDepth -= 1;
+ if (braceDepth === 0 && braceHasComma) return true;
+ }
+ }
+ return false;
+}
+
function literalInvocationWords(command: string): string[] {
return tokenizeShellWords(normalizeShellLineContinuations(command).trim()).map(shellWordLiteral);
}
@@ -9502,35 +10351,67 @@ function directCancelOutput(reason: string, handled = false): Record<string, unk
async function handleDirectOmxCancel(input: {
command: string; rawCommand: string; cwd: string; stateDir: string;
- canonicalSessionId: string; payload: CodexHookPayload; allowForce: boolean;
- activeState: Record<string, unknown>;
+ canonicalSessionId: string; payload: CodexHookPayload;
+ activeStates: Record<HookCancelWorkflow, Record<string, unknown>>;
+ skillState: Record<string, unknown>;
+ rootTranscript?: SafeRootTranscriptMetadata | null;
}): Promise<DirectCancelResult> {
const cancelLike = /^[ \t]*omx[ \t]+cancel\b/.test(input.command);
if (!cancelLike) return { kind: "not-direct-cancel" };
- // IR2: hook-owned cancellation is exclusive to active Autopilot
- // deep-interview. Every other workflow falls through to its pre-#3293
- // executable-trust path unchanged.
- if (!hookCancelAutopilotMatches(input.activeState, input.canonicalSessionId, resolve(input.cwd))) {
- return { kind: "not-direct-cancel" };
+ const canonicalCwd = resolve(input.cwd);
+ const autopilotActive = hookCancelAutopilotIsActive(input.activeStates.autopilot);
+ const ultragoalActive = hookCancelUltragoalIsActive(input.activeStates.ultragoal);
+ const autopilotLifecycleMatches = hookCancelAutopilotMatches(input.activeStates.autopilot, input.canonicalSessionId, canonicalCwd, AUTHENTICATED_HOOK_CANCEL_IDENTITY);
+ const ultragoalLifecycleMatches = hookCancelUltragoalMatches(input.activeStates.ultragoal, input.canonicalSessionId, canonicalCwd, AUTHENTICATED_HOOK_CANCEL_IDENTITY);
+ const autopilotSkillMatches = hookCancelSkillMatches(input.skillState, "autopilot", input.canonicalSessionId, canonicalCwd, AUTHENTICATED_HOOK_CANCEL_IDENTITY);
+ const ultragoalSkillMatches = hookCancelSkillMatches(input.skillState, "ultragoal", input.canonicalSessionId, canonicalCwd, AUTHENTICATED_HOOK_CANCEL_IDENTITY);
+ if (ultragoalActive && (!ultragoalLifecycleMatches || !ultragoalSkillMatches)) {
+ return { kind: "denied", reason: "active_state", output: directCancelOutput("active_state") };
+ }
+ const autopilotCandidate = autopilotLifecycleMatches && autopilotSkillMatches;
+ const workflow: HookCancelWorkflow | null = ultragoalLifecycleMatches
+ ? "ultragoal"
+ : autopilotCandidate
+ ? "autopilot"
+ : null;
+ if (!workflow && autopilotActive) {
+ return { kind: "denied", reason: "active_state", output: directCancelOutput("active_state") };
}
- if (input.rawCommand !== input.command || !isDirectOmxCancelCommand(input.command, { allowForce: input.allowForce })) {
+ // Hook-owned cancellation requires both an active matching lifecycle and its
+ // canonical skill mirror. Stale files alone retain the normal executable path.
+ if (!workflow) return { kind: "not-direct-cancel" };
+ if (input.rawCommand !== input.command || !isDirectOmxCancelCommand(input.command, { allowForce: workflow === "ultragoal" })) {
return { kind: "denied", reason: "invalid_command", output: directCancelOutput("invalid_command") };
}
- const aliases = payloadAliasValues(input.payload, ["session_id", "sessionId"]);
- if (!input.canonicalSessionId || aliases.length !== 1 || aliases[0] !== input.canonicalSessionId || payloadHasConflictingIdentityAliases(input.payload)) {
+ if (
+ !hookCancelSessionIdIsSafe(input.canonicalSessionId)
+ || !hookCancelRequiredStringAliasesMatch(
+ input.payload as Record<string, unknown>,
+ ["session_id", "sessionId"],
+ (candidate) => candidate === input.canonicalSessionId,
+ )
+ || payloadHasConflictingIdentityAliases(input.payload)
+ ) {
return { kind: "denied", reason: "session_binding", output: directCancelOutput("session_binding") };
}
- const actor = await resolvePreToolUseWriteActor(input.payload, input.cwd, input.stateDir, input.canonicalSessionId);
+ if (hasSubagentThreadSpawnProvenance(input.payload)) return { kind: "denied", reason: "actor_authority", output: directCancelOutput("actor_authority") };
+ const actor = await resolvePreToolUseWriteActor(
+ input.payload,
+ input.cwd,
+ input.stateDir,
+ input.canonicalSessionId,
+ input.rootTranscript,
+ );
if (actor !== "main-root") return { kind: "denied", reason: "actor_authority", output: directCancelOutput("actor_authority") };
const recovery = await readHookCancelTransactionRecoveryState({ stateDir: input.stateDir, canonicalSessionId: input.canonicalSessionId });
if (recovery) return { kind: "denied", reason: recovery, output: directCancelOutput(recovery) };
- const transaction = await terminalizeExactAutopilotSessionForHookCancel({
+ const transaction = await terminalizeExactWorkflowSessionForHookCancel({
stateDir: input.stateDir,
canonicalSessionId: input.canonicalSessionId,
cwd: input.cwd,
nowIso: new Date().toISOString(),
- });
+ }, workflow, AUTHENTICATED_HOOK_CANCEL_IDENTITY);
if (!transaction.ok) {
const reason = transaction.reason ?? "preflight_failed";
return { kind: "denied", reason, output: directCancelOutput(reason) };
@@ -9761,7 +10642,7 @@ const OMX_NESTED_HELP_COMMANDS = new Set([
"url",
"wiki",
]);
-const OMX_STATE_READ_ONLY_OPERATIONS = new Set(["read", "get-status"]);
+const OMX_STATE_READ_ONLY_OPERATIONS = new Set(["read", "get-status", "list-active"]);
const OMX_HELP_TOKENS = new Set(["--help", "-h"]);
function isAllowedOmxNestedHelpForm(args: readonly string[]): boolean {
@@ -9794,7 +10675,10 @@ function omxOrGjcReadOnlyShapeMatches(command: string): boolean {
if (args.length === 0) return false;
if (args.some((arg) => arg === "--help" || arg === "-h" || arg === "--version" || arg === "-v")) return true;
if (args[0] === "help" || args[0] === "status" || args[0] === "version") return true;
- if (args[0] === "state" && ["read", "get-status", "status"].includes(args[1] ?? "")) return true;
+ if (
+ args[0] === "state"
+ && (OMX_STATE_READ_ONLY_OPERATIONS.has(args[1] ?? "") || args[1] === "status")
+ ) return true;
if (args[0] === "sparkshell") return true;
return args[0] === "cleanup" && args.includes("--dry-run");
}
@@ -9841,6 +10725,9 @@ function isAllowedTrustedAbsoluteOmxReadOnlyCommand(command: string, cwd: string
if (args.length === 1 && (args[0] === "--help" || args[0] === "-h" || args[0] === "--version" || args[0] === "-v")) return true;
if (args.length === 1 && (args[0] === "help" || args[0] === "status" || args[0] === "version")) return true;
if (isAllowedOmxNestedHelpForm(args)) return true;
+ if (args[0] === "state" && OMX_STATE_READ_ONLY_OPERATIONS.has(args[1] ?? "")) {
+ return stateReadTrailingArgsAreSafe(args.slice(2));
+ }
return args.length === 3
&& args[0] === "ultragoal"
&& args[1] === "status"
@@ -9890,6 +10777,7 @@ function isAllowedDeepInterviewCommandSpecificBash(
// untrimmed, differently-named binary.
if (readPreToolUseRawCommand(payload) !== command) return false;
return isAllowedOmxReadOnlyCommand(command, cwd)
+ || isAllowedTrustedAbsoluteOmxReadOnlyCommand(command, cwd)
|| isAllowedGhReadOnlyCommand(command)
|| isAllowedVersionProbeCommand(command);
}
@@ -10152,7 +11040,12 @@ function isAllowedRalplanBashWrite(
// the shell executes a different, untrimmed binary name.
if (
rawCommand === command
- && (isAllowedOmxReadOnlyCommand(command, cwd) || isAllowedGhReadOnlyCommand(command) || isAllowedVersionProbeCommand(command))
+ && (
+ isAllowedOmxReadOnlyCommand(command, cwd)
+ || isAllowedTrustedAbsoluteOmxReadOnlyCommand(command, cwd)
+ || isAllowedGhReadOnlyCommand(command)
+ || isAllowedVersionProbeCommand(command)
+ )
) {
return true;
}
@@ -10368,55 +11261,203 @@ function teamWorkerMutationTargetsProtectedWorkflowState(
|| candidates.some(targetIsProtectedOrAliased);
}
+function hasSafeRalplanMarkdownArtifact(
+ cwd: string,
+ relativeDirectory: string,
+ filenamePattern: RegExp = /\.md$/,
+): boolean {
+ const directory = resolve(cwd, relativeDirectory);
+ try {
+ const directoryMetadata = lstatSync(directory);
+ if (!directoryMetadata.isDirectory() || directoryMetadata.isSymbolicLink()) return false;
+ return readdirSync(directory).slice(0, 256).some((entry) => {
+ if (!filenamePattern.test(entry)) return false;
+ const metadata = lstatSync(join(directory, entry));
+ return metadata.isFile()
+ && !metadata.isSymbolicLink()
+ && metadata.nlink === 1
+ && metadata.size > 0
+ && metadata.size <= 1024 * 1024
+ && (metadata.mode & 0o022) === 0;
+ });
+ } catch {
+ return false;
+ }
+}
-// #3316: `collaboration.send_message` tool_input is inert coordination
-// metadata (`{agent_id, message}`) with no path/command/code payload — it
-// cannot itself execute or mutate anything. It is scoped out of the blanket
-// native-child "orchestration" deny ONLY when a registered child can prove,
-// against the same authoritative session's `subagent-tracking.json`, that it
-// is messaging its own owning leader thread. Every other collaboration.* tool
-// (spawn/close/interrupt/followup/wait_agent) stays gated via the unchanged
-// "orchestration" transport classification, and every other actor/target
-// combination for send_message itself (foreign session, unrelated cross-child,
-// wrong parent/session, malformed/empty/non-string target, unregistered
-// cold-start leader) stays denied fail-closed.
-function readCollaborationSendMessageTargetAgentId(payload: CodexHookPayload): string {
+function hasBoundedRalplanReviewDraftArtifacts(cwd: string): boolean {
+ return hasSafeRalplanMarkdownArtifact(cwd, ".omx/plans")
+ && hasSafeRalplanMarkdownArtifact(cwd, ".omx/specs");
+}
+
+function isBoundedRalplanReviewSequenceIndex(value: unknown): value is number {
+ return typeof value === "number"
+ && Number.isSafeInteger(value)
+ && value >= 1
+ && value <= 5;
+}
+
+function hasBoundedRalplanArchitectReviewEvidence(
+ cwd: string,
+ activeState: Record<string, unknown>,
+): boolean {
+ const nestedState = safeObject(activeState.state);
+ const gate = safeObject(activeState.ralplan_consensus_gate ?? nestedState?.ralplan_consensus_gate);
+ const review = safeObject(gate?.ralplan_architect_review);
+ if (
+ !gate
+ || gate.complete !== false
+ || Object.keys(gate).length !== 2
+ || !Object.hasOwn(gate, "complete")
+ || !Object.hasOwn(gate, "ralplan_architect_review")
+ || !review
+ || safeString(review.agent_role).trim().toLowerCase() !== "architect"
+ || !new Set(["APPROVE", "ITERATE", "REJECT"]).has(safeString(review.verdict).trim().toUpperCase())
+ || !isBoundedRalplanReviewSequenceIndex(review.sequence_index)
+ ) return false;
+ const artifactPath = safeString(review.artifact_path).trim();
+ if (!artifactPath || isAbsolute(artifactPath)) return false;
+ const plansDirectory = resolve(cwd, ".omx/plans");
+ const candidate = resolve(cwd, artifactPath);
+ const relativeCandidate = relative(plansDirectory, candidate);
+ if (!relativeCandidate || relativeCandidate.startsWith("..") || isAbsolute(relativeCandidate)) return false;
+ try {
+ const metadata = lstatSync(candidate);
+ return metadata.isFile()
+ && !metadata.isSymbolicLink()
+ && metadata.nlink === 1
+ && metadata.size > 0
+ && metadata.size <= 1024 * 1024
+ && (metadata.mode & 0o022) === 0;
+ } catch {
+ return false;
+ }
+}
+
+function isExactRalplanReviewSpawn(
+ payload: CodexHookPayload,
+ activeState: Record<string, unknown>,
+ cwd: string,
+): boolean {
+ if (canonicalizeNativeCollaborationToolName(safeString(payload.tool_name).trim()) !== "collaboration.spawn_agent") {
+ return false;
+ }
const input = safeObject(payload.tool_input);
- const value = input?.agent_id;
- return typeof value === "string" ? value.trim() : "";
+ if (!input) return false;
+ const allowedKeys = new Set(["agent_type", "fork_turns", "message", "task_name"]);
+ if (Object.keys(input).some((key) => !allowedKeys.has(key))) return false;
+ const phase = safeString(activeState.current_phase ?? activeState.currentPhase).trim().toLowerCase();
+ const agentType = safeString(input.agent_type).trim().toLowerCase();
+ const expectedAgentType = phase === "architect-review" && hasBoundedRalplanReviewDraftArtifacts(cwd)
+ ? "architect"
+ : phase === "critic-review" && hasBoundedRalplanArchitectReviewEvidence(cwd, activeState)
+ ? "critic"
+ : "";
+ const taskName = safeString(input.task_name).trim();
+ return Boolean(
+ expectedAgentType
+ && agentType === expectedAgentType
+ && input.fork_turns === "none"
+ && safeString(input.message).trim()
+ && /^[a-z][a-z0-9_]{0,63}$/.test(taskName)
+ );
}
-async function resolveAuthorizedSendMessageChildToLeader(
+function isExactRalplanReviewControlPlaneTool(
payload: CodexHookPayload,
- toolName: string,
+ activeState: Record<string, unknown>,
cwd: string,
- sessionId: string,
-): Promise<boolean> {
- if (!sessionId) return false;
- if (canonicalizeNativeCollaborationToolName(toolName) !== "collaboration.send_message") return false;
+): boolean {
+ const toolName = canonicalizeNativeCollaborationToolName(safeString(payload.tool_name).trim());
+ const rawInput = payload.tool_input;
+ if (rawInput === null || typeof rawInput !== "object" || Array.isArray(rawInput)) return false;
+ const input = rawInput as Record<string, unknown>;
+ if (toolName === "collaboration.list_agents") return Object.keys(input).length === 0;
+ if (toolName === "collaboration.wait_agent") {
+ return Object.keys(input).length === 1
+ && Number.isSafeInteger(input.timeout_ms)
+ && Number(input.timeout_ms) >= 10_000
+ && Number(input.timeout_ms) <= 3_600_000;
+ }
+ return isExactRalplanReviewSpawn(payload, activeState, cwd);
+}
- const targetAgentId = readCollaborationSendMessageTargetAgentId(payload);
- if (!targetAgentId) return false;
+function selectedSessionPointerStateRootMatches(
+ pointerState: SessionState,
+ stateDir: string,
+): boolean {
+ // session.json predates state_root. The pointer was loaded from this exact
+ // selected stateDir, so absence is a legacy schema case; an explicit value
+ // is still authoritative and must match exactly.
+ if (!Object.prototype.hasOwnProperty.call(pointerState, "state_root")) return true;
+ if (typeof pointerState.state_root !== "string" || !pointerState.state_root.trim()) return false;
+ return sameFilePath(pointerState.state_root, stateDir);
+}
- const callerId = readPayloadAgentId(payload) || readPayloadThreadId(payload);
- if (!callerId) return false;
+function selectedSessionPointerCodexIdentityMatches(
+ pointerState: SessionState,
+ sessionId: string,
+): boolean {
+ const canonicalSessionId = safeString(pointerState.session_id).trim();
+ if (!sessionId || !canonicalSessionId) return false;
+ if (
+ pointerState.owner_omx_session_id !== undefined
+ && (typeof pointerState.owner_omx_session_id !== "string" || !pointerState.owner_omx_session_id.trim())
+ ) return false;
+ const codexClaims = [
+ pointerState.native_session_id,
+ pointerState.owner_codex_session_id,
+ pointerState.codex_session_id,
+ ].filter((value) => value !== undefined);
+ if (codexClaims.length === 0) return canonicalSessionId === sessionId;
+ return payloadMatchesSessionPointer(sessionId, pointerState)
+ && codexClaims.every((value) => typeof value === "string" && value.trim() === sessionId);
+}
- const trackingState = await readSubagentTrackingState(cwd).catch(() => null);
- const session = trackingState?.sessions?.[sessionId];
- // A leader that has not yet been registered (cold-start) is not treated as
- // an authoritative target here; fail closed rather than silently trust an
- // unregistered identity.
- const leaderThreadId = safeString(session?.leader_thread_id).trim();
- if (!leaderThreadId) return false;
- if (targetAgentId !== leaderThreadId) return false;
+function exactRalplanRootAuthorityMatches(input: {
+ policyCwd: string;
+ stateDir: string;
+ sessionId: string;
+ pointer: SessionPointerReadResult | null;
+ rootTranscript: SafeRootTranscriptMetadata | null;
+}): boolean {
+ const { policyCwd, stateDir, sessionId, pointer, rootTranscript } = input;
+ if (!rootTranscript?.hasExactTurnContext || rootTranscript.sessionId !== sessionId) return false;
+ if (
+ !pointer
+ || (pointer.status !== "usable" && pointer.status !== "identity-indeterminate")
+ || !pointer.state
+ ) return false;
+ const pointerState = pointer.state;
+ if (!selectedSessionPointerCodexIdentityMatches(pointerState, sessionId)) return false;
+ if (!safeString(pointerState.cwd).trim() || !isSessionStateAuthoritativeForCwd(pointerState, policyCwd)) return false;
+ if (!selectedSessionPointerStateRootMatches(pointerState, stateDir)) return false;
+ return true;
+}
- // Target relation must be proven: the caller must itself be a registered
- // subagent thread of this exact session (not an arbitrary same-session
- // cross-child, and not the leader thread messaging itself).
- const callerThread = session?.threads?.[callerId];
- return Boolean(callerThread) && callerThread!.kind === "subagent";
+async function isAuthorizedActiveRalplanRootReviewControlPlane(input: {
+ payload: CodexHookPayload;
+ policyCwd: string;
+ stateDir: string;
+ sessionId: string;
+ pointer: SessionPointerReadResult | null;
+ rootTranscript: SafeRootTranscriptMetadata | null;
+ activeState?: Record<string, unknown> | null;
+}): Promise<boolean> {
+ const { payload, policyCwd, stateDir, sessionId, pointer, rootTranscript } = input;
+ const activeState = input.activeState ?? await readActiveRalplanStateForPreToolUse(
+ policyCwd,
+ stateDir,
+ sessionId,
+ readPayloadThreadId(payload),
+ );
+ if (!activeState || safeString(activeState.mode).trim().toLowerCase() !== "ralplan") return false;
+ return exactRalplanRootAuthorityMatches({ policyCwd, stateDir, sessionId, pointer, rootTranscript })
+ && isExactRalplanReviewControlPlaneTool(payload, activeState, policyCwd);
}
+
+
async function buildRalplanPreToolUseBoundaryOutput(
payload: CodexHookPayload,
cwd: string,
@@ -10424,6 +11465,8 @@ async function buildRalplanPreToolUseBoundaryOutput(
resolvedSessionId?: string,
executionCwd = cwd,
authorityCwd = executionCwd,
+ rootTranscript: SafeRootTranscriptMetadata | null = null,
+ pointer: SessionPointerReadResult | null = null,
): Promise<Record<string, unknown> | null> {
const sessionId = safeString(resolvedSessionId ?? readPayloadSessionId(payload)).trim();
const threadId = readPayloadThreadId(payload);
@@ -10440,7 +11483,7 @@ async function buildRalplanPreToolUseBoundaryOutput(
const command = readPreToolUseCommand(payload);
const pathCandidates = readPreToolUsePathCandidates(payload);
const mutationTransport = classifyPreToolUseMutationTransport(payload, toolName);
- const actor = await resolvePreToolUseWriteActor(payload, authorityCwd, stateDir, sessionId);
+ const actor = await resolvePreToolUseWriteActor(payload, authorityCwd, stateDir, sessionId, rootTranscript);
if (actor === "team-worker") {
if (teamWorkerMutationTargetsProtectedWorkflowState(payload, toolName, command, executionCwd, stateDir)) {
return buildTeamWorkerProtectedStateDeny(
@@ -10451,19 +11494,24 @@ async function buildRalplanPreToolUseBoundaryOutput(
}
return null;
}
+ if (
+ actor === "main-root"
+ && await isAuthorizedActiveRalplanRootReviewControlPlane({
+ payload,
+ policyCwd: cwd,
+ stateDir,
+ sessionId,
+ pointer,
+ rootTranscript,
+ activeState,
+ })
+ ) return null;
const actorMutation = toolName === "Bash"
? commandHasDeepInterviewWriteIntent(command, 0, cwd)
|| collectOmxStateCommandOperations(command, "write").length > 0
|| commandHasNestedCliMutationIntent(command)
: mutationTransport !== "read-only";
- if (
- actorMutation
- && (actor === "native-child" || actor === "provenance-conflict")
- && !(
- actor === "native-child"
- && await resolveAuthorizedSendMessageChildToLeader(payload, toolName, authorityCwd, sessionId)
- )
- ) {
+ if (actorMutation && (actor === "native-child" || actor === "provenance-conflict")) {
return buildPlanningActorWriteDeny(
safeString(activeState.mode).trim().toLowerCase() === "autopilot" ? "Autopilot planning" : "Ralplan",
formatPhase(activeState.current_phase ?? activeState.currentPhase, "planning"),
@@ -10500,7 +11548,7 @@ async function buildRalplanPreToolUseBoundaryOutput(
blockedDetail = describeImplementationToolBlock(toolName, blockedPath, toolPathCandidates.length);
}
}
- } else if (mutationTransport === "unknown" || mutationTransport === "goal-lifecycle") {
+ } else if (mutationTransport === "unknown" || mutationTransport === "goal-lifecycle" || mutationTransport === "orchestration") {
blocked = true;
blockedDetail = `${toolName || "unknown tool"} is not a recognized read-only or explicitly authorized planning mutation transport`;
}
@@ -10528,15 +11576,27 @@ async function buildRalplanPreToolUseBoundaryOutput(
};
}
-function buildRawProtectedWorkflowStatePathOutput(
+async function buildRawProtectedWorkflowStatePathOutput(
payload: CodexHookPayload,
cwd: string,
stateDir: string,
-): Record<string, unknown> | null {
+ authoritativeSessionId = "",
+ activeConductor = false,
+ rootTranscript: SafeRootTranscriptMetadata | null = null,
+): Promise<Record<string, unknown> | null> {
const toolName = safeString(payload.tool_name).trim();
if (classifyPreToolUseMutationTransport(payload, toolName, cwd) !== "path") return null;
const candidates = collectImplementationToolPathCandidates(payload, toolName, readPreToolUsePathCandidates(payload));
- const protectedPath = candidates.find((candidate) => isRawProtectedPlanningStateCandidate(stateDir, cwd, candidate));
+ const protectedCandidates = candidates.filter((candidate) => isRawProtectedPlanningStateCandidate(stateDir, cwd, candidate));
+ if (
+ nativeSubagentAssignmentsOptedIn()
+ && activeConductor
+ && authoritativeSessionId
+ && protectedCandidates.length > 0
+ && protectedCandidates.every((candidate) => isSessionBoundNativeAssignmentPath(cwd, candidate, authoritativeSessionId))
+ && await resolvePreToolUseWriteActor(payload, cwd, stateDir, authoritativeSessionId, rootTranscript) === "main-root"
+ ) return null;
+ const protectedPath = protectedCandidates[0];
if (protectedPath === undefined) return null;
return {
decision: "block",
@@ -10555,6 +11615,7 @@ async function buildDeepInterviewPreToolUseBoundaryOutput(
resolvedSessionId?: string,
executionCwd = cwd,
authorityCwd = executionCwd,
+ rootTranscript: SafeRootTranscriptMetadata | null = null,
): Promise<Record<string, unknown> | null> {
const sessionId = safeString(resolvedSessionId ?? readPayloadSessionId(payload)).trim();
const threadId = readPayloadThreadId(payload);
@@ -10571,7 +11632,7 @@ async function buildDeepInterviewPreToolUseBoundaryOutput(
const command = readPreToolUseCommand(payload);
const pathCandidates = readPreToolUsePathCandidates(payload);
const mutationTransport = classifyPreToolUseMutationTransport(payload, toolName);
- const actor = await resolvePreToolUseWriteActor(payload, authorityCwd, stateDir, sessionId);
+ const actor = await resolvePreToolUseWriteActor(payload, authorityCwd, stateDir, sessionId, rootTranscript);
if (actor === "team-worker") {
if (teamWorkerMutationTargetsProtectedWorkflowState(payload, toolName, command, executionCwd, stateDir)) {
return buildTeamWorkerProtectedStateDeny(
@@ -10587,14 +11648,7 @@ async function buildDeepInterviewPreToolUseBoundaryOutput(
|| collectOmxStateCommandOperations(command, "write").length > 0
|| commandHasNestedCliMutationIntent(command)
: mutationTransport !== "read-only";
- if (
- actorMutation
- && (actor === "native-child" || actor === "provenance-conflict")
- && !(
- actor === "native-child"
- && await resolveAuthorizedSendMessageChildToLeader(payload, toolName, authorityCwd, sessionId)
- )
- ) {
+ if (actorMutation && (actor === "native-child" || actor === "provenance-conflict")) {
return buildPlanningActorWriteDeny(
"Deep-interview",
formatPhase(activeState.current_phase ?? activeState.currentPhase, "planning"),
@@ -10626,7 +11680,7 @@ async function buildDeepInterviewPreToolUseBoundaryOutput(
const blockedPath = candidates.find((candidate) => !isAllowedDeepInterviewArtifactPath(cwd, candidate, sessionId));
blockedDetail = describeImplementationToolBlock(toolName, blockedPath, candidates.length);
}
- } else if (mutationTransport === "unknown" || mutationTransport === "goal-lifecycle") {
+ } else if (mutationTransport === "unknown" || mutationTransport === "goal-lifecycle" || mutationTransport === "orchestration") {
blocked = true;
blockedDetail = `${toolName || "unknown tool"} is not a recognized read-only or explicitly authorized deep-interview mutation transport`;
}
@@ -10667,7 +11721,7 @@ function blocksDeepInterviewImplementationWrite(payload: CodexHookPayload, cwd:
return !isAllowedDeepInterviewBashWrite(cwd, readPreToolUseCommand(payload), undefined, authoritativeSessionId);
}
const mutationTransport = classifyPreToolUseMutationTransport(payload, toolName);
- if (mutationTransport === "unknown" || mutationTransport === "goal-lifecycle") return true;
+ if (mutationTransport === "unknown" || mutationTransport === "goal-lifecycle" || mutationTransport === "orchestration") return true;
if (mutationTransport !== "path") return false;
const candidates = collectImplementationToolPathCandidates(
payload,
@@ -10785,7 +11839,7 @@ async function buildPlanningRootPointerConflictPreToolUseOutput(
);
blocked = toolPathCandidates.length === 0
|| toolPathCandidates.some((candidate) => !isAllowedRalplanArtifactPath(cwd, candidate, rootSessionId));
- } else if (mutationTransport === "unknown" || mutationTransport === "goal-lifecycle") {
+ } else if (mutationTransport === "unknown" || mutationTransport === "goal-lifecycle" || mutationTransport === "orchestration") {
blocked = true;
}
@@ -10799,6 +11853,103 @@ interface ActiveConductorState {
type PreToolUseWriteActor = "main-root" | "native-child" | "provenance-conflict" | "team-worker";
+type NativeAssignmentAction = "path-write" | "bash-write";
+
+interface NativeSubagentAssignment {
+ schema_version: 1;
+ kind: "native-subagent-assignment";
+ lifecycle: "active";
+ root_session_id: string;
+ root_thread_id: string;
+ child_agent_id: string;
+ agent_type: string;
+ allowed_actions: NativeAssignmentAction[];
+ path_prefixes: string[];
+ issued_at: string;
+ expires_at: string;
+ bootstrap_generation: string;
+}
+
+
+function nativeAssignmentPath(stateDir: string, sessionId: string, childAgentId: string): string {
+ return join(
+ stateDir,
+ "sessions",
+ sessionId,
+ NATIVE_ASSIGNMENT_DIRECTORY,
+ `${encodeURIComponent(childAgentId)}.json`,
+ );
+}
+
+function isNativeAssignmentPath(stateDir: string, rawPath: string, executionCwd: string): boolean {
+ const absolute = isAbsolute(rawPath) ? resolve(rawPath) : resolve(executionCwd, rawPath);
+ const assignmentRoot = resolve(stateDir, "sessions");
+ const relativePath = relative(assignmentRoot, absolute).replace(/\\/g, "/");
+ return relativePath !== ""
+ && !relativePath.startsWith("../")
+ && /^.+\/native-assignments(?:\/|$)/.test(relativePath);
+}
+
+async function readNativeSubagentAssignment(
+ payload: CodexHookPayload,
+ cwd: string,
+ stateDir: string,
+ sessionId: string,
+): Promise<NativeSubagentAssignment | null> {
+ if (!nativeSubagentAssignmentsOptedIn()) return null;
+ const payloadSessionId = readUnambiguousNormalizedPayloadSessionId(payload);
+ const childAgentId = readPayloadAgentId(payload)
+ || readPayloadThreadId(payload)
+ || readPayloadTranscriptChildId(payload)
+ || (payloadSessionId && payloadSessionId !== sessionId ? payloadSessionId : "");
+ const agentType = readDirectPayloadAgentRole(payload) || "executor";
+ if (!childAgentId || resolveInstalledRoleName(agentType, undefined, cwd) === null) return null;
+
+ const trackingState = await readSubagentTrackingState(cwd).catch(() => null);
+ const trackedSession = safeObject(trackingState?.sessions?.[sessionId]);
+ const bootstrap = await readNativeUltragoalBootstrap(stateDir, sessionId);
+ const leaderThreadId = safeString(trackedSession?.leader_thread_id ?? bootstrap?.root_thread_id).trim();
+ if (!leaderThreadId) return null;
+ const identity = await validateLocalNativeExecutorIdentity({
+ cwd,
+ sessionId,
+ rootThreadId: leaderThreadId,
+ childAgentId,
+ receiptNotBefore: bootstrap?.created_at,
+ receiptNotAfter: bootstrap?.expires_at,
+ });
+ if (!identity.ok) return null;
+
+ const path = nativeAssignmentPath(stateDir, sessionId, childAgentId);
+ if (!await nativeExecutorAssignmentFileIsSafe(stateDir, path)) return null;
+ let raw: Record<string, unknown> | null = null;
+ try {
+ raw = safeObject(JSON.parse(readFileSync(path, "utf-8")));
+ } catch {
+ return null;
+ }
+ const assignment = await parseActiveLocalNativeExecutorAssignment(raw, {
+ cwd,
+ sessionId,
+ rootThreadId: leaderThreadId,
+ childAgentId,
+ agentType,
+ });
+ if (!assignment) return null;
+ const ready = await findReadyLocalNativeExecutorAssignment({
+ cwd,
+ stateDir,
+ sessionId,
+ rootThreadId: leaderThreadId,
+ });
+ if (
+ !ready
+ || ready.child_agent_id !== assignment.child_agent_id
+ || ready.bootstrap_generation !== assignment.bootstrap_generation
+ ) return null;
+ return assignment;
+}
+
function hasSubagentThreadSpawnProvenance(payload: CodexHookPayload): boolean {
const source = payload.source;
if (!source || typeof source !== "object") return false;
@@ -10812,6 +11963,7 @@ async function resolvePreToolUseWriteActor(
cwd: string,
stateDir: string,
sessionId: string,
+ rootTranscript: SafeRootTranscriptMetadata | null = null,
): Promise<PreToolUseWriteActor> {
if (payloadHasConflictingIdentityAliases(payload)) return "provenance-conflict";
const unofficialAgentId = safeString(payload.agentId).trim();
@@ -10822,18 +11974,31 @@ async function resolvePreToolUseWriteActor(
const session = trackingState?.sessions?.[sessionId];
const payloadThreadId = readPayloadThreadId(payload);
const payloadAgentId = readPayloadAgentId(payload);
+ const payloadTranscriptChildId = readPayloadTranscriptChildId(payload);
if (payloadAgentId && payloadThreadId && payloadAgentId !== payloadThreadId) return "provenance-conflict";
+ if (payloadTranscriptChildId && payloadTranscriptChildId !== sessionId) return "native-child";
const leaderAnchors = new Set<string>();
const trackerLeader = safeString(session?.leader_thread_id).trim();
if (trackerLeader) leaderAnchors.add(trackerLeader);
- if (leaderAnchors.has(payloadAgentId) || leaderAnchors.has(payloadThreadId)) return "main-root";
+ if (leaderAnchors.has(payloadAgentId) || leaderAnchors.has(payloadThreadId)) {
+ const hasCompanionIdentityClaim = payloadHasOwnerIdentityClaim(payload)
+ || ["agent_role", "agentRole", "agent_type", "agentType"].some((key) => (
+ Object.prototype.hasOwnProperty.call(payload, key)
+ ));
+ return hasCompanionIdentityClaim ? "provenance-conflict" : "main-root";
+ }
const rootSessionState = await readRootSessionStateFromStateDir(stateDir).catch(() => null);
const payloadSessionId = readPayloadSessionId(payload);
const leaderNativeSessionId = rootSessionState && payloadMatchesSessionPointer(sessionId, rootSessionState)
? safeString(rootSessionState.native_session_id).trim()
: "";
if (!payloadAgentId && !payloadThreadId && leaderNativeSessionId && payloadSessionId === leaderNativeSessionId) return "main-root";
+ if (
+ !payloadAgentId
+ && rootTranscript?.sessionId === payloadSessionId
+ && rootTranscript.hasExactTurnContext
+ ) return "main-root";
if (hasSubagentThreadSpawnProvenance(payload)) return "native-child";
if (payloadHasOwnerIdentityClaim(payload)) return "native-child";
@@ -10930,6 +12095,25 @@ const ULTRAGOAL_NO_OWNER_DENY_REASON =
+ "is tmux-only, and native child/descendant provenance intentionally does not grant write authority (see #3127). "
+ "Activating Conductor mode here would deadlock with only `omx cancel` reachable.";
+const ULTRAGOAL_HOST_RECEIPT_UNAVAILABLE_REASON =
+ `OMX-ULTRAGOAL-HOST-RECEIPT-UNAVAILABLE: ${DOCUMENTED_HOST_RECEIPT_UNAVAILABLE}. `
+ + "Host-backed native executor authority remains fail-closed until Codex exposes a documented receipt verifier.";
+
+function buildNativeUltragoalBootstrapRequiredReason(
+ sessionId: string,
+ rootThreadId: string,
+ generation: string,
+): string {
+ return "OMX-ULTRAGOAL-BOOTSTRAP-REQUIRED: typed native execution is available, but Ultragoal activation remains "
+ + "inactive until an exact executor is spawned and authorized. Spawn one typed `executor` with instructions to "
+ + "wait without tool calls for a follow-up after activation. Retain the returned agent path, then run "
+ + "`omx ultragoal native-bootstrap authorize "
+ + `--session-id ${JSON.stringify(sessionId)} --root-thread-id ${JSON.stringify(rootThreadId)} `
+ + `--bootstrap-generation ${JSON.stringify(generation)} `
+ + "--child-path <spawned-agent-path> --path-prefix . --json`, then retry the canonical Ultragoal state activation "
+ + "and use `followup_task` to start the authorized executor work. ";
+}
+
function collectUltragoalActivationCandidatePayloads(
payload: CodexHookPayload,
toolName: string,
@@ -10965,12 +12149,371 @@ function isUltragoalConductorActivationPayload(input: Record<string, unknown> |
return isNonTerminalPhase(flattened.current_phase ?? flattened.currentPhase);
}
+const ACTIVE_ULTRAGOAL_PHASE_TRANSITION_PHASES = new Set([
+ "planning",
+ "executing",
+ "verifying",
+ "reviewing",
+ "checkpointing",
+ "blocked",
+]);
+
+function isExactActiveUltragoalPhaseTransitionPayload(input: Record<string, unknown>): boolean {
+ const keys = Object.keys(input);
+ if (
+ keys.length !== 3
+ || !keys.includes("mode")
+ || !keys.includes("active")
+ || (keys.includes("current_phase") === keys.includes("currentPhase"))
+ ) return false;
+ const phase = safeString(input.current_phase ?? input.currentPhase).trim().toLowerCase();
+ return input.mode === "ultragoal"
+ && input.active === true
+ && ACTIVE_ULTRAGOAL_PHASE_TRANSITION_PHASES.has(phase);
+}
+
+function isTrustedDirectOmxStateCommand(
+ command: string,
+ words: string[],
+ cwd: string,
+): boolean {
+ const commandWord = shellWordLiteral(words[0] ?? "");
+ if (commandWord === "omx") return true;
+ if (
+ !isAbsolute(commandWord)
+ || !commandWord.includes("/")
+ || commandNameFromShellWord(commandWord) !== "omx"
+ || commandHasUnsafeDynamicLoaderEnvironment(command)
+ || commandHasUnsafeLeadingRuntimeEnvironment(command)
+ ) return false;
+ const unsafeInheritedNames = [
+ ...OMX_GJC_TRUSTED_CONTEXT_UNSAFE_INHERITED_ENV_NAMES,
+ ...CONDUCTOR_NODE_OUTPUT_ENVIRONMENT_NAMES,
+ ];
+ if (unsafeInheritedNames.some((name) => safeString(process.env[name]).trim() !== "")) return false;
+ const state = resolveConductorCommandPathState(words, 0, 0, createConductorRuntimeShellState(cwd));
+ return conductorSlashCommandIsTrusted(commandWord, state, cwd);
+}
+
+function isExactActiveUltragoalPhaseTransitionTransport(
+ payload: CodexHookPayload,
+ cwd: string,
+): boolean {
+ const toolName = safeString(payload.tool_name).trim();
+ if (toolName === "mcp__omx_state__state_write") {
+ const input = safeObject(payload.tool_input);
+ return Boolean(input && isExactActiveUltragoalPhaseTransitionPayload(input));
+ }
+ if (toolName !== "Bash") return false;
+ const command = readPreToolUseCommand(payload);
+ if (!isSingleLiteralShellInvocation(command)) return false;
+ const words = tokenizeConductorShellWords(command);
+ const invocations = collectShellCliInvocations(words);
+ if (invocations.length !== 1 || invocations[0]?.commandIndex !== 0) return false;
+ if (!isTrustedDirectOmxStateCommand(command, words, cwd)) return false;
+ if (!isStaticallyValidatedOmxStateWriteInvocation(words, 0)) return false;
+ const payloads = readAllStateWriteInputPayloads(cwd, command);
+ return payloads.length === 1 && isExactActiveUltragoalPhaseTransitionPayload(payloads[0]!);
+}
+
+function isExactTerminalUltragoalStatePayload(input: Record<string, unknown>): boolean {
+ const keys = Object.keys(input);
+ return keys.length === 3
+ && keys.includes("mode")
+ && keys.includes("active")
+ && keys.includes("current_phase")
+ && input.mode === "ultragoal"
+ && input.active === false
+ && input.current_phase === "complete";
+}
+
+function isExactTerminalUltragoalStateTransport(
+ payload: CodexHookPayload,
+ cwd: string,
+): boolean {
+ const toolName = safeString(payload.tool_name).trim();
+ if (toolName === "mcp__omx_state__state_write") {
+ const input = safeObject(payload.tool_input);
+ return Boolean(input && isExactTerminalUltragoalStatePayload(input));
+ }
+ if (toolName !== "Bash") return false;
+ const command = readPreToolUseCommand(payload);
+ if (!isSingleLiteralShellInvocation(command)) return false;
+ const words = tokenizeConductorShellWords(command);
+ const invocations = collectShellCliInvocations(words);
+ if (invocations.length !== 1 || invocations[0]?.commandIndex !== 0) return false;
+ if (!isTrustedDirectOmxStateCommand(command, words, cwd)) return false;
+ if (!isStaticallyValidatedOmxStateWriteInvocation(words, 0)) return false;
+ const payloads = readAllStateWriteInputPayloads(cwd, command);
+ return payloads.length === 1 && isExactTerminalUltragoalStatePayload(payloads[0]!);
+}
+
+async function readPinnedJsonObject(path: string): Promise<Record<string, unknown> | null> {
+ const metadata = await lstat(path).catch(() => null);
+ if (
+ !metadata
+ || !metadata.isFile()
+ || metadata.isSymbolicLink()
+ || metadata.nlink !== 1
+ || (metadata.mode & 0o022) !== 0
+ ) return null;
+ const handle = await open(path, fsConstants.O_RDONLY | (fsConstants.O_NOFOLLOW ?? 0)).catch(() => null);
+ if (!handle) return null;
+ try {
+ const openedMetadata = await handle.stat();
+ if (
+ !openedMetadata.isFile()
+ || openedMetadata.nlink !== 1
+ || (openedMetadata.mode & 0o022) !== 0
+ || openedMetadata.dev !== metadata.dev
+ || openedMetadata.ino !== metadata.ino
+ ) return null;
+ const raw = await handle.readFile({ encoding: "utf-8" });
+ const finalMetadata = await lstat(path).catch(() => null);
+ if (
+ !finalMetadata
+ || !finalMetadata.isFile()
+ || finalMetadata.isSymbolicLink()
+ || finalMetadata.nlink !== 1
+ || (finalMetadata.mode & 0o022) !== 0
+ || finalMetadata.dev !== metadata.dev
+ || finalMetadata.ino !== metadata.ino
+ || finalMetadata.size !== metadata.size
+ || Buffer.byteLength(raw, "utf-8") !== metadata.size
+ ) return null;
+ return safeObject(JSON.parse(raw));
+ } catch {
+ return null;
+ } finally {
+ await handle.close().catch(() => {});
+ }
+}
+
+async function readPinnedActiveUltragoalSessionState(
+ stateDir: string,
+ sessionId: string,
+): Promise<Record<string, unknown> | null> {
+ const path = join(stateDir, "sessions", sessionId, "ultragoal-state.json");
+ const metadata = await lstat(path).catch(() => null);
+ if (
+ !metadata
+ || !metadata.isFile()
+ || metadata.isSymbolicLink()
+ || metadata.nlink !== 1
+ || (metadata.mode & 0o022) !== 0
+ ) return null;
+ const handle = await open(path, fsConstants.O_RDONLY | (fsConstants.O_NOFOLLOW ?? 0)).catch(() => null);
+ if (!handle) return null;
+ try {
+ const openedMetadata = await handle.stat();
+ if (
+ !openedMetadata.isFile()
+ || openedMetadata.nlink !== 1
+ || (openedMetadata.mode & 0o022) !== 0
+ || openedMetadata.dev !== metadata.dev
+ || openedMetadata.ino !== metadata.ino
+ ) return null;
+ const raw = await handle.readFile({ encoding: "utf-8" });
+ const state = safeObject(JSON.parse(raw));
+ const persistedMode = safeString(state?.mode).trim();
+ const persistedSessionAliases = state ? [
+ state.session_id,
+ state.owner_omx_session_id,
+ state.codex_session_id,
+ state.owner_codex_session_id,
+ ].filter((value) => value !== undefined) : [];
+ if (
+ !state
+ || (persistedMode !== "" && persistedMode !== "ultragoal")
+ || state.active !== true
+ || persistedSessionAliases.some((value) => safeString(value).trim() !== sessionId)
+ || !ACTIVE_ULTRAGOAL_PHASE_TRANSITION_PHASES.has(
+ safeString(state.current_phase ?? state.currentPhase).trim().toLowerCase(),
+ )
+ ) return null;
+ return state;
+ } catch {
+ return null;
+ } finally {
+ await handle.close().catch(() => {});
+ }
+}
+
+async function isAuthorizedTerminalUltragoalStateFallback(input: {
+ payload: CodexHookPayload;
+ policyCwd: string;
+ stateDir: string;
+ sessionId: string;
+ pointer: SessionPointerReadResult | null;
+ rootTranscript: SafeRootTranscriptMetadata | null;
+}): Promise<boolean> {
+ const { payload, policyCwd, stateDir, sessionId, pointer, rootTranscript } = input;
+ if (!rootTranscript?.hasExactTurnContext || rootTranscript.sessionId !== sessionId) return false;
+ if (
+ !pointer
+ || (pointer.status !== "usable" && pointer.status !== "identity-indeterminate")
+ || !pointer.state
+ ) return false;
+ const pointerState = pointer.state;
+ if (!selectedSessionPointerCodexIdentityMatches(pointerState, sessionId)) return false;
+ if (!safeString(pointerState.cwd).trim() || !isSessionStateAuthoritativeForCwd(pointerState, policyCwd)) return false;
+ if (!selectedSessionPointerStateRootMatches(pointerState, stateDir)) return false;
+ if (!isExactTerminalUltragoalStateTransport(payload, policyCwd)) return false;
+
+ const activeState = await readPinnedActiveUltragoalSessionState(stateDir, sessionId);
+ if (safeString(activeState?.current_phase ?? activeState?.currentPhase).trim().toLowerCase() !== "checkpointing") {
+ return false;
+ }
+ const plan = await readPinnedJsonObject(join(policyCwd, ".omx", "ultragoal", "goals.json"));
+ const goals = Array.isArray(plan?.goals) ? plan.goals : [];
+ const aggregateCompletion = safeObject(plan?.aggregateCompletion);
+ if (
+ goals.length === 0
+ || goals.some((goal) => safeString(safeObject(goal)?.status).trim().toLowerCase() !== "complete")
+ || safeString(aggregateCompletion?.status).trim().toLowerCase() !== "complete"
+ ) return false;
+
+ const bootstrap = await readNativeUltragoalBootstrap(stateDir, sessionId);
+ if (
+ !bootstrap
+ || bootstrap.status !== "revoked"
+ || bootstrap.session_id !== sessionId
+ || bootstrap.root_thread_id !== rootTranscript.sessionId
+ || !bootstrap.child_agent_id
+ ) return false;
+ const assignment = await findReadyLocalNativeExecutorAssignment({
+ cwd: policyCwd,
+ stateDir,
+ sessionId,
+ rootThreadId: rootTranscript.sessionId,
+ });
+ return assignment === null;
+}
+
+async function isAuthorizedActiveUltragoalPhaseTransitionFallback(input: {
+ payload: CodexHookPayload;
+ policyCwd: string;
+ stateDir: string;
+ sessionId: string;
+ pointer: SessionPointerReadResult | null;
+ rootTranscript: SafeRootTranscriptMetadata | null;
+}): Promise<boolean> {
+ const { payload, policyCwd, stateDir, sessionId, pointer, rootTranscript } = input;
+ if (!rootTranscript?.hasExactTurnContext || rootTranscript.sessionId !== sessionId) return false;
+ if (
+ !pointer
+ || (pointer.status !== "usable" && pointer.status !== "identity-indeterminate")
+ || !pointer.state
+ ) return false;
+ const pointerState = pointer.state;
+ if (!selectedSessionPointerCodexIdentityMatches(pointerState, sessionId)) return false;
+ if (!safeString(pointerState.cwd).trim() || !isSessionStateAuthoritativeForCwd(pointerState, policyCwd)) return false;
+ if (!selectedSessionPointerStateRootMatches(pointerState, stateDir)) return false;
+ if (!isExactActiveUltragoalPhaseTransitionTransport(payload, policyCwd)) return false;
+ if (!await readPinnedActiveUltragoalSessionState(stateDir, sessionId)) return false;
+ const bootstrap = await readNativeUltragoalBootstrap(stateDir, sessionId);
+ if (
+ !bootstrap
+ || bootstrap.status !== "active"
+ || bootstrap.session_id !== sessionId
+ || bootstrap.root_thread_id !== rootTranscript.sessionId
+ || !bootstrap.child_agent_id
+ ) return false;
+ const assignment = await findReadyLocalNativeExecutorAssignment({
+ cwd: policyCwd,
+ stateDir,
+ sessionId,
+ rootThreadId: rootTranscript.sessionId,
+ });
+ return Boolean(
+ assignment
+ && assignment.child_agent_id === bootstrap.child_agent_id
+ && assignment.bootstrap_generation === bootstrap.generation,
+ );
+}
+
+async function isAuthorizedActiveUltragoalRootControlPlane(input: {
+ payload: CodexHookPayload;
+ policyCwd: string;
+ stateDir: string;
+ sessionId: string;
+ pointer: SessionPointerReadResult | null;
+ rootTranscript: SafeRootTranscriptMetadata | null;
+}): Promise<boolean> {
+ const { payload, policyCwd, stateDir, sessionId, pointer, rootTranscript } = input;
+ const toolName = safeString(payload.tool_name).trim();
+ const isGoalLifecycle = (
+ NATIVE_CODEX_GOAL_LIFECYCLE_TOOL_NAMES.has(toolName)
+ || NATIVE_CODEX_GOAL_LIFECYCLE_TOOL_NAMES.has(canonicalizeNativeCodexGoalToolName(toolName))
+ );
+ const isNativeOrchestration = NATIVE_ULTRAGOAL_ROOT_ORCHESTRATION_TOOL_NAMES.has(
+ canonicalizeNativeCollaborationToolName(toolName),
+ );
+ if (
+ !isGoalLifecycle
+ && !isNativeOrchestration
+ ) return false;
+ if (!rootTranscript?.hasExactTurnContext || rootTranscript.sessionId !== sessionId) return false;
+ if (
+ !pointer
+ || (pointer.status !== "usable" && pointer.status !== "identity-indeterminate")
+ || !pointer.state
+ ) return false;
+ const pointerState = pointer.state;
+ if (!selectedSessionPointerCodexIdentityMatches(pointerState, sessionId)) return false;
+ if (!safeString(pointerState.cwd).trim() || !isSessionStateAuthoritativeForCwd(pointerState, policyCwd)) return false;
+ if (!selectedSessionPointerStateRootMatches(pointerState, stateDir)) return false;
+ if (!await readPinnedActiveUltragoalSessionState(stateDir, sessionId)) return false;
+ let bootstrap = await readNativeUltragoalBootstrap(stateDir, sessionId);
+ if (
+ !bootstrap
+ || (bootstrap.status !== "active" && bootstrap.status !== "activating")
+ || bootstrap.session_id !== sessionId
+ || bootstrap.root_thread_id !== rootTranscript.sessionId
+ || !bootstrap.child_agent_id
+ ) return false;
+ // A successful activation write is durable before PostToolUse runs. Codex can
+ // omit enough command detail from that PostToolUse payload that the eager
+ // promotion is missed, leaving a valid receipt stuck at `activating`. The
+ // first exact Main-root control-plane call is a safe reconciliation point:
+ // pinned active state plus the same validated child receipt proves that the
+ // guarded activation completed. Promote under the native lifecycle lock.
+ if (bootstrap.status === "activating") {
+ const promoted = await markNativeUltragoalBootstrapActive({
+ cwd: policyCwd,
+ stateDir,
+ sessionId,
+ childAgentId: bootstrap.child_agent_id,
+ });
+ if (!promoted.ok) return false;
+ bootstrap = await readNativeUltragoalBootstrap(stateDir, sessionId);
+ if (!bootstrap || bootstrap.status !== "active") return false;
+ }
+ const assignment = await findReadyLocalNativeExecutorAssignment({
+ cwd: policyCwd,
+ stateDir,
+ sessionId,
+ rootThreadId: rootTranscript.sessionId,
+ });
+ return Boolean(
+ assignment
+ && assignment.child_agent_id === bootstrap.child_agent_id
+ && assignment.bootstrap_generation === bootstrap.generation,
+ );
+}
+
+/** @internal Test-only authority evaluator for the session-scoped phase fallback. */
+export const __isAuthorizedActiveUltragoalPhaseTransitionFallbackForTests =
+ isAuthorizedActiveUltragoalPhaseTransitionFallback;
+
async function buildUltragoalNoOwnerActivationGuardOutput(
payload: CodexHookPayload,
cwd: string,
stateDir: string,
resolvedSessionId?: string,
policyCwd = cwd,
+ rootTranscript: SafeRootTranscriptMetadata | null = null,
+ pointer: SessionPointerReadResult | null = null,
): Promise<Record<string, unknown> | null> {
const toolName = safeString(payload.tool_name).trim();
if (toolName !== "Bash" && toolName !== "mcp__omx_state__state_write") return null;
@@ -10980,21 +12523,120 @@ async function buildUltragoalNoOwnerActivationGuardOutput(
const sessionId = safeString(resolvedSessionId ?? readPayloadSessionId(payload)).trim();
if (!sessionId) return null;
+ if (
+ rootTranscript?.hasExactTurnContext
+ && rootTranscript.sessionId === sessionId
+ && pointer?.state
+ && !payloadMatchesSessionPointer(sessionId, pointer.state)
+ && isExactActiveUltragoalPhaseTransitionTransport(payload, policyCwd)
+ ) {
+ return {
+ decision: "block",
+ reason: "OMX-ULTRAGOAL-FOREIGN-SESSION: the exact root phase transition does not match the selected workspace session pointer.",
+ hookSpecificOutput: {
+ hookEventName: "PreToolUse",
+ additionalContext: "The selected session pointer belongs to another Ultragoal session; phase writes remain fail-closed.",
+ },
+ };
+ }
+
// Already-active sessions (phase updates, resumption, or recovery on an
// existing stuck state) remain governed by the existing Conductor write
// guard and `omx cancel`, not this pre-activation refusal.
if (await readActiveConductorStateForPreToolUse(payload, policyCwd, stateDir, sessionId)) return null;
- const writeActor = await resolvePreToolUseWriteActor(payload, cwd, stateDir, sessionId);
+ const writeActor = await resolvePreToolUseWriteActor(payload, cwd, stateDir, sessionId, rootTranscript);
if (writeActor !== "main-root") return null;
+ if (await isAuthorizedActiveUltragoalPhaseTransitionFallback({
+ payload,
+ policyCwd,
+ stateDir,
+ sessionId,
+ pointer,
+ rootTranscript,
+ })) return null;
+
const executionSurface = resolveCodexExecutionSurface(cwd, {
hookEventName: "PreToolUse",
payload,
canonicalSessionId: sessionId,
nativeSessionId: readPayloadThreadId(payload),
});
- if (executionSurface.launcher !== "native" || executionSurface.transport !== "outside-tmux") return null;
+ const rootThreadId = resolveNativeUltragoalRootThreadId(sessionId, payload, rootTranscript);
+ const nativeConfig = resolveNativeUltragoalConfig();
+ if (nativeConfig.backend === "off") {
+ if (executionSurface.launcher !== "native" || executionSurface.transport !== "outside-tmux") return null;
+ } else if (
+ executionSurface.launcher !== "native"
+ && !(rootTranscript?.hasExactTurnContext && rootTranscript.sessionId === sessionId)
+ ) return null;
+ if (nativeConfig.backend === "host") {
+ return {
+ decision: "block",
+ reason: ULTRAGOAL_HOST_RECEIPT_UNAVAILABLE_REASON,
+ hookSpecificOutput: {
+ hookEventName: "PreToolUse",
+ additionalContext: ULTRAGOAL_HOST_RECEIPT_UNAVAILABLE_REASON,
+ },
+ };
+ }
+ if (nativeConfig.backend === "local-experimental" && rootThreadId) {
+ let bootstrap = await readNativeUltragoalBootstrap(stateDir, sessionId);
+ if (!bootstrap) {
+ const nativeSupport = resolveNativeSubagentSupportStatus({
+ payload,
+ persistedSupportBlocker: await readJsonIfExists(nativeSubagentSupportBlockerPath(stateDir)),
+ persistedRoleRoutingMarker: readRoleRoutingMarker(stateDir, { cwd, sessionId }),
+ persistedCapacityBlocker: await readJsonIfExists(nativeSubagentCapacityBlockerPath(stateDir)),
+ cwd,
+ sessionId,
+ });
+ if (
+ payloadAdvertisesTypedNativeSpawn(payload, rootTranscript)
+ && (
+ nativeSupport.status === "supported"
+ || payloadAdvertisesCodexAppV2NativeSpawn(payload)
+ || rootTranscript?.hasTypedNativeSpawn === true
+ )
+ ) {
+ bootstrap = await beginNativeUltragoalBootstrap({
+ cwd: policyCwd,
+ stateDir,
+ sessionId,
+ rootThreadId,
+ backend: nativeConfig.backend,
+ ttlSeconds: nativeConfig.assignmentTtlSeconds,
+ });
+ }
+ }
+ const ready = await findReadyLocalNativeExecutorAssignment({
+ cwd: policyCwd,
+ stateDir,
+ sessionId,
+ rootThreadId,
+ });
+ if (ready) {
+ const activation = await prepareNativeUltragoalBootstrapActivation({
+ cwd: policyCwd,
+ stateDir,
+ sessionId,
+ childAgentId: ready.child_agent_id,
+ });
+ if (activation.ok) return null;
+ }
+ const reason = bootstrap
+ ? buildNativeUltragoalBootstrapRequiredReason(sessionId, rootThreadId, bootstrap.generation)
+ : ULTRAGOAL_NO_OWNER_DENY_REASON;
+ return {
+ decision: "block",
+ reason,
+ hookSpecificOutput: {
+ hookEventName: "PreToolUse",
+ additionalContext: reason,
+ },
+ };
+ }
return {
decision: "block",
@@ -11002,15 +12644,119 @@ async function buildUltragoalNoOwnerActivationGuardOutput(
hookSpecificOutput: {
hookEventName: "PreToolUse",
additionalContext:
- "Standalone Ultragoal Conductor mode requires an attached tmux session (Team execution) on native Codex App "
- + "outside tmux; native child/descendant provenance does not grant write authority. Do not set ultragoal "
- + "active/current_phase here. Proceed with direct bounded implementation for this task without "
+ "Standalone Ultragoal Conductor mode requires either an attached tmux session (Team execution) or a positively "
+ + "advertised typed native spawn surface backed by scoped write assignments; neither is proven on this native "
+ + "Codex App outside-tmux event. Do not set "
+ + "ultragoal active/current_phase here. Proceed with direct bounded implementation for this task without "
+ "entering Ultragoal's Conductor-gated planning mode, or re-run from an attached tmux OMX CLI shell so "
+ "`omx team` is available. `omx cancel` remains available if a stuck Conductor state already exists.",
},
};
}
+async function buildNativeUltragoalBootstrapMutationGuardOutput(
+ payload: CodexHookPayload,
+ cwd: string,
+ stateDir: string,
+ sessionId: string,
+ rootTranscript: SafeRootTranscriptMetadata | null = null,
+): Promise<Record<string, unknown> | null> {
+ if (safeString(payload.tool_name).trim() !== "Bash") return null;
+ const command = readPreToolUseCommand(payload);
+ if (!/\bomx\s+ultragoal\s+native-bootstrap\b/.test(command)) return null;
+ const actor = await resolvePreToolUseWriteActor(payload, cwd, stateDir, sessionId, rootTranscript);
+ if (actor === "main-root") return null;
+ const reason = actor === "native-child"
+ ? "OWNER_CONFIRMATION_REQUIRED: native Ultragoal bootstrap metadata is root-owned; a native child cannot authorize, revoke, or reconcile its own assignment."
+ : "PROVENANCE_DENIED: native Ultragoal bootstrap mutation requires exact Main-root session provenance.";
+ return {
+ decision: "block",
+ reason,
+ hookSpecificOutput: {
+ hookEventName: "PreToolUse",
+ additionalContext: reason,
+ },
+ };
+}
+
+function isExactNativeUltragoalBootstrapCommand(command: string): boolean {
+ if (nativeAssignedBashHasUnsafeStructure(".", command)) return false;
+ const words = tokenizeConductorShellWords(command).map(shellWordLiteral);
+ return words.length >= 4
+ && basename(words[0] ?? "") === "omx"
+ && words[1] === "ultragoal"
+ && words[2] === "native-bootstrap"
+ && ["authorize", "status", "revoke"].includes(words[3] ?? "");
+}
+
+function readCollaborationSendMessageTargetAgentId(payload: CodexHookPayload): string {
+ const input = safeObject(payload.tool_input);
+ const value = input?.agent_id;
+ return typeof value === "string" ? value.trim() : "";
+}
+
+async function resolveAuthorizedSendMessageChildToLeader(
+ payload: CodexHookPayload,
+ toolName: string,
+ cwd: string,
+ sessionId: string,
+): Promise<boolean> {
+ if (!sessionId) return false;
+ if (canonicalizeNativeCollaborationToolName(toolName) !== "collaboration.send_message") return false;
+
+ const targetAgentId = readCollaborationSendMessageTargetAgentId(payload);
+ if (!targetAgentId) return false;
+
+ const callerId = readPayloadAgentId(payload) || readPayloadThreadId(payload);
+ if (!callerId) return false;
+
+ const trackingState = await readSubagentTrackingState(cwd).catch(() => null);
+ const session = trackingState?.sessions?.[sessionId];
+ const leaderThreadId = safeString(session?.leader_thread_id).trim();
+ if (!leaderThreadId || targetAgentId !== leaderThreadId) return false;
+
+ const callerThread = session?.threads?.[callerId];
+ return Boolean(callerThread) && callerThread!.kind === "subagent";
+}
+
+async function buildPendingNativeUltragoalExecutorGuardOutput(
+ payload: CodexHookPayload,
+ cwd: string,
+ stateDir: string,
+ sessionId: string,
+ rootTranscript: SafeRootTranscriptMetadata | null = null,
+): Promise<Record<string, unknown> | null> {
+ if (!sessionId) return null;
+ let bootstrap = await readNativeUltragoalBootstrap(stateDir, sessionId);
+ if (!bootstrap || bootstrap.status === "revoked" || bootstrap.status === "expired") {
+ return null;
+ }
+ if (bootstrap.status === "active") {
+ const state = await readStopSessionPinnedState("ultragoal-state.json", cwd, sessionId, stateDir);
+ if (isActiveConductorModeState(state, "ultragoal", sessionId)) return null;
+ await revokeLocalNativeExecutorAssignment({
+ stateDir,
+ sessionId,
+ reason: "ultragoal_state_not_active",
+ });
+ bootstrap = await readNativeUltragoalBootstrap(stateDir, sessionId);
+ }
+ const actor = await resolvePreToolUseWriteActor(payload, cwd, stateDir, sessionId, rootTranscript);
+ if (actor !== "native-child") return null;
+ const toolName = safeString(payload.tool_name).trim();
+ if (classifyPreToolUseMutationTransport(payload, toolName, cwd) === "read-only") return null;
+ if (await resolveAuthorizedSendMessageChildToLeader(payload, toolName, cwd, sessionId)) return null;
+ const reason = "OWNER_CONFIRMATION_REQUIRED: native Ultragoal bootstrap is not active; spawned executors remain read-only until the exact assignment/receipt validates and Main-root completes activation.";
+ return {
+ decision: "block",
+ reason,
+ hookSpecificOutput: {
+ hookEventName: "PreToolUse",
+ additionalContext: reason,
+ },
+ };
+}
+
function normalizeRepoRelativePath(cwd: string, rawPath: string): string | null {
const candidate = rawPath.trim();
if (!candidate || isUnresolvedVariableTarget(candidate)) return null;
@@ -11071,6 +12817,14 @@ function conductorPathTraversesLink(cwd: string, relativePath: string): boolean
return false;
}
+function isSessionBoundNativeAssignmentPath(cwd: string, rawPath: string, sessionId: string): boolean {
+ const relativePath = normalizeRepoRelativePath(cwd, rawPath);
+ const match = relativePath
+ ? /^\.omx\/state\/sessions\/([^/]+)\/native-assignments\/[^/]+\.json$/.exec(relativePath)
+ : null;
+ return sessionId !== "" && match?.[1] === sessionId;
+}
+
function isAllowedConductorMetadataPath(cwd: string, rawPath: string): boolean {
const relativePath = normalizeRepoRelativePath(cwd, rawPath);
if (!relativePath || conductorPathnameExpansionIsAmbiguous(relativePath)) return false;
@@ -11930,7 +13684,162 @@ function commandHasUnsafeDynamicLoaderEnvironment(command: string, depth = 0): b
-function isPositivelyReadOnlyGitCommand(words: string[], commandIndex: number): boolean {
+const HARDENED_GIT_STATUS_ARGS = [
+ "--no-pager",
+ "--no-optional-locks",
+ "-c",
+ "core.fsmonitor=false",
+ "-c",
+ "core.untrackedCache=false",
+ "-c",
+ "pager.status=false",
+ "status",
+ "--short",
+ "--branch",
+ "--untracked-files=normal",
+ "--ignore-submodules=all",
+ "--no-renames",
+] as const;
+
+function gitStatusNullConfigPath(): string {
+ return process.platform === "win32" ? "NUL" : "/dev/null";
+}
+
+function gitStatusInvocationHasExactArgs(words: string[], commandIndex: number): boolean {
+ const args = collectConductorInvocationWords(words, commandIndex).map(shellWordLiteral);
+ return args.length === HARDENED_GIT_STATUS_ARGS.length
+ && args.every((arg, index) => arg === HARDENED_GIT_STATUS_ARGS[index]);
+}
+
+function gitConfigTextHasExecutableStatusSurface(text: string): boolean {
+ if (text.includes("\0")) return true;
+ let section = "";
+ for (const rawLine of text.split(/\r?\n/)) {
+ const line = rawLine.trim();
+ if (!line || line.startsWith("#") || line.startsWith(";")) continue;
+ if (line.endsWith("\\")) return true;
+ if (line.startsWith("[")) {
+ const match = /^\[\s*([^\]\s"]+)(?:\s+"[^"]*")?\s*\]$/.exec(line);
+ if (!match) return true;
+ section = safeString(match[1]).toLowerCase();
+ if (new Set(["alias", "filter", "include", "includeif", "submodule"]).has(section)) return true;
+ continue;
+ }
+ const keyMatch = /^([A-Za-z][A-Za-z0-9.-]*)\s*(?:=|$)/.exec(line);
+ if (!keyMatch || !section) return true;
+ const key = safeString(keyMatch[1]).toLowerCase();
+ if (section === "core" && new Set(["attributesfile", "excludesfile", "fsmonitor", "hookspath", "pager", "worktree"]).has(key)) return true;
+ if (section === "diff" && new Set(["command", "external", "textconv"]).has(key)) return true;
+ if (section === "interactive" && key === "difffilter") return true;
+ if (section === "pager") return true;
+ if (section === "status" && key === "submodulesummary") return true;
+ }
+ return false;
+}
+
+function gitStatusMetadataDirectories(cwd: string): string[] | null {
+ try {
+ const dotGit = join(cwd, ".git");
+ const metadata = lstatSync(dotGit);
+ let gitDir: string;
+ if (metadata.isDirectory()) {
+ gitDir = realpathSync(dotGit);
+ } else if (metadata.isFile()) {
+ const pointer = readFileSync(dotGit, "utf-8").trim();
+ const match = /^gitdir:\s*(.+)$/i.exec(pointer);
+ if (!match) return null;
+ gitDir = realpathSync(resolve(dirname(dotGit), safeString(match[1]).trim()));
+ } else {
+ return null;
+ }
+ let commonDir = gitDir;
+ const commonDirPath = join(gitDir, "commondir");
+ if (existsSync(commonDirPath)) {
+ const commonDirValue = readFileSync(commonDirPath, "utf-8").trim();
+ if (!commonDirValue) return null;
+ commonDir = realpathSync(resolve(gitDir, commonDirValue));
+ }
+ return [...new Set([gitDir, commonDir])];
+ } catch {
+ return null;
+ }
+}
+
+function gitStatusTrackedSurfaceIsSafe(cwd: string, gitExecutablePath: string): boolean {
+ const environment: NodeJS.ProcessEnv = { ...process.env };
+ for (const name of Object.keys(environment)) {
+ if (name.startsWith("GIT_") || name === "PAGER") delete environment[name];
+ }
+ environment.GIT_ATTR_NOSYSTEM = "1";
+ environment.GIT_CONFIG_COUNT = "0";
+ environment.GIT_CONFIG_GLOBAL = gitStatusNullConfigPath();
+ environment.GIT_CONFIG_NOSYSTEM = "1";
+ environment.GIT_CONFIG_SYSTEM = gitStatusNullConfigPath();
+ environment.GIT_OPTIONAL_LOCKS = "0";
+ environment.GIT_PAGER = "";
+ environment.LC_ALL = "C";
+ environment.PAGER = "";
+ const trackedDirectories = new Set<string>([cwd]);
+ try {
+ const output = execFileSync(
+ gitExecutablePath,
+ ["--no-pager", "--no-optional-locks", "-c", "core.fsmonitor=false", "ls-files", "--stage", "-z"],
+ { cwd, encoding: "utf-8", env: environment, maxBuffer: 64 * 1024 * 1024, timeout: 5_000 },
+ );
+ for (const record of output.split("\0")) {
+ if (!record) continue;
+ const separator = record.indexOf("\t");
+ if (separator < 0) return false;
+ const metadata = record.slice(0, separator);
+ const path = record.slice(separator + 1);
+ if (metadata.startsWith("160000 ")) return false;
+ if (path === ".gitmodules" || path === ".gitattributes" || path.endsWith("/.gitattributes")) return false;
+ const parts = path.split("/").slice(0, -1);
+ let directory = cwd;
+ for (const part of parts) {
+ if (!part || part === "." || part === "..") return false;
+ directory = join(directory, part);
+ trackedDirectories.add(directory);
+ }
+ }
+ for (const directory of trackedDirectories) {
+ const attributesPath = join(directory, ".gitattributes");
+ if (existsSync(attributesPath) && readFileSync(attributesPath, "utf-8").trim() !== "") return false;
+ }
+ return true;
+ } catch {
+ return false;
+ }
+}
+
+function gitStatusRepositoryConfigurationIsSafe(cwd: string, gitExecutablePath: string): boolean {
+ const metadataDirectories = gitStatusMetadataDirectories(cwd);
+ if (!metadataDirectories) return false;
+ try {
+ for (const directory of metadataDirectories) {
+ const attributesPath = join(directory, "info", "attributes");
+ if (existsSync(attributesPath) && readFileSync(attributesPath, "utf-8").trim() !== "") return false;
+ for (const name of ["config", "config.worktree"]) {
+ const configPath = join(directory, name);
+ if (existsSync(configPath) && gitConfigTextHasExecutableStatusSurface(readFileSync(configPath, "utf-8"))) return false;
+ }
+ }
+ return gitStatusTrackedSurfaceIsSafe(cwd, gitExecutablePath);
+ } catch {
+ return false;
+ }
+}
+
+function isPositivelyReadOnlyGitCommand(
+ words: string[],
+ commandIndex: number,
+ cwd: string,
+ gitExecutablePath?: string,
+): boolean {
+ if (gitStatusInvocationHasExactArgs(words, commandIndex)) {
+ if (!gitExecutablePath) return false;
+ return gitStatusRepositoryConfigurationIsSafe(cwd, gitExecutablePath);
+ }
const args = collectConductorInvocationWords(words, commandIndex);
let index = 0;
while (index < args.length) {
@@ -11942,6 +13851,18 @@ function isPositivelyReadOnlyGitCommand(words: string[], commandIndex: number):
}
const subcommand = shellWordLiteral(args[index] ?? "");
if (!subcommand) return false;
+ if (subcommand === "status") {
+ return index === 0
+ && args.length === 2
+ && shellWordLiteral(args[1] ?? "") === "--short";
+ }
+ if (subcommand === "diff") {
+ return args.length === index + 5
+ && shellWordLiteral(args[index + 1] ?? "") === "--no-ext-diff"
+ && shellWordLiteral(args[index + 2] ?? "") === "--no-textconv"
+ && shellWordLiteral(args[index + 3] ?? "") === "--"
+ && shellWordLiteral(args[index + 4] ?? "") === ".";
+ }
const allowedOptions = new Map<string, Set<string>>([
["cat-file", new Set(["-e", "-t", "-s", "--exists", "--batch", "--batch-check", "--batch-command", "--buffer", "--follow-symlinks", "--allow-unknown-type", "--unordered"])],
["ls-files", new Set(["-c", "--cached", "-d", "--deleted", "-m", "--modified", "-o", "--others", "-i", "--ignored", "--exclude-standard", "--directory", "--no-empty-directory", "--full-name", "--stage", "--debug", "--eol", "--deduplicate", "--error-unmatch"])],
@@ -11958,9 +13879,76 @@ function isPositivelyReadOnlyGitCommand(words: string[], commandIndex: number):
if (!allowed.has(word)) return false;
continue;
}
- if (!/^[A-Za-z0-9._~/:=@,+^{}-]+$/.test(word)) return false;
+ if (!/^[A-Za-z0-9._~/:=@,+^{}-]+$/.test(word)) return false;
+ }
+ return true;
+}
+
+function findCommandHasShellExpansionSyntax(command: string): boolean {
+ return /[?*{}\[\]~\\]/.test(command) || /(?:^|[\t ])[@+]\(/.test(command);
+}
+
+function findPathIsWorkspaceBounded(path: string, cwd: string): boolean {
+ if (!path || isAbsolute(path)) return false;
+ try {
+ const canonicalCwd = realpathSync(cwd);
+ const canonicalStart = realpathSync(resolve(cwd, path));
+ const workspaceRelative = relative(canonicalCwd, canonicalStart);
+ return workspaceRelative === ""
+ || (!isAbsolute(workspaceRelative) && !/^(?:\.\.(?:[\\/]|$))/.test(workspaceRelative));
+ } catch {
+ return false;
+ }
+}
+
+function isPositivelyClassifiedFindCommand(words: string[], commandIndex: number, cwd: string): boolean {
+ const args = collectConductorInvocationWords(words, commandIndex);
+ let expressionStarted = false;
+ let sawMaxDepth = false;
+ const readOnlyPredicates = new Set([
+ "-depth", "-empty", "-executable", "-false", "-ls", "-mount", "-print", "-print0", "-prune",
+ "-quit", "-readable", "-true", "-writable", "-xdev",
+ ]);
+ const booleanOperators = new Set(["!", "(", ")", ",", "-a", "-and", "-not", "-o", "-or"]);
+ const staticValuePredicates = new Set(["-iname", "-ipath", "-name", "-path"]);
+
+ for (let index = 0; index < args.length; index += 1) {
+ const raw = args[index] ?? "";
+ const word = shellWordLiteral(raw);
+ if (!word || isDynamicNestedCommandString(word) || /[$`\0\r\n]/.test(raw)) return false;
+ if (/[?*{}\[\]~<>\\]/.test(raw)) return false;
+ if (/[()]/.test(raw) && !booleanOperators.has(word)) return false;
+ if (!expressionStarted && !word.startsWith("-") && !booleanOperators.has(word)) {
+ if (!findPathIsWorkspaceBounded(word, cwd)) return false;
+ continue;
+ }
+ expressionStarted = true;
+ if (booleanOperators.has(word) || readOnlyPredicates.has(word)) continue;
+ if (word === "-maxdepth" || word === "-mindepth") {
+ const value = shellWordLiteral(args[index + 1] ?? "");
+ if (!/^(?:0|[1-9][0-9]*)$/.test(value)) return false;
+ const depth = Number(value);
+ if (!Number.isSafeInteger(depth) || depth > 32) return false;
+ if (word === "-maxdepth") sawMaxDepth = true;
+ index += 1;
+ continue;
+ }
+ if (word === "-type") {
+ const value = shellWordLiteral(args[index + 1] ?? "");
+ if (!/^[bcdpflsD]$/.test(value)) return false;
+ index += 1;
+ continue;
+ }
+ if (staticValuePredicates.has(word)) {
+ const rawValue = args[index + 1] ?? "";
+ const value = shellWordLiteral(rawValue);
+ if (!value || isDynamicNestedCommandString(value) || /[$`\0\r\n]/.test(rawValue)) return false;
+ index += 1;
+ continue;
+ }
+ return false;
}
- return true;
+ return sawMaxDepth;
}
function ghCommandPath(words: string[], commandIndex: number): [string, string] {
const operands: string[] = [];
@@ -12349,7 +14337,8 @@ function sedScriptIsPositivelyReadOnly(script: string): boolean {
const normalized = shellWordLiteral(script).trim();
const substitution = parseConductorSingleSubstitutionProgram(normalized);
if (substitution) return !/[ew]/.test(substitution.flags);
- return /^[0-9$.,+~\-]*(?:p|P|q|Q|n|N|l|d|=)$/.test(normalized);
+ return /^[0-9$.,+~\-\s;{}pPqQnNld=]+$/.test(normalized)
+ && /(?:p|P|q|Q|n|N|l|d|=)/.test(normalized);
}
function isPositivelyClassifiedSedCommand(words: string[], commandIndex: number): boolean {
@@ -12457,6 +14446,7 @@ function gitRuntimeEnvironmentIsUnsafe(name: string): boolean {
|| name === "GIT_SSH"
|| name === "GIT_SSH_COMMAND"
|| name === "GIT_PAGER"
+ || name === "PAGER"
|| name === "GIT_EDITOR"
|| name === "GIT_SEQUENCE_EDITOR"
|| name === "GIT_CONFIG_COUNT"
@@ -12464,6 +14454,7 @@ function gitRuntimeEnvironmentIsUnsafe(name: string): boolean {
|| /^GIT_DIFF_PATH_(?:COUNTER|TOTAL)$/.test(name)
|| /^GIT_TRACE(?:_|$)/.test(name);
}
+
function gitCommandHasUnsafeRuntimeEnvironment(words: string[], commandIndex: number): boolean {
if (Object.keys(process.env).some(gitRuntimeEnvironmentIsUnsafe)) return true;
return words.slice(0, commandIndex).some((word) => {
@@ -12472,6 +14463,102 @@ function gitCommandHasUnsafeRuntimeEnvironment(words: string[], commandIndex: nu
});
}
+function directInvocationCommandIndex(words: string[], commandStartIndex: number): number {
+ let index = commandStartIndex;
+ while (index < words.length && isEnvironmentAssignmentWord(words[index] ?? "")) index += 1;
+ return index;
+}
+
+function gitStatusInvocationHasSafeEnvironment(
+ words: string[],
+ commandStartIndex: number,
+ commandIndex: number,
+): boolean {
+ const nullConfigPath = gitStatusNullConfigPath();
+ const required = new Map<string, string>([
+ ["GIT_ATTR_NOSYSTEM", "1"],
+ ["GIT_CONFIG_COUNT", "0"],
+ ["GIT_CONFIG_GLOBAL", nullConfigPath],
+ ["GIT_CONFIG_NOSYSTEM", "1"],
+ ["GIT_CONFIG_SYSTEM", nullConfigPath],
+ ["GIT_EDITOR", ""],
+ ["GIT_EXTERNAL_DIFF", ""],
+ ["GIT_PAGER", ""],
+ ["GIT_SEQUENCE_EDITOR", ""],
+ ["PAGER", ""],
+ ]);
+ if (directInvocationCommandIndex(words, commandStartIndex) !== commandIndex) return false;
+
+ const assignments = new Map<string, string>();
+ for (const rawWord of words.slice(commandStartIndex, commandIndex)) {
+ const assignment = parseShellAssignmentWord(rawWord);
+ if (!assignment || assignment.append || assignments.has(assignment.name)) return false;
+ if (assignment.name !== "PATH" && !required.has(assignment.name)) return false;
+ if (assignment.name === "PATH" && /[$`\0\r\n]/.test(rawWord)) return false;
+ assignments.set(assignment.name, assignment.value);
+ }
+ for (const [name, value] of required) {
+ if (assignments.get(name) !== value) return false;
+ }
+
+ const effectiveEnvironment = new Map<string, string>();
+ for (const [name, value] of Object.entries(process.env)) effectiveEnvironment.set(name, value ?? "");
+ for (const [name, value] of assignments) effectiveEnvironment.set(name, value);
+ for (const [name, value] of effectiveEnvironment) {
+ if (value === "") continue;
+ if (required.get(name) === value) continue;
+ if (name === "GIT_TERMINAL_PROMPT" && value === "0") continue;
+ if (name === "PAGER" || name.startsWith("GIT_") || gitRuntimeEnvironmentIsUnsafe(name)) return false;
+ }
+ return true;
+}
+
+function hasHardenedGitStatusEnvironmentShape(command: string): boolean {
+ if (!isSingleLiteralShellInvocation(command)) return false;
+ const words = tokenizeConductorShellWords(command);
+ const commandStartIndex = 0;
+ const commandIndex = directInvocationCommandIndex(words, commandStartIndex);
+ if (commandNameFromShellWord(words[commandIndex] ?? "") !== "git") return false;
+ return gitStatusInvocationHasExactArgs(words, commandIndex)
+ && gitStatusInvocationHasSafeEnvironment(words, commandStartIndex, commandIndex);
+}
+
+function conductorInvocationTrustedExecutablePath(
+ words: string[],
+ commandStartIndex: number,
+ commandIndex: number,
+ state: ShellPosixState,
+ rootCwd: string,
+): string | null {
+ const commandWord = shellWordLiteral(words[commandIndex] ?? "");
+ if (!commandWord || /[$`\0\r\n]/.test(commandWord)) return null;
+ const commandName = commandNameFromShellWord(commandWord);
+ const commandState = resolveConductorCommandPathState(words, commandStartIndex, commandIndex, state);
+ if (commandWord.includes("/")) {
+ if (!conductorSlashCommandIsTrusted(commandWord, commandState, rootCwd)) return null;
+ const candidate = isAbsolute(commandWord) ? commandWord : resolve(commandState.effectiveCwd ?? rootCwd, commandWord);
+ try {
+ return realpathSync(candidate);
+ } catch {
+ return null;
+ }
+ }
+ const candidate = conductorResolvePathInterpreter(commandName, commandState);
+ return candidate !== null && conductorExecutableHasTrustedIdentity(commandName, candidate, rootCwd, commandState)
+ ? candidate
+ : null;
+}
+
+function conductorInvocationHasTrustedExecutableIdentity(
+ words: string[],
+ commandStartIndex: number,
+ commandIndex: number,
+ state: ShellPosixState,
+ rootCwd: string,
+): boolean {
+ return conductorInvocationTrustedExecutablePath(words, commandStartIndex, commandIndex, state, rootCwd) !== null;
+}
+
function conductorRuntimeEnvironmentNameIsSensitive(name: string): boolean {
return name === "NODE_OPTIONS"
|| name === "SSLKEYLOGFILE"
@@ -12681,7 +14768,7 @@ function inspectConductorRuntimeExecutions(command: string, cwd?: string, depth
const coprocCompounds = stripConductorCoprocCompoundBodiesForRuntimeInspection(command);
const topLevelCommand = coprocCompounds.command;
const unsafeDynamicLoaderEnvironment = commandHasUnsafeDynamicLoaderEnvironment(topLevelCommand);
- if (commandMayPopulateSensitiveRuntimeEnvironment(topLevelCommand)) {
+ if (commandMayPopulateSensitiveRuntimeEnvironment(topLevelCommand) && !hasHardenedGitStatusEnvironmentShape(topLevelCommand)) {
inspection.uninspectedOtherRuntimeCount += 1;
inspection.uninspectedCommandNames.push("runtime-environment-writer");
}
@@ -12786,6 +14873,12 @@ function inspectConductorRuntimeExecutions(command: string, cwd?: string, depth
}
const commandWord = commandIndex >= 0 ? words[commandIndex] ?? "" : "";
const commandName = commandNameFromShellWord(commandWord);
+ let invocationStartIndex = index;
+ while (
+ invocationStartIndex > 0
+ && !isShellCommandSeparatorAt(words, invocationStartIndex - 1)
+ && !isShellGroupingSyntaxWord(words[invocationStartIndex - 1] ?? "")
+ ) invocationStartIndex -= 1;
if (unsafeDynamicLoaderEnvironment) {
inspection.uninspectedOtherRuntimeCount += 1;
inspection.uninspectedCommandNames.push("dynamic-loader-environment");
@@ -12938,6 +15031,23 @@ function inspectConductorRuntimeExecutions(command: string, cwd?: string, depth
inspection.uninspectedOtherRuntimeCount += 1;
inspection.uninspectedCommandNames.push(commandName);
}
+ } else if (commandName === "find") {
+ const exactFindInvocation = depth === 0 && isSingleLiteralShellInvocation(topLevelCommand)
+ && directInvocationCommandIndex(words, invocationStartIndex) === commandIndex
+ && !usedExternalDispatchWrapper
+ && !invokesDefinedShellFunction
+ && !findCommandHasShellExpansionSyntax(topLevelCommand)
+ && conductorInvocationHasTrustedExecutableIdentity(
+ words,
+ invocationStartIndex,
+ commandIndex,
+ runtimeShellState,
+ runtimeCwd,
+ );
+ if (!exactFindInvocation || !isPositivelyClassifiedFindCommand(words, commandIndex, runtimeCwd)) {
+ inspection.uninspectedOtherRuntimeCount += 1;
+ inspection.uninspectedCommandNames.push(commandName);
+ }
} else if (commandName === "uniq") {
if (!isPositivelyClassifiedUniqCommand(
words,
@@ -12948,7 +15058,31 @@ function inspectConductorRuntimeExecutions(command: string, cwd?: string, depth
inspection.uninspectedCommandNames.push(commandName);
}
} else if (commandName === "git") {
- if (commandSetsGitHelper || gitCommandHasUnsafeRuntimeEnvironment(words, commandIndex) || !isPositivelyReadOnlyGitCommand(words, commandIndex)) {
+ const hardenedStatus = gitStatusInvocationHasExactArgs(words, commandIndex);
+ const trustedGitExecutablePath = hardenedStatus
+ ? conductorInvocationTrustedExecutablePath(
+ words,
+ invocationStartIndex,
+ commandIndex,
+ runtimeShellState,
+ runtimeCwd,
+ )
+ : null;
+ const exactStatusInvocation = hardenedStatus
+ && depth === 0
+ && isSingleLiteralShellInvocation(topLevelCommand)
+ && directInvocationCommandIndex(words, invocationStartIndex) === commandIndex
+ && !usedExternalDispatchWrapper
+ && !invokesDefinedShellFunction
+ && gitStatusInvocationHasSafeEnvironment(words, invocationStartIndex, commandIndex)
+ && trustedGitExecutablePath !== null;
+ const unsafeGit = hardenedStatus
+ ? !exactStatusInvocation
+ || !isPositivelyReadOnlyGitCommand(words, commandIndex, runtimeCwd, trustedGitExecutablePath ?? undefined)
+ : commandSetsGitHelper
+ || gitCommandHasUnsafeRuntimeEnvironment(words, commandIndex)
+ || !isPositivelyReadOnlyGitCommand(words, commandIndex, runtimeCwd);
+ if (unsafeGit) {
inspection.uninspectedOtherRuntimeCount += 1;
inspection.uninspectedCommandNames.push(commandName);
}
@@ -15964,7 +18098,7 @@ function omxStateWriteInputWordIsStatic(word: string): boolean {
const CONDUCTOR_STATE_WRITE_ALLOWED_PAYLOAD_KEYS = new Set([
"mode", "active", "current_phase", "currentPhase", "previous_phase", "previousPhase", "phase",
- "status", "reason", "rationale", "summary", "handoff_summary", "evidence", "result", "error",
+ "status", "reason", "blocked_reason", "rationale", "summary", "handoff_summary", "evidence", "result", "error",
"run_outcome", "runOutcome", "lifecycle_outcome", "lifecycleOutcome", "terminal_outcome", "terminalOutcome",
"started_at", "updated_at", "completed_at", "failed_at", "completion_reason", "failure_reason", "deep_interview_gate",
"session_id", "owner_omx_session_id", "codex_session_id", "owner_codex_session_id", "workingDirectory",
@@ -15972,6 +18106,29 @@ const CONDUCTOR_STATE_WRITE_ALLOWED_PAYLOAD_KEYS = new Set([
function conductorStateWritePayloadHasExactSchema(payload: Record<string, unknown>): boolean {
for (const [key, value] of Object.entries(payload)) {
+ if (key === "ralplan_consensus_gate") {
+ const gate = safeObject(value);
+ if (!gate || Object.keys(gate).some((gateKey) => !new Set([
+ "complete",
+ "blocked_reason",
+ "ralplan_architect_review",
+ ]).has(gateKey))) return false;
+ if (typeof gate.complete !== "boolean") return false;
+ if (gate.blocked_reason !== undefined && typeof gate.blocked_reason !== "string") return false;
+ if (gate.ralplan_architect_review !== undefined) {
+ const review = safeObject(gate.ralplan_architect_review);
+ if (!review || Object.keys(review).some((reviewKey) => !new Set([
+ "agent_role",
+ "verdict",
+ "artifact_path",
+ "sequence_index",
+ ]).has(reviewKey))) return false;
+ if (safeString(review.agent_role).trim().toLowerCase() !== "architect") return false;
+ if (!new Set(["APPROVE", "ITERATE", "REJECT"]).has(safeString(review.verdict).trim().toUpperCase())) return false;
+ if (!safeString(review.artifact_path).trim() || !isBoundedRalplanReviewSequenceIndex(review.sequence_index)) return false;
+ }
+ continue;
+ }
if (key === "state") {
const nested = safeObject(value);
if (!nested || !conductorStateWritePayloadHasExactSchema(nested)) return false;
@@ -16056,7 +18213,7 @@ function hasExactConductorOrchestrationOptionSchema(commandName: string, words:
required = new Set(["--kind", "--target-goal-id", "--evidence", "--rationale"]);
} else if (command === "ultragoal" && subcommand === "checkpoint") {
permitted = new Set(["--goal-id", "--status", "--codex-goal-json", "--quality-gate-json", "--evidence", "--json"]);
- required = new Set(["--goal-id", "--status", "--codex-goal-json", "--quality-gate-json", "--evidence", "--json"]);
+ required = new Set(["--goal-id", "--status", "--evidence", "--json"]);
} else if (command === "performance-goal" && subcommand === "complete") {
permitted = new Set(["--slug", "--codex-goal-json", "--evidence", "--json"]);
required = new Set(["--slug", "--codex-goal-json", "--evidence", "--json"]);
@@ -16085,6 +18242,13 @@ function hasExactConductorOrchestrationOptionSchema(commandName: string, words:
}
if (![...required].every((option) => seen.has(option))) return false;
const status = seen.get("--status");
+ if (command === "ultragoal" && subcommand === "checkpoint") {
+ if (status === "complete") return seen.has("--codex-goal-json");
+ if (status === "blocked") return seen.has("--codex-goal-json") && !seen.has("--quality-gate-json");
+ return status === "failed"
+ && !seen.has("--codex-goal-json")
+ && !seen.has("--quality-gate-json");
+ }
return status === undefined || new Set(["complete", "blocked", "failed", "in_progress"]).has(status);
}
@@ -16096,6 +18260,138 @@ function conductorOrchestrationWordIsStatic(word: string): boolean {
&& !/(?:^|[^\\])[<>]\(/.test(word);
}
+function isExactLeaderOwnedUltragoalMetadataCommand(
+ command: string,
+ rawCommand: string,
+ cwd: string,
+): boolean {
+ if (
+ command !== rawCommand
+ || !isSingleLiteralShellInvocation(command)
+ || hasUnquotedShellFilenameExpansion(command)
+ ) return false;
+ const words = tokenizeConductorShellWords(command);
+ if (words.length < 3) return false;
+ if (!words.every(conductorOrchestrationWordIsStatic)) return false;
+ const commandWord = shellWordLiteral(words[0] ?? "");
+ if (commandWord === "omx") {
+ if (!omxOrGjcExecutionContextIsTrusted(command, cwd, ["omx"])) return false;
+ } else {
+ if (!isAbsolute(commandWord) || !commandWord.includes("/") || commandNameFromShellWord(commandWord) !== "omx") return false;
+ // The real Codex hook process does not export SHELLOPTS/BASHOPTS, so the
+ // generic shell-state scanner cannot prove its state. This command shape
+ // does not depend on shell lookup, functions, aliases, substitutions, or
+ // redirections: it is one literal invocation of a verified absolute OMX
+ // executable with fully static arguments. Keep the loader/environment and
+ // executable-identity checks below, but do not reject solely because an
+ // unrelated ambient shell-option snapshot is unavailable.
+ if (commandHasUnsafeDynamicLoaderEnvironment(command) || commandHasUnsafeLeadingRuntimeEnvironment(command)) return false;
+ const unsafeInheritedNames = [...OMX_GJC_TRUSTED_CONTEXT_UNSAFE_INHERITED_ENV_NAMES, ...CONDUCTOR_NODE_OUTPUT_ENVIRONMENT_NAMES];
+ if (unsafeInheritedNames.some((name) => safeString(process.env[name]).trim() !== "")) return false;
+ const state = resolveConductorCommandPathState(words, 0, 0, createConductorRuntimeShellState(cwd));
+ if (!conductorSlashCommandIsTrusted(commandWord, state, cwd)) return false;
+ }
+
+ const args = words.slice(1);
+ if (shellWordLiteral(args[0] ?? "") !== "ultragoal") return false;
+ const subcommand = shellWordLiteral(args[1] ?? "");
+ const trailing = args.slice(2);
+
+ const parseOptions = (
+ repeatableValueOptions: ReadonlySet<string>,
+ uniqueValueOptions: ReadonlySet<string>,
+ flagOptions: ReadonlySet<string>,
+ ): Map<string, string[]> | null => {
+ const seen = new Map<string, string[]>();
+ for (let index = 0; index < trailing.length; index += 1) {
+ const rawOption = trailing[index] ?? "";
+ const option = shellWordLiteral(rawOption);
+ if (!option || !option.startsWith("--") || option === "--") return null;
+ if (flagOptions.has(option)) {
+ if (seen.has(option)) return null;
+ seen.set(option, []);
+ continue;
+ }
+ const name = option.split("=", 1)[0] ?? "";
+ if (!repeatableValueOptions.has(name) && !uniqueValueOptions.has(name)) return null;
+ if (uniqueValueOptions.has(name) && seen.has(name)) return null;
+ const inlineValue = option.startsWith(`${name}=`);
+ const rawValue = inlineValue ? rawOption.slice(rawOption.indexOf("=") + 1) : trailing[index + 1] ?? "";
+ const value = shellWordLiteral(rawValue);
+ if (
+ !value
+ || !conductorOrchestrationWordIsStatic(rawValue)
+ || (!inlineValue && value.startsWith("-"))
+ ) return null;
+ if (option === name) index += 1;
+ seen.set(name, [...(seen.get(name) ?? []), value]);
+ }
+ return seen;
+ };
+
+ if (subcommand === "create" || subcommand === "create-goals") {
+ if (trailing.some((word) => ["--force", "--brief-file", "--from-stdin"].includes(shellWordLiteral(word)))) return false;
+ const parsed = parseOptions(new Set(["--goal"]), new Set(["--brief", "--codex-goal-mode"]), new Set(["--json"]));
+ const goalMode = parsed?.get("--codex-goal-mode")?.[0];
+ return Boolean(parsed?.has("--brief"))
+ && (goalMode === undefined || ["aggregate", "per-story", "per_story"].includes(goalMode));
+ }
+ if (["complete", "complete-goals", "next", "start-next"].includes(subcommand)) {
+ return parseOptions(new Set(), new Set(), new Set(["--retry-failed", "--json"])) !== null;
+ }
+ if (subcommand === "status") {
+ return parseOptions(new Set(), new Set(["--codex-goal-json"]), new Set(["--json"])) !== null;
+ }
+ if (subcommand === "steer") {
+ const parsed = parseOptions(
+ new Set(),
+ new Set(["--kind", "--target-goal-id", "--evidence", "--rationale"]),
+ new Set(["--json"]),
+ );
+ return parsed?.get("--kind")?.[0] === "annotate_ledger"
+ && parsed.has("--evidence")
+ && parsed.has("--rationale")
+ && parsed.has("--json");
+ }
+ if (subcommand === "checkpoint") {
+ const parsed = parseOptions(
+ new Set(),
+ new Set(["--goal-id", "--status", "--evidence", "--codex-goal-json", "--quality-gate-json"]),
+ new Set(["--json"]),
+ );
+ if (
+ !parsed?.has("--goal-id")
+ || !parsed.has("--status")
+ || !parsed.has("--evidence")
+ || !parsed.has("--json")
+ ) return false;
+ const status = parsed.get("--status")?.[0];
+ if (status === "complete") {
+ return parsed.has("--codex-goal-json");
+ }
+ if (status === "blocked") {
+ return parsed.has("--codex-goal-json") && !parsed.has("--quality-gate-json");
+ }
+ return status === "failed"
+ && !parsed.has("--codex-goal-json")
+ && !parsed.has("--quality-gate-json");
+ }
+ return false;
+}
+
+function isUltragoalMetadataCommandAttempt(command: string): boolean {
+ const words = tokenizeConductorShellWords(command);
+ const commandIndex = skipShellCommandPositionPrefixWords(words, 0);
+ if (commandNameFromShellWord(words[commandIndex] ?? "") !== "omx") return false;
+ const args = collectConductorInvocationWords(words, commandIndex).map(shellWordLiteral);
+ return args[0] === "ultragoal"
+ && [
+ "create", "create-goals",
+ "complete", "complete-goals", "next", "start-next",
+ "status", "steer", "checkpoint",
+ ].includes(args[1] ?? "");
+}
+
function isStaticallyRecognizedConductorOrchestrationMutation(
commandName: string,
words: string[],
@@ -17059,9 +19355,21 @@ function conductorExecutableHasTrustedPackageCliIdentity(
): boolean {
if (commandName !== "omx" && commandName !== "gjc") return false;
try {
+ if (
+ conductorWorkspacePackageCliCandidateIsTrusted(
+ commandName,
+ commandPath,
+ dirname(commandPath),
+ rootCwd,
+ )
+ ) return conductorPackageCliHasTrustedNodeInterpreter(commandPath, state, rootCwd);
const lexical = resolve(commandPath);
+ const lexicalRoot = resolve(rootCwd);
+ if (lexical === lexicalRoot || lexical.startsWith(`${lexicalRoot}/`)) return false;
const root = realpathSync(resolve(rootCwd));
- if (lexical === root || lexical.startsWith(`${root}/`)) return false;
+ const canonicalLexicalParent = realpathSync(dirname(lexical));
+ const canonicalLexical = join(canonicalLexicalParent, basename(lexical));
+ if (canonicalLexical === root || canonicalLexical.startsWith(`${root}/`)) return false;
const knownCli = conductorKnownPackageCliPath(commandName);
const canonicalCommand = realpathSync(commandPath);
const interpreterTrusted = conductorPackageCliHasTrustedNodeInterpreter(commandPath, state, rootCwd);
@@ -19822,6 +22130,85 @@ function conductorStatePayloadPreservesActiveGuard(
return phase !== "" && isNonTerminalPhase(phase);
}
+function nativeAssignmentTargetIsWithinScope(
+ cwd: string,
+ rawTarget: string,
+ pathPrefixes: readonly string[],
+): boolean {
+ const relativeTarget = normalizePlanningArtifactRelativePath(cwd, rawTarget);
+ if (!relativeTarget || conductorPathnameExpansionIsAmbiguous(relativeTarget)) return false;
+ if (conductorPathTraversesLink(cwd, relativeTarget)) return false;
+ if (
+ relativeTarget === ".git"
+ || relativeTarget.startsWith(".git/")
+ || relativeTarget === ".omx"
+ || relativeTarget.startsWith(".omx/")
+ ) return false;
+ return pathPrefixes.some((prefix) => (
+ prefix === "."
+ || relativeTarget === prefix
+ || relativeTarget.startsWith(`${prefix}/`)
+ ));
+}
+
+function nativeAssignedBashHasUnsafeStructure(cwd: string, command: string): boolean {
+ const normalized = normalizeShellLineContinuations(command);
+ if (
+ splitConductorShellSegments(stripHeredocBodiesForCommandScan(normalized)).length !== 1
+ || hasUnresolvedShellArithmeticExpansion(normalized)
+ || hasUnquotedShellSubstitution(normalized)
+ || hasDynamicNestedShellExecution(normalized)
+ || hasUnsafeUnquotedHeredocExpansion(normalized)
+ || commandHasUnsafeConductorShellState(normalized, cwd)
+ || conductorCommandMayMutatePathResolution(normalized)
+ ) return true;
+ const interpreterWrites = extractConductorInterpreterWrites(normalized);
+ return interpreterWrites.some((write) => write.unresolved || write.targets.length === 0);
+}
+
+async function nativeChildAssignmentAllowsMutation(
+ payload: CodexHookPayload,
+ cwd: string,
+ stateDir: string,
+ sessionId: string,
+ toolName: string,
+ mutationTransport: PreToolUseMutationTransport,
+): Promise<boolean> {
+ if (
+ mutationTransport === "state"
+ || mutationTransport === "orchestration"
+ || mutationTransport === "goal-lifecycle"
+ || mutationTransport === "unknown"
+ ) {
+ return false;
+ }
+ const assignment = await readNativeSubagentAssignment(payload, cwd, stateDir, sessionId);
+ if (!assignment) return false;
+
+ if (mutationTransport === "path") {
+ if (!assignment.allowed_actions.includes("path-write")) return false;
+ const candidates = collectImplementationToolPathCandidates(
+ payload,
+ toolName,
+ readPreToolUsePathCandidates(payload),
+ );
+ return candidates.length > 0
+ && candidates.every((candidate) => (
+ !isNativeAssignmentPath(stateDir, candidate, cwd)
+ && nativeAssignmentTargetIsWithinScope(cwd, candidate, assignment.path_prefixes)
+ ));
+ }
+ if (mutationTransport !== "bash") return false;
+
+ const command = readPreToolUseCommand(payload);
+ if (nativeAssignedBashHasUnsafeStructure(cwd, command)) return false;
+ if (!assignment.allowed_actions.includes("bash-write")) return false;
+ const targets = extractDeepInterviewCommandWriteTargets(command, cwd, cwd);
+ if (targets.some((target) => isNativeAssignmentPath(stateDir, target, cwd))) return false;
+ return targets.length > 0 && targets.every((target) => (
+ nativeAssignmentTargetIsWithinScope(cwd, target, assignment.path_prefixes)
+ ));
+}
function buildConductorSessionProvenanceDeny(
activeState: ActiveConductorState,
@@ -19846,14 +22233,60 @@ export async function buildConductorPreToolUseWriteGuardOutput(
stateDir: string,
resolvedSessionId?: string,
policyCwd = cwd,
+ rootTranscript: SafeRootTranscriptMetadata | null = null,
+ pointer: SessionPointerReadResult | null = null,
): Promise<Record<string, unknown> | null> {
const activeState = await readActiveConductorStateForPreToolUse(payload, policyCwd, stateDir, resolvedSessionId);
if (!activeState) return null;
const sessionId = safeString(resolvedSessionId ?? readPayloadSessionId(payload)).trim();
- const writeActor = await resolvePreToolUseWriteActor(payload, cwd, stateDir, sessionId);
+ const writeActor = await resolvePreToolUseWriteActor(payload, cwd, stateDir, sessionId, rootTranscript);
if (writeActor === "provenance-conflict") {
return buildConductorSessionProvenanceDeny(activeState, "payload identity aliases conflict");
}
+ if (
+ writeActor === "main-root"
+ && await isAuthorizedActiveRalplanRootReviewControlPlane({
+ payload,
+ policyCwd,
+ stateDir,
+ sessionId,
+ pointer,
+ rootTranscript,
+ })
+ ) return null;
+ if (
+ writeActor === "main-root"
+ && await isAuthorizedActiveUltragoalPhaseTransitionFallback({
+ payload,
+ policyCwd,
+ stateDir,
+ sessionId,
+ pointer,
+ rootTranscript,
+ })
+ ) return null;
+ if (
+ writeActor === "main-root"
+ && await isAuthorizedActiveUltragoalRootControlPlane({
+ payload,
+ policyCwd,
+ stateDir,
+ sessionId,
+ pointer,
+ rootTranscript,
+ })
+ ) return null;
+ if (
+ writeActor === "main-root"
+ && await isAuthorizedTerminalUltragoalStateFallback({
+ payload,
+ policyCwd,
+ stateDir,
+ sessionId,
+ pointer,
+ rootTranscript,
+ })
+ ) return null;
const nativeSubagentSupport = resolveNativeSubagentSupportStatus({
payload,
persistedSupportBlocker: await readJsonIfExists(nativeSubagentSupportBlockerPath(stateDir)),
@@ -19871,15 +22304,37 @@ export async function buildConductorPreToolUseWriteGuardOutput(
const command = readPreToolUseCommand(payload);
const pathCandidates = readPreToolUsePathCandidates(payload);
const mutationTransport = classifyPreToolUseMutationTransport(payload, toolName, cwd);
+ const leaderMetadataCommandAttempt = writeActor === "main-root"
+ && toolName === "Bash"
+ && isUltragoalMetadataCommandAttempt(command);
- let blocked = false;
- let blockedDetail = "Main-root Conductor write is not delegated";
+ if (
+ writeActor === "main-root"
+ && toolName === "Bash"
+ && (
+ isExactNativeUltragoalBootstrapCommand(command)
+ || (
+ leaderMetadataCommandAttempt
+ && isExactLeaderOwnedUltragoalMetadataCommand(command, readPreToolUseRawCommand(payload), policyCwd)
+ )
+ )
+ ) return null;
+
+ let blocked = leaderMetadataCommandAttempt;
+ let blockedDetail = leaderMetadataCommandAttempt
+ ? "Ultragoal metadata command does not match the exact leader-owned option schema"
+ : "Main-root Conductor write is not delegated";
let nativeChildMutationAttempt = false;
if (toolName === "Bash") {
- if (mutationTransport !== "read-only") {
+ const rawCommand = readPreToolUseRawCommand(payload);
+ if (rawCommand !== command) {
+ blocked = true;
+ nativeChildMutationAttempt = true;
+ blockedDetail = "Bash command bytes must match the exact classified command";
+ } else if (mutationTransport !== "read-only") {
const shellMutations = extractConductorBashMutations(command, cwd, policyCwd);
- const bashEvaluation = evaluateConductorBashWrite(cwd, command, 0, sessionId, policyCwd, readPreToolUseRawCommand(payload));
+ const bashEvaluation = evaluateConductorBashWrite(cwd, command, 0, sessionId, policyCwd, rawCommand);
blocked = !bashEvaluation.allowed;
const canonicalStateCommand = canonicalizeOmxStateTransportCommand(command);
const bashStateOperations = collectOmxStateCommandOperations(canonicalStateCommand, "write");
@@ -19918,6 +22373,8 @@ export async function buildConductorPreToolUseWriteGuardOutput(
}
} else if (mutationTransport === "orchestration" || mutationTransport === "goal-lifecycle") {
nativeChildMutationAttempt = true;
+ blocked = true;
+ blockedDetail = `${toolName} requires documented host-authenticated Main-root authority that Codex 0.145.0 does not expose`;
} else if (mutationTransport === "path") {
nativeChildMutationAttempt = true;
const toolPathCandidates = collectImplementationToolPathCandidates(payload, toolName, pathCandidates);
@@ -19925,7 +22382,10 @@ export async function buildConductorPreToolUseWriteGuardOutput(
blocked = true;
blockedDetail = describeConductorBlockedWrite(toolName, undefined, toolPathCandidates.length);
} else {
- const blockedPath = toolPathCandidates.find((candidate) => !isAllowedConductorMetadataExecutionPath(cwd, policyCwd, candidate));
+ const blockedPath = toolPathCandidates.find((candidate) => (
+ !isSessionBoundNativeAssignmentPath(policyCwd, candidate, sessionId)
+ && !isAllowedConductorMetadataExecutionPath(cwd, policyCwd, candidate)
+ ));
blocked = blockedPath !== undefined;
if (blockedPath !== undefined) {
blockedDetail = describeConductorBlockedWrite(toolName, blockedPath, toolPathCandidates.length);
@@ -19945,11 +22405,23 @@ export async function buildConductorPreToolUseWriteGuardOutput(
stateDir,
policyCwd,
);
- if (writeActor === "team-worker" && !teamWorkerProtectedStateTarget) return null;
+ if (writeActor === "team-worker" && mutationTransport !== "goal-lifecycle" && !teamWorkerProtectedStateTarget) return null;
if (writeActor === "team-worker" && teamWorkerProtectedStateTarget && !blocked) {
blocked = true;
blockedDetail = "Bash targets protected workflow state outside authorized Team-worker scope";
}
+ if (
+ writeActor === "native-child"
+ && nativeChildMutationAttempt
+ && await nativeChildAssignmentAllowsMutation(
+ payload,
+ policyCwd,
+ stateDir,
+ sessionId,
+ toolName,
+ mutationTransport,
+ )
+ ) return null;
if (!blocked && (writeActor !== "native-child" || !nativeChildMutationAttempt)) return null;
if (!blocked && nativeChildMutationAttempt && writeActor === "native-child") {
blockedDetail = toolName === "Bash"
@@ -21573,9 +24045,16 @@ export async function dispatchCodexNativeHook(
: "";
const threadId = safeString(payload.thread_id ?? payload.threadId).trim();
const turnId = safeString(payload.turn_id ?? payload.turnId).trim();
+ const safeRootTranscript = hookEventName === "UserPromptSubmit" || hookEventName === "PreToolUse" || hookEventName === "Stop"
+ ? await readSafeRootTranscriptMetadata(payload, cwd, options.rootTranscriptPostReadHook, {
+ beforeReadDirHook: options.rootTranscriptBeforeReadDirHook,
+ maxEntries: options.rootTranscriptScanMaxEntries,
+ })
+ : null;
+ const safeRootTurnTranscript = safeRootTranscript?.hasExactTurnContext ? safeRootTranscript : null;
const pointer = await readSessionPointer(pointerContext);
const currentSessionState = pointer.status === "usable" ? pointer.state ?? null : null;
- let promptTurnContext: ResolvedPromptTurnContext | null = hookEventName === "UserPromptSubmit"
+ let promptTurnContext: ResolvedPromptTurnContext | null = hookEventName === "UserPromptSubmit" && !safeRootTurnTranscript
? evaluateResolvedPromptTurn({
producer: "native",
payloadSessionId: payload.session_id ?? payload.sessionId,
@@ -21608,9 +24087,18 @@ export async function dispatchCodexNativeHook(
let canonicalSessionId = safeString(currentSessionState?.session_id).trim();
if (promptTurnContext?.status === "authorized") {
canonicalSessionId = promptTurnContext.authorization.targetSessionId;
+ } else if (safeRootTurnTranscript) {
+ canonicalSessionId = safeRootTurnTranscript.sessionId;
+ if (hookEventName === "UserPromptSubmit") {
+ allowImplicitSessionSideEffects = true;
+ stopAuthorizationFailure = null;
+ }
}
let allowGlobalSideEffects = promptTurnContext?.status !== "authorized"
|| promptTurnContext.authorization.globalSideEffects === "allow";
+ if (safeRootTurnTranscript && currentSessionState && !payloadMatchesSessionPointer(safeRootTurnTranscript.sessionId, currentSessionState)) {
+ allowGlobalSideEffects = false;
+ }
let resolvedNativeSessionId = nativeSessionId;
let skipCanonicalSessionStartContext = false;
let isSubagentSessionStart = false;
@@ -21801,8 +24289,38 @@ export async function dispatchCodexNativeHook(
if (hookEventName === "Stop") {
const stopPayloadSessionId = readPayloadSessionId(payload);
const authorizedWorkerStopSessionId = authoritativeWorkerPayloadSessionId;
+ const pointerStateRootMatches = pointer.state
+ ? selectedSessionPointerStateRootMatches(pointer.state, stateDir)
+ : false;
+ const sameSessionStaleDeadPointerAuthorizesStop = !declaredTeamWorker
+ && pointer.status === "stale-dead"
+ && pointer.state !== null
+ && pointer.state !== undefined
+ && pointerStateRootMatches
+ && isSessionStateAuthoritativeForCwd(pointer.state, cwd)
+ && selectedSessionPointerCodexIdentityMatches(pointer.state, stopPayloadSessionId)
+ && safeRootTranscript?.sessionId === stopPayloadSessionId;
+ const rootTranscriptAuthorizesDegradedPointerStop = !declaredTeamWorker
+ && (pointer.status === "stale-dead" || pointer.status === "identity-indeterminate")
+ && pointer.state !== null
+ && pointer.state !== undefined
+ && isSessionStateAuthoritativeForCwd(pointer.state, cwd)
+ && pointerStateRootMatches
+ && (
+ sameSessionStaleDeadPointerAuthorizesStop
+ || (
+ safeRootTranscript?.hasExactTurnContext === true
+ && safeRootTranscript.sessionId === stopPayloadSessionId
+ && (
+ pointer.status === "stale-dead"
+ || selectedSessionPointerCodexIdentityMatches(pointer.state, stopPayloadSessionId)
+ )
+ )
+ );
const stopCanonicalSessionId = declaredTeamWorker && !authorizedWorkerStopSessionId
? ""
+ : rootTranscriptAuthorizesDegradedPointerStop
+ ? stopPayloadSessionId
: await resolveInternalSessionIdForPayload(
cwd,
authorizedWorkerStopSessionId || stopPayloadSessionId,
@@ -21843,6 +24361,13 @@ export async function dispatchCodexNativeHook(
} else if (stopCanonicalSessionId) {
canonicalSessionId = stopCanonicalSessionId;
}
+ if (rootTranscriptAuthorizesDegradedPointerStop) {
+ canonicalSessionId = stopPayloadSessionId;
+ resolvedNativeSessionId = stopPayloadSessionId;
+ allowImplicitSessionSideEffects = true;
+ allowGlobalSideEffects = false;
+ stopAuthorizationFailure = null;
+ }
if (authorizedWorkerStopSessionId && stopCanonicalSessionId === authorizedWorkerStopSessionId) {
allowImplicitSessionSideEffects = true;
stopAuthorizationFailure = null;
@@ -21919,7 +24444,7 @@ export async function dispatchCodexNativeHook(
} else if (prompt && !isSubagentPromptSubmit && allowImplicitSessionSideEffects) {
const rawHookSessionId = canonicalSessionId || nativeSessionId;
const normalizedHookSessionId = normalizeSessionId(rawHookSessionId);
- const explicitHookSessionId = currentSessionState ? undefined : normalizedHookSessionId;
+ const explicitHookSessionId = safeRootTurnTranscript?.sessionId ?? (currentSessionState ? undefined : normalizedHookSessionId);
if (rawHookSessionId && !normalizedHookSessionId) {
suppressActivationSeeding = true;
} else {
@@ -21948,6 +24473,7 @@ export async function dispatchCodexNativeHook(
sessionIdForState || undefined,
threadId || undefined,
turnId || undefined,
+ safeRootTurnTranscript,
) ?? await recordSkillActivation({
stateDir,
sourceCwd: cwd,
@@ -21963,6 +24489,32 @@ export async function dispatchCodexNativeHook(
},
});
}
+ if (
+ skillState?.active === true
+ && skillState.initialized_mode === "ultragoal"
+ && sessionIdForState
+ && (
+ isNativeOutsideTmuxUserPrompt(cwd, payload, sessionIdForState)
+ || isNativeUltragoalBootstrapSurface(cwd, payload, sessionIdForState, safeRootTurnTranscript)
+ )
+ ) {
+ const bootstrap = await readNativeUltragoalBootstrap(stateDir, sessionIdForState);
+ let receiptConfirmed = bootstrap?.status === "active";
+ if (bootstrap && ["ready", "activating"].includes(bootstrap.status) && bootstrap.child_agent_id) {
+ const confirmed = await markNativeUltragoalBootstrapActive({
+ cwd,
+ stateDir,
+ sessionId: sessionIdForState,
+ childAgentId: bootstrap.child_agent_id,
+ });
+ receiptConfirmed = confirmed.ok;
+ }
+ if (!receiptConfirmed && resolveNativeUltragoalConfig().backend === "local-experimental") {
+ const reason = "native_ultragoal_activation_receipt_invalid";
+ await failNativeUltragoalActivation(cwd, stateDir, sessionIdForState, reason);
+ skillState = { ...skillState, active: false, transition_error: reason };
+ }
+ }
// --- Triage classifier (advisory-only, non-keyword prompts) ---
if (
prompt
@@ -22162,6 +24714,8 @@ export async function dispatchCodexNativeHook(
stateDir,
payload,
identitylessTeamWorkerContext,
+ safeRootTranscript,
+ pointer,
);
const payloadSessionId = readPayloadSessionId(payload);
const rootPointerConflict = await readLiveRootSessionPointerConflict(stateDir, payloadSessionId);
@@ -22186,12 +24740,21 @@ export async function dispatchCodexNativeHook(
stateDir,
payloadSessionId,
payloadPolicyCwd,
+ safeRootTranscript,
+ pointer,
)
: null;
const directCancelCommand = safeString(payload.tool_name).trim() === "Bash"
? readPreToolUseCommand(payload)
: "";
if (/^[ \t]*omx[ \t]+cancel\b/.test(directCancelCommand)) {
+ const [autopilotState, ultragoalState, skillState] = sessionBinding.valid
+ ? await Promise.all([
+ readStopSessionPinnedState("autopilot-state.json", policyCwd, sessionBinding.canonicalSessionId, stateDir),
+ readStopSessionPinnedState("ultragoal-state.json", policyCwd, sessionBinding.canonicalSessionId, stateDir),
+ readStopSessionPinnedState("skill-active-state.json", policyCwd, sessionBinding.canonicalSessionId, stateDir),
+ ])
+ : [null, null, null];
const directCancel = await handleDirectOmxCancel({
command: directCancelCommand,
rawCommand: readPreToolUseRawCommand(payload),
@@ -22199,12 +24762,23 @@ export async function dispatchCodexNativeHook(
stateDir,
canonicalSessionId: sessionBinding.valid ? sessionBinding.canonicalSessionId : "",
payload,
- allowForce: false,
- activeState: sessionBinding.valid
- ? (await readStopSessionPinnedState("autopilot-state.json", policyCwd, sessionBinding.canonicalSessionId, stateDir) ?? {})
- : {},
+ activeStates: {
+ autopilot: autopilotState ?? {},
+ ultragoal: ultragoalState ?? {},
+ },
+ skillState: skillState ?? {},
+ rootTranscript: safeRootTranscript,
});
- if (directCancel.kind !== "not-direct-cancel") outputJson = directCancel.output;
+ if (directCancel.kind !== "not-direct-cancel") {
+ if (directCancel.kind === "handled" && sessionBinding.canonicalSessionId) {
+ await revokeLocalNativeExecutorAssignment({
+ stateDir,
+ sessionId: sessionBinding.canonicalSessionId,
+ reason: "root_cancelled",
+ });
+ }
+ outputJson = directCancel.output;
+ }
}
if (!outputJson && !policyRoot.valid && policyRoot.statePresent && mutationTransport !== "read-only") {
outputJson = buildConductorSessionProvenanceDeny(
@@ -22303,6 +24877,8 @@ export async function dispatchCodexNativeHook(
stateDir,
payloadSessionId,
policyCwd,
+ safeRootTranscript,
+ pointer,
)
: null;
outputJson = buildNativeUnknownRolePreToolUseOutput(payload, policyCwd)
@@ -22326,12 +24902,21 @@ export async function dispatchCodexNativeHook(
})();
outputJson = nativePreToolUseSpecificDeny
?? buildNativeUnknownRolePreToolUseOutput(payload, policyCwd)
+ ?? await buildPendingNativeUltragoalExecutorGuardOutput(
+ payload,
+ policyCwd,
+ stateDir,
+ preToolUseSessionId,
+ safeRootTranscript,
+ )
?? await buildDeepInterviewPreToolUseBoundaryOutput(
payload,
policyCwd,
stateDir,
preToolUseSessionId,
cwd,
+ cwd,
+ safeRootTranscript,
)
?? await buildRalplanPreToolUseBoundaryOutput(
payload,
@@ -22339,6 +24924,9 @@ export async function dispatchCodexNativeHook(
stateDir,
preToolUseSessionId,
cwd,
+ cwd,
+ safeRootTranscript,
+ pointer,
)
?? await buildPlanningRootPointerConflictPreToolUseOutput(
payload,
@@ -22346,12 +24934,21 @@ export async function dispatchCodexNativeHook(
stateDir,
rootPointerConflict,
)
+ ?? await buildNativeUltragoalBootstrapMutationGuardOutput(
+ payload,
+ policyCwd,
+ stateDir,
+ preToolUseSessionId,
+ safeRootTranscript,
+ )
?? await buildUltragoalNoOwnerActivationGuardOutput(
payload,
cwd,
stateDir,
preToolUseSessionId,
policyCwd,
+ safeRootTranscript,
+ pointer,
)
?? await buildConductorPreToolUseWriteGuardOutput(
payload,
@@ -22359,8 +24956,17 @@ export async function dispatchCodexNativeHook(
stateDir,
preToolUseSessionId,
policyCwd,
+ safeRootTranscript,
+ pointer,
+ )
+ ?? await buildRawProtectedWorkflowStatePathOutput(
+ payload,
+ policyCwd,
+ stateDir,
+ preToolUseSessionId,
+ guardedConductorState !== null,
+ safeRootTranscript,
)
- ?? buildRawProtectedWorkflowStatePathOutput(payload, policyCwd, stateDir)
?? await buildNativeSubagentCapacityCloseGuardOutput(payload, policyCwd, stateDir)
?? buildMalformedPreToolUseBlockTestOutput(payload)
?? buildNativePreToolUseOutput(payload);
@@ -22375,6 +24981,40 @@ export async function dispatchCodexNativeHook(
}
await handleTeamWorkerPostToolUseSuccess(payload, cwd);
}
+ if (
+ canonicalSessionId
+ && (
+ isNativeOutsideTmuxUserPrompt(cwd, payload, canonicalSessionId)
+ || isNativeUltragoalBootstrapSurface(cwd, payload, canonicalSessionId)
+ )
+ ) {
+ const toolName = safeString(payload.tool_name).trim();
+ const activationCandidates = collectUltragoalActivationCandidatePayloads(payload, toolName, cwd);
+ if (activationCandidates.some((candidate) => isUltragoalConductorActivationPayload(candidate))) {
+ const bootstrap = await readNativeUltragoalBootstrap(stateDir, canonicalSessionId);
+ const state = await readStopSessionPinnedState("ultragoal-state.json", cwd, canonicalSessionId, stateDir);
+ if (isActiveConductorModeState(state, "ultragoal", canonicalSessionId)) {
+ let receiptConfirmed = bootstrap?.status === "active";
+ if (bootstrap?.status === "activating" && bootstrap.child_agent_id) {
+ const confirmed = await markNativeUltragoalBootstrapActive({
+ cwd,
+ stateDir,
+ sessionId: canonicalSessionId,
+ childAgentId: bootstrap.child_agent_id,
+ });
+ receiptConfirmed = confirmed.ok;
+ }
+ if (!receiptConfirmed && resolveNativeUltragoalConfig().backend === "local-experimental") {
+ await failNativeUltragoalActivation(
+ cwd,
+ stateDir,
+ canonicalSessionId,
+ "native_ultragoal_activation_receipt_invalid",
+ );
+ }
+ }
+ }
+ }
outputJson = buildNativePostToolUseOutput(payload);
} else if (hookEventName === "Stop") {
if (declaredTeamWorkerStopOnly) {
@@ -22413,6 +25053,9 @@ export async function dispatchCodexNativeHook(
};
}
}
+ if (!declaredTeamWorkerStopOnly && canonicalSessionId) {
+ await revokeTerminalNativeUltragoalBootstrap(policyCwd, stateDir, canonicalSessionId);
+ }
}
return {
diff --git a/src/scripts/notify-hook.ts b/src/scripts/notify-hook.ts
index 6c7e2cbcc84f5a0405a432061765b22344a66db5..42ab6e2848e1d7f37817e998e7e9a7ef8885f215 100644
--- a/src/scripts/notify-hook.ts
+++ b/src/scripts/notify-hook.ts
@@ -301,7 +301,8 @@ function looksLikeAutopilotTerminalHandoff(text: string): boolean {
function isTerminalModeStateObject(value: unknown, mode: string): boolean {
if (!value || typeof value !== 'object' || Array.isArray(value)) return false;
const state = value as Record<string, unknown>;
- if (safeString(state.mode).trim() !== mode) return false;
+ const persistedMode = safeString(state.mode).trim();
+ if (persistedMode && persistedMode !== mode) return false;
if (state.active === true) return false;
const phase = safeString(state.current_phase || state.currentPhase).trim().toLowerCase().replace(/_/g, '-');
if (['complete', 'completed', 'failed', 'cancelled', 'canceled', 'stopped', 'user-stopped'].includes(phase)) return true;
@@ -324,20 +325,40 @@ function terminalStateMatchesNotifyTurn(state: Record<string, unknown>, payload:
return Boolean(payloadThreadId && stateThreadId && payloadThreadId === stateThreadId);
}
-async function hasTerminalAutopilotStateForNotifyTurn(
+async function nativeStopReceiptMatchesNotifyTurn(
stateDir: string,
sessionId: string,
payload: Record<string, unknown>,
+): Promise<boolean> {
+ const payloadTurnId = safeString(payload['turn-id'] || payload.turn_id || '').trim();
+ if (!sessionId || !payloadTurnId) return false;
+ const rootState = await readJsonFileIfObject(join(stateDir, 'native-stop-state.json'));
+ const sessions = rootState?.sessions;
+ if (!sessions || typeof sessions !== 'object' || Array.isArray(sessions)) return false;
+ const session = (sessions as Record<string, unknown>)[sessionId];
+ if (!session || typeof session !== 'object' || Array.isArray(session)) return false;
+ const guard = (session as Record<string, unknown>).ordinary_no_progress_guard;
+ if (!guard || typeof guard !== 'object' || Array.isArray(guard)) return false;
+ return safeString((guard as Record<string, unknown>).last_turn_id).trim() === payloadTurnId;
+}
+
+async function hasTerminalModeStateForNotifyTurn(
+ stateDir: string,
+ sessionId: string,
+ payload: Record<string, unknown>,
+ mode: string,
): Promise<boolean> {
const state = await readScopedJsonIfExists(
stateDir,
- 'autopilot-state.json',
+ `${mode}-state.json`,
sessionId || undefined,
null,
{ includeRootFallback: true },
);
- return isTerminalModeStateObject(state, 'autopilot')
- && terminalStateMatchesNotifyTurn(state as Record<string, unknown>, payload);
+ if (!isTerminalModeStateObject(state, mode)) return false;
+ if (terminalStateMatchesNotifyTurn(state as Record<string, unknown>, payload)) return true;
+ return mode === 'ultragoal'
+ && await nativeStopReceiptMatchesNotifyTurn(stateDir, sessionId, payload);
}
async function shouldSuppressAutopilotTerminalReplayActivation(
@@ -352,7 +373,24 @@ async function shouldSuppressAutopilotTerminalReplayActivation(
const lastAssistantMessage = safeString(payload['last-assistant-message'] || payload.last_assistant_message || '');
if (!looksLikeAutopilotTerminalHandoff(lastAssistantMessage) && !isNotifyFallbackTaskCompletePayload(payload)) return false;
- return hasTerminalAutopilotStateForNotifyTurn(stateDir, sessionId, payload);
+ return hasTerminalModeStateForNotifyTurn(stateDir, sessionId, payload, 'autopilot');
+}
+
+async function shouldSuppressUltragoalTerminalReplayActivation(
+ stateDir: string,
+ payload: Record<string, unknown>,
+ isUltragoalActivation: boolean,
+ sessionId: string,
+): Promise<boolean> {
+ if (!isTurnCompletePayload(payload) && !isNotifyFallbackTaskCompletePayload(payload)) return false;
+ if (!isUltragoalActivation) return false;
+
+ // Native Codex notify replays the completed turn's original input after the
+ // final assistant message. A same-turn terminal state is stronger evidence
+ // than prose in that message and must win over the replayed `$ultragoal`
+ // keyword. A later turn has a different turn id and remains eligible to
+ // start a new run through the ordinary activation path.
+ return hasTerminalModeStateForNotifyTurn(stateDir, sessionId, payload, 'ultragoal');
}
export interface NotifySkillActivationInput {
@@ -425,6 +463,13 @@ export async function recordNotifySkillActivation(
input.sessionId || '',
);
if (terminalAutopilotReplay && runtimeMatches[0]?.skill === 'autopilot') return null;
+ const terminalUltragoalReplay = await shouldSuppressUltragoalTerminalReplayActivation(
+ input.stateDir,
+ input.payload,
+ runtimeMatches.some((match) => match.skill === 'ultragoal'),
+ input.sessionId || '',
+ );
+ if (terminalUltragoalReplay && runtimeMatches[0]?.skill === 'ultragoal') return null;
return (dependencies.recordSkillActivation ?? recordSkillActivation)({
stateDir: input.stateDir,
diff --git a/src/state/__tests__/operations.test.ts b/src/state/__tests__/operations.test.ts
index 188f9e96dcb726ef583e2513d001cd7a817a6a43..67887410b8869ce8a1d126a8a869c5fa1d8561d0 100644
--- a/src/state/__tests__/operations.test.ts
+++ b/src/state/__tests__/operations.test.ts
@@ -604,6 +604,31 @@ describe('state operations directory initialization', () => {
}
});
+ it('reads the ultragoal workflow state written through the generic state surface', async () => {
+ const wd = await mkdtemp(join(tmpdir(), 'omx-state-ops-ultragoal-read-'));
+ try {
+ const writeResponse = await executeStateOperation('state_write', {
+ workingDirectory: wd,
+ mode: 'ultragoal',
+ active: false,
+ current_phase: 'complete',
+ });
+ assert.equal(writeResponse.isError, undefined);
+
+ const readResponse = await executeStateOperation('state_read', {
+ workingDirectory: wd,
+ mode: 'ultragoal',
+ });
+
+ assert.equal(readResponse.isError, undefined);
+ assert.equal((readResponse.payload as { active?: unknown }).active, false);
+ assert.equal((readResponse.payload as { current_phase?: unknown }).current_phase, 'complete');
+ assert.equal((readResponse.payload as { run_outcome?: unknown }).run_outcome, 'finish');
+ } finally {
+ await rm(wd, { recursive: true, force: true });
+ }
+ });
+
it('bootstraps tmux-hook from the current tmux pane for mutating state operations', async () => {
const wd = await mkdtemp(join(tmpdir(), 'omx-state-ops-live-'));
try {
@@ -1249,6 +1274,68 @@ describe('state operations directory initialization', () => {
}
});
+ it('terminalizes a locally reviewed ralplan as non-authorizing blocked state', async () => {
+ const wd = await mkdtemp(join(tmpdir(), 'omx-state-ops-ralplan-local-review-blocked-'));
+ try {
+ const { stateDir, sessionId } = await seedWritableScope(wd, 'sess-ralplan-local-review-blocked');
+ const sessionDir = join(stateDir, 'sessions', sessionId);
+ await writeFile(join(sessionDir, 'ralplan-state.json'), JSON.stringify({
+ mode: 'ralplan',
+ active: true,
+ current_phase: 'critic-review',
+ session_id: sessionId,
+ ralplan_consensus_gate: {
+ complete: false,
+ ralplan_architect_review: { verdict: 'APPROVE', artifact_path: '.omx/plans/architect-review.md' },
+ ralplan_critic_review: { verdict: 'APPROVE', artifact_path: '.omx/plans/critic-review.md' },
+ },
+ }, null, 2));
+ const activeSkillState = {
+ version: 1,
+ active: true,
+ skill: 'ralplan',
+ phase: 'critic-review',
+ session_id: sessionId,
+ active_skills: [{ skill: 'ralplan', phase: 'critic-review', active: true, session_id: sessionId }],
+ };
+ await writeFile(join(stateDir, 'skill-active-state.json'), JSON.stringify(activeSkillState, null, 2));
+ await writeFile(join(sessionDir, 'skill-active-state.json'), JSON.stringify(activeSkillState, null, 2));
+
+ const response = await executeStateOperation('state_write', {
+ workingDirectory: wd,
+ mode: 'ralplan',
+ active: false,
+ current_phase: 'blocked',
+ blocked_reason: 'documented_host_consensus_receipt_unavailable',
+ ralplan_consensus_gate: {
+ complete: false,
+ blocked_reason: 'documented_host_consensus_receipt_unavailable',
+ },
+ });
+
+ assert.equal(response.isError, undefined);
+ const sessionRalplan = JSON.parse(await readFile(join(sessionDir, 'ralplan-state.json'), 'utf-8')) as Record<string, unknown>;
+ assert.equal(sessionRalplan.active, false);
+ assert.equal(sessionRalplan.current_phase, 'blocked');
+ assert.equal(sessionRalplan.blocked_reason, 'documented_host_consensus_receipt_unavailable');
+ assert.equal((sessionRalplan.ralplan_consensus_gate as Record<string, unknown>).complete, false);
+ assert.deepEqual(
+ (sessionRalplan.ralplan_consensus_gate as Record<string, unknown>).ralplan_architect_review,
+ { verdict: 'APPROVE', artifact_path: '.omx/plans/architect-review.md' },
+ );
+ assert.deepEqual(
+ (sessionRalplan.ralplan_consensus_gate as Record<string, unknown>).ralplan_critic_review,
+ { verdict: 'APPROVE', artifact_path: '.omx/plans/critic-review.md' },
+ );
+ const sessionSkill = JSON.parse(await readFile(join(sessionDir, 'skill-active-state.json'), 'utf-8')) as Record<string, unknown>;
+ assert.equal(sessionSkill.active, false);
+ assert.equal(sessionSkill.phase, 'blocked');
+ assert.deepEqual((await executeStateOperation('state_list_active', { workingDirectory: wd })).payload, { active_modes: [] });
+ } finally {
+ await rm(wd, { recursive: true, force: true });
+ }
+ });
+
it('rejects forged ralplan complete gates before mutating active session state', async () => {
const wd = await mkdtemp(join(tmpdir(), 'omx-state-ops-ralplan-forged-complete-'));
try {
@@ -4863,4 +4950,3 @@ function assertPrefix(events: WritableEvent[], expected: WritableEvent[]): void
}
});
});
-
diff --git a/src/state/__tests__/skill-active.test.ts b/src/state/__tests__/skill-active.test.ts
index 3576e6558d33fbc4863a5fcd4d7aac46f0632efb..c09c15acd9882a1dc2ecf4d3acff86c1146141a3 100644
--- a/src/state/__tests__/skill-active.test.ts
+++ b/src/state/__tests__/skill-active.test.ts
@@ -431,6 +431,7 @@ describe('skill-active state helpers', () => {
const sessionState = await readVisibleSkillActiveState(cwd, 'sess-terminal');
assert.ok(sessionState);
assert.equal(sessionState.active, false);
+ assert.equal(sessionState.phase, 'complete');
assert.deepEqual(listActiveSkills(sessionState), []);
const rootState = JSON.parse(
diff --git a/src/state/operations.ts b/src/state/operations.ts
index 3b3c99a56de8d1871dc4e5db55a87ba888481194..7290c933a00c30417e62de13e247c0d1ac644fd4 100644
--- a/src/state/operations.ts
+++ b/src/state/operations.ts
@@ -116,6 +116,7 @@ export const SUPPORTED_STATE_READ_MODES = [
'ralph',
'ultrawork',
'ultraqa',
+ 'ultragoal',
'ralplan',
'deep-interview',
'skill-active',
@@ -134,6 +135,10 @@ export interface StateOperationResponse {
isError?: boolean;
}
+export interface StateOperationExecutionOptions {
+ beforeStateWriteCommit?: () => Promise<void>;
+}
+
const stateWriteQueues = new Map<string, Promise<void>>();
async function withStateWriteLock<T>(path: string, fn: () => Promise<T>): Promise<T> {
@@ -769,6 +774,7 @@ async function readSessionDetailTransitionModes(
export async function executeStateOperation(
name: StateOperationName,
rawArgs: Record<string, unknown> = {},
+ executionOptions: StateOperationExecutionOptions = {},
): Promise<StateOperationResponse> {
let cwd: string;
let explicitSessionId: string | undefined;
@@ -802,13 +808,17 @@ export async function executeStateOperation(
const mode = validateStateModeSegment(rawArgs.mode);
const { baseStateDir, rootSource } = getBaseStateDirWithSource(cwd);
await initializeStateEnvironment(cwd, effectiveSessionId, rootSource);
- const beforeCommit = createWritableCommitRevalidator({
+ const revalidateWritableScope = createWritableCommitRevalidator({
operation: 'state_write',
cwd,
explicitSessionId,
capturedScope: stateScope,
baseStateDir,
});
+ const beforeCommit: BeforeWritableCommit = async (event) => {
+ await revalidateWritableScope(event);
+ await executionOptions.beforeStateWriteCommit?.();
+ };
// Write to the exact resolved scope directory; never recompute the
// target root/path after authorization.
const path = join(stateScope.stateDir, getStateFilename(mode));
@@ -834,11 +844,20 @@ export async function executeStateOperation(
}
}
+ const customStateRecord = (customState as Record<string, unknown>) || {};
const mergedRaw = {
...existing,
...fields,
- ...((customState as Record<string, unknown>) || {}),
+ ...customStateRecord,
} as Record<string, unknown>;
+ const incomingRalplanConsensusGate = fields.ralplan_consensus_gate
+ ?? customStateRecord.ralplan_consensus_gate;
+ if (mode === 'ralplan' && incomingRalplanConsensusGate !== undefined) {
+ mergedRaw.ralplan_consensus_gate = {
+ ...objectRecord(existing.ralplan_consensus_gate),
+ ...objectRecord(incomingRalplanConsensusGate),
+ };
+ }
normalizeCurrentPhaseAliasForWrite(mergedRaw, fields, customState);
delete mergedRaw.trustedPipelineProgress;
if (!hasExplicitStateField(fields, customState, 'run_outcome')) {
diff --git a/src/state/skill-active.ts b/src/state/skill-active.ts
index 6f485e6622c0525cc377e074b0301d6d2f75ddc5..daf04b9745d67fe04554f43b1969422053edbb2a 100644
--- a/src/state/skill-active.ts
+++ b/src/state/skill-active.ts
@@ -468,7 +468,9 @@ export async function syncCanonicalSkillStateForMode(options: SyncCanonicalSkill
active: entries.length > 0,
skill: primaryEntry?.skill || primarySkill || fallbackMode,
keyword: safeString(inheritedBase.keyword).trim(),
- phase: primaryEntry?.phase || safeString(inheritedBase.phase).trim(),
+ phase: primaryEntry?.phase
+ || (entries.length === 0 ? safeString(currentPhase).trim() : '')
+ || safeString(inheritedBase.phase).trim(),
activated_at: primaryEntry?.activated_at || safeString(inheritedBase.activated_at).trim() || nowIso,
updated_at: nowIso,
source: safeString(inheritedBase.source).trim() || source,
diff --git a/src/subagents/__tests__/tracker.test.ts b/src/subagents/__tests__/tracker.test.ts
index f5ace53170b2c7fad4efa7dfc36e4c7195d39ea6..79e369758bb8785da3f2d8e2ad898490313b4079 100644
--- a/src/subagents/__tests__/tracker.test.ts
+++ b/src/subagents/__tests__/tracker.test.ts
@@ -5,7 +5,7 @@ import { mkdtemp, mkdir, rm, writeFile } from 'node:fs/promises';
import { hostname, tmpdir } from 'node:os';
import { join } from 'node:path';
import { describe, it } from 'node:test';
-import { __setCrossProcessPublishBarrierForTest, __setCrossProcessQuarantineBarrierForTest, consumeDirectChildReopenContext, CrossProcessLockLostError, buildSubagentResumeLedger, CROSS_PROCESS_LOCK_ARTIFACT_SWEEP_CAP, CROSS_PROCESS_LOCK_LEASE_MS, createSubagentTrackingState, crossProcessLockPath, DESCRIPTIVE_ADAPTED_PROVENANCE, fenceNativeSubagentAuthorities, forceGlobalAuthorityDenial, recordNativeSubagentAuthorityObservation, recordSubagentTurn, recordSubagentTurnForSession, NATIVE_SUBAGENT_PROVENANCE, readProcessStartIdentity, readSubagentTrackingState, readSubagentTrackingStateStrict, repairPersistedRootIdentity, revokeNativeSubagentAuthorities, selectReusableSubagentEntry, subagentTrackingPath, summarizeSubagentSession, withCrossProcessFileLockSync, writeSubagentTrackingState } from '../tracker.js';
+import { acquireCrossProcessFileLock, __setCrossProcessPublishBarrierForTest, __setCrossProcessQuarantineBarrierForTest, consumeDirectChildReopenContext, CrossProcessLockLostError, buildSubagentResumeLedger, CROSS_PROCESS_LOCK_ARTIFACT_SWEEP_CAP, CROSS_PROCESS_LOCK_LEASE_MS, createSubagentTrackingState, crossProcessLockPath, DESCRIPTIVE_ADAPTED_PROVENANCE, ensureExactDescriptiveLeaderForSession, fenceNativeSubagentAuthorities, forceGlobalAuthorityDenial, recordNativeSubagentAuthorityObservation, recordSubagentTurn, recordSubagentTurnForSession, NATIVE_SUBAGENT_PROVENANCE, readProcessStartIdentity, readSubagentTrackingState, readSubagentTrackingStateStrict, repairPersistedRootIdentity, revokeNativeSubagentAuthorities, selectReusableSubagentEntry, subagentTrackingPath, summarizeSubagentSession, withCrossProcessFileLockSync, writeSubagentTrackingState } from '../tracker.js';
import { NATIVE_SUBAGENT_ROLE_ROUTING_MARKER_FILE, readRoleRoutingMarker, writeRoleRoutingMarker } from '../role-routing-marker.js';
const CROSS_PROCESS_LOCK_HOLDER_SOURCE = `
@@ -919,6 +919,268 @@ describe('subagents/tracker', () => {
}
});
+ it('keeps an exact descriptive leader byte-for-byte without clearing completion or status', () => {
+ const cwd = mkdtempSync(join(tmpdir(), 'omx-native-root-preserve-'));
+ try {
+ const path = subagentTrackingPath(cwd);
+ mkdirSync(join(cwd, '.omx', 'state'), { recursive: true });
+ const timestamp = '2026-07-29T20:00:00.000Z';
+ const raw = `${JSON.stringify({
+ schemaVersion: 1,
+ sessions: {
+ canonical: {
+ session_id: 'canonical',
+ leader_thread_id: 'root',
+ updated_at: timestamp,
+ threads: {
+ root: {
+ thread_id: 'root',
+ kind: 'leader',
+ status: 'closed',
+ completed_at: timestamp,
+ completion_source: 'task_complete',
+ first_seen_at: timestamp,
+ last_seen_at: timestamp,
+ turn_count: 7,
+ },
+ child: {
+ thread_id: 'child',
+ kind: 'subagent',
+ provenance_kind: NATIVE_SUBAGENT_PROVENANCE,
+ direct_child_root_id: 'root',
+ direct_child_parent_id: 'root',
+ status: 'available',
+ first_seen_at: timestamp,
+ last_seen_at: timestamp,
+ turn_count: 1,
+ },
+ },
+ },
+ },
+ }, null, 2)}\n`;
+ writeFileSync(path, raw);
+ __setCrossProcessPublishBarrierForTest(() => {
+ throw new Error('exact root must not publish');
+ });
+ const result = ensureExactDescriptiveLeaderForSession(cwd, {
+ sessionId: 'canonical',
+ rootThreadId: 'root',
+ timestamp: '2026-07-29T21:00:00.000Z',
+ });
+ assert.equal(result.sessions.canonical?.threads.root?.status, 'closed');
+ assert.equal(result.sessions.canonical?.threads.root?.completed_at, timestamp);
+ assert.equal(readFileSync(path, 'utf8'), raw);
+
+ const conflicting = JSON.parse(raw);
+ conflicting.sessions.canonical.threads.child.direct_child_parent_id = 'foreign-parent';
+ const conflictingRaw = `${JSON.stringify(conflicting, null, 2)}\n`;
+ writeFileSync(path, conflictingRaw);
+ assert.throws(() => ensureExactDescriptiveLeaderForSession(cwd, {
+ sessionId: 'canonical',
+ rootThreadId: 'root',
+ }), /native_ultragoal_root_tracker_conflict/);
+ assert.equal(readFileSync(path, 'utf8'), conflictingRaw);
+ } finally {
+ __setCrossProcessPublishBarrierForTest(null);
+ rmSync(cwd, { recursive: true, force: true });
+ }
+ });
+
+ it('replaces a lone auxiliary descriptive leader with the exact canonical App root', () => {
+ const cwd = mkdtempSync(join(tmpdir(), 'omx-native-root-auxiliary-repair-'));
+ try {
+ const path = subagentTrackingPath(cwd);
+ mkdirSync(join(cwd, '.omx', 'state'), { recursive: true });
+ const timestamp = '2026-07-30T10:31:39.523Z';
+ writeFileSync(path, `${JSON.stringify({
+ schemaVersion: 1,
+ sessions: {
+ canonical: {
+ session_id: 'canonical',
+ leader_thread_id: 'auxiliary-notify-thread',
+ updated_at: timestamp,
+ threads: {
+ 'auxiliary-notify-thread': {
+ thread_id: 'auxiliary-notify-thread',
+ kind: 'leader',
+ first_seen_at: timestamp,
+ last_seen_at: timestamp,
+ last_turn_id: 'auxiliary-notify-turn',
+ turn_count: 1,
+ },
+ },
+ },
+ },
+ }, null, 2)}\n`);
+
+ const result = ensureExactDescriptiveLeaderForSession(cwd, {
+ sessionId: 'canonical',
+ rootThreadId: 'canonical',
+ timestamp: '2026-07-30T10:32:00.000Z',
+ });
+
+ assert.equal(result.sessions.canonical?.leader_thread_id, 'canonical');
+ assert.equal(result.sessions.canonical?.threads.canonical?.kind, 'leader');
+ assert.equal(result.sessions.canonical?.threads['auxiliary-notify-thread'], undefined);
+ } finally {
+ rmSync(cwd, { recursive: true, force: true });
+ }
+ });
+
+ it('does not replace a non-canonical or non-minimal tracker leader', () => {
+ for (const [name, rootThreadId, extraLeaderFields] of [
+ ['non-canonical root', 'different-root', {}],
+ ['non-minimal leader', 'canonical', { status: 'available' }],
+ ['unknown future authority', 'canonical', { future_authority_marker: 'attested' }],
+ ] as const) {
+ const cwd = mkdtempSync(join(tmpdir(), 'omx-native-root-auxiliary-deny-'));
+ try {
+ const path = subagentTrackingPath(cwd);
+ mkdirSync(join(cwd, '.omx', 'state'), { recursive: true });
+ const timestamp = '2026-07-30T10:31:39.523Z';
+ const raw = `${JSON.stringify({
+ schemaVersion: 1,
+ sessions: {
+ canonical: {
+ session_id: 'canonical',
+ leader_thread_id: 'existing-leader',
+ updated_at: timestamp,
+ threads: {
+ 'existing-leader': {
+ thread_id: 'existing-leader',
+ kind: 'leader',
+ first_seen_at: timestamp,
+ last_seen_at: timestamp,
+ turn_count: 1,
+ ...extraLeaderFields,
+ },
+ },
+ },
+ },
+ }, null, 2)}\n`;
+ writeFileSync(path, raw);
+ assert.throws(() => ensureExactDescriptiveLeaderForSession(cwd, {
+ sessionId: 'canonical',
+ rootThreadId,
+ }), /native_ultragoal_root_tracker_conflict/, name);
+ assert.equal(readFileSync(path, 'utf8'), raw, name);
+ } finally {
+ rmSync(cwd, { recursive: true, force: true });
+ }
+ }
+ });
+
+ it('rejects a root id that is a trusted subagent in a foreign session without publishing', () => {
+ const cwd = mkdtempSync(join(tmpdir(), 'omx-native-root-global-collision-'));
+ try {
+ const path = subagentTrackingPath(cwd);
+ mkdirSync(join(cwd, '.omx', 'state'), { recursive: true });
+ const timestamp = '2026-07-29T20:00:00.000Z';
+ const raw = `${JSON.stringify({
+ schemaVersion: 1,
+ sessions: {
+ foreign: {
+ session_id: 'foreign',
+ leader_thread_id: 'foreign-root',
+ updated_at: timestamp,
+ threads: {
+ 'foreign-root': {
+ thread_id: 'foreign-root',
+ kind: 'leader',
+ first_seen_at: timestamp,
+ last_seen_at: timestamp,
+ turn_count: 1,
+ },
+ root: {
+ thread_id: 'root',
+ kind: 'subagent',
+ provenance_kind: NATIVE_SUBAGENT_PROVENANCE,
+ direct_child_root_id: 'foreign-root',
+ direct_child_parent_id: 'foreign-root',
+ status: 'available',
+ first_seen_at: timestamp,
+ last_seen_at: timestamp,
+ turn_count: 1,
+ },
+ },
+ },
+ },
+ }, null, 2)}\n`;
+ writeFileSync(path, raw);
+ assert.throws(() => ensureExactDescriptiveLeaderForSession(cwd, {
+ sessionId: 'canonical',
+ rootThreadId: 'root',
+ }), /native_ultragoal_root_tracker_conflict/);
+ assert.equal(readFileSync(path, 'utf8'), raw);
+ assert.equal(JSON.parse(readFileSync(path, 'utf8')).sessions.canonical, undefined);
+ } finally {
+ rmSync(cwd, { recursive: true, force: true });
+ }
+ });
+
+ it('serializes descriptive root publication before a competing authority conflict', async () => {
+ const cwd = mkdtempSync(join(tmpdir(), 'omx-native-root-authority-race-'));
+ const readyPath = join(cwd, 'authority-contended');
+ const resultPath = join(cwd, 'authority-result.json');
+ let competitor: ReturnType<typeof spawn> | undefined;
+ try {
+ const timestamp = '2026-07-29T20:00:00.000Z';
+ mkdirSync(join(cwd, '.omx', 'state'), { recursive: true });
+ writeFileSync(subagentTrackingPath(cwd), JSON.stringify({
+ schemaVersion: 1,
+ sessions: {
+ canonical: {
+ session_id: 'canonical',
+ updated_at: timestamp,
+ threads: {
+ child: {
+ thread_id: 'child',
+ kind: 'subagent',
+ provenance_kind: NATIVE_SUBAGENT_PROVENANCE,
+ direct_child_root_id: 'root',
+ direct_child_parent_id: 'root',
+ status: 'available',
+ first_seen_at: timestamp,
+ last_seen_at: timestamp,
+ turn_count: 1,
+ },
+ },
+ },
+ },
+ }));
+ __setCrossProcessPublishBarrierForTest(() => {
+ competitor = spawnAuthorityCompetitor(cwd, 'revoke', readyPath, resultPath);
+ waitForFileSync(readyPath, 10_000);
+ });
+ ensureExactDescriptiveLeaderForSession(cwd, {
+ sessionId: 'canonical',
+ rootThreadId: 'root',
+ });
+ __setCrossProcessPublishBarrierForTest(null);
+ assert.ok(competitor);
+ await waitForChildExit(competitor);
+ const result = JSON.parse(readFileSync(resultPath, 'utf8'));
+ assert.equal(result.observedContention, true);
+ assert.equal(result.result, 'revoked');
+ const state = JSON.parse(readFileSync(subagentTrackingPath(cwd), 'utf8'));
+ assert.equal(state.sessions.canonical.leader_thread_id, 'root');
+ assert.equal(state.sessions.canonical.threads.root.kind, 'leader');
+ assert.equal(state.sessions.canonical.threads.child.reopen_authority_revoked, true);
+ assert.throws(() => ensureExactDescriptiveLeaderForSession(cwd, {
+ sessionId: 'canonical',
+ rootThreadId: 'other-root',
+ }), /native_ultragoal_root_tracker_conflict/);
+ assert.equal(
+ JSON.parse(readFileSync(subagentTrackingPath(cwd), 'utf8')).sessions.canonical.threads.child.reopen_authority_revoked,
+ true,
+ );
+ } finally {
+ __setCrossProcessPublishBarrierForTest(null);
+ await stopChild(competitor);
+ rmSync(cwd, { recursive: true, force: true });
+ }
+ });
+
it('serializes a queued reopen behind revocation publication', async () => {
const cwd = mkdtempSync(join(tmpdir(), 'omx-3284-tracker-contended-revoke-first-'));
const readyPath = join(cwd, 'reopen-contended');
@@ -1880,6 +2142,31 @@ describe('subagents/tracker', () => {
}
});
+ it('can preserve a live local async owner beyond the legacy lease', async () => {
+ const cwd = await mkdtemp(join(tmpdir(), 'omx-subagent-tracker-'));
+ const resourcePath = join(cwd, 'lock-resource');
+ const lockPath = crossProcessLockPath(resourcePath);
+ try {
+ const liveClaim = crossProcessLockClaim(
+ 'live-async-owner',
+ process.pid,
+ Date.now() - CROSS_PROCESS_LOCK_LEASE_MS - 1,
+ );
+ await writeFile(lockPath, liveClaim);
+ await assert.rejects(
+ acquireCrossProcessFileLock(resourcePath, {
+ maxAttempts: 1,
+ retryMs: 1,
+ preserveLiveLocalOwner: true,
+ }),
+ /Timed out waiting for cross-process lock/,
+ );
+ assert.equal(readFileSync(lockPath, 'utf-8'), liveClaim);
+ } finally {
+ await rm(cwd, { recursive: true, force: true });
+ }
+ });
+
it('does not steal a live same-host identity-matched claim after its lease or mistake its token for ours', async () => {
const cwd = await mkdtemp(join(tmpdir(), 'omx-subagent-tracker-'));
const resourcePath = join(cwd, 'lock-resource');
diff --git a/src/subagents/tracker.ts b/src/subagents/tracker.ts
index 7823b2523a857fbc70bdb2252d138287d22239c1..b8426fb181e3d07c133d1b2a7e5277ad5662cd38 100644
--- a/src/subagents/tracker.ts
+++ b/src/subagents/tracker.ts
@@ -435,12 +435,18 @@ function parseStrictSubagentTrackingState(raw: string): SubagentTrackingState |
return normalizeSubagentTrackingState(parsed);
}
-function readSubagentTrackingStateStrictSync(cwd: string): { ok: true; state: SubagentTrackingState } | { ok: false } {
+function readSubagentTrackingStateStrictSync(cwd: string):
+ | { ok: true; state: SubagentTrackingState; rawState: unknown }
+ | { ok: false } {
const path = subagentTrackingPath(cwd);
- if (!existsSync(path)) return { ok: true, state: createSubagentTrackingState() };
+ if (!existsSync(path)) {
+ const state = createSubagentTrackingState();
+ return { ok: true, state, rawState: state };
+ }
try {
- const state = parseStrictSubagentTrackingState(readFileSync(path, 'utf-8'));
- return state ? { ok: true, state } : { ok: false };
+ const raw = readFileSync(path, 'utf-8');
+ const state = parseStrictSubagentTrackingState(raw);
+ return state ? { ok: true, state, rawState: JSON.parse(raw) as unknown } : { ok: false };
} catch {
return { ok: false };
}
@@ -567,12 +573,16 @@ function isCrossProcessLockOlderThanLease(acquiredAtMs: number, nowMs: number):
return acquiredAtMs < nowMs - CROSS_PROCESS_LOCK_LEASE_MS;
}
-function isCrossProcessLockReclaimable(claim: CrossProcessLockClaim): boolean {
+function isCrossProcessLockReclaimable(
+ claim: CrossProcessLockClaim,
+ options: { preserveLiveLocalOwner?: boolean } = {},
+): boolean {
if (claim.host !== hostname()) return isCrossProcessLockOlderThanLease(claim.acquiredAtMs, Date.now());
if (isCrossProcessLockOwnerDead(claim.pid)) return true;
const currentPidStartId = readProcessStartIdentity(claim.pid);
if (claim.pidStartId && currentPidStartId) return currentPidStartId !== claim.pidStartId;
+ if (options.preserveLiveLocalOwner) return false;
return isCrossProcessLockOlderThanLease(claim.acquiredAtMs, Date.now());
}
@@ -624,9 +634,13 @@ function restoreQuarantinedCrossProcessLock(lockPath: string, quarantinedPath: s
removeCrossProcessLockFile(quarantinedPath);
}
-function recoverCrossProcessFileLock(lockPath: string, observed: CrossProcessLockState): boolean {
+function recoverCrossProcessFileLock(
+ lockPath: string,
+ observed: CrossProcessLockState,
+ options: { preserveLiveLocalOwner?: boolean } = {},
+): boolean {
if (observed.kind === 'missing') return true;
- if (observed.kind === 'claim' && !isCrossProcessLockReclaimable(observed.claim)) return false;
+ if (observed.kind === 'claim' && !isCrossProcessLockReclaimable(observed.claim, options)) return false;
const quarantinedPath = `${lockPath}.${Date.now()}.${randomUUID()}.quarantine`;
try {
@@ -644,7 +658,11 @@ function recoverCrossProcessFileLock(lockPath: string, observed: CrossProcessLoc
&& captured.kind === 'claim'
&& captured.claim.token === observed.claim.token;
const capturedRecoverable = captured.kind === 'malformed'
- || (capturedExpectedClaim && captured.kind === 'claim' && isCrossProcessLockReclaimable(captured.claim));
+ || (
+ capturedExpectedClaim
+ && captured.kind === 'claim'
+ && isCrossProcessLockReclaimable(captured.claim, options)
+ );
if (!capturedRecoverable) {
restoreQuarantinedCrossProcessLock(lockPath, quarantinedPath);
return true;
@@ -742,6 +760,47 @@ export function __setCrossProcessQuarantineBarrierForTest(
crossProcessQuarantineBarrier = barrier;
}
+export type CrossProcessFileLockHandle = {
+ assertOwnership(): void;
+ release(): void;
+};
+
+/** Acquire the shared recoverable lock for an async caller that owns its writes. */
+export async function acquireCrossProcessFileLock(
+ resourcePath: string,
+ options: { maxAttempts?: number; retryMs?: number; preserveLiveLocalOwner?: boolean } = {},
+): Promise<CrossProcessFileLockHandle> {
+ const lockPath = crossProcessLockPath(resourcePath);
+ const maxAttempts = typeof options.maxAttempts === 'number' && Number.isFinite(options.maxAttempts)
+ ? Math.max(1, Math.floor(options.maxAttempts))
+ : DEFAULT_CROSS_PROCESS_LOCK_MAX_ATTEMPTS;
+ const retryMs = typeof options.retryMs === 'number' && Number.isFinite(options.retryMs)
+ ? Math.max(1, Math.floor(options.retryMs))
+ : DEFAULT_CROSS_PROCESS_LOCK_RETRY_MS;
+ mkdirSync(dirname(lockPath), { recursive: true });
+ const token = randomUUID();
+ for (let attempt = 0; attempt < maxAttempts; attempt += 1) {
+ if (
+ tryAcquireCrossProcessFileLock(lockPath, token)
+ || (
+ recoverCrossProcessFileLock(lockPath, readCrossProcessLockState(lockPath), options)
+ && tryAcquireCrossProcessFileLock(lockPath, token)
+ )
+ ) {
+ return {
+ assertOwnership: () => assertCrossProcessFileLockOwnership(lockPath, token),
+ release: () => releaseCrossProcessFileLock(lockPath, token),
+ };
+ }
+ if (attempt < maxAttempts - 1) {
+ await new Promise((resolveDelay) => {
+ setTimeout(resolveDelay, Math.min(25, retryMs * 2 ** Math.min(attempt, 4)));
+ });
+ }
+ }
+ throw new Error(`Timed out waiting for cross-process lock at ${lockPath}`);
+}
+
export function withCrossProcessFileLockSync<T>(
resourcePath: string,
operation: (context: CrossProcessFileLockContext) => T,
@@ -1077,6 +1136,119 @@ export async function recordSubagentTurnForSession(cwd: string, input: RecordSub
return next;
});
}
+
+export function ensureExactDescriptiveLeaderForSession(cwd: string, input: {
+ sessionId: string;
+ rootThreadId: string;
+ timestamp?: string;
+}): SubagentTrackingState {
+ const sessionId = input.sessionId.trim();
+ const rootThreadId = input.rootThreadId.trim();
+ if (!sessionId || !rootThreadId) throw new Error('native_ultragoal_root_tracker_conflict');
+
+ return withCrossProcessFileLockSync(subagentTrackingPath(cwd), (context) => {
+ const strict = readSubagentTrackingStateStrictSync(cwd);
+ if (!strict.ok) throw new Error('Malformed subagent tracker authority state');
+ const current = strict.state;
+ const session = current.sessions[sessionId];
+ const root = session?.threads[rootThreadId];
+ const existingLeaderThreadId = session?.leader_thread_id;
+ const existingLeader = existingLeaderThreadId
+ ? session?.threads[existingLeaderThreadId]
+ : undefined;
+ const rawSession = (strict.rawState as { sessions?: Record<string, {
+ threads?: Record<string, Record<string, unknown>>;
+ }> })?.sessions?.[sessionId];
+ const rawExistingLeader = existingLeaderThreadId
+ ? rawSession?.threads?.[existingLeaderThreadId]
+ : undefined;
+ // Codex App can emit an auxiliary notify turn before the first real root
+ // turn. Ordinary notify tracking has no authority evidence, so that lone
+ // descriptive row must not outrank the exact canonical App session id
+ // established by the root transcript.
+ // Keep every wider or lifecycle-bearing conflict fail-closed.
+ const purelyDescriptiveLeaderKeys = new Set([
+ 'thread_id',
+ 'kind',
+ 'first_seen_at',
+ 'last_seen_at',
+ 'last_turn_id',
+ 'turn_count',
+ ]);
+ const replaceableAuxiliaryLeaderId = rootThreadId === sessionId
+ && existingLeaderThreadId
+ && existingLeaderThreadId !== rootThreadId
+ && existingLeader?.kind === 'leader'
+ && rawExistingLeader
+ && Object.keys(session?.threads ?? {}).length === 1
+ && Object.keys(rawExistingLeader).every((key) => purelyDescriptiveLeaderKeys.has(key))
+ ? existingLeaderThreadId
+ : undefined;
+ const conflictingAuthority = Object.values(session?.threads ?? {}).some((thread) => {
+ if (thread.thread_id === rootThreadId) {
+ return thread.provenance_kind === NATIVE_SUBAGENT_PROVENANCE
+ || thread.direct_child_parent_id !== undefined
+ || thread.direct_child_root_id !== undefined
+ || thread.reopen_authority_revoked !== undefined
+ || thread.reopen_authority_conflict_reason !== undefined
+ || thread.reopen_authority_conflict_at !== undefined;
+ }
+ if (thread.provenance_kind === NATIVE_SUBAGENT_PROVENANCE) {
+ return thread.direct_child_root_id !== rootThreadId
+ || thread.direct_child_parent_id !== rootThreadId;
+ }
+ return thread.direct_child_parent_id !== undefined
+ || thread.direct_child_root_id !== undefined
+ || thread.reopen_authority_revoked !== undefined
+ || thread.reopen_authority_conflict_reason !== undefined
+ || thread.reopen_authority_conflict_at !== undefined;
+ });
+ if (
+ hasLeaderSubagentCollision(current, rootThreadId)
+ || (session?.leader_thread_id
+ && session.leader_thread_id !== rootThreadId
+ && session.leader_thread_id !== replaceableAuxiliaryLeaderId)
+ || Object.values(session?.threads ?? {}).some((thread) => (
+ thread.kind === 'leader'
+ && thread.thread_id !== rootThreadId
+ && thread.thread_id !== replaceableAuxiliaryLeaderId
+ ))
+ || root?.kind === 'subagent'
+ || conflictingAuthority
+ ) throw new Error('native_ultragoal_root_tracker_conflict');
+
+ if (session?.leader_thread_id === rootThreadId && root?.kind === 'leader') return current;
+
+ const timestamp = input.timestamp ?? new Date().toISOString();
+ const nextRoot: TrackedSubagentThread = root ?? {
+ thread_id: rootThreadId,
+ kind: 'leader',
+ first_seen_at: timestamp,
+ last_seen_at: timestamp,
+ turn_count: 1,
+ };
+ const nextThreads = { ...(session?.threads ?? {}) };
+ if (replaceableAuxiliaryLeaderId) delete nextThreads[replaceableAuxiliaryLeaderId];
+ const next: SubagentTrackingState = {
+ ...current,
+ sessions: {
+ ...current.sessions,
+ [sessionId]: {
+ session_id: sessionId,
+ leader_thread_id: rootThreadId,
+ updated_at: session?.updated_at ?? timestamp,
+ threads: {
+ ...nextThreads,
+ [rootThreadId]: nextRoot,
+ },
+ },
+ },
+ };
+ context.assertOwnership();
+ writeSubagentTrackingStateSync(cwd, next, context.publish);
+ return next;
+ });
+}
export function recordNativeSubagentAuthorityObservation(
cwd: string,
observation: NativeSubagentAuthorityObservation,
@@ -1182,6 +1354,12 @@ function readAuthorityFence(cwd: string): { ok: boolean; ids: Set<string> } {
}
}
+/** True when durable authority state requires fail-closed denial for this child. */
+export function isNativeSubagentAuthorityFenced(cwd: string, childThreadId: string): boolean {
+ const fence = readAuthorityFence(cwd);
+ return !fence.ok || fence.ids.has(childThreadId.trim());
+}
+
/** Upper bound on fenced ids, so repeated failures cannot grow the fence without limit. */
export const AUTHORITY_FENCE_MAX_IDS = 512;
diff --git a/src/team/ultragoal-context.ts b/src/team/ultragoal-context.ts
index 9a30f426fc82ba3b7d6d0d430b8c976e472a5c56..46a925b229952d2f6a09c088f3729119af4feee6 100644
--- a/src/team/ultragoal-context.ts
+++ b/src/team/ultragoal-context.ts
@@ -219,8 +219,8 @@ export function buildUltragoalCheckpointGuidance(
context: UltragoalTeamContext,
): UltragoalCheckpointGuidance {
const goalId = context.activeGoalId;
- const intermediateStoryCommand = `omx ultragoal checkpoint --goal-id ${goalId} --status complete --evidence "<team evidence mentioning .omx/ultragoal and ${goalId}>" --codex-goal-json <fresh-active-get_goal-json-or-path>`;
- const finalStoryCommand = `omx ultragoal checkpoint --goal-id ${goalId} --status complete --evidence "<team evidence mentioning .omx/ultragoal and ${goalId}>" --codex-goal-json <fresh-complete-get_goal-json-or-path> --quality-gate-json <quality-gate-json-or-path>`;
+ const intermediateStoryCommand = `omx ultragoal checkpoint --goal-id ${goalId} --status complete --evidence "<team evidence mentioning .omx/ultragoal and ${goalId}>" --codex-goal-json <fresh-active-get_goal-json-or-path> --json`;
+ const finalStoryCommand = `omx ultragoal checkpoint --goal-id ${goalId} --status complete --evidence "<team evidence mentioning .omx/ultragoal and ${goalId}>" --codex-goal-json <fresh-complete-get_goal-json-or-path> --quality-gate-json <quality-gate-json-or-path> --json`;
return {
goal_id: goalId,
...(context.activeGoalTitle ? { goal_title: context.activeGoalTitle } : {}),
@@ -240,8 +240,8 @@ export function buildUltragoalCheckpointGuidance(
command_templates: {
intermediate_story: intermediateStoryCommand,
final_story: finalStoryCommand,
- per_story: `omx ultragoal checkpoint --goal-id ${goalId} --status complete --evidence "<team evidence mentioning .omx/ultragoal and ${goalId}>" --codex-goal-json <fresh-matching-get_goal-json-or-path>`,
- completed_wrong_legacy_goal_blocker: `omx ultragoal checkpoint --goal-id ${goalId} --status blocked --evidence "<completed legacy Codex goal blocks this ultragoal story>" --codex-goal-json <fresh-completed-wrong-get_goal-json-or-path>`,
+ per_story: `omx ultragoal checkpoint --goal-id ${goalId} --status complete --evidence "<team evidence mentioning .omx/ultragoal and ${goalId}>" --codex-goal-json <fresh-matching-get_goal-json-or-path> --json`,
+ completed_wrong_legacy_goal_blocker: `omx ultragoal checkpoint --goal-id ${goalId} --status blocked --evidence "<completed legacy Codex goal blocks this ultragoal story>" --codex-goal-json <fresh-completed-wrong-get_goal-json-or-path> --json`,
},
};
}
diff --git a/src/ultragoal/__tests__/artifacts.test.ts b/src/ultragoal/__tests__/artifacts.test.ts
index ecc90f7c65d03a915c98f96cc0ee2cb737e9e13b..20d210d9373ab240c19ae24ebb62038b6baac672 100644
--- a/src/ultragoal/__tests__/artifacts.test.ts
+++ b/src/ultragoal/__tests__/artifacts.test.ts
@@ -29,6 +29,7 @@ import {
type UltragoalSteeringProposal,
} from '../artifacts.js';
import { LEADER_CONDUCTOR_BLOCK, buildUnsupportedNativeSubagentGuidance } from '../../leader/contract.js';
+import { __setWritableStateScopeTestHooksForTests } from '../../mcp/state-paths.js';
import { steeringFixtures, type SteeringFixtureProposal } from './steering-fixtures.js';
const tmpdir = (): string => realpathSync(osTmpdir());
@@ -936,6 +937,81 @@ describe('ultragoal artifacts', () => {
});
});
+ it('reconciles a nested review-blocker resolver chain in one final-leaf checkpoint', async () => {
+ await withTempRepo(async (cwd) => {
+ await createUltragoalPlan(cwd, {
+ brief: 'brief',
+ goals: [{ title: 'Final', objective: 'Complete final milestone.' }],
+ });
+ const first = await startNextUltragoal(cwd);
+ const objective = first.plan.codexObjective!;
+
+ const firstBlocked = await recordFinalReviewBlockers(cwd, {
+ goalId: first.goal!.id,
+ title: 'Resolve first review blockers',
+ objective: 'Fix first review blockers and rerun final gates.',
+ evidence: 'first review BLOCK',
+ codexGoal: { goal: { objective, status: 'active' } },
+ });
+ const second = await startNextUltragoal(cwd);
+ const secondBlocked = await recordFinalReviewBlockers(cwd, {
+ goalId: second.goal!.id,
+ title: 'Resolve second review blockers',
+ objective: 'Fix second review blockers and rerun final gates.',
+ evidence: 'second review BLOCK',
+ codexGoal: { goal: { objective, status: 'active' } },
+ });
+ const leaf = await startNextUltragoal(cwd);
+ assert.equal(leaf.goal?.id, secondBlocked.addedGoal.id);
+ assert.equal(isFinalRunCompletionCandidate(leaf.plan, leaf.goal!), true);
+
+ const completed = await checkpointUltragoal(cwd, {
+ goalId: leaf.goal!.id,
+ status: 'complete',
+ evidence: `${leaf.goal!.id} fixed nested blockers; tests and reviews passed for .omx/ultragoal/goals.json`,
+ codexGoal: { goal: { objective, status: 'complete' } },
+ qualityGate: cleanQualityGate(),
+ });
+ const firstParent = completed.goals.find((goal) => goal.id === firstBlocked.blockedGoal.id);
+ const secondParent = completed.goals.find((goal) => goal.id === firstBlocked.addedGoal.id);
+ const summary = summarizeUltragoalPlan(completed);
+
+ assert.equal(summary.complete, 3);
+ assert.equal(summary.reviewBlocked, 0);
+ assert.equal(summary.aggregateComplete, true);
+ assert.equal(summary.artifactComplete, true);
+ assert.equal(firstParent?.reviewBlockerResolution?.status, 'complete');
+ assert.equal(secondParent?.reviewBlockerResolution?.status, 'complete');
+ assert.equal(firstParent?.reviewBlockerResolution?.resolverGoalId, secondParent?.id);
+ assert.equal(secondParent?.reviewBlockerResolution?.resolverGoalId, leaf.goal!.id);
+
+ const ledger = await readFile(join(cwd, '.omx/ultragoal/ledger.jsonl'), 'utf-8');
+ const entries = ledger.trim().split('\n').map((line) => JSON.parse(line) as {
+ event: string;
+ goalId?: string;
+ message?: string;
+ status?: string;
+ });
+ assert.deepEqual(
+ entries.slice(-4).map(({ event, goalId }) => ({ event, goalId })),
+ [
+ { event: 'goal_completed', goalId: leaf.goal!.id },
+ { event: 'goal_completed', goalId: secondParent!.id },
+ { event: 'goal_completed', goalId: firstParent!.id },
+ { event: 'aggregate_completed', goalId: leaf.goal!.id },
+ ],
+ );
+ assert.equal(entries.at(-3)?.status, 'complete');
+ assert.equal(entries.at(-2)?.status, 'complete');
+ assert.match(entries.at(-3)?.message ?? '', new RegExp(`resolved by ${leaf.goal!.id}`));
+ assert.match(entries.at(-2)?.message ?? '', new RegExp(`resolved by ${secondParent!.id}`));
+ assert.equal(entries.filter((entry) => entry.event === 'goal_completed' && entry.goalId === leaf.goal!.id).length, 1);
+ assert.equal(entries.filter((entry) => entry.event === 'goal_completed' && entry.goalId === secondParent!.id).length, 1);
+ assert.equal(entries.filter((entry) => entry.event === 'goal_completed' && entry.goalId === firstParent!.id).length, 1);
+ assert.equal(entries.filter((entry) => entry.event === 'aggregate_completed').length, 1);
+ });
+ });
+
it('does not terminalize through a one-way designated resolver pointer', async () => {
await withTempRepo(async (cwd) => {
await createUltragoalPlan(cwd, {
@@ -3213,6 +3289,8 @@ describe('ultragoal artifacts', () => {
it('allows durable Ultragoal mutations for an exact-match identity-indeterminate pointer and rejects mismatches', async () => {
await withTempRepo(async (cwd) => {
const previousEnv = process.env.OMX_SESSION_ID;
+ const previousCodexThreadId = process.env.CODEX_THREAD_ID;
+ const previousBackend = process.env.OMX_NATIVE_ULTRAGOAL_BACKEND;
const sessionId = 'sess-indeterminate';
const stateDir = join(cwd, '.omx', 'state');
try {
@@ -3225,6 +3303,8 @@ describe('ultragoal artifacts', () => {
}));
__setSessionPointerTransactionDependenciesForTests({ probePid: () => 'indeterminate' });
process.env.OMX_SESSION_ID = sessionId;
+ delete process.env.CODEX_THREAD_ID;
+ process.env.OMX_NATIVE_ULTRAGOAL_BACKEND = 'off';
const plan = await createUltragoalPlan(cwd, { brief: '- Ship the indeterminate recovery' });
assert.equal(plan.goals.length, 1);
@@ -3254,6 +3334,249 @@ describe('ultragoal artifacts', () => {
} finally {
if (typeof previousEnv === 'string') process.env.OMX_SESSION_ID = previousEnv;
else delete process.env.OMX_SESSION_ID;
+ if (typeof previousCodexThreadId === 'string') process.env.CODEX_THREAD_ID = previousCodexThreadId;
+ else delete process.env.CODEX_THREAD_ID;
+ if (typeof previousBackend === 'string') process.env.OMX_NATIVE_ULTRAGOAL_BACKEND = previousBackend;
+ else delete process.env.OMX_NATIVE_ULTRAGOAL_BACKEND;
+ __resetSessionPointerTransactionDependenciesForTests();
+ }
+ });
+ });
+
+ it('opts App-native recovery into local-experimental Ultragoal artifacts only', async () => {
+ await withTempRepo(async (cwd) => {
+ const previousBackend = process.env.OMX_NATIVE_ULTRAGOAL_BACKEND;
+ const previousCodexThreadId = process.env.CODEX_THREAD_ID;
+ const previousOmxSessionId = process.env.OMX_SESSION_ID;
+ const sessionId = '019faf7e-0010-7000-8000-000000000010';
+ const stateDir = join(cwd, '.omx', 'state');
+ try {
+ await mkdir(stateDir, { recursive: true });
+ await writeFile(join(stateDir, 'session.json'), JSON.stringify({
+ session_id: sessionId,
+ native_session_id: sessionId,
+ cwd,
+ state_root: stateDir,
+ pid: 8388607,
+ }));
+ __setSessionPointerTransactionDependenciesForTests({ probePid: () => 'indeterminate' });
+ delete process.env.OMX_SESSION_ID;
+ process.env.CODEX_THREAD_ID = sessionId;
+ process.env.OMX_NATIVE_ULTRAGOAL_BACKEND = 'local-experimental';
+
+ const plan = await createUltragoalPlan(cwd, { brief: '- Ship native App recovery' });
+ assert.equal(plan.goals.length, 1);
+ assert.equal(existsSync(join(cwd, '.omx', 'ultragoal', 'goals.json')), true);
+ assert.deepEqual(await assertUltragoalWritableLifecycleAuthority(cwd), {
+ kind: 'resolved',
+ source: 'session',
+ sessionId,
+ stateDir: join(stateDir, 'sessions', sessionId),
+ });
+
+ process.env.OMX_NATIVE_ULTRAGOAL_BACKEND = 'host';
+ await assert.rejects(
+ () => addUltragoalGoal(cwd, { title: 'Must not persist', objective: 'Host backend cannot use local recovery.' }),
+ /writable lifecycle authority/,
+ );
+ } finally {
+ if (typeof previousBackend === 'string') process.env.OMX_NATIVE_ULTRAGOAL_BACKEND = previousBackend;
+ else delete process.env.OMX_NATIVE_ULTRAGOAL_BACKEND;
+ if (typeof previousCodexThreadId === 'string') process.env.CODEX_THREAD_ID = previousCodexThreadId;
+ else delete process.env.CODEX_THREAD_ID;
+ if (typeof previousOmxSessionId === 'string') process.env.OMX_SESSION_ID = previousOmxSessionId;
+ else delete process.env.OMX_SESSION_ID;
+ __resetSessionPointerTransactionDependenciesForTests();
+ }
+ });
+ });
+
+ it('revalidates the App-native pointer before the first durable artifact commit', async () => {
+ await withTempRepo(async (cwd) => {
+ const previousBackend = process.env.OMX_NATIVE_ULTRAGOAL_BACKEND;
+ const previousCodexThreadId = process.env.CODEX_THREAD_ID;
+ const sessionId = '019faf7e-0011-7000-8000-000000000011';
+ const stateDir = join(cwd, '.omx', 'state');
+ const sessionPath = join(stateDir, 'session.json');
+ let recoveryReadCount = 0;
+ try {
+ await mkdir(stateDir, { recursive: true });
+ await writeFile(sessionPath, JSON.stringify({
+ session_id: sessionId,
+ native_session_id: sessionId,
+ cwd,
+ state_root: stateDir,
+ pid: 8388607,
+ }));
+ __setSessionPointerTransactionDependenciesForTests({ probePid: () => 'indeterminate' });
+ process.env.CODEX_THREAD_ID = sessionId;
+ process.env.OMX_NATIVE_ULTRAGOAL_BACKEND = 'local-experimental';
+ __setWritableStateScopeTestHooksForTests({
+ beforeRecoveryReread: async () => {
+ recoveryReadCount += 1;
+ if (recoveryReadCount === 3) {
+ await writeFile(sessionPath, JSON.stringify({
+ session_id: sessionId,
+ native_session_id: sessionId,
+ cwd,
+ state_root: stateDir,
+ pid: 9999999,
+ }));
+ }
+ },
+ });
+
+ await assert.rejects(
+ () => createUltragoalPlan(cwd, { brief: '- Must not commit after pointer drift' }),
+ /writable lifecycle authority/,
+ );
+ assert.equal(existsSync(join(cwd, '.omx', 'ultragoal', 'brief.md')), false);
+ assert.equal(existsSync(join(cwd, '.omx', 'ultragoal', 'goals.json')), false);
+ } finally {
+ __setWritableStateScopeTestHooksForTests({});
+ if (typeof previousBackend === 'string') process.env.OMX_NATIVE_ULTRAGOAL_BACKEND = previousBackend;
+ else delete process.env.OMX_NATIVE_ULTRAGOAL_BACKEND;
+ if (typeof previousCodexThreadId === 'string') process.env.CODEX_THREAD_ID = previousCodexThreadId;
+ else delete process.env.CODEX_THREAD_ID;
+ __resetSessionPointerTransactionDependenciesForTests();
+ }
+ });
+ });
+
+ it('fails annotate_ledger closed when App-native authority changes immediately before plan commit', async () => {
+ await withTempRepo(async (cwd) => {
+ const previousBackend = process.env.OMX_NATIVE_ULTRAGOAL_BACKEND;
+ const previousCodexThreadId = process.env.CODEX_THREAD_ID;
+ const previousOmxSessionId = process.env.OMX_SESSION_ID;
+ const sessionId = '019faf7e-0012-7000-8000-000000000012';
+ const stateDir = join(cwd, '.omx', 'state');
+ const sessionPath = join(stateDir, 'session.json');
+ const goalsPath = join(cwd, '.omx', 'ultragoal', 'goals.json');
+ const ledgerPath = join(cwd, '.omx', 'ultragoal', 'ledger.jsonl');
+ let recoveryReadCount = 0;
+ try {
+ await mkdir(stateDir, { recursive: true });
+ await writeFile(sessionPath, JSON.stringify({
+ session_id: sessionId,
+ native_session_id: sessionId,
+ cwd,
+ state_root: stateDir,
+ pid: 8388607,
+ }));
+ __setSessionPointerTransactionDependenciesForTests({ probePid: () => 'indeterminate' });
+ delete process.env.OMX_SESSION_ID;
+ process.env.CODEX_THREAD_ID = sessionId;
+ process.env.OMX_NATIVE_ULTRAGOAL_BACKEND = 'local-experimental';
+
+ await createUltragoalPlan(cwd, { brief: '- Preserve commit-time authority' });
+ const beforeGoals = await readFile(goalsPath, 'utf-8');
+ const beforeLedger = await readFile(ledgerPath, 'utf-8');
+ __setWritableStateScopeTestHooksForTests({
+ beforeRecoveryReread: async () => {
+ recoveryReadCount += 1;
+ // annotate_ledger has no plan mutation: before-lock, after-lock,
+ // pre-mkdir, then the ledger's final pre-append authority check.
+ if (recoveryReadCount === 4) {
+ await writeFile(sessionPath, JSON.stringify({
+ session_id: sessionId,
+ native_session_id: sessionId,
+ cwd,
+ state_root: stateDir,
+ pid: 9999999,
+ }));
+ }
+ },
+ });
+
+ await assert.rejects(
+ () => steerUltragoal(cwd, {
+ kind: 'annotate_ledger',
+ source: 'cli',
+ evidence: 'commit-time race evidence',
+ rationale: 'record evidence without changing the goal graph',
+ }),
+ /writable lifecycle authority/,
+ );
+ assert.equal(await readFile(goalsPath, 'utf-8'), beforeGoals);
+ assert.equal(await readFile(ledgerPath, 'utf-8'), beforeLedger);
+ } finally {
+ __setWritableStateScopeTestHooksForTests({});
+ if (typeof previousBackend === 'string') process.env.OMX_NATIVE_ULTRAGOAL_BACKEND = previousBackend;
+ else delete process.env.OMX_NATIVE_ULTRAGOAL_BACKEND;
+ if (typeof previousCodexThreadId === 'string') process.env.CODEX_THREAD_ID = previousCodexThreadId;
+ else delete process.env.CODEX_THREAD_ID;
+ if (typeof previousOmxSessionId === 'string') process.env.OMX_SESSION_ID = previousOmxSessionId;
+ else delete process.env.OMX_SESSION_ID;
+ __resetSessionPointerTransactionDependenciesForTests();
+ }
+ });
+ });
+
+ it('fails a final checkpoint closed when App-native authority changes immediately before plan commit', async () => {
+ await withTempRepo(async (cwd) => {
+ const previousBackend = process.env.OMX_NATIVE_ULTRAGOAL_BACKEND;
+ const previousCodexThreadId = process.env.CODEX_THREAD_ID;
+ const previousOmxSessionId = process.env.OMX_SESSION_ID;
+ const sessionId = '019faf7e-0013-7000-8000-000000000013';
+ const stateDir = join(cwd, '.omx', 'state');
+ const sessionPath = join(stateDir, 'session.json');
+ const goalsPath = join(cwd, '.omx', 'ultragoal', 'goals.json');
+ const ledgerPath = join(cwd, '.omx', 'ultragoal', 'ledger.jsonl');
+ let recoveryReadCount = 0;
+ try {
+ await mkdir(stateDir, { recursive: true });
+ await writeFile(sessionPath, JSON.stringify({
+ session_id: sessionId,
+ native_session_id: sessionId,
+ cwd,
+ state_root: stateDir,
+ pid: 8388607,
+ }));
+ __setSessionPointerTransactionDependenciesForTests({ probePid: () => 'indeterminate' });
+ delete process.env.OMX_SESSION_ID;
+ process.env.CODEX_THREAD_ID = sessionId;
+ process.env.OMX_NATIVE_ULTRAGOAL_BACKEND = 'local-experimental';
+
+ const created = await createUltragoalPlan(cwd, { brief: '- Preserve final checkpoint authority' });
+ const started = await startNextUltragoal(cwd);
+ const beforeGoals = await readFile(goalsPath, 'utf-8');
+ const beforeLedger = await readFile(ledgerPath, 'utf-8');
+ __setWritableStateScopeTestHooksForTests({
+ beforeRecoveryReread: async () => {
+ recoveryReadCount += 1;
+ // Revoke the selected pointer at writePlan's final pre-rename check.
+ if (recoveryReadCount === 5) {
+ await writeFile(sessionPath, JSON.stringify({
+ session_id: sessionId,
+ native_session_id: sessionId,
+ cwd,
+ state_root: stateDir,
+ pid: 9999999,
+ }));
+ }
+ },
+ });
+
+ await assert.rejects(
+ () => checkpointUltragoal(cwd, {
+ goalId: started.goal!.id,
+ status: 'complete',
+ evidence: 'implementation and verification complete for the active ultragoal',
+ codexGoal: { goal: { objective: created.codexObjective, status: 'complete' } },
+ qualityGate: cleanQualityGate(),
+ }),
+ /writable lifecycle authority/,
+ );
+ assert.equal(await readFile(goalsPath, 'utf-8'), beforeGoals);
+ assert.equal(await readFile(ledgerPath, 'utf-8'), beforeLedger);
+ } finally {
+ __setWritableStateScopeTestHooksForTests({});
+ if (typeof previousBackend === 'string') process.env.OMX_NATIVE_ULTRAGOAL_BACKEND = previousBackend;
+ else delete process.env.OMX_NATIVE_ULTRAGOAL_BACKEND;
+ if (typeof previousCodexThreadId === 'string') process.env.CODEX_THREAD_ID = previousCodexThreadId;
+ else delete process.env.CODEX_THREAD_ID;
+ if (typeof previousOmxSessionId === 'string') process.env.OMX_SESSION_ID = previousOmxSessionId;
+ else delete process.env.OMX_SESSION_ID;
__resetSessionPointerTransactionDependenciesForTests();
}
});
diff --git a/src/ultragoal/__tests__/docs-contract.test.ts b/src/ultragoal/__tests__/docs-contract.test.ts
index 33896ebc6f3b5f90680ce089676dfff6b295d660..3244660f04faecba6d40363b6250089842aaddb4 100644
--- a/src/ultragoal/__tests__/docs-contract.test.ts
+++ b/src/ultragoal/__tests__/docs-contract.test.ts
@@ -54,6 +54,22 @@ describe('ultragoal docs contract', () => {
assert.match(doc, /matching native Codex `blocked`|matching native Codex blocked|truthfully `blocked`/i);
});
+ it('keeps every model-facing checkpoint command JSON-safe for Conductor', () => {
+ const docs = [
+ loadDoc('docs/ultragoal.md'),
+ loadDoc('skills/ultragoal/SKILL.md'),
+ loadDoc('plugins/oh-my-codex/skills/ultragoal/SKILL.md'),
+ loadDoc('skills/team/SKILL.md'),
+ loadDoc('plugins/oh-my-codex/skills/team/SKILL.md'),
+ ];
+
+ for (const doc of docs) {
+ const commands = doc.split('\n').filter((line) => line.includes('omx ultragoal checkpoint --goal-id'));
+ assert.ok(commands.length > 0);
+ for (const command of commands) assert.match(command, /--json(?:\s|`|$)/, command);
+ }
+ });
+
it('documents the mandatory final cleanup and review gate', () => {
const docs = [
loadDoc('docs/ultragoal.md'),
diff --git a/src/ultragoal/__tests__/native-bootstrap.test.ts b/src/ultragoal/__tests__/native-bootstrap.test.ts
new file mode 100644
index 0000000000000000000000000000000000000000..233edbc528ffdbe176bb0b526194e86c925dd0ea
--- /dev/null
+++ b/src/ultragoal/__tests__/native-bootstrap.test.ts
@@ -0,0 +1,755 @@
+import assert from 'node:assert/strict';
+import { chmod, link, mkdir, mkdtemp, readFile, rm, symlink, writeFile } from 'node:fs/promises';
+import { tmpdir } from 'node:os';
+import { dirname, join } from 'node:path';
+import { describe, it } from 'node:test';
+import {
+ beginNativeUltragoalBootstrap,
+ DOCUMENTED_HOST_RECEIPT_UNAVAILABLE,
+ findReadyLocalNativeExecutorAssignment,
+ issueLocalNativeExecutorAssignment,
+ markNativeUltragoalBootstrapActive,
+ nativeExecutorAssignmentPath,
+ prepareNativeUltragoalBootstrapActivation,
+ readNativeUltragoalBootstrap,
+ reconcileLocalNativeExecutorAssignments,
+ resolveLocalNativeExecutorChildReceipt,
+ revokeLocalNativeExecutorAssignment,
+ unavailableHostNativeExecutorReceiptVerifier,
+ validateLocalNativeExecutorIdentity,
+} from '../native-bootstrap.js';
+
+async function writeJson(path: string, value: unknown): Promise<void> {
+ await mkdir(dirname(path), { recursive: true });
+ await writeFile(path, `${JSON.stringify(value, null, 2)}\n`);
+}
+
+async function fixture() {
+ const cwd = await mkdtemp(join(tmpdir(), 'omx-native-bootstrap-'));
+ const stateDir = join(cwd, '.omx', 'state');
+ const sessionId = 'session-native-bootstrap';
+ const rootThreadId = 'root-native-bootstrap';
+ const childAgentId = 'child-native-bootstrap';
+ const now = new Date('2026-07-28T12:00:00.000Z');
+ await writeJson(join(stateDir, 'subagent-tracking.json'), {
+ schemaVersion: 1,
+ sessions: {
+ [sessionId]: {
+ session_id: sessionId,
+ leader_thread_id: rootThreadId,
+ updated_at: now.toISOString(),
+ threads: {
+ [rootThreadId]: {
+ thread_id: rootThreadId,
+ kind: 'leader',
+ first_seen_at: now.toISOString(),
+ last_seen_at: now.toISOString(),
+ turn_count: 1,
+ },
+ [childAgentId]: {
+ thread_id: childAgentId,
+ kind: 'subagent',
+ mode: 'executor',
+ status: 'available',
+ provenance_kind: 'native_subagent',
+ direct_child_parent_id: rootThreadId,
+ direct_child_root_id: rootThreadId,
+ first_seen_at: now.toISOString(),
+ last_seen_at: now.toISOString(),
+ turn_count: 1,
+ },
+ },
+ },
+ },
+ });
+ return { cwd, stateDir, sessionId, rootThreadId, childAgentId, now };
+}
+
+async function writeChildRollout(input: {
+ codexHome: string;
+ childId: string;
+ timestamp: string;
+ cwd: string;
+ sessionId: string;
+ rootThreadId: string;
+ agentPath: string;
+ depth?: number;
+ role?: string;
+ directory?: string;
+}): Promise<string> {
+ const path = join(
+ input.codexHome,
+ 'sessions',
+ input.directory ?? '2026/07/29',
+ `rollout-test-${input.childId}.jsonl`,
+ );
+ await mkdir(dirname(path), { recursive: true });
+ await writeFile(path, `${JSON.stringify({
+ timestamp: input.timestamp,
+ type: 'session_meta',
+ payload: {
+ id: input.childId,
+ session_id: input.sessionId,
+ cwd: input.cwd,
+ source: {
+ subagent: {
+ thread_spawn: {
+ parent_thread_id: input.rootThreadId,
+ depth: input.depth ?? 1,
+ agent_path: input.agentPath,
+ agent_role: input.role ?? 'executor',
+ },
+ },
+ },
+ },
+ })}\n`);
+ return path;
+}
+
+describe('native Ultragoal bootstrap', () => {
+ it('seeds only the exact descriptive root tracker and fails closed on leader contradiction', async () => {
+ const cwd = await mkdtemp(join(tmpdir(), 'omx-native-bootstrap-root-seed-'));
+ const stateDir = join(cwd, '.omx', 'state');
+ const sessionId = 'session-root-seed';
+ const rootThreadId = 'root-thread-seed';
+ try {
+ await beginNativeUltragoalBootstrap({
+ cwd,
+ stateDir,
+ sessionId,
+ rootThreadId,
+ backend: 'local-experimental',
+ ttlSeconds: 300,
+ });
+ const tracking = JSON.parse(await readFile(join(stateDir, 'subagent-tracking.json'), 'utf8')) as {
+ sessions: Record<string, {
+ leader_thread_id?: string;
+ threads: Record<string, Record<string, unknown>>;
+ }>;
+ };
+ const root = tracking.sessions[sessionId]?.threads[rootThreadId];
+ assert.equal(tracking.sessions[sessionId]?.leader_thread_id, rootThreadId);
+ assert.equal(root?.kind, 'leader');
+ assert.equal(root?.provenance_kind, undefined);
+ assert.equal(root?.direct_child_parent_id, undefined);
+ assert.equal(root?.direct_child_root_id, undefined);
+
+ const conflictingSessionId = 'session-root-conflict';
+ const conflictTimestamp = new Date().toISOString();
+ await writeJson(join(stateDir, 'subagent-tracking.json'), {
+ schemaVersion: 1,
+ sessions: {
+ [conflictingSessionId]: {
+ session_id: conflictingSessionId,
+ leader_thread_id: 'foreign-root',
+ updated_at: conflictTimestamp,
+ threads: {
+ 'foreign-root': {
+ thread_id: 'foreign-root',
+ kind: 'leader',
+ first_seen_at: conflictTimestamp,
+ last_seen_at: conflictTimestamp,
+ turn_count: 1,
+ },
+ },
+ },
+ },
+ });
+ await assert.rejects(beginNativeUltragoalBootstrap({
+ cwd,
+ stateDir,
+ sessionId: conflictingSessionId,
+ rootThreadId,
+ backend: 'local-experimental',
+ ttlSeconds: 300,
+ }), /native_ultragoal_root_tracker_conflict/);
+ assert.equal(await readNativeUltragoalBootstrap(stateDir, conflictingSessionId), null);
+ const afterConflict = JSON.parse(await readFile(join(stateDir, 'subagent-tracking.json'), 'utf8')) as {
+ sessions: Record<string, { threads: Record<string, unknown> }>;
+ };
+ assert.equal(afterConflict.sessions[conflictingSessionId]?.threads[rootThreadId], undefined);
+ } finally {
+ await rm(cwd, { recursive: true, force: true });
+ }
+ });
+
+ it('resolves a safe unique child rollout from an exact agent path without granting tracker authority', async () => {
+ const cwd = await mkdtemp(join(tmpdir(), 'omx-native-child-path-'));
+ const codexHome = join(cwd, 'codex-home');
+ const previousCodexHome = process.env.CODEX_HOME;
+ process.env.CODEX_HOME = codexHome;
+ const childId = '019faf7d-ffbb-70d2-b58f-9bb83e752007';
+ const sessionId = 'session-child-path';
+ const rootThreadId = 'root-child-path';
+ const agentPath = '/root/ultragoal_native_executor';
+ const timestamp = '2026-07-29T20:00:00.000Z';
+ try {
+ await writeChildRollout({
+ codexHome,
+ childId,
+ timestamp,
+ cwd,
+ sessionId,
+ rootThreadId,
+ agentPath,
+ });
+ assert.deepEqual(await resolveLocalNativeExecutorChildReceipt({
+ cwd,
+ sessionId,
+ rootThreadId,
+ agentPath,
+ receiptNotBefore: '2026-07-29T19:59:00.000Z',
+ receiptNotAfter: '2026-07-29T20:01:00.000Z',
+ now: new Date(timestamp),
+ }), { ok: true, childAgentId: childId });
+ await assert.rejects(readFile(join(cwd, '.omx', 'state', 'subagent-tracking.json')), /ENOENT/);
+ } finally {
+ if (previousCodexHome === undefined) delete process.env.CODEX_HOME;
+ else process.env.CODEX_HOME = previousCodexHome;
+ await rm(cwd, { recursive: true, force: true });
+ }
+ });
+
+ it('rejects missing, ambiguous, stale, foreign, malformed, writable, and linked child-path receipts', async () => {
+ const cwd = await mkdtemp(join(tmpdir(), 'omx-native-child-path-deny-'));
+ const codexHome = join(cwd, 'codex-home');
+ const previousCodexHome = process.env.CODEX_HOME;
+ process.env.CODEX_HOME = codexHome;
+ const sessionId = 'session-child-path-deny';
+ const rootThreadId = 'root-child-path-deny';
+ const timestamp = '2026-07-29T20:00:00.000Z';
+ const window = {
+ receiptNotBefore: '2026-07-29T19:59:00.000Z',
+ receiptNotAfter: '2026-07-29T20:01:00.000Z',
+ now: new Date(timestamp),
+ };
+ const resolvePath = (agentPath: string) => resolveLocalNativeExecutorChildReceipt({
+ cwd, sessionId, rootThreadId, agentPath, ...window,
+ });
+ try {
+ await mkdir(join(codexHome, 'sessions'), { recursive: true });
+ assert.deepEqual(await resolvePath('/root/missing'), {
+ ok: false, reason: 'child_transcript_receipt_missing',
+ });
+
+ const unreadableDirectory = join(codexHome, 'sessions', 'unreadable');
+ await mkdir(unreadableDirectory, { recursive: true });
+ await chmod(unreadableDirectory, 0o000);
+ assert.deepEqual(await resolvePath('/root/missing'), {
+ ok: false, reason: 'child_transcript_receipt_scan_incomplete',
+ });
+ await beginNativeUltragoalBootstrap({
+ cwd,
+ stateDir: join(cwd, '.omx', 'state'),
+ sessionId,
+ rootThreadId,
+ backend: 'local-experimental',
+ ttlSeconds: 300,
+ now: new Date(timestamp),
+ });
+ assert.deepEqual(await validateLocalNativeExecutorIdentity({
+ cwd,
+ sessionId,
+ rootThreadId,
+ childAgentId: '019faf7d-0099-7000-8000-000000000099',
+ receiptNotBefore: window.receiptNotBefore,
+ receiptNotAfter: window.receiptNotAfter,
+ }), { ok: false, reason: 'child_transcript_receipt_scan_incomplete' });
+ await chmod(unreadableDirectory, 0o700);
+
+ const invalidCases = [
+ { name: 'stale', childId: '019faf7d-0001-7000-8000-000000000001', timestamp: '2026-07-29T19:58:59.000Z' },
+ { name: 'parent', childId: '019faf7d-0002-7000-8000-000000000002', rootThreadId: 'foreign-root' },
+ { name: 'depth', childId: '019faf7d-0003-7000-8000-000000000003', depth: 2 },
+ { name: 'role', childId: '019faf7d-0004-7000-8000-000000000004', role: 'reviewer' },
+ { name: 'cwd', childId: '019faf7d-0005-7000-8000-000000000005', cwd: codexHome },
+ { name: 'session', childId: '019faf7d-0006-7000-8000-000000000006', sessionId: 'foreign-session' },
+ { name: 'id', childId: 'not-a-canonical-uuid' },
+ ];
+ for (const invalid of invalidCases) {
+ const agentPath = `/root/deny_${invalid.name}`;
+ await writeChildRollout({
+ codexHome,
+ childId: invalid.childId,
+ timestamp: invalid.timestamp ?? timestamp,
+ cwd: invalid.cwd ?? cwd,
+ sessionId: invalid.sessionId ?? sessionId,
+ rootThreadId: invalid.rootThreadId ?? rootThreadId,
+ agentPath,
+ depth: invalid.depth,
+ role: invalid.role,
+ directory: invalid.name,
+ });
+ assert.deepEqual(await resolvePath(agentPath), {
+ ok: false, reason: 'child_transcript_receipt_missing',
+ }, invalid.name);
+ }
+
+ const writablePath = await writeChildRollout({
+ codexHome,
+ childId: '019faf7d-0007-7000-8000-000000000007',
+ timestamp,
+ cwd,
+ sessionId,
+ rootThreadId,
+ agentPath: '/root/deny_writable',
+ directory: 'writable',
+ });
+ await chmod(writablePath, 0o666);
+ assert.deepEqual(await resolvePath('/root/deny_writable'), {
+ ok: false, reason: 'child_transcript_receipt_missing',
+ });
+
+ const linkedSource = await writeChildRollout({
+ codexHome,
+ childId: '019faf7d-0008-7000-8000-000000000008',
+ timestamp,
+ cwd,
+ sessionId,
+ rootThreadId,
+ agentPath: '/root/deny_linked',
+ directory: 'linked',
+ });
+ await link(linkedSource, `${linkedSource}.copy`);
+ assert.deepEqual(await resolvePath('/root/deny_linked'), {
+ ok: false, reason: 'child_transcript_receipt_missing',
+ });
+
+ const symlinkTarget = await writeChildRollout({
+ codexHome,
+ childId: '019faf7d-0009-7000-8000-000000000009',
+ timestamp,
+ cwd,
+ sessionId,
+ rootThreadId,
+ agentPath: '/root/deny_symlink',
+ directory: 'outside-live-tree',
+ });
+ const symlinkPath = join(codexHome, 'sessions', `rollout-link-019faf7d-0009-7000-8000-000000000009.jsonl`);
+ await symlink(symlinkTarget, symlinkPath);
+ await rm(symlinkTarget);
+ assert.deepEqual(await resolvePath('/root/deny_symlink'), {
+ ok: false, reason: 'child_transcript_receipt_missing',
+ });
+
+ for (const [index, childId] of [
+ '019faf7d-0010-7000-8000-000000000010',
+ '019faf7d-0011-7000-8000-000000000011',
+ ].entries()) {
+ await writeChildRollout({
+ codexHome,
+ childId,
+ timestamp,
+ cwd,
+ sessionId,
+ rootThreadId,
+ agentPath: '/root/deny_ambiguous',
+ directory: `ambiguous-${index}`,
+ });
+ }
+ assert.deepEqual(await resolvePath('/root/deny_ambiguous'), {
+ ok: false, reason: 'child_transcript_receipt_ambiguous',
+ });
+ } finally {
+ if (previousCodexHome === undefined) delete process.env.CODEX_HOME;
+ else process.env.CODEX_HOME = previousCodexHome;
+ await rm(cwd, { recursive: true, force: true });
+ }
+ });
+ it('keeps the host backend explicitly unavailable without a documented verifier', async () => {
+ const f = await fixture();
+ try {
+ const state = await beginNativeUltragoalBootstrap({
+ cwd: f.cwd,
+ stateDir: f.stateDir,
+ sessionId: f.sessionId,
+ rootThreadId: f.rootThreadId,
+ backend: 'host',
+ ttlSeconds: 300,
+ now: f.now,
+ });
+ assert.equal(state.status, 'host-receipt-unavailable');
+ assert.equal(state.reason, DOCUMENTED_HOST_RECEIPT_UNAVAILABLE);
+ assert.deepEqual(await unavailableHostNativeExecutorReceiptVerifier.verifyActivationReceipt({
+ cwd: f.cwd,
+ sessionId: f.sessionId,
+ rootThreadId: f.rootThreadId,
+ }), { ok: false, reason: DOCUMENTED_HOST_RECEIPT_UNAVAILABLE });
+ } finally {
+ await rm(f.cwd, { recursive: true, force: true });
+ }
+ });
+
+ it('orders local bootstrap before assignment and activation', async () => {
+ const f = await fixture();
+ try {
+ const bootstrap = await beginNativeUltragoalBootstrap({
+ cwd: f.cwd,
+ stateDir: f.stateDir,
+ sessionId: f.sessionId,
+ rootThreadId: f.rootThreadId,
+ backend: 'local-experimental',
+ ttlSeconds: 900,
+ now: f.now,
+ });
+ assert.equal(bootstrap.status, 'awaiting-executor');
+ assert.equal(await findReadyLocalNativeExecutorAssignment({
+ cwd: f.cwd,
+ stateDir: f.stateDir,
+ sessionId: f.sessionId,
+ rootThreadId: f.rootThreadId,
+ now: f.now,
+ }), null);
+
+ await assert.rejects(
+ issueLocalNativeExecutorAssignment({
+ cwd: f.cwd,
+ stateDir: f.stateDir,
+ sessionId: f.sessionId,
+ rootThreadId: f.rootThreadId,
+ childAgentId: f.childAgentId,
+ expectedGeneration: bootstrap.generation,
+ pathPrefixes: ['$UNRESOLVED/*'],
+ ttlSeconds: 300,
+ now: f.now,
+ }),
+ /invalid_native_assignment_path_prefixes/,
+ );
+
+ const assignment = await issueLocalNativeExecutorAssignment({
+ cwd: f.cwd,
+ stateDir: f.stateDir,
+ sessionId: f.sessionId,
+ rootThreadId: f.rootThreadId,
+ childAgentId: f.childAgentId,
+ expectedGeneration: bootstrap.generation,
+ pathPrefixes: ['src', 'tests'],
+ ttlSeconds: 300,
+ now: f.now,
+ });
+ assert.equal(assignment.bootstrap_generation, bootstrap.generation);
+ assert.equal((await readNativeUltragoalBootstrap(f.stateDir, f.sessionId))?.status, 'ready');
+ assert.equal((await findReadyLocalNativeExecutorAssignment({
+ cwd: f.cwd,
+ stateDir: f.stateDir,
+ sessionId: f.sessionId,
+ rootThreadId: f.rootThreadId,
+ now: f.now,
+ }))?.child_agent_id, f.childAgentId);
+
+ const prepared = await prepareNativeUltragoalBootstrapActivation({
+ cwd: f.cwd,
+ stateDir: f.stateDir,
+ sessionId: f.sessionId,
+ childAgentId: f.childAgentId,
+ now: f.now,
+ });
+ assert.equal(prepared.ok, true);
+ assert.equal((await readNativeUltragoalBootstrap(f.stateDir, f.sessionId))?.status, 'activating');
+ const activation = await markNativeUltragoalBootstrapActive({
+ cwd: f.cwd,
+ stateDir: f.stateDir,
+ sessionId: f.sessionId,
+ childAgentId: f.childAgentId,
+ now: f.now,
+ });
+ assert.equal(activation.ok, true);
+ assert.equal((await readNativeUltragoalBootstrap(f.stateDir, f.sessionId))?.status, 'active');
+ assert.equal((await markNativeUltragoalBootstrapActive({
+ cwd: f.cwd,
+ stateDir: f.stateDir,
+ sessionId: f.sessionId,
+ childAgentId: f.childAgentId,
+ now: f.now,
+ })).ok, true);
+
+ const renewed = await issueLocalNativeExecutorAssignment({
+ cwd: f.cwd,
+ stateDir: f.stateDir,
+ sessionId: f.sessionId,
+ rootThreadId: f.rootThreadId,
+ childAgentId: f.childAgentId,
+ expectedGeneration: bootstrap.generation,
+ pathPrefixes: ['src'],
+ ttlSeconds: 600,
+ now: new Date(f.now.getTime() + 60_000),
+ });
+ assert.equal(renewed.bootstrap_generation, bootstrap.generation);
+ assert.equal((await readNativeUltragoalBootstrap(f.stateDir, f.sessionId))?.status, 'active');
+ } finally {
+ await rm(f.cwd, { recursive: true, force: true });
+ }
+ });
+
+ it('revokes a local lease when tracker lifecycle closes and supports explicit revoke', async () => {
+ const f = await fixture();
+ try {
+ const bootstrap = await beginNativeUltragoalBootstrap({
+ cwd: f.cwd,
+ stateDir: f.stateDir,
+ sessionId: f.sessionId,
+ rootThreadId: f.rootThreadId,
+ backend: 'local-experimental',
+ ttlSeconds: 900,
+ now: f.now,
+ });
+ await issueLocalNativeExecutorAssignment({
+ cwd: f.cwd,
+ stateDir: f.stateDir,
+ sessionId: f.sessionId,
+ rootThreadId: f.rootThreadId,
+ childAgentId: f.childAgentId,
+ expectedGeneration: bootstrap.generation,
+ pathPrefixes: ['src'],
+ ttlSeconds: 300,
+ now: f.now,
+ });
+ const trackerPath = join(f.stateDir, 'subagent-tracking.json');
+ const tracker = JSON.parse(await readFile(trackerPath, 'utf-8')) as {
+ sessions: Record<string, { threads: Record<string, { status: string }> }>;
+ };
+ tracker.sessions[f.sessionId].threads[f.childAgentId].status = 'closed';
+ await writeJson(trackerPath, tracker);
+ assert.deepEqual(await reconcileLocalNativeExecutorAssignments({
+ cwd: f.cwd,
+ stateDir: f.stateDir,
+ sessionId: f.sessionId,
+ rootThreadId: f.rootThreadId,
+ now: f.now,
+ }), { ready: false });
+ const assignment = JSON.parse(await readFile(
+ nativeExecutorAssignmentPath(f.stateDir, f.sessionId, f.childAgentId),
+ 'utf-8',
+ )) as { lifecycle: string; revoke_reason?: string };
+ assert.equal(assignment.lifecycle, 'revoked');
+ assert.equal(assignment.revoke_reason, 'child_closed');
+
+ await revokeLocalNativeExecutorAssignment({
+ stateDir: f.stateDir,
+ sessionId: f.sessionId,
+ reason: 'root_cancelled',
+ now: f.now,
+ });
+ assert.equal((await readNativeUltragoalBootstrap(f.stateDir, f.sessionId))?.status, 'revoked');
+ } finally {
+ await rm(f.cwd, { recursive: true, force: true });
+ }
+ });
+
+ it('denies explicit and fail-closed durable authority fences', async () => {
+ const f = await fixture();
+ try {
+ const bootstrap = await beginNativeUltragoalBootstrap({
+ cwd: f.cwd,
+ stateDir: f.stateDir,
+ sessionId: f.sessionId,
+ rootThreadId: f.rootThreadId,
+ backend: 'local-experimental',
+ ttlSeconds: 900,
+ now: f.now,
+ });
+ const fencePath = join(f.stateDir, 'subagent-tracking.json.authority-fence.json');
+ await writeJson(fencePath, { ids: [f.childAgentId] });
+ await assert.rejects(issueLocalNativeExecutorAssignment({
+ cwd: f.cwd,
+ stateDir: f.stateDir,
+ sessionId: f.sessionId,
+ rootThreadId: f.rootThreadId,
+ childAgentId: f.childAgentId,
+ expectedGeneration: bootstrap.generation,
+ pathPrefixes: ['src'],
+ ttlSeconds: 300,
+ now: f.now,
+ }), /child_authority_fenced/);
+
+ await writeFile(fencePath, '{ malformed');
+ await assert.rejects(issueLocalNativeExecutorAssignment({
+ cwd: f.cwd,
+ stateDir: f.stateDir,
+ sessionId: f.sessionId,
+ rootThreadId: f.rootThreadId,
+ childAgentId: f.childAgentId,
+ expectedGeneration: bootstrap.generation,
+ pathPrefixes: ['src'],
+ ttlSeconds: 300,
+ now: f.now,
+ }), /child_authority_fenced/);
+ } finally {
+ await rm(f.cwd, { recursive: true, force: true });
+ }
+ });
+
+ it('rotates expired bootstrap generations and cannot activate without the exact assignment file', async () => {
+ const f = await fixture();
+ try {
+ const first = await beginNativeUltragoalBootstrap({
+ cwd: f.cwd,
+ stateDir: f.stateDir,
+ sessionId: f.sessionId,
+ rootThreadId: f.rootThreadId,
+ backend: 'local-experimental',
+ ttlSeconds: 30,
+ now: f.now,
+ });
+ await issueLocalNativeExecutorAssignment({
+ cwd: f.cwd,
+ stateDir: f.stateDir,
+ sessionId: f.sessionId,
+ rootThreadId: f.rootThreadId,
+ childAgentId: f.childAgentId,
+ expectedGeneration: first.generation,
+ pathPrefixes: ['src'],
+ ttlSeconds: 30,
+ now: f.now,
+ });
+ const assignmentPath = nativeExecutorAssignmentPath(f.stateDir, f.sessionId, f.childAgentId);
+ await rm(assignmentPath);
+ const missingAssignmentActivation = await markNativeUltragoalBootstrapActive({
+ cwd: f.cwd,
+ stateDir: f.stateDir,
+ sessionId: f.sessionId,
+ childAgentId: f.childAgentId,
+ now: f.now,
+ });
+ assert.equal(missingAssignmentActivation.ok, false);
+ assert.equal((await readNativeUltragoalBootstrap(f.stateDir, f.sessionId))?.status, 'ready');
+
+ const second = await beginNativeUltragoalBootstrap({
+ cwd: f.cwd,
+ stateDir: f.stateDir,
+ sessionId: f.sessionId,
+ rootThreadId: f.rootThreadId,
+ backend: 'local-experimental',
+ ttlSeconds: 30,
+ now: new Date(f.now.getTime() + 31_000),
+ });
+ assert.notEqual(second.generation, first.generation);
+ assert.equal(second.status, 'awaiting-executor');
+ } finally {
+ await rm(f.cwd, { recursive: true, force: true });
+ }
+ });
+
+ it('serializes authorize before revoke so stale readiness cannot resurrect authority', async () => {
+ const f = await fixture();
+ try {
+ const bootstrap = await beginNativeUltragoalBootstrap({
+ cwd: f.cwd,
+ stateDir: f.stateDir,
+ sessionId: f.sessionId,
+ rootThreadId: f.rootThreadId,
+ backend: 'local-experimental',
+ ttlSeconds: 900,
+ now: f.now,
+ });
+ const concurrent = await Promise.allSettled([
+ issueLocalNativeExecutorAssignment({
+ cwd: f.cwd,
+ stateDir: f.stateDir,
+ sessionId: f.sessionId,
+ rootThreadId: f.rootThreadId,
+ childAgentId: f.childAgentId,
+ expectedGeneration: bootstrap.generation,
+ pathPrefixes: ['src'],
+ ttlSeconds: 300,
+ now: f.now,
+ }),
+ revokeLocalNativeExecutorAssignment({
+ stateDir: f.stateDir,
+ sessionId: f.sessionId,
+ reason: 'concurrent_root_revoke',
+ now: f.now,
+ }),
+ ]);
+ if (concurrent[0].status === 'rejected') {
+ assert.match(String(concurrent[0].reason), /native_ultragoal_bootstrap_not_ready/);
+ }
+ assert.equal(concurrent[1].status, 'fulfilled');
+ assert.equal((await readNativeUltragoalBootstrap(f.stateDir, f.sessionId))?.status, 'revoked');
+ const assignmentPath = nativeExecutorAssignmentPath(f.stateDir, f.sessionId, f.childAgentId);
+ if (concurrent[0].status === 'fulfilled') {
+ const assignment = JSON.parse(await readFile(assignmentPath, 'utf-8')) as {
+ lifecycle: string;
+ revoke_reason?: string;
+ };
+ assert.equal(assignment.lifecycle, 'revoked');
+ assert.equal(assignment.revoke_reason, 'concurrent_root_revoke');
+ } else {
+ await assert.rejects(readFile(assignmentPath), /ENOENT/);
+ }
+ const replacement = await beginNativeUltragoalBootstrap({
+ cwd: f.cwd,
+ stateDir: f.stateDir,
+ sessionId: f.sessionId,
+ rootThreadId: f.rootThreadId,
+ backend: 'local-experimental',
+ ttlSeconds: 900,
+ now: f.now,
+ });
+ await assert.rejects(issueLocalNativeExecutorAssignment({
+ cwd: f.cwd,
+ stateDir: f.stateDir,
+ sessionId: f.sessionId,
+ rootThreadId: f.rootThreadId,
+ childAgentId: f.childAgentId,
+ expectedGeneration: bootstrap.generation,
+ pathPrefixes: ['src'],
+ ttlSeconds: 300,
+ now: f.now,
+ }), /native_ultragoal_bootstrap_not_ready/);
+ assert.notEqual(replacement.generation, bootstrap.generation);
+ } finally {
+ await rm(f.cwd, { recursive: true, force: true });
+ }
+ });
+
+ it('recovers one dead lifecycle lock without letting concurrent mutations overlap', async () => {
+ const f = await fixture();
+ try {
+ const bootstrap = await beginNativeUltragoalBootstrap({
+ cwd: f.cwd,
+ stateDir: f.stateDir,
+ sessionId: f.sessionId,
+ rootThreadId: f.rootThreadId,
+ backend: 'local-experimental',
+ ttlSeconds: 900,
+ now: f.now,
+ });
+ const lockPath = join(
+ f.stateDir,
+ 'sessions',
+ f.sessionId,
+ 'native-ultragoal-bootstrap.json.lock',
+ );
+ await writeJson(lockPath, { pid: 2_147_483_647, token: 'dead-owner' });
+ const concurrent = await Promise.allSettled([
+ issueLocalNativeExecutorAssignment({
+ cwd: f.cwd,
+ stateDir: f.stateDir,
+ sessionId: f.sessionId,
+ rootThreadId: f.rootThreadId,
+ childAgentId: f.childAgentId,
+ expectedGeneration: bootstrap.generation,
+ pathPrefixes: ['src'],
+ ttlSeconds: 300,
+ now: f.now,
+ }),
+ revokeLocalNativeExecutorAssignment({
+ stateDir: f.stateDir,
+ sessionId: f.sessionId,
+ reason: 'dead_lock_concurrent_revoke',
+ now: f.now,
+ }),
+ ]);
+ if (concurrent[0].status === 'rejected') {
+ assert.match(String(concurrent[0].reason), /native_ultragoal_bootstrap_not_ready/);
+ }
+ assert.equal(concurrent[1].status, 'fulfilled');
+ assert.equal((await readNativeUltragoalBootstrap(f.stateDir, f.sessionId))?.status, 'revoked');
+ await assert.rejects(readFile(lockPath), /ENOENT/);
+ await assert.rejects(readFile(`${lockPath}.reaper`), /ENOENT/);
+ } finally {
+ await rm(f.cwd, { recursive: true, force: true });
+ }
+ });
+});
diff --git a/src/ultragoal/artifacts.ts b/src/ultragoal/artifacts.ts
index 9e4ca72fe0d627e06405a28dc5306dee86cce547..326103f86a6a33d2b619cabc6f2d5481f1e2c333 100644
--- a/src/ultragoal/artifacts.ts
+++ b/src/ultragoal/artifacts.ts
@@ -3,6 +3,7 @@ import { appendFile, mkdir, open, readFile, rename, rm, writeFile } from 'node:f
import { isAbsolute, join, relative } from 'node:path';
import { normalizeSessionId, resolveWritableStateScope, WRITABLE_STATE_SCOPE_ERRORS } from '../mcp/state-paths.js';
import type { ResolvedStateScope } from '../mcp/state-paths.js';
+import { resolveNativeUltragoalConfig } from '../config/native-ultragoal.js';
import {
formatCodexGoalReconciliation,
buildCompletedCodexGoalRemediation,
@@ -615,6 +616,23 @@ function isDesignatedReviewBlockerResolver(goal: UltragoalItem, parent: Ultragoa
&& parent.reviewBlockerResolution?.resolverGoalId === goal.id;
}
+function reciprocalReviewBlockedParentChain(plan: UltragoalPlan, goal: UltragoalItem): UltragoalItem[] {
+ if (!hasUniqueGoalIds(plan)) return [];
+ const chain: UltragoalItem[] = [];
+ const visited = new Set([goal.id]);
+ let resolver = goal;
+ while (resolver.resolvesReviewBlockedGoalId) {
+ const parents = plan.goals.filter((candidate) => candidate.id === resolver.resolvesReviewBlockedGoalId);
+ if (parents.length !== 1) return [];
+ const parent = parents[0]!;
+ if (!isDesignatedReviewBlockerResolver(resolver, parent) || visited.has(parent.id)) return [];
+ chain.push(parent);
+ visited.add(parent.id);
+ resolver = parent;
+ }
+ return chain;
+}
+
function canUseCleanFinalResolverPathForReviewBlockedParent(
plan: UltragoalPlan,
goal: UltragoalItem,
@@ -622,10 +640,12 @@ function canUseCleanFinalResolverPathForReviewBlockedParent(
allowActiveFinalCodexGoal: boolean | undefined,
): boolean {
const unresolvedReviewBlocked = unresolvedReviewBlockedGoals(plan);
- if (unresolvedReviewBlocked.length !== 1) return false;
+ const parentChain = reciprocalReviewBlockedParentChain(plan, goal);
+ if (parentChain.length === 0 || unresolvedReviewBlocked.length !== parentChain.length) return false;
+ const unresolvedIds = new Set(unresolvedReviewBlocked.map((candidate) => candidate.id));
return finalRunCheckpoint
&& !allowActiveFinalCodexGoal
- && isDesignatedReviewBlockerResolver(goal, unresolvedReviewBlocked[0]);
+ && parentChain.every((candidate) => unresolvedIds.has(candidate.id));
}
function hasReciprocalReviewBlockerResolver(goal: UltragoalItem, plan: UltragoalPlan): boolean {
@@ -673,7 +693,7 @@ async function canReconcileCompletedTaskScopedAggregateSnapshot(
function buildCompletedLegacyGoalRemediation(goal: UltragoalItem): string {
return [
'If get_goal returns a different completed legacy/thread objective, do not repeat --status complete in this thread.',
- `Record a non-terminal blocker with: omx ultragoal checkpoint --goal-id ${goal.id} --status blocked --evidence "<completed legacy Codex goal blocks create_goal in this thread>" --codex-goal-json "<different completed get_goal JSON or path>".`,
+ `Record a non-terminal blocker with: omx ultragoal checkpoint --goal-id ${goal.id} --status blocked --evidence "<completed legacy Codex goal blocks create_goal in this thread>" --codex-goal-json "<different completed get_goal JSON or path>" --json.`,
'Then continue only from a Codex goal context with no active/completed conflicting goal, in the same repo/worktree, and create the intended goal there.',
].join(' ');
}
@@ -681,7 +701,7 @@ function buildCompletedLegacyGoalRemediation(goal: UltragoalItem): string {
function buildUnavailableCodexGoalRemediation(goal: UltragoalItem): string {
return [
'If get_goal itself is unavailable due to a Codex DB/schema/context error, such as "no such table: thread_goals", do not repeat --status complete or mark the Codex goal complete from shell state.',
- `Record an auditable non-terminal blocker with: omx ultragoal checkpoint --goal-id ${goal.id} --status blocked --evidence "<get_goal unavailable due to Codex DB/schema/context error; safe recovery requires a working Codex goal context>" --codex-goal-json "<unavailable get_goal error JSON or path>".`,
+ `Record an auditable non-terminal blocker with: omx ultragoal checkpoint --goal-id ${goal.id} --status blocked --evidence "<get_goal unavailable due to Codex DB/schema/context error; safe recovery requires a working Codex goal context>" --codex-goal-json "<unavailable get_goal error JSON or path>" --json.`,
'Then continue from a Codex goal context where get_goal works and strict completion reconciliation can be proven.',
].join(' ');
}
@@ -779,9 +799,14 @@ function isCompletionBlocking(goal: UltragoalItem, plan: UltragoalPlan): boolean
return !isResolvedStatus(goal.status);
}
-function isCompletionBlockingForFinalCandidate(candidate: UltragoalItem, finalCandidate: UltragoalItem, plan: UltragoalPlan): boolean {
+function isCompletionBlockingForFinalCandidate(
+ candidate: UltragoalItem,
+ finalCandidate: UltragoalItem,
+ plan: UltragoalPlan,
+ reviewBlockedParentIds: ReadonlySet<string>,
+): boolean {
if (candidate.id === finalCandidate.id) return false;
- if (candidate.status === 'review_blocked' && candidate.reviewBlockerResolution?.resolverGoalId === finalCandidate.id) return false;
+ if (candidate.status === 'review_blocked' && reviewBlockedParentIds.has(candidate.id)) return false;
if (candidate.steeringStatus === 'superseded') {
const replacements = candidate.supersededBy ?? [];
if (replacements.length === 0) return true;
@@ -794,12 +819,35 @@ function isCompletionBlockingForFinalCandidate(candidate: UltragoalItem, finalCa
return isCompletionBlocking(candidate, plan);
}
+function reviewBlockedAncestorIdsForFinalCandidate(plan: UltragoalPlan, finalCandidate: UltragoalItem): Set<string> {
+ const ancestors = new Set<string>();
+ const frontier = [finalCandidate.id];
+ while (frontier.length > 0) {
+ const resolverId = frontier.pop()!;
+ for (const candidate of plan.goals) {
+ if (
+ candidate.status !== 'review_blocked'
+ || candidate.reviewBlockerResolution?.resolverGoalId !== resolverId
+ || ancestors.has(candidate.id)
+ ) {
+ continue;
+ }
+ ancestors.add(candidate.id);
+ frontier.push(candidate.id);
+ }
+ }
+ return ancestors;
+}
+
function isScheduleEligible(goal: UltragoalItem): boolean {
return goal.steeringStatus !== 'superseded' && goal.steeringStatus !== 'blocked';
}
export function isFinalRunCompletionCandidate(plan: UltragoalPlan, goal: UltragoalItem): boolean {
- return plan.goals.every((candidate) => !isCompletionBlockingForFinalCandidate(candidate, goal, plan));
+ const reviewBlockedParentIds = reviewBlockedAncestorIdsForFinalCandidate(plan, goal);
+ return plan.goals.every((candidate) => (
+ !isCompletionBlockingForFinalCandidate(candidate, goal, plan, reviewBlockedParentIds)
+ ));
}
export function isUltragoalDone(plan: UltragoalPlan): boolean {
@@ -874,7 +922,9 @@ export async function assertUltragoalWritableLifecycleAuthority(
): Promise<UltragoalWritableAuthority> {
try {
const suppliedEnvironmentSessionId = process.env.OMX_SESSION_ID?.trim();
- const scope = await resolveWritableStateScope(cwd);
+ const scope = await resolveWritableStateScope(cwd, undefined, {
+ nativeUltragoalBackend: resolveNativeUltragoalConfig().backend,
+ });
if (
options.allowUnboundEnvironment === false
&& suppliedEnvironmentSessionId
@@ -933,7 +983,7 @@ function describeWritableAuthority(authority: UltragoalWritableAuthority): strin
async function withUltragoalMutationLock<T>(
cwd: string,
- operation: () => Promise<T>,
+ operation: (beforeCommit: () => Promise<void>) => Promise<T>,
options: { allowUnboundEnvironment?: boolean } = {},
): Promise<T> {
const beforeLock = await assertUltragoalWritableLifecycleAuthority(cwd, options);
@@ -964,15 +1014,29 @@ async function withUltragoalMutationLock<T>(
`Refusing durable ultragoal mutation after writable lifecycle authority drift while waiting for the mutation lock: before lock ${describeWritableAuthority(beforeLock)}; after lock ${describeWritableAuthority(afterLock)}.`,
);
}
- return await operation();
+ const beforeCommit = async (): Promise<void> => {
+ const current = await assertUltragoalWritableLifecycleAuthority(cwd, options);
+ if (!writableAuthorityEquals(afterLock, current)) {
+ throw new UltragoalError(
+ `Refusing durable ultragoal mutation after writable lifecycle authority drift before commit: locked ${describeWritableAuthority(afterLock)}; current ${describeWritableAuthority(current)}.`,
+ );
+ }
+ };
+ return await operation(beforeCommit);
} finally {
await handle.close().catch(() => undefined);
await rm(lockPath, { force: true }).catch(() => undefined);
}
}
-async function appendLedger(cwd: string, entry: UltragoalLedgerEntry): Promise<void> {
+async function appendLedger(
+ cwd: string,
+ entry: UltragoalLedgerEntry,
+ beforeCommit: () => Promise<void>,
+): Promise<void> {
+ await beforeCommit();
await mkdir(ultragoalDir(cwd), { recursive: true });
+ await beforeCommit();
const path = ultragoalLedgerPath(cwd);
await appendFile(path, `${JSON.stringify(entry)}\n`);
}
@@ -1014,7 +1078,11 @@ function requiresAggregateObjectiveMigration(plan: UltragoalPlan, statePathPrefi
}
/** Durable legacy-objective migration; caller MUST hold the mutation lock. */
-async function migrateAggregateObjectiveUnderLock(cwd: string, parsed: UltragoalPlan): Promise<UltragoalPlan> {
+async function migrateAggregateObjectiveUnderLock(
+ cwd: string,
+ parsed: UltragoalPlan,
+ beforeCommit: () => Promise<void>,
+): Promise<UltragoalPlan> {
const statePathPrefix = ultragoalStatePathPrefix(cwd);
if (!requiresAggregateObjectiveMigration(parsed, statePathPrefix)) return parsed;
const canonicalStatePathMigration = requiresCanonicalStatePathMigration(parsed, statePathPrefix);
@@ -1024,7 +1092,7 @@ async function migrateAggregateObjectiveUnderLock(cwd: string, parsed: Ultragoal
parsed.statePathPrefix = statePathPrefix === '' ? undefined : statePathPrefix;
parsed.codexObjectiveAliases = Array.from(new Set([...(parsed.codexObjectiveAliases ?? []), previousObjective].filter((value): value is string => typeof value === 'string' && value.length > 0)));
parsed.updatedAt = now;
- await writePlan(cwd, parsed);
+ await writePlan(cwd, parsed, beforeCommit);
await appendLedger(cwd, {
ts: now,
event: 'aggregate_objective_migrated',
@@ -1033,13 +1101,16 @@ async function migrateAggregateObjectiveUnderLock(cwd: string, parsed: Ultragoal
: 'Migrated legacy enumerated aggregate Codex objective to the stable pointer objective.',
before: { codexObjective: previousObjective },
after: { codexObjective: parsed.codexObjective },
- });
+ }, beforeCommit);
return parsed;
}
/** Locked plan read for mutators that already hold the mutation lock. */
-async function readUltragoalPlanUnderLock(cwd: string): Promise<UltragoalPlan> {
- return migrateAggregateObjectiveUnderLock(cwd, await readUltragoalPlanFile(cwd));
+async function readUltragoalPlanUnderLock(
+ cwd: string,
+ beforeCommit: () => Promise<void>,
+): Promise<UltragoalPlan> {
+ return migrateAggregateObjectiveUnderLock(cwd, await readUltragoalPlanFile(cwd), beforeCommit);
}
export async function readUltragoalPlan(cwd: string): Promise<UltragoalPlan> {
@@ -1048,19 +1119,30 @@ export async function readUltragoalPlan(cwd: string): Promise<UltragoalPlan> {
// The legacy objective migration is a durable story transition: it requires
// writable lifecycle authority and the mutation lock, and re-reads the plan
// under the lock so a concurrent mutator cannot be clobbered or duplicated.
- return withUltragoalMutationLock(cwd, async () => readUltragoalPlanUnderLock(cwd));
+ return withUltragoalMutationLock(cwd, async (beforeCommit) => readUltragoalPlanUnderLock(cwd, beforeCommit));
}
-async function writePlan(cwd: string, plan: UltragoalPlan): Promise<void> {
+async function writePlan(
+ cwd: string,
+ plan: UltragoalPlan,
+ beforeCommit: () => Promise<void>,
+): Promise<void> {
+ await beforeCommit();
await mkdir(ultragoalDir(cwd), { recursive: true });
const path = ultragoalGoalsPath(cwd);
const tmpPath = `${path}.${process.pid}.${Date.now()}.tmp`;
- await writeFile(tmpPath, `${JSON.stringify(plan, null, 2)}\n`);
- await rename(tmpPath, path);
+ await beforeCommit();
+ try {
+ await writeFile(tmpPath, `${JSON.stringify(plan, null, 2)}\n`);
+ await beforeCommit();
+ await rename(tmpPath, path);
+ } finally {
+ await rm(tmpPath, { force: true }).catch(() => undefined);
+ }
}
export async function createUltragoalPlan(cwd: string, options: CreateUltragoalOptions): Promise<UltragoalPlan> {
- return withUltragoalMutationLock(cwd, async () => {
+ return withUltragoalMutationLock(cwd, async (beforeCommit) => {
if (!options.force && existsSync(ultragoalGoalsPath(cwd))) {
throw new UltragoalError(`Refusing to overwrite existing ${ULTRAGOAL_DIR}/${ULTRAGOAL_GOALS}; pass --force to recreate it.`);
}
@@ -1096,11 +1178,14 @@ export async function createUltragoalPlan(cwd: string, options: CreateUltragoalO
plan.codexObjective = aggregateCodexObjective(statePathPrefix);
}
+ await beforeCommit();
await mkdir(ultragoalDir(cwd), { recursive: true });
+ await beforeCommit();
await writeFile(ultragoalBriefPath(cwd), options.brief.endsWith('\n') ? options.brief : `${options.brief}\n`);
- await writePlan(cwd, plan);
+ await writePlan(cwd, plan, beforeCommit);
+ await beforeCommit();
await writeFile(ultragoalLedgerPath(cwd), '');
- await appendLedger(cwd, { ts: now, event: 'plan_created', message: `${candidates.length} goal(s) created` });
+ await appendLedger(cwd, { ts: now, event: 'plan_created', message: `${candidates.length} goal(s) created` }, beforeCommit);
return plan;
}, { allowUnboundEnvironment: false });
}
@@ -1170,14 +1255,14 @@ function appendGoalToPlan(plan: UltragoalPlan, options: AddUltragoalGoalOptions
}
export async function addUltragoalGoal(cwd: string, options: AddUltragoalGoalOptions): Promise<{ plan: UltragoalPlan; goal: UltragoalItem }> {
- return withUltragoalMutationLock(cwd, async () => {
- const plan = await readUltragoalPlanUnderLock(cwd);
+ return withUltragoalMutationLock(cwd, async (beforeCommit) => {
+ const plan = await readUltragoalPlanUnderLock(cwd, beforeCommit);
if (plan.aggregateCompletion?.status === 'complete') {
throw new UltragoalError('Cannot add a goal to an already completed aggregate ultragoal plan; start a new plan for post-terminal work.');
}
const now = iso(options.now);
const goal = appendGoalToPlan(plan, options);
- await writePlan(cwd, plan);
+ await writePlan(cwd, plan, beforeCommit);
await appendLedger(cwd, {
ts: now,
event: 'goal_added',
@@ -1185,7 +1270,7 @@ export async function addUltragoalGoal(cwd: string, options: AddUltragoalGoalOpt
status: goal.status,
evidence: options.evidence,
message: goal.title,
- });
+ }, beforeCommit);
return { plan, goal };
});
}
@@ -1457,8 +1542,8 @@ function applySteeringMutation(plan: UltragoalPlan, proposal: UltragoalSteeringP
}
export async function steerUltragoal(cwd: string, proposal: UltragoalSteeringProposal, options: { now?: Date; directiveText?: string } = {}): Promise<SteerUltragoalResult> {
- return withUltragoalMutationLock(cwd, async () => {
- const plan = await readUltragoalPlanUnderLock(cwd);
+ return withUltragoalMutationLock(cwd, async (beforeCommit) => {
+ const plan = await readUltragoalPlanUnderLock(cwd, beforeCommit);
const existing = proposal.idempotencyKey
? (await readSteeringLedgerEntries(cwd)).find((entry) => entry.event === 'steering_accepted' && (entry.idempotencyKey === proposal.idempotencyKey || entry.steering?.idempotencyKey === proposal.idempotencyKey) && entry.steering)
: undefined;
@@ -1499,7 +1584,7 @@ export async function steerUltragoal(cwd: string, proposal: UltragoalSteeringPro
idempotencyKey: proposal.idempotencyKey,
};
- if (invariant.accepted) await writePlan(cwd, plan);
+ if (invariant.accepted && proposal.kind !== 'annotate_ledger') await writePlan(cwd, plan, beforeCommit);
await appendLedger(cwd, {
ts: now,
event: invariant.accepted ? 'steering_accepted' : 'steering_rejected',
@@ -1510,7 +1595,7 @@ export async function steerUltragoal(cwd: string, proposal: UltragoalSteeringPro
mutationKind: proposal.kind,
before: audit.before,
after: audit.after,
- });
+ }, beforeCommit);
return { plan, accepted: invariant.accepted, audit, rejectedReasons: invariant.rejectedReasons, deduped: false };
});
@@ -1730,20 +1815,20 @@ function validateQualityGate(value: unknown, requiredInvariants: readonly Requir
}
export async function startNextUltragoal(cwd: string, options: StartNextOptions = {}): Promise<{ plan: UltragoalPlan; goal: UltragoalItem | null; resumed: boolean; done: boolean }> {
- return withUltragoalMutationLock(cwd, async () => {
- const plan = await readUltragoalPlanUnderLock(cwd);
+ return withUltragoalMutationLock(cwd, async (beforeCommit) => {
+ const plan = await readUltragoalPlanUnderLock(cwd, beforeCommit);
const now = iso(options.now);
if (plan.aggregateCompletion?.status === 'complete') return { plan, goal: null, resumed: false, done: true };
const existing = plan.goals.find((goal) => goal.status === 'in_progress' && isScheduleEligibleGoal(goal));
if (existing) {
- await appendLedger(cwd, { ts: now, event: 'goal_resumed', goalId: existing.id, status: existing.status, message: 'Resuming active ultragoal' });
+ await appendLedger(cwd, { ts: now, event: 'goal_resumed', goalId: existing.id, status: existing.status, message: 'Resuming active ultragoal' }, beforeCommit);
return { plan, goal: existing, resumed: true, done: false };
}
let next = plan.goals.find((goal) => goal.status === 'pending' && isScheduleEligible(goal));
if (!next && options.retryFailed) {
next = plan.goals.find((goal) => goal.status === 'failed' && !goal.nonRetriable && isScheduleEligible(goal));
- if (next) await appendLedger(cwd, { ts: now, event: 'goal_retried', goalId: next.id, status: 'pending', message: next.failureReason });
+ if (next) await appendLedger(cwd, { ts: now, event: 'goal_retried', goalId: next.id, status: 'pending', message: next.failureReason }, beforeCommit);
}
if (!next) return { plan, goal: null, resumed: false, done: isUltragoalDone(plan) };
@@ -1756,15 +1841,15 @@ export async function startNextUltragoal(cwd: string, options: StartNextOptions
next.updatedAt = now;
plan.activeGoalId = next.id;
plan.updatedAt = now;
- await writePlan(cwd, plan);
- await appendLedger(cwd, { ts: now, event: 'goal_started', goalId: next.id, status: next.status, message: `Attempt ${next.attempt}` });
+ await writePlan(cwd, plan, beforeCommit);
+ await appendLedger(cwd, { ts: now, event: 'goal_started', goalId: next.id, status: next.status, message: `Attempt ${next.attempt}` }, beforeCommit);
return { plan, goal: next, resumed: false, done: false };
});
}
export async function checkpointUltragoal(cwd: string, options: CheckpointOptions): Promise<UltragoalPlan> {
- return withUltragoalMutationLock(cwd, async () => {
- const plan = await readUltragoalPlanUnderLock(cwd);
+ return withUltragoalMutationLock(cwd, async (beforeCommit) => {
+ const plan = await readUltragoalPlanUnderLock(cwd, beforeCommit);
const goal = plan.goals.find((candidate) => candidate.id === options.goalId);
if (!goal) throw new UltragoalError(`Unknown ultragoal id: ${options.goalId}`);
if (plan.aggregateCompletion?.status === 'complete' && options.status !== 'complete') {
@@ -1781,7 +1866,7 @@ export async function checkpointUltragoal(cwd: string, options: CheckpointOption
goal.failureReason = assertNonEmpty(options.evidence, '--evidence');
plan.activeGoalId = goal.id;
plan.updatedAt = now;
- await writePlan(cwd, plan);
+ await writePlan(cwd, plan, beforeCommit);
await appendLedger(cwd, {
ts: now,
event: 'goal_blocked',
@@ -1790,7 +1875,7 @@ export async function checkpointUltragoal(cwd: string, options: CheckpointOption
evidence: options.evidence,
codexGoal: options.codexGoal,
message: 'Codex get_goal was unavailable due to a DB/schema/context error; strict completion reconciliation is deferred until get_goal works.',
- });
+ }, beforeCommit);
return plan;
}
if (!snapshot?.available) {
@@ -1811,7 +1896,7 @@ export async function checkpointUltragoal(cwd: string, options: CheckpointOption
goal.updatedAt = now;
plan.activeGoalId = goal.id;
plan.updatedAt = now;
- await writePlan(cwd, plan);
+ await writePlan(cwd, plan, beforeCommit);
await appendLedger(cwd, {
ts: now,
event: 'goal_blocked',
@@ -1820,7 +1905,7 @@ export async function checkpointUltragoal(cwd: string, options: CheckpointOption
evidence,
codexGoal: options.codexGoal,
message: 'Native Codex goal status is blocked for the matching objective; recorded a non-terminal goal_blocked checkpoint. Continue work without treating this as complete or failed; re-check get_goal when the blocker clears.',
- });
+ }, beforeCommit);
return plan;
}
if (snapshot.status !== 'complete') {
@@ -1834,7 +1919,7 @@ export async function checkpointUltragoal(cwd: string, options: CheckpointOption
if (safeCompletedAggregateBlocker) goal.failureReason = assertNonEmpty(options.evidence, '--evidence');
plan.activeGoalId = goal.id;
plan.updatedAt = now;
- await writePlan(cwd, plan);
+ await writePlan(cwd, plan, beforeCommit);
await appendLedger(cwd, {
ts: now,
event: 'goal_blocked',
@@ -1845,7 +1930,7 @@ export async function checkpointUltragoal(cwd: string, options: CheckpointOption
message: safeCompletedAggregateBlocker
? 'Completed aggregate Codex goal is already terminal while the repo-native microgoal remains in progress; recorded a non-terminal safe-recovery blocker to avoid repeating an impossible checkpoint loop.'
: undefined,
- });
+ }, beforeCommit);
return plan;
}
let aggregateCompletion: UltragoalAggregateCompletion | undefined;
@@ -1931,6 +2016,7 @@ export async function checkpointUltragoal(cwd: string, options: CheckpointOption
const qualityGate = options.status === 'complete' && (aggregateCompletion !== undefined || (isFinalRunCompletionCandidate(plan, goal) && !options.allowActiveFinalCodexGoal))
? validateQualityGate(options.qualityGate, requiredArchitectureInvariants)
: undefined;
+ const resolvedParentChain = qualityGate ? reciprocalReviewBlockedParentChain(plan, goal) : [];
if (aggregateCompletion) {
goal.status = 'complete';
goal.completedAt = now;
@@ -1942,7 +2028,7 @@ export async function checkpointUltragoal(cwd: string, options: CheckpointOption
plan.aggregateCompletion = aggregateCompletion;
if (plan.activeGoalId === goal.id) delete plan.activeGoalId;
plan.updatedAt = now;
- await writePlan(cwd, plan);
+ await writePlan(cwd, plan, beforeCommit);
await appendLedger(cwd, {
ts: now,
event: 'goal_completed',
@@ -1952,7 +2038,7 @@ export async function checkpointUltragoal(cwd: string, options: CheckpointOption
codexGoal: options.codexGoal,
qualityGate,
message: 'Active repo-native microgoal completed while reconciling a completed task-scoped aggregate Codex goal snapshot.',
- });
+ }, beforeCommit);
await appendLedger(cwd, {
ts: now,
event: 'aggregate_completed',
@@ -1962,7 +2048,7 @@ export async function checkpointUltragoal(cwd: string, options: CheckpointOption
codexGoal: options.codexGoal,
qualityGate,
message: 'Aggregate ultragoal plan completed via task-scoped Codex goal snapshot; checkpointed active microgoal row was reconciled to complete.',
- });
+ }, beforeCommit);
return plan;
}
goal.status = options.status;
@@ -1974,20 +2060,19 @@ export async function checkpointUltragoal(cwd: string, options: CheckpointOption
goal.failedAt = undefined;
clearGoalBlockerFields(goal);
if (normalFinalAggregateCompletion) plan.aggregateCompletion = normalFinalAggregateCompletion;
- const resolvedParent = goal.resolvesReviewBlockedGoalId
- ? plan.goals.find((candidate) => candidate.id === goal.resolvesReviewBlockedGoalId)
- : undefined;
- if (resolvedParent?.status === 'review_blocked' && resolvedParent.reviewBlockerResolution?.resolverGoalId === goal.id && qualityGate) {
+ let resolver = goal;
+ for (const resolvedParent of resolvedParentChain) {
resolvedParent.status = 'complete';
resolvedParent.completedAt = now;
resolvedParent.updatedAt = now;
resolvedParent.reviewBlockerResolution = {
- resolverGoalId: goal.id,
+ resolverGoalId: resolver.id,
status: 'complete',
resolvedAt: now,
evidence: options.evidence,
};
clearGoalBlockerFields(resolvedParent);
+ resolver = resolvedParent;
}
if (plan.activeGoalId === goal.id) delete plan.activeGoalId;
} else {
@@ -2008,7 +2093,7 @@ export async function checkpointUltragoal(cwd: string, options: CheckpointOption
if (plan.activeGoalId === goal.id) delete plan.activeGoalId;
}
plan.updatedAt = now;
- await writePlan(cwd, plan);
+ await writePlan(cwd, plan, beforeCommit);
const blockerEvent = goal.status === 'needs_user_decision';
await appendLedger(cwd, {
ts: now,
@@ -2024,10 +2109,10 @@ export async function checkpointUltragoal(cwd: string, options: CheckpointOption
message: blockerEvent
? `Blocked on repeated external authorization. Required decision: ${goal.requiredExternalDecision}.`
: undefined,
- });
- if (options.status === 'complete' && goal.resolvesReviewBlockedGoalId) {
- const resolvedParent = plan.goals.find((candidate) => candidate.id === goal.resolvesReviewBlockedGoalId);
- if (resolvedParent?.reviewBlockerResolution?.status === 'complete' && resolvedParent.reviewBlockerResolution.resolverGoalId === goal.id) {
+ }, beforeCommit);
+ if (options.status === 'complete') {
+ let resolver = goal;
+ for (const resolvedParent of resolvedParentChain) {
await appendLedger(cwd, {
ts: now,
event: 'goal_completed',
@@ -2036,8 +2121,9 @@ export async function checkpointUltragoal(cwd: string, options: CheckpointOption
evidence: options.evidence,
codexGoal: options.codexGoal,
qualityGate,
- message: `Review-blocked final story resolved by ${goal.id}; original failed review remains in prior final_review_failed/goal_review_blocked ledger entries.`,
- });
+ message: `Review-blocked final story resolved by ${resolver.id}; original failed review remains in prior final_review_failed/goal_review_blocked ledger entries.`,
+ }, beforeCommit);
+ resolver = resolvedParent;
}
}
if (normalFinalAggregateCompletion) {
@@ -2050,15 +2136,15 @@ export async function checkpointUltragoal(cwd: string, options: CheckpointOption
codexGoal: options.codexGoal,
qualityGate,
message: 'Aggregate ultragoal plan completed with a clean final quality gate.',
- });
+ }, beforeCommit);
}
return plan;
});
}
export async function recordFinalReviewBlockers(cwd: string, options: RecordFinalReviewBlockersOptions): Promise<{ plan: UltragoalPlan; blockedGoal: UltragoalItem; addedGoal: UltragoalItem }> {
- return withUltragoalMutationLock(cwd, async () => {
- const plan = await readUltragoalPlanUnderLock(cwd);
+ return withUltragoalMutationLock(cwd, async (beforeCommit) => {
+ const plan = await readUltragoalPlanUnderLock(cwd, beforeCommit);
const goal = plan.goals.find((candidate) => candidate.id === options.goalId);
if (!goal) throw new UltragoalError(`Unknown ultragoal id: ${options.goalId}`);
assertNonEmpty(options.evidence, '--evidence');
@@ -2102,7 +2188,7 @@ export async function recordFinalReviewBlockers(cwd: string, options: RecordFina
if (plan.activeGoalId === goal.id) delete plan.activeGoalId;
plan.updatedAt = now;
- await writePlan(cwd, plan);
+ await writePlan(cwd, plan, beforeCommit);
await appendLedger(cwd, {
ts: now,
event: 'final_review_failed',
@@ -2113,7 +2199,7 @@ export async function recordFinalReviewBlockers(cwd: string, options: RecordFina
message: aggregateMode
? 'Final aggregate code-review was not clean; blocker story was appended while Codex goal remains active.'
: 'Final per-story code-review was not clean; blocker story was appended and may require an available Codex goal context.',
- });
+ }, beforeCommit);
await appendLedger(cwd, {
ts: now,
event: 'goal_added',
@@ -2121,7 +2207,7 @@ export async function recordFinalReviewBlockers(cwd: string, options: RecordFina
status: addedGoal.status,
evidence: options.evidence,
message: addedGoal.title,
- });
+ }, beforeCommit);
await appendLedger(cwd, {
ts: now,
event: 'goal_review_blocked',
@@ -2129,7 +2215,7 @@ export async function recordFinalReviewBlockers(cwd: string, options: RecordFina
status: goal.status,
evidence: options.evidence,
codexGoal: options.codexGoal,
- });
+ }, beforeCommit);
return { plan, blockedGoal: goal, addedGoal };
});
}
@@ -2174,7 +2260,7 @@ function buildPerStoryCodexGoalInstruction(goal: UltragoalItem, plan: UltragoalP
'- If a different active Codex goal exists, finish/checkpoint that goal before starting this ultragoal.',
'- Ultragoal cannot call /goal clear from the model/shell tool surface. For another per-story goal in the same session/thread after a completed Codex goal, manually run /goal clear in the Codex UI before creating the next goal.',
'- If get_goal returns a different completed legacy/thread goal and create_goal rejects because this thread already has a completed goal, continue only from a Codex goal context with no active/completed conflicting goal in the same repo/worktree and create the payload there.',
- `- To preserve the durable ledger before switching threads, record the non-terminal blocker without failing this goal: omx ultragoal checkpoint --goal-id ${goal.id} --status blocked --evidence "<completed legacy Codex goal blocks create_goal in this thread>" --codex-goal-json "<get_goal JSON or path>"`,
+ `- To preserve the durable ledger before switching threads, record the non-terminal blocker without failing this goal: omx ultragoal checkpoint --goal-id ${goal.id} --status blocked --evidence "<completed legacy Codex goal blocks create_goal in this thread>" --codex-goal-json "<get_goal JSON or path>" --json`,
'- Work only this goal until its completion audit passes.',
finalStory
? '- Final mandatory quality gate: run ai-slop-cleaner on changed files even when it is a no-op, rerun verification, then run $code-review.'
@@ -2187,7 +2273,7 @@ function buildPerStoryCodexGoalInstruction(goal: UltragoalItem, plan: UltragoalP
: '- After the goal is actually complete, call update_goal({status: "complete"}), call get_goal again for a fresh completion snapshot, then checkpoint the ledger with:',
finalStory
? ` omx ultragoal record-review-blockers --goal-id ${goal.id} --title "Resolve final code-review blockers" --objective "<blocker-resolution objective>" --evidence "<review findings>" --codex-goal-json "<active get_goal JSON or path>"`
- : ` omx ultragoal checkpoint --goal-id ${goal.id} --status complete --evidence "<tests/files/PR evidence>" --codex-goal-json "<fresh get_goal JSON or path>"`,
+ : ` omx ultragoal checkpoint --goal-id ${goal.id} --status complete --evidence "<tests/files/PR evidence>" --codex-goal-json "<fresh get_goal JSON or path>" --json`,
finalStory
? '- In legacy per-story mode, the blocker story may require an available Codex goal context because this story remains an active incomplete Codex goal; do not claim it is complete.'
: null,
@@ -2195,12 +2281,12 @@ function buildPerStoryCodexGoalInstruction(goal: UltragoalItem, plan: UltragoalP
? '- If final $code-review is clean (APPROVE + CLEAR + independent code-reviewer and architect subagent evidence), call update_goal({status: "complete"}), call get_goal again, then checkpoint with --quality-gate-json:'
: null,
finalStory
- ? ` omx ultragoal checkpoint --goal-id ${goal.id} --status complete --evidence "<tests/files/PR evidence>" --codex-goal-json "<fresh complete get_goal JSON or path>" --quality-gate-json "<quality gate JSON or path>"`
+ ? ` omx ultragoal checkpoint --goal-id ${goal.id} --status complete --evidence "<tests/files/PR evidence>" --codex-goal-json "<fresh complete get_goal JSON or path>" --quality-gate-json "<quality gate JSON or path>" --json`
: null,
finalStory
? '- After the final checkpoint command succeeds, treat `/goal clear` as the explicit terminal cleanup step before another same-thread goal.'
: null,
- '- If blocked on a matching native Codex goal status, record a non-terminal blocker with: omx ultragoal checkpoint --goal-id ' + goal.id + ' --status blocked --evidence "<blocker evidence>" --codex-goal-json "<matching blocked get_goal JSON or path>". If failed, checkpoint with --status failed and the failure evidence; rerun complete-goals --retry-failed to resume.',
+ '- If blocked on a matching native Codex goal status, record a non-terminal blocker with: omx ultragoal checkpoint --goal-id ' + goal.id + ' --status blocked --evidence "<blocker evidence>" --codex-goal-json "<matching blocked get_goal JSON or path>" --json. If failed, checkpoint with --status failed, the failure evidence, and --json; rerun complete-goals --retry-failed to resume.',
'',
'create_goal payload:',
JSON.stringify(createPayload, null, 2),
@@ -2251,9 +2337,9 @@ function buildAggregateCodexGoalInstruction(goal: UltragoalItem, plan: Ultragoal
: null,
`- Checkpoint this OMX story with a fresh get_goal snapshot whose objective matches the aggregate payload and whose status is ${checkpointStatus}:`,
finalStory
- ? ` omx ultragoal checkpoint --goal-id ${goal.id} --status complete --evidence "<tests/files/PR evidence>" --codex-goal-json "<fresh complete get_goal JSON or path>" --quality-gate-json "<quality gate JSON or path>"`
- : ` omx ultragoal checkpoint --goal-id ${goal.id} --status complete --evidence "<tests/files/PR evidence>" --codex-goal-json "<fresh get_goal JSON or path>"`,
- '- If blocked on a matching native Codex goal status, record a non-terminal blocker with: omx ultragoal checkpoint --goal-id ' + goal.id + ' --status blocked --evidence "<blocker evidence>" --codex-goal-json "<matching blocked get_goal JSON or path>". If failed, checkpoint with --status failed and the failure evidence; rerun complete-goals --retry-failed to resume.',
+ ? ` omx ultragoal checkpoint --goal-id ${goal.id} --status complete --evidence "<tests/files/PR evidence>" --codex-goal-json "<fresh complete get_goal JSON or path>" --quality-gate-json "<quality gate JSON or path>" --json`
+ : ` omx ultragoal checkpoint --goal-id ${goal.id} --status complete --evidence "<tests/files/PR evidence>" --codex-goal-json "<fresh get_goal JSON or path>" --json`,
+ '- If blocked on a matching native Codex goal status, record a non-terminal blocker with: omx ultragoal checkpoint --goal-id ' + goal.id + ' --status blocked --evidence "<blocker evidence>" --codex-goal-json "<matching blocked get_goal JSON or path>" --json. If failed, checkpoint with --status failed, the failure evidence, and --json; rerun complete-goals --retry-failed to resume.',
'',
'create_goal payload:',
JSON.stringify(createPayload, null, 2),
diff --git a/src/ultragoal/native-bootstrap.ts b/src/ultragoal/native-bootstrap.ts
new file mode 100644
index 0000000000000000000000000000000000000000..0d0079e3f8f509b0f8d053a0e1135df733887b00
--- /dev/null
+++ b/src/ultragoal/native-bootstrap.ts
@@ -0,0 +1,1106 @@
+import { randomUUID } from 'node:crypto';
+import { constants as fsConstants, type Dirent } from 'node:fs';
+import { access, chmod, lstat, mkdir, open, readFile, readdir, realpath, rename, unlink, writeFile } from 'node:fs/promises';
+import { homedir } from 'node:os';
+import { dirname, isAbsolute, join, relative, resolve } from 'node:path';
+import {
+ acquireCrossProcessFileLock,
+ ensureExactDescriptiveLeaderForSession,
+ isNativeSubagentAuthorityFenced,
+ NATIVE_SUBAGENT_PROVENANCE,
+ recordSubagentTurnForSession,
+ readSubagentTrackingState,
+} from '../subagents/tracker.js';
+import type { NativeUltragoalBackend } from '../config/native-ultragoal.js';
+
+export const NATIVE_ULTRAGOAL_BOOTSTRAP_FILE = 'native-ultragoal-bootstrap.json';
+export const NATIVE_ASSIGNMENT_DIRECTORY = 'native-assignments';
+export const DOCUMENTED_HOST_RECEIPT_UNAVAILABLE = 'documented_host_native_executor_receipt_unavailable';
+
+export type NativeUltragoalBootstrapStatus =
+ | 'awaiting-executor'
+ | 'ready'
+ | 'activating'
+ | 'active'
+ | 'revoked'
+ | 'expired'
+ | 'host-receipt-unavailable';
+
+export interface NativeUltragoalBootstrapState {
+ schema_version: 1;
+ kind: 'native-ultragoal-bootstrap';
+ generation: string;
+ backend: NativeUltragoalBackend;
+ status: NativeUltragoalBootstrapStatus;
+ session_id: string;
+ root_thread_id: string;
+ child_agent_id?: string;
+ created_at: string;
+ updated_at: string;
+ expires_at: string;
+ reason?: string;
+}
+
+export interface LocalNativeExecutorAssignment {
+ schema_version: 1;
+ kind: 'native-subagent-assignment';
+ lifecycle: 'active' | 'revoked' | 'expired';
+ root_session_id: string;
+ root_thread_id: string;
+ child_agent_id: string;
+ agent_type: 'executor';
+ allowed_actions: Array<'path-write' | 'bash-write'>;
+ path_prefixes: string[];
+ issued_at: string;
+ expires_at: string;
+ bootstrap_generation: string;
+ revoked_at?: string;
+ revoke_reason?: string;
+}
+
+export interface HostNativeExecutorReceiptVerifier {
+ readonly available: boolean;
+ verifyActivationReceipt(input: {
+ cwd: string;
+ sessionId: string;
+ rootThreadId: string;
+ }): Promise<{ ok: true; childAgentId: string } | { ok: false; reason: string }>;
+}
+
+const ACTIVE_ASSIGNMENT_SCHEMA_KEYS = new Set([
+ 'schema_version',
+ 'kind',
+ 'lifecycle',
+ 'root_session_id',
+ 'root_thread_id',
+ 'child_agent_id',
+ 'agent_type',
+ 'allowed_actions',
+ 'path_prefixes',
+ 'issued_at',
+ 'expires_at',
+ 'bootstrap_generation',
+]);
+const MAX_ASSIGNMENT_LIFETIME_MS = 24 * 60 * 60 * 1000;
+
+export const unavailableHostNativeExecutorReceiptVerifier: HostNativeExecutorReceiptVerifier = {
+ available: false,
+ async verifyActivationReceipt() {
+ return { ok: false, reason: DOCUMENTED_HOST_RECEIPT_UNAVAILABLE };
+ },
+};
+
+function bootstrapPath(stateDir: string, sessionId: string): string {
+ return join(stateDir, 'sessions', sessionId, NATIVE_ULTRAGOAL_BOOTSTRAP_FILE);
+}
+
+async function withNativeUltragoalLifecycleLock<T>(
+ stateDir: string,
+ sessionId: string,
+ operation: () => Promise<T>,
+): Promise<T> {
+ const handle = await acquireCrossProcessFileLock(bootstrapPath(stateDir, sessionId), {
+ maxAttempts: 200,
+ retryMs: 25,
+ preserveLiveLocalOwner: true,
+ });
+ try {
+ const result = await operation();
+ handle.assertOwnership();
+ return result;
+ } finally {
+ handle.release();
+ }
+}
+
+export function nativeExecutorAssignmentPath(stateDir: string, sessionId: string, childAgentId: string): string {
+ return join(
+ stateDir,
+ 'sessions',
+ sessionId,
+ NATIVE_ASSIGNMENT_DIRECTORY,
+ `${encodeURIComponent(childAgentId)}.json`,
+ );
+}
+
+async function writeJsonAtomic(path: string, value: unknown, mode = 0o600): Promise<void> {
+ await mkdir(dirname(path), { recursive: true, mode: 0o700 });
+ const tmpPath = `${path}.tmp.${process.pid}.${Date.now()}.${randomUUID()}`;
+ await writeFile(tmpPath, `${JSON.stringify(value, null, 2)}\n`, { encoding: 'utf-8', mode });
+ try {
+ await chmod(tmpPath, mode);
+ await rename(tmpPath, path);
+ } catch (error) {
+ await unlink(tmpPath).catch(() => {});
+ throw error;
+ }
+}
+
+async function readJsonObject(path: string): Promise<Record<string, unknown> | null> {
+ try {
+ const parsed = JSON.parse(await readFile(path, 'utf-8')) as unknown;
+ return parsed && typeof parsed === 'object' && !Array.isArray(parsed)
+ ? parsed as Record<string, unknown>
+ : null;
+ } catch {
+ return null;
+ }
+}
+
+function readString(value: unknown): string {
+ return typeof value === 'string' ? value.trim() : '';
+}
+
+function normalizePrefix(cwd: string, rawPrefix: string): string | null {
+ const trimmed = rawPrefix.trim().replace(/\\/g, '/');
+ if (trimmed === '.') return '.';
+ if (!trimmed || isAbsolute(trimmed) || trimmed.includes('\0') || /[$`*?\[\]{}]/.test(trimmed)) return null;
+ const absolute = resolve(cwd, trimmed);
+ const normalized = relative(cwd, absolute).replace(/\\/g, '/');
+ if (!normalized || normalized === '..' || normalized.startsWith('../')) return null;
+ if (
+ normalized === '.git'
+ || normalized.startsWith('.git/')
+ || normalized === '.omx'
+ || normalized.startsWith('.omx/')
+ ) return null;
+ return normalized;
+}
+
+async function pathPrefixTraversesUnsafeLink(cwd: string, relativePath: string): Promise<boolean> {
+ if (relativePath === '.') return false;
+ let current = resolve(cwd);
+ for (const segment of relativePath.split('/').filter(Boolean)) {
+ current = join(current, segment);
+ try {
+ const metadata = await lstat(current);
+ if (metadata.isSymbolicLink() || (!metadata.isDirectory() && metadata.nlink > 1)) return true;
+ } catch (error) {
+ if ((error as NodeJS.ErrnoException).code === 'ENOENT') continue;
+ return true;
+ }
+ }
+ return false;
+}
+
+export async function parseActiveLocalNativeExecutorAssignment(
+ raw: Record<string, unknown> | null,
+ input: {
+ cwd: string;
+ sessionId: string;
+ rootThreadId: string;
+ childAgentId: string;
+ agentType: string;
+ nowMs?: number;
+ },
+): Promise<(LocalNativeExecutorAssignment & { lifecycle: 'active' }) | null> {
+ if (!raw || Object.keys(raw).some((key) => !ACTIVE_ASSIGNMENT_SCHEMA_KEYS.has(key))) return null;
+ if (
+ raw.schema_version !== 1
+ || raw.kind !== 'native-subagent-assignment'
+ || raw.lifecycle !== 'active'
+ || readString(raw.root_session_id) !== input.sessionId
+ || readString(raw.root_thread_id) !== input.rootThreadId
+ || readString(raw.child_agent_id) !== input.childAgentId
+ || readString(raw.agent_type).toLowerCase() !== 'executor'
+ || input.agentType.trim().toLowerCase() !== 'executor'
+ || !readString(raw.bootstrap_generation)
+ ) return null;
+
+ const nowMs = input.nowMs ?? Date.now();
+ const issuedAt = Date.parse(readString(raw.issued_at));
+ const expiresAt = Date.parse(readString(raw.expires_at));
+ if (
+ !Number.isFinite(issuedAt)
+ || !Number.isFinite(expiresAt)
+ || issuedAt > nowMs + 30_000
+ || expiresAt <= nowMs
+ || expiresAt <= issuedAt
+ || expiresAt - issuedAt > MAX_ASSIGNMENT_LIFETIME_MS
+ ) return null;
+
+ const allowedActions = Array.isArray(raw.allowed_actions)
+ ? raw.allowed_actions.map((value) => readString(value))
+ : [];
+ if (
+ allowedActions.length === 0
+ || allowedActions.length > 2
+ || new Set(allowedActions).size !== allowedActions.length
+ || allowedActions.some((action) => action !== 'path-write' && action !== 'bash-write')
+ ) return null;
+
+ const pathPrefixes = Array.isArray(raw.path_prefixes)
+ ? raw.path_prefixes.map((value) => normalizePrefix(input.cwd, readString(value)))
+ : [];
+ if (
+ pathPrefixes.length === 0
+ || pathPrefixes.length > 32
+ || pathPrefixes.some((prefix) => prefix === null)
+ || new Set(pathPrefixes).size !== pathPrefixes.length
+ ) return null;
+ for (const prefix of pathPrefixes as string[]) {
+ if (await pathPrefixTraversesUnsafeLink(input.cwd, prefix)) return null;
+ }
+
+ return {
+ schema_version: 1,
+ kind: 'native-subagent-assignment',
+ lifecycle: 'active',
+ root_session_id: input.sessionId,
+ root_thread_id: input.rootThreadId,
+ child_agent_id: input.childAgentId,
+ agent_type: 'executor',
+ allowed_actions: allowedActions as Array<'path-write' | 'bash-write'>,
+ path_prefixes: pathPrefixes as string[],
+ issued_at: new Date(issuedAt).toISOString(),
+ expires_at: new Date(expiresAt).toISOString(),
+ bootstrap_generation: readString(raw.bootstrap_generation),
+ };
+}
+
+function parseBootstrap(raw: Record<string, unknown> | null): NativeUltragoalBootstrapState | null {
+ if (
+ raw?.schema_version !== 1
+ || raw.kind !== 'native-ultragoal-bootstrap'
+ || !readString(raw.generation)
+ || !['off', 'host', 'local-experimental'].includes(readString(raw.backend))
+ || ![
+ 'awaiting-executor', 'ready', 'activating', 'active', 'revoked', 'expired', 'host-receipt-unavailable',
+ ].includes(readString(raw.status))
+ || !readString(raw.session_id)
+ || !readString(raw.root_thread_id)
+ || !readString(raw.created_at)
+ || !readString(raw.updated_at)
+ || !readString(raw.expires_at)
+ || !Number.isFinite(Date.parse(readString(raw.expires_at)))
+ ) return null;
+ return raw as unknown as NativeUltragoalBootstrapState;
+}
+
+function parseAssignment(raw: Record<string, unknown> | null): LocalNativeExecutorAssignment | null {
+ if (
+ raw?.schema_version !== 1
+ || raw.kind !== 'native-subagent-assignment'
+ || !['active', 'revoked', 'expired'].includes(readString(raw.lifecycle))
+ || raw.agent_type !== 'executor'
+ || !Array.isArray(raw.allowed_actions)
+ || !Array.isArray(raw.path_prefixes)
+ || !readString(raw.root_session_id)
+ || !readString(raw.root_thread_id)
+ || !readString(raw.child_agent_id)
+ || !readString(raw.issued_at)
+ || !readString(raw.expires_at)
+ || !readString(raw.bootstrap_generation)
+ || !Number.isFinite(Date.parse(readString(raw.expires_at)))
+ ) return null;
+ return raw as unknown as LocalNativeExecutorAssignment;
+}
+
+async function beginNativeUltragoalBootstrapUnlocked(input: {
+ cwd: string;
+ stateDir: string;
+ sessionId: string;
+ rootThreadId: string;
+ backend: NativeUltragoalBackend;
+ ttlSeconds: number;
+ now?: Date;
+}): Promise<NativeUltragoalBootstrapState> {
+ const now = input.now ?? new Date();
+ const cwd = input.cwd;
+ ensureExactDescriptiveLeaderForSession(cwd, {
+ sessionId: input.sessionId,
+ rootThreadId: input.rootThreadId,
+ timestamp: now.toISOString(),
+ });
+ const existing = parseBootstrap(await readJsonObject(bootstrapPath(input.stateDir, input.sessionId)));
+ if (
+ existing
+ && existing.session_id === input.sessionId
+ && existing.root_thread_id === input.rootThreadId
+ && existing.backend === input.backend
+ && Date.parse(existing.expires_at) > now.getTime()
+ && ['awaiting-executor', 'ready', 'activating', 'active'].includes(existing.status)
+ ) return existing;
+
+ if (existing?.child_agent_id) {
+ const staleAssignmentPath = nativeExecutorAssignmentPath(
+ input.stateDir,
+ input.sessionId,
+ existing.child_agent_id,
+ );
+ const staleAssignment = parseAssignment(await readJsonObject(staleAssignmentPath));
+ if (staleAssignment?.lifecycle === 'active') {
+ await transitionAssignment(
+ staleAssignmentPath,
+ staleAssignment,
+ Date.parse(existing.expires_at) <= now.getTime() ? 'expired' : 'revoked',
+ 'bootstrap_replaced',
+ now,
+ );
+ }
+ }
+
+ const state: NativeUltragoalBootstrapState = {
+ schema_version: 1,
+ kind: 'native-ultragoal-bootstrap',
+ generation: randomUUID(),
+ backend: input.backend,
+ status: input.backend === 'host' ? 'host-receipt-unavailable' : 'awaiting-executor',
+ session_id: input.sessionId,
+ root_thread_id: input.rootThreadId,
+ created_at: now.toISOString(),
+ updated_at: now.toISOString(),
+ expires_at: new Date(now.getTime() + input.ttlSeconds * 1000).toISOString(),
+ ...(input.backend === 'host' ? { reason: DOCUMENTED_HOST_RECEIPT_UNAVAILABLE } : {}),
+ };
+ await writeJsonAtomic(bootstrapPath(input.stateDir, input.sessionId), state);
+ return state;
+}
+
+export async function beginNativeUltragoalBootstrap(
+ input: Parameters<typeof beginNativeUltragoalBootstrapUnlocked>[0],
+): Promise<NativeUltragoalBootstrapState> {
+ return withNativeUltragoalLifecycleLock(input.stateDir, input.sessionId, () => (
+ beginNativeUltragoalBootstrapUnlocked(input)
+ ));
+}
+
+export async function readNativeUltragoalBootstrap(
+ stateDir: string,
+ sessionId: string,
+): Promise<NativeUltragoalBootstrapState | null> {
+ return parseBootstrap(await readJsonObject(bootstrapPath(stateDir, sessionId)));
+}
+
+export async function validateLocalNativeExecutorIdentity(input: {
+ cwd: string;
+ sessionId: string;
+ rootThreadId: string;
+ childAgentId: string;
+ receiptNotBefore?: string;
+ receiptNotAfter?: string;
+}): Promise<{ ok: true } | { ok: false; reason: string }> {
+ const tracking = await readSubagentTrackingState(input.cwd).catch(() => null);
+ const session = tracking?.sessions?.[input.sessionId];
+ const child = session?.threads?.[input.childAgentId];
+ if (!session || session.leader_thread_id !== input.rootThreadId) {
+ return { ok: false, reason: 'leader_session_mismatch' };
+ }
+ if (isNativeSubagentAuthorityFenced(input.cwd, input.childAgentId)) {
+ return { ok: false, reason: 'child_authority_fenced' };
+ }
+ if (child) {
+ if (child.kind !== 'subagent') return { ok: false, reason: 'child_not_tracked' };
+ if (child.reopen_authority_revoked === true) return { ok: false, reason: 'child_authority_revoked' };
+ if (child.status && child.status !== 'available') return { ok: false, reason: `child_${child.status}` };
+ if (child.completed_at) return { ok: false, reason: 'child_completed' };
+ const role = readString(child.mode || child.role).toLowerCase();
+ if (role && role !== 'executor') return { ok: false, reason: 'child_role_mismatch' };
+ const carriesAuthority = child.provenance_kind === NATIVE_SUBAGENT_PROVENANCE
+ || child.direct_child_parent_id !== undefined
+ || child.direct_child_root_id !== undefined;
+ if (carriesAuthority) {
+ if (role !== 'executor') return { ok: false, reason: 'child_role_mismatch' };
+ if (child.provenance_kind !== NATIVE_SUBAGENT_PROVENANCE) {
+ return { ok: false, reason: 'child_native_authority_unproven' };
+ }
+ if (child.direct_child_parent_id !== input.rootThreadId) {
+ return { ok: false, reason: 'child_parent_mismatch' };
+ }
+ if (child.direct_child_root_id !== input.rootThreadId) {
+ return { ok: false, reason: 'child_root_mismatch' };
+ }
+ return { ok: true };
+ }
+ }
+
+ if (!readString(input.receiptNotBefore) || !readString(input.receiptNotAfter)) {
+ return { ok: false, reason: 'child_transcript_receipt_unbound' };
+ }
+
+ // Codex App v2 currently puts the canonical child id and typed direct-parent
+ // receipt in the child rollout session_meta, while SessionStart reports the
+ // root session id. local-experimental may consume that same-user receipt for
+ // this scoped assignment only; it never promotes the child into persisted
+ // reopen authority in subagent-tracking.json.
+ const transcriptReceipt = await validateLocalCodexAppExecutorTranscript(input);
+ if (transcriptReceipt.ok) return transcriptReceipt;
+ return {
+ ok: false,
+ reason: transcriptReceipt.reason || (child ? 'child_native_authority_unproven' : 'child_not_tracked'),
+ };
+}
+
+const MAX_LOCAL_TRANSCRIPT_FIRST_LINE_BYTES = 64 * 1024;
+const MAX_LOCAL_TRANSCRIPT_SCAN_ENTRIES = 10_000;
+const CANONICAL_CODEX_THREAD_ID = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/;
+
+export type LocalNativeExecutorChildReceiptResolution =
+ | { ok: true; childAgentId: string }
+ | { ok: false; reason: string };
+
+function readUniqueStringAlias(
+ value: Record<string, unknown> | null,
+ aliases: string[],
+): { present: false } | { present: true; valid: false } | { present: true; valid: true; value: string } {
+ if (!value) return { present: false };
+ const present = aliases.filter((alias) => Object.prototype.hasOwnProperty.call(value, alias));
+ if (present.length === 0) return { present: false };
+ const values = present.map((alias) => readString(value[alias]));
+ if (values.some((candidate) => !candidate) || new Set(values).size !== 1) {
+ return { present: true, valid: false };
+ }
+ return { present: true, valid: true, value: values[0]! };
+}
+
+async function readBoundedTranscriptSessionMeta(path: string): Promise<Record<string, unknown> | null> {
+ const metadata = await lstat(path).catch(() => null);
+ if (
+ !metadata
+ || !metadata.isFile()
+ || metadata.isSymbolicLink()
+ || metadata.nlink !== 1
+ || (metadata.mode & 0o022) !== 0
+ ) return null;
+
+ const handle = await open(path, fsConstants.O_RDONLY | (fsConstants.O_NOFOLLOW ?? 0)).catch(() => null);
+ if (!handle) return null;
+ try {
+ const openedMetadata = await handle.stat();
+ if (
+ !openedMetadata.isFile()
+ || openedMetadata.nlink !== 1
+ || (openedMetadata.mode & 0o022) !== 0
+ || openedMetadata.dev !== metadata.dev
+ || openedMetadata.ino !== metadata.ino
+ ) return null;
+ const buffer = Buffer.alloc(MAX_LOCAL_TRANSCRIPT_FIRST_LINE_BYTES);
+ const { bytesRead } = await handle.read(buffer, 0, buffer.length, 0);
+ const newline = buffer.subarray(0, bytesRead).indexOf(0x0a);
+ if (newline < 0) return null;
+ const line = buffer.subarray(0, newline).toString('utf8').trim();
+ if (!line) return null;
+ const parsed = JSON.parse(line) as unknown;
+ const finalMetadata = await handle.stat();
+ if (
+ finalMetadata.dev !== openedMetadata.dev
+ || finalMetadata.ino !== openedMetadata.ino
+ || finalMetadata.mode !== openedMetadata.mode
+ || finalMetadata.nlink !== openedMetadata.nlink
+ || finalMetadata.size !== openedMetadata.size
+ || finalMetadata.mtimeMs !== openedMetadata.mtimeMs
+ || finalMetadata.ctimeMs !== openedMetadata.ctimeMs
+ ) return null;
+ return parsed && typeof parsed === 'object' && !Array.isArray(parsed)
+ ? parsed as Record<string, unknown>
+ : null;
+ } catch {
+ return null;
+ } finally {
+ await handle.close().catch(() => {});
+ }
+}
+
+async function findLocalCodexTranscriptPaths(
+ childAgentId: string,
+): Promise<{ paths: string[]; complete: boolean }> {
+ const codexHome = process.env.CODEX_HOME?.trim() || join(homedir(), '.codex');
+ const suffix = `-${childAgentId}.jsonl`;
+ const matches: string[] = [];
+ let visited = 0;
+ const pending = [{ path: join(codexHome, 'sessions'), depth: 0 }];
+
+ while (pending.length > 0) {
+ const current = pending.shift()!;
+ let entries: Dirent[];
+ try {
+ entries = await readdir(current.path, { withFileTypes: true });
+ } catch {
+ return { paths: matches, complete: false };
+ }
+ if (visited + entries.length > MAX_LOCAL_TRANSCRIPT_SCAN_ENTRIES) {
+ return { paths: matches, complete: false };
+ }
+ visited += entries.length;
+ for (const entry of entries) {
+ const path = join(current.path, entry.name);
+ if (entry.isDirectory() && current.depth < 4) {
+ pending.push({ path, depth: current.depth + 1 });
+ } else if (entry.isFile() && entry.name.endsWith(suffix)) {
+ matches.push(path);
+ if (matches.length > 1) return { paths: matches, complete: true };
+ }
+ }
+ }
+ return { paths: matches, complete: true };
+}
+
+async function findLiveLocalCodexTranscriptPaths(): Promise<{ paths: string[]; complete: boolean }> {
+ const codexHome = process.env.CODEX_HOME?.trim() || join(homedir(), '.codex');
+ const matches: string[] = [];
+ let visited = 0;
+ const pending = [{ path: join(codexHome, 'sessions'), depth: 0 }];
+
+ while (pending.length > 0) {
+ const current = pending.shift()!;
+ let entries: Dirent[];
+ try {
+ entries = await readdir(current.path, { withFileTypes: true });
+ } catch {
+ return { paths: matches, complete: false };
+ }
+ if (visited + entries.length > MAX_LOCAL_TRANSCRIPT_SCAN_ENTRIES) {
+ return { paths: matches, complete: false };
+ }
+ visited += entries.length;
+ for (const entry of entries) {
+ const path = join(current.path, entry.name);
+ if (entry.isDirectory() && current.depth < 4) {
+ pending.push({ path, depth: current.depth + 1 });
+ } else if (entry.isFile() && entry.name.startsWith('rollout-') && entry.name.endsWith('.jsonl')) {
+ matches.push(path);
+ }
+ }
+ }
+ return { paths: matches, complete: true };
+}
+
+/**
+ * Resolve a typed executor's canonical child id from the App-owned rollout.
+ * The supplied agent path is only a lookup key; every authority-bearing field
+ * is re-attested from one safe, unique, generation-bounded session_meta record.
+ */
+export async function resolveLocalNativeExecutorChildReceipt(input: {
+ cwd: string;
+ sessionId: string;
+ rootThreadId: string;
+ agentPath: string;
+ receiptNotBefore: string;
+ receiptNotAfter: string;
+ now?: Date;
+}): Promise<LocalNativeExecutorChildReceiptResolution> {
+ const requestedAgentPath = readString(input.agentPath);
+ const notBefore = Date.parse(readString(input.receiptNotBefore));
+ const notAfter = Date.parse(readString(input.receiptNotAfter));
+ if (
+ !requestedAgentPath
+ || !Number.isFinite(notBefore)
+ || !Number.isFinite(notAfter)
+ || notAfter < notBefore
+ ) return { ok: false, reason: 'child_transcript_receipt_unbound' };
+
+ const canonicalInputCwd = await realpath(input.cwd).catch(() => '');
+ if (!canonicalInputCwd) return { ok: false, reason: 'child_transcript_receipt_cwd_invalid' };
+ const nowMs = (input.now ?? new Date()).getTime();
+ const matches: string[] = [];
+
+ const scan = await findLiveLocalCodexTranscriptPaths();
+ if (!scan.complete) return { ok: false, reason: 'child_transcript_receipt_scan_incomplete' };
+ for (const path of scan.paths) {
+ const record = await readBoundedTranscriptSessionMeta(path);
+ if (!record || record.type !== 'session_meta') continue;
+ const payload = record.payload && typeof record.payload === 'object' && !Array.isArray(record.payload)
+ ? record.payload as Record<string, unknown>
+ : null;
+ const source = payload?.source && typeof payload.source === 'object' && !Array.isArray(payload.source)
+ ? payload.source as Record<string, unknown>
+ : null;
+ const subagent = source?.subagent && typeof source.subagent === 'object' && !Array.isArray(source.subagent)
+ ? source.subagent as Record<string, unknown>
+ : null;
+ const spawn = subagent?.thread_spawn && typeof subagent.thread_spawn === 'object' && !Array.isArray(subagent.thread_spawn)
+ ? subagent.thread_spawn as Record<string, unknown>
+ : null;
+ const agentPath = readUniqueStringAlias(spawn, ['agent_path', 'agentPath']);
+ if (!agentPath.present || !agentPath.valid || agentPath.value !== requestedAgentPath) continue;
+
+ const childId = readUniqueStringAlias(payload, ['id']);
+ const sessionClaim = readUniqueStringAlias(payload, ['session_id', 'sessionId']);
+ const cwdClaim = readUniqueStringAlias(payload, ['cwd']);
+ const parentClaim = readUniqueStringAlias(spawn, ['parent_thread_id', 'parentThreadId']);
+ const roleClaim = readUniqueStringAlias(spawn, ['agent_role', 'agentRole', 'agent_type', 'agentType']);
+ const timestamp = Date.parse(readString(record.timestamp));
+ const canonicalReceiptCwd = cwdClaim.present && cwdClaim.valid
+ ? await realpath(cwdClaim.value).catch(() => '')
+ : '';
+ if (
+ !childId.present || !childId.valid || !CANONICAL_CODEX_THREAD_ID.test(childId.value)
+ || !path.endsWith(`-${childId.value}.jsonl`)
+ || !sessionClaim.present || !sessionClaim.valid
+ || (sessionClaim.value !== input.sessionId && sessionClaim.value !== input.rootThreadId)
+ || !parentClaim.present || !parentClaim.valid || parentClaim.value !== input.rootThreadId
+ || spawn?.depth !== 1
+ || !roleClaim.present || !roleClaim.valid || roleClaim.value.toLowerCase() !== 'executor'
+ || !canonicalReceiptCwd || canonicalReceiptCwd !== canonicalInputCwd
+ || !Number.isFinite(timestamp) || timestamp < notBefore || timestamp > notAfter
+ || timestamp > nowMs + 30_000
+ ) continue;
+ matches.push(childId.value);
+ if (matches.length > 1) return { ok: false, reason: 'child_transcript_receipt_ambiguous' };
+ }
+
+ return matches.length === 1
+ ? { ok: true, childAgentId: matches[0]! }
+ : { ok: false, reason: 'child_transcript_receipt_missing' };
+}
+
+async function validateLocalCodexAppExecutorTranscript(input: {
+ cwd: string;
+ sessionId: string;
+ rootThreadId: string;
+ childAgentId: string;
+ receiptNotBefore?: string;
+ receiptNotAfter?: string;
+}): Promise<{ ok: true } | { ok: false; reason: string }> {
+ const scan = await findLocalCodexTranscriptPaths(input.childAgentId);
+ if (!scan.complete) return { ok: false, reason: 'child_transcript_receipt_scan_incomplete' };
+ const paths = scan.paths;
+ if (paths.length === 0) return { ok: false, reason: 'child_transcript_receipt_missing' };
+ if (paths.length !== 1) return { ok: false, reason: 'child_transcript_receipt_ambiguous' };
+ const record = await readBoundedTranscriptSessionMeta(paths[0]!);
+ if (!record || record.type !== 'session_meta') {
+ return { ok: false, reason: 'child_transcript_receipt_invalid' };
+ }
+ const payload = record.payload && typeof record.payload === 'object' && !Array.isArray(record.payload)
+ ? record.payload as Record<string, unknown>
+ : null;
+ const source = payload?.source && typeof payload.source === 'object' && !Array.isArray(payload.source)
+ ? payload.source as Record<string, unknown>
+ : null;
+ const subagent = source?.subagent && typeof source.subagent === 'object' && !Array.isArray(source.subagent)
+ ? source.subagent as Record<string, unknown>
+ : null;
+ const spawn = subagent?.thread_spawn && typeof subagent.thread_spawn === 'object' && !Array.isArray(subagent.thread_spawn)
+ ? subagent.thread_spawn as Record<string, unknown>
+ : null;
+ const receiptSessionId = readString(payload?.session_id ?? payload?.sessionId);
+ const receiptCwd = readString(payload?.cwd);
+ const receiptTimestamp = Date.parse(readString(record.timestamp));
+ const receiptNotBefore = Date.parse(readString(input.receiptNotBefore));
+ const receiptNotAfter = Date.parse(readString(input.receiptNotAfter));
+ const [canonicalReceiptCwd, canonicalInputCwd] = receiptCwd
+ ? await Promise.all([realpath(receiptCwd).catch(() => ''), realpath(input.cwd).catch(() => '')])
+ : ['', ''];
+ const role = readString(spawn?.agent_role ?? spawn?.agentRole ?? spawn?.agent_type ?? spawn?.agentType).toLowerCase();
+ if (
+ readString(payload?.id) !== input.childAgentId
+ || (receiptSessionId !== input.sessionId && receiptSessionId !== input.rootThreadId)
+ || !Number.isFinite(receiptTimestamp)
+ || !Number.isFinite(receiptNotBefore)
+ || !Number.isFinite(receiptNotAfter)
+ || receiptTimestamp < receiptNotBefore
+ || receiptTimestamp > receiptNotAfter
+ || receiptTimestamp > Date.now() + 30_000
+ || !canonicalReceiptCwd
+ || canonicalReceiptCwd !== canonicalInputCwd
+ || readString(spawn?.parent_thread_id ?? spawn?.parentThreadId) !== input.rootThreadId
+ || spawn?.depth !== 1
+ || role !== 'executor'
+ ) return { ok: false, reason: 'child_transcript_receipt_mismatch' };
+ return { ok: true };
+}
+
+async function issueLocalNativeExecutorAssignmentUnlocked(input: {
+ cwd: string;
+ stateDir: string;
+ sessionId: string;
+ rootThreadId: string;
+ childAgentId: string;
+ expectedGeneration: string;
+ pathPrefixes: string[];
+ ttlSeconds: number;
+ allowedActions?: Array<'path-write' | 'bash-write'>;
+ now?: Date;
+}): Promise<LocalNativeExecutorAssignment> {
+ const now = input.now ?? new Date();
+ if (!Number.isInteger(input.ttlSeconds) || input.ttlSeconds < 30 || input.ttlSeconds > 3600) {
+ throw new Error('invalid_native_assignment_ttl');
+ }
+ let bootstrap = await readNativeUltragoalBootstrap(input.stateDir, input.sessionId);
+ const wasActive = bootstrap?.status === 'active';
+ if (
+ !bootstrap
+ || bootstrap.backend !== 'local-experimental'
+ || bootstrap.session_id !== input.sessionId
+ || bootstrap.root_thread_id !== input.rootThreadId
+ || bootstrap.generation !== input.expectedGeneration
+ || !['awaiting-executor', 'ready', 'active'].includes(bootstrap.status)
+ || Date.parse(bootstrap.expires_at) <= now.getTime()
+ ) throw new Error('native_ultragoal_bootstrap_not_ready');
+
+ const tracked = await validateLocalNativeExecutorIdentity({
+ ...input,
+ receiptNotBefore: bootstrap.created_at,
+ receiptNotAfter: bootstrap.expires_at,
+ });
+ if (!tracked.ok) throw new Error(tracked.reason);
+ const normalizedPrefixes = input.pathPrefixes.map((prefix) => normalizePrefix(input.cwd, prefix));
+ if (
+ normalizedPrefixes.length === 0
+ || normalizedPrefixes.length > 32
+ || normalizedPrefixes.some((prefix) => prefix === null)
+ || new Set(normalizedPrefixes).size !== normalizedPrefixes.length
+ ) throw new Error('invalid_native_assignment_path_prefixes');
+ for (const prefix of normalizedPrefixes as string[]) {
+ if (await pathPrefixTraversesUnsafeLink(input.cwd, prefix)) {
+ throw new Error('invalid_native_assignment_path_prefixes');
+ }
+ }
+ const actions = input.allowedActions ?? ['path-write', 'bash-write'];
+ if (
+ actions.length === 0
+ || actions.length > 2
+ || new Set(actions).size !== actions.length
+ || actions.some((action) => action !== 'path-write' && action !== 'bash-write')
+ ) throw new Error('invalid_native_assignment_actions');
+ await recordSubagentTurnForSession(input.cwd, {
+ sessionId: input.sessionId,
+ threadId: input.childAgentId,
+ kind: 'subagent',
+ leaderThreadId: input.rootThreadId,
+ mode: 'executor',
+ });
+ const requestedExpiry = now.getTime() + input.ttlSeconds * 1000;
+ const expiresAt = wasActive
+ ? requestedExpiry
+ : Math.min(requestedExpiry, Date.parse(bootstrap.expires_at));
+ const assignment: LocalNativeExecutorAssignment = {
+ schema_version: 1,
+ kind: 'native-subagent-assignment',
+ lifecycle: 'active',
+ root_session_id: input.sessionId,
+ root_thread_id: input.rootThreadId,
+ child_agent_id: input.childAgentId,
+ agent_type: 'executor',
+ allowed_actions: actions,
+ path_prefixes: normalizedPrefixes as string[],
+ issued_at: now.toISOString(),
+ expires_at: new Date(expiresAt).toISOString(),
+ bootstrap_generation: bootstrap.generation,
+ };
+ await writeJsonAtomic(
+ nativeExecutorAssignmentPath(input.stateDir, input.sessionId, input.childAgentId),
+ assignment,
+ );
+ await writeJsonAtomic(bootstrapPath(input.stateDir, input.sessionId), {
+ ...bootstrap,
+ status: wasActive ? 'active' : 'ready',
+ child_agent_id: input.childAgentId,
+ updated_at: now.toISOString(),
+ ...(wasActive ? { expires_at: new Date(expiresAt).toISOString(), reason: undefined } : {}),
+ });
+ return assignment;
+}
+
+export async function issueLocalNativeExecutorAssignment(
+ input: Parameters<typeof issueLocalNativeExecutorAssignmentUnlocked>[0],
+): Promise<LocalNativeExecutorAssignment> {
+ return withNativeUltragoalLifecycleLock(input.stateDir, input.sessionId, () => (
+ issueLocalNativeExecutorAssignmentUnlocked(input)
+ ));
+}
+
+export async function nativeExecutorAssignmentFileIsSafe(stateDir: string, path: string): Promise<boolean> {
+ try {
+ const relativePath = relative(resolve(stateDir), resolve(path)).replace(/\\/g, '/');
+ if (!relativePath || relativePath === '..' || relativePath.startsWith('../')) return false;
+ let current = resolve(stateDir);
+ for (const segment of relativePath.split('/').filter(Boolean)) {
+ current = join(current, segment);
+ const metadata = await lstat(current);
+ if (metadata.isSymbolicLink()) return false;
+ if (current === resolve(path)) {
+ if (!metadata.isFile() || metadata.nlink !== 1 || (metadata.mode & 0o022) !== 0 || metadata.size > 64 * 1024) {
+ return false;
+ }
+ } else if (!metadata.isDirectory()) return false;
+ }
+ await access(path, fsConstants.R_OK);
+ return true;
+ } catch {
+ return false;
+ }
+}
+
+async function transitionAssignment(
+ path: string,
+ assignment: LocalNativeExecutorAssignment,
+ lifecycle: 'revoked' | 'expired',
+ reason: string,
+ now = new Date(),
+): Promise<LocalNativeExecutorAssignment> {
+ const next: LocalNativeExecutorAssignment = {
+ ...assignment,
+ lifecycle,
+ revoked_at: now.toISOString(),
+ revoke_reason: reason,
+ };
+ await writeJsonAtomic(path, next);
+ return next;
+}
+
+async function findReadyLocalNativeExecutorAssignmentUnlocked(input: {
+ cwd: string;
+ stateDir: string;
+ sessionId: string;
+ rootThreadId: string;
+ now?: Date;
+}): Promise<LocalNativeExecutorAssignment | null> {
+ const now = input.now ?? new Date();
+ const bootstrap = await readNativeUltragoalBootstrap(input.stateDir, input.sessionId);
+ if (
+ !bootstrap
+ || bootstrap.backend !== 'local-experimental'
+ || bootstrap.root_thread_id !== input.rootThreadId
+ || !bootstrap.child_agent_id
+ || !['ready', 'activating', 'active'].includes(bootstrap.status)
+ || Date.parse(bootstrap.expires_at) <= now.getTime()
+ ) return null;
+ const path = nativeExecutorAssignmentPath(input.stateDir, input.sessionId, bootstrap.child_agent_id);
+ if (!await nativeExecutorAssignmentFileIsSafe(input.stateDir, path)) return null;
+ const rawAssignment = await readJsonObject(path);
+ const transitionableAssignment = parseAssignment(rawAssignment);
+ if (
+ transitionableAssignment?.lifecycle === 'active'
+ && Date.parse(transitionableAssignment.expires_at) <= now.getTime()
+ ) {
+ await transitionAssignment(path, transitionableAssignment, 'expired', 'assignment_expired', now);
+ return null;
+ }
+ const assignment = await parseActiveLocalNativeExecutorAssignment(rawAssignment, {
+ cwd: input.cwd,
+ sessionId: input.sessionId,
+ rootThreadId: input.rootThreadId,
+ childAgentId: bootstrap.child_agent_id,
+ agentType: 'executor',
+ nowMs: now.getTime(),
+ });
+ if (!assignment || assignment.bootstrap_generation !== bootstrap.generation) return null;
+ const tracked = await validateLocalNativeExecutorIdentity({
+ cwd: input.cwd,
+ sessionId: input.sessionId,
+ rootThreadId: input.rootThreadId,
+ childAgentId: assignment.child_agent_id,
+ receiptNotBefore: bootstrap.created_at,
+ receiptNotAfter: bootstrap.expires_at,
+ });
+ if (!tracked.ok) {
+ await transitionAssignment(path, assignment, 'revoked', tracked.reason, now);
+ return null;
+ }
+ return assignment;
+}
+
+export async function findReadyLocalNativeExecutorAssignment(
+ input: Parameters<typeof findReadyLocalNativeExecutorAssignmentUnlocked>[0],
+): Promise<LocalNativeExecutorAssignment | null> {
+ return withNativeUltragoalLifecycleLock(input.stateDir, input.sessionId, () => (
+ findReadyLocalNativeExecutorAssignmentUnlocked(input)
+ ));
+}
+
+async function validateNativeUltragoalActivationReceipt(input: {
+ cwd: string;
+ stateDir: string;
+ sessionId: string;
+ childAgentId: string;
+ now?: Date;
+}, allowedStatuses: NativeUltragoalBootstrapStatus[]): Promise<{
+ ok: true;
+ assignment: LocalNativeExecutorAssignment;
+ bootstrap: NativeUltragoalBootstrapState;
+} | { ok: false }> {
+ const bootstrap = await readNativeUltragoalBootstrap(input.stateDir, input.sessionId);
+ if (
+ !bootstrap
+ || !allowedStatuses.includes(bootstrap.status)
+ || bootstrap.child_agent_id !== input.childAgentId
+ ) return { ok: false };
+ const now = input.now ?? new Date();
+ if (Date.parse(bootstrap.expires_at) <= now.getTime()) return { ok: false };
+ const assignmentPath = nativeExecutorAssignmentPath(input.stateDir, input.sessionId, input.childAgentId);
+ if (!await nativeExecutorAssignmentFileIsSafe(input.stateDir, assignmentPath)) return { ok: false };
+ const assignment = await parseActiveLocalNativeExecutorAssignment(await readJsonObject(assignmentPath), {
+ cwd: input.cwd,
+ sessionId: input.sessionId,
+ rootThreadId: bootstrap.root_thread_id,
+ childAgentId: input.childAgentId,
+ agentType: 'executor',
+ nowMs: now.getTime(),
+ });
+ if (
+ !assignment
+ || assignment.bootstrap_generation !== bootstrap.generation
+ ) return { ok: false };
+ const tracked = await validateLocalNativeExecutorIdentity({
+ cwd: input.cwd,
+ sessionId: input.sessionId,
+ rootThreadId: bootstrap.root_thread_id,
+ childAgentId: input.childAgentId,
+ receiptNotBefore: bootstrap.created_at,
+ receiptNotAfter: bootstrap.expires_at,
+ });
+ if (!tracked.ok) return { ok: false };
+ return { ok: true, assignment, bootstrap };
+}
+
+export async function withNativeUltragoalActivationAuthorization<T>(input: {
+ cwd: string;
+ stateDir: string;
+ sessionId: string;
+ childAgentId: string;
+ bootstrapStatus?: 'activating' | 'active';
+}, run: (assertAuthorized: () => Promise<void>) => Promise<T>): Promise<
+ { ok: true; value: T } | { ok: false }
+> {
+ return withNativeUltragoalLifecycleLock(input.stateDir, input.sessionId, async () => {
+ const bootstrapStatus = input.bootstrapStatus ?? 'activating';
+ const initial = await validateNativeUltragoalActivationReceipt(input, [bootstrapStatus]);
+ if (!initial.ok) return { ok: false };
+ const expectedGeneration = initial.bootstrap.generation;
+ const expectedAssignmentId = initial.assignment.child_agent_id;
+ const assertAuthorized = async (): Promise<void> => {
+ const current = await validateNativeUltragoalActivationReceipt(input, [bootstrapStatus]);
+ if (
+ !current.ok
+ || current.bootstrap.generation !== expectedGeneration
+ || current.assignment.child_agent_id !== expectedAssignmentId
+ ) throw new Error('native_ultragoal_activation_receipt_invalid');
+ };
+ return { ok: true, value: await run(assertAuthorized) };
+ });
+}
+
+async function prepareNativeUltragoalBootstrapActivationUnlocked(input: {
+ cwd: string;
+ stateDir: string;
+ sessionId: string;
+ childAgentId: string;
+ now?: Date;
+}): Promise<{ ok: true; assignment: LocalNativeExecutorAssignment } | { ok: false }> {
+ const validated = await validateNativeUltragoalActivationReceipt(input, ['ready', 'activating']);
+ if (!validated.ok) return validated;
+ const { assignment, bootstrap } = validated;
+ if (bootstrap.status !== 'activating') {
+ await writeJsonAtomic(bootstrapPath(input.stateDir, input.sessionId), {
+ ...bootstrap,
+ status: 'activating',
+ updated_at: (input.now ?? new Date()).toISOString(),
+ });
+ }
+ return { ok: true, assignment };
+}
+
+export async function prepareNativeUltragoalBootstrapActivation(
+ input: Parameters<typeof prepareNativeUltragoalBootstrapActivationUnlocked>[0],
+): Promise<{ ok: true; assignment: LocalNativeExecutorAssignment } | { ok: false }> {
+ return withNativeUltragoalLifecycleLock(input.stateDir, input.sessionId, () => (
+ prepareNativeUltragoalBootstrapActivationUnlocked(input)
+ ));
+}
+
+async function markNativeUltragoalBootstrapActiveUnlocked(
+ input: Parameters<typeof prepareNativeUltragoalBootstrapActivationUnlocked>[0],
+): Promise<{ ok: true; assignment: LocalNativeExecutorAssignment } | { ok: false }> {
+ const validated = await validateNativeUltragoalActivationReceipt(input, ['ready', 'activating', 'active']);
+ if (!validated.ok) return validated;
+ const { assignment, bootstrap } = validated;
+ if (bootstrap.status !== 'active') {
+ await writeJsonAtomic(bootstrapPath(input.stateDir, input.sessionId), {
+ ...bootstrap,
+ status: 'active',
+ updated_at: (input.now ?? new Date()).toISOString(),
+ });
+ }
+ return { ok: true, assignment };
+}
+
+export async function markNativeUltragoalBootstrapActive(
+ input: Parameters<typeof markNativeUltragoalBootstrapActiveUnlocked>[0],
+): Promise<{ ok: true; assignment: LocalNativeExecutorAssignment } | { ok: false }> {
+ return withNativeUltragoalLifecycleLock(input.stateDir, input.sessionId, () => (
+ markNativeUltragoalBootstrapActiveUnlocked(input)
+ ));
+}
+
+async function revokeLocalNativeExecutorAssignmentUnlocked(input: {
+ stateDir: string;
+ sessionId: string;
+ childAgentId?: string;
+ reason: string;
+ now?: Date;
+}): Promise<void> {
+ const now = input.now ?? new Date();
+ const bootstrap = await readNativeUltragoalBootstrap(input.stateDir, input.sessionId);
+ const childAgentId = input.childAgentId ?? bootstrap?.child_agent_id;
+ if (childAgentId) {
+ const path = nativeExecutorAssignmentPath(input.stateDir, input.sessionId, childAgentId);
+ const assignment = parseAssignment(await readJsonObject(path));
+ if (assignment?.lifecycle === 'active') {
+ await transitionAssignment(path, assignment, 'revoked', input.reason, now);
+ }
+ }
+ if (bootstrap) {
+ await writeJsonAtomic(bootstrapPath(input.stateDir, input.sessionId), {
+ ...bootstrap,
+ status: 'revoked',
+ updated_at: now.toISOString(),
+ reason: input.reason,
+ });
+ }
+}
+
+export async function revokeLocalNativeExecutorAssignment(
+ input: Parameters<typeof revokeLocalNativeExecutorAssignmentUnlocked>[0],
+): Promise<void> {
+ return withNativeUltragoalLifecycleLock(input.stateDir, input.sessionId, () => (
+ revokeLocalNativeExecutorAssignmentUnlocked(input)
+ ));
+}
+
+async function reconcileLocalNativeExecutorAssignmentsUnlocked(input: {
+ cwd: string;
+ stateDir: string;
+ sessionId: string;
+ rootThreadId: string;
+ now?: Date;
+}): Promise<{ ready: boolean; childAgentId?: string }> {
+ const bootstrap = await readNativeUltragoalBootstrap(input.stateDir, input.sessionId);
+ const directory = join(input.stateDir, 'sessions', input.sessionId, NATIVE_ASSIGNMENT_DIRECTORY);
+ const entries = await readdir(directory).catch(() => []);
+ for (const entry of entries) {
+ if (!entry.endsWith('.json')) continue;
+ const path = join(directory, entry);
+ const assignment = parseAssignment(await readJsonObject(path));
+ if (!assignment || assignment.lifecycle !== 'active') continue;
+ if (
+ !bootstrap
+ || assignment.bootstrap_generation !== bootstrap.generation
+ || assignment.child_agent_id !== bootstrap.child_agent_id
+ ) {
+ await transitionAssignment(path, assignment, 'revoked', 'bootstrap_replaced', input.now);
+ continue;
+ }
+ const tracked = await validateLocalNativeExecutorIdentity({
+ cwd: input.cwd,
+ sessionId: input.sessionId,
+ rootThreadId: input.rootThreadId,
+ childAgentId: assignment.child_agent_id,
+ receiptNotBefore: bootstrap.created_at,
+ receiptNotAfter: bootstrap.expires_at,
+ });
+ if (!tracked.ok) await transitionAssignment(path, assignment, 'revoked', tracked.reason, input.now);
+ }
+ const assignment = await findReadyLocalNativeExecutorAssignmentUnlocked(input);
+ return assignment
+ ? { ready: true, childAgentId: assignment.child_agent_id }
+ : { ready: false };
+}
+
+export async function reconcileLocalNativeExecutorAssignments(
+ input: Parameters<typeof reconcileLocalNativeExecutorAssignmentsUnlocked>[0],
+): Promise<{ ready: boolean; childAgentId?: string }> {
+ return withNativeUltragoalLifecycleLock(input.stateDir, input.sessionId, () => (
+ reconcileLocalNativeExecutorAssignmentsUnlocked(input)
+ ));
+}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment