@agentskit/harness 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/CHANGELOG.md +77 -0
  2. package/CODE_OF_CONDUCT.md +5 -0
  3. package/CONTRIBUTING.md +26 -0
  4. package/LICENSE +21 -0
  5. package/README.md +473 -0
  6. package/SECURITY.md +11 -0
  7. package/dist/cli.js +1308 -0
  8. package/dist/cli.js.map +1 -0
  9. package/dist/index.d.ts +968 -0
  10. package/dist/index.js +1828 -0
  11. package/dist/index.js.map +1 -0
  12. package/docs/ADR-0001-extensible-kernel.md +41 -0
  13. package/docs/ADR-0002-profiles-and-context.md +22 -0
  14. package/docs/ADR-0003-doc-bridge-context-binding.md +36 -0
  15. package/docs/ADR-0004-run-metrics.md +29 -0
  16. package/docs/ADR-0005-benchmark-manifest.md +27 -0
  17. package/docs/ADR-0006-agent-session-protocol.md +36 -0
  18. package/docs/ADR-0007-policy-gate.md +33 -0
  19. package/docs/ADR-0008-runtime-executor.md +33 -0
  20. package/docs/ADR-0009-process-runtime-boundary.md +34 -0
  21. package/docs/ADR-0010-docker-sandbox-runtime.md +32 -0
  22. package/docs/ADR-0011-runtime-attestation.md +30 -0
  23. package/docs/ADR-0012-controlled-baseline-observations.md +27 -0
  24. package/docs/ADR-0013-honest-benchmark-comparability.md +27 -0
  25. package/docs/ADR-0014-criterion-level-benchmark-evidence.md +24 -0
  26. package/docs/ADR-0015-directional-benchmark-outcomes.md +23 -0
  27. package/docs/ADR-0016-baseline-evidence-digests.md +21 -0
  28. package/docs/ADR-0017-event-log-integrity.md +25 -0
  29. package/docs/ADR-0018-verification-projection-attestation.md +23 -0
  30. package/docs/ADR-0019-human-decision-attestation.md +27 -0
  31. package/docs/ADR-0020-terminal-reconciliation.md +26 -0
  32. package/docs/ADR-0021-event-lock-recovery.md +25 -0
  33. package/docs/ADR-0022-signed-evidence-bundle.md +27 -0
  34. package/docs/ADR-0023-safe-action-recovery.md +30 -0
  35. package/docs/ADR-0024-controlled-completion-metrics.md +27 -0
  36. package/docs/ADR-0025-ci-dogfood.md +22 -0
  37. package/docs/ADR-0026-ci-evidence-artifact.md +22 -0
  38. package/docs/ADR-0027-portable-evidence.md +19 -0
  39. package/docs/ADR-0028-effective-metrics.md +20 -0
  40. package/docs/ADR-0029-honest-ci-preparation.md +20 -0
  41. package/docs/ADR-0030-agentskit-os-benchmark-bridge.md +20 -0
  42. package/docs/ADR-0031-real-provider-baseline.md +18 -0
  43. package/docs/ADR-0032-harness-equivalent-benchmark.md +25 -0
  44. package/docs/ADR-0033-portable-agent-gate.md +25 -0
  45. package/docs/ADR-0034-measurement-quality-gates.md +25 -0
  46. package/docs/ADR-0035-reproducible-benchmark-samples.md +20 -0
  47. package/docs/ADR-0036-comparable-baseline-samples.md +20 -0
  48. package/docs/ADR-0037-replicated-baseline-collection.md +27 -0
  49. package/docs/ADR-0038-end-to-end-benchmark-boundary.md +28 -0
  50. package/docs/ADR-0039-artifact-and-protocol-metrics.md +39 -0
  51. package/docs/ADR-0040-benchmark-corpus-surfaces.md +32 -0
  52. package/package.json +68 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,77 @@
1
+ # Changelog
2
+
3
+ All notable changes to `@agentskit/harness` are documented here.
4
+
5
+ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and the package follows Semantic Versioning.
6
+
7
+ ## [0.1.0] - 2026-08-31
8
+
9
+ ### Added
10
+
11
+ - Replicated baseline collection with independent disposable samples, median
12
+ duration recording, and atomic complete-manifest replacement.
13
+ - Baseline samples use the same end-to-end measurement boundary as the harness
14
+ check while retaining provider-only duration for diagnosis.
15
+ - Incomplete baselines no longer qualify for duration or resource comparisons;
16
+ escape reduction remains visible as a separate outcome metric.
17
+ - Baseline reports expose artifact acceptance separately from protocol
18
+ completion, preserving useful outcome data without weakening fail-closed
19
+ comparison gates.
20
+ - Benchmark execution supports collision-safe task-specific replacement
21
+ samples, preserving blocked and timed-out evidence.
22
+ - Benchmark comparisons expose artifact acceptance rates and protocol
23
+ completion rates separately from performance comparability.
24
+ - Protocol and artifact acceptance comparisons expose absolute deltas when
25
+ relative improvement is undefined because the baseline was zero.
26
+ - Benchmark tasks declare typed surface coverage; the AgentsKit OS corpus
27
+ includes executable CLI and documentation tasks with real acceptance
28
+ validation.
29
+ - Fail-closed baseline sample policy and median baseline duration support for fair replicated comparisons.
30
+ - Independent benchmark samples with median-duration comparisons and retry metrics that do not confuse replication with retries.
31
+ - Configurable benchmark quality gates, confidence labels, and explicit retry metrics.
32
+ - Portable `ak-verify` fixture gate for real coding-agent benchmark runs; provider delivery remains blocked until its result is complete and human approval is recorded.
33
+ - Harness-equivalent benchmark preparation and collection for paired real-provider runs, with explicit human approval and honest non-comparability.
34
+ - Source snapshots now ignore untracked directories while retaining hashes for untracked files.
35
+ - Reproducible disposable-fixture runner and validator for the first real-provider AgentsKit OS baseline; improvement remains unavailable until equivalent harness runs exist.
36
+ - Provenance-bearing benchmark tasks and a portable validator for AgentsKit OS coding benchmark reports; missing controlled observations remain explicitly non-comparable.
37
+ - Playbook CI dogfooding for the package test suite, built CLI, and clean packed consumer.
38
+ - Playbook CI now preserves the official harness run as an auditable artifact for human review.
39
+ - Signed evidence flow now verifies a copied bundle from an isolated directory.
40
+ - Benchmark reports now separate effective non-superseded delivery metrics from attempt history.
41
+ - CI evidence now records automated preparation separately from human contract approval.
42
+ - Strict TypeScript modular core with generated declarations and source maps.
43
+ - Contract-frozen lifecycle, structured evidence, stale detection, human approval, retry, and cleanup.
44
+ - Explicit human cancellation and superseded retry history.
45
+ - Typed dependency-aware plugin lifecycle with deterministic cleanup.
46
+ - Append-only, source- and contract-bound lifecycle event log per run.
47
+ - Declarative profile inheritance with validated check overrides.
48
+ - Optional provenance-bearing context provider slot for Doc Bridge and Playbook adapters.
49
+ - Dependency-free Doc Bridge index adapter with deterministic references and frozen context snapshots.
50
+ - Context lifecycle events and stable context hashes that ignore resolution timestamps.
51
+ - Portable CLI snapshot resolution and `plan --context-file` binding for shell-based agents.
52
+ - Tamper-evident validation for imported context snapshots.
53
+ - Direct API callers now receive the same tamper-evident context validation as CLI callers.
54
+ - `benchmarkRuns` and `ak-harness benchmark` for reproducible historical run metrics.
55
+ - Phase 0 benchmark manifests, task identity bindings, and explicit baseline comparisons.
56
+ - Typed agent session recorder with correlated turn/tool events and guarded ordering.
57
+ - Adapter metadata and session event protocol that persists hashes instead of raw agent content.
58
+ - Required deny-by-default Policy Gate with ordered rules and correlated blocked-tool events.
59
+ - Bounded in-process tool runtime with timeout, abort signal, hashed results, and structured failures.
60
+ - Shell-free child-process runtime with timeout, output limits, and structured process failures.
61
+ - Optional Docker runtime with a no-network, read-only, unprivileged, resource-limited sandbox profile.
62
+ - Typed runtime attestation with Docker image digest and effective profile hash in terminal tool events.
63
+ - Controlled baseline observation recording through the typed API and `ak-harness benchmark baseline`, with duplicate, unknown-task, and atomic-write protections.
64
+ - Benchmark comparisons now require completed harness evidence and report honest non-comparability reasons plus check, outcome, evidence, and review metrics.
65
+ - Benchmark baselines now require explicit, unique criterion-level evidence; comparisons report baseline evidence coverage and reject incomplete evidence.
66
+ - Comparable benchmark reports now expose directional duration, attempt, and human-review outcomes, with `unavailable` for non-comparable tasks.
67
+ - CLI-recorded baseline evidence now preserves a SHA-256 digest of the evidence file and validates digest format on manifest load.
68
+ - New lifecycle event logs carry a chained SHA-256 digest and expose explicit integrity verification; legacy logs remain readable but are not reported as verified.
69
+ - Event-log locks now carry owner metadata and expose explicit human-authorized stale-lock inspection and recovery through the API and `events lock|unlock` CLI commands.
70
+ - Signed evidence verification now supports stable key identities and explicit active/revoked trust stores for controlled key rotation.
71
+ - Policy rules can require explicit human approval before sensitive tool actions enter the runtime; unresolved and rejected approvals remain fail-closed and auditable.
72
+ - Agent sessions can be resumed from their hash-chained event log, preserving pending approvals without replaying completed tools.
73
+ - Ambiguous resumed tool actions now require an explicit human retry or abandonment decision after `tool.execution.started`.
74
+ - Benchmark comparisons now expose controlled `escapedIncomplete` deltas for measuring incomplete deliveries that escaped validation.
75
+ - Verification results now carry a projection digest in `run.json` and a matching `verification.completed` event; approval rejects projection tampering.
76
+ - `ak-harness` CLI and `ak-verify` common-protocol alias.
77
+ - Public package documentation and community policy files.
@@ -0,0 +1,5 @@
1
+ # Code of Conduct
2
+
3
+ Contributors are expected to communicate respectfully, assume good faith, and keep technical review focused on behavior, evidence, and maintainability.
4
+
5
+ Harassment, discrimination, threats, and deliberate exposure of private information are not acceptable. Maintainers may remove contributions or restrict participation when this standard is violated.
@@ -0,0 +1,26 @@
1
+ # Contributing to `@agentskit/harness`
2
+
3
+ ## Before opening a change
4
+
5
+ 1. State the behavior and failure mode the change addresses.
6
+ 2. Keep the public API in `src/index.ts` intentionally small.
7
+ 3. Add or update a typed test for every behavior change.
8
+ 4. Update the README, changelog, and contract when the user-facing protocol changes.
9
+
10
+ ## Local checks
11
+
12
+ ```bash
13
+ pnpm --filter @agentskit/harness typecheck
14
+ pnpm --filter @agentskit/harness test
15
+ pnpm --filter @agentskit/harness build
16
+ ```
17
+
18
+ Do not claim completion when a required check is unavailable. Preserve criterion-level evidence and report blocked work honestly.
19
+
20
+ ## Pull requests
21
+
22
+ Use a focused branch and commit. Describe the contract change, affected states, evidence produced, and exact commands executed. Breaking public API or CLI changes require a changelog entry and a maintainer review.
23
+
24
+ ## License
25
+
26
+ Contributions are accepted under the repository's MIT license.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 AgentsKit Contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,473 @@
1
+ # @agentskit/harness
2
+
3
+ Portable, evidence-backed development protocol for coding agents. The harness freezes a human-approved task contract, executes every configured check, binds evidence to the current source revision, detects stale results, and refuses completion without human approval.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ pnpm add -D @agentskit/harness
9
+ ```
10
+
11
+ The package requires Node.js 22 or newer and exposes both `ak-harness` and the common-protocol alias `ak-verify`.
12
+
13
+ ## Workflow
14
+
15
+ ```bash
16
+ ak-harness doctor --json
17
+ ak-harness plan approved --by human
18
+ ak-harness start
19
+ ak-verify run --json
20
+ ak-verify approve <run-id> approved --by human --json
21
+ ak-harness cancel <run-id> --by human --reason "Requirements changed"
22
+ ak-harness benchmark --manifest benchmarks/harness-phase-0.json --json
23
+ ```
24
+
25
+ `plan` rejects unresolved ambiguities and unauthorized dirty worktrees. After `start`, the contract is frozen. Any source, configuration, or contract change invalidates evidence and moves the run to `STALE`. A human can cancel an active run; retrying a blocked, stale, or cancelled run marks the previous run `SUPERSEDED`.
26
+
27
+ Automated CI may prepare a run with `ak-harness plan prepared --by ci`. This records a CI preparation, never a human approval; the run remains unable to become `COMPLETE` until a human approves the verified result.
28
+
29
+ ## External coding benchmark bridge
30
+
31
+ The harness validates a provenance-bearing task manifest and the JSON report
32
+ emitted by an external coding benchmark, including AgentsKit OS:
33
+
34
+ ```bash
35
+ AGENTSKIT_OS_ROOT=/path/to/agentskit-os \
36
+ AGENTSKIT_OS_BENCHMARK_REPORT=/path/to/report.json \
37
+ node scripts/verify-harness-agentskit-os-benchmark.mjs \
38
+ --manifest benchmarks/agentskit-os-phase-28.json \
39
+ --target "$AGENTSKIT_OS_ROOT" \
40
+ --report "$AGENTSKIT_OS_BENCHMARK_REPORT"
41
+ ```
42
+
43
+ The bridge checks the pinned source revision, task definition, prompt digests,
44
+ scope, and provider report shape. Provider status and heuristic scores remain
45
+ observations: they do not grant human acceptance. With no controlled baseline,
46
+ improvement is reported as unavailable rather than inferred.
47
+
48
+ The phase-45 corpus adds explicit task surfaces and keeps the task definition
49
+ bound to the real AgentsKit OS fixture. It covers logic, CLI, and documentation
50
+ surfaces; the added CLI task executes compact, pretty, and invalid-input paths,
51
+ while the documentation task checks the API contract and its reproducible test
52
+ command:
53
+
54
+ ```bash
55
+ node scripts/verify-harness-agentskit-os-benchmark.mjs \
56
+ --manifest benchmarks/agentskit-os-phase-45.json \
57
+ --target /path/to/agentskit-os \
58
+ --require-surface-coverage logic,cli,docs
59
+ ```
60
+
61
+ Corpus coverage is a readiness gate, not a performance claim. Live provider
62
+ samples and human approval remain required before the expanded tasks become
63
+ comparable benchmark evidence.
64
+
65
+ Phase 29 adds a reproducible real-provider baseline runner for the AgentsKit OS
66
+ seed corpus. It uses disposable fixture copies, the existing OS benchmark
67
+ runner, and task-specific validation:
68
+
69
+ ```bash
70
+ node scripts/run-agentskit-os-baseline.mjs \
71
+ --target /path/to/agentskit-os \
72
+ --provider codex \
73
+ --output benchmarks/agentskit-os-phase-29-baseline
74
+ ```
75
+
76
+ The observations are not an improvement claim until equivalent harness runs
77
+ exist.
78
+
79
+ To collect equivalent baseline samples, run the same corpus independently and
80
+ record the aggregate only after every task has been sampled:
81
+
82
+ ```bash
83
+ node scripts/run-agentskit-os-baseline.mjs \
84
+ --target /path/to/agentskit-os \
85
+ --provider codex \
86
+ --repeats 3 \
87
+ --output benchmarks/agentskit-os-phase-36-baseline \
88
+ --record-manifest benchmarks/agentskit-os-phase-28.json
89
+ ```
90
+
91
+ Each repeat uses a fresh disposable fixture. The report stores the end-to-end
92
+ duration of fixture setup, provider execution, validation, and cleanup in
93
+ `durationSamplesMs`; the provider's own duration remains nested in the raw
94
+ report. The manifest is replaced atomically through
95
+ the typed observation recorder. `--record-manifest` requires the complete task
96
+ set; omit it to inspect an uncommitted collection. Replicas are not retries,
97
+ and a failed sample keeps the aggregate failed. Escape reduction may remain
98
+ visible as a separate outcome, but duration, attempt, and review improvements
99
+ remain unavailable until the baseline proves complete delivery.
100
+
101
+ ## Contract
102
+
103
+ Every repository supplies `.codex/verification.json` with explicit scope, outcomes, applicable surfaces, and executable checks. Each check must declare `evidence: "structured"`; its final output line must be JSON and map to the outcome IDs it proves:
104
+
105
+ ```json
106
+ {"status":"passed","criteria":["api-behavior"]}
107
+ ```
108
+
109
+ Endpoint, database, CLI, MCP, and UI checks must declare `execution: "real"`. UI checks additionally require `real-browser` and `screenshot` capabilities. Screenshot artifacts carry a project-relative path, SHA-256 hash, and viewport.
110
+
111
+ ## API
112
+
113
+ The public TypeScript API is exported from `src/index.ts` and includes configuration loading, lifecycle operations, state transitions, evidence verification, approvals, cancellation, retries, and task-owned cleanup. Internal modules are not part of the supported API.
114
+
115
+ ## Extensibility
116
+
117
+ The kernel stays responsible for contracts, state transitions, evidence, source
118
+ binding, stale detection, and human decisions. Optional integrations use the
119
+ typed plugin registry instead of changing those guarantees:
120
+
121
+ ```ts
122
+ import { createPluginRegistry, createPluginSlot } from '@agentskit/harness'
123
+
124
+ const providers = createPluginSlot<{ readonly resolve: (query: string) => Promise<string> }>('context.provider')
125
+ const registry = createPluginRegistry()
126
+ registry.register({
127
+ id: 'my-context', version: '1.0.0', apiVersion: 1,
128
+ apply: (context) => {
129
+ context.register(providers, 'local', { resolve: async (query) => `context:${query}` })
130
+ },
131
+ })
132
+ registry.mount()
133
+ // registry.contributions(providers) is deterministic and typed.
134
+ registry.dispose()
135
+ ```
136
+
137
+ Each run also writes an append-only `events.ndjson` containing lifecycle facts
138
+ bound to its source revision and contract hash. New event logs carry a chained
139
+ SHA-256 digest; verify one with `ak-harness events verify [run-id]`. Logs from
140
+ older harness versions remain readable but are reported as `legacy`, not as
141
+ verified. After verification, `run.json` also carries a `verificationDigest`
142
+ that must match the `verification.completed` event before human approval. Human
143
+ approvals, rejections, and tracking authorizations are then recorded as
144
+ hash-chained `approval.recorded` or `authorization.recorded` events bound to
145
+ that digest, source revision, and contract hash. The stable `run.json` remains
146
+ the CLI projection and evidence index.
147
+
148
+ Use `ak-harness audit [run-id]` to reconcile a run projection with its verified
149
+ events. `ak-harness status` performs the same reconciliation before reporting
150
+ the current state, so a post-approval edit cannot appear as `COMPLETE`.
151
+ Concurrent event writers are serialized by an atomic per-run lock and fail
152
+ closed if the log is busy.
153
+
154
+ Export a reconciled `COMPLETE` run for external review with an Ed25519 key:
155
+
156
+ ```bash
157
+ ak-harness events export <run-id> --output evidence.json --private-key private.pem --key-id release-v1
158
+ ak-harness events verify-bundle evidence.json --trusted-key-store trust-store.json
159
+ ```
160
+
161
+ The bundle includes the run projection, event log, and referenced check outputs,
162
+ each with a SHA-256 digest. A trust store can mark keys `active` or `revoked` to
163
+ support controlled key rotation. Treat exported outputs as potentially sensitive.
164
+
165
+ The signed bundle is self-contained: it can be copied to an isolated directory
166
+ and verified there with only the bundle and the trusted public key.
167
+
168
+ Profiles are optional declarative overlays in `.codex/verification.json`. They
169
+ inherit in order, override existing checks by ID, and are resolved before the
170
+ contract is frozen:
171
+
172
+ ```json
173
+ {
174
+ "profile": "ci",
175
+ "profiles": {
176
+ "ci": {
177
+ "checkOverrides": [{ "id": "unit", "timeoutMs": 120000 }],
178
+ "budget": { "maxDurationMs": 900000 }
179
+ }
180
+ }
181
+ }
182
+ ```
183
+
184
+ Doc Bridge and Playbook integrations can implement `ContextProvider` and
185
+ register it through `CONTEXT_PROVIDER_SLOT`; the kernel records neither their
186
+ credentials nor their transport and does not depend on either package. The
187
+ portable adapter reads a local Doc Bridge index without adding a dependency:
188
+
189
+ ```ts
190
+ import { createDocBridgeContextProvider, planRun } from '@agentskit/harness'
191
+
192
+ const provider = createDocBridgeContextProvider({ root: process.cwd() })
193
+ const context = await provider.resolve({ query: 'harness', scope: ['playbook'] })
194
+ const run = await planRun({
195
+ configPath: '.codex/verification.json',
196
+ decision: 'approved',
197
+ contextSnapshots: [context],
198
+ })
199
+ ```
200
+
201
+ The same boundary is available to shell-based agents:
202
+
203
+ ```bash
204
+ ak-harness context resolve harness --scope playbook --json > context.json
205
+ ak-harness plan approved --context-file context.json --json
206
+ ```
207
+
208
+ `context.json` may contain one snapshot or an array of snapshots, so providers
209
+ outside this package can participate without a runtime plugin loader.
210
+ The loader rejects a snapshot when its semantic contents no longer match its
211
+ `snapshotHash`.
212
+
213
+ The snapshot stores the Doc Bridge `contentHash`, reference hashes, and a
214
+ stable `contextHash`; resolution time is metadata and does not change the
215
+ reproducibility hash. Context is resolved before planning and is frozen with
216
+ the run, so later index changes cannot silently change its evidence.
217
+
218
+ Agent sessions can record adapter identity, turns, and guarded tool actions
219
+ during `IMPLEMENTING` without persisting prompt, argument, or result contents:
220
+
221
+ ```ts
222
+ import { createSessionRecorder } from '@agentskit/harness'
223
+
224
+ const session = createSessionRecorder({
225
+ stateDir: '.codex/verification',
226
+ run: implementingRun,
227
+ adapter: { id: 'my-agent', version: '1.0.0', capabilities: ['tool-calls'] },
228
+ policy,
229
+ runtime,
230
+ })
231
+ const turn = session.startTurn(inputHash)
232
+ const action = session.requestTool({ turnId: turn.payload.turnId, toolId: 'shell', argumentsHash })
233
+ await session.executeTool({ actionId: action.payload.actionId, arguments: { command: 'echo ok' } })
234
+ session.end('completed')
235
+
236
+ // After a process interruption, recover the same session from events.ndjson.
237
+ const resumed = createSessionRecorder({ stateDir, run, adapter, policy, runtime, sessionId: session.sessionId, resume: true })
238
+ ```
239
+
240
+ The recorder enforces turn-before-tool, one terminal result per action, no
241
+ pending actions or unresolved approvals at session end, and no calls after
242
+ termination. With `resume: true`, it reconstructs turns, pending actions, and
243
+ approval decisions from the hash-chained event log; completed actions are not
244
+ replayed. It is an observation seam; tool execution and policy decisions remain
245
+ separate kernel phases.
246
+
247
+ Every session also requires a policy gate. The built-in gate is an ordered
248
+ allow/block/approve list with deny-by-default behavior:
249
+
250
+ ```ts
251
+ import { createPolicyGate, createSessionRecorder } from '@agentskit/harness'
252
+
253
+ const policy = createPolicyGate({
254
+ rules: [{ id: 'safe-shell', effect: 'allow', toolIds: ['shell'], reason: 'approved local tool' }],
255
+ })
256
+ const session = createSessionRecorder({ stateDir, run, adapter, policy })
257
+ ```
258
+
259
+ The first matching rule wins. A blocked attempt writes `policy.evaluated` and
260
+ `tool.blocked` events and raises `POLICY_BLOCKED`; it never becomes a pending
261
+ tool action. An `approve` decision writes `tool.approval.requested` and keeps
262
+ the action out of the runtime until `session.approveTool({ actionId,
263
+ decision: 'approved' })` is called by a human. Rejection writes an auditable
264
+ `tool.approval.recorded` and `tool.blocked` pair. Custom policy gates can
265
+ implement the same typed `PolicyGate` interface without coupling the harness
266
+ to a runtime or provider.
267
+
268
+ When resuming, an action with a persisted `tool.execution.started` event is
269
+ ambiguous: its runtime may have produced an external side effect before the
270
+ process stopped. The harness refuses to execute it until a human calls
271
+ `session.recoverTool({ actionId, decision: 'retry', actor: 'human' })` or
272
+ `session.recoverTool({ actionId, decision: 'abandon', actor: 'human' })`.
273
+ Actions that were requested but never started remain safe to execute after
274
+ recovery. Completed actions are never replayed.
275
+
276
+ The built-in runtime executes registered handlers in memory, passes an
277
+ `AbortSignal`, enforces a timeout, and records only a result hash and duration:
278
+
279
+ ```ts
280
+ import { createToolRuntime } from '@agentskit/harness'
281
+
282
+ const runtime = createToolRuntime({
283
+ timeoutMs: 30_000,
284
+ tools: [{ toolId: 'shell', execute: async ({ arguments: input }) => runShell(input) }],
285
+ })
286
+ ```
287
+
288
+ Missing tools, handler errors, and timeouts become structured failures. This is
289
+ an execution boundary, not a process/container security sandbox; use a
290
+ provider-specific isolated runtime when hard isolation is required.
291
+
292
+ For a shell-free child-process boundary, register fixed commands with
293
+ `createProcessToolRuntime`. It sends one JSON request over stdin, kills a
294
+ timed-out or oversized process, and hashes stdout without storing it:
295
+
296
+ ```ts
297
+ import { createProcessToolRuntime } from '@agentskit/harness'
298
+
299
+ const runtime = createProcessToolRuntime({
300
+ timeoutMs: 30_000,
301
+ maxOutputBytes: 1_048_576,
302
+ tools: [{ toolId: 'worker', command: process.execPath, args: ['worker.mjs'] }],
303
+ })
304
+ ```
305
+
306
+ This is a process boundary with bounded I/O, not a container or operating
307
+ system security boundary. Use an isolated provider runtime for untrusted code.
308
+
309
+ For an optional Docker boundary, register fixed image commands with
310
+ `createDockerToolRuntime`. The default is fail-closed for image supply: it
311
+ uses cached images only, disables network access, makes the container root
312
+ filesystem read-only, drops capabilities, runs without privilege escalation,
313
+ and applies resource limits:
314
+
315
+ ```ts
316
+ import { createDockerToolRuntime } from '@agentskit/harness'
317
+
318
+ const runtime = createDockerToolRuntime({
319
+ tools: [{
320
+ toolId: 'worker',
321
+ image: 'node:22.13.0-bookworm-slim',
322
+ command: ['node', 'worker.mjs'],
323
+ mounts: [{ source: process.cwd(), target: '/workspace', readOnly: true }],
324
+ cwd: '/workspace',
325
+ }],
326
+ memoryLimit: '512m',
327
+ cpus: 1,
328
+ pidsLimit: 128,
329
+ })
330
+ ```
331
+
332
+ The provider does not add Docker as a package dependency and is not a VM or a
333
+ compromised-daemon boundary. Pin images for reproducibility; set `pull` to
334
+ `missing` or `always` only when image acquisition is explicitly authorized.
335
+ Completed and failed tool events carry the resolved image digest and an
336
+ effective profile hash, so reviewers can identify the runtime used for each
337
+ action without storing raw output.
338
+
339
+ `benchmark` aggregates the local run history into a versioned JSON report. It
340
+ includes check/outcome/evidence pass rates, retries, stale runs, human approvals,
341
+ and average/median verification duration. It also reports `effective*` metrics
342
+ over the latest non-superseded run in each retry lineage, so attempt history is
343
+ not confused with the current delivery state. With `--manifest`, it also compares
344
+ bound harness tasks with explicitly recorded baseline observations. A baseline
345
+ must include evidence for every acceptance criterion; missing, duplicate, or
346
+ unknown criterion evidence is rejected. Missing baselines and incomplete
347
+ evidence remain non-comparable; the harness never invents a baseline. Baseline
348
+ collectors also record `baselineArtifactAcceptanceRate`, the fraction of
349
+ repeated samples whose real artifact validation passed. This is independent of
350
+ protocol completion: a correct artifact with missing or incomplete protocol
351
+ evidence is visible as an accepted artifact but remains non-comparable for
352
+ duration and resource claims. These are
353
+ execution metrics, not a claim of productivity improvement; compare reports over
354
+ a controlled task corpus to measure that outcome.
355
+
356
+ Attach a task to a benchmark suite in the verification contract:
357
+
358
+ ```json
359
+ {
360
+ "benchmark": {
361
+ "suiteId": "agentskit-harness-phase-9",
362
+ "taskId": "harness-benchmark-evidence",
363
+ "mode": "harness"
364
+ }
365
+ }
366
+ ```
367
+
368
+ The manifest format is available at `benchmarks/harness-phase-9.json`. Record a
369
+ controlled baseline through the public CLI instead of editing JSON by hand:
370
+
371
+ ```bash
372
+ ak-harness benchmark baseline harness-benchmark-evidence \
373
+ --manifest benchmarks/harness-phase-9.json \
374
+ --status passed \
375
+ --source manual-run-2026-08-29 \
376
+ --evidence-file benchmarks/harness-phase-9-evidence.example.json \
377
+ --attempts 1 --duration-ms 900000 \
378
+ --review-minutes 20 --escaped-incomplete 0
379
+ ```
380
+
381
+ The command validates the task and values, rejects duplicate observations, and
382
+ atomically updates the manifest. Baseline observations are explicit records
383
+ with a source, timestamp, and criterion-level evidence. An empty or `not-run` baseline is reported as
384
+ non-comparable rather than treated as success.
385
+
386
+ When evidence is supplied through `--evidence-file`, the manifest also stores
387
+ the file's lowercase SHA-256 digest as `evidenceDigest`. This binds the
388
+ recorded JSON input to the observation; it does not independently validate a
389
+ manual, remote, or external source named by an evidence entry.
390
+
391
+ A comparison is considered comparable only when the task has an explicit
392
+ baseline with complete criterion-level evidence and its latest bound harness
393
+ run is `COMPLETE`. Blocked, incomplete, missing, or `not-run` inputs expose a
394
+ non-comparability reason and mark directional outcomes as `unavailable`.
395
+ Comparable reports include check, outcome, evidence, duration, attempt, and
396
+ human-review metrics plus directional outcomes. Completed runs with every
397
+ check, outcome, and evidence slot passing are projected as
398
+ `escapedIncomplete: 0`; a controlled baseline can record observed escapes and
399
+ the report exposes their delta and direction. A positive improvement rate
400
+ means the harness used less of that measured resource; these metrics do not
401
+ establish causality or productivity improvement alone.
402
+
403
+ When a structured check includes `artifactAcceptanceRate` directly or inside
404
+ its benchmark `reports`, comparisons also expose the harness rate, contributing
405
+ sample count, and acceptance improvement. Missing rates remain uncounted and
406
+ never become a failed artifact implicitly.
407
+
408
+ Baseline and harness comparisons also expose `protocolCompletionRate`, which
409
+ measures whether the verification protocol completed independently of artifact
410
+ acceptance. A protocol rate does not override the fail-closed comparability
411
+ rules.
412
+
413
+ When a baseline rate is zero, relative improvement remains `unavailable`; the
414
+ report still exposes the absolute acceptance or protocol completion delta.
415
+
416
+ For paired real-provider measurements, `scripts/run-agentskit-os-harness-benchmark.mjs`
417
+ prepares one frozen contract per manifest task, binds each run to the suite and
418
+ task ID, and leaves the lifecycle at the human approval gate. Use
419
+ `--repeats 3` for three independent samples per task; each sample has its own
420
+ state directory and must be approved separately. Run `--collect` after
421
+ approvals to aggregate the isolated task state directories. Pending or blocked
422
+ task runs remain non-comparable; only `COMPLETE` runs produce directional
423
+ improvement values. Duration comparisons use the median of completed samples,
424
+ while retry metrics count only superseded retry lineages, so experimental
425
+ replication is not misreported as agent retry cost.
426
+
427
+ When one sample is blocked or times out, prepare a distinct replacement without
428
+ overwriting the original evidence:
429
+
430
+ ```bash
431
+ node scripts/run-agentskit-os-harness-benchmark.mjs \
432
+ --execute --task-id feat-formatter --sample 4 \
433
+ --phase-root .codex/verification/phase-39/harness
434
+ ```
435
+
436
+ `--sample` requires a positive sample number and refuses an existing config or
437
+ state directory. The original blocked run remains part of the audit trail;
438
+ replacement runs add evidence and do not retroactively turn the blocked sample
439
+ into success.
440
+
441
+ The AgentsKit OS benchmark runner can expose the built `ak-verify` CLI inside
442
+ its disposable fixture. The fixture contract is prepared by CI, the provider
443
+ inherits a fixture-local PATH entry, and human approval is never synthesized.
444
+ This makes provider-side verification available without making the fixture a
445
+ security boundary; the outer harness remains the authoritative evidence gate.
446
+
447
+ Benchmark reports also expose a fail-closed `qualityGate`. It separates
448
+ historical retries from effective delivery, reports duration regressions, and
449
+ labels small samples as `insufficient-data` or `directional` instead of
450
+ claiming enterprise-level improvement. Configure
451
+ `minBaselineSamplesPerTask` alongside `minCompletedRunsPerTask`: a single
452
+ baseline observation is not comparable to replicated harness runs. Baseline
453
+ observations may store `durationSamplesMs`; the report compares medians.
454
+
455
+ ## Development
456
+
457
+ ```bash
458
+ pnpm install
459
+ pnpm --filter @agentskit/harness typecheck
460
+ pnpm --filter @agentskit/harness test
461
+ pnpm --filter @agentskit/harness build
462
+ ```
463
+
464
+ See [CONTRIBUTING.md](./CONTRIBUTING.md) for changes, tests, and release expectations. See [CHANGELOG.md](./CHANGELOG.md) for version history.
465
+
466
+ The Playbook CI dogfoods the package with `harness:test`, `harness:cli`, and a
467
+ clean packed-consumer probe before the broader repository checks run.
468
+ It also uploads the resulting `.codex/verification/harness-phase-24` run
469
+ directory so a human can inspect the exact evidence before approval.
470
+
471
+ ## License
472
+
473
+ MIT. See [LICENSE](./LICENSE).
package/SECURITY.md ADDED
@@ -0,0 +1,11 @@
1
+ # Security policy
2
+
3
+ ## Reporting a vulnerability
4
+
5
+ Do not disclose security issues in public issues. Report a suspected vulnerability privately to the repository maintainers through the security contact configured on GitHub.
6
+
7
+ Include the affected version, reproduction steps, impact, and any proposed mitigation. Do not include secrets or personal data.
8
+
9
+ ## Scope
10
+
11
+ The harness executes commands declared by a repository contract. Treat verification contracts as trusted code, review them before execution, and never run an untrusted contract in a sensitive environment.