docs: agent platform v2.1 — hardening review (agreed 2026-07-21)
Some checks failed
ClawSweeper Dispatch / dispatch (push) Has been cancelled
CodeQL / Security High (actions) (push) Has been cancelled
CodeQL / Security High (channel-runtime-boundary) (push) Has been cancelled
CodeQL / Security High (core-auth-secrets) (push) Has been cancelled
CodeQL / Security High (mcp-process-tool-boundary) (push) Has been cancelled
CodeQL / Security High (network-ssrf-boundary) (push) Has been cancelled
CodeQL / Security High (plugin-trust-boundary) (push) Has been cancelled
CodeQL / Security High (process-exec-boundary) (push) Has been cancelled
Docs / docs (push) Has been cancelled
OpenClaw Stable Main Closeout / Resolve stable release closeout inputs (push) Has been cancelled
OpenClaw Stable Main Closeout / Verify stable main closeout (push) Has been cancelled
Workflow Sanity / generated-doc-baselines (push) Has been cancelled
Workflow Sanity / no-tabs (push) Has been cancelled
Workflow Sanity / actionlint (push) Has been cancelled
Some checks failed
ClawSweeper Dispatch / dispatch (push) Has been cancelled
CodeQL / Security High (actions) (push) Has been cancelled
CodeQL / Security High (channel-runtime-boundary) (push) Has been cancelled
CodeQL / Security High (core-auth-secrets) (push) Has been cancelled
CodeQL / Security High (mcp-process-tool-boundary) (push) Has been cancelled
CodeQL / Security High (network-ssrf-boundary) (push) Has been cancelled
CodeQL / Security High (plugin-trust-boundary) (push) Has been cancelled
CodeQL / Security High (process-exec-boundary) (push) Has been cancelled
Docs / docs (push) Has been cancelled
OpenClaw Stable Main Closeout / Resolve stable release closeout inputs (push) Has been cancelled
OpenClaw Stable Main Closeout / Verify stable main closeout (push) Has been cancelled
Workflow Sanity / generated-doc-baselines (push) Has been cancelled
Workflow Sanity / no-tabs (push) Has been cancelled
Workflow Sanity / actionlint (push) Has been cancelled
Fixes two v2 design bugs and closes the review gaps alvis accepted: - Transport rule: sync = direct A2A RPC (journaled to KB); async = KB polling; polling never on a sync path. - GPU residency: local a(t)=f(VRAM), never-evict set, pre-load checks. - NEW §5b Humans (plural): per-human private banks + shared household bank, interlocutor-scoped recall, cross-human leakage forbidden; human inbox design (priority-routed notifications, digest, no default-approve, vacation mode). - NEW §6b fabric-keeper: scheduling decomposed (triggering/dispatch/ admission/time); the keeper janitor owns leases, deadlines, cron catch-up, dead-letter, digests. - NEW §6c KB as tier-0 (backup/monitoring/degraded mode). - Completion vs verification: Done column = unverified, closed task = verified, producer never closes own task. - A2A auth mandatory (LAN untrusted: VPN peers); fabric hygiene (creation quotas, ancestry cap, dead-letter); personas/Cards in git; golden-set eval gate on backbone swaps. - Decision log entries 12-21. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014t8Qg9gi7H7HtT8MncoXAB
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
# DESIGN — Agap Agent Platform v2: the agent algebra
|
# DESIGN — Agap Agent Platform v2.1: the agent algebra
|
||||||
|
|
||||||
Status: **v2, agreed with alvis 2026-07-21** (supersedes v1 draft `2499218c`)
|
Status: **v2.1, agreed with alvis 2026-07-21** (v2 `7be30c71` + hardening review)
|
||||||
Owner: alvis · Written with Claude
|
Owner: alvis · Written with Claude
|
||||||
|
|
||||||
One design, two axioms, one verb. Everything alvis asked for — per-model queues,
|
One design, two axioms, one verb. Everything alvis asked for — per-model queues,
|
||||||
@@ -23,6 +23,9 @@ rule. This document is the reference; the Kanboard A2A tasks implement it.
|
|||||||
- **Backbone** — the concrete LLM an agent currently uses for reasoning.
|
- **Backbone** — the concrete LLM an agent currently uses for reasoning.
|
||||||
- **Context ref** — a pointer (Hindsight bank id, git ref, KB task id, file
|
- **Context ref** — a pointer (Hindsight bank id, git ref, KB task id, file
|
||||||
path) passed *instead of* pasted content.
|
path) passed *instead of* pasted content.
|
||||||
|
- **fabric-keeper** — the janitor daemon owning time semantics (§6b): lease
|
||||||
|
sweeps, deadlines, cron catch-up, dead-letter, inbox digests. It never
|
||||||
|
assigns work.
|
||||||
|
|
||||||
## 1. Why
|
## 1. Why
|
||||||
|
|
||||||
@@ -75,6 +78,21 @@ Context travels **by reference, never by value** — the single most important
|
|||||||
efficiency rule for inter-agent communication (A2A context-passing practice).
|
efficiency rule for inter-agent communication (A2A context-passing practice).
|
||||||
`sync` vs `async` is not a second mechanism: sync = submit + await.
|
`sync` vs `async` is not a second mechanism: sync = submit + await.
|
||||||
|
|
||||||
|
**Transport rule.** Sync and async share the algebra but not the transport:
|
||||||
|
**sync goes direct** — an A2A `message/send` RPC straight to the target agent's
|
||||||
|
endpoint, journaled to KB afterwards; **async/durable goes through KB** and is
|
||||||
|
drained by polling workers. KB polling must never sit on a sync path — a sync
|
||||||
|
call may not inherit poll-interval latency.
|
||||||
|
|
||||||
|
### Completion vs verification
|
||||||
|
|
||||||
|
KB convention (native semantics, no new machinery): the **Done column =
|
||||||
|
unverified completion** — the worker/agent finished and self-reported. **Closing
|
||||||
|
the task = verified completion.** The producer never closes its own task; the
|
||||||
|
submitter, a human, or (later) a reviewer-agent closes after checking the
|
||||||
|
task's acceptance criteria. Lifecycle: … → done (unverified) → closed
|
||||||
|
(verified). For code, the PR review is the verification; closing follows merge.
|
||||||
|
|
||||||
### Theorems — the old rules become consequences
|
### Theorems — the old rules become consequences
|
||||||
|
|
||||||
1. **"Queues are per model, not per agent."** Every agent has an inbox, but
|
1. **"Queues are per model, not per agent."** Every agent has an inbox, but
|
||||||
@@ -132,6 +150,30 @@ fabric free of micro-churn by construction.
|
|||||||
└─────────────────────────────────────────────────────────────────────┘
|
└─────────────────────────────────────────────────────────────────────┘
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### GPU residency — a local model's a(t) is not 1
|
||||||
|
|
||||||
|
Local "free" models contend for VRAM with interactive components (measured on
|
||||||
|
the 8 GB GTX 1070: bge-m3 + gemma3:4b + tei-reranker ≈ 6.2 GB; loading anything
|
||||||
|
bigger evicts the reranker and silently regresses recall latency). So a local
|
||||||
|
model's availability is **a(t) = f(VRAM headroom)**, and the model registry
|
||||||
|
carries a **residency policy**: a never-evict set (embedder, reranker —
|
||||||
|
interactive-critical), allowed co-residency groups, and a pre-load check every
|
||||||
|
worker must pass before pulling a model onto a GPU. With more GPUs this becomes
|
||||||
|
a placement problem — same policy, more slots.
|
||||||
|
|
||||||
|
### Personas and Cards are code
|
||||||
|
|
||||||
|
SOUL.md files and agent Cards live **in git** and are deployed to runtimes —
|
||||||
|
never edited live in volumes. "Who changed Adolf's soul" must be a `git log`
|
||||||
|
answer. (The current SOUL.md in the adolf-state volume is migration debt.)
|
||||||
|
|
||||||
|
### Eval gate on backbone/routing changes
|
||||||
|
|
||||||
|
Backbone swap being "one constraint edit" is quality-blind. Each agent keeps a
|
||||||
|
**golden set** (10–20 canonical exchanges); any backbone or routing change is
|
||||||
|
shadow-replayed against it and compared (Langfuse datasets/evals) before taking
|
||||||
|
effect. The algebra's flexibility must not become a silent-degradation machine.
|
||||||
|
|
||||||
## 4. A2A: the protocol, adopted now
|
## 4. A2A: the protocol, adopted now
|
||||||
|
|
||||||
The algebra maps 1:1 onto A2A v1.0 (Jan 2026), which is why we implement the
|
The algebra maps 1:1 onto A2A v1.0 (Jan 2026), which is why we implement the
|
||||||
@@ -149,6 +191,10 @@ Claude loop, workers) exposes/consumes A2A; Kanboard remains the durable state
|
|||||||
behind the endpoints. Scalability/extensibility later (remote nodes, third-party
|
behind the endpoints. Scalability/extensibility later (remote nodes, third-party
|
||||||
agents) then needs zero redesign.
|
agents) then needs zero redesign.
|
||||||
|
|
||||||
|
**Auth is mandatory on every A2A surface.** The LAN is **not trusted** — the
|
||||||
|
xray/3x-ui VPN terminates other people's peers on it. No unauthenticated
|
||||||
|
JSON-RPC listener, ever: shared tokens minimum, mTLS preferred.
|
||||||
|
|
||||||
## 5. Trust & sandboxing
|
## 5. Trust & sandboxing
|
||||||
|
|
||||||
**Trust classes** (on every Card):
|
**Trust classes** (on every Card):
|
||||||
@@ -183,6 +229,43 @@ Reviewer = human, or later a reviewer-agent (just another persona).
|
|||||||
(Adolf) outrank background ones (researcher, consolidation) — arbitration lives
|
(Adolf) outrank background ones (researcher, consolidation) — arbitration lives
|
||||||
in the fabric (priorities + a small governor rule), not in LiteLLM.
|
in the fabric (priorities + a small governor rule), not in LiteLLM.
|
||||||
|
|
||||||
|
**Fabric hygiene (runaway protection):** agents submit tasks that cause agents
|
||||||
|
to submit tasks — idempotency keys stop duplicates, not generative loops. So:
|
||||||
|
per-agent **task-creation quotas**; an **ancestry depth cap** on provenance
|
||||||
|
chains; cycle detection at submit; and a **dead-letter** state for poison tasks
|
||||||
|
after max-retries — never an infinite retry loop through paid quota.
|
||||||
|
|
||||||
|
## 5b. Humans (plural) and memory partitioning
|
||||||
|
|
||||||
|
There is more than one human already (alvis and elizaveta are both on Adolf's
|
||||||
|
Matrix allowlist) and there will be more. Every human is an agent with
|
||||||
|
trust=human, their own inbox, and — critically — **their own privacy domain**.
|
||||||
|
|
||||||
|
**Memory partitioning (hard rules):**
|
||||||
|
|
||||||
|
- **Per-human private banks**: `adolf-alvis`, `adolf-elizaveta`, … Everything
|
||||||
|
learned in conversation with human H goes to H's private bank by default.
|
||||||
|
**Content from one human's conversations must never surface to another
|
||||||
|
human.** This is a correctness property, not a preference.
|
||||||
|
- **One shared household bank** for facts that are explicitly household-wide
|
||||||
|
(addresses, devices, routines, shared plans). Trusted agents may write;
|
||||||
|
**promotion from a private bank happens only by that human's explicit action
|
||||||
|
or approval task** — never automatically.
|
||||||
|
- **Recall is interlocutor-scoped**: when Adolf talks to H it recalls from H's
|
||||||
|
private bank + the shared bank, nothing else. The recall/retain hooks select
|
||||||
|
the bank by interlocutor identity.
|
||||||
|
- Sandboxed agents (Torgash, researcher) read at most the shared bank; never
|
||||||
|
any private bank. This is the cross-human face of the memory matrix.
|
||||||
|
- The current single `adolf` bank is migration debt: split into
|
||||||
|
`adolf-alvis` + shared.
|
||||||
|
|
||||||
|
**Human inbox design:** notifications are priority-routed — gate/urgent tasks
|
||||||
|
ping the human via Matrix (Adolf initiates them; cf. proactive-messaging work),
|
||||||
|
everything else lands in a daily digest from the fabric-keeper. Ignored gate
|
||||||
|
tasks park and re-remind; **they never default-approve**. Vacation mode: a
|
||||||
|
human's a(t)=0 parks their inbox like any other scarce queue — gated flows
|
||||||
|
wait; predefined degraded defaults apply where explicitly configured.
|
||||||
|
|
||||||
## 6. Executor — thin KB-polling workers
|
## 6. Executor — thin KB-polling workers
|
||||||
|
|
||||||
No Temporal/Hatchet: at homelab scale (dozens of tasks/day) a durable-execution
|
No Temporal/Hatchet: at homelab scale (dozens of tasks/day) a durable-execution
|
||||||
@@ -205,6 +288,32 @@ queued. Two workers on one queue never double-run a task (claim is atomic).
|
|||||||
Idempotency keys on submission prevent duplicate proactive tasks. OpenClaw cron
|
Idempotency keys on submission prevent duplicate proactive tasks. OpenClaw cron
|
||||||
is the proactive *submitter* (Adolf's schedule); workers are the *drainers*.
|
is the proactive *submitter* (Adolf's schedule); workers are the *drainers*.
|
||||||
|
|
||||||
|
### 6b. Who is "the scheduler"? — decomposed, plus one janitor
|
||||||
|
|
||||||
|
There is deliberately **no central dispatcher**. Scheduling decomposes into
|
||||||
|
four concerns, each with its own owner:
|
||||||
|
|
||||||
|
| Concern | Question | Owner |
|
||||||
|
|---|---|---|
|
||||||
|
| Triggering | when do tasks appear? | OpenClaw cron, agents' delayed self-submissions, humans |
|
||||||
|
| Dispatch | which task runs next? | each queue's worker (claim by priority under its a(t)) |
|
||||||
|
| Admission | may it run now? | LiteLLM budgets/rate + the budget governor |
|
||||||
|
| **Time semantics** | deadlines, missed crons, stuck tasks? | **the fabric-keeper** |
|
||||||
|
|
||||||
|
The **fabric-keeper** is one tiny always-on daemon that never assigns work: it
|
||||||
|
sweeps expired leases back to queued, enforces deadlines (escalating to
|
||||||
|
inboxes), applies per-schedule **cron catch-up policy** (missed window →
|
||||||
|
run-once | skip, configured per schedule), moves poison tasks to dead-letter,
|
||||||
|
emits the human daily digest, and exports queue depths to Zabbix. Deadline and
|
||||||
|
catch-up semantics live here and nowhere else.
|
||||||
|
|
||||||
|
### 6c. Kanboard is tier-0 now
|
||||||
|
|
||||||
|
Promoting KB to the fabric's backbone promotes its ops class: **backups on par
|
||||||
|
with the vault**, Zabbix monitoring of the service and API, and a defined
|
||||||
|
**degraded mode** — if KB is down, Adolf still answers Matrix chat (no fabric
|
||||||
|
operations, no task memory), workers park, nothing crashes or data-loses.
|
||||||
|
|
||||||
## 7. Observability — Langfuse (kept), wired for real
|
## 7. Observability — Langfuse (kept), wired for real
|
||||||
|
|
||||||
Decision: keep **Langfuse** (already deployed; best-in-class self-hosted:
|
Decision: keep **Langfuse** (already deployed; best-in-class self-hosted:
|
||||||
@@ -251,3 +360,24 @@ completion is traced here — this is where sub-Task granularity lives.
|
|||||||
9. Executor = thin KB-polling workers; no Hatchet/Temporal at this scale.
|
9. Executor = thin KB-polling workers; no Hatchet/Temporal at this scale.
|
||||||
10. Sync routing = LiteLLM Auto Router v2; fabric owns async/parking.
|
10. Sync routing = LiteLLM Auto Router v2; fabric owns async/parking.
|
||||||
11. Sandbox = per-task workspace lease + container + PR-only merges.
|
11. Sandbox = per-task workspace lease + container + PR-only merges.
|
||||||
|
|
||||||
|
Added in v2.1 (hardening review, same day):
|
||||||
|
|
||||||
|
12. **Multi-human**: per-human private banks + shared household bank;
|
||||||
|
interlocutor-scoped recall; cross-human leakage forbidden (hard rule);
|
||||||
|
promotion to shared only by the owning human's action/approval.
|
||||||
|
13. A2A auth mandatory everywhere — the LAN is untrusted (VPN peers).
|
||||||
|
14. KB = tier-0 infrastructure (backup, monitoring, degraded mode).
|
||||||
|
15. Done column = unverified completion; closed task = verified; the producer
|
||||||
|
never closes its own task.
|
||||||
|
16. Scheduler = decomposed (cron/self-submission triggers; workers dispatch;
|
||||||
|
LiteLLM+governor admit); the **fabric-keeper** janitor owns time semantics;
|
||||||
|
cron catch-up policy is per-schedule config.
|
||||||
|
17. Personas/Cards live in git, deployed — never edited live.
|
||||||
|
18. Backbone/routing changes gated by golden-set shadow eval (Langfuse).
|
||||||
|
19. Fabric hygiene: creation quotas, ancestry depth cap, cycle detection,
|
||||||
|
dead-letter for poison tasks.
|
||||||
|
20. GPU residency policy: local a(t)=f(VRAM); never-evict set (embedder,
|
||||||
|
reranker); pre-load checks.
|
||||||
|
21. Transport: sync = direct A2A RPC (journaled); async = KB polling; polling
|
||||||
|
never on a sync path.
|
||||||
|
|||||||
Reference in New Issue
Block a user