@calliopelabs/cli 3.5.4 → 3.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (291) hide show
  1. package/README.md +8 -0
  2. package/dist/acp.d.ts +10 -3
  3. package/dist/acp.d.ts.map +1 -1
  4. package/dist/acp.js +27 -7
  5. package/dist/acp.js.map +1 -1
  6. package/dist/bin.d.ts.map +1 -1
  7. package/dist/bin.js +28 -8
  8. package/dist/bin.js.map +1 -1
  9. package/dist/execution/authority.d.ts +4 -1
  10. package/dist/execution/authority.d.ts.map +1 -1
  11. package/dist/execution/authority.js +23 -7
  12. package/dist/execution/authority.js.map +1 -1
  13. package/dist/execution/child-grants.d.ts +2 -0
  14. package/dist/execution/child-grants.d.ts.map +1 -1
  15. package/dist/execution/child-grants.js +19 -4
  16. package/dist/execution/child-grants.js.map +1 -1
  17. package/dist/execution/delegated.d.ts +14 -0
  18. package/dist/execution/delegated.d.ts.map +1 -0
  19. package/dist/execution/delegated.js +66 -0
  20. package/dist/execution/delegated.js.map +1 -0
  21. package/dist/execution/files.js +6 -6
  22. package/dist/execution/files.js.map +1 -1
  23. package/dist/execution/guard.d.ts +5 -0
  24. package/dist/execution/guard.d.ts.map +1 -1
  25. package/dist/execution/guard.js +31 -16
  26. package/dist/execution/guard.js.map +1 -1
  27. package/dist/execution/index.d.ts +4 -0
  28. package/dist/execution/index.d.ts.map +1 -1
  29. package/dist/execution/index.js +4 -0
  30. package/dist/execution/index.js.map +1 -1
  31. package/dist/execution/ledger-cli.d.ts +2 -1
  32. package/dist/execution/ledger-cli.d.ts.map +1 -1
  33. package/dist/execution/ledger-cli.js +51 -14
  34. package/dist/execution/ledger-cli.js.map +1 -1
  35. package/dist/execution/ledger-protocol.d.ts +6 -2
  36. package/dist/execution/ledger-protocol.d.ts.map +1 -1
  37. package/dist/execution/ledger-protocol.js +110 -24
  38. package/dist/execution/ledger-protocol.js.map +1 -1
  39. package/dist/execution/ledger-server.d.ts +13 -0
  40. package/dist/execution/ledger-server.d.ts.map +1 -1
  41. package/dist/execution/ledger-server.js +57 -13
  42. package/dist/execution/ledger-server.js.map +1 -1
  43. package/dist/execution/ledger-tunnel.d.ts +50 -0
  44. package/dist/execution/ledger-tunnel.d.ts.map +1 -0
  45. package/dist/execution/ledger-tunnel.js +307 -0
  46. package/dist/execution/ledger-tunnel.js.map +1 -0
  47. package/dist/execution/ledger.d.ts +4 -0
  48. package/dist/execution/ledger.d.ts.map +1 -1
  49. package/dist/execution/ledger.js +30 -4
  50. package/dist/execution/ledger.js.map +1 -1
  51. package/dist/execution/parent-accounting.d.ts +41 -0
  52. package/dist/execution/parent-accounting.d.ts.map +1 -0
  53. package/dist/execution/parent-accounting.js +52 -0
  54. package/dist/execution/parent-accounting.js.map +1 -0
  55. package/dist/execution/parent-budget.d.ts +25 -0
  56. package/dist/execution/parent-budget.d.ts.map +1 -0
  57. package/dist/execution/parent-budget.js +102 -0
  58. package/dist/execution/parent-budget.js.map +1 -0
  59. package/dist/execution/project-spend.d.ts.map +1 -1
  60. package/dist/execution/project-spend.js +35 -5
  61. package/dist/execution/project-spend.js.map +1 -1
  62. package/dist/execution/remote-checkpoint.d.ts +15 -0
  63. package/dist/execution/remote-checkpoint.d.ts.map +1 -0
  64. package/dist/execution/remote-checkpoint.js +165 -0
  65. package/dist/execution/remote-checkpoint.js.map +1 -0
  66. package/dist/execution/remote-ledger.d.ts +12 -2
  67. package/dist/execution/remote-ledger.d.ts.map +1 -1
  68. package/dist/execution/remote-ledger.js +53 -21
  69. package/dist/execution/remote-ledger.js.map +1 -1
  70. package/dist/execution/types.d.ts +23 -5
  71. package/dist/execution/types.d.ts.map +1 -1
  72. package/dist/execution/types.js.map +1 -1
  73. package/dist/goals/supervised.js +2 -2
  74. package/dist/goals/supervised.js.map +1 -1
  75. package/dist/headless.d.ts +2 -6
  76. package/dist/headless.d.ts.map +1 -1
  77. package/dist/headless.js +17 -21
  78. package/dist/headless.js.map +1 -1
  79. package/dist/improvement/actions.d.ts +3 -4
  80. package/dist/improvement/actions.d.ts.map +1 -1
  81. package/dist/improvement/actions.js +10 -7
  82. package/dist/improvement/actions.js.map +1 -1
  83. package/dist/improvement/capabilities.d.ts +54 -0
  84. package/dist/improvement/capabilities.d.ts.map +1 -0
  85. package/dist/improvement/capabilities.js +44 -0
  86. package/dist/improvement/capabilities.js.map +1 -0
  87. package/dist/improvement/cli.d.ts +1 -1
  88. package/dist/improvement/cli.d.ts.map +1 -1
  89. package/dist/improvement/cli.js +14 -2
  90. package/dist/improvement/cli.js.map +1 -1
  91. package/dist/improvement/index.d.ts +5 -0
  92. package/dist/improvement/index.d.ts.map +1 -1
  93. package/dist/improvement/index.js +5 -0
  94. package/dist/improvement/index.js.map +1 -1
  95. package/dist/improvement/proposal-hash.d.ts +3 -0
  96. package/dist/improvement/proposal-hash.d.ts.map +1 -0
  97. package/dist/improvement/proposal-hash.js +5 -0
  98. package/dist/improvement/proposal-hash.js.map +1 -0
  99. package/dist/improvement/review-contract.d.ts +32 -0
  100. package/dist/improvement/review-contract.d.ts.map +1 -0
  101. package/dist/improvement/review-contract.js +62 -0
  102. package/dist/improvement/review-contract.js.map +1 -0
  103. package/dist/improvement/review-requests.d.ts +72 -0
  104. package/dist/improvement/review-requests.d.ts.map +1 -0
  105. package/dist/improvement/review-requests.js +63 -0
  106. package/dist/improvement/review-requests.js.map +1 -0
  107. package/dist/improvement/source-changes.d.ts +78 -0
  108. package/dist/improvement/source-changes.d.ts.map +1 -0
  109. package/dist/improvement/source-changes.js +91 -0
  110. package/dist/improvement/source-changes.js.map +1 -0
  111. package/dist/improvement/task-outcomes.d.ts +82 -0
  112. package/dist/improvement/task-outcomes.d.ts.map +1 -0
  113. package/dist/improvement/task-outcomes.js +72 -0
  114. package/dist/improvement/task-outcomes.js.map +1 -0
  115. package/dist/index.d.ts +10 -0
  116. package/dist/index.d.ts.map +1 -1
  117. package/dist/index.js +6 -0
  118. package/dist/index.js.map +1 -1
  119. package/dist/isolation/contracts.d.ts +13 -0
  120. package/dist/isolation/contracts.d.ts.map +1 -1
  121. package/dist/isolation/contracts.js +9 -1
  122. package/dist/isolation/contracts.js.map +1 -1
  123. package/dist/isolation/coordinator.d.ts.map +1 -1
  124. package/dist/isolation/coordinator.js +4 -0
  125. package/dist/isolation/coordinator.js.map +1 -1
  126. package/dist/isolation/process.d.ts.map +1 -1
  127. package/dist/isolation/process.js +3 -1
  128. package/dist/isolation/process.js.map +1 -1
  129. package/dist/isolation/worktree.d.ts +9 -1
  130. package/dist/isolation/worktree.d.ts.map +1 -1
  131. package/dist/isolation/worktree.js +8 -3
  132. package/dist/isolation/worktree.js.map +1 -1
  133. package/dist/memory.d.ts +5 -3
  134. package/dist/memory.d.ts.map +1 -1
  135. package/dist/memory.js +8 -6
  136. package/dist/memory.js.map +1 -1
  137. package/dist/migration/assessment-contract.d.ts +60 -0
  138. package/dist/migration/assessment-contract.d.ts.map +1 -0
  139. package/dist/migration/assessment-contract.js +132 -0
  140. package/dist/migration/assessment-contract.js.map +1 -0
  141. package/dist/migration/assessment-schema.d.ts +19 -0
  142. package/dist/migration/assessment-schema.d.ts.map +1 -0
  143. package/dist/migration/assessment-schema.js +43 -0
  144. package/dist/migration/assessment-schema.js.map +1 -0
  145. package/dist/migration/assessment.d.ts +159 -0
  146. package/dist/migration/assessment.d.ts.map +1 -0
  147. package/dist/migration/assessment.js +219 -0
  148. package/dist/migration/assessment.js.map +1 -0
  149. package/dist/migration/cli.d.ts +6 -0
  150. package/dist/migration/cli.d.ts.map +1 -0
  151. package/dist/migration/cli.js +101 -0
  152. package/dist/migration/cli.js.map +1 -0
  153. package/dist/migration/evidence.d.ts +27 -0
  154. package/dist/migration/evidence.d.ts.map +1 -0
  155. package/dist/migration/evidence.js +124 -0
  156. package/dist/migration/evidence.js.map +1 -0
  157. package/dist/migration/example.d.ts +33 -0
  158. package/dist/migration/example.d.ts.map +1 -0
  159. package/dist/migration/example.js +28 -0
  160. package/dist/migration/example.js.map +1 -0
  161. package/dist/migration/index.d.ts +21 -0
  162. package/dist/migration/index.d.ts.map +1 -0
  163. package/dist/migration/index.js +15 -0
  164. package/dist/migration/index.js.map +1 -0
  165. package/dist/migration/inventory.d.ts +70 -0
  166. package/dist/migration/inventory.d.ts.map +1 -0
  167. package/dist/migration/inventory.js +233 -0
  168. package/dist/migration/inventory.js.map +1 -0
  169. package/dist/migration/schema.d.ts +61 -0
  170. package/dist/migration/schema.d.ts.map +1 -0
  171. package/dist/migration/schema.js +76 -0
  172. package/dist/migration/schema.js.map +1 -0
  173. package/dist/migration/verification.d.ts +146 -0
  174. package/dist/migration/verification.d.ts.map +1 -0
  175. package/dist/migration/verification.js +260 -0
  176. package/dist/migration/verification.js.map +1 -0
  177. package/dist/orchestration/actions.d.ts +2 -0
  178. package/dist/orchestration/actions.d.ts.map +1 -1
  179. package/dist/orchestration/actions.js.map +1 -1
  180. package/dist/orchestration/artifact-host.d.ts +46 -0
  181. package/dist/orchestration/artifact-host.d.ts.map +1 -0
  182. package/dist/orchestration/artifact-host.js +64 -0
  183. package/dist/orchestration/artifact-host.js.map +1 -0
  184. package/dist/orchestration/coordinator-actions.d.ts +1 -1
  185. package/dist/orchestration/coordinator-actions.d.ts.map +1 -1
  186. package/dist/orchestration/coordinator-actions.js +5 -3
  187. package/dist/orchestration/coordinator-actions.js.map +1 -1
  188. package/dist/orchestration/coordinator-types.d.ts +23 -2
  189. package/dist/orchestration/coordinator-types.d.ts.map +1 -1
  190. package/dist/orchestration/coordinator.d.ts +5 -0
  191. package/dist/orchestration/coordinator.d.ts.map +1 -1
  192. package/dist/orchestration/coordinator.js +30 -13
  193. package/dist/orchestration/coordinator.js.map +1 -1
  194. package/dist/orchestration/execution-cli.d.ts +1 -1
  195. package/dist/orchestration/execution-cli.d.ts.map +1 -1
  196. package/dist/orchestration/execution-cli.js +29 -6
  197. package/dist/orchestration/execution-cli.js.map +1 -1
  198. package/dist/orchestration/execution-journal.d.ts.map +1 -1
  199. package/dist/orchestration/execution-journal.js +79 -6
  200. package/dist/orchestration/execution-journal.js.map +1 -1
  201. package/dist/orchestration/execution-store.d.ts +5 -1
  202. package/dist/orchestration/execution-store.d.ts.map +1 -1
  203. package/dist/orchestration/execution-store.js +66 -5
  204. package/dist/orchestration/execution-store.js.map +1 -1
  205. package/dist/orchestration/execution.d.ts.map +1 -1
  206. package/dist/orchestration/execution.js +37 -10
  207. package/dist/orchestration/execution.js.map +1 -1
  208. package/dist/orchestration/index.d.ts +6 -0
  209. package/dist/orchestration/index.d.ts.map +1 -1
  210. package/dist/orchestration/index.js +6 -0
  211. package/dist/orchestration/index.js.map +1 -1
  212. package/dist/orchestration/interruption.d.ts +10 -0
  213. package/dist/orchestration/interruption.d.ts.map +1 -0
  214. package/dist/orchestration/interruption.js +38 -0
  215. package/dist/orchestration/interruption.js.map +1 -0
  216. package/dist/orchestration/question-contract.d.ts +19 -0
  217. package/dist/orchestration/question-contract.d.ts.map +1 -0
  218. package/dist/orchestration/question-contract.js +21 -0
  219. package/dist/orchestration/question-contract.js.map +1 -0
  220. package/dist/orchestration/questions.d.ts +9 -0
  221. package/dist/orchestration/questions.d.ts.map +1 -0
  222. package/dist/orchestration/questions.js +75 -0
  223. package/dist/orchestration/questions.js.map +1 -0
  224. package/dist/orchestration/reviewed-ledger.d.ts +23 -0
  225. package/dist/orchestration/reviewed-ledger.d.ts.map +1 -0
  226. package/dist/orchestration/reviewed-ledger.js +49 -0
  227. package/dist/orchestration/reviewed-ledger.js.map +1 -0
  228. package/dist/orchestration/source-candidates.d.ts +64 -0
  229. package/dist/orchestration/source-candidates.d.ts.map +1 -0
  230. package/dist/orchestration/source-candidates.js +95 -0
  231. package/dist/orchestration/source-candidates.js.map +1 -0
  232. package/dist/orchestration/validation.js +1 -1
  233. package/dist/orchestration/validation.js.map +1 -1
  234. package/dist/runlog.js +2 -2
  235. package/dist/runlog.js.map +1 -1
  236. package/dist/runtime/permissions.d.ts.map +1 -1
  237. package/dist/runtime/permissions.js +3 -2
  238. package/dist/runtime/permissions.js.map +1 -1
  239. package/dist/runtime/turn.d.ts +2 -0
  240. package/dist/runtime/turn.d.ts.map +1 -1
  241. package/dist/runtime/turn.js +21 -7
  242. package/dist/runtime/turn.js.map +1 -1
  243. package/dist/session-management/actions.js +1 -1
  244. package/dist/session-management/actions.js.map +1 -1
  245. package/dist/sessions/execution-binding.d.ts +8 -0
  246. package/dist/sessions/execution-binding.d.ts.map +1 -0
  247. package/dist/sessions/execution-binding.js +9 -0
  248. package/dist/sessions/execution-binding.js.map +1 -0
  249. package/dist/sessions/index.d.ts +1 -0
  250. package/dist/sessions/index.d.ts.map +1 -1
  251. package/dist/sessions/index.js +1 -0
  252. package/dist/sessions/index.js.map +1 -1
  253. package/dist/source-changes/writer.d.ts +77 -0
  254. package/dist/source-changes/writer.d.ts.map +1 -0
  255. package/dist/source-changes/writer.js +189 -0
  256. package/dist/source-changes/writer.js.map +1 -0
  257. package/dist/spawning/actions.d.ts +10 -1
  258. package/dist/spawning/actions.d.ts.map +1 -1
  259. package/dist/spawning/actions.js +26 -7
  260. package/dist/spawning/actions.js.map +1 -1
  261. package/dist/spawning/cli.js +1 -1
  262. package/dist/spawning/cli.js.map +1 -1
  263. package/dist/spawning/execution.d.ts.map +1 -1
  264. package/dist/spawning/execution.js +2 -0
  265. package/dist/spawning/execution.js.map +1 -1
  266. package/dist/spawning/types.d.ts +19 -6
  267. package/dist/spawning/types.d.ts.map +1 -1
  268. package/dist/spawning/validation.d.ts +16 -0
  269. package/dist/spawning/validation.d.ts.map +1 -1
  270. package/dist/spawning/validation.js +44 -8
  271. package/dist/spawning/validation.js.map +1 -1
  272. package/dist/storage.d.ts +3 -0
  273. package/dist/storage.d.ts.map +1 -1
  274. package/dist/storage.js +6 -1
  275. package/dist/storage.js.map +1 -1
  276. package/dist/supervision/contracts.js +4 -1
  277. package/dist/supervision/contracts.js.map +1 -1
  278. package/dist/tools.d.ts +1 -0
  279. package/dist/tools.d.ts.map +1 -1
  280. package/dist/tools.js +5 -0
  281. package/dist/tools.js.map +1 -1
  282. package/docs/README.md +66 -0
  283. package/docs/delegation-ledger.md +329 -0
  284. package/docs/migration-assessment.md +113 -0
  285. package/docs/migration-example-plan.json +88 -0
  286. package/docs/migration-example-report.json +511 -0
  287. package/docs/migration-inventory.md +63 -0
  288. package/docs/migration-playbook.md +152 -0
  289. package/docs/migration-verification.md +177 -0
  290. package/docs/releases/3.6.0.md +43 -0
  291. package/package.json +7 -2
@@ -0,0 +1,329 @@
1
+ # Delegation ledger (`delegation-ledger/v1`)
2
+
3
+ One parent execution allowance, shared with children that run in other processes or on other
4
+ hosts (#415). The authority is the existing reservation ledger (`src/execution/ledger.ts`):
5
+ requests are charged before dispatch, every ancestor is charged, child accounts come from
6
+ `child_grant` events, original deadlines hold, and unknown outcomes never restore capacity. This
7
+ protocol serves that ledger; it adds no second set of budget rules.
8
+
9
+ ## Placement
10
+
11
+ The user chooses where a run's ledger lives:
12
+
13
+ - **local**: the parent CLI serves its own ledger from the user's machine or container.
14
+ - **astrolift**: Astrolift runs the same `calliope ledger serve` as a durable managed service, so
15
+ children in pods, restarts and disconnects never lose reservations.
16
+
17
+ Children only receive a URL and a scoped token.
18
+
19
+ ## Serve
20
+
21
+ ```sh
22
+ calliope ledger serve --budget RUNS/<run>/budget --project /path/to/project \
23
+ --token-file /private/parent.token [--host 127.0.0.1] [--port 0]
24
+ ```
25
+
26
+ It prints `{"protocol":"delegation-ledger/v1","url":...,"runId":...}` once listening. The parent
27
+ token goes to `--token-file` (created new, mode 0600) and is never printed. Server state (signing
28
+ key, grant epochs) lives in a private sibling directory, never inside the budget directory.
29
+
30
+ ## Serve a reviewed native run
31
+
32
+ ```sh
33
+ calliope ledger serve-reviewed --run RUN_ID --agent AGENT_ID \
34
+ --max-output-tokens 1024 --project /path/to/project \
35
+ --token-file /private/owner.token
36
+ ```
37
+
38
+ This mode calls `prepareReviewedLedger`, reuses the run's native permission gates,
39
+ original budget, parent funding and deadline, and serves only the selected agent's
40
+ subtree. The token file must be outside the project in a private canonical directory;
41
+ it is created exclusively and never printed. Output includes the owner, original
42
+ deadline and versioned reviewed-host capability. SIGINT/SIGTERM close the listener.
43
+ Failed credential delivery also closes it without replacing an existing file.
44
+ Library hosts can call `prepareReviewedLedger(cwd, runId, agentId, maxOutputTokens,
45
+ options)` for the unbound server and private credential. They control where it listens.
46
+
47
+ Version 2 credentials bind the owner scope and exact native run review. Older
48
+ servers reject that token version; current raw-ledger endpoints reject its reviewed
49
+ authority binding. Child credentials retain that binding. A sibling owner endpoint
50
+ cannot accept the token, and reservations, settlements and revocations enforce the
51
+ selected subtree. Each new request also checks the target account's native admission,
52
+ stop/escalation state and the host's output cap. Existing requests can still settle
53
+ after owner cancellation; grant revocation and token expiry retain their existing
54
+ semantics.
55
+
56
+ The HTTP grant operation only returns credentials for an **exact, already admitted**
57
+ native child grant. It cannot create a proposal, approve children, bypass native
58
+ depth/count limits or promote an interrupted ledger grant into the execution graph.
59
+ Use the existing native proposal review/admission flow first. Reissuing a credential
60
+ preserves its account, deadline and all recorded spending; revoked grants stay revoked.
61
+
62
+ All owners of a run share its private signing key and revocation history. A native
63
+ writer lock serializes revocations from separate processes; only confirmed dead locks
64
+ are reclaimed. Malformed, missing, public or linked revocation/key files are refused.
65
+ New keys initialize an empty revocation history once. A retained legacy key without
66
+ that history requires verified restoration or an explicit owner-managed credential
67
+ rotation; opening it never silently treats missing revocations as an empty history.
68
+
69
+ This is reviewed ledger hosting, not automatic Cykick/Astrolift enrollment. Remote
70
+ workspace identity, dispatcher credential delivery, task-attempt ownership, transport
71
+ reachability and any narrower Cykick file-mutation policy still need their native
72
+ bindings. A loopback listener does not make a desktop reachable from a remote pod.
73
+
74
+ ## Run a delegated child
75
+
76
+ A host (Cy, an Astrolift task) grants the child, writes its scoped token to a private file and
77
+ starts a headless run or native ACP process:
78
+
79
+ ```sh
80
+ calliope --headless --json --ledger-url URL --ledger-token-file /private/child.token \
81
+ --ledger-agent CHILD_ACCOUNT "objective"
82
+
83
+ calliope acp --ledger-url URL --ledger-token-file /private/child.token \
84
+ --ledger-agent CHILD_ACCOUNT
85
+ ```
86
+
87
+ The turn runs under `ExecutionGuard` with the parent's ledger: the child's tools, paths, deadline
88
+ and budget come from its grant, and every provider request is reserved and settled with the
89
+ parent. A revoked or unknown grant, or an unreachable parent, stops the child before any turn.
90
+ The three flags go together, using separate flag/value arguments. Partial, repeated,
91
+ unknown or equals-form ledger flags fail before execution; they never select an
92
+ undelegated fallback.
93
+
94
+ ## Operations
95
+
96
+ `POST /v1/<op>` with `Authorization: Bearer <token>` and a JSON body.
97
+
98
+ | Op | Who | Effect |
99
+ | --- | --- | --- |
100
+ | `hello` | any | protocol and operations |
101
+ | `journal` | any | the full hash-chained history (`manifest`, `events`) |
102
+ | `execution` | account owner | verify `{agentId, project: {root, key}}` against the retained owner grant and return its native workspace binding |
103
+ | `reserve` | owner of `reservation.agentId` | charge before dispatch; same id replays the original admission |
104
+ | `settle` | owner of the reserved request | record usage or an outcome; same settlement replays |
105
+ | `grant` | parent, or a child for its own accounts | allocate child accounts; returns the child's scoped token |
106
+ | `revoke` | parent | permanently fence a grant and every descendant |
107
+
108
+ A token may act for its accounts and their descendants only. A child cannot charge a sibling or
109
+ the root, cannot mint a root allowance, and a revoked grant cannot be reissued. Errors carry the
110
+ ledger's codes (`budget`, `deadline`, `authority`, `conflict`, `limit`, `locked`, `unavailable`).
111
+
112
+ Admission rechecks token expiry and grant revocation while holding the ledger's
113
+ writer lock, immediately before committing a reservation or nested grant. A
114
+ request queued before revocation cannot acquire authority when the lock opens.
115
+
116
+ An embedded owner can also supply `createLedgerServer({ledger, cwd, state,
117
+ assertAuthority: execution.assertAuthority})`, using the handle returned by
118
+ `prepareAgentExecution`. The server rechecks this trusted callback before new
119
+ admission and under the writer lock, including grant reissue. Cancelling the
120
+ native reviewed run then fences remote reservations and grants even before a
121
+ coordinator journal exists. Once the journal exists, completing the run or stopping
122
+ the handle's selected agent (or an ancestor) through an explicit stop control also
123
+ fences new work. Reopening the handle does not bypass those controls; an independently active sibling remains
124
+ eligible under its own handle. These checks reuse native execution history.
125
+ The callback is host code, never a request argument.
126
+ The standalone `ledger serve --budget ...` command serves an explicitly selected
127
+ raw ledger; it does not infer a reviewed-run binding.
128
+
129
+ Owner cancellation, agent stops and run completion still permit authenticated
130
+ journal inspection, replay of an already admitted reservation, and settlement
131
+ of existing requests. These reconcile
132
+ prior work; they do not authorize another provider call. Unknown/cancelled usage
133
+ retains its reserved charge. Token expiry and grant revocation continue to apply
134
+ to every operation, so a revoked child needs its owner to reconcile its requests.
135
+
136
+ ## Client behaviour
137
+
138
+ `RemoteReservationLedger` gives `ExecutionGuard` the same read/reserve/settle surface as the local
139
+ ledger. It replays and verifies the hash chain itself and refuses any history that is not an
140
+ append-only extension of what it has seen, so a server reset or rollback cannot return spent
141
+ capacity. Writes retry with the same id; if every attempt is lost it inspects the journal, and
142
+ only an outcome the parent recorded counts. Otherwise the result is `unavailable` and nothing is
143
+ authorized (a reservation that was admitted stays charged).
144
+
145
+ The verified history is checkpointed atomically beneath the client's private
146
+ `root` as `verified-parent/history.json`. Reuse that root after reconnect or
147
+ restart. A missing, damaged, public or linked history file is an error; it is
148
+ never replaced with an empty allowance. Concurrent clients retain the longest
149
+ verified history, so an older response cannot overwrite a newer checkpoint.
150
+ The checkpoint contains no bearer token and never admits a provider request by
151
+ itself. Only the parent service can reserve or settle usage.
152
+
153
+ Headless and ACP children keep this state under `~/.calliope-cli/delegation-ledgers`,
154
+ keyed by the canonical project, configured token-file location and account. Rotating
155
+ the token or its projected-secret symlink at that location preserves verified history; restarting against a
156
+ rolled-back parent stops before the turn starts. Keep this directory on the
157
+ child's persistent private volume when running in a container. A new configured
158
+ token path is a separate connection, not recovery of the old one. These client
159
+ checkpoints do not by themselves wire Astrolift task admission or cancellation
160
+ to the ledger service.
161
+
162
+ The shared project budget also retains its reservation while admission is unknown.
163
+ An error releases project capacity only after a confirmed rejection before any
164
+ lost response. Even a fresh journal can lag an in-flight admission. Neither a
165
+ disconnect nor restarting the child restores the reserved project capacity.
166
+ Reservation errors optionally report `admission: refused` when the server has
167
+ verified non-admission after the local operation ends, or `unknown` otherwise.
168
+ Clients retain capacity when talking to older v1 servers that omit this evidence.
169
+
170
+ ## Owner-bound remote workspaces
171
+
172
+ A copied checkout has a different path and filesystem identity. It cannot use a
173
+ parent grant just because its files look the same. The ledger owner may issue a
174
+ version 2 child grant with `project: {root, key}`, captured using the CLI's
175
+ `projectIdentity()` on the intended child host. The existing proposal hash,
176
+ review revision and native run manifest references remain part of that immutable
177
+ grant. The trusted host must establish the identity and authorize the binding;
178
+ model output or an unauthenticated workspace claim is not sufficient.
179
+
180
+ Only a parent token may issue these workspace grants. Child-issued version 1
181
+ grants inherit the nearest owner-bound workspace, and cannot change it. Workspace
182
+ grants use reservation event version 5 and projection version 4; existing grant
183
+ events, manifests and hashes are unchanged. A restarted client replays the same
184
+ grant through its retained verified checkpoint.
185
+
186
+ Headless and ACP invocations negotiate `execution` before starting their turn. The server
187
+ checks the token's account scope, live owner authority and exact project identity.
188
+ The client independently checks the response against the native journal and its
189
+ actual local directory. Missing protocol support, another account, a substituted
190
+ binding or a replaced directory stops execution. Library callers opt in with
191
+ `RemoteReservationLedger.connect({..., execution: {cwd, agentId}})`.
192
+
193
+ File and brain-path checks use the bound child root and key, with the original
194
+ relative tool/path grants. Filesystem separators are normalized for grant checks;
195
+ parent traversal and symlink aliases remain denied. The immutable source budget
196
+ manifest, account ancestry, reservations and deadline remain on the parent ledger.
197
+ The checkpoint stays outside the child's project, and local project spending
198
+ limits still apply. Binding a folder does not copy files, mount a volume, import
199
+ brain content, install credentials or create another allowance.
200
+
201
+ The protocol now supports explicit workspace identity binding. Astrolift must
202
+ still establish that identity from its native runtime authority, enroll the task
203
+ under its owner, and connect lifecycle cancellation and funding. The raw ledger
204
+ service and a parent task UUID do not establish those bindings automatically.
205
+
206
+ `tests/delegation-ledger.test.ts` is the local-host conformance suite: concurrent and nested
207
+ children exhausting one allowance, duplicate dispatch and lost acknowledgements, an unreachable
208
+ parent, restart and rollback, revocation of a child and its descendants, foreign runs, siblings
209
+ and forged tokens, and `ExecutionGuard` admission through the parent.
210
+
211
+ ### Runner capability negotiation
212
+
213
+ `calliope --version --json` is an offline, credential-free probe.
214
+ `headless: {protocol: 1, delegation: 1, workspaceBinding: 1}` advertises
215
+ NDJSON terminal events, native parent-ledger admission and owner-bound workspace
216
+ validation. Embedders must verify these fields before supplying delegated tasks;
217
+ a matching package version alone does not establish those capabilities. This
218
+ probe does not grant authority: each invocation still negotiates with the live
219
+ parent and validates its token, journal and workspace before inference.
220
+
221
+
222
+ ### Native ACP session continuity
223
+
224
+ ACP connects to the parent's ledger before opening its protocol transport. The
225
+ process has one trusted execution context; `session/new` and `session/load` cannot
226
+ replace it through client parameters. `initialize` advertises
227
+ `agentCapabilities._meta.calliopeDelegation` with `version: 1`,
228
+ `workspaceBinding: 1` and `sessionBinding: 1`. A host must negotiate this metadata
229
+ before relying on delegated ACP behavior.
230
+
231
+ New delegated sessions retain a versioned restriction containing the original
232
+ manifest hash and account ID in private session metadata. Saving a conversation
233
+ or creating a manual/safety branch preserves it. This marker does not mint a
234
+ grant, reserve tokens or confer authority. Loading requires the same live ledger
235
+ and account, an exact workspace match and an unexpired original deadline. A
236
+ plain ACP process cannot load a bound session, and a delegated process cannot
237
+ attach its allowance to old unbound history. The shared turn engine also checks
238
+ the restriction before inference through other clients.
239
+
240
+ Follow-up prompts use the original account's reservations, costs and clock.
241
+ Native one-time approvals, tool results, cancellation and protocol replay remain
242
+ in use. Automatic project memory/context is filtered through the granted read
243
+ scope before inclusion in the system prompt; project trust alone does not widen
244
+ that scope. Operator-owned global preferences remain trusted configuration.
245
+
246
+ This is a CLI capability, not completed Astrolift enrollment. The runtime adapter
247
+ must still pass the trusted tuple, retain its task binding across restarts, verify
248
+ the capability and connect owner lifecycle/funding. Retained metadata is a
249
+ restriction within the private store, not protection against an administrator
250
+ rewriting that store or explicitly transferring conversation content elsewhere.
251
+
252
+ ### Private reverse transport for hosted tasks
253
+
254
+ The execution API exports `LEDGER_TUNNEL_CAPABILITY`, `attachLedgerTunnel` (owner)
255
+ and `listenLedgerTunnel` (task). The owner injects an authenticated, non-replayed
256
+ duplex exec connection; ordinary HTTP framing and backpressure carry only native
257
+ ledger requests. The owner opens no public listener. The task binds its original
258
+ loopback port, and never picks another port after a conflict. This does not yet
259
+ supply an Astrolift websocket endpoint or its task-placement authorization.
260
+
261
+ Both ends pin the original child credential's SHA-256, reviewed audience, run,
262
+ grant and expiration. Parent/replacement credentials are refused before task
263
+ traffic enters the exec stream. Claims are restrictions, not authentication:
264
+ the existing native server still verifies the signature, current grant, workspace
265
+ and account controls. The owner URL must be its trusted reviewed loopback host;
266
+ requests cannot choose another URL, follow redirects or invoke revocation.
267
+
268
+ Requests retain the native 256 KiB limit. Responses stream with a 32 MiB bound
269
+ for the bounded journal and envelope. There is one task request in flight;
270
+ heartbeats, request deadlines, stream closure and the original credential expiry
271
+ close both ends on loss of the owner. Bridge failures never assert non-admission.
272
+ The remote ledger retains unknown charges and retries the original request ID.
273
+
274
+ Reconnect attaches a new authorized stream to the original task port and native
275
+ stores, using the same credential and child checkpoint. It must not mint another
276
+ grant or replace a task binding. The trusted host must revalidate task identity,
277
+ placement and caller access through `assertConnection`, and abort the connection
278
+ when that lease ends. Do not use terminal replay, chat events or logs for these
279
+ streams: request headers contain the child bearer credential. The API performs
280
+ no task enrollment, credential persistence, scheduling or independent accounting.
281
+
282
+ ### Live execution authority
283
+
284
+ A retained journal proves accounting history, not current permission to execute.
285
+ Delegated clients revalidate the exact account and workspace through `execution`
286
+ before model requests and tool effects, and again before committing staged file
287
+ bytes. Revoked grants, stopped owners and an unreachable authority refuse further
288
+ work even when cached history is readable. Reconciliation reads do not restore
289
+ execution permission or release unresolved reservations.
290
+
291
+
292
+ ### Runnable host conformance example
293
+
294
+ Run `npm run test:reviewed-host` from the source checkout. The example at
295
+ `scripts/qualification/reviewed-host.mjs` creates a reviewed native run, serves
296
+ its parent ledger over HTTP and launches two concurrent built headless CLI
297
+ processes with separate account-scoped credentials against a deterministic local
298
+ inference endpoint. Each account ledger is also served by its own CLI process,
299
+ which is stopped and recreated during the restart check. Both children settle
300
+ into one parent allowance. Retained unknown requests then exhaust that allowance;
301
+ a host restart preserves them, and real CLI invocations refuse exhausted,
302
+ foreign-workspace, sibling-account and cancelled authority without another
303
+ inference request.
304
+ It uses private disposable configuration and makes no paid provider requests.
305
+
306
+ To qualify a standalone artifact built from the same source:
307
+
308
+ ```sh
309
+ npm run build
310
+ bun packaging/build-binary.mjs --native
311
+ CALLIOPE_REVIEWED_HOST_BINARY="$PWD/packaging/dist/calliope-native" \
312
+ node scripts/qualification/reviewed-host.mjs
313
+ ```
314
+
315
+ To qualify an extracted npm tarball with its production dependencies installed,
316
+ set `CALLIOPE_REVIEWED_HOST_PACKAGE` to that package directory instead. Both the
317
+ host library and all child processes then use the extracted package. The package
318
+ and standalone-binary options are mutually exclusive.
319
+
320
+ The executable reports its tested artifact type and invariant results as JSON.
321
+ This is a local HTTP host example, not a deployed Astrolift acceptance test.
322
+ Use `delegation-ledger/v1`, reviewed host capability version 1 and the headless
323
+ capability tuple above; a matching package version alone is insufficient.
324
+ The current CLI entry point requests a 4096-token output limit, so the reviewed
325
+ host and discovered model must both permit that bound. Lower output caps are
326
+ available to library callers through `DelegatedExecutionOptions.maxOutputTokens`.
327
+ The existing ledger, workspace and session suites cover nested grants, lost
328
+ acknowledgments, rollback and approval/session replay; those are separate from
329
+ this example's process-level assertions.
@@ -0,0 +1,113 @@
1
+ # Read-only migration assessment
2
+
3
+ `calliope migration assess --repository /path/to/clone --request request.json --json`
4
+ produces a feasibility report, rulebook and work manifest from a pinned source
5
+ inventory and supplied pilot evidence. It does not run scripts, invoke Docker,
6
+ start workers, create a workflow, write project artifacts or propose brain changes.
7
+ Save the returned JSON through the project's authorized artifact owner when wanted.
8
+
9
+ `migration assessment-schema` returns the request/report JSON Schemas.
10
+ `migration review-assessment --request request.json` validates the request and
11
+ returns its digest without reading a repository. Schemas describe structure;
12
+ runtime validation also checks normalized paths, ownership and cross-references.
13
+ The assessment CLI exits 0 when it produced a report, including `investigate` or
14
+ `do-not-migrate`. Read `recommendation`; exit 0 is not a migration approval.
15
+
16
+ ## Request and inventory
17
+
18
+ The versioned request records:
19
+
20
+ - Source commit and authorized literal read paths, target adapter/stack/runtime.
21
+ - Port, redesign or incremental-upgrade intent, motivation, compatibility
22
+ obligations, deployment constraints and success criteria.
23
+ - USD budget in integer micros, duration limit and maximum concurrency.
24
+ - The rulebook's exact commit/path/blob, unique source/target unit ownership,
25
+ explicit source-file dependencies, risk and rationale, and reasoned exclusions.
26
+ - Up to 16 pilot plan/report pairs with separately evidenced implementation,
27
+ verification and review measurements. Measurements bind the exact report digest.
28
+
29
+ One request is bounded to 2 MiB, 128 units, 128 exclusions and 64 read prefixes.
30
+ All repository reads use the existing bounded committed inventory. The repository
31
+ is canonicalized before asynchronous work; moving a path alias cannot redirect
32
+ later reads. Evidence pins outside the selected read scope are reported without
33
+ reading them. Hosts must supply a scope already authorized for the user/task.
34
+
35
+ Every selected source file must be owned by a unit or explicitly excluded. Original
36
+ tests, build configuration, manifests and lockfiles remain listed in the rulebook.
37
+ The assessment identifies unsupported adapter/runtime/unit shapes, unavailable
38
+ sources, uncovered code, external dependencies, declared package cycles and unit
39
+ cycles. Unit dependencies must include declared local-package ordering. This is
40
+ declaration analysis, not an import parser or proof of dynamic dependency coverage.
41
+
42
+ The current adapter supports self-contained `.mjs` to `.mts` CLI ports on the pinned
43
+ Node 24 runtime. A redesign or incremental upgrade requires a different plan;
44
+ passing old CLI cases does not make it a structure-preserving port. Unsupported
45
+ scope yields `do-not-migrate` **for this plan and adapter**, not a general claim
46
+ that the selected technology or a migration is unsuitable.
47
+
48
+ ## Evidence and independent host review
49
+
50
+ Each pilot goes through [saved evidence review](migration-verification.md#review-saved-observations).
51
+ The assessment then checks every source, candidate, negative-control and rules pin
52
+ against actual committed blobs. Self-consistent JSON with invented Git pins is not
53
+ enough. Changed source, rules, runtime, cases or pilot accounting require a new
54
+ assessment and review. Missing or nonpassing baselines, known-failure checks or
55
+ candidate observations remain findings, regardless of a host's acceptance.
56
+
57
+ Library hosts call `assessMigration(repository, request, { signal, implementation, review })`.
58
+ `implementation` contains `kitSha256` and `verifierSha256`, supplied by the trusted
59
+ host from its installed kit artifact and the verifier that produced the pilot
60
+ evidence. These exact identities join the logical versions in the report, review
61
+ digest and unit bindings. Missing identities prevent `go`; request JSON cannot
62
+ supply them as authority. The host must check these hashes against its own
63
+ installation and evidence-producer records, not blindly copy a client's claims.
64
+ The optional `review` callback is trusted host code, never deserialized request
65
+ data. It receives the canonical repository, request, inventory digest, findings
66
+ and a digest binding that exact review context. The host must verify evidence
67
+ provenance, behavioral/compatibility coverage, risk classification, representative
68
+ pilot selection and measurement receipts through its owning records. It returns
69
+ `{ decision: 'accepted' | 'rejected', receipt: 'opaque-review-reference' }`.
70
+
71
+ Callbacks get a detached copy and cannot rewrite the assessment's inputs or
72
+ findings. A rejection, invalid receipt, unavailable review or absent host callback
73
+ prevents `go`. The standalone CLI deliberately has no flag that turns an authored
74
+ JSON report into independent review authority; it can still complete a read-only
75
+ assessment and return the work to investigate. A future native host adapter must
76
+ resolve review receipts through its existing authenticated owner.
77
+
78
+ `go` means the supported, pinned plan has no unresolved assessment findings and
79
+ its pilot evidence/coverage has been accepted by that host. It does not mean all
80
+ manifest units were migrated or verified. Every unit remains `planned`. Neither
81
+ the output digest nor an opaque review reference is portable authentication or
82
+ execution permission. A workflow owner must validate current bindings and its own
83
+ authority before dispatch; merely loading this report must never start work.
84
+
85
+ ## Measured ranges and work artifacts
86
+
87
+ Every populated risk group, including high-risk units, requires a passing pilot,
88
+ with representativeness checked by the host. The manifest shows coverage by risk
89
+ group; one passing example does not establish coverage of every unit. A measurement
90
+ records total pilot cost, work time (implementation plus verification), independent
91
+ review time and an accounting evidence ID. Zero billed cost is valid for an
92
+ evidenced local fixture; missing measurements are not represented as zero.
93
+
94
+ Only accepted, fully qualified evidence produces estimates. Cost bounds multiply
95
+ the observed pilot minimum/maximum by the exact manifest unit count. Lower time
96
+ uses concurrency and dependency depth, then serial review; upper time assumes
97
+ serial work and review. These are explicit extrapolation assumptions, not
98
+ statistical confidence intervals. Unmeasured deployment, external data migration
99
+ and operating costs are excluded. A lower bound over budget yields
100
+ `do-not-migrate`; an overlapping range yields `investigate`.
101
+
102
+ The manifest has stable source-path unit IDs, deterministic dependency ordering
103
+ or cycle components, exact source blobs, per-unit binding digests and pilot
104
+ references. Binding digests conservatively include the complete assessment inputs,
105
+ including source/config/rules, logical revisions and exact kit/verifier hashes. A changed plan
106
+ requires re-review; this version does not claim minimal per-unit invalidation or
107
+ resume reconciliation. Execution must honor the pinned worker package artifact.
108
+
109
+ The evidence storage plan names a project-relative directory, assessment/rulebook/
110
+ manifest files and per-unit pin, verification, accounting and review artifacts.
111
+ `written: false` makes its status explicit. Native Astrolift project/agent bindings,
112
+ artifact persistence, conversational setup, reviewed compatibility exceptions,
113
+ rule-update replay and resumable execution remain separate host integration work.
@@ -0,0 +1,88 @@
1
+ {
2
+ "format": "calliope.migration.verification-plan/v1",
3
+ "adapter": "javascript-to-typescript-cli/v1",
4
+ "verifier": "byte-parity-v1",
5
+ "runtime": {
6
+ "image": "sha256:55fb5f5a527ea2c5c4a95f963e48ef90aa38c7b346054fdc8ee9957a2b55d205",
7
+ "node": "v24.22.1"
8
+ },
9
+ "source": {
10
+ "revision": "54bdcbfa6e40806cd709736e448bd50c453799ea",
11
+ "path": "source.mjs",
12
+ "object": "b96c6972d5a4bfc7e1c52fea78ba340ff24b97c5"
13
+ },
14
+ "negative": {
15
+ "revision": "54bdcbfa6e40806cd709736e448bd50c453799ea",
16
+ "path": "negative.mts",
17
+ "object": "0d6091a5c5d47ed8b4c97b7f74f296853fcc09a0"
18
+ },
19
+ "rules": {
20
+ "revision": "54bdcbfa6e40806cd709736e448bd50c453799ea",
21
+ "path": "RULES.md",
22
+ "object": "ece25894441e04857adea069e792b6f622fb2e7b"
23
+ },
24
+ "cases": [
25
+ {
26
+ "id": "positive",
27
+ "argument": "[1,2,3]",
28
+ "expected": {
29
+ "exitCode": 0,
30
+ "stdout": "{\"sum\":6,\"count\":3}\n",
31
+ "stderr": ""
32
+ }
33
+ },
34
+ {
35
+ "id": "empty",
36
+ "argument": "[]",
37
+ "expected": {
38
+ "exitCode": 0,
39
+ "stdout": "{\"sum\":0,\"count\":0}\n",
40
+ "stderr": ""
41
+ }
42
+ },
43
+ {
44
+ "id": "negative-values",
45
+ "argument": "[-2,5]",
46
+ "expected": {
47
+ "exitCode": 0,
48
+ "stdout": "{\"sum\":3,\"count\":2}\n",
49
+ "stderr": ""
50
+ }
51
+ },
52
+ {
53
+ "id": "invalid-type",
54
+ "argument": "[\"1\"]",
55
+ "expected": {
56
+ "exitCode": 2,
57
+ "stdout": "",
58
+ "stderr": "Expected an array of safe integers.\n"
59
+ }
60
+ },
61
+ {
62
+ "id": "invalid-json",
63
+ "argument": "not-json",
64
+ "expected": {
65
+ "exitCode": 2,
66
+ "stdout": "",
67
+ "stderr": "Invalid JSON.\n"
68
+ }
69
+ }
70
+ ],
71
+ "negativeControl": {
72
+ "caseId": "positive",
73
+ "expected": {
74
+ "exitCode": 0,
75
+ "stdout": "{\"sum\":9,\"count\":3}\n",
76
+ "stderr": ""
77
+ }
78
+ },
79
+ "limits": {
80
+ "commandTimeoutMs": 10000,
81
+ "totalMs": 120000
82
+ },
83
+ "candidate": {
84
+ "revision": "f4732441c67d285f5005ac0afb25d412c2d74f93",
85
+ "path": "candidate.mts",
86
+ "object": "4b551e05cce761a68a30a20207c47add9a9f4eff"
87
+ }
88
+ }