# Harness acceptance checklist Users should be able to complete the same supported workflows with every SDK and native harness. This checklist connects the existing harness bench and feature recipes; it is not another test runner or a claim that every harness has passed. Pi has the same acceptance criteria as Claude and Codex. Capability differences can justify exceptions; maintainer assignment or support tier cannot. ## Sub-features P0 is the usable-session baseline; P1 covers recovery and additional supported features. These are checklist priorities, not changes to the bench's probe priorities or CI gates. Scope a change to affected rows and consumers, and record omissions rather than treating unselected checks as passed. | ID | Priority | Observable acceptance | | --- | --- | --- | | `launch-reply` | P0 | Launch through the supported entry point; streamed output and the final answer appear once. Usage is reported where supported. | | `working-status` | P0 | A demonstrably active turn stays working through quiet model/tool work. Supported blocked states explain what input is needed. Completion, interruption and process exit settle the indicator; the next turn works. Opening or closing a terminal viewer does not change the reported state. | | `tool-history` | P0 | A real tool returns a value; a later turn uses that value without repeating the tool. Tool events and results remain visible. | | `model-effort` | P0 | Pre-launch and in-session selections reach the intended model/request. Supported effort survives a tool round trip and a later change without losing history; rejected changes do not falsely appear applied. | | `interrupt-continue` | P0 | Interrupt a demonstrably active turn, then complete another turn in the same session without stale work or a stuck running state. | | `reload-resume` | P1 | Reload/reattach and supported resume retain history and settings; a subsequent turn works without missing or duplicated output. | | `auth-recovery` | P1 | The normal credential path works; renewal during tools/later turns works where supported. Authentication failure is clear and redacted; after repair the supported continuation path works. | | `approvals` | P1 | Supported allow, deny and ask decisions reach the tool; denied side effects do not occur and the session can continue. | | `steering-queue` | P1 | Supported immediate steering and queued messages arrive once, in the intended order, including around interruption. | | `compaction` | P1 | Supported compaction finishes and a later turn works with retained context; pending messages are not lost. | | `images` | P1 | A supported image reaches the model and its reply uses the image; unsupported inputs are rejected without losing the draft. | | `fork` | P1 | A supported fork uses copied history on its first turn and remains separate from its parent. | | `mcp` | P1 | A configured, supported Omnigent MCP connection can call a harmless tool and show its result. | | `user-resources` | P1 | Supported user skills, extensions, prompts and packages remain available after launch/resume; relative paths, disabled resources and owner context controls retain their meaning. | | `interactive-input` | P1 | Supported questions and editor dialogs preserve literal/empty answers, settle cancellation, and allow a later turn to complete. | ## How to get to it (user POV) Use a separate evidence row for each applicable surface; a shared implementation does not make the surfaces interchangeable. | Surface | Entry point and owning recipe | | --- | --- | | Web new session | Pick a native harness or SDK custom agent, host/workspace, model and effort, then send. See [Composer](./composer.md) and [Custom agents](./custom-agents.md). | | Web existing session | Send follow-ups, edit configuration, interrupt, answer approvals, reload or fork. See [Composer](./composer.md), [Sessions](./sessions.md) and [Native harnesses](./native-harnesses.md). | | Native terminal / CLI | Launch using the harness's CLI entry, use supported native controls, and switch Terminal ↔ Chat. See [Native harnesses](./native-harnesses.md) and [Terminals](./terminals.md). | | SDK CLI / API | Launch a custom agent with `omnigent run` or the session API; verify the server/runner contract. The [bench](../tests/harness_bench/README.md#transport-selection) uses this boundary, not browser rendering. | | Alternate UI surfaces | Exercise mobile, fork-dialog configuration and Inbox approvals when the change affects them. Use the owning recipes above, not desktop Chat as a substitute. | ## Driving it with the repro environment Preconditions: read the [verification skill](./skills/verify-omnigent/SKILL.md) and the owning feature recipes. Use only an isolated instance you started. Record the exact commit, CLI/SDK versions and CI pins, OS, provider/model, transport, relevant feature gates and sandbox state. Keep native and SDK results separate, including `pi-native` versus `pi`. OSS using a Databricks gateway is still OSS; Managed means Databricks-deployed Omnigent and needs its own deployment evidence. ### Select harnesses and existing checks Use the capability registry through the bench rather than maintaining another list of harness names or capabilities: ```sh uv run --no-sync python -m tests.harness_bench --list uv run --no-sync python -m tests.harness_bench --list-dimensions uv run --no-sync python -m tests.harness_bench --no-live --markdown ``` The offline matrix is **declarations only**, not acceptance evidence. Select the affected SDK/native harnesses, existing/default configurations and other consumers of shared code. A capability declaration selects relevant checks; it does not prove behavior. Missing credentials or an unobservable transport are blocked/missing evidence, not reasons to mark a supported feature N/A. ### Compare harnesses by user journey Keep a dated comparison with the project's evidence, using one column per harness and separate SDK/native rows when their behavior differs. Start with Claude, Codex and Pi using the existing declared matrix: ```sh uv run --no-sync python -m tests.harness_bench --no-live --markdown \ --harness claude-sdk --harness claude-native \ --harness codex --harness codex-native --harness pi --harness pi-native ``` Omit the harness filters to include every official bench profile. Read the [capability registry](../omnigent/harness_plugins.py) and owning recipes for axes the bench does not measure, such as model families, resources, native child discovery and startup settings. Do not duplicate the registry as a second maintained capability matrix here. Each comparison cell needs two independent statements: | Dimension | What to record | | --- | --- | | Product behavior | Implemented, limited, known gap, or not established; name the surface and provider/version limits. | | Verification | Declaration/source review, mapped test, or observed pass/failure at a specific revision and transport. An unrun test is available coverage, not a pass. | Unknown declarations are not unsupported features. In particular, a generic elicitation flag does not describe every policy bridge or extension dialog; Omnigent subagent tools and vendor-child discovery are different journeys. Compare like-for-like observations before calling one harness more reliable. Keep OSS, live-gateway and Managed evidence separate. For a short CUJ table, include core turns, model/effort choice, history recovery, user resources, interactive input, native child visibility and remaining acceptance gaps. ### Existing coverage and gaps Bench dimensions below are reusable checks, not complete coverage of a row. Use the [bench transport matrix](../tests/harness_bench/README.md#coverage-by-transport) and each harness's [mapped tests](./native-harnesses.md#driving-it-with-the-repro-environment) to identify the actual boundary. A dash means no shared bench probe, not that no harness-specific tests exist. No passing per-harness results are implied. | Checklist ID | Bench dimensions | Existing automation / remaining gap | | --- | --- | --- | | `launch-reply` | `basic_turn`, `streaming`, `cost_tracking` | Also check authored instructions for custom agents via the [native instruction recipe](./native-harnesses.md#driving-it-with-the-repro-environment); bench replies alone do not prove delivery. Server/runner observations; browser launch/rendering and exact-once presentation need the owning UI tests. | | `working-status` | — | No shared status-continuity probe. Use the [native working-status recipe](./native-harnesses.md#driving-it-with-the-repro-environment) for Claude OSC/file fallback and UI status routing; SDK lifecycle and other natives need their own evidence. A completed basic turn does not prove quiet-work or blocked-state accuracy. | | `tool-history` | `tool_calling` | Tool round trip only. Later-turn recall is not a shared probe; reuse the Pi scenarios below and identify other harness coverage explicitly. | | `model-effort` | `model_override`, `reasoning` | Native-TUI model override is currently skipped; SDK routing/reasoning observations are narrower than selection persistence. Reasoning output does not prove outgoing effort, tool continuity, High→Low or UI state. | | `interrupt-continue` | `interrupt` | Cancellation signal/early termination; follow-up recovery needs a separate assertion in the same session. | | `reload-resume` | — | No shared resume/reconnect probe. Existing native resume/disconnect tests and session/terminal recipes cover specific harnesses and boundaries only. | | `auth-recovery` | — | No shared auth-renewal probe. Reuse the owning harness credential tests; distinguish injected rotation from real elapsed expiry. | | `approvals` | `policy_allow`, `policy_deny`, `policy_ask` | Supported policy paths through the chosen transport; Chat/Inbox presentation and post-decision continuation need their own evidence. | | `steering-queue` | — | No shared probe. Map the harness-specific steer/queue scenarios from Composer and Native harnesses. | | `compaction` | — | No shared probe. Use the Composer compaction recipe and the harness's supported entry points. | | `images` | — | No shared probe. Attachment UI alone does not establish delivery to a real harness/model. | | `fork` | `fork_replay` | Copied-history use through server/runner; fork dialog, alternate targets and parent isolation need the Sessions recipe. | | `mcp` | `omnigent_mcp` | Read-only relay tool for supported natives; Settings inventory alone is not a tool-execution check. | | `user-resources` | — | Use the Pi resource recipes below and the native skill/plugin recipes. No shared cross-harness resource-loading probe; file linking alone does not prove runtime discovery or marketplace compatibility. | | `interactive-input` | — | `tests/e2e/test_pi_extension_ui_round_trip.py` drives SDK/native Pi through the approval API. The [native dialog recipe](./native-harnesses.md#driving-it-with-the-repro-environment) separately covers browser answers. No shared cross-harness dialog probe. | Start the tool/history/effort continuity work by extending compatible scenarios, not by copying their server/runner setup: - SDK Pi: `tests/e2e/omnigent/test_pi_retry_session_sync_e2e.py::test_pi_session_stays_in_sync_after_retry_recovery`. - Native Pi: `tests/e2e/test_pi_native_model_scope_e2e.py::test_generic_provider_delivers_effort_through_native_tool_turn`. - Browser selection: the [Composer model/effort recipes](./composer.md#driving-it-with-the-repro-environment). These are starting points, not proof for other harnesses or providers. When generalizing a scenario, keep assertions shared and transport-specific setup in the existing drivers/[primitives](../tests/_helpers/README.md). Keep input matrices at the lowest reliable layer; retain browser/process cases for distinct boundaries. Do not move or replace working regression coverage just to fit the checklist. ### Pi SDK large tool requests For the transport portion of `tool-history`, run `pytest tests/inner/test_pi_executor.py -k TestToolServer --reruns 0 -q` with Node installed. The generated bridge sends a request larger than 64 KiB, then another tool call in the same Node process. The oversized case checks the exact size-limit error, no rejected tool execution, redacted diagnostics, and a successful next call. Real TCP cases cover a sender still writing and bounded cleanup of truncated or stalled input. Rejection tests reduce the production 16 MiB request limit. These checks use the production generated extension and loopback server with a test tool executor and Pi registration stub. They do not launch Pi, exercise the server/runner or browser entry points, or establish later-turn model recall. Native Pi uses a separate tool path. To verify the SDK CLI/API journey, use a Pi custom agent with a harmless tool accepting a large string; send a request over 64 KiB but below 16 MiB, then one above the limit, and confirm another small tool call succeeds after each. The limit includes the serialized request envelope, not only its arguments. ### Pi SDK compaction and restart (own environment) For `compaction`, `reload-resume` and `fork`, run `tests/e2e/test_pi_compact_restart_resume.py::test_pi_compacted_session_resumes_compacted_after_restart`. It drives the real Pi CLI through a server/runner with a scripted provider and a 32k context limit. After repeated compactions, restart both processes and continue the session, then fork it and continue the copy. Both outgoing requests must retain the summary and recent context, omit summarized turns and fit the window; the fork must leave its parent unchanged. This is an API/process check, not browser reload or live-provider acceptance. Existing sessions without a saved compaction checkpoint are not repaired by this recipe. After compaction, a failed streamed retry is aborted and drained to settlement before exporting context and evicting Pi; retry text is suppressed. If settlement or context export fails, the fallback retains only the summary and loses recent kept context. Component tests cover these failure paths separately. ### Pi SDK bundled resources (own environment) For `launch-reply`, launch an uploaded Pi agent bundle through the server/runner, then run `omnigent run ` from a sibling workspace under Linux Bubblewrap. Include an extension, a skill and bundle-root instructions; verify all reach the provider request and that tools still use the session workspace. Existing scenarios: `tests/e2e/omnigent/test_pi_bundle_extensions_cwd_e2e.py`, `tests/e2e/omnigent/test_pi_bundle_project_resources_e2e.py`, and `tests/e2e/omnigent/test_pi_managed_extensions_e2e.py`. The managed-extensions filename refers to extension provisioning, not Managed Omnigent. The uploaded-bundle and existing global-extension CLI scenarios cover unsandboxed startup; the separate CLI bundle case covers real Bubblewrap isolation; a macOS skip does not validate that boundary. Native Pi resource discovery is a separate path. Run the scoped `launch-reply` checks (own environments; real Pi, scripted provider): ```sh uv run --no-sync pytest tests/e2e/omnigent/test_pi_bundle_extensions_cwd_e2e.py tests/e2e/omnigent/test_pi_bundle_project_resources_e2e.py tests/e2e/omnigent/test_pi_managed_extensions_e2e.py --reruns 0 -q ``` ### Pi user resources (own environments) For `user-resources`, `launch-reply` and `reload-resume`, configure Pi skills/extensions in the user agent root, with relative local-package paths and disabled-resource patterns. `tests/e2e/omnigent/test_pi_managed_extensions_e2e.py` drives SDK CLI startup with default and relative custom roots; inspect provider requests for loaded skills, package markers, excluded extensions, and unchanged SDK tool restrictions. `tests/e2e/omnigent/test_pi_context_files_e2e.py` checks that context/prompt controls and `skills: none` still apply, and that the user root's `AGENTS.md` follows `context_files`. Native startup/resume is covered by `tests/e2e/test_pi_native_cold_resume_model_rewrite_e2e.py` through server/host/runner. A host custom root uses the existing explicit `OMNIGENT_RUNNER_ENV_PASSTHROUGH=PI_CODING_AGENT_DIR` setting. These scenarios use real Pi with scripted providers or prompt-observer extensions; they do not establish marketplace compatibility, browser rendering, live MCP OAuth, OS sandbox or Managed deployment acceptance. Linked resources, including global context files, are shared writable files; `SYSTEM.md`, `APPEND_SYSTEM.md`, model credentials and session state stay separate. ### Deterministic checks versus live canaries | Lane | Use | What a pass does not prove | | --- | --- | --- | | Deterministic regression | Components, real processes with scripted providers, and existing browser tests. Run relevant existing targets with retries disabled. | Live provider compatibility or elapsed credential expiry. | | Authorized live canary | Exact versions/model through the real runtime; bounded prompts and harmless tools. Repeat the selected workflow, not just an isolated HTTP request. | Every model, OS, deployment or browser surface. | The verification environment configures mock Claude/Codex, not every harness. Other harnesses use the owning scenario's isolated setup. A missing vendor CLI or credential must remain visible. Do not change global rollout settings or reuse a developer daemon to obtain a passing result. For mock journeys, verify that the test's unique user prompt reaches the mock under the intended model. A reply that echoes an expected token, or a nonzero background-request count, is insufficient. Native Claude mock sessions reject conflicting machine-managed routing before launch; isolated user directories do not override machine policy. Run on a clean container/CI host and record the blocked local attempt separately (see [native prerequisites](./native-harnesses.md#driving-it-with-the-repro-environment)). For an **authorized** live bench slice, use an explicit harness/model and require observations. This example runs SDK Pi; select `pi-native` separately for native: ```sh uv run --no-sync python -m tests.harness_bench --live --require-complete \ --harness pi=system.ai.deepseek-v4-1-flash \ --dimension basic_turn,streaming,tool_calling \ --json --report /tmp/pi-harness-results.json ``` Choose a model actually served by your provider; the example is not an endpoint availability guarantee. The current native-TUI driver does not apply the bench model override: configure and verify its actual selected model separately, and do not claim `--harness pi-native=MODEL` pinned the request. A complete, drift-free bench report covers only its selected dimensions/transport. Check the acceptance assertions above as well: an expected `PARTIAL` or `UNSUPPORTED` verdict is not a pass for a required workflow. This checklist adds no repository-wide or Resolve gate, scheduler, paid live run, or automatic rollout requirement. ### Record per-harness evidence Copy this table into the PR's Test Plan or linked evidence. Expand it for **every affected harness × checklist ID × entry point/configuration**; do not combine SDK/native, mock/live or OSS/Managed results. Include gaps even where no test exists. Add an owner/next step for unresolved rows. | Harness / transport / model | Checklist ID / entry point | Coverage | Run result | Evidence / gap / owner | | --- | --- | --- | --- | --- | | Fill exact configuration | Fill ID and surface | Covered / Partial / Missing / N/A | Pass / Fail / Blocked / Not run / N/A | Test or manual steps, command, artifact and remaining action | - **Coverage** describes available checks, not their outcome. Covered means all assertions for that row/surface have a test or explicit manual recipe; Partial lists missing assertions; Missing has no matching check yet. N/A needs a capability/surface reason, never a support-tier exemption. - **Run result** describes this exact revision/environment. Missing setup, skipped probes and inconclusive observations are Blocked, with the reason; unexecuted checks are Not run. Preserve the bench's raw verdicts beside the acceptance result. Failures must not be relabeled as coverage gaps. - **Evidence** includes the version/configuration record, actual command and result, redacted request fields or process/session transcript, and media for user-visible claims following the [PR demo standard](README.md#pr-demo-standard). Put the recording and its evidence caption in Demo; link it from the relevant table rows without treating one recording as proof for unshown workflows. Keep failed attempts; do not publish tokens. ## Gotchas - A matrix row, a linked test, an offline report or a green docs validator is not proof that the harness ran. `--require-complete` prevents silent missing bench observations; it does not validate this entire checklist or browser UI. - Tool, reasoning and interrupt probes are independent checks, not a substitute for a single session surviving tools, effort changes and follow-ups. - For Pi gateway reasoning, include a model whose metadata exists only in its vendor catalog (for example GPT), alongside a Databricks-catalog model (Gemini). Observe outgoing effort through a tool result and follow-up; a pre-enriched model fixture or a visible High label alone misses catalog fallback failures. - Browser reload is not runner restart; neither is credential renewal. Test the boundary affected by the change and name unrun boundaries explicitly. - Use the same baseline for all affected harnesses. Until a gap is covered, report it with an owner rather than reducing acceptance for a tier-2 harness.