@mikenguyen69/harness 0.1.0-beta.1
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.
- package/LICENSE +21 -0
- package/README.md +43 -0
- package/dist/build-identity.json +1 -0
- package/dist/cancellation.js +138 -0
- package/dist/cli.js +47 -0
- package/dist/dispatch.js +70 -0
- package/dist/help.js +47 -0
- package/dist/internal/agent/adapter/conformance.js +53 -0
- package/dist/internal/agent/adapter/hook.js +113 -0
- package/dist/internal/agent/adapter/install.js +30 -0
- package/dist/internal/agent/adapter/scope.js +55 -0
- package/dist/internal/agent/adapter/session.js +63 -0
- package/dist/internal/agent/adapter/settings.js +51 -0
- package/dist/internal/agent/cli.js +79 -0
- package/dist/internal/agent/evals/index.js +111 -0
- package/dist/internal/agent/index.js +15 -0
- package/dist/internal/agent/ledger-read.js +27 -0
- package/dist/internal/agent/routing/cli.js +104 -0
- package/dist/internal/agent/routing/index.js +123 -0
- package/dist/internal/agent/telemetry/index.js +97 -0
- package/dist/internal/orchestration/activity/index.js +111 -0
- package/dist/internal/orchestration/analyze/index.js +237 -0
- package/dist/internal/orchestration/cli.js +475 -0
- package/dist/internal/orchestration/config/index.js +66 -0
- package/dist/internal/orchestration/doctor/index.js +202 -0
- package/dist/internal/orchestration/forge/index.js +121 -0
- package/dist/internal/orchestration/git/index.js +181 -0
- package/dist/internal/orchestration/harness/cli.js +378 -0
- package/dist/internal/orchestration/harness/index.js +186 -0
- package/dist/internal/orchestration/harness/shim.js +182 -0
- package/dist/internal/orchestration/index.js +29 -0
- package/dist/internal/orchestration/loop/index.js +1107 -0
- package/dist/internal/orchestration/prompts/index.js +199 -0
- package/dist/internal/orchestration/report/index.js +125 -0
- package/dist/internal/orchestration/routes/index.js +85 -0
- package/dist/internal/orchestration/run/index.js +221 -0
- package/dist/internal/orchestration/runner/index.js +90 -0
- package/dist/internal/orchestration/runners/claude/index.js +246 -0
- package/dist/internal/orchestration/runners/claude/sdk.js +198 -0
- package/dist/internal/orchestration/runners/claude/wiring.js +98 -0
- package/dist/internal/orchestration/runners/codex/exec.js +114 -0
- package/dist/internal/orchestration/runners/codex/index.js +72 -0
- package/dist/internal/orchestration/runners/conformance/index.js +169 -0
- package/dist/internal/orchestration/runners/cursor/exec.js +531 -0
- package/dist/internal/orchestration/runners/cursor/index.js +184 -0
- package/dist/internal/orchestration/runners/stub/index.js +168 -0
- package/dist/internal/orchestration/runners/telemetry.js +36 -0
- package/dist/internal/orchestration/runstate/index.js +213 -0
- package/dist/internal/orchestration/runstate/publish.js +115 -0
- package/dist/internal/orchestration/worktree/index.js +89 -0
- package/dist/internal/system/adapters/index.js +19 -0
- package/dist/internal/system/agentops/index.js +16 -0
- package/dist/internal/system/agentops/scope.js +67 -0
- package/dist/internal/system/assets.js +45 -0
- package/dist/internal/system/board/cli.js +56 -0
- package/dist/internal/system/board/index.js +276 -0
- package/dist/internal/system/board/live.js +277 -0
- package/dist/internal/system/calibration/cli.js +45 -0
- package/dist/internal/system/calibration/index.js +141 -0
- package/dist/internal/system/cli.js +174 -0
- package/dist/internal/system/corpus/replay.js +79 -0
- package/dist/internal/system/digest/cli.js +23 -0
- package/dist/internal/system/digest/index.js +145 -0
- package/dist/internal/system/doors/classify.js +94 -0
- package/dist/internal/system/doors/cli.js +184 -0
- package/dist/internal/system/doors/index.js +249 -0
- package/dist/internal/system/doors/metrics.js +47 -0
- package/dist/internal/system/escapes/cli.js +45 -0
- package/dist/internal/system/escapes/index.js +81 -0
- package/dist/internal/system/explore/cli.js +77 -0
- package/dist/internal/system/explore/index.js +91 -0
- package/dist/internal/system/gates/cli.js +43 -0
- package/dist/internal/system/gates/detectors.js +55 -0
- package/dist/internal/system/gates/pre.js +51 -0
- package/dist/internal/system/hub/cli.js +51 -0
- package/dist/internal/system/hub/index.js +146 -0
- package/dist/internal/system/init/index.js +83 -0
- package/dist/internal/system/ledger/cli.js +54 -0
- package/dist/internal/system/ledger/index.js +176 -0
- package/dist/internal/system/manifest/index.js +207 -0
- package/dist/internal/system/provenance/index.js +13 -0
- package/dist/internal/system/report/index.js +15 -0
- package/dist/internal/system/runner/index.js +74 -0
- package/dist/internal/system/runstatus/cli.js +86 -0
- package/dist/internal/system/runstatus/index.js +168 -0
- package/dist/internal/system/sequencer/briefing.js +75 -0
- package/dist/internal/system/sequencer/cli.js +170 -0
- package/dist/internal/system/sequencer/index.js +156 -0
- package/dist/internal/system/spec/cli.js +110 -0
- package/dist/internal/system/spec/index.js +212 -0
- package/dist/internal/system/spec/materialize.js +111 -0
- package/dist/internal/system/spec/openspec-parse.js +83 -0
- package/dist/internal/system/spec/project.js +208 -0
- package/dist/internal/system/substrate/index.js +14 -0
- package/dist/internal/system/system/index.js +159 -0
- package/dist/internal/system/units/index.js +87 -0
- package/dist/internal/system/verify/cli.js +103 -0
- package/dist/internal/system/verify/declined-reasons.js +61 -0
- package/dist/internal/system/verify/index.js +188 -0
- package/dist/internal/system/verify/signing.js +79 -0
- package/dist/paths.js +50 -0
- package/dist/routes.js +93 -0
- package/dist/version.js +30 -0
- package/dist/win32-process-group.js +360 -0
- package/package.json +41 -0
- package/profiles/python/bindings.toml +59 -0
- package/profiles/terraform/bindings.toml +66 -0
- package/profiles/typescript/bindings.toml +64 -0
- package/profiles/typescript/smoke/README.md +8 -0
- package/schema/baseline.schema.json +26 -0
- package/schema/decision-classes.yaml +45 -0
- package/schema/envelope.schema.json +186 -0
- package/schema/ledger-event.schema.json +235 -0
- package/schema/manifest.schema.json +119 -0
- package/schema/routes.schema.json +55 -0
- package/schema/run-status.schema.json +162 -0
- package/schema/session-event.schema.json +74 -0
- package/schema/spec.schema.json +114 -0
- package/schema/system.schema.json +142 -0
- package/templates/ci/verify.yml +23 -0
- package/templates/target-kit/README.md +78 -0
- package/templates/target-kit/component.toml +20 -0
- package/templates/target-kit/orchestration.json +9 -0
- package/templates/target-kit/profiles/target/bindings.toml +6 -0
- package/templates/target-kit/routes.toml +5 -0
- package/templates/target-kit/specs/first-unit.yaml +11 -0
- package/templates/target-kit/system.toml +7 -0
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://harness.local/schema/manifest.schema.json",
|
|
4
|
+
"title": "Contract A — component.toml (gate manifest)",
|
|
5
|
+
"description": "Binds the abstract gate vocabulary to real commands per component root (ADR 0003: the file is component.toml). Structural rules: every vocabulary gate is either bound or explicitly declined with a reason — absence is an error (all-skip is never a pass); a gate name outside the closed vocabulary is a config error. Severity is data so the maturity ramp needs no tooling fork. Re-rooted per component and extended with `external` gates per system-harness-blueprint.md §3 (\"Contract A — component manifest\").",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"required": ["harness", "gates"],
|
|
8
|
+
"properties": {
|
|
9
|
+
"harness": {
|
|
10
|
+
"type": "object",
|
|
11
|
+
"required": ["policy_version", "profile"],
|
|
12
|
+
"properties": {
|
|
13
|
+
"policy_version": {
|
|
14
|
+
"type": "string",
|
|
15
|
+
"description": "semver of the policy data this manifest conforms to"
|
|
16
|
+
},
|
|
17
|
+
"profile": {
|
|
18
|
+
"type": "string",
|
|
19
|
+
"description": "base profile name, e.g. 'typescript'"
|
|
20
|
+
},
|
|
21
|
+
"mode": {
|
|
22
|
+
"enum": ["standard", "ratchet"],
|
|
23
|
+
"default": "standard",
|
|
24
|
+
"description": "ratchet = brownfield adoption: bulk gates run changed-lines against a frozen debt baseline that may only fall"
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
"ratchet": {
|
|
29
|
+
"type": "object",
|
|
30
|
+
"description": "Required when mode=ratchet. Debt is counted at init (harness init --audit), frozen, and may only fall — repo totals above the floor fail even at changed-lines severity.",
|
|
31
|
+
"required": ["baseline_path"],
|
|
32
|
+
"properties": {
|
|
33
|
+
"baseline_path": {
|
|
34
|
+
"type": "string",
|
|
35
|
+
"default": ".harness/baseline.json",
|
|
36
|
+
"description": "frozen debt inventory, schema/baseline.schema.json"
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
"quarantine": {
|
|
41
|
+
"type": "array",
|
|
42
|
+
"description": "Flaky tests parked by name — never silently retried. Suspended for any quarantined test covering code inside the current unit's touched scope: fix the flake or the behavior. Expired entries fail verify until fixed, deleted, or re-quarantined with a fresh reason.",
|
|
43
|
+
"items": {
|
|
44
|
+
"type": "object",
|
|
45
|
+
"required": ["test_id", "expires", "reason"],
|
|
46
|
+
"properties": {
|
|
47
|
+
"test_id": {
|
|
48
|
+
"type": "string",
|
|
49
|
+
"description": "suite/case identifier as the runner reports it"
|
|
50
|
+
},
|
|
51
|
+
"expires": { "type": "string", "format": "date" },
|
|
52
|
+
"reason": { "type": "string", "minLength": 10 }
|
|
53
|
+
},
|
|
54
|
+
"additionalProperties": false
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
"substrate": {
|
|
58
|
+
"type": "object",
|
|
59
|
+
"description": "The one layer with no maturity ramp — branch protection is on or decorative. enforced_from allows a dated cutover on brownfield repos; until that date, verify reports itself as ADVISORY at the repo level (the harness never lets the guarantee be silently absent).",
|
|
60
|
+
"properties": {
|
|
61
|
+
"enforced_from": {
|
|
62
|
+
"type": "string",
|
|
63
|
+
"format": "date",
|
|
64
|
+
"description": "date server-side enforcement becomes active; absent = enforced now"
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
"gates": {
|
|
69
|
+
"type": "object",
|
|
70
|
+
"description": "One entry per vocabulary gate: spec, fmt, lint, types, test, arch, contract, size, gen:fresh, or any sec:<tool> under the sec:* namespace (ADR 0004). Each is a binding or a declination — never absent.",
|
|
71
|
+
"propertyNames": {
|
|
72
|
+
"pattern": "^(spec|fmt|lint|types|test|arch|contract|size|gen:fresh|sec:[a-z][a-z-]*)$",
|
|
73
|
+
"description": "closed vocabulary — an unrecognised gate name is a config error, not a silent skip"
|
|
74
|
+
},
|
|
75
|
+
"additionalProperties": {
|
|
76
|
+
"oneOf": [
|
|
77
|
+
{
|
|
78
|
+
"type": "object",
|
|
79
|
+
"required": ["run", "severity", "cost"],
|
|
80
|
+
"properties": {
|
|
81
|
+
"run": { "type": "string", "description": "the real command" },
|
|
82
|
+
"severity": {
|
|
83
|
+
"enum": ["advisory", "changed-lines", "blocking"],
|
|
84
|
+
"description": "maturity-ramp position; moved by calibration data, not by hand"
|
|
85
|
+
},
|
|
86
|
+
"cost": {
|
|
87
|
+
"enum": ["cheap", "expensive"],
|
|
88
|
+
"description": "runner orders cheap-first, fail-fast"
|
|
89
|
+
},
|
|
90
|
+
"timeout_seconds": { "type": "integer", "minimum": 1 },
|
|
91
|
+
"external": {
|
|
92
|
+
"type": "boolean",
|
|
93
|
+
"default": false,
|
|
94
|
+
"description": "true = runs only in the component's deploy phase (e.g. terraform post-apply reality checks), never in hermetic `verify`. Blueprint §3: keeps verify offline and reproducible."
|
|
95
|
+
},
|
|
96
|
+
"snapshot_max_age_days": {
|
|
97
|
+
"type": "integer",
|
|
98
|
+
"description": "for gates needing external data (sec:deps): max staleness of the vendored snapshot; network during verify is otherwise forbidden"
|
|
99
|
+
}
|
|
100
|
+
},
|
|
101
|
+
"additionalProperties": false
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
"type": "object",
|
|
105
|
+
"required": ["declined"],
|
|
106
|
+
"properties": {
|
|
107
|
+
"declined": {
|
|
108
|
+
"type": "string",
|
|
109
|
+
"minLength": 10,
|
|
110
|
+
"description": "explicit reason this gate does not apply here"
|
|
111
|
+
}
|
|
112
|
+
},
|
|
113
|
+
"additionalProperties": false
|
|
114
|
+
}
|
|
115
|
+
]
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://harness.local/schema/routes.schema.json",
|
|
4
|
+
"title": "routes.toml — agent-harness routing policy",
|
|
5
|
+
"description": "Hub-side policy data (solution design §8). Maps a component profile to a model + config, plus optional mode-tightening that the eval loop lifts on measurement (e.g. `propose-only until route-eval>=90`). Adapters read the resolved route at session start; calibration may PROPOSE route changes, never apply them. An A/B test is two entries for one profile with `split` weights. Describes the parsed TOML: `[[route]]` -> the `route` array.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"required": ["route"],
|
|
8
|
+
"additionalProperties": false,
|
|
9
|
+
"properties": {
|
|
10
|
+
"route": {
|
|
11
|
+
"type": "array",
|
|
12
|
+
"minItems": 1,
|
|
13
|
+
"items": {
|
|
14
|
+
"type": "object",
|
|
15
|
+
"required": ["profile", "model"],
|
|
16
|
+
"additionalProperties": false,
|
|
17
|
+
"properties": {
|
|
18
|
+
"profile": {
|
|
19
|
+
"type": "string",
|
|
20
|
+
"minLength": 1,
|
|
21
|
+
"description": "component profile this route serves, e.g. 'typescript'"
|
|
22
|
+
},
|
|
23
|
+
"model": {
|
|
24
|
+
"type": "string",
|
|
25
|
+
"minLength": 1,
|
|
26
|
+
"description": "model id, e.g. 'claude-fable-5'"
|
|
27
|
+
},
|
|
28
|
+
"runner": {
|
|
29
|
+
"enum": ["claude", "codex", "cursor"],
|
|
30
|
+
"default": "claude",
|
|
31
|
+
"description": "which coding agent runs the unit. Routing policy, same as `model`. Absent = claude, so existing routes.toml files stay valid. An A/B `split` may vary runner as well as model."
|
|
32
|
+
},
|
|
33
|
+
"config": {
|
|
34
|
+
"type": "string",
|
|
35
|
+
"description": "config/preset id; hashed into session.config_hash"
|
|
36
|
+
},
|
|
37
|
+
"split": {
|
|
38
|
+
"type": "number",
|
|
39
|
+
"minimum": 0,
|
|
40
|
+
"maximum": 1,
|
|
41
|
+
"description": "A/B weight when more than one route shares a profile; weights across a profile should sum to 1"
|
|
42
|
+
},
|
|
43
|
+
"mode": {
|
|
44
|
+
"enum": ["standard", "propose-only"],
|
|
45
|
+
"default": "standard"
|
|
46
|
+
},
|
|
47
|
+
"until": {
|
|
48
|
+
"type": "string",
|
|
49
|
+
"description": "condition that lifts a tightened mode, e.g. 'route-eval>=90'"
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://harness.local/schema/run-status.schema.json",
|
|
4
|
+
"title": "Run-status document — the live overlay for the board",
|
|
5
|
+
"description": "A latest-state-wins snapshot of one orchestration run on one machine (dashboard-plan.md). NOT a ledger event: in-flight state (attempt counts, a session mid-run, cost ticking) is high-churn and worthless after the run, so it never enters the hash-chained ledger. system-harness owns this shape; orchestration-harness (and any future actuator) emits documents conforming to it via `harness runstatus publish`, which stamps `machine_id` and writes to the hub spool. The hub keeps latest-per-(machine_id, run_id); `heartbeat_at` older than the staleness threshold renders as stale, never live; a terminal `outcome` (or staleness past expiry) retires the run from the overlay.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"additionalProperties": false,
|
|
8
|
+
"required": [
|
|
9
|
+
"machine_id",
|
|
10
|
+
"run_id",
|
|
11
|
+
"system_id",
|
|
12
|
+
"spec_ref",
|
|
13
|
+
"started_at",
|
|
14
|
+
"heartbeat_at",
|
|
15
|
+
"lanes",
|
|
16
|
+
"needs_you",
|
|
17
|
+
"counts"
|
|
18
|
+
],
|
|
19
|
+
"properties": {
|
|
20
|
+
"machine_id": {
|
|
21
|
+
"type": "string",
|
|
22
|
+
"minLength": 1,
|
|
23
|
+
"description": "the machine the run is on. Stamped by `harness runstatus publish`; a publisher that sets it itself is overridden."
|
|
24
|
+
},
|
|
25
|
+
"run_id": {
|
|
26
|
+
"type": "string",
|
|
27
|
+
"minLength": 1,
|
|
28
|
+
"description": "unique per `orchestrate` invocation. A restart is a new run_id (crash = restart, by design)."
|
|
29
|
+
},
|
|
30
|
+
"system_id": { "type": "string", "minLength": 1 },
|
|
31
|
+
"spec_ref": {
|
|
32
|
+
"type": "string",
|
|
33
|
+
"minLength": 1,
|
|
34
|
+
"description": "the materialised spec DAG the run is driving (path or id)."
|
|
35
|
+
},
|
|
36
|
+
"started_at": { "type": "string", "format": "date-time" },
|
|
37
|
+
"heartbeat_at": {
|
|
38
|
+
"type": "string",
|
|
39
|
+
"format": "date-time",
|
|
40
|
+
"description": "last time the machine published. The board's staleness rules key off this — older than the threshold renders 'stale (machine silent since …)'."
|
|
41
|
+
},
|
|
42
|
+
"outcome": {
|
|
43
|
+
"enum": ["completed", "halted", "crashed"],
|
|
44
|
+
"description": "present only on the terminal publish. Retires the run from the live overlay."
|
|
45
|
+
},
|
|
46
|
+
"lanes": {
|
|
47
|
+
"type": "array",
|
|
48
|
+
"description": "one entry per unit the run has opened a lane for.",
|
|
49
|
+
"items": {
|
|
50
|
+
"type": "object",
|
|
51
|
+
"additionalProperties": false,
|
|
52
|
+
"required": ["unit_id", "step", "runner", "model", "attempt", "retry_budget", "cost", "emitter"],
|
|
53
|
+
"properties": {
|
|
54
|
+
"unit_id": { "type": "string", "minLength": 1 },
|
|
55
|
+
"step": {
|
|
56
|
+
"type": "string",
|
|
57
|
+
"minLength": 1,
|
|
58
|
+
"description": "the lane's current step (the emitter's vocabulary, e.g. claim | implement | rebase | verify | review | merge | land)."
|
|
59
|
+
},
|
|
60
|
+
"runner": {
|
|
61
|
+
"type": "string",
|
|
62
|
+
"minLength": 1,
|
|
63
|
+
"description": "which coding agent is driving the lane (claude | codex | cursor)."
|
|
64
|
+
},
|
|
65
|
+
"model": { "type": "string", "minLength": 1 },
|
|
66
|
+
"attempt": { "type": "integer", "minimum": 1 },
|
|
67
|
+
"retry_budget": { "type": "integer", "minimum": 0 },
|
|
68
|
+
"cost": {
|
|
69
|
+
"type": "number",
|
|
70
|
+
"minimum": 0,
|
|
71
|
+
"description": "cumulative estimated USD spent on this lane so far."
|
|
72
|
+
},
|
|
73
|
+
"emitter": {
|
|
74
|
+
"enum": ["session", "orchestrator"],
|
|
75
|
+
"description": "telemetry tier — `session` = first-hand from the agent's adapter; `orchestrator` = reconstructed by the actuator for an adapter-less runner (badged as such on the board)."
|
|
76
|
+
},
|
|
77
|
+
"settled": {
|
|
78
|
+
"type": "boolean",
|
|
79
|
+
"description": "the lane reached a terminal step (merged / halted). Optional; absent = still in flight."
|
|
80
|
+
},
|
|
81
|
+
"envelope_hash": {
|
|
82
|
+
"type": "string",
|
|
83
|
+
"minLength": 1,
|
|
84
|
+
"description": "the `hash` of the ring-1 `envelope` ledger event for this lane's verify (from `harness verify --json`). Optional; present once ring 1 has passed."
|
|
85
|
+
},
|
|
86
|
+
"door_id": {
|
|
87
|
+
"type": "string",
|
|
88
|
+
"minLength": 1,
|
|
89
|
+
"description": "the real door id `harness merge` opened for this lane (parsed from its stderr), when the lane halted on a one-way / propose-only door. Optional."
|
|
90
|
+
},
|
|
91
|
+
"activity": {
|
|
92
|
+
"type": "string",
|
|
93
|
+
"maxLength": 160,
|
|
94
|
+
"description": "Live-activity group (latest-state-wins snapshot — NOT a ledger/event channel): one-line summary of the agent's current/last action (a tool name plus a short target — never transcript or model prose). Optional; absent means the runner emits no session-tier stream (degraded tier: Codex / Cursor)."
|
|
95
|
+
},
|
|
96
|
+
"activity_at": {
|
|
97
|
+
"type": "string",
|
|
98
|
+
"format": "date-time",
|
|
99
|
+
"description": "Live-activity group (latest-state-wins snapshot — NOT a ledger/event channel): when this activity snapshot was last stamped. Optional; absent means the runner emits no session-tier stream (degraded tier)."
|
|
100
|
+
},
|
|
101
|
+
"turn": {
|
|
102
|
+
"type": "integer",
|
|
103
|
+
"minimum": 0,
|
|
104
|
+
"description": "Live-activity group (latest-state-wins snapshot — NOT a ledger/event channel): agent turn counter for the current session. Optional; absent means the runner emits no session-tier stream (degraded tier)."
|
|
105
|
+
},
|
|
106
|
+
"tokens": {
|
|
107
|
+
"type": "object",
|
|
108
|
+
"additionalProperties": false,
|
|
109
|
+
"required": ["in", "out"],
|
|
110
|
+
"description": "Live-activity group (latest-state-wins snapshot — NOT a ledger/event channel): running token count for the session. Optional; absent means the runner emits no session-tier stream (degraded tier).",
|
|
111
|
+
"properties": {
|
|
112
|
+
"in": { "type": "integer", "minimum": 0 },
|
|
113
|
+
"out": { "type": "integer", "minimum": 0 }
|
|
114
|
+
}
|
|
115
|
+
},
|
|
116
|
+
"recent": {
|
|
117
|
+
"type": "array",
|
|
118
|
+
"maxItems": 5,
|
|
119
|
+
"description": "Live-activity group (latest-state-wins snapshot — NOT a ledger/event channel): small ring buffer of recent action lines — each a one-line summary of an agent action (a tool name plus a short target — never transcript or model prose). Optional; absent means the runner emits no session-tier stream (degraded tier).",
|
|
120
|
+
"items": { "type": "string", "maxLength": 160 }
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
},
|
|
125
|
+
"needs_you": {
|
|
126
|
+
"type": "array",
|
|
127
|
+
"description": "the operator queue — doors pending, escalations, exhausted retries, budget trips.",
|
|
128
|
+
"items": {
|
|
129
|
+
"type": "object",
|
|
130
|
+
"additionalProperties": false,
|
|
131
|
+
"required": ["kind", "message", "unblock"],
|
|
132
|
+
"properties": {
|
|
133
|
+
"kind": {
|
|
134
|
+
"type": "string",
|
|
135
|
+
"minLength": 1,
|
|
136
|
+
"description": "e.g. one-way-door | escalation | retry-exhausted | stranded-in-review | ledger-ahead-of-git | budget."
|
|
137
|
+
},
|
|
138
|
+
"unit_id": { "type": "string", "minLength": 1 },
|
|
139
|
+
"message": { "type": "string", "minLength": 1 },
|
|
140
|
+
"unblock": {
|
|
141
|
+
"type": "string",
|
|
142
|
+
"minLength": 1,
|
|
143
|
+
"description": "the exact operator command (or config fix) that clears this entry."
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
},
|
|
148
|
+
"counts": {
|
|
149
|
+
"type": "object",
|
|
150
|
+
"additionalProperties": false,
|
|
151
|
+
"required": ["merged", "escalated", "parked", "in_flight", "needs_you"],
|
|
152
|
+
"properties": {
|
|
153
|
+
"merged": { "type": "integer", "minimum": 0 },
|
|
154
|
+
"escalated": { "type": "integer", "minimum": 0 },
|
|
155
|
+
"parked": { "type": "integer", "minimum": 0 },
|
|
156
|
+
"in_flight": { "type": "integer", "minimum": 0 },
|
|
157
|
+
"needs_you": { "type": "integer", "minimum": 0 },
|
|
158
|
+
"dag_size": { "type": "integer", "minimum": 0 }
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://harness.local/schema/session-event.schema.json",
|
|
4
|
+
"title": "Contract D — session event body",
|
|
5
|
+
"description": "The `body` of a `session.*` ledger event, emitted by an agent adapter (Claude Code first) through `harness ledger append`. One session = one agent working one unit in one component. Carries model id, config hash, token counts, cost, in-loop (ring-0) gate firings, and escalations. This is the join key set for fleet telemetry: agent-harness joins these to Contract B envelopes by `session_id`. system-harness never reads a session event to decide a merge (solution design D2). v1 keeps per-phase fields optional; the ledger event's `type` (session.started | heartbeat | gate_fired | escalated | ended) is the discriminator.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"required": ["session_id", "unit_id", "component_id"],
|
|
8
|
+
"additionalProperties": false,
|
|
9
|
+
"properties": {
|
|
10
|
+
"session_id": { "type": "string", "minLength": 1 },
|
|
11
|
+
"unit_id": { "type": "string", "minLength": 1 },
|
|
12
|
+
"component_id": { "type": "string", "minLength": 1 },
|
|
13
|
+
"phase": {
|
|
14
|
+
"enum": ["started", "heartbeat", "gate_fired", "escalated", "ended"],
|
|
15
|
+
"description": "mirrors the ledger event type suffix; optional self-description for standalone consumers"
|
|
16
|
+
},
|
|
17
|
+
"emitter": {
|
|
18
|
+
"enum": ["adapter", "orchestrator"],
|
|
19
|
+
"default": "adapter",
|
|
20
|
+
"description": "who produced this event. `adapter` (default) = first-hand, from the agent's own agent-harness adapter in-session. `orchestrator` = reconstructed by orchestration-harness from a RunResult for a runner with no adapter (P7.1 / degraded tier); telemetry joins keep the distinction."
|
|
21
|
+
},
|
|
22
|
+
"model": {
|
|
23
|
+
"type": "string",
|
|
24
|
+
"description": "model id, e.g. claude-fable-5"
|
|
25
|
+
},
|
|
26
|
+
"runner": { "type": "string" },
|
|
27
|
+
"role": { "enum": ["implementer", "verifier"] },
|
|
28
|
+
"transcript_ref": { "type": ["string", "null"] },
|
|
29
|
+
"config_hash": {
|
|
30
|
+
"type": "string",
|
|
31
|
+
"description": "hash of the model config/preset; distinguishes A/B arms of one route"
|
|
32
|
+
},
|
|
33
|
+
"tokens": {
|
|
34
|
+
"type": "object",
|
|
35
|
+
"required": ["in", "out"],
|
|
36
|
+
"additionalProperties": false,
|
|
37
|
+
"properties": {
|
|
38
|
+
"in": { "type": "integer", "minimum": 0 },
|
|
39
|
+
"out": { "type": "integer", "minimum": 0 }
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
"cost_usd": { "type": "number", "minimum": 0 },
|
|
43
|
+
"gate": {
|
|
44
|
+
"type": "object",
|
|
45
|
+
"description": "present on session.gate_fired — a ring-0 (`gate --pre`) firing observed in the loop",
|
|
46
|
+
"required": ["name", "outcome"],
|
|
47
|
+
"additionalProperties": false,
|
|
48
|
+
"properties": {
|
|
49
|
+
"name": { "type": "string" },
|
|
50
|
+
"outcome": { "enum": ["pass", "fail"] },
|
|
51
|
+
"ring": { "const": 0 }
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
"escalation": {
|
|
55
|
+
"type": "object",
|
|
56
|
+
"description": "present on session.escalated",
|
|
57
|
+
"required": ["reason", "wants"],
|
|
58
|
+
"additionalProperties": false,
|
|
59
|
+
"properties": {
|
|
60
|
+
"reason": { "type": "string", "minLength": 1 },
|
|
61
|
+
"wants": { "type": "string", "minLength": 1 }
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
"ended": {
|
|
65
|
+
"type": "object",
|
|
66
|
+
"description": "present on session.ended",
|
|
67
|
+
"required": ["outcome"],
|
|
68
|
+
"additionalProperties": false,
|
|
69
|
+
"properties": {
|
|
70
|
+
"outcome": { "enum": ["handed-off", "escalated", "abandoned"] }
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://harness.local/schema/spec.schema.json",
|
|
4
|
+
"title": "Spec standard — the required form of a unit of work",
|
|
5
|
+
"description": "What the `spec` gate lints. Every acceptance criterion is either machine-checkable (names a verifier) or explicitly manual with a reason — absence is an error, the same declined-with-reason structure the manifest uses. Mechanizes the FORM of specs; intent quality remains the human's job upstream. Component-first extension per system-harness-blueprint.md §3 (\"Spec standard (extended)\"): every unit names its `component`; `outputs`/`consumes` reference artifact names declared in Contract C (system.toml); `deps` items are `[component#]unit-id`.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"required": ["id", "component", "intent", "acceptance_criteria", "scope"],
|
|
8
|
+
"properties": {
|
|
9
|
+
"id": {
|
|
10
|
+
"type": "string",
|
|
11
|
+
"pattern": "^[^#]+$",
|
|
12
|
+
"description": "globally unique bare canonical unit id; component identity belongs in the component field"
|
|
13
|
+
},
|
|
14
|
+
"component": {
|
|
15
|
+
"type": "string",
|
|
16
|
+
"description": "the component this unit belongs to (must exist in system.toml). One agent session works one component — blueprint §1."
|
|
17
|
+
},
|
|
18
|
+
"mode": {
|
|
19
|
+
"enum": ["build", "explore"],
|
|
20
|
+
"default": "build",
|
|
21
|
+
"description": "explore = a throwaway branch, ring-0 gates only, NO edge to merged (D7). Its only exits are abort or graduate (graduate emits a draft build spec from what was learned)."
|
|
22
|
+
},
|
|
23
|
+
"intent": { "type": "string", "minLength": 20 },
|
|
24
|
+
"acceptance_criteria": {
|
|
25
|
+
"type": "array",
|
|
26
|
+
"minItems": 1,
|
|
27
|
+
"items": {
|
|
28
|
+
"type": "object",
|
|
29
|
+
"required": ["statement"],
|
|
30
|
+
"properties": {
|
|
31
|
+
"statement": {
|
|
32
|
+
"type": "string",
|
|
33
|
+
"description": "RFC 2119 vocabulary (MUST/SHOULD/MAY); Given-When-Then encouraged"
|
|
34
|
+
},
|
|
35
|
+
"verifier": {
|
|
36
|
+
"type": "string",
|
|
37
|
+
"description": "gate name or command that checks this mechanically"
|
|
38
|
+
},
|
|
39
|
+
"manual": {
|
|
40
|
+
"type": "string",
|
|
41
|
+
"minLength": 10,
|
|
42
|
+
"description": "reason this criterion cannot be machine-checked"
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
"oneOf": [{ "required": ["verifier"] }, { "required": ["manual"] }]
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
"scope": {
|
|
49
|
+
"type": "array",
|
|
50
|
+
"minItems": 1,
|
|
51
|
+
"items": { "type": "string" },
|
|
52
|
+
"description": "path globs this unit may touch; anything outside halts (fail closed), never warns"
|
|
53
|
+
},
|
|
54
|
+
"size_budget": {
|
|
55
|
+
"type": "object",
|
|
56
|
+
"properties": {
|
|
57
|
+
"max_changed_lines": { "type": "integer", "default": 400 },
|
|
58
|
+
"max_changed_files": { "type": "integer", "default": 15 }
|
|
59
|
+
},
|
|
60
|
+
"description": "the `size` gate's input — bounded diffs are the biggest single lever on review quality and blast radius"
|
|
61
|
+
},
|
|
62
|
+
"door": {
|
|
63
|
+
"enum": ["two-way", "one-way"],
|
|
64
|
+
"description": "one-way (or unset) requires human approval at merge"
|
|
65
|
+
},
|
|
66
|
+
"merge_facts": {
|
|
67
|
+
"type": "object",
|
|
68
|
+
"additionalProperties": false,
|
|
69
|
+
"description": "the spec-declared merge facts `harness merge` classifies a door from (src/doors/classify.ts fact set). Booleans, all default false; `door` above stays the top-level field. `harness claim --json` (P7.4) delivers these to the orchestrator verbatim — facts are declared here and only here, never diff-guessed.",
|
|
70
|
+
"properties": {
|
|
71
|
+
"adds_dependency": {
|
|
72
|
+
"type": "boolean",
|
|
73
|
+
"default": false,
|
|
74
|
+
"description": "the change adds a runtime/build dependency (`harness merge --adds-dependency`)"
|
|
75
|
+
},
|
|
76
|
+
"schema_change": {
|
|
77
|
+
"type": "boolean",
|
|
78
|
+
"default": false,
|
|
79
|
+
"description": "the change touches a schema or a published API surface (`--schema-change`)"
|
|
80
|
+
},
|
|
81
|
+
"security": {
|
|
82
|
+
"type": "boolean",
|
|
83
|
+
"default": false,
|
|
84
|
+
"description": "the change touches auth, crypto, secrets, or another security-sensitive path (`--security`)"
|
|
85
|
+
},
|
|
86
|
+
"gate_external": {
|
|
87
|
+
"type": "boolean",
|
|
88
|
+
"default": false,
|
|
89
|
+
"description": "the change runs a gate marked external:true — a deploy-phase side effect (`--gate-external`)"
|
|
90
|
+
},
|
|
91
|
+
"artifact_producer_change": {
|
|
92
|
+
"type": "boolean",
|
|
93
|
+
"default": false,
|
|
94
|
+
"description": "the change alters a published artifact's producer (`--artifact-producer-change`)"
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
},
|
|
98
|
+
"deps": {
|
|
99
|
+
"type": "array",
|
|
100
|
+
"items": { "type": "string" },
|
|
101
|
+
"description": "unit ids this unit depends on; cross-component deps are written `component#unit-id`, same-component deps may omit the prefix"
|
|
102
|
+
},
|
|
103
|
+
"outputs": {
|
|
104
|
+
"type": "array",
|
|
105
|
+
"items": { "type": "string" },
|
|
106
|
+
"description": "artifact names this unit publishes; each MUST be declared in system.toml with this unit's component as producer (blueprint §3)"
|
|
107
|
+
},
|
|
108
|
+
"consumes": {
|
|
109
|
+
"type": "array",
|
|
110
|
+
"items": { "type": "string" },
|
|
111
|
+
"description": "artifact names this unit consumes; the `spec` gate checks every one has a producer unit upstream in the DAG"
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|