harnex 0.8.0 → 0.10.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +188 -0
- data/GUIDE.md +17 -10
- data/README.md +61 -54
- data/TECHNICAL.md +38 -15
- data/docs/codex-appserver.md +175 -0
- data/docs/configuration.md +118 -0
- data/docs/dispatch-telemetry.md +502 -0
- data/docs/events.md +132 -0
- data/guides/01_dispatch.md +31 -28
- data/guides/04_monitoring.md +10 -9
- data/guides/05_naming.md +18 -8
- data/lib/harnex/adapters/base.rb +10 -0
- data/lib/harnex/adapters/codex_appserver.rb +25 -0
- data/lib/harnex/artifact_report.rb +455 -6
- data/lib/harnex/cli.rb +3 -3
- data/lib/harnex/commands/artifact_report.rb +8 -7
- data/lib/harnex/commands/doctor.rb +38 -4
- data/lib/harnex/commands/history.rb +7 -3
- data/lib/harnex/commands/run.rb +55 -43
- data/lib/harnex/commands/status.rb +0 -2
- data/lib/harnex/commands/wait.rb +0 -1
- data/lib/harnex/config.rb +170 -0
- data/lib/harnex/core.rb +200 -21
- data/lib/harnex/dispatch_history.rb +16 -7
- data/lib/harnex/pricing.rb +135 -0
- data/lib/harnex/retention.rb +320 -0
- data/lib/harnex/runtime/session.rb +451 -166
- data/lib/harnex/terminal_status.rb +18 -21
- data/lib/harnex/version.rb +2 -2
- data/lib/harnex.rb +3 -0
- metadata +9 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: d0a3ac349311bc2677614dabb091443bb21ec82bf63852d237fb38fd47ecaeda
|
|
4
|
+
data.tar.gz: f1b909c7ed43636ea57a297e25f2adc1d56283faa5f8af882ed22b63b4c55f2f
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: fe2b745dd618e1967fa5bbe1f7f55f4c0c2beb104cd6d213592f8545528118d3b3a80053b5643fce5482d3eaca9c7e6d800b6f5dd6d41873c0c9e5cc73aff332
|
|
7
|
+
data.tar.gz: 0c13e6cb6fe6bbac64e14ae43b23061a2b5a96cbc7f4699d438b5e5eac48ef70435c017b638635c0ded52886536f94aac37df712b1d67a9c5485dc0dd1cfa4b7
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,193 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.10.0] - 2026-08-03 | 01:44 PM | IST
|
|
4
|
+
|
|
5
|
+
Minor bump, **breaking**: `--summary-out` is removed outright, so the canonical
|
|
6
|
+
`.harnex/dispatch.jsonl` is the only telemetry destination. Also fixes four
|
|
7
|
+
runner reliability defects found while verifying that removal — concurrent
|
|
8
|
+
registry corruption, a delivered send reported as failed, a corrupt registry
|
|
9
|
+
entry crashing every session scan, and a closed stdout wedging the wrapped
|
|
10
|
+
agent.
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
|
|
14
|
+
- **Concurrent registry writes no longer corrupt each other** (#66).
|
|
15
|
+
`write_registry` derived its temp path from the pid alone, but several
|
|
16
|
+
threads in one session write the same registry — the startup persist, the
|
|
17
|
+
inbox delivery thread, and one thread per API client. One thread renamed the
|
|
18
|
+
file another was still writing, and the loser raised `Errno::ENOENT`
|
|
19
|
+
(2080 failures in a 2400-write reproduction; now zero). Writes are also no
|
|
20
|
+
longer defeated by a state directory that was reaped mid-session.
|
|
21
|
+
- **A failed registry write no longer fails an already delivered send** (#66).
|
|
22
|
+
Registry persistence runs *after* the prompt has reached the agent, so a
|
|
23
|
+
bookkeeping failure was reporting a dispatched turn as failed — enough to
|
|
24
|
+
make an orchestrator retry work already in flight. Post-injection refresh now
|
|
25
|
+
warns; startup persistence stays strict so an undiscoverable session still
|
|
26
|
+
fails loudly instead of running unreachable.
|
|
27
|
+
- **One corrupt registry file no longer crashes every session scan** (#66).
|
|
28
|
+
A non-numeric pid raised `ArgumentError` out of `active_sessions`, taking
|
|
29
|
+
down `harnex status`, `harnex send`, and `harnex pane`. Such an entry is now
|
|
30
|
+
treated as dead and pruned, matching the existing self-healing for
|
|
31
|
+
unparseable JSON.
|
|
32
|
+
- **A closed stdout no longer wedges the wrapped agent** (#66).
|
|
33
|
+
`Errno::EPIPE`/`EBADF` are not `IOError` subclasses, so they escaped the
|
|
34
|
+
output reader's rescue and killed the thread; the PTY then stopped draining
|
|
35
|
+
and the agent blocked forever on write, presenting as an agent hang with no
|
|
36
|
+
harness error. Draining is now unconditional and stdout echo is best-effort.
|
|
37
|
+
Both reader loops report an unexpected exit instead of vanishing silently.
|
|
38
|
+
- `Retention` metadata writes route through the shared atomic writer instead of
|
|
39
|
+
repeating the same pid-only temp-name pattern.
|
|
40
|
+
|
|
41
|
+
### Removed
|
|
42
|
+
|
|
43
|
+
- **BREAKING: `--summary-out` is gone** (#65). `.harnex/dispatch.jsonl` is now
|
|
44
|
+
the only destination a dispatch writes telemetry to. Passing `--summary-out
|
|
45
|
+
PATH` or `--summary-out=PATH` is rejected as an unknown flag and exits
|
|
46
|
+
non-zero; it is deliberately not a silent ignore, so a stale caller fails
|
|
47
|
+
immediately rather than believing it still has a second copy. 0.9.0 demoted
|
|
48
|
+
the flag to an explicit-only mirror but left it in place; that mirror was the
|
|
49
|
+
source of a three-times-hand-reconciled stranded-telemetry class.
|
|
50
|
+
- `summary_out_path` no longer appears on `dispatch_start` or `dispatch_end`
|
|
51
|
+
rows, and `summary_out` no longer appears in `harnex status --json`,
|
|
52
|
+
`harnex wait`, or `harnex watch` payloads. The `summary` event no longer
|
|
53
|
+
carries `mirror_path`.
|
|
54
|
+
|
|
55
|
+
### Added
|
|
56
|
+
|
|
57
|
+
- **Harness-authored observed-state receipts** (#64): every dispatch now writes
|
|
58
|
+
a canonical `harnex.artifact_report.v1` receipt without worker-authored JSON.
|
|
59
|
+
Receipts carry explicit `receipt.author=harnex` provenance, start/end Git
|
|
60
|
+
state (committed plus staged/unstaged/untracked paths and LOC), bounded Codex
|
|
61
|
+
command exits, turn acceptance, and usage. The receipt is written before a
|
|
62
|
+
structured `task_complete` event and refreshed with final teardown telemetry.
|
|
63
|
+
- Every session receives a default repo-keyed receipt under
|
|
64
|
+
`~/.local/state/harnex/receipts/`; `--artifact-report` now overrides that
|
|
65
|
+
destination. Live status, detached/tmux launch payloads, dispatch-start rows,
|
|
66
|
+
and dispatch-end metadata expose the receipt and claims paths.
|
|
67
|
+
- Review workers may write a bounded optional block to
|
|
68
|
+
`HARNEX_ARTIFACT_CLAIMS_PATH` (`summary`, `verdict`, and P1/P2/P3 counts).
|
|
69
|
+
Claims are sanitized and copied into the receipt but never participate in
|
|
70
|
+
completion acceptance or final-receipt validity.
|
|
71
|
+
- Receipt files and claims inputs join the existing 45-day / 1-GiB retention
|
|
72
|
+
policy as a third independently configurable directory, including
|
|
73
|
+
`HARNEX_RECEIPTS_MAX_AGE_DAYS` / `HARNEX_RECEIPTS_MAX_BYTES` and live/current
|
|
74
|
+
path protection.
|
|
75
|
+
|
|
76
|
+
### Changed
|
|
77
|
+
|
|
78
|
+
- `TerminalStatus` resolves exclusively from the canonical stream. It
|
|
79
|
+
previously preferred the mirror file named by a record's `summary_out_path`,
|
|
80
|
+
which — with the writer removed — would have let a leftover mirror from an
|
|
81
|
+
older release resolve status from stale data. A pre-existing mirror file on
|
|
82
|
+
disk now has no effect on any id.
|
|
83
|
+
- `status["source"]` reports `dispatch_end` where it previously reported
|
|
84
|
+
`summary_out` for rich end rows. `dispatch_history`, `dispatch_start`,
|
|
85
|
+
`live`, `registry`, and `none` are unchanged.
|
|
86
|
+
- `artifact-report validate --final` preserves the legacy manual-v1 contract
|
|
87
|
+
while recognizing the additive harness-receipt contract. Harness receipts
|
|
88
|
+
validate observed acceptance and zero-delta evidence; failed exploratory
|
|
89
|
+
command exits remain factual telemetry for queue policy rather than allowing
|
|
90
|
+
worker claims to decide receipt validity.
|
|
91
|
+
- Artifact fingerprints are now internal claims-freshness bookkeeping only.
|
|
92
|
+
Pre-existing, stale, malformed, or missing worker reports are overwritten by
|
|
93
|
+
fresh harness proof instead of becoming work-acceptance failures. The legacy
|
|
94
|
+
`init` command and `--require-artifact-report` flag remain compatible, but
|
|
95
|
+
neither an explicit path nor model-authored proof is required.
|
|
96
|
+
- Codex autonomous completion still rejects acknowledgment-only turns as
|
|
97
|
+
`completed_no_activity`; optional claims cannot satisfy the observed-activity
|
|
98
|
+
gate. Receipt write/validation failure is fail-closed as `report_invalid`.
|
|
99
|
+
- Git observation now baselines the starting worktree so uncommitted product
|
|
100
|
+
edits are included while unchanged pre-existing dirt and harness-owned
|
|
101
|
+
dispatch/receipt files are excluded.
|
|
102
|
+
|
|
103
|
+
## [0.9.0] - 2026-08-03 | 01:11 AM | IST
|
|
104
|
+
|
|
105
|
+
Minor bump: the durable dispatch row family is now v2, `--summary-out` changes
|
|
106
|
+
from a default destination to an explicit mirror, and retention/phase policy add
|
|
107
|
+
operator-visible behavior.
|
|
108
|
+
|
|
109
|
+
### Added
|
|
110
|
+
|
|
111
|
+
- **Price-table cost for token-reporting adapters** (#63, plan 33
|
|
112
|
+
Phase 2; subsumes #58's cost gap): new `lib/harnex/pricing.rb` holds a
|
|
113
|
+
static per-1M-token USD rate table keyed by provider + model, each entry
|
|
114
|
+
`as_of`-dated and hand-copied from the provider pricing pages
|
|
115
|
+
(OpenAI gpt-5.x/codex and Anthropic Claude families, rates as of
|
|
116
|
+
2026-08-02; update procedure documented in the file header).
|
|
117
|
+
`build_summary_usage` applies it only when `cost_usd` is null, usage
|
|
118
|
+
status is `observed`/`zero`, and the effective model matches the table —
|
|
119
|
+
then `cost_source: "price_table"` and a new always-present
|
|
120
|
+
`usage.cost_price_as_of` field record provenance. Unknown models stay
|
|
121
|
+
null; provider-reported cost (Pi) is never overwritten; costs are never
|
|
122
|
+
backfilled.
|
|
123
|
+
- The codex app-server adapter now captures the effective model from the
|
|
124
|
+
schema-required `model` field on `thread/start` / `thread/resume`
|
|
125
|
+
responses, so `agent.model_effective` (and price-table lookup) resolves
|
|
126
|
+
without the caller passing `--meta '{"model": ...}'`.
|
|
127
|
+
- Token-semantics are capture-path-aware: new adapter hook
|
|
128
|
+
`usage_input_includes_cached?` distinguishes codex app-server JSON
|
|
129
|
+
(cached ⊆ input → billable input = input − cached) from the codex PTY
|
|
130
|
+
transcript line (input excludes cached → cached prices additively).
|
|
131
|
+
Verified against the captured schema fixtures and a live app-server row.
|
|
132
|
+
- Price-table lookup now covers Holm's effective `gpt-5.5` model and keys its
|
|
133
|
+
tier-sensitive rates by the recorded service tier (`standard`, `flex`, or
|
|
134
|
+
`fast`; `priority` aliases fast). Because published `gpt-5.5` rates split at
|
|
135
|
+
272K active context, Harnex also requires an observed peak below that boundary;
|
|
136
|
+
missing/long-context evidence remains unpriced rather than applying the wrong
|
|
137
|
+
short-context rate.
|
|
138
|
+
- Optional repo phase policy in `.harnex/config.json`: an allowlist can `warn`
|
|
139
|
+
or `reject` non-canonical effective `meta.phase` values before spawn. Explicit
|
|
140
|
+
malformed policy files fail closed; no config preserves existing behavior.
|
|
141
|
+
- Bounded events/output retention: 45-day and 1-GiB defaults per directory,
|
|
142
|
+
repo config plus environment overrides, current/live-session protection,
|
|
143
|
+
oldest-first age/size pruning, one-hour automatic throttle, and bounded
|
|
144
|
+
last-prune metadata. `harnex doctor` reports size/limits; `--prune --dry-run`
|
|
145
|
+
previews bounded candidate paths and `--prune` applies the policy.
|
|
146
|
+
|
|
147
|
+
### Changed
|
|
148
|
+
|
|
149
|
+
- **Single tracked telemetry stream** (#63, plan 33 Phase 1): a dispatch
|
|
150
|
+
now writes exactly two rows to the repo-tracked `.harnex/dispatch.jsonl`
|
|
151
|
+
— the `dispatch_start` row and one unified v2 `dispatch_end` row that
|
|
152
|
+
merges the thin envelope (top-level `schema_version: 2`, `record_type`,
|
|
153
|
+
`id`, `status`, `tier`, timing, `tmux_state`, …) with the rich summary
|
|
154
|
+
sections (`meta`, `predicted`, `actual`, `agent`, `usage`, `context`,
|
|
155
|
+
`attribution`, `outcome`, `attempt`, `reliability`, `queue?`,
|
|
156
|
+
`orchestration?`, artifact-report keys). Start rows stamp
|
|
157
|
+
`schema_version: 2` as well. Readers accept v1 and v2 rows mixed in one
|
|
158
|
+
file; `harnex history` keeps skipping pre-0.7.3 envelope-less rows.
|
|
159
|
+
- `--summary-out` is now an explicit-only mirror: no default path. When
|
|
160
|
+
set, the identical v2 end record is appended there in addition to the
|
|
161
|
+
tracked stream. Consumers that redirected `--summary-out` to keep rich
|
|
162
|
+
rows should drop the flag — the tracked stream now carries everything.
|
|
163
|
+
`Harnex.default_summary_out_path` is removed; every writer and reader
|
|
164
|
+
resolves the stream through `DispatchHistory.path_for` (git-root walk,
|
|
165
|
+
global fallback), so non-git roots stream to the global file instead of
|
|
166
|
+
a repo-local `.harnex/` directory.
|
|
167
|
+
- The `summary` event now points `path` at the tracked stream and carries
|
|
168
|
+
`mirror_path` when a mirror is configured.
|
|
169
|
+
- `TerminalStatus` resolves a v2 end row as both summary and history in
|
|
170
|
+
one shot (branching on `record_type` first), so `wait --until done` and
|
|
171
|
+
`status --id` fall back to the unified stream; legacy duck-types remain
|
|
172
|
+
for pre-v2 files.
|
|
173
|
+
- Cross-dispatch attempt fields are harness-derived from the canonical stream:
|
|
174
|
+
`attempts_total`/succeeded/failed, `fallback_triggered`, and
|
|
175
|
+
`reliability.recovered` follow bounded parent links and degrade safely on
|
|
176
|
+
missing, duplicate, malformed, or cyclic history. `fallback` is now a public,
|
|
177
|
+
live-parent-guarded attempt kind; in-run `retry_count` remains separate.
|
|
178
|
+
- Public telemetry/configuration references under `docs/*.md` are now packaged
|
|
179
|
+
in the gem. README, GUIDE, TECHNICAL, agent guides, and event/telemetry docs
|
|
180
|
+
use the same canonical-stream, mirror, native-watch, pricing, phase-policy,
|
|
181
|
+
and retention terminology.
|
|
182
|
+
|
|
183
|
+
### Fixed
|
|
184
|
+
|
|
185
|
+
- `harnex history` no longer renders blank rows for pre-0.7.3
|
|
186
|
+
`{meta, predicted, actual}`-schema telemetry rows in
|
|
187
|
+
`.harnex/dispatch.jsonl`: rows recognized as neither start nor end
|
|
188
|
+
records are skipped in both table and `--json` output. The raw file is
|
|
189
|
+
untouched — legacy rows remain available for forensics.
|
|
190
|
+
|
|
3
191
|
## [0.8.0] - 2026-08-02 | 08:46 PM | IST
|
|
4
192
|
|
|
5
193
|
Minor bump: two behavior changes below (`wait --until done` exit codes,
|
data/GUIDE.md
CHANGED
|
@@ -8,11 +8,11 @@ Treat harnex as a local supervisor harness, not as a conversation
|
|
|
8
8
|
bus between agents.
|
|
9
9
|
|
|
10
10
|
- Start a fresh worker for each step, usually with `--tmux`
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
|
|
15
|
-
- Stop
|
|
11
|
+
- Give one clear startup task with `--context`; add `--auto-stop` for one-shot work
|
|
12
|
+
- Monitor existing visible work with `harnex watch --until done`
|
|
13
|
+
- Use `--wait-for-idle` only as a follow-up-send fence, then verify the artifact
|
|
14
|
+
- Ask the worker to write its output to a file when the next step needs it
|
|
15
|
+
- Stop completed interactive workers promptly
|
|
16
16
|
|
|
17
17
|
For multi-step flows, chain fresh workers with file handoffs:
|
|
18
18
|
Codex writes a plan, another Codex implements it, Claude reviews it,
|
|
@@ -49,14 +49,18 @@ automatically when the agent is ready. You don't have to wait
|
|
|
49
49
|
or retry. Queueing exists, but the default workflow should still be
|
|
50
50
|
one task per fresh worker.
|
|
51
51
|
|
|
52
|
-
For unattended dispatch, prefer
|
|
52
|
+
For unattended visible dispatch, prefer the native work-level watcher over
|
|
53
|
+
external poll loops:
|
|
53
54
|
|
|
54
55
|
```bash
|
|
55
|
-
harnex run codex --id impl --tmux impl
|
|
56
|
+
harnex run codex --id impl --tmux impl \
|
|
57
|
+
--context "Read and execute /tmp/task-impl.md" --auto-stop
|
|
58
|
+
harnex watch --id impl --until done --max-wait 90m
|
|
56
59
|
```
|
|
57
60
|
|
|
58
|
-
|
|
59
|
-
|
|
61
|
+
`harnex run --watch --preset impl` is a separate foreground launch-and-stall
|
|
62
|
+
babysitter; do not combine it with `--tmux` or `--detach`. For full flag
|
|
63
|
+
behavior and event-stream consumers, see
|
|
60
64
|
[TECHNICAL.md](TECHNICAL.md) and the built-in monitoring section in
|
|
61
65
|
[README.md](README.md).
|
|
62
66
|
|
|
@@ -262,4 +266,7 @@ harnex agents-guide # deeper agent-facing guidance
|
|
|
262
266
|
## What's next
|
|
263
267
|
|
|
264
268
|
For the full command reference, flags, HTTP API, and internals,
|
|
265
|
-
see [TECHNICAL.md](TECHNICAL.md).
|
|
269
|
+
see [TECHNICAL.md](TECHNICAL.md). The packaged
|
|
270
|
+
[dispatch telemetry](docs/dispatch-telemetry.md) and
|
|
271
|
+
[configuration](docs/configuration.md) references cover the canonical v2 stream,
|
|
272
|
+
phase allowlists, and log retention.
|
data/README.md
CHANGED
|
@@ -60,9 +60,10 @@ job, watch it work, stop it when done.
|
|
|
60
60
|
### Run from a temporary/public bundle
|
|
61
61
|
|
|
62
62
|
Use `--cwd DIR` when the worker should see a specific directory rather than
|
|
63
|
-
the orchestrator's current repo. Harnex starts the wrapped agent in `DIR
|
|
64
|
-
|
|
65
|
-
`.harnex/dispatch.jsonl
|
|
63
|
+
the orchestrator's current repo. Harnex starts the wrapped agent in `DIR` and
|
|
64
|
+
uses it for session attribution. Canonical dispatch telemetry is written to the
|
|
65
|
+
enclosing git root's `.harnex/dispatch.jsonl`; a non-git directory uses the
|
|
66
|
+
global `~/.local/state/harnex/dispatch.jsonl` fallback:
|
|
66
67
|
|
|
67
68
|
```bash
|
|
68
69
|
harnex run codex --cwd /tmp/leximaze_eval_run_001 \
|
|
@@ -205,8 +206,8 @@ bare `--watch` means babysitter mode.
|
|
|
205
206
|
|
|
206
207
|
For one-shot startup prompts, add `--auto-stop`. It requires `--context`.
|
|
207
208
|
A Codex app-server turn launched from `--context` only counts as accepted
|
|
208
|
-
autonomous work when structured command/tool activity
|
|
209
|
-
|
|
209
|
+
autonomous work when structured command/tool activity or a Git delta proves
|
|
210
|
+
activity. Optional receipt claims cannot satisfy this gate. An acknowledgment-only turn emits
|
|
210
211
|
`outcome.class=completed_no_activity`, makes `watch --until done` return
|
|
211
212
|
non-zero, and auto-stops with a non-zero verdict instead of reporting success.
|
|
212
213
|
PTY adapters still stop on prompt return because they do not expose equivalent
|
|
@@ -252,14 +253,17 @@ Schema details and compatibility policy are documented in
|
|
|
252
253
|
|
|
253
254
|
## Dispatch history
|
|
254
255
|
|
|
255
|
-
Every
|
|
256
|
-
|
|
257
|
-
`
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
256
|
+
Every `harnex run` writes exactly one v2 `dispatch_start` row at registration
|
|
257
|
+
and one rich v2 `dispatch_end` row at teardown. Both use the canonical stream:
|
|
258
|
+
`<git-root>/.harnex/dispatch.jsonl` inside a git repo, or
|
|
259
|
+
`~/.local/state/harnex/dispatch.jsonl` otherwise. The end row combines the
|
|
260
|
+
history envelope with usage, context, attribution, outcome, attempt,
|
|
261
|
+
reliability, queue/orchestration, and a harness-authored observed-state receipt.
|
|
262
|
+
|
|
263
|
+
The canonical stream is the only destination; there is no flag to mirror a
|
|
264
|
+
second copy elsewhere. `harnex history`, `harnex status --id ID --json`, and
|
|
265
|
+
`harnex wait` all read the canonical stream when the live registry is gone.
|
|
266
|
+
Mixed legacy v1 and v2 rows remain readable.
|
|
263
267
|
|
|
264
268
|
Use `harnex history` to inspect it:
|
|
265
269
|
|
|
@@ -274,36 +278,37 @@ Dispatch briefs can declare soft budget metadata through `--meta`:
|
|
|
274
278
|
harnex run pi --meta '{"read_budget_lines":2000,"output_ceiling_lines":800}' ...
|
|
275
279
|
```
|
|
276
280
|
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
281
|
+
Every dispatch gets a canonical `harnex.artifact_report.v1` receipt generated
|
|
282
|
+
by Harnex from observed state: start/end Git SHA and delta, changed paths and
|
|
283
|
+
LOC, structured command exits when the transport exposes them, turn outcome,
|
|
284
|
+
and usage. No model-authored proof JSON or `--artifact-report` flag is needed.
|
|
285
|
+
The default file lives under `~/.local/state/harnex/receipts/`; the live status
|
|
286
|
+
payload and final dispatch row expose its absolute path.
|
|
287
|
+
|
|
288
|
+
Use `--artifact-report PATH` only to override that destination. During the run,
|
|
289
|
+
`HARNEX_ARTIFACT_REPORT_PATH` names the harness-owned final file and
|
|
290
|
+
`HARNEX_ARTIFACT_CLAIMS_PATH` names a separate optional worker input. A review
|
|
291
|
+
worker may attach bounded context without controlling acceptance:
|
|
292
|
+
|
|
293
|
+
```json
|
|
294
|
+
{
|
|
295
|
+
"claims": {
|
|
296
|
+
"summary": "Review complete; one P2 remains.",
|
|
297
|
+
"verdict": "changes_requested",
|
|
298
|
+
"findings": { "P1": 0, "P2": 1, "P3": 0 }
|
|
299
|
+
}
|
|
300
|
+
}
|
|
288
301
|
```
|
|
289
302
|
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
Without `--require-artifact-report`, report defects remain fail-soft warning
|
|
300
|
-
telemetry. With it, a missing, malformed, unsupported, oversized,
|
|
301
|
-
contract-incomplete, rejected, or unchanged stale report makes the work verdict
|
|
302
|
-
non-zero. A fresh explicit `no_change` report can prove an intentional no-delta
|
|
303
|
-
task without fake edits. Harnex records compact `artifact_report`, `validation`,
|
|
304
|
-
and `artifacts` blocks plus `outcome.class` / `outcome.report_status`; Git
|
|
305
|
-
changes alone never imply semantic acceptance, and JSON printed in final prose
|
|
306
|
-
is never scraped as a sidecar.
|
|
303
|
+
Harnex sanitizes that block and writes it into the receipt; malformed, stale,
|
|
304
|
+
or missing claims are ignored. Claims and final prose can never turn an
|
|
305
|
+
otherwise rejected completion into accepted proof. `harnex artifact-report
|
|
306
|
+
validate PATH --final` validates the harness receipt for consumers, while the
|
|
307
|
+
older `init` command and legacy worker-authored v1 validation remain available
|
|
308
|
+
for compatibility. `--require-artifact-report` is also retained for existing
|
|
309
|
+
scripts but no longer requires an explicit path. A receipt write failure fails
|
|
310
|
+
closed as `report_invalid`; ordinary workers no longer fail because they forgot
|
|
311
|
+
or malformed proof JSON.
|
|
307
312
|
|
|
308
313
|
Queue runners can pass first-class attribution without hiding it in prose:
|
|
309
314
|
|
|
@@ -312,17 +317,17 @@ harnex run pi --project-id harnex --queue-id queue-005 --entry-id SP-4 \
|
|
|
312
317
|
--phase implement --intent queue-work --require-attribution ...
|
|
313
318
|
```
|
|
314
319
|
|
|
315
|
-
Soft budget metadata is copied into
|
|
316
|
-
metadata is copied into top-level `queue`, `agent`, and `reliability`
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
`
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
320
|
+
Soft budget metadata is copied into end-row `meta`; queue/agent/reliability
|
|
321
|
+
metadata is copied into top-level `queue`, `agent`, and `reliability` blocks.
|
|
322
|
+
Every end row also has `usage` (so null is distinguishable from explicit zero or
|
|
323
|
+
an estimate), `attribution`, `outcome`, and a joinable `attempt` block. When an
|
|
324
|
+
adapter reports tokens but no cost, Harnex may compute provider list-price cost
|
|
325
|
+
only for an exact maintained provider/model/service-tier/context-rate match; such rows use
|
|
326
|
+
`usage.cost_source: "price_table"` and carry `usage.cost_price_as_of`.
|
|
327
|
+
Provider-reported cost remains authoritative, estimates remain labelled, and
|
|
328
|
+
unknown rates stay null. `actual` also records timing, exit classification, git
|
|
329
|
+
deltas, task-completion state, harness-derived cross-dispatch attempt counts,
|
|
330
|
+
operational counters, output/event paths, and bounded volume measurements.
|
|
326
331
|
|
|
327
332
|
Long queue runners can also opt into logical primary-orchestrator rollups:
|
|
328
333
|
|
|
@@ -422,8 +427,8 @@ See [recipes/03_buddy.md](recipes/03_buddy.md) for the full pattern.
|
|
|
422
427
|
| `harnex events --id <id>` | Stream structured session events (`--snapshot` for non-blocking dump) |
|
|
423
428
|
| `harnex history` | List completed dispatches from `.harnex/dispatch.jsonl` |
|
|
424
429
|
| `harnex wait --id <id>` | Block until process exit by default; use `--until done` for unattended work completion or `--until task_complete` for exact structured turn completion |
|
|
425
|
-
| `harnex artifact-report init\|validate PATH` |
|
|
426
|
-
| `harnex doctor` | Run
|
|
430
|
+
| `harnex artifact-report init\|validate PATH` | Validate harness-authored `harnex.artifact_report.v1` receipts; `init` remains for legacy/manual documents |
|
|
431
|
+
| `harnex doctor` | Run dependency and retention diagnostics; `--sweep` reports session drift, `--prune --dry-run` previews retention, and `--prune` applies it |
|
|
427
432
|
| `harnex guide` | Getting started walkthrough |
|
|
428
433
|
| `harnex agents-guide` | Agent-facing dispatch, chain, buddy, monitoring, and naming guides |
|
|
429
434
|
| `harnex recipes` | List and read tested workflow patterns (`show 01`, `show buddy`) |
|
|
@@ -442,6 +447,8 @@ longer used. Remove stale `~/.claude/skills/harnex-*` or
|
|
|
442
447
|
|
|
443
448
|
- [GUIDE.md](GUIDE.md) — getting started walkthrough with examples
|
|
444
449
|
- [TECHNICAL.md](TECHNICAL.md) — full command reference, flags, HTTP API, architecture
|
|
450
|
+
- [docs/dispatch-telemetry.md](docs/dispatch-telemetry.md) — v2 dispatch stream and field contract
|
|
451
|
+
- [docs/configuration.md](docs/configuration.md) — phase allowlists and events/output/receipt retention
|
|
445
452
|
|
|
446
453
|
## License
|
|
447
454
|
|
data/TECHNICAL.md
CHANGED
|
@@ -29,27 +29,44 @@ harnex run codex -- --cd ~/other/repo
|
|
|
29
29
|
| `--watch-file PATH` | Auto-send a file-change hook (`--watch PATH`/`--watch=PATH` legacy) |
|
|
30
30
|
| `--context TXT` | Give the agent a task on startup |
|
|
31
31
|
| `--auto-stop` | With `--context`, stop after accepted task completion |
|
|
32
|
-
| `--
|
|
33
|
-
| `--
|
|
32
|
+
| `--meta JSON` | Attach bounded caller metadata |
|
|
33
|
+
| `--phase TEXT` | First-class phase attribution (optionally repo-allowlisted) |
|
|
34
|
+
| `--artifact-report PATH` | Override the harness-authored v1 receipt destination |
|
|
35
|
+
| `--require-artifact-report` | Compatibility strict flag; default receipt path is sufficient |
|
|
34
36
|
| `--fast` | For Codex, use `service_tier="fast"` instead of default `flex` |
|
|
35
37
|
| `--timeout SEC` | Wait budget for detached registration |
|
|
36
38
|
|
|
37
39
|
Codex app-server auto-stop rejects completion with no structured command/tool
|
|
38
|
-
activity
|
|
39
|
-
|
|
40
|
-
and
|
|
40
|
+
activity or Git delta as `completed_no_activity`. Every transport gets a
|
|
41
|
+
harness-authored observed-state receipt; optional worker claims never determine
|
|
42
|
+
acceptance, and receipt-write failure is fail-closed.
|
|
41
43
|
|
|
42
|
-
### `harnex
|
|
44
|
+
### `harnex doctor` — Preflight, drift, and retention
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
harnex doctor
|
|
48
|
+
harnex doctor --sweep
|
|
49
|
+
harnex doctor --prune --dry-run
|
|
50
|
+
harnex doctor --prune
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Plain output includes adapter prerequisites and events/output/receipt retention status.
|
|
54
|
+
`--sweep` adds read-only live-session/tmux drift diagnostics. `--prune --dry-run`
|
|
55
|
+
previews age/size-cap deletions; `--prune` applies them while preserving current
|
|
56
|
+
and live-session files. See [docs/configuration.md](docs/configuration.md).
|
|
57
|
+
|
|
58
|
+
### `harnex artifact-report` — Validate receipts and legacy proof
|
|
43
59
|
|
|
44
60
|
```bash
|
|
45
61
|
harnex artifact-report init .harnex/reports/worker.json
|
|
46
62
|
harnex artifact-report validate .harnex/reports/worker.json --final
|
|
47
63
|
```
|
|
48
64
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
validation
|
|
65
|
+
Normal runs write their own final receipt, so workers do not call `init`.
|
|
66
|
+
`validate` emits bounded machine-readable field diagnostics; `--final` accepts
|
|
67
|
+
a complete harness receipt whose observed terminal state was accepted. `init`
|
|
68
|
+
remains for legacy/manual v1 documents, whose older successful-validation
|
|
69
|
+
contract is still supported.
|
|
53
70
|
|
|
54
71
|
### `harnex send` — Talk to a running agent
|
|
55
72
|
|
|
@@ -98,6 +115,8 @@ Use `--json` for full payloads. JSON includes:
|
|
|
98
115
|
|
|
99
116
|
- `log_mtime` (ISO8601 or `null`) — transcript file mtime
|
|
100
117
|
- `log_idle_s` (Integer or `null`) — seconds since last transcript write
|
|
118
|
+
- `artifact_report_path` — harness-owned final observed-state receipt
|
|
119
|
+
- `artifact_claims_path` — optional bounded worker-claims input
|
|
101
120
|
|
|
102
121
|
Use `--all` for all repos.
|
|
103
122
|
|
|
@@ -115,8 +134,10 @@ harnex history
|
|
|
115
134
|
harnex history --json | jq .
|
|
116
135
|
```
|
|
117
136
|
|
|
118
|
-
Reads `<
|
|
119
|
-
|
|
137
|
+
Reads the canonical v2 stream at `<git-root>/.harnex/dispatch.jsonl`; use
|
|
138
|
+
`--global` for `~/.local/state/harnex/dispatch.jsonl` outside a repo. Each run
|
|
139
|
+
has one `dispatch_start` plus one rich `dispatch_end`. That stream is the only
|
|
140
|
+
destination; no flag mirrors the end row into a second file.
|
|
120
141
|
|
|
121
142
|
### `harnex logs` — Read session transcripts
|
|
122
143
|
|
|
@@ -246,8 +267,9 @@ Transport file (append-only JSONL):
|
|
|
246
267
|
```
|
|
247
268
|
|
|
248
269
|
Each row uses schema v1 with envelope fields `schema_version`, `seq`, `ts`,
|
|
249
|
-
`id`, and `type`.
|
|
250
|
-
|
|
270
|
+
`id`, and `type`. Lifecycle, send, usage, git, summary, attempt, completion,
|
|
271
|
+
and adapter-specific events are additive; consumers must ignore unknown event
|
|
272
|
+
types. `send.msg` is a 200-character preview with `msg_truncated` when shortened.
|
|
251
273
|
|
|
252
274
|
Schema details and compatibility guarantees are in [docs/events.md](docs/events.md).
|
|
253
275
|
|
|
@@ -300,7 +322,8 @@ When you run `harnex run codex --id worker`:
|
|
|
300
322
|
hash(repo_root + id) % port_span + base_port
|
|
301
323
|
walk forward until a free port is found
|
|
302
324
|
6. Start HTTP server on 127.0.0.1:<port>
|
|
303
|
-
7.
|
|
325
|
+
7. Opportunistically enforce configured age/size retention for events/output/receipts,
|
|
326
|
+
preserving current and live-session files; then write registry file:
|
|
304
327
|
~/.local/state/harnex/sessions/<repo_hash>--<id>.json
|
|
305
328
|
and open transcript file:
|
|
306
329
|
~/.local/state/harnex/output/<repo_hash>--<id>.log
|