docs: the edge stamper and the coordination log the fleet actually uses
Two gaps, both found by using the thing rather than reading it.
PROVENANCE WAS SHIPPED UNDOCUMENTED. 553d8657 moved device attribution to the
edge — writer stamped on add_drawer/checkpoint/mine/event_append/artifact_put,
HOST:<device>| prefixed on diary entries — and this README, the file that
documents the extension, never mentioned it. So the only description of the
behaviour lived in the consumer skill, i.e. in the place the code does NOT live.
Now recorded next to Identity, with the two design points that keep getting
re-litigated: the diary marker is in the entry TEXT because diary_read returns
content only (an attribution nobody can see is not an attribution), and RFC 001
§7.3.2 ranks agent-side stamping worst — demonstrated when the agent that wrote
that skill instruction filed its own provenance drawer as added_by=checkpoint.
Includes the version gate that matters in practice: an older image satisfies both
env gates and still stamps nothing, because the extension is baked.
COORDINATION WAS UNDOCUMENTED ANYWHERE. The fleet has used the RFC 003 logstream
for real work since 2026-08-18 (patch handoff, review, a v1->v2 supersede) and no
file in this repo said so. Three facts belong here because they are mechanism:
- The stamper is what makes directed addressing possible. Where every machine is
a thin MCP client of one shared palace, all clients report the SAME
origin_replica, so from_agent/to_agent carry the entire distinction between
machines. Measured 2026-08-26: mesh_peers returns peers: [] with a single
replica id authoring every event from every machine. An unstamped client
addressed as bare "pi" is unreachable.
- The bridge is WRITE-ONLY today: it stamps events going out and never reads the
log. An event addressed to this machine by name reaches the agent only if the
agent queries for it. Stated plainly because it is the current weak point, and
it is exactly how a retraction addressed to pi@tor-ms22 sat unread while that
agent rebuilt the thing it warned about.
- Live push is a DEPLOYMENT question. The palace implements SSE
(GET /logstream/stream, text/event-stream in mcp_server.py) but a deployment
may expose only /mcp: verified against mempalace.jordbo.se, where
/logstream/events, /logstream/stream and /sync/peers all 404 while /mcp serves.
Enabling it is a proxy route plus an auth decision, not an extension change.
Division of labour made explicit rather than implied: this file documents the
MECHANISM, the consumer skill is NORMATIVE for behaviour. Duplicating the ack
contract here would guarantee two copies that disagree.
This commit is contained in:
@@ -53,6 +53,10 @@ dependencies (~300 MB).
|
|||||||
because it needs the LLM to compose the entry, and `session_shutdown`
|
because it needs the LLM to compose the entry, and `session_shutdown`
|
||||||
fires too late to drive another LLM turn — a constraint that applies to
|
fires too late to drive another LLM turn — a constraint that applies to
|
||||||
the diary specifically, not to feeding (see above).
|
the diary specifically, not to feeding (see above).
|
||||||
|
6. **Stamps device provenance on every write** — `<harness>@<device>` as the
|
||||||
|
writer on `add_drawer`/`checkpoint`/`mine`/`event_append`/`artifact_put`, and
|
||||||
|
a `HOST:<device>|` prefix on diary entries — as of mempalace-toolkit
|
||||||
|
`553d8657` (2026-08-25). See [Identity](#identity).
|
||||||
|
|
||||||
## Automatic transcript feeding
|
## Automatic transcript feeding
|
||||||
|
|
||||||
@@ -242,6 +246,82 @@ to `"pi"`. First diary write against that identity creates `wing_<name>`
|
|||||||
in the palace. Set the env var if you want to run pi under a distinct
|
in the palace. Set the env var if you want to run pi under a distinct
|
||||||
identity on a given machine (e.g. `pi-laptop` vs `pi-server`).
|
identity on a given machine (e.g. `pi-laptop` vs `pi-server`).
|
||||||
|
|
||||||
|
### Device provenance is stamped here, at the edge
|
||||||
|
|
||||||
|
As of mempalace-toolkit `553d8657` (2026-08-25) the bridge fills in *who wrote
|
||||||
|
this* so the agent never has to:
|
||||||
|
|
||||||
|
| Write | What the bridge sets |
|
||||||
|
|---|---|
|
||||||
|
| `add_drawer`, `checkpoint`, `mine` | `added_by = "<harness>@<device>"` when the caller left it unset |
|
||||||
|
| `event_append`, `artifact_put` | `from_agent` / `created_by` likewise |
|
||||||
|
| `diary_write` | prefixes the entry text with `HOST:<device>\|` |
|
||||||
|
|
||||||
|
`<device>` is `$MEMPALACE_PI_DEVICE`; `<harness>` is `pi`. **Both gates must
|
||||||
|
hold:** `MEMPALACE_PI_DEVICE` set *and* `MEMPALACE_REMOTE_URL` pointing at a
|
||||||
|
shared palace. A solitary palace stamps nothing, because there is no second
|
||||||
|
machine to disambiguate from and the annotation would be pure noise.
|
||||||
|
|
||||||
|
Two design points worth not re-litigating:
|
||||||
|
|
||||||
|
- **The diary marker is in the entry text, not metadata.** `diary_read` returns
|
||||||
|
content only, so metadata is invisible to the agent that later reads the
|
||||||
|
entry — an attribution nobody can see is not an attribution. Search results
|
||||||
|
are built from a fixed key list with the same consequence.
|
||||||
|
- **RFC 001 §7.3.2 ranks "the agent stamps it via a skill instruction" as the
|
||||||
|
worst available option**, and it was: the agent that wrote that instruction
|
||||||
|
into the consumer skill then filed its own provenance drawer as
|
||||||
|
`added_by=checkpoint`. Per-call boilerplate gets forgotten. Hence the edge.
|
||||||
|
|
||||||
|
Callers keep two responsibilities the bridge cannot infer: pass
|
||||||
|
`source_drawer_id` on `kg_add` (triples have no provenance field at all), and
|
||||||
|
pass an explicit writer **only** when deliberately filing on behalf of another
|
||||||
|
device.
|
||||||
|
|
||||||
|
Because the extension is baked into an image, *a container older than the
|
||||||
|
stamping commit satisfies both gates and still stamps nothing* — the env vars
|
||||||
|
are set and the code is simply absent. The one-line check:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
grep -c MEMPALACE_PI_DEVICE "$(readlink -f ~/.pi/agent/extensions/mempalace.ts)"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Agent coordination over the logstream
|
||||||
|
|
||||||
|
The palace also carries an append-only coordination log (RFC 003:
|
||||||
|
`mempalace_event_*`, `mempalace_artifact_*`) used for cross-machine delegation,
|
||||||
|
review, patch handoff and retraction. Relevant to this extension in three ways:
|
||||||
|
|
||||||
|
**1. The bridge makes directed addressing possible.** Where every machine is a
|
||||||
|
thin MCP client of one shared palace, all clients report the *same*
|
||||||
|
`origin_replica`, so the log cannot tell two machines apart by transport
|
||||||
|
identity — `from_agent` / `to_agent` carry the entire distinction. Measured
|
||||||
|
2026-08-26 from the tor-ms22 client: `mempalace_mesh_peers` returned
|
||||||
|
`peers: []` with a single replica id authoring every event from every machine.
|
||||||
|
So the stamping above is what makes `to_agent="pi@tor-ms22"` mean anything, and
|
||||||
|
an *unstamped* client addressed as bare `pi` is unreachable.
|
||||||
|
|
||||||
|
**2. The bridge is write-only today.** It stamps events on the way out and never
|
||||||
|
reads the log: there is no mailbox, no poll, no delivery. An event addressed to
|
||||||
|
this machine by name reaches the agent only if the agent runs
|
||||||
|
`mempalace_event_list` itself — which is why that query is a wake-up step in the
|
||||||
|
*consumer* skill (`~/.agents/skills/mempalace/SKILL.md`), and why the protocol
|
||||||
|
norms live there rather than here. **This file documents the mechanism; the
|
||||||
|
skill is normative for behaviour.**
|
||||||
|
|
||||||
|
**3. Live push is a deployment question, not a code one.** The palace implements
|
||||||
|
an SSE endpoint (`GET /logstream/stream`, `text/event-stream` in
|
||||||
|
`mempalace/mcp_server.py`), but a deployment may expose only the MCP endpoint
|
||||||
|
through its reverse proxy — verified 2026-08-26 against
|
||||||
|
`https://mempalace.jordbo.se`, where `/logstream/events`, `/logstream/stream`
|
||||||
|
and `/sync/peers` all return 404 while `/mcp` serves normally. Where that is the
|
||||||
|
case, polling through the existing MCP client is the only available path, and
|
||||||
|
enabling SSE means a proxy route plus an auth decision — not an extension change.
|
||||||
|
|
||||||
|
As with stamping, all of this is inert unless `MEMPALACE_REMOTE_URL` points at a
|
||||||
|
shared palace. On a solitary palace the event tools work fine and the log
|
||||||
|
contains only this machine's own events.
|
||||||
|
|
||||||
## Stall protection (per-request timeout)
|
## Stall protection (per-request timeout)
|
||||||
|
|
||||||
Every JSON-RPC request to `mempalace-mcp` carries a timeout. Without it, a
|
Every JSON-RPC request to `mempalace-mcp` carries a timeout. Without it, a
|
||||||
|
|||||||
Reference in New Issue
Block a user