blun-king-cli 9.1.486 → 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 +26 -7
- package/README.md +14 -3
- 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 +9 -1
- package/bin/plugin-bootstrap.js +68 -27
- package/bin/turn-thinking-policy.cjs +5 -4
- package/bin/turn-tool-performance-policy.cjs +15 -2
- package/blun.mjs +96 -31
- package/package.json +2 -1
|
@@ -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.
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# Safe learning
|
|
2
|
+
|
|
3
|
+
AgentSpine separates an observation from a fact that may enter future context. An agent can propose a candidate and append evidence, but the candidate remains invisible to `learning_context` until it passes an explicit review or the narrowly scoped, default-off automatic policy.
|
|
4
|
+
|
|
5
|
+
```mermaid
|
|
6
|
+
flowchart LR
|
|
7
|
+
O["Observation"] --> C["Candidate"]
|
|
8
|
+
C --> E["Append-only evidence"]
|
|
9
|
+
E --> R{"Review gate"}
|
|
10
|
+
R -->|"explicit user confirmation"| A["Accepted context"]
|
|
11
|
+
R -->|"reject"| X["Rejected history"]
|
|
12
|
+
R -->|"opt-in low-risk policy"| A
|
|
13
|
+
A --> S["Supersede without erasing"]
|
|
14
|
+
S --> B["Rollback restores prior fact"]
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Candidate kinds
|
|
18
|
+
|
|
19
|
+
| Kind | Normal review path | Automatic eligibility |
|
|
20
|
+
|---|---|---|
|
|
21
|
+
| `preference` | Explicit confirmation | Never |
|
|
22
|
+
| `no-go` | Explicit confirmation | Never |
|
|
23
|
+
| `goal` | Explicit confirmation | Never |
|
|
24
|
+
| `correction` | Explicit confirmation | Never |
|
|
25
|
+
| `personal-fact` | Explicit confirmation | Never |
|
|
26
|
+
| `project-fact` | Explicit confirmation | Opt-in, evidence-gated |
|
|
27
|
+
| `reference` | Explicit confirmation | Opt-in, evidence-gated |
|
|
28
|
+
|
|
29
|
+
Every candidate and evidence record carries `authority: context-only`. Accepted learning can improve relevance and consistency, but it cannot grant permissions, delegation, production access, spending rights, policy exceptions, or instructions to act.
|
|
30
|
+
|
|
31
|
+
## Evidence and provenance
|
|
32
|
+
|
|
33
|
+
Evidence is append-only while a candidate is awaiting review. Supported evidence types are `user-statement`, `document`, `interaction`, and `test`. Document evidence must reference a discovered Markdown source; AgentSpine records that source's SHA-256 at observation time without editing it.
|
|
34
|
+
|
|
35
|
+
Adding evidence stores the previous candidate version in history before recalculating confidence. Distinct evidence IDs or source fingerprints are counted for automatic evaluation. Secret-shaped content is rejected before it reaches learning state.
|
|
36
|
+
|
|
37
|
+
## Explicit review
|
|
38
|
+
|
|
39
|
+
Acceptance requires the `confirmedByUser` marker and a review reason. The marker is an integration attestation, not identity proof: a host adapter should set it only after an actual user gesture or unambiguous user instruction. AgentSpine never infers confirmation from another memory, Markdown sentence, candidate, agent message, or relationship edge.
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
agentspine learn-propose learning:concise \
|
|
43
|
+
--kind preference \
|
|
44
|
+
--claim "The preferred output is concise." \
|
|
45
|
+
--evidence "The user explicitly requested concise output." \
|
|
46
|
+
--privacy private
|
|
47
|
+
|
|
48
|
+
agentspine learn-review learning:concise \
|
|
49
|
+
--decision accept \
|
|
50
|
+
--reason "Explicitly confirmed by the user." \
|
|
51
|
+
--confirmed-by-user
|
|
52
|
+
|
|
53
|
+
agentspine learn-context . --include-private --json
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Candidates never appear in learned context before acceptance. Native lifecycle hooks inject only accepted, exactly scoped learning inside the byte-budgeted session briefing. They never inject unreviewed candidates.
|
|
57
|
+
|
|
58
|
+
## Optional automatic promotion
|
|
59
|
+
|
|
60
|
+
Automatic promotion is disabled by default. When deliberately enabled, it applies only to `project-fact` and `reference`, and only when both confidence and distinct-evidence thresholds pass.
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
agentspine learn-config . \
|
|
64
|
+
--auto-promote true \
|
|
65
|
+
--min-confidence 0.9 \
|
|
66
|
+
--min-evidence 2
|
|
67
|
+
|
|
68
|
+
agentspine learn-evaluate . --json
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
The accepted record stores the policy thresholds, evidence count, and evaluation time used for that decision. The audit rejects an accepted record with no valid manual-review proof or automatic-promotion snapshot. Personal facts, preferences, goals, corrections, and no-gos are never automatically promoted by this general evaluator.
|
|
72
|
+
|
|
73
|
+
This evaluator is separate from [automatic continuity](automatic-continuity.md). After its own local privacy opt-in, the lifecycle adapter may accept only direct, high-confidence style preferences, no-gos, corrections, project facts, and references with a recorded threshold proof. Personal facts, group conversation content, identity claims, secrets, authority, access, and operational permissions are never eligible. The continuity path is not exposed through MCP.
|
|
74
|
+
|
|
75
|
+
## Supersession and rollback
|
|
76
|
+
|
|
77
|
+
New information does not overwrite an accepted fact. Propose a new candidate with `--supersedes` and the same kind, subject, and privacy scope. Acceptance marks the prior record `superseded` and retains both versions. Rollback deactivates the replacement and restores the prior accepted record atomically.
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
agentspine learn-propose learning:new-goal \
|
|
81
|
+
--kind goal \
|
|
82
|
+
--claim "The current goal is the new synthetic milestone." \
|
|
83
|
+
--evidence "The user changed the goal." \
|
|
84
|
+
--supersedes learning:old-goal
|
|
85
|
+
|
|
86
|
+
agentspine learn-rollback learning:new-goal \
|
|
87
|
+
--reason "The change was recorded incorrectly."
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Permanent deletion removes one candidate and its learning history. An accepted superseding record must be rolled back before deletion so its predecessor is not stranded.
|
|
91
|
+
|
|
92
|
+
## Privacy and groups
|
|
93
|
+
|
|
94
|
+
Private learning requires an explicit `includePrivate` read. Group learning requires a known group entity, an exact `groupId`, and—when a subject is present—a visible `member-of` edge. `includePrivate` does not bypass a different or missing group audience. Session hooks have no group audience and therefore expose no group learning.
|
|
95
|
+
|
|
96
|
+
## Storage and concurrency
|
|
97
|
+
|
|
98
|
+
`learning.json` lives in the same external per-project state directory as the catalog, graph, and attention state. Mutations use a per-project lock and atomic replacement, so concurrent agents cannot silently discard evidence. State is capped at 5 MiB and original Markdown remains byte-for-byte unchanged.
|