Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
57 commits
Select commit Hold shift + click to select a range
c5bec14
docs: design Rescue worktree late binding
vitry Aug 21, 2026
0963587
docs: plan Rescue worktree late binding
vitry Aug 21, 2026
8bcb168
docs: deepen active-turn compatibility design
vitry Aug 21, 2026
ed866c8
docs: remove parallel authority plan
vitry Aug 21, 2026
6a68c53
docs: close worktree authority review gaps
vitry Aug 21, 2026
f192e82
feat: add compatible active-turn workspace binding
vitry Aug 21, 2026
8fdfa10
fix: harden active-turn lifecycle transactions
vitry Aug 21, 2026
1010b06
docs: specify fenced lifecycle lock order
vitry Aug 21, 2026
a444396
docs: match lifecycle lock storage
vitry Aug 21, 2026
d676d61
fix: make session tombstones revoke caller tokens
vitry Aug 21, 2026
e5e0836
fix: bind caller tokens to lifecycle generations
vitry Aug 21, 2026
50fa169
docs: bind callers to lifecycle generations
vitry Aug 21, 2026
78c8c68
fix: bind Rescue to a prepared worktree
vitry Aug 21, 2026
8ecb6b7
fix: harden prepared worktree binding
vitry Aug 21, 2026
1f87c44
docs: specify prepared transport linearization
vitry Aug 21, 2026
81c31c1
fix: preserve installed launcher provenance
vitry Aug 21, 2026
ed996a2
docs: preserve installed launcher provenance
vitry Aug 21, 2026
201e391
fix: route Rescue lifecycle through its bound worktree
vitry Aug 21, 2026
3b47df9
fix: linearize Rescue executor routing
vitry Aug 21, 2026
884b007
fix: fence Rescue route publication
vitry Aug 21, 2026
fa5cb2a
fix: compensate failed Rescue route publication
vitry Aug 21, 2026
36d8112
fix: compensate executor write failures
vitry Aug 21, 2026
ea104fd
docs: specify executor route fencing
vitry Aug 21, 2026
2383644
test: qualify Rescue worktree late binding
vitry Aug 21, 2026
afef089
test: observe installed Rescue worktree binding
vitry Aug 21, 2026
8a33b69
test: bind real qualification to installed Rescue
vitry Aug 21, 2026
c7c9646
test: prove broker worktree ownership
vitry Aug 21, 2026
987f471
test: independently verify broker routing
vitry Aug 21, 2026
9fb1a20
fix: preserve protected caller compatibility
vitry Aug 21, 2026
89e4f7a
docs: specify caller compatibility minting
vitry Aug 21, 2026
f2f8546
test: strengthen caller compatibility races
vitry Aug 21, 2026
4dec0d3
test: observe real sessions through their broker
vitry Aug 21, 2026
34b48af
build: refresh marketplace worktree binding snapshot
vitry Aug 21, 2026
03e2c19
test: harden real broker qualification evidence
vitry Aug 21, 2026
3c16a80
build: pin marketplace qualification source
vitry Aug 21, 2026
d36626d
test: close qualification evidence races
vitry Aug 21, 2026
f918bb0
build: repin marketplace qualification source
vitry Aug 21, 2026
b32d573
test: align qualification with prepared broker routing
vitry Aug 21, 2026
3353d6b
build: finalize marketplace qualification source
vitry Aug 21, 2026
6abcc56
fix: reject stopped executor route replays
vitry Aug 21, 2026
31f5fef
fix: recover orphaned pending lifecycles
vitry Aug 21, 2026
6b70665
fix: accept newer orphan lifecycle proofs
vitry Aug 21, 2026
37205c9
build: refresh reviewed marketplace snapshot
vitry Aug 21, 2026
5a16824
fix: unify lifecycle begin timestamps
vitry Aug 21, 2026
6851241
test: surface caller hook failures
vitry Aug 21, 2026
4e1b457
build: refresh reviewed marketplace snapshot
vitry Aug 21, 2026
b1aa413
fix: snapshot caller lifecycle clocks once
vitry Aug 21, 2026
9d8b006
build: refresh reviewed marketplace snapshot
vitry Aug 21, 2026
f10f634
fix: rotate newer orphan session proofs
vitry Aug 21, 2026
5852ca4
build: refresh reviewed marketplace snapshot
vitry Aug 21, 2026
6263aed
test: make identity mode checks portable
vitry Aug 21, 2026
25718e9
test: canonicalize Windows qualification paths
vitry Aug 21, 2026
f78a868
fix: recover empty Windows lock layouts
vitry Aug 21, 2026
7d45833
build: refresh reviewed marketplace snapshot
vitry Aug 21, 2026
f761603
test: rewrite Windows qualification fixtures safely
vitry Aug 21, 2026
b171d17
test: avoid forcing EOF in prepare timeout
vitry Aug 21, 2026
9e6155d
build: refresh reviewed marketplace snapshot
vitry Aug 21, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ All notable changes follow Semantic Versioning.

## Unreleased

- Added compatible Rescue worktree late binding: lifecycle proof retains the origin workspace while the first trusted prepare automatically and immutably binds one execution workspace from the same canonical Git common-dir, without manual handoff. Role preview and children cannot claim; unrelated repositories fail closed; Root Stop, a new prompt, and SessionEnd revoke or replace authority before target cleanup.
- Accepted ZCode CLI 0.16.3's captured initial empty-session revision and pre-turn settings snapshots while retaining exact empty-state, event-sequence, identity, workspace, and activity checks. Real qualification now proves two visible responses through each turn's exact persisted user-root parent chain when the CLI remaps request input IDs.
- Removed the plugin-defined ordinary Rescue completion deadline while retaining finite request, review-gate, qualification, caller credential, and one-shot preparation budgets. Active parent authority is now hook-lifecycle-bound; same-parent-turn continuation replaces consumed preparation generation 1 with an executor-bound generation 2, follows up the exact stopped child, and reuses the exact binding and ZCode session. Root Stop, replacement prompts, SessionEnd, explicit cancellation, SIGINT, and SIGTERM remain authoritative boundaries. Role readiness now distinguishes `caller-unavailable` and `inspection-unavailable` from managed setup states; existing owned Roles require the normal one-time setup upgrade.
- Added private durable per-job human-readable logs that retain the complete accepted safe semantic-progress history while job previews remain bounded to four entries. Exact-owner detailed status displays the private absolute path; compact, foreign, sibling-session, sidecar, relay, and terminal surfaces remain path-free, with no new log command or retention lifecycle.
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ A source checkout and an installed plugin use intentionally isolated namespaces:

On every owned parent turn, the owned `UserPromptSubmit` hook injects one machine-rendered, instance-bound launcher command derived from the exact plugin instance that executed the hook. Root and its Rescue child reuse those exact bytes and append only fixed Rescue arguments. They never construct a path from cwd or Skill prose, never call the direct companion form `node scripts/zcode-companion.mjs`, and never use PATH, a global package, or a cache search to select another plugin instance. This removes model-authored path selection without weakening instance or namespace isolation.

Rescue distinguishes the conversation's origin workspace from its execution workspace. When Root creates or enters a linked worktree during the same parent turn, the first trusted `prepare rescue` automatically binds execution there; no manual handoff is needed. The origin itself or a canonical linked-worktree top level is eligible only when it shares the same canonical Git common-dir. That target is immutable for the turn, so another worktree or an unrelated repository is rejected. Role inspection is read-only and a child cannot claim or change the target. Root `Stop`, a new prompt, and `SessionEnd` revoke or replace authority before cleanup across the origin and bound target.

`source-session-unproven` is terminal for that Rescue route: use the launcher from the active owned lifecycle context, but do not run `$zcode:setup`, prepare, follow up, or spawn from the unproven source checkout. A launcher error caused by a shell-unsafe install path is also terminal and provides a fixed reinstall remedy; reinstall the plugin to a shell-safe path and retry from a new owned parent turn. Neither condition authorizes a fallback launcher or automatic redirect.

Rescue has two equivalent entry forms. An explicit `$zcode:rescue` request is literal and applicable; Root may also choose Rescue proactively from the complete business objective. This is automatic routing and there is no `--auto` option. Explicit `--fresh` or `--resume` remains authoritative; clear proactive continuations materialize resume and clear independent work materializes fresh before any child starts.
Expand Down
2 changes: 2 additions & 0 deletions README.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ source checkout 和已安装插件使用刻意隔离的命名空间:source dev

在每个受管父 turn 中,受管 `UserPromptSubmit` hook 都会注入一条由执行该 hook 的精确插件实例机器渲染的 instance-bound launcher command。Root 和 Rescue 子 agent 原样复用这些精确字节,并且只追加固定 Rescue 参数。它们绝不从 cwd 或 Skill 文本构造路径,绝不调用直接 companion 形式 `node scripts/zcode-companion.mjs`,也绝不通过 PATH、全局包或 cache 搜索选择另一个插件实例。这样无需模型自行选择路径,同时不削弱实例或命名空间隔离。

Rescue 会区分对话的 origin workspace 与 execution workspace。Root 在同一个 parent turn 中创建或进入 linked worktree 时,第一次可信的 `prepare rescue` 会自动绑定到该 execution workspace,不需要手动 handoff。只有 origin 本身,或与它共享相同的 canonical Git common-dir 的 canonical linked-worktree 顶层目录才合格。目标在同一 turn 内不可变,因此其他 worktree 或无关仓库会被拒绝。Role inspection 只读,child 不能 claim 或更改目标。Root `Stop`、新 prompt 与 `SessionEnd` 会先撤销或替换 origin 和已绑定目标之间的授权,再执行清理。

`source-session-unproven` 对该 Rescue 路由是终态:应使用活动受管 lifecycle context 中的 launcher,但不要从未证明的 source checkout 运行 `$zcode:setup`、prepare、follow up 或 spawn。launcher error 由 shell-unsafe 安装路径触发时同样是终态,并给出固定的重新安装 remedy;请把插件重新安装到 shell-safe 路径,再从新的受管父 turn 重试。两种情况都不授权 fallback launcher 或自动重定向。

Rescue 有两种等价入口:显式 `$zcode:rescue` 是请求中字面且适用的入口;Root 也可以根据完整业务目标主动选择 Rescue。这就是自动路由,不提供 `--auto` 选项。显式 `--fresh` 或 `--resume` 始终权威;明确的主动续做会在 child 启动前物化为 resume,明确的独立工作会物化为 fresh。
Expand Down
1 change: 1 addition & 0 deletions SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ Report suspected vulnerabilities privately through GitHub's private vulnerabilit
- A private durable per-job log contains every accepted safe semantic progress event successfully dispatched by that bounded allowlist and may also contain current-turn visible assistant text selected by the exact existing linkage rules and authoritative final output. Raw command stdout/stderr, arbitrary tool payloads (input/output/errors/metadata), raw reasoning, file or patch contents, environment values, credentials, capabilities, and hidden messages are never directly ingested as log source fields. The log is not a semantic secret-redaction boundary: if visible assistant or final text itself quotes or paraphrases sensitive material, that selected text is retained. Keep secrets out of visible model text and protect the private log accordingly. The log is observational and cannot establish or alter terminal authority. Its absolute path is disclosed only by exact-owner detailed status, never by compact or foreign projections, sibling sessions, sidecars, relays, or terminal notices.
- Child stderr and detailed progress stay in the child thread. Parent-visible output is limited to host lifecycle events and the final public result. Subscription or optional progress-sink failure is observational and cannot weaken the authoritative completion guard.
- Rescue task material exists in the routing rollout only as the Root parent's single LF-terminated JSON line sent through `write_stdin` to `prepare rescue`. The companion requires a raw-capable TTY and enables raw mode before emitting task-free readiness and before accepting any task bytes; readiness is nonterminal. Root sends no EOF or U+0004. Non-TTY/readiness/raw-mode failure stops before delivery. Tool output must never contain or echo the payload. Prepared state is bound to the exact Codex session, initiating turn, canonical workspace, and executor identity; it is single consume, has a bounded expiry, and is subject to private-state cleanup. The task, source, and options must never appear in argv, environment variables, output, logs, artifacts, relays, status, task names, or any child assignment/transcript. Named and generic children are task-blind and capability-free and receive only the constant `invoke-prepared rescue` assignment.
- Rescue records the trusted prompt cwd as the origin workspace and lets only the first trusted prepare bind one execution workspace. Cross-worktree binding requires an exact canonical Git top level with the same canonical Git common-dir; the first prepare makes that target immutable for the turn. Role preview is read-only, a child cannot claim authority, and an unrelated repository fails closed. Root Stop, a new prompt, and SessionEnd revoke or replace authority before target cleanup, while all preparation, executor, job, binding, broker, and peer state remains scoped to the execution workspace.
- A durable Rescue binding authorizes the same stopped child to continue only its exact ZCode session. The private `anchorJobId` and `currentJobId` remain inside protected plugin state and never cross the parent-to-child message boundary. Missing, closed, corrupt, permission-incompatible, workspace-mismatched, executor-mismatched, or provenance-inconsistent bindings fail closed.
- Ordinary foreground completion has no plugin wall-clock deadline. Authority still ends at Root `Stop`, replacement prompt, `SessionEnd`, explicit `$zcode:cancel`, `SIGINT`, or `SIGTERM`; request, review-gate, qualification, caller credential, and one-shot preparation budgets remain finite. Same-parent-turn continuation requires the exact stopped executor, exact binding operation/anchor/current CAS values, and exact ZCode session. Each 30-minute preparation generation is single-consume and generation 2 is bound to generation 1's exact executor.
- Role readiness is fail-closed but distinguishes unavailable caller authority (`caller-unavailable`) from an unavailable inspection channel (`inspection-unavailable`) and from managed install/upgrade/drift/conflict/restart/genuine-unsupported states. Only the managed states authorize setup guidance; owned prior Role bytes require the normal one-time upgrade and foreign Role state is never adopted.
Expand Down
8 changes: 7 additions & 1 deletion docs/adr/0010-use-thread-bound-direct-companion.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
status: accepted
supersedes: caller-capability-through-model-and-fd
amended: 2026-08-20
amended: 2026-08-20; 2026-08-21
---

# Use a thread-bound direct companion for installed Skills
Expand Down Expand Up @@ -82,6 +82,12 @@ binding child identity through native lifecycle hooks, and failing closed is
retained. Only Rescue command-location selection is superseded: the model no
longer constructs or directly invokes `scripts/zcode-companion.mjs`.

## Rescue worktree late-binding amendment (2026-08-21)

The active parent turn now distinguishes its trusted origin workspace from one optional execution workspace. The first trusted prepare automatically binds an immutable target for the turn, without manual handoff. A different target is eligible only when it is an exact canonical linked-worktree top level with the same canonical Git common-dir as the origin workspace. Role inspection remains read-only and a child cannot claim or redirect this authority.

SubagentStart and SubagentStop may continue to arrive at the origin workspace. A generation-bound private route points to executor storage in the execution workspace, where preparation, job, binding, broker, and peer state remain isolated. Root Stop, a new prompt, and SessionEnd revoke or replace authority before advisory cleanup. This deepens the existing thread-bound active-turn semantic; it does not create a second handoff authority or weaken the launcher boundary.

## Rejected alternative

A bundled stdio MCP server would provide structured arguments, and current
Expand Down
2 changes: 2 additions & 0 deletions docs/adr/0013-bind-rescue-child-to-zcode-session.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,6 @@ An active exact child is rejoined without preparation or invocation. A stopped e

Legacy jobs-only state may be adopted only when it supplies one exact eligible candidate and no conflicting pending state. A permission change prevents resume and requires an explicit fresh operation to capture the current permission snapshot. `SessionEnd` closes the ending Codex session's whole binding partition. Missing, invalid, closed, corrupt, ambiguous, wrong-workspace, wrong-executor, or provenance-mismatched state must fail closed without selecting a latest session or another child.

For linked worktrees, the prompt-proved origin workspace and the Rescue execution workspace are distinct. The first trusted prepare automatically binds one immutable execution target for the turn, without manual handoff, and only an exact canonical linked worktree sharing the same canonical Git common-dir is eligible. A child cannot claim the target. The stopped child's generation-bound route and all durable binding state remain in that execution workspace; Root Stop, a new prompt, and SessionEnd revoke or replace the origin authority before cleaning the target.

This replaces ADR 0010 only where that decision treated a stopped child as reusable solely for the immediate `needs-choice` exchange. Choice continuation remains same-child; this decision also permits a later prepared turn for the exact durably bound operation.
Loading
Loading