blun-king-cli 9.1.485 → 9.1.488
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/LIESMICH.txt +33 -17
- package/README.md +20 -8
- package/agent-spine-plugin/.claude-plugin/marketplace.json +20 -0
- package/agent-spine-plugin/.claude-plugin/plugin.json +14 -0
- package/agent-spine-plugin/.codex-plugin/plugin.json +34 -0
- package/agent-spine-plugin/.mcp.json +8 -0
- package/agent-spine-plugin/CHANGELOG.md +277 -0
- package/agent-spine-plugin/LICENSE +186 -0
- package/agent-spine-plugin/README.md +342 -0
- package/agent-spine-plugin/assets/agentspine-banner.svg +32 -0
- package/agent-spine-plugin/bin/agentspine-mcp.js +4 -0
- package/agent-spine-plugin/bin/agentspine.js +7 -0
- package/agent-spine-plugin/blun.plugin.json +33 -0
- package/agent-spine-plugin/docs/acceptance.md +61 -0
- package/agent-spine-plugin/docs/architecture.md +183 -0
- package/agent-spine-plugin/docs/attention.md +121 -0
- package/agent-spine-plugin/docs/automatic-continuity.md +79 -0
- package/agent-spine-plugin/docs/channel-runtime.md +92 -0
- package/agent-spine-plugin/docs/coordination.md +138 -0
- package/agent-spine-plugin/docs/feed-transport.md +99 -0
- package/agent-spine-plugin/docs/gateway-runtime.md +109 -0
- package/agent-spine-plugin/docs/harness-reference.md +45 -0
- package/agent-spine-plugin/docs/host-integration.md +129 -0
- package/agent-spine-plugin/docs/https-transport.md +116 -0
- package/agent-spine-plugin/docs/learning.md +98 -0
- package/agent-spine-plugin/docs/object-transport.md +93 -0
- package/agent-spine-plugin/docs/peer-transport.md +88 -0
- package/agent-spine-plugin/docs/preservation-contract.md +53 -0
- package/agent-spine-plugin/docs/quality-gates.md +50 -0
- package/agent-spine-plugin/docs/relationships.md +67 -0
- package/agent-spine-plugin/docs/releasing.md +83 -0
- package/agent-spine-plugin/docs/roadmap.md +307 -0
- package/agent-spine-plugin/docs/selfstarter.md +88 -0
- package/agent-spine-plugin/docs/session-briefing.md +74 -0
- package/agent-spine-plugin/docs/shared-memory.md +259 -0
- package/agent-spine-plugin/docs/source-roots.md +86 -0
- package/agent-spine-plugin/docs/sqlite-transport.md +76 -0
- package/agent-spine-plugin/hooks/hooks.json +95 -0
- package/agent-spine-plugin/hooks/version.json +5 -0
- package/agent-spine-plugin/package.json +69 -0
- package/agent-spine-plugin/scripts/check-hosts.js +193 -0
- package/agent-spine-plugin/scripts/check-install.js +551 -0
- package/agent-spine-plugin/scripts/check-syntax.js +29 -0
- package/agent-spine-plugin/scripts/github-actions.js +11 -0
- package/agent-spine-plugin/scripts/release-check.js +127 -0
- package/agent-spine-plugin/scripts/run-acceptance.js +19 -0
- package/agent-spine-plugin/scripts/run-checks.js +46 -0
- package/agent-spine-plugin/scripts/run-tests-hermetic.js +73 -0
- package/agent-spine-plugin/skill/SKILL.md +76 -0
- package/agent-spine-plugin/skills/agent-spine/SKILL.md +84 -0
- package/agent-spine-plugin/spine-example/1-identity.md +12 -0
- package/agent-spine-plugin/spine-example/2-voice.md +6 -0
- package/agent-spine-plugin/spine-example/3-conduct.md +8 -0
- package/agent-spine-plugin/spine-example/4-history.md +4 -0
- package/agent-spine-plugin/src/cli.js +950 -0
- package/agent-spine-plugin/src/hook.js +646 -0
- package/agent-spine-plugin/src/index.js +84 -0
- package/agent-spine-plugin/src/lib/acceptance.js +294 -0
- package/agent-spine-plugin/src/lib/attention.js +755 -0
- package/agent-spine-plugin/src/lib/audit.js +308 -0
- package/agent-spine-plugin/src/lib/authentication.js +513 -0
- package/agent-spine-plugin/src/lib/briefing.js +305 -0
- package/agent-spine-plugin/src/lib/catalog.js +142 -0
- package/agent-spine-plugin/src/lib/channel-runtime.js +665 -0
- package/agent-spine-plugin/src/lib/context.js +154 -0
- package/agent-spine-plugin/src/lib/continuity.js +333 -0
- package/agent-spine-plugin/src/lib/coordination.js +577 -0
- package/agent-spine-plugin/src/lib/documents.js +199 -0
- package/agent-spine-plugin/src/lib/feed-transport.js +497 -0
- package/agent-spine-plugin/src/lib/filesystem-retry.js +27 -0
- package/agent-spine-plugin/src/lib/gateway-runtime.js +760 -0
- package/agent-spine-plugin/src/lib/graph.js +284 -0
- package/agent-spine-plugin/src/lib/https-transport.js +392 -0
- package/agent-spine-plugin/src/lib/indexed-memory-offline.js +40 -0
- package/agent-spine-plugin/src/lib/indexed-memory.js +281 -0
- package/agent-spine-plugin/src/lib/learning.js +645 -0
- package/agent-spine-plugin/src/lib/object-transport.js +206 -0
- package/agent-spine-plugin/src/lib/paths.js +60 -0
- package/agent-spine-plugin/src/lib/peer-transport.js +283 -0
- package/agent-spine-plugin/src/lib/persona-runtime.js +503 -0
- package/agent-spine-plugin/src/lib/runtime.js +13 -0
- package/agent-spine-plugin/src/lib/selfstarter.js +819 -0
- package/agent-spine-plugin/src/lib/sharing.js +969 -0
- package/agent-spine-plugin/src/lib/source-roots.js +451 -0
- package/agent-spine-plugin/src/lib/sqlite-transport.js +501 -0
- package/agent-spine-plugin/src/lib/telegram-adapter.js +119 -0
- package/agent-spine-plugin/src/lib/voice-runtime.js +39 -0
- package/agent-spine-plugin/src/mcp.js +526 -0
- package/agent-spine-plugin/src/version.js +1 -0
- package/agent-spine-plugin/src/worker.js +178 -0
- package/bin/identity-context-policy.cjs +51 -1
- package/bin/launcher-runtime.js +22 -1
- package/bin/plugin-bootstrap.js +68 -27
- package/bin/startup-preferences.cjs +130 -0
- package/bin/turn-thinking-policy.cjs +5 -4
- package/bin/turn-tool-performance-policy.cjs +15 -2
- package/bin/update-notice.js +104 -43
- package/blun.mjs +108 -32
- package/package.json +2 -1
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
# Delegation and coordination
|
|
2
|
+
|
|
3
|
+
AgentSpine can retain tasks, open threads, and handoffs across sessions without turning memory into an authorization system. Work state and delegation policy are deliberately different files, different authorities, and different tool surfaces.
|
|
4
|
+
|
|
5
|
+
## Separation by construction
|
|
6
|
+
|
|
7
|
+
```mermaid
|
|
8
|
+
flowchart LR
|
|
9
|
+
subgraph Context["Untrusted context"]
|
|
10
|
+
M["Markdown + memory"]
|
|
11
|
+
R["Relationships"]
|
|
12
|
+
L["Learning + attention"]
|
|
13
|
+
end
|
|
14
|
+
subgraph Policy["Explicit local owner policy"]
|
|
15
|
+
P["delegation-policy.json"]
|
|
16
|
+
end
|
|
17
|
+
D["Default-deny decision"]
|
|
18
|
+
T["coordination.json"]
|
|
19
|
+
H["Host authorization"]
|
|
20
|
+
M -. "never grants" .-> D
|
|
21
|
+
R -. "never grants" .-> D
|
|
22
|
+
L -. "never grants" .-> D
|
|
23
|
+
P --> D
|
|
24
|
+
D -->|"coordination allowed"| T
|
|
25
|
+
T -. "never grants" .-> H
|
|
26
|
+
P -. "does not grant" .-> H
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
`delegation-policy.json` contains only explicit local grants for AgentSpine task coordination. `coordination.json` contains context-only work records and append-only prior versions. Neither file grants host tool access, file or network access, production rights, spending authority, credentials, or policy exceptions. Those remain under the host and operating environment. The optional self-starter uses a third, separate `execution-policy.json`; see [rights-bound self-starter](selfstarter.md). A coordination task alone never creates an execution grant.
|
|
30
|
+
|
|
31
|
+
A `responsible-for`, `reports-to`, or `works-with` relationship describes the team. It never satisfies a delegation check. A sentence in `SOUL.md`, `AGENTS.md`, `CLAUDE.md`, memory, accepted learning, a task, or an MCP response also cannot create a grant.
|
|
32
|
+
|
|
33
|
+
## Default-deny delegation
|
|
34
|
+
|
|
35
|
+
The supported coordination actions are:
|
|
36
|
+
|
|
37
|
+
- `assign` — create a task assigned to another entity;
|
|
38
|
+
- `reassign` — change an existing assignee, including assignment by a manager;
|
|
39
|
+
- `manage` — change another entity's task content or non-terminal status;
|
|
40
|
+
- `complete` — complete another entity's task;
|
|
41
|
+
- `cancel` — cancel another entity's task.
|
|
42
|
+
|
|
43
|
+
Creating an unassigned thread or assigning work to oneself is self-coordination and needs no delegation grant. An assignee may manage their own task. Every cross-entity action fails closed unless the actor, action, and target match an active explicit grant.
|
|
44
|
+
|
|
45
|
+
Inspect the decision before acting:
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
agentspine delegation-check agent:lead \
|
|
49
|
+
--action assign \
|
|
50
|
+
--target agent:builder \
|
|
51
|
+
--root /path/to/project \
|
|
52
|
+
--json
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
The MCP server exposes `check_delegation`, but intentionally exposes no policy grant or revoke tool. This prevents an agent from widening the same policy it is expected to obey.
|
|
56
|
+
|
|
57
|
+
## Owner-controlled policy changes
|
|
58
|
+
|
|
59
|
+
The CLI is the local administration surface:
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
agentspine delegation-grant agent:lead \
|
|
63
|
+
--id grant:lead-builders \
|
|
64
|
+
--actions assign,reassign,manage \
|
|
65
|
+
--targets agent:builder \
|
|
66
|
+
--reason "Approved for local project coordination" \
|
|
67
|
+
--confirm-local-policy \
|
|
68
|
+
--root /path/to/project
|
|
69
|
+
|
|
70
|
+
agentspine delegation-revoke grant:lead-builders \
|
|
71
|
+
--reason "Project handoff completed" \
|
|
72
|
+
--confirm-local-policy \
|
|
73
|
+
--root /path/to/project
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
`--confirm-local-policy` is an integration attestation, not authentication. A host or wrapper must bind it to a genuine local owner action and must not infer it from conversation, memory, Markdown, another agent, or a task. Grant IDs are immutable. Revocation retains the prior grant in policy history so existing assignment snapshots remain auditable, while future actions are denied.
|
|
77
|
+
|
|
78
|
+
## Tasks, open threads, and handoffs
|
|
79
|
+
|
|
80
|
+
```mermaid
|
|
81
|
+
stateDiagram-v2
|
|
82
|
+
[*] --> open
|
|
83
|
+
open --> in_progress
|
|
84
|
+
in_progress --> blocked
|
|
85
|
+
blocked --> in_progress
|
|
86
|
+
open --> completed
|
|
87
|
+
in_progress --> completed
|
|
88
|
+
blocked --> completed
|
|
89
|
+
open --> cancelled
|
|
90
|
+
in_progress --> cancelled
|
|
91
|
+
blocked --> cancelled
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Create and inspect work:
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
agentspine task-create task:release \
|
|
98
|
+
--actor agent:lead \
|
|
99
|
+
--assignee agent:builder \
|
|
100
|
+
--kind handoff \
|
|
101
|
+
--title "Prepare the release candidate" \
|
|
102
|
+
--summary "Run the documented release gates" \
|
|
103
|
+
--privacy shared \
|
|
104
|
+
--root /path/to/project
|
|
105
|
+
|
|
106
|
+
agentspine task-update task:release \
|
|
107
|
+
--actor agent:builder \
|
|
108
|
+
--status in-progress \
|
|
109
|
+
--note "Validation is running" \
|
|
110
|
+
--root /path/to/project
|
|
111
|
+
|
|
112
|
+
agentspine tasks /path/to/project --assignee agent:builder --json
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
The MCP equivalents are `create_task`, `update_task`, and `task_context`. Returned context omits the internal delegation snapshot. Each mutation retains the complete previous task value before replacing the active view. New information therefore changes current relevance without erasing what was previously understood.
|
|
116
|
+
|
|
117
|
+
Permanent task deletion is CLI-only and requires the same explicit local confirmation marker. It removes the active record and all retained versions; use it for privacy removal, not routine completion.
|
|
118
|
+
|
|
119
|
+
## Privacy and groups
|
|
120
|
+
|
|
121
|
+
Tasks use `private`, `shared`, or `group` scope. Group tasks require a known group and visible `member-of` edges for the creator and assignee. Reads require the exact same group ID. `includePrivate` cannot bypass a missing or different group audience.
|
|
122
|
+
|
|
123
|
+
Lifecycle hooks have no private or group audience. They inject only the number and kinds of open shared coordination records—never titles, summaries, notes, assignees, or delegation policy. The agent must explicitly request relevant context.
|
|
124
|
+
|
|
125
|
+
## Integrity and concurrency
|
|
126
|
+
|
|
127
|
+
Both state files are private external project state, capped at 5 MiB, written with restrictive file mode and atomic replacement. Cross-process locks serialize policy changes and task mutations. A task mutation holds the policy read lock until its coordination write completes, so revocation cannot race an assignment into existence.
|
|
128
|
+
|
|
129
|
+
All decision and mutation paths validate current state before use. Unknown entities, secrets, forged provenance, invalid assignment snapshots, malformed JSON, or inconsistent policy cause a fail-closed error. Damaged files are reported by `agentspine audit` and are never overwritten automatically.
|
|
130
|
+
|
|
131
|
+
## Deliberate limits
|
|
132
|
+
|
|
133
|
+
- AgentSpine coordinates records without execution authority. The optional self-starter is the sole narrow exception and requires a separate current exact execution grant for every lifecycle effect.
|
|
134
|
+
- It does not send Telegram, email, chat, or notification messages.
|
|
135
|
+
- It does not authenticate the human operating a shell.
|
|
136
|
+
- It does not synchronize policy or tasks across machines.
|
|
137
|
+
- It does not treat organizational relationships as an access-control list.
|
|
138
|
+
- It does not replace host approvals, operating-system permissions, or an external policy engine.
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
# Signed mutable feed transport
|
|
2
|
+
|
|
3
|
+
AgentSpine can discover successive immutable HTTPS snapshots through one signed, compare-and-swap feed. The feed is provider-neutral and deliberately narrow: it is a bounded hash-chain window of snapshot references, not a remote database, command queue, permission source, or replacement for local review.
|
|
4
|
+
|
|
5
|
+
```mermaid
|
|
6
|
+
sequenceDiagram
|
|
7
|
+
participant P as Local publisher
|
|
8
|
+
participant O as Immutable objects
|
|
9
|
+
participant F as Mutable feed
|
|
10
|
+
participant R as Local receiver
|
|
11
|
+
P->>O: Create snapshot object<br/>If-None-Match: *
|
|
12
|
+
P->>F: GET signed chain + strong ETag
|
|
13
|
+
P->>P: Append entry and sign entire window
|
|
14
|
+
P->>F: PUT new chain<br/>If-Match: previous ETag
|
|
15
|
+
F-->>P: 200/204 or 412 conflict
|
|
16
|
+
P->>F: Verify exact read-back
|
|
17
|
+
R->>F: GET signed chain + strong ETag
|
|
18
|
+
R->>R: Verify trusted key, chain and local receipt
|
|
19
|
+
R->>O: GET content-addressed snapshot
|
|
20
|
+
R->>R: Verify snapshot and import to quarantine
|
|
21
|
+
R->>R: Persist new receipt with prior receipt in history
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Publish
|
|
25
|
+
|
|
26
|
+
The directory adapter must already be authenticated, and the named signer must remain stable for the lifetime of one feed:
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
export AGENTSPINE_FEED_TOKEN='deployment-supplied-value'
|
|
30
|
+
|
|
31
|
+
agentspine share-feed-publish /srv/agent-memory/team-alpha \
|
|
32
|
+
--root /path/to/publisher-project \
|
|
33
|
+
--base https://memory.example.org/agentspine/team-alpha \
|
|
34
|
+
--feed feed:team-alpha \
|
|
35
|
+
--signer signer:team-alpha \
|
|
36
|
+
--id snapshot:team-alpha-2026-08-28-01 \
|
|
37
|
+
--token-env AGENTSPINE_FEED_TOKEN \
|
|
38
|
+
--confirm-local-share
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Publication first creates and verifies the immutable object. It then reads the current feed, appends one entry, signs the entire retained window, updates using the previous strong ETag, and verifies an exact read-back. A `412` is a normal concurrency conflict: no retry is hidden, and the caller must fetch the winning feed before deciding whether to publish another snapshot.
|
|
42
|
+
|
|
43
|
+
The stable feed URL is derived from the SHA-256 digest of `feedId`:
|
|
44
|
+
|
|
45
|
+
```text
|
|
46
|
+
https://memory.example.org/agentspine/team-alpha/feeds/{sha256(feedId)}.json
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Pull
|
|
50
|
+
|
|
51
|
+
The receiver explicitly trusts the publisher's exported Ed25519 identity before pulling:
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
agentspine share-feed-pull \
|
|
55
|
+
--root /path/to/receiver-project \
|
|
56
|
+
--base https://memory.example.org/agentspine/team-alpha \
|
|
57
|
+
--feed feed:team-alpha \
|
|
58
|
+
--token-env AGENTSPINE_FEED_TOKEN
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
The first observation may join an established feed at its current tip. Every later pull must prove continuity from the locally stored receipt. A lower sequence is a rollback. A different entry at an observed sequence is equivocation. A newer feed whose bounded window no longer contains the observed tip is a continuity gap and fails closed instead of silently skipping history.
|
|
62
|
+
|
|
63
|
+
The feed retains at most 256 references. Receivers that may remain offline for more than 255 publications should poll less sparsely or begin a new explicitly trusted feed after operator review. Feed signer rotation also requires a new `feedId`; this avoids treating a same-name key as the old identity.
|
|
64
|
+
|
|
65
|
+
`share-feed-state` shows local receipts and retained prior receipts. There is intentionally no automatic reset command. Removing or replacing rollback protection is an operator decision outside the agent-controlled CLI workflow.
|
|
66
|
+
|
|
67
|
+
## Server contract
|
|
68
|
+
|
|
69
|
+
For a new feed, the service must atomically create the resource:
|
|
70
|
+
|
|
71
|
+
```http
|
|
72
|
+
PUT /agentspine/team-alpha/feeds/{feed-id-sha256}.json
|
|
73
|
+
Content-Type: application/vnd.agentspine.feed+json
|
|
74
|
+
If-None-Match: *
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
It returns `201` or `204`, then serves the exact document with a strong ETag. Updates require:
|
|
78
|
+
|
|
79
|
+
```http
|
|
80
|
+
PUT /agentspine/team-alpha/feeds/{feed-id-sha256}.json
|
|
81
|
+
Content-Type: application/vnd.agentspine.feed+json
|
|
82
|
+
If-Match: "the-etag-returned-by-the-last-get"
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
The service returns `200` or `204` only when that exact ETag still matches. It returns `412` without changing the feed after a competing update. Weak ETags are rejected because they cannot protect byte-exact compare-and-swap semantics. Responses are uncompressed JSON, no larger than 256 KiB, and redirects are never followed.
|
|
86
|
+
|
|
87
|
+
The object endpoints continue to implement the create-only contract in [immutable HTTPS objects](object-transport.md). A production service should independently authenticate writers, verify request sizes and preconditions atomically, rate-limit access, and avoid logging bearer values or feed bodies.
|
|
88
|
+
|
|
89
|
+
## Security and authority boundary
|
|
90
|
+
|
|
91
|
+
- TLS, vetted and pinned DNS, SSRF protection, strict timeouts, no redirects, exact limits, and environment-only bearer tokens apply to both feed reads and writes.
|
|
92
|
+
- Every network write requires explicit local owner confirmation. Private-network access requires the same confirmation plus an explicit opt-in.
|
|
93
|
+
- The signed feed authenticates one configured origin and detects history changes. It does not approve any referenced claim.
|
|
94
|
+
- The referenced snapshot is independently digest-checked and signature-checked, then imported through the existing quarantine. A second local user review remains mandatory before context use.
|
|
95
|
+
- Feed receipts and their history live outside the scanned project and are checked by the ten-gate audit. Corrupt state is never overwritten automatically.
|
|
96
|
+
- Feed payloads, receipts, snapshots, bearer authentication, signatures, and remote service responses always remain `context-only`. They cannot grant permissions, delegation, production access, spending rights, or policy exceptions.
|
|
97
|
+
- Feed publication, pulling, endpoint selection, tokens, and receipt mutation are absent from MCP and hooks.
|
|
98
|
+
|
|
99
|
+
Existing `AGENTS.md`, `CLAUDE.md`, `SOUL.md`, `MEMORY.md`, and other discovered Markdown files are never transported or modified by this layer.
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# Durable gateway worker
|
|
2
|
+
|
|
3
|
+
AgentSpine `0.8.0` includes an optional long-running worker that closes the gap between a channel message and an actual Claude Code or Codex run. While the worker is running, it polls configured Telegram accounts, authenticates every accepted update against an exact local channel binding, starts one leased agent lane, and delivers one idempotent reply to the original chat, topic, and message.
|
|
4
|
+
|
|
5
|
+
The worker is not exposed through MCP and is never started by remembered text. Its policy defaults to disabled; the owner enables it once with `agentspine gateway-control /path/to/project --enabled true --confirm-local-gateway`. An operating-system service manager may then supervise it after the owner configures its environment and command line.
|
|
6
|
+
|
|
7
|
+
## Automatic persona roster
|
|
8
|
+
|
|
9
|
+
Set `AGENTSPINE_PERSONA_ROSTER_FILE` or pass `--persona-roster` to the worker. The path must be absolute, point to a regular non-symlink JSON file outside the agent project, and remain below 1 MiB. The file uses this envelope:
|
|
10
|
+
|
|
11
|
+
```json
|
|
12
|
+
{
|
|
13
|
+
"schema": "agentspine.persona-roster/v1",
|
|
14
|
+
"revision": 1,
|
|
15
|
+
"observedAt": "2032-01-01T00:00:00.000Z",
|
|
16
|
+
"bindings": [
|
|
17
|
+
{
|
|
18
|
+
"id": "persona-binding:franz",
|
|
19
|
+
"authenticator": "host-manifest",
|
|
20
|
+
"issuer": "host:local",
|
|
21
|
+
"tenantId": "tenant:blun",
|
|
22
|
+
"host": "codex",
|
|
23
|
+
"profileId": "profile:franz",
|
|
24
|
+
"subjectId": "subject:franz",
|
|
25
|
+
"kind": "agent",
|
|
26
|
+
"displayName": "Franz",
|
|
27
|
+
"sourceBinding": ".codex/agents/franz.md",
|
|
28
|
+
"groupId": "group:engineering"
|
|
29
|
+
}
|
|
30
|
+
]
|
|
31
|
+
}
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Every tick synchronizes authenticated identities before any work is reconciled. New bindings append `join` events; renames retain the stable persona ID; omitted members in the same explicit roster scope become `left`; `"deactivated": true` records a distinct deactivation; reappearance appends `rejoin`. Names, Markdown, memory, and chat text cannot create identity or rights. Existing source files are never changed.
|
|
35
|
+
|
|
36
|
+
The same approved envelope may contain `nativeDiscovery` scopes. AgentSpine then checks only the officially documented direct agent-manifest directories: Claude Code `~/.claude/agents/` or `<project>/.claude/agents/`, and Codex `~/.codex/agents/` or `<project>/.codex/agents/`. `CLAUDE_CONFIG_DIR` and `CODEX_HOME` replace only their matching user scope. Each scope fixes issuer, tenant, profile, agent/bot kind, and optional group; those authenticated scope fields plus the exact source binding form the stable identity. The manifest contributes only its declared display name and an exact source descriptor; its instructions remain host-native context. Direct regular `.md` or `.toml` files are bounded to 128 entries and 256 KiB each; symlinks and files exchanged during a read fail closed. No other home or project directory is enumerated. See the official [Claude Code custom subagent locations](https://code.claude.com/docs/en/sub-agents) and [Codex custom agent locations](https://developers.openai.com/codex/agent-configuration/subagents).
|
|
37
|
+
|
|
38
|
+
```json
|
|
39
|
+
{
|
|
40
|
+
"nativeDiscovery": [
|
|
41
|
+
{
|
|
42
|
+
"id": "native:claude:user",
|
|
43
|
+
"host": "claude",
|
|
44
|
+
"scope": "user",
|
|
45
|
+
"issuer": "host:local",
|
|
46
|
+
"tenantId": "tenant:blun",
|
|
47
|
+
"profileId": "profile:franz",
|
|
48
|
+
"kind": "agent",
|
|
49
|
+
"groupId": "group:engineering"
|
|
50
|
+
}
|
|
51
|
+
]
|
|
52
|
+
}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
A one-shot manual validation is available through:
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
agentspine persona-sync /path/to/project \
|
|
59
|
+
--roster /absolute/path/to/roster.json \
|
|
60
|
+
--confirm-local-persona
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Telegram and host runner
|
|
64
|
+
|
|
65
|
+
An active Telegram channel binding needs `receive` and `reply`, an ingress HMAC environment variable, and an outbound Bot API token environment variable. The worker polls only accounts present in current bindings. Unknown chats, topics, senders, and non-text updates do not enter the queue.
|
|
66
|
+
|
|
67
|
+
`AGENTSPINE_HOST_RUNNER` must be an absolute locally approved executable path. AgentSpine invokes it with no shell and a minimized environment. One bounded JSON request arrives on stdin. For channel work it contains the exact host, profile, project root, agent scope, session key, and `agent_spine_channel_event` reference needed to start the native lifecycle hook. The message text itself is loaded by that hook from the authenticated channel state.
|
|
68
|
+
|
|
69
|
+
When the runner starts the selected stock CLI, it maps that request to the child process environment: `AGENTSPINE_GATEWAY_CONTEXT=agentspine.gateway-start/v1`, `AGENTSPINE_ENTITY_ID`, `AGENTSPINE_PROJECT_ID`, optional `AGENTSPINE_GROUP_ID`, plus `AGENTSPINE_CHANNEL_EVENT_ID` and `AGENTSPINE_CHANNEL_PROVIDER`. The native `SessionStart` payload does not need proprietary fields; the trusted AgentSpine hook reads this exact environment bridge and then leases the referenced event. The runner must not pass provider tokens or the ingress HMAC secret to the host process.
|
|
70
|
+
|
|
71
|
+
The runner returns one bounded JSON result:
|
|
72
|
+
|
|
73
|
+
```json
|
|
74
|
+
{
|
|
75
|
+
"text": "Die geprüfte Antwort.",
|
|
76
|
+
"checkpoint": { "step": "verified" },
|
|
77
|
+
"completed": true
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Start one diagnostic tick:
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
agentspine gateway-control /path/to/project \
|
|
85
|
+
--enabled true --confirm-local-gateway
|
|
86
|
+
|
|
87
|
+
AGENTSPINE_TELEGRAM_TOKEN='…' \
|
|
88
|
+
AGENTSPINE_TELEGRAM_INGRESS_SECRET='at-least-32-bytes…' \
|
|
89
|
+
AGENTSPINE_HOST_RUNNER='/absolute/path/to/approved-runner' \
|
|
90
|
+
agentspine-worker --root /path/to/project \
|
|
91
|
+
--persona-roster /absolute/path/to/roster.json --once
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Remove `--once` under a service manager for continuous operation. AgentSpine does not silently install a daemon, persist provider tokens, or approve Codex/Claude executable hooks. Codex still requires the current hook definition to be visible and trusted in `/hooks`.
|
|
95
|
+
|
|
96
|
+
## Goals, attention, and recovery
|
|
97
|
+
|
|
98
|
+
An agent without a queued message or an owner-assigned goal reports `idle/needs-goal`. `goal-assign` creates one exact focused goal for an active authenticated agent. Promise, resolved-blocker, deadline, assignment, follow-up, and direct-message wakes share bounded per-agent lanes. Each effect rechecks current policy, identity, group, route, and kill-switch state.
|
|
99
|
+
|
|
100
|
+
Queue leases expire safely, retries are bounded, and the worker wakes on relevant desired-state files or a capped timer without watching its own runtime writes. Prepared and demonstrably effect-free failed deliveries resume after restart. A revoked reply capability or exhausted no-effect retry budget becomes `dead-letter`; ambiguous sends become `delivery-unknown` and are never automatically replayed. Already delivered outbox entries are never sent twice. Checkpoints reject secrets and authority-shaped content. The ten-gate audit replays persona events, gateway history, receipts, lanes, queue IDs, delivery IDs, independent health heartbeats, and current authority markers.
|
|
101
|
+
|
|
102
|
+
The worker can be stopped locally at any time:
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
agentspine gateway-control /path/to/project \
|
|
106
|
+
--kill-switch true --confirm-local-gateway
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Memory, learning, relationships, persona files, goals, and model output cannot grant channel, tool, process, or execution permission.
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# Harness reference study
|
|
2
|
+
|
|
3
|
+
This architecture input was reviewed on 2026-08-29 against primary sources only. No upstream code, brand material, or persona text is included in AgentSpine.
|
|
4
|
+
|
|
5
|
+
## Reviewed snapshots
|
|
6
|
+
|
|
7
|
+
- OpenClaw `2026.8.1`, commit [`fb7822e1`](https://github.com/openclaw/openclaw/commit/fb7822e1d3333c9417131fa3514000a6a17e6dbd): [multi-agent routing](https://docs.openclaw.ai/concepts/multi-agent), [Gateway protocol](https://docs.openclaw.ai/gateway/protocol), and [cron jobs](https://docs.openclaw.ai/automation/cron-jobs).
|
|
8
|
+
- NousResearch Hermes Agent `0.20.6`, commit [`1c5ee581`](https://github.com/NousResearch/hermes-agent/commit/1c5ee5815fe5a3913530ba9d803b5b60bc633766): [cron guide](https://hermes-agent.nousresearch.com/docs/user-guide/features/cron), [messaging overview](https://hermes-agent.nousresearch.com/docs/user-guide/messaging), and [Telegram guide](https://hermes-agent.nousresearch.com/docs/user-guide/messaging/telegram).
|
|
9
|
+
|
|
10
|
+
## Architecture comparison
|
|
11
|
+
|
|
12
|
+
| Pattern | Übernehmen | An AgentSpine anpassen | Bewusst nicht übernehmen |
|
|
13
|
+
|---|---|---|---|
|
|
14
|
+
| Long-lived local gateway | Durable event ownership, health, wake-up, and recovery outside conversational turns | Optional provider-neutral worker; it does not replace the model host or tool registry | No silent network listener, hidden installation, or MCP administration |
|
|
15
|
+
| Agent isolation | Per-agent lane, state, session key, and exact channel-account binding | Separate tenant, profile, project, group, chat, and thread in every route | No fallback from one agent's private session, credentials, or memory into another |
|
|
16
|
+
| Scheduler | Persistent desired state, startup reconciliation, targeted event wake, and independent ticker health | Goals and obligations enter one bounded priority queue; timer is capped and has no busy loop | No prompt-created cron authority and no model-controlled scheduler policy |
|
|
17
|
+
| Isolated scheduled run | Fresh bounded host run with a terminal result and durable checkpoint | Return only the safe result/checkpoint to the responsible main context | No global transcript import and no private cross-session history mixing |
|
|
18
|
+
| Telegram | Stable numeric identities, explicit binding, origin-preserving replies, allowlist-style ingress | HMAC-normalized `agentspine.channel-event/v1`, exact tenant/account/chat/thread/sender/agent scope | No name-based identity, inferred recipient, broad bot token access, or send capability from text |
|
|
19
|
+
| Persona and voice | Per-agent persona source and stable named-bot separation | Authenticated roster metadata plus a bounded context-only `voiceBrief` | No persona file copying, invented feelings, dependency language, or authority from `SOUL.md` |
|
|
20
|
+
| Delivery | Idempotent outbox, receipts, retry, and terminal failure | Ambiguous sends become `delivery-unknown` and require reconciliation rather than replay | No claim of mathematical exactly-once transport; the guarantee is at-most-one automatic external effect |
|
|
21
|
+
|
|
22
|
+
## AgentSpine contracts derived from the study
|
|
23
|
+
|
|
24
|
+
1. `agentspine.channel-event/v1` is immutable and binds provider, tenant, account, chat, thread, sender, agent, project, group, privacy, reply target, and observed time.
|
|
25
|
+
2. The optional worker owns typed inbound, run, lifecycle, health, scheduler, and delivery transitions in external private state.
|
|
26
|
+
3. Per-agent lanes serialize work; another agent, tenant, profile, project, group, chat, or thread cannot claim the lease.
|
|
27
|
+
4. Reconciliation expires abandoned leases, detects ambiguous delivery, re-enqueues only demonstrably effect-free failures, and preserves terminal receipts.
|
|
28
|
+
5. Gateway, adapter, scheduler, queue, worker lease, and host runtime have separate health fields. A live process alone is not healthy.
|
|
29
|
+
6. Goals require an authenticated local owner assignment and contain one success criterion, next safe step, deadline, checkpoint, heartbeat, blocker, and history.
|
|
30
|
+
7. Memory, Markdown, persona, relationship, task text, prior output, and MCP never satisfy identity, execution, route, or send policy.
|
|
31
|
+
|
|
32
|
+
## Regression classes
|
|
33
|
+
|
|
34
|
+
The local tests cover the public failure classes as contracts rather than copying their implementations:
|
|
35
|
+
|
|
36
|
+
- A scheduled result that is delivered but never checkpointed cannot become terminal; run completion persists before delivery preparation.
|
|
37
|
+
- A stopped scheduler cannot hide behind a running gateway because health gates are independent and audited.
|
|
38
|
+
- Restart reconciliation converts an in-flight ambiguous send to `delivery-unknown`; it never floods Telegram by replaying it.
|
|
39
|
+
- Every run has a bounded host timeout and one of the terminal or retryable queue states; no final-tool-call ghost remains leased forever.
|
|
40
|
+
- Lease expiry and startup reconciliation close ghost lane rows and allow only safe work to resume.
|
|
41
|
+
- Duplicate provider updates, parallel workers, and repeated delivery calls converge on one event, one lane, one outbox key, and at most one automatic external send.
|
|
42
|
+
|
|
43
|
+
## Stronger boundaries retained
|
|
44
|
+
|
|
45
|
+
AgentSpine keeps no global full transcript, exposes no channel, goal, wake, worker, kill-switch, secret, or send administration through MCP, and does not broaden tools from persona or team membership. Host and local policy stores remain physically separate from context state. Explicit host trust and local owner confirmation remain unavoidable security decisions.
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
# Host integration
|
|
2
|
+
|
|
3
|
+
AgentSpine uses native plugin surfaces instead of asking users to paste a large system prompt into every project.
|
|
4
|
+
|
|
5
|
+
## Claude Code
|
|
6
|
+
|
|
7
|
+
| Component | Path | Purpose |
|
|
8
|
+
|---|---|---|
|
|
9
|
+
| Manifest | `.claude-plugin/plugin.json` | Package identity and version |
|
|
10
|
+
| Marketplace | `.claude-plugin/marketplace.json` | GitHub installation and updates |
|
|
11
|
+
| Skill | `skills/agent-spine/SKILL.md` | Context rules and preservation invariants |
|
|
12
|
+
| MCP | `.mcp.json` | Read-only source tools plus external overlay workflows |
|
|
13
|
+
| Hooks | `hooks/hooks.json` | Automatic briefing, attention, protected-source guard, and rights-bound checkpoints |
|
|
14
|
+
|
|
15
|
+
Install from GitHub:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
claude plugin marketplace add Maykbiletti/AgentSpine
|
|
19
|
+
claude plugin install agent-spine@agent-spine
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Use `claude plugin validate .` in a checkout to validate the manifest and marketplace. Claude Code asks the user to approve executable plugin components according to its trust model.
|
|
23
|
+
|
|
24
|
+
The Claude manifest explicitly references `./.mcp.json`. The hook bundle remains at Claude Code's native auto-discovery path `hooks/hooks.json`; it is deliberately not registered a second time through the manifest. Version `0.8.0` replaces the `0.7.0` plugin cache identity. The hook definition contains only portable documented hook fields; `hooks/version.json` carries the separately validated bundle release and lifecycle contract. The repository checks resolve installed-root variables, perform a real MCP `initialize` handshake, validate exactly one native hook command per event, and exercise staged clean install, previous-version cache rejection, upgrade, host-native source resolution, indexed and lazy Claude memory, automatic multilingual briefing, attention, exact job start, tool checkpoint, new-session resume, purge, and uninstall preservation:
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
npm run host:check
|
|
28
|
+
npm run host:install-check
|
|
29
|
+
npm run acceptance
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### Claude MCP troubleshooting
|
|
33
|
+
|
|
34
|
+
If the plugin is listed but `agent-spine` is missing from `/mcp`, update the marketplace cache and reinstall before starting a new session:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
claude plugin marketplace update agent-spine
|
|
38
|
+
claude plugin uninstall agent-spine@agent-spine
|
|
39
|
+
claude plugin install agent-spine@agent-spine
|
|
40
|
+
claude plugin list
|
|
41
|
+
claude mcp list
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Open `/mcp` in the new interactive session and approve or reconnect `agent-spine`. `Pending approval` means discovery succeeded but Claude Code still needs the user's trust decision. A missing entry after reinstall should be diagnosed from `claude plugin validate .`, `npm run host:check`, and Claude Code's plugin diagnostics; AgentSpine does not write to Claude's user configuration or silently approve itself.
|
|
45
|
+
|
|
46
|
+
## Codex
|
|
47
|
+
|
|
48
|
+
| Component | Path | Purpose |
|
|
49
|
+
|---|---|---|
|
|
50
|
+
| Manifest | `.codex-plugin/plugin.json` | Package identity plus explicit skill and MCP registration |
|
|
51
|
+
| Skill | `skills/agent-spine/SKILL.md` | Context rules and preservation invariants |
|
|
52
|
+
| MCP | Manifest `mcpServers` | Read-only source tools plus external overlay workflows |
|
|
53
|
+
| Hooks | `hooks/hooks.json` | Auto-discovered lifecycle guardrails |
|
|
54
|
+
|
|
55
|
+
Open `/plugins` in Codex CLI after configuring a marketplace that contains AgentSpine, then start a new session. Codex presents a startup review when a new or changed hook definition needs trust; there is no `/hooks` slash command. Codex records trust against the exact hook-definition hash, so an installed, updated, or previously untrusted bundle is skipped until that current definition is reviewed and trusted. This follows the official [Codex hooks trust and plugin discovery contract](https://developers.openai.com/codex/hooks).
|
|
56
|
+
|
|
57
|
+
Codex discovers the hook at the standard `hooks/hooks.json` path. The file deliberately contains only the documented top-level `description` and `hooks` fields; earlier AgentSpine builds added private `version` and `contract` metadata there, which a strict Codex parser could reject before presenting a trust decision. Cache identity remains in `.codex-plugin/plugin.json`, while Codex records hook trust against the current definition hash. Codex sets `CLAUDE_PLUGIN_ROOT` for hook compatibility, so the same hook bundle can execute in both hosts. The MCP registration uses Codex's `PLUGIN_ROOT` expansion.
|
|
58
|
+
|
|
59
|
+
Verify the live host in a newly started Codex CLI session:
|
|
60
|
+
|
|
61
|
+
```text
|
|
62
|
+
/plugins
|
|
63
|
+
Trust all and continue
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
`npm run host:check` proves manifest shape, package containment, and a real MCP handshake. `npm run host:install-check` stages the installed bundle and executes its hook entrypoint with native event JSON. Neither command can manufacture Codex's user-controlled trust receipt; only the startup review in the actual host proves that final boundary.
|
|
67
|
+
|
|
68
|
+
## BLUN King
|
|
69
|
+
|
|
70
|
+
| Component | Path | Purpose |
|
|
71
|
+
|---|---|---|
|
|
72
|
+
| Manifest | `blun.plugin.json` | Native BLUN plugin identity plus skill, MCP, and lifecycle-hook registration |
|
|
73
|
+
| Skill | `skills/agent-spine/SKILL.md` | Context rules and preservation invariants |
|
|
74
|
+
| MCP | Manifest `mcpServers` | Read-only source tools plus external overlay workflows |
|
|
75
|
+
| Hooks | Manifest `hooks` | Automatic briefing, attention, protected-source guard, and checkpoints |
|
|
76
|
+
|
|
77
|
+
Install the local checkout from Fredrik's TUI:
|
|
78
|
+
|
|
79
|
+
```text
|
|
80
|
+
/plugins install C:\path\to\AgentSpine
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
BLUN asks the user to trust a third-party plugin before installation because its MCP server and hooks execute local code. Accept that visible install decision, then use `/reload` or `/new`; BLUN has no separate `/hooks` command. The BLUN adapter maps its isolated `BLUN_HOME` to AgentSpine's Codex-compatible `AGENTS.md` source hierarchy, so user state remains under the BLUN app home instead of leaking into `.codex` or a scanned project.
|
|
84
|
+
|
|
85
|
+
## Direct MCP use
|
|
86
|
+
|
|
87
|
+
Any MCP client that supports stdio can launch:
|
|
88
|
+
|
|
89
|
+
```json
|
|
90
|
+
{
|
|
91
|
+
"mcpServers": {
|
|
92
|
+
"agent-spine": {
|
|
93
|
+
"command": "agentspine-mcp"
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
The server implements `initialize`, `ping`, `tools/list`, and `tools/call`. It has no network dependency and exposes no source-file, delegation-policy, signer, trust, or shared-adapter administration tool. Overlay tools write only private AgentSpine context state outside the scanned project. Explicit delegation grants, key generation and rotation, trust changes, adapter connections, publication, HTTPS snapshot export, object upload or pulls, SQLite paths or operations, import review, and destructive sharing operations remain on the local CLI surface. MCP can only read already reviewed `shared_context`; its authentication summary contains no signature or public-key material. `session_briefing` is a read-only aggregator over these already constrained read paths and cannot widen them.
|
|
100
|
+
|
|
101
|
+
Verify either installation against a synthetic or real project without changing its Markdown:
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
agentspine doctor --json
|
|
105
|
+
npm run host:check
|
|
106
|
+
agentspine audit /path/to/project --json
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
The audit exits non-zero when a required gate fails, making it suitable for installation smoke tests and CI.
|
|
110
|
+
|
|
111
|
+
Use `agentspine doctor --host claude|codex --cwd /active/project --json` or `agentspine source-status --host claude|codex --cwd /active/project --json` to see the checked scope counts and a concrete empty/fail-closed reason. The lifecycle adapter never substitutes the installation directory for the active host hierarchy. Details and official host references are in [host-native source roots](source-roots.md).
|
|
112
|
+
|
|
113
|
+
The provider-neutral lifecycle adapter covers `SessionStart` (including resume and compact starts), `UserPromptSubmit`, `PreToolUse`, `PostToolUse`, `PreCompact`, `PostCompact`, `Stop`, and `SubagentStop`. Start, prompt, and compaction boundaries scan and inject the actual byte-budgeted `session_briefing`; no model-side MCP selection is required. Prompt submission can additionally capture minimal safe learning and direct promise/blocker signals after the separate local continuity opt-in. `PostToolUse` writes an idempotent task heartbeat; `Stop` and `SubagentStop` close that heartbeat without emitting repeated chat text.
|
|
114
|
+
|
|
115
|
+
When an exact locally registered job is waiting, `SessionStart` acquires its lease and injects its real checkpoint automatically. Subsequent tool and stop hooks resolve that job from the native host session; the model does not need to repeat a job envelope. `PreToolUse` first retains the protected-source guard, then rechecks the current execution grant, assignment, scope, capability, lease, and workspace. `PostToolUse` checkpoints exactly one matching result. A new session resumes only after the same checks. Grant and job administration remain local CLI operations and are absent from MCP. No hook creates permissions.
|
|
116
|
+
|
|
117
|
+
Identity and audience come from explicit hook scope fields or the locally configured default direct-person/project scope. Group content requires an exact group ID and never enters automatic learning. Missing scope produces no inferred identity; corrupt state returns a visible `failedClosed` packet and must never be reported as successful recall.
|
|
118
|
+
|
|
119
|
+
Hook stdin is JSON-only and limited to 64 KiB. State transitions use external atomic files and locks. Hook stdout contains only host protocol JSON; diagnostics are bounded to stderr by the host process. Hooks do not expose transport, key, trust, database, network, message, payment, production, delegation, or policy administration.
|
|
120
|
+
|
|
121
|
+
The first executable-component trust approval remains mandatory. AgentSpine cannot approve itself. After approval and the one-time continuity opt-in, no per-session enablement or voluntary tool call is required.
|
|
122
|
+
|
|
123
|
+
## Optional gateway worker
|
|
124
|
+
|
|
125
|
+
The package also registers exactly one `agentspine-worker` entrypoint. It is separate from MCP and lifecycle hooks. When an owner runs it under a service manager, it synchronizes the configured authenticated persona roster, polls current Telegram bindings, prepares exact Claude/Codex start data, invokes only the absolute executable in `AGENTSPINE_HOST_RUNNER` without a shell, and returns one idempotent reply to the bound origin.
|
|
126
|
+
|
|
127
|
+
The host runner is responsible for starting the selected host with the supplied scope and `agent_spine_channel_event` fields. Codex still refuses the injected context until the current hook hash has been reviewed in `/hooks`; the worker cannot bypass or manufacture that trust. Setup and the stdin/stdout contract are documented in [durable gateway worker](gateway-runtime.md).
|
|
128
|
+
|
|
129
|
+
The visible acceptance runner invokes the same production lifecycle adapter with new synthetic people, separated groups, Swedish and Spanish prompts, restarts, compaction, correction, rollback, purge, current-rights checks, and durable checkpoints. It prints one reproducible receipt per gate and proves `mcpCalls: 0`. See [visible cross-host acceptance](acceptance.md).
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
# HTTPS snapshot transport
|
|
2
|
+
|
|
3
|
+
AgentSpine can carry a signed directory exchange across ordinary HTTPS without depending on a particular cloud, database, or agent vendor. The basic workflow is deliberately static: AgentSpine creates one immutable JSON snapshot, an operator publishes that file through existing infrastructure, and receivers pull it into the normal local quarantine. For direct create-only uploads, use the separate [immutable HTTPS object transport](object-transport.md).
|
|
4
|
+
|
|
5
|
+
```mermaid
|
|
6
|
+
sequenceDiagram
|
|
7
|
+
participant P as Publisher CLI
|
|
8
|
+
participant F as Signed directory adapter
|
|
9
|
+
participant H as Operator-controlled HTTPS
|
|
10
|
+
participant R as Receiver CLI
|
|
11
|
+
participant Q as Local quarantine
|
|
12
|
+
P->>F: validate signed manifest + every event
|
|
13
|
+
P->>P: create immutable snapshot outside project
|
|
14
|
+
P-->>H: operator publishes JSON file
|
|
15
|
+
R->>H: pinned-DNS HTTPS GET
|
|
16
|
+
H-->>R: bounded JSON, no redirect/compression
|
|
17
|
+
R->>R: validate snapshot digest + all Ed25519 envelopes
|
|
18
|
+
R->>Q: pending imports only
|
|
19
|
+
Q-->>R: second explicit local review still required
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
The web server never becomes an authority source. A TLS connection protects bytes in transit. The snapshot digest detects truncation or bundle mutation. The existing Ed25519 envelopes authenticate the configured manifest and event keys. The receiving project's trust store decides which keys are recognized. None of those checks approves a claim, grants a permission, or bypasses review.
|
|
23
|
+
|
|
24
|
+
## Publish a snapshot
|
|
25
|
+
|
|
26
|
+
Snapshots require a signed directory adapter. First create the signer, trust distribution, adapter, and events as described in [shared memory adapters](shared-memory.md). Then export:
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
agentspine share-snapshot-export /srv/agent-memory/team-alpha \
|
|
30
|
+
--root /path/to/publisher-project \
|
|
31
|
+
--out /srv/static/agent-memory/team-alpha-2026-08-28.json \
|
|
32
|
+
--id snapshot:team-alpha-2026-08-28 \
|
|
33
|
+
--confirm-local-share
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
The output must be outside the scanned project and must not already exist. AgentSpine writes it with owner-only mode on POSIX systems. Updating a feed means exporting a new file or atomically changing a server-side alias outside this static workflow. `share-https-publish` can create immutable remote objects, but AgentSpine still has no remote overwrite, delete, listing, or mutable alias command.
|
|
37
|
+
|
|
38
|
+
Serve the exact file over HTTPS with:
|
|
39
|
+
|
|
40
|
+
- a certificate accepted by the local Node.js trust store;
|
|
41
|
+
- `Content-Type: application/json`;
|
|
42
|
+
- no content compression;
|
|
43
|
+
- no redirect at the configured URL;
|
|
44
|
+
- access logs and retention appropriate for the snapshot's metadata sensitivity.
|
|
45
|
+
|
|
46
|
+
Snapshots contain shared claims, group IDs, timestamps, public signing identities, and signatures. They contain no private learning, source Markdown, evidence text, tasks, delegation policy, credentials, attention state, or relationship profiles. TLS does not encrypt a snapshot stored on the server; secure storage and server access remain deployment responsibilities.
|
|
47
|
+
|
|
48
|
+
## Pull a public endpoint
|
|
49
|
+
|
|
50
|
+
Trust every expected event signer in the receiving project first, then run:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
agentspine share-https-pull \
|
|
54
|
+
https://memory.example.org/team-alpha-2026-08-28.json \
|
|
55
|
+
--root /path/to/receiving-project
|
|
56
|
+
|
|
57
|
+
agentspine share-inbox /path/to/receiving-project --status pending --json
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
The pull validates the entire response before writing local sharing state. All imports remain `pending` and invisible to `shared_context` until the receiving user accepts each item through `share-review --confirmed-by-user`.
|
|
61
|
+
|
|
62
|
+
For an endpoint protected by a bearer token, provide only the environment variable name:
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
export AGENTSPINE_SNAPSHOT_TOKEN='deployment-supplied-value'
|
|
66
|
+
agentspine share-https-pull \
|
|
67
|
+
https://memory.example.org/private/team-alpha.json \
|
|
68
|
+
--token-env AGENTSPINE_SNAPSHOT_TOKEN \
|
|
69
|
+
--root /path/to/receiving-project
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Tokens are read at request time. They are not accepted in URLs, command arguments, snapshots, local sharing state, hook context, MCP results, or command output. Shell history, process environment access, and server logs are still operating-system concerns.
|
|
73
|
+
|
|
74
|
+
## Private networks
|
|
75
|
+
|
|
76
|
+
Public mode rejects loopback, private, link-local, carrier-grade NAT, multicast, reserved, and documentation address ranges. Every DNS answer is checked and the HTTPS connection is pinned to one vetted answer, preventing a second unvalidated lookup from rebinding the request. Mixed public/private answer sets fail closed.
|
|
77
|
+
|
|
78
|
+
Self-hosted private endpoints require both flags:
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
agentspine share-https-pull \
|
|
82
|
+
https://memory.internal.example/team-alpha.json \
|
|
83
|
+
--allow-private-network \
|
|
84
|
+
--confirm-local-share \
|
|
85
|
+
--root /path/to/receiving-project
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
The confirmation is a local integration attestation, not permission derived from memory or an agent. TLS certificate verification remains enabled for private networks.
|
|
89
|
+
|
|
90
|
+
## Network safety limits
|
|
91
|
+
|
|
92
|
+
The reference client:
|
|
93
|
+
|
|
94
|
+
- accepts one explicit `https://` JSON resource with no embedded credentials, query, or fragment;
|
|
95
|
+
- performs one `GET`, disables connection pooling, pins validated DNS, and follows no redirects;
|
|
96
|
+
- rejects non-JSON media types and compressed responses;
|
|
97
|
+
- defaults to a 10-second timeout, configurable only from 1 to 30 seconds;
|
|
98
|
+
- caps the response and validated snapshot at 21 MiB and the event set at 2,000;
|
|
99
|
+
- rejects unknown fields, duplicate IDs, collisions, metadata mismatches, invalid bundle digests, unsigned documents, bad signatures, and untrusted keys before quarantine mutation;
|
|
100
|
+
- deletes its temporary materialization after every success or failure;
|
|
101
|
+
- exposes no HTTPS export or pull operation through MCP.
|
|
102
|
+
|
|
103
|
+
The static client intentionally does not execute remote instructions, enumerate endpoints, accept remote redirects, refresh tokens, upload data, or implement a hosted control plane. Writable object, local SQLite, and peer transports are separate modules and preserve the same local validation and review boundary; hosted database adapters remain extension work.
|
|
104
|
+
|
|
105
|
+
## Snapshot schema
|
|
106
|
+
|
|
107
|
+
`agentspine.https-snapshot/v1` has exact top-level fields:
|
|
108
|
+
|
|
109
|
+
- stable snapshot, scope, and adapter IDs;
|
|
110
|
+
- generation timestamp;
|
|
111
|
+
- one signed `agentspine.directory-adapter/v1` manifest envelope;
|
|
112
|
+
- up to 2,000 signed `agentspine.shared-event/v1` event envelopes;
|
|
113
|
+
- `authority: context-only`;
|
|
114
|
+
- canonical SHA-256 digest over the complete snapshot body.
|
|
115
|
+
|
|
116
|
+
Snapshot integrity is packaging evidence, not source identity. Manifest and event signatures are verified independently, and every event signer needs explicit local trust.
|