# Agent workspace ABI

This ABI covers the one-shot practice runner's container workspace at `/workspace/`. The conversation host uses its own layout. See [Conversation runtime](/contributor/unified-pi-runtime.md).

The worker renders one disposable folder for an owned execution attempt. The runtime contract is version 8. Practice inputs and candidates use script contract version 3.

## Folder layout

```
/workspace/

├── context/                         # Authorized frozen source records.

│   ├── scm/                         # SCM domain evidence.

│   ├── chat/                        # Permitted thread evidence.

│   ├── docs/                        # Permitted document evidence.

│   └── people/                      # Permitted account context.

├── repos/                           # Read-only repository working copies.

├── inputs/

│   ├── history/results.json         # Authorized prior results.

│   └── practices/                   # Pinned practices and criteria.

├── work/

│   ├── practice-scripts/

│   │   ├── lib/                     # Installed core and host toolkit.

│   │   ├── kits/                    # Installed domain kits.

│   │   └── practices/               # <slug>.inputs.json and custom <slug>.ts.

│   └── review-input/                # Prepared input for fresh review sessions.

├── out/                             # Collected bounded output and diagnostics.

└── task.json                        # Owned runtime envelope.
```

The worker stages the conversation host's scripts, its system prompt, and a `package.json` from its own JAR. Nothing else is staged. It also reads the practice-script library at `/opt/practice-scripts`, through the same workspace link that the practice runner uses. It reads the stored path and the situation of a turn from the worker (`GET context`).

The conversation host reads context documents and repositories from a [context folder](/contributor/practice-review-glossary.md#runtime-terms) in a turn sandbox, through the worker ([Conversation runtime](/contributor/unified-pi-runtime.md#context-folder)). That folder uses a layout similar to the job folder: documents under `inputs/context/` and repositories under `repos/`. The practice runner and the conversation host execute on Node. See [ADR 0036](https://github.com/hephaestus-build/Hephaestus/blob/main/docs/decisions/0036-agent-runtime-runs-on-node-24.md).

Source identity and capture facts are frozen before evaluation. A folder path alone is not authorization or durable proof. The [source contract](/contributor/item-source-contract.md) owns capture-state meaning. The [runtime guide](/contributor/practice-review-runtime.md) owns execution and retry.

## Practice inputs

Each practice gets one `<slug>.inputs.json` record. It contains contractVersion 3, kind, unknown domain item, About, practice identity, scope, review metadata and previous result metadata. The host supplies decimal-string bigint IDs, UUIDs and the pinned version. Custom code cannot select another workspace, developer or assignment.

The core toolkit defines the result and host capabilities. A domain kit validates the item before it offers domain evidence helpers. The authored SCM record remains in the SCM domain. Core does not receive a diff type.

For ITEM, scope names the reviewed item. For SCAN, scope names an assigned file at the frozen default-branch commit. The product review's item is the repository, while About remains null. No authored-person history or blame is inferred from repository file content.

## Evidence and read receipts

Read receipts identify source, path, version, read extent and completion state. The host supplies trusted receipts separately from the returned candidate. A search, listing or isolated quotation cannot establish a full assigned-file read. A failed read is unavailable, not proved absence.

For SCAN, `repos/reviewed/` contains the pinned files without Git metadata. `context/item.json` identifies the assigned path, blob and repository commit. The runner checks this record against the frozen assignment before it reads the tree. The record is the `scm.repository.tree` source witness for scan read receipts and citations.

The server fills verified citation coordinates from captured text. The capture manifest maps source, path, side and version to staged bytes and their digest. Core reads those bytes again and checks their digest before accepting the quote. A domain verifier can refuse unsupported semantics but cannot supply replacement text.

Core checks quotes, ambiguity and criteria warrants. Domain citation verifiers own side, version and change-basis checks. The source contract defines which sources support those coordinates. Archived or redacted proof keeps null text and coordinates instead of fabricated line 1.

### Claims that the repository lacks something

A search receipt (`SEARCHED`, path `.`) records a grep for its `pattern` over the whole checkout. The grep had no file filter and ran to the end. The receipt has no digest or line range, and it proves no file read.

A grep that the runner sees produces a search receipt, also inside a codemode script. A cut, failed, filtered or narrower grep produces none. A file listing, a search through the shell and a pattern over 500 characters produce none. A checkout that the capture holds only in part produces none. A session keeps at most 20 search receipts.

In an item review, a result says that the repository lacks something in one of two ways:

* Its search warrant or inapplicability warrant names the tree as consulted.
* The review reads a checkout, captured or not, and a text that the result shows matches an absence marker. The texts are the summary, the explanation, the example note and every warrant field. They also include each problem's summary, explanation, basis and next step, and each open question. `AbsenceClaims.java` and `pi-session-reads.ts` hold the same short list of markers. The list reads words, not the meaning of the text, so a claim in other words can pass. A clause bounded to the change or the record, such as "anywhere in the diff", is no claim. A clause that says what the review did not establish is no claim.

Such a result needs a search receipt of the tree. Admission records the pattern for audit, but it does not compare the pattern with the claim. The capture must hold the tree `COMPLETE` at the version of the receipt. A could-not-determine result says nothing about the work, so it needs no receipt.

A result keeps only the search receipts of the decision that it keeps. A review session's unchanged result keeps the searches of that session. A result that code decided keeps the searches of the script's reader.

The orchestrator prompt tells the model to grep the checkout and name the tree for such a claim. Before the runner submits a result without the receipt, it returns it to the model once for each practice. The runner submits the next result of that practice as it is. Thus, a session that cannot repair the claim does not use up the refusals of the practice. When the capture does not hold the whole checkout, the runner asks the model to remove the claim.

Then admission withholds a result without the receipt. The reason is `source_unavailable` when the capture does not hold the whole checkout. Otherwise the reason is `consulted_source_unread`.

## Admission and composition

Candidates use the strict shape in the [script runner](/contributor/practice-script-runner.md). The server allocates result and problem IDs during atomic admission. Its response includes those identities, verified citations and public eligibility. A composer cannot invent problem references or substitute failed candidate fragments.

The workspace stops at admission: the worker composes the feedback after the sandbox ends, outside this workspace. Composition reads the admitted result record, the inputs that admission retained and authorized history. Confirmed earlier feedback words enter only after custody and source-access checks. Unavailable history is a refusal, not empty history. Prepared feedback commits its exact basis and physical copies before egress.

## Output and custody

Collected output is bounded runtime data, not the sole owner of a product review. Reviews, assignments and feedback receipts remain durable independently of raw logs. A stopped or cancelled attempt cannot publish through its earlier fence. Unknown external visibility authorizes readback, never an automatic repeat write.

Erasure tracks every person's evidence dependency, including work copied into another developer's review. Mounted-store receipts survive parent cleanup until removal is acknowledged. The [data map](/admin/dsms/personal-data-map.md) owns export, retention and physical erasure.

## Practice script validation and limits

New scripts import the core author entry point and the appropriate domain kit. They return one candidate, without result-level severity or positional context. The runtime validates declared model access and brokers each call through credential-free IPC. Proof beyond a bound is withheld rather than silently truncated. The [operator script guide](/admin/practice-scripts.md) owns author tests and model limits.
