@sentropic/h2a 0.96.1 → 0.96.2

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 (71) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/.codex-plugin/plugin.json +1 -1
  3. package/dist/cli.d.ts.map +1 -1
  4. package/dist/cli.js +74 -27
  5. package/dist/cli.js.map +1 -1
  6. package/dist/index.d.ts +3 -0
  7. package/dist/index.d.ts.map +1 -1
  8. package/dist/index.js +2 -0
  9. package/dist/index.js.map +1 -1
  10. package/dist/runtime/drive/cluster-mesh-outer.d.ts +44 -0
  11. package/dist/runtime/drive/cluster-mesh-outer.d.ts.map +1 -0
  12. package/dist/runtime/drive/cluster-mesh-outer.js +70 -0
  13. package/dist/runtime/drive/cluster-mesh-outer.js.map +1 -0
  14. package/dist/runtime/drive/pty-actuator.d.ts +54 -0
  15. package/dist/runtime/drive/pty-actuator.d.ts.map +1 -0
  16. package/dist/runtime/drive/pty-actuator.js +371 -0
  17. package/dist/runtime/drive/pty-actuator.js.map +1 -0
  18. package/dist/runtime/local-files/paths.js +1 -1
  19. package/dist/runtime/local-files/paths.js.map +1 -1
  20. package/dist/runtime/local-files/presence.d.ts.map +1 -1
  21. package/dist/runtime/local-files/presence.js +10 -1
  22. package/dist/runtime/local-files/presence.js.map +1 -1
  23. package/dist/runtime/mcp/agent-launch.d.ts +2 -1
  24. package/dist/runtime/mcp/agent-launch.d.ts.map +1 -1
  25. package/dist/runtime/mcp/agent-launch.js +48 -8
  26. package/dist/runtime/mcp/agent-launch.js.map +1 -1
  27. package/dist/runtime/mcp/tools.d.ts.map +1 -1
  28. package/dist/runtime/mcp/tools.js +19 -6
  29. package/dist/runtime/mcp/tools.js.map +1 -1
  30. package/dist/runtime/memory/admit-client.d.ts +30 -0
  31. package/dist/runtime/memory/admit-client.d.ts.map +1 -0
  32. package/dist/runtime/memory/admit-client.js +44 -0
  33. package/dist/runtime/memory/admit-client.js.map +1 -0
  34. package/dist/runtime/memory/d11-ceremony.d.ts +731 -0
  35. package/dist/runtime/memory/d11-ceremony.d.ts.map +1 -0
  36. package/dist/runtime/memory/d11-ceremony.js +1282 -0
  37. package/dist/runtime/memory/d11-ceremony.js.map +1 -0
  38. package/dist/runtime/memory/graphify-contracts-v2.vendored.d.ts +922 -0
  39. package/dist/runtime/memory/graphify-contracts-v2.vendored.d.ts.map +1 -0
  40. package/dist/runtime/memory/graphify-contracts-v2.vendored.js +2 -0
  41. package/dist/runtime/memory/graphify-contracts-v2.vendored.js.map +1 -0
  42. package/dist/runtime/memory/note-builder.d.ts +83 -0
  43. package/dist/runtime/memory/note-builder.d.ts.map +1 -0
  44. package/dist/runtime/memory/note-builder.js +89 -0
  45. package/dist/runtime/memory/note-builder.js.map +1 -0
  46. package/dist/runtime/memory/port-v1.d.ts +235 -0
  47. package/dist/runtime/memory/port-v1.d.ts.map +1 -0
  48. package/dist/runtime/memory/port-v1.js +129 -0
  49. package/dist/runtime/memory/port-v1.js.map +1 -0
  50. package/dist/runtime/memory/port-v2-adapter.d.ts +117 -0
  51. package/dist/runtime/memory/port-v2-adapter.d.ts.map +1 -0
  52. package/dist/runtime/memory/port-v2-adapter.js +140 -0
  53. package/dist/runtime/memory/port-v2-adapter.js.map +1 -0
  54. package/dist/runtime/memory/port-v2-compat.d.ts +50 -0
  55. package/dist/runtime/memory/port-v2-compat.d.ts.map +1 -0
  56. package/dist/runtime/memory/port-v2-compat.js +102 -0
  57. package/dist/runtime/memory/port-v2-compat.js.map +1 -0
  58. package/dist/runtime/memory/preflight.d.ts +17 -0
  59. package/dist/runtime/memory/preflight.d.ts.map +1 -0
  60. package/dist/runtime/memory/preflight.js +18 -0
  61. package/dist/runtime/memory/preflight.js.map +1 -0
  62. package/dist/runtime/memory/promote-client.d.ts +172 -0
  63. package/dist/runtime/memory/promote-client.d.ts.map +1 -0
  64. package/dist/runtime/memory/promote-client.js +168 -0
  65. package/dist/runtime/memory/promote-client.js.map +1 -0
  66. package/dist/runtime/memory/recall-client.d.ts +74 -0
  67. package/dist/runtime/memory/recall-client.d.ts.map +1 -0
  68. package/dist/runtime/memory/recall-client.js +91 -0
  69. package/dist/runtime/memory/recall-client.js.map +1 -0
  70. package/package.json +4 -1
  71. package/skills/h2a-run/SKILL.md +39 -6
@@ -0,0 +1,172 @@
1
+ /**
2
+ * Promote client — D11 double-consensus, CLIENT-SIDE orchestration (build brief
3
+ * slice 6, this build's WP11-slice-3). Two independent high-grade legs each
4
+ * write a VERDICT (third-party-readable, never self-report); this module
5
+ * enforces the double-consensus BEFORE `promoteNote` is ever called, and
6
+ * dispatches through an INJECTED `MemoryProducerPort` exactly like
7
+ * `admit-client.ts` does for admission.
8
+ *
9
+ * SCOPE (bounded): this is the client's consensus *enforcement* + evidence
10
+ * *assembly*. Launching the two model legs and interpreting/reading verdict
11
+ * FILES is out of scope here — a "leg" is an opaque `{model, session}` pair
12
+ * and a verdict ref is an opaque locator string, both supplied by the caller
13
+ * (the conductor orchestrating the legs). graphify's gate is the other half
14
+ * of this boundary: it re-checks structurally (refs + attestation shape), it
15
+ * never trusts this client's say-so either — this module's own refusal is a
16
+ * courtesy that saves a round trip, not the authority.
17
+ *
18
+ * REF, NOT INLINE: `independence_attestation` in `PromotionEvidence` is a
19
+ * LOCATOR string, exactly like `leg1_verdict_ref`/`leg2_verdict_ref` (§9.4).
20
+ * graphify's evidence holds the three refs; the attestation ARTIFACT (a file
21
+ * — see `./d11-ceremony.ts`, which writes it) holds the actual
22
+ * `IndependenceAttestation` content that ref points to. This module never
23
+ * serializes the attestation object itself into the evidence — the caller
24
+ * writes the artifact and hands `assemblePromotionEvidence` the ref it got
25
+ * back.
26
+ *
27
+ * I5 — fail-closed, TWO LAYERS:
28
+ * 1. `checkDoubleConsensusPreconditions` is a PURE, port-less function. It
29
+ * cannot call the port even if it wanted to — a refusal here makes
30
+ * "promoteNote never called" true BY CONSTRUCTION, not by a runtime
31
+ * guard that could be bypassed or forgotten.
32
+ * 2. `promoteNote` (the raw dispatch) mirrors `admit-client.ts`: an absent
33
+ * port, or one that throws/rejects, REFUSES — never a silent
34
+ * `promoted: true` a caller might mistake for success.
35
+ * `promoteNoteWithDoubleConsensus` composes both layers for a caller that
36
+ * wants one call: check → assemble → dispatch, short-circuiting before the
37
+ * port is ever touched on any local refusal.
38
+ *
39
+ * STRUCTURAL independence, not merely attested: the guard computes leg
40
+ * distinctness and the author/session collision from the VERDICTS'
41
+ * own `leg` field, never from `attestation.distinctModels` /
42
+ * `attestation.distinctSessions` — those booleans are a self-report from the
43
+ * orchestrator and reach graphify only by reference (the attestation
44
+ * ARTIFACT, not this in-memory object — see the REF note above), but this
45
+ * client does not treat them as authoritative for its own local refusal. A
46
+ * lying attestation cannot paper over two identical verdict legs.
47
+ *
48
+ * I1 — durable identity slot: `leg.model`, `leg.session`, `authorId` and
49
+ * `noteId` are all OPAQUE strings here — compared with `===` only, never
50
+ * parsed, split or derived-from. This module reserves the slot; it does not
51
+ * mint or interpret conversation-scoped identity.
52
+ * I4 — no new capabilities vocabulary opens here; `MemoryVerdict` and
53
+ * `IndependenceAttestation` are D11-specific data shapes, not a second
54
+ * capabilities taxonomy, and `PromotionEvidence`/`PromotionOutcome` are
55
+ * reused unchanged from `./port-v1.ts`.
56
+ */
57
+ import type { MemoryContext, MemoryProducerPort, PromotionEvidence, PromotionOutcome } from "./port-v1.js";
58
+ /** An opaque leg identity — never parsed, only compared for equality. */
59
+ export interface LegIdentity {
60
+ readonly model: string;
61
+ readonly session: string;
62
+ }
63
+ /**
64
+ * A single leg's verdict on a note. Written by the leg itself, to a
65
+ * third-party-readable file; the FILE (referenced elsewhere by an opaque
66
+ * `*Ref` string) is the record, not this in-memory shape — this type is how
67
+ * the client reasons about a verdict once the caller has already resolved
68
+ * one, not a re-implementation of reading the file.
69
+ */
70
+ export interface MemoryVerdict {
71
+ readonly noteId: string;
72
+ readonly verdict: "GO" | "NO-GO";
73
+ readonly leg: LegIdentity;
74
+ readonly at: number;
75
+ readonly reason?: string;
76
+ }
77
+ /**
78
+ * The orchestrator's attestation that the two legs were actually independent.
79
+ * This is the CONTENT of the attestation artifact a ceremony writes (see
80
+ * `./d11-ceremony.ts`); `PromotionEvidence.independence_attestation` carries
81
+ * only that artifact's REF (locator string), never this object inline — see
82
+ * the module doc's REF note. This client does NOT treat
83
+ * `distinctModels`/`distinctSessions` here as authoritative for its own
84
+ * refusal; it recomputes distinctness from the verdicts.
85
+ */
86
+ export interface IndependenceAttestation {
87
+ readonly leg1: LegIdentity;
88
+ readonly leg2: LegIdentity;
89
+ readonly distinctModels: boolean;
90
+ readonly distinctSessions: boolean;
91
+ readonly verdictsWrittenBeforeCrossVisibility: boolean;
92
+ readonly orchestrator: string;
93
+ }
94
+ /**
95
+ * Pack the two verdict-file references and the attestation REFERENCE into the
96
+ * port's `PromotionEvidence` shape. Pure: same inputs → same output, no I/O.
97
+ *
98
+ * `attestationRef` is a LOCATOR string, exactly like `leg1Ref`/`leg2Ref` — NOT
99
+ * the `IndependenceAttestation` object serialized inline. graphify's evidence
100
+ * holds the three refs; the attestation ARTIFACT (a file, written by whoever
101
+ * ran the ceremony — see `./d11-ceremony.ts`) holds the actual
102
+ * `{leg1,leg2,distinct*,...}` content that ref points to. Passed through
103
+ * unchanged — no `JSON.stringify` — because there is nothing to serialize
104
+ * here: the caller already resolved the ref by writing the artifact.
105
+ */
106
+ export declare function assemblePromotionEvidence(leg1Ref: string, leg2Ref: string, attestationRef: string): PromotionEvidence;
107
+ export type DoubleConsensusCheck = {
108
+ ok: true;
109
+ } | {
110
+ ok: false;
111
+ reason: string;
112
+ };
113
+ export interface DoubleConsensusInput {
114
+ readonly verdicts: readonly MemoryVerdict[];
115
+ readonly attestation: IndependenceAttestation;
116
+ readonly leg1Ref: string;
117
+ readonly leg2Ref: string;
118
+ /** The note's author (opaque id) — a leg's `session` must not equal this. */
119
+ readonly authorId: string;
120
+ }
121
+ /**
122
+ * REFUSES to let a caller proceed to `promoteNote` unless ALL hold:
123
+ * - exactly 2 verdicts;
124
+ * - BOTH verdicts are `"GO"` (any `"NO-GO"`, or a split, refuses);
125
+ * - the two verdicts reference the SAME note (a mismatch refuses — two
126
+ * verdicts for different notes cannot jointly promote either one);
127
+ * - the two legs are STRUCTURALLY distinct — computed from `verdict.leg`
128
+ * itself, not from the attestation's own booleans (not the same
129
+ * model+session counted twice);
130
+ * - `leg1Ref !== leg2Ref` (the same verdict-file reference cannot stand in
131
+ * for both legs);
132
+ * - neither leg's `session` equals `authorId` (separation of powers — a
133
+ * leg cannot review its own note).
134
+ * This function takes no port: it cannot call `promoteNote` even if it
135
+ * wanted to, so its refusal holds by construction, not by convention.
136
+ */
137
+ export declare function checkDoubleConsensusPreconditions(input: DoubleConsensusInput): DoubleConsensusCheck;
138
+ export interface PromoteNoteResult {
139
+ readonly outcome: PromotionOutcome;
140
+ /** True when refused locally (no port, unreachable port, or a precondition) — the port was never called, or its call never resolved to a success. */
141
+ readonly localOnly: boolean;
142
+ }
143
+ /**
144
+ * Dispatch `evidence` through `port.promoteNote(noteId, evidence, ctx)`.
145
+ * `port` is injected and may be `undefined`/`null` (I5: fail-closed default,
146
+ * not a wiring error — mirrors `admit-client.ts`). This function does NOT
147
+ * itself enforce the double-consensus preconditions — that is
148
+ * `checkDoubleConsensusPreconditions`'s job, run BEFORE this is called (see
149
+ * `promoteNoteWithDoubleConsensus` for the composed entry point).
150
+ */
151
+ export declare function promoteNote(noteId: string, evidence: PromotionEvidence, ctx: MemoryContext, port: MemoryProducerPort | undefined | null): Promise<PromoteNoteResult>;
152
+ export interface PromoteNoteWithDoubleConsensusInput extends DoubleConsensusInput {
153
+ readonly noteId: string;
154
+ readonly ctx: MemoryContext;
155
+ /**
156
+ * The attestation ARTIFACT's locator — distinct from `attestation` (the
157
+ * in-memory object `checkDoubleConsensusPreconditions` uses for its own
158
+ * completeness gate, unchanged by this reconciliation). This is what
159
+ * actually travels to the port via `assemblePromotionEvidence`.
160
+ */
161
+ readonly attestationRef: string;
162
+ }
163
+ /**
164
+ * The client-side D11 promotion entry point: runs
165
+ * `checkDoubleConsensusPreconditions` first, and ONLY on `{ok: true}`
166
+ * assembles the evidence (`assemblePromotionEvidence`) and dispatches
167
+ * (`promoteNote`). A local refusal short-circuits BEFORE the port is ever
168
+ * touched — the composed call, not just the pure guard in isolation, is what
169
+ * a conductor actually invokes once both legs have written their verdicts.
170
+ */
171
+ export declare function promoteNoteWithDoubleConsensus(input: PromoteNoteWithDoubleConsensusInput, port: MemoryProducerPort | undefined | null): Promise<PromoteNoteResult>;
172
+ //# sourceMappingURL=promote-client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"promote-client.d.ts","sourceRoot":"","sources":["../../../src/runtime/memory/promote-client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuDG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAM3G,yEAAyE;AACzE,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED;;;;;;GAMG;AACH,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,OAAO,EAAE,IAAI,GAAG,OAAO,CAAC;IACjC,QAAQ,CAAC,GAAG,EAAE,WAAW,CAAC;IAC1B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;IAC3B,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;IAC3B,QAAQ,CAAC,cAAc,EAAE,OAAO,CAAC;IACjC,QAAQ,CAAC,gBAAgB,EAAE,OAAO,CAAC;IACnC,QAAQ,CAAC,oCAAoC,EAAE,OAAO,CAAC;IACvD,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;CAC/B;AAMD;;;;;;;;;;;GAWG;AACH,wBAAgB,yBAAyB,CACvC,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,EACf,cAAc,EAAE,MAAM,GACrB,iBAAiB,CAMnB;AAMD,MAAM,MAAM,oBAAoB,GAAG;IAAE,EAAE,EAAE,IAAI,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAEhF,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,QAAQ,EAAE,SAAS,aAAa,EAAE,CAAC;IAC5C,QAAQ,CAAC,WAAW,EAAE,uBAAuB,CAAC;IAC9C,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,6EAA6E;IAC7E,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAUD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,iCAAiC,CAAC,KAAK,EAAE,oBAAoB,GAAG,oBAAoB,CAwCnG;AAMD,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,OAAO,EAAE,gBAAgB,CAAC;IACnC,qJAAqJ;IACrJ,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;CAC7B;AAMD;;;;;;;GAOG;AACH,wBAAsB,WAAW,CAC/B,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,iBAAiB,EAC3B,GAAG,EAAE,aAAa,EAClB,IAAI,EAAE,kBAAkB,GAAG,SAAS,GAAG,IAAI,GAC1C,OAAO,CAAC,iBAAiB,CAAC,CAY5B;AAMD,MAAM,WAAW,mCAAoC,SAAQ,oBAAoB;IAC/E,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,GAAG,EAAE,aAAa,CAAC;IAC5B;;;;;OAKG;IACH,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;CACjC;AAED;;;;;;;GAOG;AACH,wBAAsB,8BAA8B,CAClD,KAAK,EAAE,mCAAmC,EAC1C,IAAI,EAAE,kBAAkB,GAAG,SAAS,GAAG,IAAI,GAC1C,OAAO,CAAC,iBAAiB,CAAC,CAQ5B"}
@@ -0,0 +1,168 @@
1
+ /**
2
+ * Promote client — D11 double-consensus, CLIENT-SIDE orchestration (build brief
3
+ * slice 6, this build's WP11-slice-3). Two independent high-grade legs each
4
+ * write a VERDICT (third-party-readable, never self-report); this module
5
+ * enforces the double-consensus BEFORE `promoteNote` is ever called, and
6
+ * dispatches through an INJECTED `MemoryProducerPort` exactly like
7
+ * `admit-client.ts` does for admission.
8
+ *
9
+ * SCOPE (bounded): this is the client's consensus *enforcement* + evidence
10
+ * *assembly*. Launching the two model legs and interpreting/reading verdict
11
+ * FILES is out of scope here — a "leg" is an opaque `{model, session}` pair
12
+ * and a verdict ref is an opaque locator string, both supplied by the caller
13
+ * (the conductor orchestrating the legs). graphify's gate is the other half
14
+ * of this boundary: it re-checks structurally (refs + attestation shape), it
15
+ * never trusts this client's say-so either — this module's own refusal is a
16
+ * courtesy that saves a round trip, not the authority.
17
+ *
18
+ * REF, NOT INLINE: `independence_attestation` in `PromotionEvidence` is a
19
+ * LOCATOR string, exactly like `leg1_verdict_ref`/`leg2_verdict_ref` (§9.4).
20
+ * graphify's evidence holds the three refs; the attestation ARTIFACT (a file
21
+ * — see `./d11-ceremony.ts`, which writes it) holds the actual
22
+ * `IndependenceAttestation` content that ref points to. This module never
23
+ * serializes the attestation object itself into the evidence — the caller
24
+ * writes the artifact and hands `assemblePromotionEvidence` the ref it got
25
+ * back.
26
+ *
27
+ * I5 — fail-closed, TWO LAYERS:
28
+ * 1. `checkDoubleConsensusPreconditions` is a PURE, port-less function. It
29
+ * cannot call the port even if it wanted to — a refusal here makes
30
+ * "promoteNote never called" true BY CONSTRUCTION, not by a runtime
31
+ * guard that could be bypassed or forgotten.
32
+ * 2. `promoteNote` (the raw dispatch) mirrors `admit-client.ts`: an absent
33
+ * port, or one that throws/rejects, REFUSES — never a silent
34
+ * `promoted: true` a caller might mistake for success.
35
+ * `promoteNoteWithDoubleConsensus` composes both layers for a caller that
36
+ * wants one call: check → assemble → dispatch, short-circuiting before the
37
+ * port is ever touched on any local refusal.
38
+ *
39
+ * STRUCTURAL independence, not merely attested: the guard computes leg
40
+ * distinctness and the author/session collision from the VERDICTS'
41
+ * own `leg` field, never from `attestation.distinctModels` /
42
+ * `attestation.distinctSessions` — those booleans are a self-report from the
43
+ * orchestrator and reach graphify only by reference (the attestation
44
+ * ARTIFACT, not this in-memory object — see the REF note above), but this
45
+ * client does not treat them as authoritative for its own local refusal. A
46
+ * lying attestation cannot paper over two identical verdict legs.
47
+ *
48
+ * I1 — durable identity slot: `leg.model`, `leg.session`, `authorId` and
49
+ * `noteId` are all OPAQUE strings here — compared with `===` only, never
50
+ * parsed, split or derived-from. This module reserves the slot; it does not
51
+ * mint or interpret conversation-scoped identity.
52
+ * I4 — no new capabilities vocabulary opens here; `MemoryVerdict` and
53
+ * `IndependenceAttestation` are D11-specific data shapes, not a second
54
+ * capabilities taxonomy, and `PromotionEvidence`/`PromotionOutcome` are
55
+ * reused unchanged from `./port-v1.ts`.
56
+ */
57
+ // ---------------------------------------------------------------------------
58
+ // assemblePromotionEvidence — pure, packs refs + attestation into the port's shape.
59
+ // ---------------------------------------------------------------------------
60
+ /**
61
+ * Pack the two verdict-file references and the attestation REFERENCE into the
62
+ * port's `PromotionEvidence` shape. Pure: same inputs → same output, no I/O.
63
+ *
64
+ * `attestationRef` is a LOCATOR string, exactly like `leg1Ref`/`leg2Ref` — NOT
65
+ * the `IndependenceAttestation` object serialized inline. graphify's evidence
66
+ * holds the three refs; the attestation ARTIFACT (a file, written by whoever
67
+ * ran the ceremony — see `./d11-ceremony.ts`) holds the actual
68
+ * `{leg1,leg2,distinct*,...}` content that ref points to. Passed through
69
+ * unchanged — no `JSON.stringify` — because there is nothing to serialize
70
+ * here: the caller already resolved the ref by writing the artifact.
71
+ */
72
+ export function assemblePromotionEvidence(leg1Ref, leg2Ref, attestationRef) {
73
+ return {
74
+ leg1_verdict_ref: leg1Ref,
75
+ leg2_verdict_ref: leg2Ref,
76
+ independence_attestation: attestationRef
77
+ };
78
+ }
79
+ function refuseCheck(reason) {
80
+ return { ok: false, reason };
81
+ }
82
+ function sameLeg(a, b) {
83
+ return a.model === b.model && a.session === b.session;
84
+ }
85
+ /**
86
+ * REFUSES to let a caller proceed to `promoteNote` unless ALL hold:
87
+ * - exactly 2 verdicts;
88
+ * - BOTH verdicts are `"GO"` (any `"NO-GO"`, or a split, refuses);
89
+ * - the two verdicts reference the SAME note (a mismatch refuses — two
90
+ * verdicts for different notes cannot jointly promote either one);
91
+ * - the two legs are STRUCTURALLY distinct — computed from `verdict.leg`
92
+ * itself, not from the attestation's own booleans (not the same
93
+ * model+session counted twice);
94
+ * - `leg1Ref !== leg2Ref` (the same verdict-file reference cannot stand in
95
+ * for both legs);
96
+ * - neither leg's `session` equals `authorId` (separation of powers — a
97
+ * leg cannot review its own note).
98
+ * This function takes no port: it cannot call `promoteNote` even if it
99
+ * wanted to, so its refusal holds by construction, not by convention.
100
+ */
101
+ export function checkDoubleConsensusPreconditions(input) {
102
+ const { verdicts, attestation, leg1Ref, leg2Ref, authorId } = input;
103
+ if (!attestation) {
104
+ return refuseCheck("an independence attestation is required");
105
+ }
106
+ if (!Array.isArray(verdicts) || verdicts.length !== 2) {
107
+ const got = Array.isArray(verdicts) ? String(verdicts.length) : "a non-array";
108
+ return refuseCheck(`double consensus requires exactly 2 verdicts, got ${got}`);
109
+ }
110
+ const [v1, v2] = verdicts;
111
+ if (v1.verdict !== "GO" || v2.verdict !== "GO") {
112
+ return refuseCheck("double consensus requires BOTH legs to verdict GO — a NO-GO or a split refuses locally");
113
+ }
114
+ if (v1.noteId !== v2.noteId) {
115
+ return refuseCheck("the two verdicts reference different notes — refusing to conflate them");
116
+ }
117
+ if (sameLeg(v1.leg, v2.leg)) {
118
+ return refuseCheck("the two legs are not independent — the same model+session was counted twice (same leg twice)");
119
+ }
120
+ if (leg1Ref === leg2Ref) {
121
+ return refuseCheck("leg1Ref and leg2Ref are identical — refusing to accept one verdict reference twice");
122
+ }
123
+ if (v1.leg.session === authorId || v2.leg.session === authorId) {
124
+ return refuseCheck("a promoting leg's session equals the note's author — separation of powers requires an independent reviewer");
125
+ }
126
+ return { ok: true };
127
+ }
128
+ function refuseResult(reason) {
129
+ return { outcome: { promoted: false, reason }, localOnly: true };
130
+ }
131
+ /**
132
+ * Dispatch `evidence` through `port.promoteNote(noteId, evidence, ctx)`.
133
+ * `port` is injected and may be `undefined`/`null` (I5: fail-closed default,
134
+ * not a wiring error — mirrors `admit-client.ts`). This function does NOT
135
+ * itself enforce the double-consensus preconditions — that is
136
+ * `checkDoubleConsensusPreconditions`'s job, run BEFORE this is called (see
137
+ * `promoteNoteWithDoubleConsensus` for the composed entry point).
138
+ */
139
+ export async function promoteNote(noteId, evidence, ctx, port) {
140
+ if (!port) {
141
+ return refuseResult("no memory producer port injected — refusing (fail-closed, I5)");
142
+ }
143
+ try {
144
+ const outcome = await port.promoteNote(noteId, evidence, ctx);
145
+ return { outcome, localOnly: false };
146
+ }
147
+ catch (err) {
148
+ const reason = err instanceof Error ? err.message : String(err);
149
+ return refuseResult(`memory producer port unreachable: ${reason}`);
150
+ }
151
+ }
152
+ /**
153
+ * The client-side D11 promotion entry point: runs
154
+ * `checkDoubleConsensusPreconditions` first, and ONLY on `{ok: true}`
155
+ * assembles the evidence (`assemblePromotionEvidence`) and dispatches
156
+ * (`promoteNote`). A local refusal short-circuits BEFORE the port is ever
157
+ * touched — the composed call, not just the pure guard in isolation, is what
158
+ * a conductor actually invokes once both legs have written their verdicts.
159
+ */
160
+ export async function promoteNoteWithDoubleConsensus(input, port) {
161
+ const check = checkDoubleConsensusPreconditions(input);
162
+ if (!check.ok) {
163
+ return refuseResult(`double-consensus preconditions not met: ${check.reason}`);
164
+ }
165
+ const evidence = assemblePromotionEvidence(input.leg1Ref, input.leg2Ref, input.attestationRef);
166
+ return promoteNote(input.noteId, evidence, input.ctx, port);
167
+ }
168
+ //# sourceMappingURL=promote-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"promote-client.js","sourceRoot":"","sources":["../../../src/runtime/memory/promote-client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,74 @@
1
+ /**
2
+ * Recall client — WP11 slice 5 (build brief), read-side (wake-recall). Consumes
3
+ * an INJECTED `MemoryRecallPort` and returns the notes for the wake path. This
4
+ * slice stubs the port in tests; it never wires to real storage/graphify and is
5
+ * NOT wired into the actual wake/CLI path — the real recall factory awaits
6
+ * graphify's storage-laying Vague B (out of scope here, same boundary as
7
+ * `admit-client.ts`'s producer side).
8
+ *
9
+ * READ-SIDE GUARANTEES ENFORCED HERE, AS A CONSUMER (not just assumed from the
10
+ * port's types — the port is an external boundary, so this module re-checks the
11
+ * shape of what it gets back):
12
+ * - `projection: "notes-only"` — this module exposes the notes as a FLAT LIST
13
+ * and offers no helper that aggregates `subject: "human:<id>"` notes into a
14
+ * profile. `groupAgentWorkNotesBySubject` below is the ONE grouping helper
15
+ * this module offers, and it EXCLUDES human-subject notes from the grouping
16
+ * by construction (counts them, never groups them) — so a UserModel cannot
17
+ * be assembled by composing this consumer's exports. A port that returns a
18
+ * different projection value is refused locally too: a misbehaving or
19
+ * incorrectly-stubbed port must not silently smuggle a different shape past
20
+ * the consumer boundary (the projection prohibition, §3.3.3, holds even if
21
+ * the far side does not enforce it correctly).
22
+ * - `freshness` and each note's `trust`/`review_status`/`provenance` are
23
+ * passed through VERBATIM — never stripped, never re-labeled as verified.
24
+ * - I5 fail-closed: an absent port, or one that throws/rejects, REFUSES —
25
+ * never a silent `notes: []` that reads as "no memories exist". A refusal
26
+ * is a structurally distinct shape (`refused: true` + `reason`, `notes: []`)
27
+ * from a genuine empty recall (`refused: false, notes: []`), so a caller
28
+ * cannot conflate "asked and got nothing" with "could not ask".
29
+ * - I1: `ctx.principal_owner` travels through opaque and unexamined — this
30
+ * module never derives, parses or keys on it (same reservation as
31
+ * `note-builder.ts`).
32
+ * - I4: no new capabilities/taxonomy vocabulary opens here — the
33
+ * human-subject predicate is REUSED from `note-builder.ts`
34
+ * (`isHumanMemorySubject`), never redefined.
35
+ */
36
+ import type { MemoryContext, MemoryRecallPort, MemoryRecallQuery, MemoryRecallResultView, RecalledMemoryNoteView } from "./port-v1.js";
37
+ export interface RecallMemorySuccess {
38
+ readonly refused: false;
39
+ readonly notes: readonly RecalledMemoryNoteView[];
40
+ readonly freshness: MemoryRecallResultView["freshness"];
41
+ readonly projection: MemoryRecallResultView["projection"];
42
+ readonly requestingPrincipal: string;
43
+ readonly unpaged: true;
44
+ }
45
+ export interface RecallMemoryRefusal {
46
+ readonly refused: true;
47
+ readonly reason: string;
48
+ /** Always empty on a refusal — never conflate with a genuine empty recall. */
49
+ readonly notes: readonly [];
50
+ }
51
+ export type RecallMemoryOutcome = RecallMemorySuccess | RecallMemoryRefusal;
52
+ /**
53
+ * Dispatch `query` through `port.recallMemory(query, ctx)` for the wake path.
54
+ * `port` is injected and may be `undefined`/`null` (I5: fail-closed default,
55
+ * not a wiring error — the real recall factory does not exist yet).
56
+ */
57
+ export declare function recallMemory(query: MemoryRecallQuery, ctx: MemoryContext, port: MemoryRecallPort | undefined | null): Promise<RecallMemoryOutcome>;
58
+ export interface NotesGroupedBySubject {
59
+ /** Grouped ONLY for non-human subjects (e.g. `"agent-work"`). */
60
+ readonly grouped: Readonly<Record<string, readonly RecalledMemoryNoteView[]>>;
61
+ /** Count of human-subject notes excluded from the grouping — never aggregated. */
62
+ readonly excludedHumanSubjectCount: number;
63
+ }
64
+ /**
65
+ * The ONE grouping/summary helper this consumer offers, and it deliberately
66
+ * cannot be used to assemble a human-subject profile: any `human:<id>`
67
+ * subject note is EXCLUDED from the grouping (counted, never aggregated).
68
+ * Only non-human subjects (e.g. `"agent-work"`) are grouped. This mirrors the
69
+ * projection prohibition (§3.3.3) at the consumer boundary, so the
70
+ * prohibition holds even if a caller composes only this module's own exports
71
+ * — there is no way to reach a `Record<humanSubject, notes[]>` through it.
72
+ */
73
+ export declare function groupAgentWorkNotesBySubject(notes: readonly RecalledMemoryNoteView[]): NotesGroupedBySubject;
74
+ //# sourceMappingURL=recall-client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"recall-client.d.ts","sourceRoot":"","sources":["../../../src/runtime/memory/recall-client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAGH,OAAO,KAAK,EACV,aAAa,EACb,gBAAgB,EAChB,iBAAiB,EACjB,sBAAsB,EACtB,sBAAsB,EACvB,MAAM,cAAc,CAAC;AAEtB,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,OAAO,EAAE,KAAK,CAAC;IACxB,QAAQ,CAAC,KAAK,EAAE,SAAS,sBAAsB,EAAE,CAAC;IAClD,QAAQ,CAAC,SAAS,EAAE,sBAAsB,CAAC,WAAW,CAAC,CAAC;IACxD,QAAQ,CAAC,UAAU,EAAE,sBAAsB,CAAC,YAAY,CAAC,CAAC;IAC1D,QAAQ,CAAC,mBAAmB,EAAE,MAAM,CAAC;IACrC,QAAQ,CAAC,OAAO,EAAE,IAAI,CAAC;CACxB;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,OAAO,EAAE,IAAI,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,8EAA8E;IAC9E,QAAQ,CAAC,KAAK,EAAE,SAAS,EAAE,CAAC;CAC7B;AAED,MAAM,MAAM,mBAAmB,GAAG,mBAAmB,GAAG,mBAAmB,CAAC;AAM5E;;;;GAIG;AACH,wBAAsB,YAAY,CAChC,KAAK,EAAE,iBAAiB,EACxB,GAAG,EAAE,aAAa,EAClB,IAAI,EAAE,gBAAgB,GAAG,SAAS,GAAG,IAAI,GACxC,OAAO,CAAC,mBAAmB,CAAC,CA2B9B;AAED,MAAM,WAAW,qBAAqB;IACpC,iEAAiE;IACjE,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,sBAAsB,EAAE,CAAC,CAAC,CAAC;IAC9E,kFAAkF;IAClF,QAAQ,CAAC,yBAAyB,EAAE,MAAM,CAAC;CAC5C;AAED;;;;;;;;GAQG;AACH,wBAAgB,4BAA4B,CAC1C,KAAK,EAAE,SAAS,sBAAsB,EAAE,GACvC,qBAAqB,CAcvB"}
@@ -0,0 +1,91 @@
1
+ /**
2
+ * Recall client — WP11 slice 5 (build brief), read-side (wake-recall). Consumes
3
+ * an INJECTED `MemoryRecallPort` and returns the notes for the wake path. This
4
+ * slice stubs the port in tests; it never wires to real storage/graphify and is
5
+ * NOT wired into the actual wake/CLI path — the real recall factory awaits
6
+ * graphify's storage-laying Vague B (out of scope here, same boundary as
7
+ * `admit-client.ts`'s producer side).
8
+ *
9
+ * READ-SIDE GUARANTEES ENFORCED HERE, AS A CONSUMER (not just assumed from the
10
+ * port's types — the port is an external boundary, so this module re-checks the
11
+ * shape of what it gets back):
12
+ * - `projection: "notes-only"` — this module exposes the notes as a FLAT LIST
13
+ * and offers no helper that aggregates `subject: "human:<id>"` notes into a
14
+ * profile. `groupAgentWorkNotesBySubject` below is the ONE grouping helper
15
+ * this module offers, and it EXCLUDES human-subject notes from the grouping
16
+ * by construction (counts them, never groups them) — so a UserModel cannot
17
+ * be assembled by composing this consumer's exports. A port that returns a
18
+ * different projection value is refused locally too: a misbehaving or
19
+ * incorrectly-stubbed port must not silently smuggle a different shape past
20
+ * the consumer boundary (the projection prohibition, §3.3.3, holds even if
21
+ * the far side does not enforce it correctly).
22
+ * - `freshness` and each note's `trust`/`review_status`/`provenance` are
23
+ * passed through VERBATIM — never stripped, never re-labeled as verified.
24
+ * - I5 fail-closed: an absent port, or one that throws/rejects, REFUSES —
25
+ * never a silent `notes: []` that reads as "no memories exist". A refusal
26
+ * is a structurally distinct shape (`refused: true` + `reason`, `notes: []`)
27
+ * from a genuine empty recall (`refused: false, notes: []`), so a caller
28
+ * cannot conflate "asked and got nothing" with "could not ask".
29
+ * - I1: `ctx.principal_owner` travels through opaque and unexamined — this
30
+ * module never derives, parses or keys on it (same reservation as
31
+ * `note-builder.ts`).
32
+ * - I4: no new capabilities/taxonomy vocabulary opens here — the
33
+ * human-subject predicate is REUSED from `note-builder.ts`
34
+ * (`isHumanMemorySubject`), never redefined.
35
+ */
36
+ import { isHumanMemorySubject } from "./note-builder.js";
37
+ function refuse(reason) {
38
+ return { refused: true, reason, notes: [] };
39
+ }
40
+ /**
41
+ * Dispatch `query` through `port.recallMemory(query, ctx)` for the wake path.
42
+ * `port` is injected and may be `undefined`/`null` (I5: fail-closed default,
43
+ * not a wiring error — the real recall factory does not exist yet).
44
+ */
45
+ export async function recallMemory(query, ctx, port) {
46
+ if (!port) {
47
+ return refuse("no memory recall port injected — refusing (fail-closed, I5)");
48
+ }
49
+ let result;
50
+ try {
51
+ result = await port.recallMemory(query, ctx);
52
+ }
53
+ catch (err) {
54
+ const reason = err instanceof Error ? err.message : String(err);
55
+ return refuse(`memory recall port unreachable: ${reason}`);
56
+ }
57
+ if (result.projection !== "notes-only") {
58
+ return refuse(`memory recall port returned projection "${String(result.projection)}", expected "notes-only" — refusing rather than trusting an unverified shape`);
59
+ }
60
+ return {
61
+ refused: false,
62
+ notes: result.notes,
63
+ freshness: result.freshness,
64
+ projection: result.projection,
65
+ requestingPrincipal: result.requestingPrincipal,
66
+ unpaged: result.unpaged
67
+ };
68
+ }
69
+ /**
70
+ * The ONE grouping/summary helper this consumer offers, and it deliberately
71
+ * cannot be used to assemble a human-subject profile: any `human:<id>`
72
+ * subject note is EXCLUDED from the grouping (counted, never aggregated).
73
+ * Only non-human subjects (e.g. `"agent-work"`) are grouped. This mirrors the
74
+ * projection prohibition (§3.3.3) at the consumer boundary, so the
75
+ * prohibition holds even if a caller composes only this module's own exports
76
+ * — there is no way to reach a `Record<humanSubject, notes[]>` through it.
77
+ */
78
+ export function groupAgentWorkNotesBySubject(notes) {
79
+ const grouped = {};
80
+ let excludedHumanSubjectCount = 0;
81
+ for (const note of notes) {
82
+ if (isHumanMemorySubject(note.subject)) {
83
+ excludedHumanSubjectCount += 1;
84
+ continue;
85
+ }
86
+ const bucket = grouped[note.subject] ?? (grouped[note.subject] = []);
87
+ bucket.push(note);
88
+ }
89
+ return { grouped, excludedHumanSubjectCount };
90
+ }
91
+ //# sourceMappingURL=recall-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"recall-client.js","sourceRoot":"","sources":["../../../src/runtime/memory/recall-client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAEH,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AA2BzD,SAAS,MAAM,CAAC,MAAc;IAC5B,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC;AAC9C,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,KAAwB,EACxB,GAAkB,EAClB,IAAyC;IAEzC,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,OAAO,MAAM,CAAC,6DAA6D,CAAC,CAAC;IAC/E,CAAC;IAED,IAAI,MAA8B,CAAC;IACnC,IAAI,CAAC;QACH,MAAM,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;IAC/C,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,MAAM,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAChE,OAAO,MAAM,CAAC,mCAAmC,MAAM,EAAE,CAAC,CAAC;IAC7D,CAAC;IAED,IAAI,MAAM,CAAC,UAAU,KAAK,YAAY,EAAE,CAAC;QACvC,OAAO,MAAM,CACX,2CAA2C,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,8EAA8E,CACnJ,CAAC;IACJ,CAAC;IAED,OAAO;QACL,OAAO,EAAE,KAAK;QACd,KAAK,EAAE,MAAM,CAAC,KAAK;QACnB,SAAS,EAAE,MAAM,CAAC,SAAS;QAC3B,UAAU,EAAE,MAAM,CAAC,UAAU;QAC7B,mBAAmB,EAAE,MAAM,CAAC,mBAAmB;QAC/C,OAAO,EAAE,MAAM,CAAC,OAAO;KACxB,CAAC;AACJ,CAAC;AASD;;;;;;;;GAQG;AACH,MAAM,UAAU,4BAA4B,CAC1C,KAAwC;IAExC,MAAM,OAAO,GAA6C,EAAE,CAAC;IAC7D,IAAI,yBAAyB,GAAG,CAAC,CAAC;IAElC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,oBAAoB,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;YACvC,yBAAyB,IAAI,CAAC,CAAC;YAC/B,SAAS;QACX,CAAC;QACD,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;QACrE,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACpB,CAAC;IAED,OAAO,EAAE,OAAO,EAAE,yBAAyB,EAAE,CAAC;AAChD,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sentropic/h2a",
3
- "version": "0.96.1",
3
+ "version": "0.96.2",
4
4
  "description": "h2a — the unified CLI + core for human-to-agent coordination.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -52,6 +52,9 @@
52
52
  "@hono/mcp": "^0.3.0",
53
53
  "@hono/node-server": "^2.0.12",
54
54
  "@modelcontextprotocol/sdk": "^1.30.0",
55
+ "@sentropic/cluster-mesh": "0.9.0",
56
+ "@sentropic/contracts": "^0.3.0",
57
+ "@sentropic/events": "^0.2.0",
55
58
  "@sentropic/track": "^0.96.1",
56
59
  "hono": "^4.12.32"
57
60
  },
@@ -8,7 +8,7 @@ description: Translate a friendly launch intent ("terra 5.6 xhigh", "codex sol h
8
8
  ## When to use this
9
9
 
10
10
  - The user names a launch by nickname + effort ("terra 5.6 xhigh", "sol en max", "relance codex en xhigh") instead of a provider model id.
11
- - The user wants a background or interactive Claude/Codex session with a specific reasoning effort, with or without the llm-mesh gateway, and needs the exact CLI flags or MCP parameters.
11
+ - The user wants a background or interactive Claude/Codex/AGY session with a specific reasoning effort, with or without the llm-mesh gateway, and needs the exact CLI flags or MCP parameters.
12
12
  - **Not** for deciding *which* flavor is best for a task (that is a human/model-delegation call, not this skill's job), and **not** for resolving alias→upstream-provider routing — that table is owned by the llm-mesh gateway, not this skill (see Step 2).
13
13
 
14
14
  ## Hard rule: never call the raw `h2a` binary from Bash
@@ -19,9 +19,9 @@ This plugin's PreToolUse hook (`packages/h2a/hooks/deny-manual-h2a-cli.mjs`) blo
19
19
 
20
20
  None of these require knowing a provider model id up front:
21
21
 
22
- 1. **Profile** — `claude` or `codex` (which CLI to launch). Default to whichever CLI the user is already in if unstated; ask if genuinely ambiguous.
22
+ 1. **Profile** — `claude`, `codex`, or `agy` (which CLI to launch). Default to whichever CLI the user is already in if unstated; ask if genuinely ambiguous.
23
23
  2. **Model flavor** — a nickname like *terra*, *sol* (aka *fable*), *luna*, or unstated (→ the CLI's own default model). Resolves to a `--model` / `model` value (Step 2).
24
- 3. **Effort** — `low | medium | high | xhigh`. "max" said by the user means `xhigh` — there is no higher tier for `h2a run` / `h2a_run` today.
24
+ 3. **Effort** — `low | medium | high | xhigh`. For Claude/Codex, "max" means `xhigh`; AGY accepts only `low | medium | high` and rejects both `xhigh` and "max".
25
25
 
26
26
  ## Step 2 — resolve the model flavor (source-of-truth caveat)
27
27
 
@@ -39,11 +39,13 @@ Any non-default flavor needs the llm-mesh gateway to translate the Anthropic-sha
39
39
  - CLI: `--gw` (alias `--llm-gateway`) forces it on, `--no-gw` (alias `--no-llm-gateway`) forces it off, omit for the CLI's own default.
40
40
  - MCP `h2a_run`: `gateway: "required"` forces it on, `"off"` forces it off, `"auto"` (default) decides. **`"required"` is rejected when `profile` is `"codex"`** — codex already talks to llm-mesh over an Anthropic-compatible surface, use `"auto"` there.
41
41
 
42
+ AGY is the exception to the named-flavor rule: it talks to its provider directly. Use `gateway: "off"` for `profile: "agy"`; `"required"` is rejected. AGY accepts effort `low|medium|high`, not `xhigh`, and supports run-once mode through its verified `--print` stdin contract. Resolve the exact AGY model with `agy models`; for example, the displayed "Gemini 3.7 Flash (High)" id is `gemini-3.7-flash-high`.
43
+
42
44
  ## Step 4 — compose the call
43
45
 
44
46
  ### `h2a_run` MCP tool (what this agent must use)
45
47
 
46
- Required: `profile` (`"claude"|"codex"`), `name` (`^[A-Za-z0-9_-]{1,64}$`), `workspace` (absolute path, must exist, must stay inside the MCP server's startup workspace root), `prompt` (1–65536 UTF-8 bytes, sent on stdin — never put it in argv), `background` (must be literal `true`). Optional: `model` (free-text, format-checked only — see Step 2 for the value), `effort` (`"low"|"medium"|"high"|"xhigh"`), `gateway` (`"auto"|"required"|"off"`, default `"auto"`), `headless` (default `false`), `h2aSidecar` (default `!headless`; cannot be `true` together with `headless: true`).
48
+ Required: `profile` (`"claude"|"codex"|"agy"`), `name` (`^[A-Za-z0-9_-]{1,64}$`), `workspace` (absolute path, must exist, must stay inside the MCP server's startup workspace root), `prompt` (1–65536 UTF-8 bytes, sent on stdin — never put it in argv), `background` (must be literal `true`). Optional: `agent` (AGY only; for example `"stp"`), `model` (free-text, format-checked only — see Step 2 for the value), `effort` (`"low"|"medium"|"high"|"xhigh"`; AGY rejects `xhigh`), `gateway` (`"auto"|"required"|"off"`, default `"auto"`; AGY uses `"off"`), `headless` (default `false`; AGY maps `true` to `--print`), `h2aSidecar` (default `!headless`; cannot be `true` together with `headless: true`).
47
49
 
48
50
  Example — "terra, xhigh, headless, on this repo":
49
51
 
@@ -63,6 +65,24 @@ Example — "terra, xhigh, headless, on this repo":
63
65
 
64
66
  The tool returns an `h2a.run.result` contract with `session.tmuxSession`, `session.pane`, `session.gateway` (`"gateway"|"direct"`). Read those fields back to confirm what actually launched — do not assume the request was honored silently.
65
67
 
68
+ Example — direct AGY run-once:
69
+
70
+ ```json
71
+ {
72
+ "profile": "agy",
73
+ "name": "gemini-review",
74
+ "workspace": "/abs/path/to/repo",
75
+ "prompt": "<initial instructions>",
76
+ "background": true,
77
+ "agent": "stp",
78
+ "model": "gemini-3.7-flash-high",
79
+ "effort": "high",
80
+ "gateway": "off",
81
+ "headless": true,
82
+ "h2aSidecar": false
83
+ }
84
+ ```
85
+
66
86
  ### `h2a run` CLI (reference only — non-Claude-Code hosts / humans at a terminal)
67
87
 
68
88
  ```
@@ -75,10 +95,23 @@ Interactive/attached form (drop the background-launch flags, add nothing else):
75
95
  h2a run claude . --model gpt-5.6-terra --effort xhigh --gw --name terra-review
76
96
  ```
77
97
 
98
+ Direct AGY run-once form (prompt delivered on stdin):
99
+
100
+ ```
101
+ h2a run agy . --agent stp --model gemini-3.7-flash-high --effort high --no-gw --name gemini-review --no-attach --background --json --headless --no-h2a --prompt-stdin
102
+ ```
103
+
104
+ Interactive AGY keeps the TUI and accepts the same prompt-over-stdin contract; resume uses AGY's native `--conversation` argv through h2a's `-r/--resume` option:
105
+
106
+ ```
107
+ h2a run agy . --agent stp --model gemini-3.7-flash-high --effort high --no-gw --name gemini-review --prompt-stdin
108
+ h2a run agy . -r <conversation-id> --agent stp --model gemini-3.7-flash-high --effort high --no-gw --name gemini-review
109
+ ```
110
+
78
111
  Other `h2a run` flags worth knowing:
79
112
 
80
- - `-r, --resume <convId>` — continue a conversation; combine with `--model`/`--effort` to relaunch the same conversation at a different flavor/effort.
81
- - `--headless` — run once, record output under `.h2a/runs/<name>`, then exit (cannot combine with `--h2a`).
113
+ - `-r, --resume <convId>` — continue a conversation; combine with `--model`/`--effort` to relaunch the same conversation at a different flavor/effort (AGY maps this to `--conversation <convId>`).
114
+ - `--headless` — run once, record output under `.h2a/runs/<name>`, then exit (cannot combine with `--h2a`; AGY uses `--input-format stream-json --output-format stream-json`, with one escaped `user` event on stdin).
82
115
  - `--count <n>` — fan out N fresh sessions; incompatible with `--model`/`--effort`/`--resume`/any structured launch (each fanned session is a fresh conversation).
83
116
  - `--h2a` / `--no-h2a` — start (or skip) the side-window h2a MCP server; defaults on unless `--headless`.
84
117
  - `--name <label>` — tmux slug + tab label; defaults to the workspace dirname. Pick one deliberately when launching more than one session against the same repo.