@calliopelabs/cli 3.5.4 → 3.7.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.
- package/README.md +8 -0
- package/dist/acp/controls.d.ts +10 -0
- package/dist/acp/controls.d.ts.map +1 -0
- package/dist/acp/controls.js +81 -0
- package/dist/acp/controls.js.map +1 -0
- package/dist/acp.d.ts +21 -7
- package/dist/acp.d.ts.map +1 -1
- package/dist/acp.js +139 -23
- package/dist/acp.js.map +1 -1
- package/dist/bin.d.ts.map +1 -1
- package/dist/bin.js +28 -8
- package/dist/bin.js.map +1 -1
- package/dist/build-identity.d.ts +27 -0
- package/dist/build-identity.d.ts.map +1 -0
- package/dist/build-identity.js +32 -0
- package/dist/build-identity.js.map +1 -0
- package/dist/build-metadata.json +1 -0
- package/dist/execution/authority.d.ts +4 -1
- package/dist/execution/authority.d.ts.map +1 -1
- package/dist/execution/authority.js +23 -7
- package/dist/execution/authority.js.map +1 -1
- package/dist/execution/child-grants.d.ts +2 -0
- package/dist/execution/child-grants.d.ts.map +1 -1
- package/dist/execution/child-grants.js +19 -4
- package/dist/execution/child-grants.js.map +1 -1
- package/dist/execution/delegated.d.ts +14 -0
- package/dist/execution/delegated.d.ts.map +1 -0
- package/dist/execution/delegated.js +66 -0
- package/dist/execution/delegated.js.map +1 -0
- package/dist/execution/files.js +6 -6
- package/dist/execution/files.js.map +1 -1
- package/dist/execution/guard.d.ts +5 -0
- package/dist/execution/guard.d.ts.map +1 -1
- package/dist/execution/guard.js +31 -16
- package/dist/execution/guard.js.map +1 -1
- package/dist/execution/index.d.ts +4 -0
- package/dist/execution/index.d.ts.map +1 -1
- package/dist/execution/index.js +4 -0
- package/dist/execution/index.js.map +1 -1
- package/dist/execution/ledger-cli.d.ts +2 -1
- package/dist/execution/ledger-cli.d.ts.map +1 -1
- package/dist/execution/ledger-cli.js +51 -14
- package/dist/execution/ledger-cli.js.map +1 -1
- package/dist/execution/ledger-protocol.d.ts +6 -2
- package/dist/execution/ledger-protocol.d.ts.map +1 -1
- package/dist/execution/ledger-protocol.js +110 -24
- package/dist/execution/ledger-protocol.js.map +1 -1
- package/dist/execution/ledger-server.d.ts +13 -0
- package/dist/execution/ledger-server.d.ts.map +1 -1
- package/dist/execution/ledger-server.js +57 -13
- package/dist/execution/ledger-server.js.map +1 -1
- package/dist/execution/ledger-tunnel.d.ts +50 -0
- package/dist/execution/ledger-tunnel.d.ts.map +1 -0
- package/dist/execution/ledger-tunnel.js +307 -0
- package/dist/execution/ledger-tunnel.js.map +1 -0
- package/dist/execution/ledger.d.ts +4 -0
- package/dist/execution/ledger.d.ts.map +1 -1
- package/dist/execution/ledger.js +30 -4
- package/dist/execution/ledger.js.map +1 -1
- package/dist/execution/parent-accounting.d.ts +41 -0
- package/dist/execution/parent-accounting.d.ts.map +1 -0
- package/dist/execution/parent-accounting.js +52 -0
- package/dist/execution/parent-accounting.js.map +1 -0
- package/dist/execution/parent-budget.d.ts +25 -0
- package/dist/execution/parent-budget.d.ts.map +1 -0
- package/dist/execution/parent-budget.js +102 -0
- package/dist/execution/parent-budget.js.map +1 -0
- package/dist/execution/project-spend.d.ts.map +1 -1
- package/dist/execution/project-spend.js +35 -5
- package/dist/execution/project-spend.js.map +1 -1
- package/dist/execution/remote-checkpoint.d.ts +15 -0
- package/dist/execution/remote-checkpoint.d.ts.map +1 -0
- package/dist/execution/remote-checkpoint.js +165 -0
- package/dist/execution/remote-checkpoint.js.map +1 -0
- package/dist/execution/remote-ledger.d.ts +12 -2
- package/dist/execution/remote-ledger.d.ts.map +1 -1
- package/dist/execution/remote-ledger.js +53 -21
- package/dist/execution/remote-ledger.js.map +1 -1
- package/dist/execution/types.d.ts +23 -5
- package/dist/execution/types.d.ts.map +1 -1
- package/dist/execution/types.js.map +1 -1
- package/dist/goals/supervised.js +2 -2
- package/dist/goals/supervised.js.map +1 -1
- package/dist/headless.d.ts +2 -6
- package/dist/headless.d.ts.map +1 -1
- package/dist/headless.js +17 -21
- package/dist/headless.js.map +1 -1
- package/dist/improvement/actions.d.ts +3 -4
- package/dist/improvement/actions.d.ts.map +1 -1
- package/dist/improvement/actions.js +10 -7
- package/dist/improvement/actions.js.map +1 -1
- package/dist/improvement/capabilities.d.ts +54 -0
- package/dist/improvement/capabilities.d.ts.map +1 -0
- package/dist/improvement/capabilities.js +44 -0
- package/dist/improvement/capabilities.js.map +1 -0
- package/dist/improvement/cli.d.ts +1 -1
- package/dist/improvement/cli.d.ts.map +1 -1
- package/dist/improvement/cli.js +29 -3
- package/dist/improvement/cli.js.map +1 -1
- package/dist/improvement/host-capabilities.d.ts +119 -0
- package/dist/improvement/host-capabilities.d.ts.map +1 -0
- package/dist/improvement/host-capabilities.js +18 -0
- package/dist/improvement/host-capabilities.js.map +1 -0
- package/dist/improvement/index.d.ts +6 -0
- package/dist/improvement/index.d.ts.map +1 -1
- package/dist/improvement/index.js +6 -0
- package/dist/improvement/index.js.map +1 -1
- package/dist/improvement/proposal-hash.d.ts +3 -0
- package/dist/improvement/proposal-hash.d.ts.map +1 -0
- package/dist/improvement/proposal-hash.js +5 -0
- package/dist/improvement/proposal-hash.js.map +1 -0
- package/dist/improvement/review-contract.d.ts +32 -0
- package/dist/improvement/review-contract.d.ts.map +1 -0
- package/dist/improvement/review-contract.js +62 -0
- package/dist/improvement/review-contract.js.map +1 -0
- package/dist/improvement/review-requests.d.ts +72 -0
- package/dist/improvement/review-requests.d.ts.map +1 -0
- package/dist/improvement/review-requests.js +63 -0
- package/dist/improvement/review-requests.js.map +1 -0
- package/dist/improvement/source-changes.d.ts +78 -0
- package/dist/improvement/source-changes.d.ts.map +1 -0
- package/dist/improvement/source-changes.js +91 -0
- package/dist/improvement/source-changes.js.map +1 -0
- package/dist/improvement/task-outcomes.d.ts +82 -0
- package/dist/improvement/task-outcomes.d.ts.map +1 -0
- package/dist/improvement/task-outcomes.js +72 -0
- package/dist/improvement/task-outcomes.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -1
- package/dist/isolation/contracts.d.ts +13 -0
- package/dist/isolation/contracts.d.ts.map +1 -1
- package/dist/isolation/contracts.js +9 -1
- package/dist/isolation/contracts.js.map +1 -1
- package/dist/isolation/coordinator.d.ts.map +1 -1
- package/dist/isolation/coordinator.js +4 -0
- package/dist/isolation/coordinator.js.map +1 -1
- package/dist/isolation/process.d.ts.map +1 -1
- package/dist/isolation/process.js +3 -1
- package/dist/isolation/process.js.map +1 -1
- package/dist/isolation/worktree.d.ts +9 -1
- package/dist/isolation/worktree.d.ts.map +1 -1
- package/dist/isolation/worktree.js +8 -3
- package/dist/isolation/worktree.js.map +1 -1
- package/dist/memory.d.ts +5 -3
- package/dist/memory.d.ts.map +1 -1
- package/dist/memory.js +8 -6
- package/dist/memory.js.map +1 -1
- package/dist/migration/assessment-contract.d.ts +60 -0
- package/dist/migration/assessment-contract.d.ts.map +1 -0
- package/dist/migration/assessment-contract.js +132 -0
- package/dist/migration/assessment-contract.js.map +1 -0
- package/dist/migration/assessment-schema.d.ts +19 -0
- package/dist/migration/assessment-schema.d.ts.map +1 -0
- package/dist/migration/assessment-schema.js +43 -0
- package/dist/migration/assessment-schema.js.map +1 -0
- package/dist/migration/assessment.d.ts +159 -0
- package/dist/migration/assessment.d.ts.map +1 -0
- package/dist/migration/assessment.js +219 -0
- package/dist/migration/assessment.js.map +1 -0
- package/dist/migration/cli.d.ts +6 -0
- package/dist/migration/cli.d.ts.map +1 -0
- package/dist/migration/cli.js +101 -0
- package/dist/migration/cli.js.map +1 -0
- package/dist/migration/evidence.d.ts +27 -0
- package/dist/migration/evidence.d.ts.map +1 -0
- package/dist/migration/evidence.js +124 -0
- package/dist/migration/evidence.js.map +1 -0
- package/dist/migration/example.d.ts +33 -0
- package/dist/migration/example.d.ts.map +1 -0
- package/dist/migration/example.js +28 -0
- package/dist/migration/example.js.map +1 -0
- package/dist/migration/index.d.ts +21 -0
- package/dist/migration/index.d.ts.map +1 -0
- package/dist/migration/index.js +15 -0
- package/dist/migration/index.js.map +1 -0
- package/dist/migration/inventory.d.ts +70 -0
- package/dist/migration/inventory.d.ts.map +1 -0
- package/dist/migration/inventory.js +233 -0
- package/dist/migration/inventory.js.map +1 -0
- package/dist/migration/schema.d.ts +61 -0
- package/dist/migration/schema.d.ts.map +1 -0
- package/dist/migration/schema.js +76 -0
- package/dist/migration/schema.js.map +1 -0
- package/dist/migration/verification.d.ts +146 -0
- package/dist/migration/verification.d.ts.map +1 -0
- package/dist/migration/verification.js +260 -0
- package/dist/migration/verification.js.map +1 -0
- package/dist/orchestration/actions.d.ts +2 -0
- package/dist/orchestration/actions.d.ts.map +1 -1
- package/dist/orchestration/actions.js.map +1 -1
- package/dist/orchestration/artifact-host.d.ts +46 -0
- package/dist/orchestration/artifact-host.d.ts.map +1 -0
- package/dist/orchestration/artifact-host.js +64 -0
- package/dist/orchestration/artifact-host.js.map +1 -0
- package/dist/orchestration/coordinator-actions.d.ts +1 -1
- package/dist/orchestration/coordinator-actions.d.ts.map +1 -1
- package/dist/orchestration/coordinator-actions.js +5 -3
- package/dist/orchestration/coordinator-actions.js.map +1 -1
- package/dist/orchestration/coordinator-types.d.ts +23 -2
- package/dist/orchestration/coordinator-types.d.ts.map +1 -1
- package/dist/orchestration/coordinator.d.ts +5 -0
- package/dist/orchestration/coordinator.d.ts.map +1 -1
- package/dist/orchestration/coordinator.js +30 -13
- package/dist/orchestration/coordinator.js.map +1 -1
- package/dist/orchestration/execution-cli.d.ts +1 -1
- package/dist/orchestration/execution-cli.d.ts.map +1 -1
- package/dist/orchestration/execution-cli.js +29 -6
- package/dist/orchestration/execution-cli.js.map +1 -1
- package/dist/orchestration/execution-journal.d.ts.map +1 -1
- package/dist/orchestration/execution-journal.js +79 -6
- package/dist/orchestration/execution-journal.js.map +1 -1
- package/dist/orchestration/execution-store.d.ts +5 -1
- package/dist/orchestration/execution-store.d.ts.map +1 -1
- package/dist/orchestration/execution-store.js +66 -5
- package/dist/orchestration/execution-store.js.map +1 -1
- package/dist/orchestration/execution.d.ts.map +1 -1
- package/dist/orchestration/execution.js +37 -10
- package/dist/orchestration/execution.js.map +1 -1
- package/dist/orchestration/index.d.ts +6 -0
- package/dist/orchestration/index.d.ts.map +1 -1
- package/dist/orchestration/index.js +6 -0
- package/dist/orchestration/index.js.map +1 -1
- package/dist/orchestration/interruption.d.ts +10 -0
- package/dist/orchestration/interruption.d.ts.map +1 -0
- package/dist/orchestration/interruption.js +38 -0
- package/dist/orchestration/interruption.js.map +1 -0
- package/dist/orchestration/question-contract.d.ts +19 -0
- package/dist/orchestration/question-contract.d.ts.map +1 -0
- package/dist/orchestration/question-contract.js +21 -0
- package/dist/orchestration/question-contract.js.map +1 -0
- package/dist/orchestration/questions.d.ts +9 -0
- package/dist/orchestration/questions.d.ts.map +1 -0
- package/dist/orchestration/questions.js +75 -0
- package/dist/orchestration/questions.js.map +1 -0
- package/dist/orchestration/reviewed-ledger.d.ts +23 -0
- package/dist/orchestration/reviewed-ledger.d.ts.map +1 -0
- package/dist/orchestration/reviewed-ledger.js +57 -0
- package/dist/orchestration/reviewed-ledger.js.map +1 -0
- package/dist/orchestration/routing.d.ts +3 -0
- package/dist/orchestration/routing.d.ts.map +1 -1
- package/dist/orchestration/routing.js +5 -1
- package/dist/orchestration/routing.js.map +1 -1
- package/dist/orchestration/source-candidates.d.ts +64 -0
- package/dist/orchestration/source-candidates.d.ts.map +1 -0
- package/dist/orchestration/source-candidates.js +95 -0
- package/dist/orchestration/source-candidates.js.map +1 -0
- package/dist/orchestration/validation.js +1 -1
- package/dist/orchestration/validation.js.map +1 -1
- package/dist/runlog.js +2 -2
- package/dist/runlog.js.map +1 -1
- package/dist/runtime/permissions.d.ts.map +1 -1
- package/dist/runtime/permissions.js +3 -2
- package/dist/runtime/permissions.js.map +1 -1
- package/dist/runtime/turn.d.ts +2 -0
- package/dist/runtime/turn.d.ts.map +1 -1
- package/dist/runtime/turn.js +21 -7
- package/dist/runtime/turn.js.map +1 -1
- package/dist/session-management/actions.js +1 -1
- package/dist/session-management/actions.js.map +1 -1
- package/dist/sessions/execution-binding.d.ts +8 -0
- package/dist/sessions/execution-binding.d.ts.map +1 -0
- package/dist/sessions/execution-binding.js +9 -0
- package/dist/sessions/execution-binding.js.map +1 -0
- package/dist/sessions/index.d.ts +1 -0
- package/dist/sessions/index.d.ts.map +1 -1
- package/dist/sessions/index.js +1 -0
- package/dist/sessions/index.js.map +1 -1
- package/dist/source-changes/writer.d.ts +77 -0
- package/dist/source-changes/writer.d.ts.map +1 -0
- package/dist/source-changes/writer.js +189 -0
- package/dist/source-changes/writer.js.map +1 -0
- package/dist/spawning/actions.d.ts +10 -1
- package/dist/spawning/actions.d.ts.map +1 -1
- package/dist/spawning/actions.js +26 -7
- package/dist/spawning/actions.js.map +1 -1
- package/dist/spawning/cli.js +1 -1
- package/dist/spawning/cli.js.map +1 -1
- package/dist/spawning/execution.d.ts.map +1 -1
- package/dist/spawning/execution.js +2 -0
- package/dist/spawning/execution.js.map +1 -1
- package/dist/spawning/types.d.ts +19 -6
- package/dist/spawning/types.d.ts.map +1 -1
- package/dist/spawning/validation.d.ts +16 -0
- package/dist/spawning/validation.d.ts.map +1 -1
- package/dist/spawning/validation.js +44 -8
- package/dist/spawning/validation.js.map +1 -1
- package/dist/storage.d.ts +5 -0
- package/dist/storage.d.ts.map +1 -1
- package/dist/storage.js +10 -1
- package/dist/storage.js.map +1 -1
- package/dist/supervision/contracts.js +4 -1
- package/dist/supervision/contracts.js.map +1 -1
- package/dist/tools.d.ts +1 -0
- package/dist/tools.d.ts.map +1 -1
- package/dist/tools.js +5 -0
- package/dist/tools.js.map +1 -1
- package/docs/README.md +66 -0
- package/docs/acp.md +228 -0
- package/docs/delegation-ledger.md +331 -0
- package/docs/improvement-cycles.md +304 -0
- package/docs/migration-assessment.md +113 -0
- package/docs/migration-example-plan.json +88 -0
- package/docs/migration-example-report.json +511 -0
- package/docs/migration-inventory.md +63 -0
- package/docs/migration-playbook.md +152 -0
- package/docs/migration-verification.md +177 -0
- package/docs/releases/3.6.0.md +43 -0
- package/docs/releases/3.7.0.md +53 -0
- package/package.json +11 -3
package/docs/acp.md
ADDED
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
# Editors: Agent Client Protocol (ACP)
|
|
2
|
+
|
|
3
|
+
Calliope can run as an [Agent Client Protocol](https://agentclientprotocol.com)
|
|
4
|
+
agent, so ACP-speaking editors — [Zed](https://zed.dev), JetBrains IDEs, Neovim,
|
|
5
|
+
and others — can drive it as a coding agent without any Calliope-specific plugin.
|
|
6
|
+
One command, `calliope acp`, speaks JSON-RPC 2.0 over stdio.
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
calliope acp
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
The subcommand is not meant to be run by hand: the editor launches it, writes
|
|
13
|
+
JSON-RPC to its stdin, and reads notifications from its stdout. **stdout carries
|
|
14
|
+
the protocol; all logs go to stderr**, so nothing corrupts the stream.
|
|
15
|
+
|
|
16
|
+
It reuses the same agent core as everything else in Calliope — the provider chat
|
|
17
|
+
loop, the tool runtime, the pre-tool policy hook, and the audit run log — so an
|
|
18
|
+
ACP session behaves like a headless or interactive session, just driven by your
|
|
19
|
+
editor.
|
|
20
|
+
|
|
21
|
+
The maintained SDK validates protocol messages with the pinned Zod runtime.
|
|
22
|
+
The SDK package version is independent of the negotiated ACP version; this
|
|
23
|
+
integration continues to use stable ACP v1, not the experimental v2 entrypoint.
|
|
24
|
+
Incoming messages are bounded before schema validation: 64 nested levels, 16,384
|
|
25
|
+
values, 4,096 members per collection and 32 MiB of string data. The NDJSON
|
|
26
|
+
transport also enforces its 32 MiB message limit. Over-limit requests receive an invalid-parameters response without creating a
|
|
27
|
+
session or starting inference; oversized notifications are discarded and
|
|
28
|
+
oversized replies fail the waiting request.
|
|
29
|
+
|
|
30
|
+
## What works (baseline conformance)
|
|
31
|
+
|
|
32
|
+
The [baseline ACP agent surface](https://agentclientprotocol.com/protocol/overview#agent)
|
|
33
|
+
is implemented and tested against the official TypeScript SDK
|
|
34
|
+
(`@agentclientprotocol/sdk`, stable ACP v1 entrypoint):
|
|
35
|
+
|
|
36
|
+
| Method / flow | Status | Notes |
|
|
37
|
+
|---|---|---|
|
|
38
|
+
| `initialize` | ✅ | Negotiates protocol v1; advertises agent capabilities |
|
|
39
|
+
| `authenticate` | ✅ | No-op — Calliope authenticates via locally-configured provider keys |
|
|
40
|
+
| `session/new` | ✅ | One Calliope session per ACP session; the session id round-trips |
|
|
41
|
+
| `session/load` | ✅ | Restores a saved session in its project and replays its history (see *Loading a session*) |
|
|
42
|
+
| `session/set_mode` | ✅ | Session-scoped Work and Plan modes |
|
|
43
|
+
| `session/set_config_option` | ✅ | Selects a discovered model for this session |
|
|
44
|
+
| `session/prompt` | ✅ | Drives the agent loop (chat + tools) to a stop reason |
|
|
45
|
+
| `session/cancel` | ✅ | Aborts provider I/O and pending permission waits; returns `stopReason: cancelled` |
|
|
46
|
+
| `session/update` (streaming) | ✅ | `agent_message_chunk`, `tool_call`, `tool_call_update`; `user_message_chunk` in a replay |
|
|
47
|
+
| `session/request_permission` | ✅ | Asked for mutating/destructive tools (see below) |
|
|
48
|
+
| `fs/read_text_file`, `fs/write_text_file` | ✅ | Preferred for file tools when the client advertises `fs` |
|
|
49
|
+
|
|
50
|
+
### Capability matrix
|
|
51
|
+
|
|
52
|
+
**Advertised by Calliope (agent):**
|
|
53
|
+
|
|
54
|
+
| Capability | Value |
|
|
55
|
+
|---|---|
|
|
56
|
+
| `promptCapabilities.image` / `audio` / `embeddedContext` | `false` — text and resource links only |
|
|
57
|
+
| `loadSession` | `true`; see *Loading a session* |
|
|
58
|
+
| `authMethods` | `[]` — no authentication required |
|
|
59
|
+
|
|
60
|
+
**Consumed from the client (editor):**
|
|
61
|
+
|
|
62
|
+
| Client capability | Effect |
|
|
63
|
+
|---|---|
|
|
64
|
+
| `fs.readTextFile` | `read_file` / `edit_file` read the editor's buffer instead of disk |
|
|
65
|
+
| `fs.writeTextFile` | `write_file` / `edit_file` write through the editor instead of disk |
|
|
66
|
+
| `requestPermission` | Used to gate mutating tools; falls back to *deny* if unavailable |
|
|
67
|
+
| `terminal` | Not used yet — Calliope runs shell tools itself |
|
|
68
|
+
|
|
69
|
+
### Permissions
|
|
70
|
+
|
|
71
|
+
Read-only tools (`read_file`, `list_files`, `glob`, `grep`, `web_search`,
|
|
72
|
+
`think`) run without asking. Tools that mutate state or that Calliope's risk model
|
|
73
|
+
flags for confirmation (`write_file`, `edit_file`, `shell`, `git`, `execute_code`,
|
|
74
|
+
and any high/critical-risk command) trigger a `session/request_permission` call so
|
|
75
|
+
your editor can prompt you. If the client can't handle a permission request, the
|
|
76
|
+
non-interactive default is to **deny** the mutating tool (read-only tools still
|
|
77
|
+
run).
|
|
78
|
+
|
|
79
|
+
Scope, **pre-tool hooks** and the external **policy hook** (the
|
|
80
|
+
[Zentinelle](./governance.md) integration point) run before the prompt and again
|
|
81
|
+
after approval. A denial prevents execution and is reported to the model.
|
|
82
|
+
|
|
83
|
+
`allow` approves once. For eligible file operations, `allow_always` means the
|
|
84
|
+
exact arguments and canonical path in this ACP session for at most 24 hours;
|
|
85
|
+
changed arguments or policy configuration need a new approval. Shell, code and
|
|
86
|
+
plugin operations offer only once/reject. Unknown option IDs are rejected.
|
|
87
|
+
Session grants disappear on process restart; existing project grants may apply
|
|
88
|
+
but ACP does not create project grants. See [permissions](./permissions.md) for
|
|
89
|
+
scope, revocation and audit semantics.
|
|
90
|
+
|
|
91
|
+
### Loading a session
|
|
92
|
+
|
|
93
|
+
`session/load` restores a session this agent saved, including after the agent or
|
|
94
|
+
its host restarts. Every turn already checkpoints a verified
|
|
95
|
+
[recovery snapshot](./session-recovery.md), and `session/new` commits the first
|
|
96
|
+
one, so a session that was never prompted loads too.
|
|
97
|
+
|
|
98
|
+
- Pass the ID from `session/new` and the same `cwd`. A session loads only in its
|
|
99
|
+
recorded project; an unknown ID or a missing or damaged snapshot is refused.
|
|
100
|
+
- Before responding, Calliope replays the conversation as `session/update`
|
|
101
|
+
notifications: `user_message_chunk`, `agent_message_chunk`, `tool_call`, then a
|
|
102
|
+
`tool_call_update` carrying the recorded result. The system prompt is not
|
|
103
|
+
replayed.
|
|
104
|
+
- A tool call without a recorded result is closed as an unknown outcome and
|
|
105
|
+
replays as `failed`, as do recorded tool errors. No tool or inference is
|
|
106
|
+
replayed; an `agent_thought_chunk` says so when work was interrupted or
|
|
107
|
+
retention omitted older messages.
|
|
108
|
+
- A load is refused while a prompt runs in that session. Provider and model
|
|
109
|
+
preferences resolve for `cwd` as they do for `session/new`, with any explicit
|
|
110
|
+
saved ACP model selection applied to that session. Session approvals do not
|
|
111
|
+
survive a restart.
|
|
112
|
+
|
|
113
|
+
### Session modes and models
|
|
114
|
+
|
|
115
|
+
New and loaded sessions return `modes` and `configOptions`. `session/set_mode`
|
|
116
|
+
is advertised through `agentCapabilities._meta.calliopeSessionControls.version: 1` and
|
|
117
|
+
selects `work` (normal permissions and confirmations) or `plan` (the core's
|
|
118
|
+
read-only planning tools). Plan mode refuses workspace mutation, shell/code
|
|
119
|
+
execution and other non-planning tools before effects, including editor-buffer
|
|
120
|
+
writes. Planning may still write native conversation/audit state. Returning to
|
|
121
|
+
Work does not grant permission to bypass project policy or a parent allowance.
|
|
122
|
+
|
|
123
|
+
Model selection uses stable ACP v1 `session/set_config_option`, with
|
|
124
|
+
`configId: "model"`; the older `session/set_model` method is not used. Select an
|
|
125
|
+
advertised value, or `default` to use the configured preference. Options come
|
|
126
|
+
from live model discovery for the session's resolved provider. Discovery is
|
|
127
|
+
bounded to five seconds and may use its current cache; unavailable discovery
|
|
128
|
+
does not invent selectable models. It may query provider catalog metadata when
|
|
129
|
+
creating/loading a session or changing its model, but does not run inference.
|
|
130
|
+
|
|
131
|
+
Mode and explicit model selections are stored with the native session and
|
|
132
|
+
survive `session/load`. Changes affect no other session or global/project
|
|
133
|
+
configuration. Busy sessions refuse changes; stale or damaged control state
|
|
134
|
+
requires reload or restoration. Delegated sessions retain parent model control
|
|
135
|
+
and refuse independent model selection. Mode changes recheck their live parent
|
|
136
|
+
authority, and every subsequent tool/model request retains native admission.
|
|
137
|
+
|
|
138
|
+
### Client-side filesystem
|
|
139
|
+
|
|
140
|
+
When your editor advertises the `fs` capability, Calliope routes `read_file`,
|
|
141
|
+
`write_file`, and `edit_file` through the editor's `fs/read_text_file` and
|
|
142
|
+
`fs/write_text_file` rather than touching local disk. This is the marquee ACP
|
|
143
|
+
behavior: edits apply to the buffer you are actually looking at — including
|
|
144
|
+
**unsaved changes** — instead of the last-saved bytes on disk. Without the `fs`
|
|
145
|
+
capability, file tools use local disk as usual.
|
|
146
|
+
|
|
147
|
+
### Audit
|
|
148
|
+
|
|
149
|
+
Every ACP session writes the same tamper-evident audit run log as any other
|
|
150
|
+
Calliope session, tagged `mode: acp` in its `run_start` event. Inspect one with
|
|
151
|
+
`calliope replay <sessionId>` (see [governance](./governance.md)).
|
|
152
|
+
|
|
153
|
+
## Configuring your editor
|
|
154
|
+
|
|
155
|
+
The provider and model come from your Calliope config (`defaultProvider` /
|
|
156
|
+
`defaultModel`) or the usual `*_API_KEY` environment variables — configure those
|
|
157
|
+
first (`calliope --setup`), exactly as for interactive use.
|
|
158
|
+
|
|
159
|
+
### Zed
|
|
160
|
+
|
|
161
|
+
Add an agent server to your Zed `settings.json`. Point it at the `calliope`
|
|
162
|
+
binary (or `node /absolute/path/to/dist/bin.js`) with the `acp` argument:
|
|
163
|
+
|
|
164
|
+
```json
|
|
165
|
+
{
|
|
166
|
+
"agent_servers": {
|
|
167
|
+
"Calliope": {
|
|
168
|
+
"command": "calliope",
|
|
169
|
+
"args": ["acp"],
|
|
170
|
+
"env": {
|
|
171
|
+
"ANTHROPIC_API_KEY": "sk-ant-..."
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
Then pick **Calliope** from the agent panel's agent menu. See Zed's
|
|
179
|
+
[External Agents](https://zed.dev/docs/ai/external-agents) docs.
|
|
180
|
+
|
|
181
|
+
### JetBrains
|
|
182
|
+
|
|
183
|
+
JetBrains IDEs speak ACP through the AI Assistant / external-agent integration.
|
|
184
|
+
Register an external ACP agent with the command `calliope` and argument `acp`
|
|
185
|
+
(and the provider key in the environment), then select Calliope as the agent.
|
|
186
|
+
The exact settings path varies by IDE version; consult your IDE's ACP/external
|
|
187
|
+
agent documentation.
|
|
188
|
+
|
|
189
|
+
### Any ACP client
|
|
190
|
+
|
|
191
|
+
Any client that can launch a stdio ACP agent works the same way: run the command
|
|
192
|
+
`calliope acp` with a configured provider key in the environment.
|
|
193
|
+
|
|
194
|
+
## Not yet done
|
|
195
|
+
|
|
196
|
+
- **Registry listing.** Submitting Calliope to the public ACP agent registry is
|
|
197
|
+
deferred to a later release.
|
|
198
|
+
- **MCP servers over ACP.** `session/new` and `session/load` accept an
|
|
199
|
+
`mcpServers` list; Calliope ignores it for now and uses its own MCP configuration.
|
|
200
|
+
- **Terminals, images, and audio** in prompts/tool calls.
|
|
201
|
+
|
|
202
|
+
## Verification status
|
|
203
|
+
|
|
204
|
+
Code-level conformance is tested against the official ACP TypeScript SDK: the
|
|
205
|
+
handshake, session lifecycle, streaming updates, the permission round-trip (grant
|
|
206
|
+
and deny), mid-prompt cancellation, and client-side filesystem delegation are all
|
|
207
|
+
covered by in-process tests that drive the SDK's client against the agent
|
|
208
|
+
(`tests/acp.test.ts`, `tests/acp-fs-delegate.test.ts`). `tests/acp-stdio.test.ts`
|
|
209
|
+
runs the built CLI over stdio, kills it after a turn and loads the session in a
|
|
210
|
+
new process. A live editor smoke test
|
|
211
|
+
in Zed and JetBrains is pending and tracked on the release checklist.
|
|
212
|
+
|
|
213
|
+
## Cancellation and instructions
|
|
214
|
+
|
|
215
|
+
Each session owns one active prompt. Concurrent prompts in the same session are
|
|
216
|
+
rejected; a completed cancellation permits a new prompt. Late permission replies
|
|
217
|
+
cannot authorize tools from a cancelled turn. Cancellation preserves assistant /
|
|
218
|
+
tool-result pairing for the next request. It cannot undo completed writes or
|
|
219
|
+
retract remote operations; see [cancellation limits](./features.md#cancellation).
|
|
220
|
+
|
|
221
|
+
Trusted [repository instructions](./instructions.md) load from the session's
|
|
222
|
+
`cwd` when the session is created.
|
|
223
|
+
|
|
224
|
+
ACP forwards append-only assistant chunks. A partial stream failure returns the
|
|
225
|
+
existing JSON-RPC error without automatically repeating those chunks; an explicit
|
|
226
|
+
later prompt continues from committed conversation state. Bounded tool output
|
|
227
|
+
is available locally through `calliope session outputs SESSION_ID --json`. See
|
|
228
|
+
[streaming and output storage](streaming.md); no ACP message schema is changed.
|
|
@@ -0,0 +1,331 @@
|
|
|
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, explicit reviewed provider/model choices and the host's
|
|
53
|
+
output cap. The provider/model check uses the current admitted graph and runs
|
|
54
|
+
again under the ledger writer lock before a new reservation commits. Existing requests can still settle
|
|
55
|
+
after owner cancellation; grant revocation and token expiry retain their existing
|
|
56
|
+
semantics.
|
|
57
|
+
|
|
58
|
+
The HTTP grant operation only returns credentials for an **exact, already admitted**
|
|
59
|
+
native child grant. It cannot create a proposal, approve children, bypass native
|
|
60
|
+
depth/count limits or promote an interrupted ledger grant into the execution graph.
|
|
61
|
+
Use the existing native proposal review/admission flow first. Reissuing a credential
|
|
62
|
+
preserves its account, deadline and all recorded spending; revoked grants stay revoked.
|
|
63
|
+
|
|
64
|
+
All owners of a run share its private signing key and revocation history. A native
|
|
65
|
+
writer lock serializes revocations from separate processes; only confirmed dead locks
|
|
66
|
+
are reclaimed. Malformed, missing, public or linked revocation/key files are refused.
|
|
67
|
+
New keys initialize an empty revocation history once. A retained legacy key without
|
|
68
|
+
that history requires verified restoration or an explicit owner-managed credential
|
|
69
|
+
rotation; opening it never silently treats missing revocations as an empty history.
|
|
70
|
+
|
|
71
|
+
This is reviewed ledger hosting, not automatic Cykick/Astrolift enrollment. Remote
|
|
72
|
+
workspace identity, dispatcher credential delivery, task-attempt ownership, transport
|
|
73
|
+
reachability and any narrower Cykick file-mutation policy still need their native
|
|
74
|
+
bindings. A loopback listener does not make a desktop reachable from a remote pod.
|
|
75
|
+
|
|
76
|
+
## Run a delegated child
|
|
77
|
+
|
|
78
|
+
A host (Cy, an Astrolift task) grants the child, writes its scoped token to a private file and
|
|
79
|
+
starts a headless run or native ACP process:
|
|
80
|
+
|
|
81
|
+
```sh
|
|
82
|
+
calliope --headless --json --ledger-url URL --ledger-token-file /private/child.token \
|
|
83
|
+
--ledger-agent CHILD_ACCOUNT "objective"
|
|
84
|
+
|
|
85
|
+
calliope acp --ledger-url URL --ledger-token-file /private/child.token \
|
|
86
|
+
--ledger-agent CHILD_ACCOUNT
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
The turn runs under `ExecutionGuard` with the parent's ledger: the child's tools, paths, deadline
|
|
90
|
+
and budget come from its grant, and every provider request is reserved and settled with the
|
|
91
|
+
parent. A revoked or unknown grant, or an unreachable parent, stops the child before any turn.
|
|
92
|
+
The three flags go together, using separate flag/value arguments. Partial, repeated,
|
|
93
|
+
unknown or equals-form ledger flags fail before execution; they never select an
|
|
94
|
+
undelegated fallback.
|
|
95
|
+
|
|
96
|
+
## Operations
|
|
97
|
+
|
|
98
|
+
`POST /v1/<op>` with `Authorization: Bearer <token>` and a JSON body.
|
|
99
|
+
|
|
100
|
+
| Op | Who | Effect |
|
|
101
|
+
| --- | --- | --- |
|
|
102
|
+
| `hello` | any | protocol and operations |
|
|
103
|
+
| `journal` | any | the full hash-chained history (`manifest`, `events`) |
|
|
104
|
+
| `execution` | account owner | verify `{agentId, project: {root, key}}` against the retained owner grant and return its native workspace binding |
|
|
105
|
+
| `reserve` | owner of `reservation.agentId` | charge before dispatch; same id replays the original admission |
|
|
106
|
+
| `settle` | owner of the reserved request | record usage or an outcome; same settlement replays |
|
|
107
|
+
| `grant` | parent, or a child for its own accounts | allocate child accounts; returns the child's scoped token |
|
|
108
|
+
| `revoke` | parent | permanently fence a grant and every descendant |
|
|
109
|
+
|
|
110
|
+
A token may act for its accounts and their descendants only. A child cannot charge a sibling or
|
|
111
|
+
the root, cannot mint a root allowance, and a revoked grant cannot be reissued. Errors carry the
|
|
112
|
+
ledger's codes (`budget`, `deadline`, `authority`, `conflict`, `limit`, `locked`, `unavailable`).
|
|
113
|
+
|
|
114
|
+
Admission rechecks token expiry and grant revocation while holding the ledger's
|
|
115
|
+
writer lock, immediately before committing a reservation or nested grant. A
|
|
116
|
+
request queued before revocation cannot acquire authority when the lock opens.
|
|
117
|
+
|
|
118
|
+
An embedded owner can also supply `createLedgerServer({ledger, cwd, state,
|
|
119
|
+
assertAuthority: execution.assertAuthority})`, using the handle returned by
|
|
120
|
+
`prepareAgentExecution`. The server rechecks this trusted callback before new
|
|
121
|
+
admission and under the writer lock, including grant reissue. Cancelling the
|
|
122
|
+
native reviewed run then fences remote reservations and grants even before a
|
|
123
|
+
coordinator journal exists. Once the journal exists, completing the run or stopping
|
|
124
|
+
the handle's selected agent (or an ancestor) through an explicit stop control also
|
|
125
|
+
fences new work. Reopening the handle does not bypass those controls; an independently active sibling remains
|
|
126
|
+
eligible under its own handle. These checks reuse native execution history.
|
|
127
|
+
The callback is host code, never a request argument.
|
|
128
|
+
The standalone `ledger serve --budget ...` command serves an explicitly selected
|
|
129
|
+
raw ledger; it does not infer a reviewed-run binding.
|
|
130
|
+
|
|
131
|
+
Owner cancellation, agent stops and run completion still permit authenticated
|
|
132
|
+
journal inspection, replay of an already admitted reservation, and settlement
|
|
133
|
+
of existing requests. These reconcile
|
|
134
|
+
prior work; they do not authorize another provider call. Unknown/cancelled usage
|
|
135
|
+
retains its reserved charge. Token expiry and grant revocation continue to apply
|
|
136
|
+
to every operation, so a revoked child needs its owner to reconcile its requests.
|
|
137
|
+
|
|
138
|
+
## Client behaviour
|
|
139
|
+
|
|
140
|
+
`RemoteReservationLedger` gives `ExecutionGuard` the same read/reserve/settle surface as the local
|
|
141
|
+
ledger. It replays and verifies the hash chain itself and refuses any history that is not an
|
|
142
|
+
append-only extension of what it has seen, so a server reset or rollback cannot return spent
|
|
143
|
+
capacity. Writes retry with the same id; if every attempt is lost it inspects the journal, and
|
|
144
|
+
only an outcome the parent recorded counts. Otherwise the result is `unavailable` and nothing is
|
|
145
|
+
authorized (a reservation that was admitted stays charged).
|
|
146
|
+
|
|
147
|
+
The verified history is checkpointed atomically beneath the client's private
|
|
148
|
+
`root` as `verified-parent/history.json`. Reuse that root after reconnect or
|
|
149
|
+
restart. A missing, damaged, public or linked history file is an error; it is
|
|
150
|
+
never replaced with an empty allowance. Concurrent clients retain the longest
|
|
151
|
+
verified history, so an older response cannot overwrite a newer checkpoint.
|
|
152
|
+
The checkpoint contains no bearer token and never admits a provider request by
|
|
153
|
+
itself. Only the parent service can reserve or settle usage.
|
|
154
|
+
|
|
155
|
+
Headless and ACP children keep this state under `~/.calliope-cli/delegation-ledgers`,
|
|
156
|
+
keyed by the canonical project, configured token-file location and account. Rotating
|
|
157
|
+
the token or its projected-secret symlink at that location preserves verified history; restarting against a
|
|
158
|
+
rolled-back parent stops before the turn starts. Keep this directory on the
|
|
159
|
+
child's persistent private volume when running in a container. A new configured
|
|
160
|
+
token path is a separate connection, not recovery of the old one. These client
|
|
161
|
+
checkpoints do not by themselves wire Astrolift task admission or cancellation
|
|
162
|
+
to the ledger service.
|
|
163
|
+
|
|
164
|
+
The shared project budget also retains its reservation while admission is unknown.
|
|
165
|
+
An error releases project capacity only after a confirmed rejection before any
|
|
166
|
+
lost response. Even a fresh journal can lag an in-flight admission. Neither a
|
|
167
|
+
disconnect nor restarting the child restores the reserved project capacity.
|
|
168
|
+
Reservation errors optionally report `admission: refused` when the server has
|
|
169
|
+
verified non-admission after the local operation ends, or `unknown` otherwise.
|
|
170
|
+
Clients retain capacity when talking to older v1 servers that omit this evidence.
|
|
171
|
+
|
|
172
|
+
## Owner-bound remote workspaces
|
|
173
|
+
|
|
174
|
+
A copied checkout has a different path and filesystem identity. It cannot use a
|
|
175
|
+
parent grant just because its files look the same. The ledger owner may issue a
|
|
176
|
+
version 2 child grant with `project: {root, key}`, captured using the CLI's
|
|
177
|
+
`projectIdentity()` on the intended child host. The existing proposal hash,
|
|
178
|
+
review revision and native run manifest references remain part of that immutable
|
|
179
|
+
grant. The trusted host must establish the identity and authorize the binding;
|
|
180
|
+
model output or an unauthenticated workspace claim is not sufficient.
|
|
181
|
+
|
|
182
|
+
Only a parent token may issue these workspace grants. Child-issued version 1
|
|
183
|
+
grants inherit the nearest owner-bound workspace, and cannot change it. Workspace
|
|
184
|
+
grants use reservation event version 5 and projection version 4; existing grant
|
|
185
|
+
events, manifests and hashes are unchanged. A restarted client replays the same
|
|
186
|
+
grant through its retained verified checkpoint.
|
|
187
|
+
|
|
188
|
+
Headless and ACP invocations negotiate `execution` before starting their turn. The server
|
|
189
|
+
checks the token's account scope, live owner authority and exact project identity.
|
|
190
|
+
The client independently checks the response against the native journal and its
|
|
191
|
+
actual local directory. Missing protocol support, another account, a substituted
|
|
192
|
+
binding or a replaced directory stops execution. Library callers opt in with
|
|
193
|
+
`RemoteReservationLedger.connect({..., execution: {cwd, agentId}})`.
|
|
194
|
+
|
|
195
|
+
File and brain-path checks use the bound child root and key, with the original
|
|
196
|
+
relative tool/path grants. Filesystem separators are normalized for grant checks;
|
|
197
|
+
parent traversal and symlink aliases remain denied. The immutable source budget
|
|
198
|
+
manifest, account ancestry, reservations and deadline remain on the parent ledger.
|
|
199
|
+
The checkpoint stays outside the child's project, and local project spending
|
|
200
|
+
limits still apply. Binding a folder does not copy files, mount a volume, import
|
|
201
|
+
brain content, install credentials or create another allowance.
|
|
202
|
+
|
|
203
|
+
The protocol now supports explicit workspace identity binding. Astrolift must
|
|
204
|
+
still establish that identity from its native runtime authority, enroll the task
|
|
205
|
+
under its owner, and connect lifecycle cancellation and funding. The raw ledger
|
|
206
|
+
service and a parent task UUID do not establish those bindings automatically.
|
|
207
|
+
|
|
208
|
+
`tests/delegation-ledger.test.ts` is the local-host conformance suite: concurrent and nested
|
|
209
|
+
children exhausting one allowance, duplicate dispatch and lost acknowledgements, an unreachable
|
|
210
|
+
parent, restart and rollback, revocation of a child and its descendants, foreign runs, siblings
|
|
211
|
+
and forged tokens, and `ExecutionGuard` admission through the parent.
|
|
212
|
+
|
|
213
|
+
### Runner capability negotiation
|
|
214
|
+
|
|
215
|
+
`calliope --version --json` is an offline, credential-free probe.
|
|
216
|
+
`headless: {protocol: 1, delegation: 1, workspaceBinding: 1}` advertises
|
|
217
|
+
NDJSON terminal events, native parent-ledger admission and owner-bound workspace
|
|
218
|
+
validation. Embedders must verify these fields before supplying delegated tasks;
|
|
219
|
+
a matching package version alone does not establish those capabilities. This
|
|
220
|
+
probe does not grant authority: each invocation still negotiates with the live
|
|
221
|
+
parent and validates its token, journal and workspace before inference.
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
### Native ACP session continuity
|
|
225
|
+
|
|
226
|
+
ACP connects to the parent's ledger before opening its protocol transport. The
|
|
227
|
+
process has one trusted execution context; `session/new` and `session/load` cannot
|
|
228
|
+
replace it through client parameters. `initialize` advertises
|
|
229
|
+
`agentCapabilities._meta.calliopeDelegation` with `version: 1`,
|
|
230
|
+
`workspaceBinding: 1` and `sessionBinding: 1`. A host must negotiate this metadata
|
|
231
|
+
before relying on delegated ACP behavior.
|
|
232
|
+
|
|
233
|
+
New delegated sessions retain a versioned restriction containing the original
|
|
234
|
+
manifest hash and account ID in private session metadata. Saving a conversation
|
|
235
|
+
or creating a manual/safety branch preserves it. This marker does not mint a
|
|
236
|
+
grant, reserve tokens or confer authority. Loading requires the same live ledger
|
|
237
|
+
and account, an exact workspace match and an unexpired original deadline. A
|
|
238
|
+
plain ACP process cannot load a bound session, and a delegated process cannot
|
|
239
|
+
attach its allowance to old unbound history. The shared turn engine also checks
|
|
240
|
+
the restriction before inference through other clients.
|
|
241
|
+
|
|
242
|
+
Follow-up prompts use the original account's reservations, costs and clock.
|
|
243
|
+
Native one-time approvals, tool results, cancellation and protocol replay remain
|
|
244
|
+
in use. Automatic project memory/context is filtered through the granted read
|
|
245
|
+
scope before inclusion in the system prompt; project trust alone does not widen
|
|
246
|
+
that scope. Operator-owned global preferences remain trusted configuration.
|
|
247
|
+
|
|
248
|
+
This is a CLI capability, not completed Astrolift enrollment. The runtime adapter
|
|
249
|
+
must still pass the trusted tuple, retain its task binding across restarts, verify
|
|
250
|
+
the capability and connect owner lifecycle/funding. Retained metadata is a
|
|
251
|
+
restriction within the private store, not protection against an administrator
|
|
252
|
+
rewriting that store or explicitly transferring conversation content elsewhere.
|
|
253
|
+
|
|
254
|
+
### Private reverse transport for hosted tasks
|
|
255
|
+
|
|
256
|
+
The execution API exports `LEDGER_TUNNEL_CAPABILITY`, `attachLedgerTunnel` (owner)
|
|
257
|
+
and `listenLedgerTunnel` (task). The owner injects an authenticated, non-replayed
|
|
258
|
+
duplex exec connection; ordinary HTTP framing and backpressure carry only native
|
|
259
|
+
ledger requests. The owner opens no public listener. The task binds its original
|
|
260
|
+
loopback port, and never picks another port after a conflict. This does not yet
|
|
261
|
+
supply an Astrolift websocket endpoint or its task-placement authorization.
|
|
262
|
+
|
|
263
|
+
Both ends pin the original child credential's SHA-256, reviewed audience, run,
|
|
264
|
+
grant and expiration. Parent/replacement credentials are refused before task
|
|
265
|
+
traffic enters the exec stream. Claims are restrictions, not authentication:
|
|
266
|
+
the existing native server still verifies the signature, current grant, workspace
|
|
267
|
+
and account controls. The owner URL must be its trusted reviewed loopback host;
|
|
268
|
+
requests cannot choose another URL, follow redirects or invoke revocation.
|
|
269
|
+
|
|
270
|
+
Requests retain the native 256 KiB limit. Responses stream with a 32 MiB bound
|
|
271
|
+
for the bounded journal and envelope. There is one task request in flight;
|
|
272
|
+
heartbeats, request deadlines, stream closure and the original credential expiry
|
|
273
|
+
close both ends on loss of the owner. Bridge failures never assert non-admission.
|
|
274
|
+
The remote ledger retains unknown charges and retries the original request ID.
|
|
275
|
+
|
|
276
|
+
Reconnect attaches a new authorized stream to the original task port and native
|
|
277
|
+
stores, using the same credential and child checkpoint. It must not mint another
|
|
278
|
+
grant or replace a task binding. The trusted host must revalidate task identity,
|
|
279
|
+
placement and caller access through `assertConnection`, and abort the connection
|
|
280
|
+
when that lease ends. Do not use terminal replay, chat events or logs for these
|
|
281
|
+
streams: request headers contain the child bearer credential. The API performs
|
|
282
|
+
no task enrollment, credential persistence, scheduling or independent accounting.
|
|
283
|
+
|
|
284
|
+
### Live execution authority
|
|
285
|
+
|
|
286
|
+
A retained journal proves accounting history, not current permission to execute.
|
|
287
|
+
Delegated clients revalidate the exact account and workspace through `execution`
|
|
288
|
+
before model requests and tool effects, and again before committing staged file
|
|
289
|
+
bytes. Revoked grants, stopped owners and an unreachable authority refuse further
|
|
290
|
+
work even when cached history is readable. Reconciliation reads do not restore
|
|
291
|
+
execution permission or release unresolved reservations.
|
|
292
|
+
|
|
293
|
+
|
|
294
|
+
### Runnable host conformance example
|
|
295
|
+
|
|
296
|
+
Run `npm run test:reviewed-host` from the source checkout. The example at
|
|
297
|
+
`scripts/qualification/reviewed-host.mjs` creates a reviewed native run, serves
|
|
298
|
+
its parent ledger over HTTP and launches two concurrent built headless CLI
|
|
299
|
+
processes with separate account-scoped credentials against a deterministic local
|
|
300
|
+
inference endpoint. Each account ledger is also served by its own CLI process,
|
|
301
|
+
which is stopped and recreated during the restart check. Both children settle
|
|
302
|
+
into one parent allowance. Retained unknown requests then exhaust that allowance;
|
|
303
|
+
a host restart preserves them, and real CLI invocations refuse exhausted,
|
|
304
|
+
foreign-workspace, sibling-account and cancelled authority without another
|
|
305
|
+
inference request.
|
|
306
|
+
It uses private disposable configuration and makes no paid provider requests.
|
|
307
|
+
|
|
308
|
+
To qualify a standalone artifact built from the same source:
|
|
309
|
+
|
|
310
|
+
```sh
|
|
311
|
+
npm run build
|
|
312
|
+
bun packaging/build-binary.mjs --native
|
|
313
|
+
CALLIOPE_REVIEWED_HOST_BINARY="$PWD/packaging/dist/calliope-native" \
|
|
314
|
+
node scripts/qualification/reviewed-host.mjs
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
To qualify an extracted npm tarball with its production dependencies installed,
|
|
318
|
+
set `CALLIOPE_REVIEWED_HOST_PACKAGE` to that package directory instead. Both the
|
|
319
|
+
host library and all child processes then use the extracted package. The package
|
|
320
|
+
and standalone-binary options are mutually exclusive.
|
|
321
|
+
|
|
322
|
+
The executable reports its tested artifact type and invariant results as JSON.
|
|
323
|
+
This is a local HTTP host example, not a deployed Astrolift acceptance test.
|
|
324
|
+
Use `delegation-ledger/v1`, reviewed host capability version 1 and the headless
|
|
325
|
+
capability tuple above; a matching package version alone is insufficient.
|
|
326
|
+
The current CLI entry point requests a 4096-token output limit, so the reviewed
|
|
327
|
+
host and discovered model must both permit that bound. Lower output caps are
|
|
328
|
+
available to library callers through `DelegatedExecutionOptions.maxOutputTokens`.
|
|
329
|
+
The existing ledger, workspace and session suites cover nested grants, lost
|
|
330
|
+
acknowledgments, rollback and approval/session replay; those are separate from
|
|
331
|
+
this example's process-level assertions.
|