Skip to content

Latest commit

 

History

History
305 lines (259 loc) · 17.3 KB

File metadata and controls

305 lines (259 loc) · 17.3 KB

Share optional evidence with Claude, Codex, and Devin

An approved context packet can now accompany a work order and its independent review. Every host uses the same evidence renderer and authorization checks. The calling host remains the orchestrator; a context provider gains no builder, reviewer, tracker-write, or merge authority. Ordinary sessions without context keep their existing behavior and do not load the optional Coworker SDK.

Start with a verified private connection. The guided path below fetches once for the work item and retains the opaque packet handle; the lower-level workflow can still fetch it explicitly. Every delivery verifies authorization online; it does not repeat the search. Only Claude, Codex, and Devin orchestrator, builder, and reviewer roles are supported for private delivery in this release. Each role must be explicitly approved in the private connection configuration as <host>:<role>; a connection without devin:* recipients never delivers to Devin.

Guided session path

For the normal workflow, bind the work item when starting the session and let Code Mower carry the private identity into retrieval and work-order creation:

code-mower session start --repo OWNER/REPO --host codex --work-item EXAMPLE-123
code-mower session context prepare .code-mower/sessions/SESSION.json
code-mower session context deliver .code-mower/sessions/SESSION.json

Use --host claude when Claude starts the session. The selected host is the implicit orchestrator. It is also the default builder; prepare --builder NAME selects another configured builder for a handoff. The work order names review lanes selected for the session while excluding the builder, so a builder's own review cannot satisfy the peer-review requirement. No optional reviewer is added unless it was selected for the session.

The prepare command uses the selected work-item identity as its bounded private query by default. For a more specific query, use private stdin:

cat /private/path/query.txt | code-mower session context prepare \
  .code-mower/sessions/SESSION.json --query-stdin

The query is hashed for retry consistency and is not saved or rendered. The command performs the existing online authorization and packet fetch, writes a local context-aware work order, and records its opaque references in protected session state. Repeating it reauthorizes the packet without repeating the search. Use --refresh only to retry a failed/interrupted search or intentionally replace changed retrieval input. Refreshes and builder handoffs create a new generated work-order path so local edits to the previous work order are not overwritten. The lower-level commands below remain useful for expert scripting and diagnostics.

session context deliver derives the repository, work item, connection, policy, packet, and selected builder from protected state. It writes the private evidence to stdout for the builder's prompt; keep that output out of tracked files and public logs. The selected builder must be Claude, Codex, or Devin in this release.

Work order and builder

work-order draft --context-packet HANDLE adds the opaque identity and a delivery instruction to the existing work-order format. It adds no source text, account binding, or new cloud telemetry fields.

Before a PR exists, the approved builder or orchestrator can receive the packet:

code-mower context deliver --packet HANDLE --connection example-context \
  --recipient codex:builder --request-stdin < /private/path/delivery-request.json

The private JSON request has exactly repository, work_item, and policy. Use the same scope and policy as the original fetch. Evidence is written to stdout for the approved participant's prompt. Keep it out of public terminal logs, tracked files, PR descriptions, and shared artifacts.

Hosted Devin builder

A trusted hosted work order can carry the packet to devin:builder without a local prompt file. The trusted context decision is part of the work order: WorkOrder.context_policy is none, optional, or required, comes from dispatcher policy, and is included in the durable binding. A context-bearing order also carries the trusted WorkOrder.context_work_item: the tracker-neutral identity from the session or manifest context binding (a Jira key, for example), which may differ from the integer GitHub delivery issue WorkOrder.issue. Only the integer issue closes and verifies the pull request; only the work item binds the packet. When a key is supplied the prepared source may omit issue_number, though a present one must still match. Context-free orders carry no key, and their serialized binding is unchanged.

The embedding binds one packet with devin_work_orders.packet_context(store, name, handle, policy, order=order), which validates the handle and the trusted policy (its required flag must agree with the order) and returns a PacketContext holding only the protected store, connection name, packet handle, normalized policy, and backend. It carries no packet, evidence, callable, or identity of its own: the request is derived from the order it is used with. That value is passed as context= to dispatch, clarify, or fix.

Immediately before each paid create or message write, and never in preview, the work-order boundary itself calls load_authorized() with the order's repository, work item, and devin:builder: a new online authorization under the store lock for the selected account, current authorization, revocation and expiry, then the packet's own binding, freshness, and recipients. The evidence is rendered inside that boundary from the exact packet the authorized load returned, under the exact authorized packet handle as its Packet identity, the same identity the Claude and Codex peer paths render; no separately supplied packet or evidence is ever accepted, and a synthetic local packet with matching binding fields never reaches the store lookup. A handle for another ticket, a packet without the recipient, or a store without an authorizable connection is unavailable; a bare handle, packet, string, look-alike object, store subclass, or any context on a none order fails as context_binding_mismatch. Rendering and the 64 KiB combined-size check (context_budget_exceeded) happen before the work-order record, branch reservation, or a new round is written, so a rejected input leaves no undispatched reservation and consumes no round. Evidence text is appended only to the provider input; records keep only digests plus the safe state enum, and status, collect, and cancel reject a context argument.

A required order fails closed when no packet is supplied or it cannot be reauthorized (wrong account, revoked or expired authorization, refreshed or invalidated packet). run then returns, rather than raises, the issue's closed outcome: {"outcome": "UNKNOWN", "state": "paused", "reason": "context_unavailable", "context": {"policy": "required", "dispatch" | "message": "unavailable"}, "merge_authority": false}; nothing was reserved, persisted, or sent, and an already dispatched order keeps its prior round and state. Only an optional order degrades to a code-only input (degraded) or runs without a packet (omitted).

The complete intended input, including the evidence and its safe state, is digested before the local dispatch or message intent becomes durable, and the remote session's input fingerprint covers the same text. A retry after a stop between the two writes must regenerate the identical input; changed, refreshed, or dropped evidence fails as request_conflict and the saved state keeps reporting what was actually intended. The state chosen for the create input and for each message intent is persisted and reported by every command as context: {policy, dispatch, message}; replay, acknowledgement, status, and collect return the saved state rather than recomputing it. Durable records written before the context field existed keep their original binding and dispatch input: a none order serializes without context_policy or context_work_item, and records without context or input digests are read as context-free.

Attach evidence to independent review

After creating the PR, attach the packet to its current code head without a request file or copied packet handle:

code-mower session context attach .code-mower/sessions/SESSION.json --pr 42

The guided command derives every private input from the session. It verifies the live session lease, trusted-base control authority, current PR head, packet, and online authorization before publishing. Repeating it on the same current head and input succeeds without another comment or revision. A changed code head gets a new saved intent and requires a new review.

The session saves its random revision before the first GitHub write. If a process stops after GitHub accepted the comment, rerunning attach reconciles that exact revision from the trusted current comment. If a write returns an uncertain result and the revision is not current, status pauses the workflow; after independently checking the PR, attach --retry-uncertain republishes the same revision rather than creating another one. No uncertain or unpublished binding can deliver evidence. A saved uncertain or pending intent is never cleared just because a later attach was asked for: it may already be the GitHub-accepted state a lost response only looked like it missed.

Before attempting a fresh reservation, the session first saves a durable reserving marker -- proof that no GitHub write has happened yet, because publication only ever follows a reservation that has itself already become durable. If that reservation then fails within the same attach call -- for example because the actual consuming checkout has moved past the evidence it was prepared from, or the local graph was rebuilt in the meantime -- the same call rolls the session back to its prior prepared, unattached state inline, keeping the failure reason visible in status. If the process instead stops before that same-call rollback, or before the reservation's own durable transition out of reserving completes -- a crash, or a storage fault like the one that also surfaces as a ContextError from a saved-state transition that did not complete -- the saved intent is left as reserving instead. The next attach recognizes a saved reserving marker, finishes abandoning it and clearing the session back to its prior prepared, unattached state, and asks the caller to rerun attach rather than completing a fresh attempt in that same call, since resuming immediately could race a concurrent recovery. Only once that cleanup has actually finished is the session safe to explicitly rebuild, rerun prepare --refresh, or attach again; refresh must not be used while a reserving cleanup is still outstanding, and a storage or other fault surfaced while attach itself was trying to advance a saved intent does not promise that this cleanup has already happened -- rerunning attach is what finishes it.

A saved pending or uncertain intent is different: its reservation is already durable, and GitHub publication may have begun or even completed before a lost response left the local state unconfirmed, so it is never blanket-cleared the way a reserving marker is. Once the trusted current pull request head has genuinely moved past such a saved intent, that old identity is retired before any new evidence is authorized, so a checkout that has since moved on cannot block its own recovery. This retirement, like the reserving cleanup above, is safe to retry after an interruption partway through.

The lower-level expert form remains available for scripts that intentionally manage request files and revisions:

code-mower context attach --connection example-context --host codex \
  --repo-path /path/to/repository --base-ref origin/main \
  --request-stdin < /private/path/attachment-request.json

The private request has exactly repository, work_item, policy, packet (the handle), and pr (a positive integer). --host may come from CODE_MOWER_HOST. Use origin/develop when that is the trusted target branch.

The GitHub actor must already be a configured control authority: the trusted base's owner_surface.owner_login or decisions.authorities, or the equivalent trusted runtime setting. Configure the same authority for the gate and local auditor. PR-supplied configuration cannot grant that authority. Updating existing repositories requires the current generated gate workflow and support helpers. If trusted repository policy requires context, both audit wrappers and the generated gate reject a review without its first required input declaration. If local policy discovery itself fails, ordinary audits remain usable; explicit input revisions and known declarations still require context. The generated gate independently reads current policy from its trusted default-branch checkout and rejects a code-only PASS. Changing context.required does not require regenerating the workflow. A selected but malformed context policy fails closed; an absent context section leaves ordinary workflows usable.

Attachment sets code-mower/gate pending and publishes a small control comment containing only a random input revision, code head, required/available state, and expiry. The packet hash, handle, account, alias, query, citations, and source text stay local. A failed or uncertain publication leaves the local binding unusable. The lower-level explicit attachment always creates a new review input revision; the guided path reconciles its saved revision instead.

Run the usual independent audit on the machine that holds the private connection:

code-mower claude-audit --repo owner/repo --pr 42 \
  --repo-paths owner/repo:/path/to/repository --base-ref origin/main \
  --context-revision REVISION

The corresponding codex-audit command uses the same options. The explicit revision is optional: both wrappers discover current control declarations from trusted authorities. It is useful when dispatching a specific work order. Use --context-state-dir for a nondefault private store. A remote runner without the selected authorization cannot review private context; it reports UNKNOWN. Do not copy credentials or private packets into GitHub Actions to bypass this.

Both wrappers frame source material as evidence outside trusted project doctrine and owner decisions. They preserve citations, uncertainty, and contradictions. The model receives neither credentials nor account-binding metadata. Existing sandbox and ambient-MCP restrictions remain in force.

Findings, refresh, and failure

Before accepting the verdict, the wrapper checks the current code head, current input revision, packet identity, expiry, and fresh online authorization again. Missing required context, authorization failure, or changed input yields UNKNOWN. An explicitly declared optional-unavailable input can receive an ordinary code review, but that review must still name its input revision. Neither wrapper silently drops selected private evidence to fit a truncated diff.

When private evidence was supplied, public review comments and saved verdict artifacts contain only review status, severity counts, input metadata, and the standard audit provenance. Model-authored findings stay in the protected local binding because they may quote private sources. Raw CLI sidecars are disabled for this path. Retrieve detailed findings for the session's selected builder without copying the review revision:

code-mower session context feedback .code-mower/sessions/SESSION.json \
  --reviewer claude

This command derives the current revision and builder recipient, then checks the current PR head, trusted input, and online authorization before printing private findings. It records the session as reviewed after the first successful read. The lower-level context feedback --revision REVISION ... and analogous context deliver --revision REVISION commands remain available. All three have private stdout.

Changed material context requires an explicit fetch with --refresh, followed by attachment and a new audit, even when code is unchanged. A changed code head also requires a new attachment. The gate checks both identities; an old PASS cannot satisfy a newly attached input. UNKNOWN from a later authorization check supersedes a prior PASS on the same input. Context-bound verdict artifacts cannot be reposted offline; run a fresh authorized audit.

Gate status is updated by GitHub events, not a continuous authorization monitor. Do not treat a previously displayed green status as permission to replay expired evidence. Recheck the selected input when resuming work. Deleting or manually rewriting control comments is not a supported way to change the selected input; use the context commands and review the new revision.

Refresh, eviction, and disconnect delete the packet's local delivery bindings and private findings. At most eight bindings are retained per packet. Deletion cannot recall evidence already sent to an approved model. Provider billing that was not returned stays unknown; replay performs authorization, not another organization search.

The synthetic local-repository graph fixture uses the common packet validation and evidence renderer for all six roles without OAuth identity fields. It exercises the extension point that the shipped optional Graphify provider uses; a passing fixture neither installs Graphify nor qualifies a provider build. See Optional Graphify Setup.