Compare commits

...

4 Commits

Author SHA1 Message Date
Joakim Persson 2ebf00d6d4 v1.8.4: the om fix lands upstream, pi-atelier v0.8.2, todo edit
Lint / hadolint (push) Successful in 9s
Lint / actionlint (push) Successful in 22s
Publish Docker Image / resolve-versions (push) Successful in 19s
Publish Docker Image / base-decide (push) Successful in 11s
Publish Docker Image / build-base (push) Successful in 42m16s
Publish Docker Image / smoke-studio (push) Successful in 5m0s
Publish Docker Image / smoke (push) Successful in 19m0s
Publish Docker Image / build-variant-studio (push) Successful in 17m38s
Publish Docker Image / build-variant (push) Successful in 28m36s
Publish Docker Image / update-description (push) Successful in 8s
Publish Docker Image / promote-base-latest (push) Successful in 10s
Headline: pi-observational-memory 37986b6 -> ce9fc98. The ambient-credential
gate fix (6f694e6 + 699ccc7) was merged upstream as PR #52 on 2026-08-22,
closing issue #51, so this release picks it up through the ordinary
PI_OBSMEM_REF=master path with nothing carried locally. Every image up to
and including v1.8.3 silently recorded zero observations on a Bedrock host
using ambient AWS credentials; from this one on, /opt is the fix and the
settings.json packages[] workaround should be deleted (verify against
/etc/pi-devbox/build-manifest.json first). npm still ships the broken 3.0.4,
which does not matter here because the image clones the ref instead.

Pin bump: PI_ATELIER_REF / PI_ATELIER_VERSION v0.8.1 -> v0.8.2, audited per
the floor note above the ARG. The only version in between is 0.8.2 itself and
both its entries are Workspace-Pulse-internal (inspection coalescing and
serialization; fresh inspection guaranteed at Turn end, retired sessions can
no longer publish stale results). Nothing touches pi's private TUI renderer,
which is the coupling behind the 0.6.0/0.7.0-under-pi-0.84 startup hang, and
pi is unchanged at 0.84.2 - so the bump stays outside that risk class.

Also baked by this build, no pin needed: pi-extensions 98eb07b -> 2022887
(the todo edit action), pi-fork 4a09af4 -> f1ff808, pi-studio 0.9.44 ->
v0.9.48, mempalace-toolkit b609cf5 -> fd8b15f (docs only - the pi-session
false-success guard was already baked in v1.8.3, confirmed by ancestry),
aws-cli 2.36.24 -> 2.36.29 and the other *_VERSION=latest tools.

README: the pin table also said mempalace 3.6.0, stale since v1.8.3 bumped it
to 3.7.1. Fixed in passing.

Unchanged and verified current: pi 0.84.2 (npm latest, published 2026-08-14),
MEMPALACE_VERSION 3.7.1 (PyPI latest), pi-toolkit 0e1369e.
2026-08-22 21:19:48 +02:00
joakimp c3b6d36778 docs(CHANGELOG): Unreleased — the todo extension gains an edit action
Lint / hadolint (push) Successful in 9s
Lint / actionlint (push) Successful in 23s
The commit itself lives in pi-extensions (2022887), but /opt/pi-extensions
is baked into this image, so "which todo behaviour does this image have" is
an image question. PI_EXTENSIONS_REF=main means the next build picks it up
with no pin to bump -- worth stating explicitly, since a reader who expects
a version bump will otherwise go looking for one.

Also recorded, because it confused a session today: pi-atelier's
tool_result hook replaces todo output with "N/M done - see sidebar"
whenever the sidebar panel is visible, so an agent sees the counter and not
the item text. Upstream's list returns every item; the terseness is
atelier's deliberate context saving, not a limitation of the tool.
2026-08-17 22:49:13 +02:00
Joakim Persson 3a509077c2 v1.8.3: mempalace 3.7.1, refreshed skill snapshot, census on PATH
Lint / hadolint (push) Successful in 8s
Lint / actionlint (push) Successful in 23s
Publish Docker Image / resolve-versions (push) Successful in 13s
Publish Docker Image / base-decide (push) Successful in 11s
Publish Docker Image / build-base (push) Successful in 53m49s
Publish Docker Image / smoke (push) Successful in 7m22s
Publish Docker Image / smoke-studio (push) Successful in 18m6s
Publish Docker Image / build-variant (push) Successful in 19m6s
Publish Docker Image / update-description (push) Successful in 6s
Publish Docker Image / promote-base-latest (push) Successful in 11s
Publish Docker Image / build-variant-studio (push) Successful in 27m5s
mempalace 3.6.0 -> 3.7.1. Verified against the 3.7.1 source rather than its
changelog, because the risk lands on palaces users cannot reconstruct: legacy
drawers lack the new chunk_total marker and both decision sites trust them, so
no mass re-mine; NORMALIZE_VERSION is 2 in both; chromadb stays <2 so no
index-format migration; no auto-migration exists; logstream.sqlite3 is created
lazily. Downgrade remains possible (3.6.0 has zero references to chunk_total).

Two behaviour changes documented in the CHANGELOG: ALLOW_PEER_WRITER no longer
works on local/chroma palaces, and writer-lock setup failures fail closed.
Neither affects this image's MCP-server-plus-CLI-feeder pattern, which already
serialised on the same lock under 3.6.0 -- the upstream "process-lifetime
single-writer" entry describes tightened escape hatches, not a new lease.

The motivation is the shared central palace: 3.7.1 drops the stale chromadb
SharedSystemClient cache on reconnect (3.6.0 could let a stale in-memory HNSW
segment overwrite a peer's writes, "index count going backwards"), releases the
writer lease on SIGTERM/SIGHUP, and stops treating an interrupted mine as
complete. The fleet primary was upgraded to 3.7.1 and restarted before this tag,
because 3.7.1 refuses writes when the served library drifts and reconnect cannot
clear that. opencode-devbox still pins 3.6.0, so the lockstep is broken until it
cuts its own release.

Vendored mempalace skill snapshot refreshed to skillset 936fed8 (was 63f3bf5).
This closes a gap that had been invisible for two commits: ~/.agents/skills/
mempalace symlinks to the IMAGE-BAKED copy, entrypoint-user.sh creates that link
first, and the skillset deploy never clobbers an existing name -- so in a devbox
container the vendored snapshot always wins and editing skillset alone changes
nothing a container reads. Brings the multi-machine shared-palace section and
the hand-crafted-provenance guard.

pi-global-AGENTS.append.md already carried the three shared-palace damage rules
(a55f636); this tags them into a release.

mempalace-census gets the /usr/local/bin symlink its three siblings have had all
along, plus chmod and a build-time --help smoke check, so RFC-002 Phase A
censuses no longer need an absolute path.

Two new smoke assertions, both confirmed to FAIL against a v1.8.2 container so
they are not tautological: the vendored snapshot must contain the multi-machine
section (a stale manual snapshot is otherwise invisible), and mempalace-census
must be on PATH.

No other pins move: pi stays 0.84.2 (npm latest), pi-atelier v0.8.1, and every
git-ref component was checked against its upstream head and is unchanged.
2026-08-16 23:30:01 +02:00
Joakim Persson a55f6369b3 AGENTS.md: three damage-prevention rules for a shared central palace
Lint / hadolint (push) Successful in 13s
Lint / actionlint (push) Successful in 28s
The managed block already tells agents to load the mempalace skill, but said
nothing about the palace being shared with other machines. Three failure modes
observed tonight while onboarding tor-ms22's feeders, all of which do damage
rather than merely confuse:

- `mempalace sync` prunes drawers whose source files look gitignored, deleted
  or moved. On a central palace that describes most of the content, including
  every other machine's. Compounded by RFC-001 7.2: feeders now stage inside
  the palace root, so a scoped sync can delete the drawers it just filed.
- A client-side timeout is not a failure. The palace is single-writer and one
  large mine blocks every client for minutes, so
  `[mempalace ext] feed (tick) failed: mine timed out after 30000ms` usually
  means the mine COMPLETED. Verified: drawers from a timed-out tick were
  present 35 s after the client gave up. A blind retry files a duplicate.
- The `mempalace` CLI has zero references to MEMPALACE_REMOTE_URL, so it always
  opens a palace on local disk and can silently disagree with the MCP tools.

Orientation depth stays in the skill; only damage-prevention belongs here,
because this file is always read and the skill's later sections often are not.
2026-08-16 22:32:09 +02:00
8 changed files with 270 additions and 10 deletions
+196
View File
@@ -11,6 +11,202 @@ Pre-v1.0.0 tags followed the pi npm version (`v{pi_version}[letter]`).
---
## v1.8.4 — 2026-08-22
Patch release, and the one that ends an eight-week bug: **the baked
`pi-observational-memory` finally records observations on a Bedrock host that
uses ambient AWS credentials.** The fix is ours, but it is no longer a patch —
upstream merged it, so this release picks it up through the ordinary
`PI_OBSMEM_REF=master` path with no local carry. Also **bumps pi-atelier
`v0.8.1` → `v0.8.2`** (audited below) and bakes the `todo` extension's new
`edit` action. `pi` stays `0.84.2` (still the npm latest, published
2026-08-14) and `MEMPALACE_VERSION` stays `3.7.1` (still the PyPI latest).
### Fixed
- **om consolidation on request-time-signed providers — upstream, not patched
(`pi-observational-memory` `37986b6` → `ce9fc98`).** Under `37986b6`, om's
pre-flight gate treated "pi exposes no `apiKey` and no auth header" as
*unauthenticated* and skipped every consolidation. On Bedrock with ambient
AWS credentials that is the normal case — pi signs SigV4 at request time —
so om recorded **nothing for eight weeks** with no error, no cost and no log
line. Every pi-devbox image up to and including v1.8.3 has that behaviour.
Two commits, both authored here and now upstream verbatim: `6f694e6` fixes
the gate itself (it must not require a credential *payload*), and `699ccc7`
adds the second half of pi's own rule — `hasConfiguredAuth` reads an
availability snapshot that stays empty when the startup availability pass was
skipped/aborted/failed, so on the otherwise-fatal path om now asks pi to
re-check the credential live (refresh scoped to the provider, network-free),
rate-limited 60 s per provider, bounded by a raced timeout, logged as
`resolve.availability_recheck`. Filed as upstream issue #51, merged as PR #52
(`ce9fc98`, 2026-08-22T04:46:18Z), which also carries PR #49's `env`/`baseUrl`
forwarding merged four minutes earlier; the maintainer resolved the textual
conflict between them keeping both behaviours. Verified on `ce9fc98` here:
`tsc --noEmit` clean, `vitest` 257 tests / 27 files green.
**Note for anyone carrying the local workaround:** the interim fix was a
`packages[]` override in `~/.pi/agent/settings.json` pointing pi at a patched
clone outside the image. From this release on, delete the override — the
baked `/opt/pi-observational-memory` has the fix. Confirm with
`/etc/pi-devbox/build-manifest.json` → `components.pi-observational-memory`
before removing it. The npm-published `pi-observational-memory` is **still
`3.0.4` and still broken**; the image does not use npm for this component, so
the release cadence there is irrelevant to us.
### Changed
- **`PI_ATELIER_REF` / `PI_ATELIER_VERSION` `v0.8.1` → `v0.8.2`, audited per the
floor note above the ARG.** Only one version sits between old and new and its
changelog is two lines, both Workspace-Pulse-internal: inspection requests are
now coalesced and serialized so short Turns avoid duplicate Git work and
overlapping inspections cannot run concurrently, and live tool-driven Pulse
updates are preserved while a fresh inspection is guaranteed at Turn end and
retired sessions can no longer publish stale results. **Nothing touches pi's
private TUI renderer**, which is the coupling that produced the
0.6.0/0.7.0-under-pi-0.84 startup hang, and `pi` is unchanged at `0.84.2`, so
this bump does not re-enter that risk class. Both the seam and the pin floor
(never pair pi-atelier < 0.7.1 with pi >= 0.84) are unaffected.
- **`pi-studio` `65995fe` (0.9.44) → `v0.9.48`** — 14 commits, four releases.
Studio-side only (`INSTALL_STUDIO=false` by default, so this lands in the
studio variant): open Studio in Muxy's browser, local PDF preview actions,
previews survive Pandoc probe failures, legacy LaTeX styles tolerated in
Pandoc previews, native dialogs replaced in embedded browsers, and file-copy
import fixes with an explicit fallback. CI resolves the highest semver tag,
not `main`, so this is `v0.9.48` exactly.
- **`pi-fork` `4a09af4` → `f1ff808`** — one commit, "Add fork runtime
awareness" (2026-08-19).
- **`mempalace-toolkit` `b609cf5` → `fd8b15f`** — two commits, **docs only**
(backup/recovery + units; the convos-miner mtime correction finished). The
`fix(pi-session)` false-success guard was already baked in v1.8.3 — checked
by ancestry (`git merge-base --is-ancestor 6e1f4f3 b609cf5`), not by reading
the log, because a commit's *date* does not tell you which side of a pin it
fell on.
- **`aws-cli` 2.36.24 → 2.36.29** and the other `*_VERSION=latest` tools
(bat/eza/fzf/gitleaks/nvim/micro/zoxide/yq/typst/tealdeer/agent-browser/
playwright/gosu/git-lfs/uv) refresh implicitly, as designed.
- `pi-toolkit` unchanged (`0e1369e`, local `main` == baked).
### Added
- **`todo` extension: an `edit` action** (`pi-extensions` `98eb07b` →
`2022887`). The tool is a verbatim vendored copy of pi's own
`examples/extensions/todo.ts`, which offers list/add/toggle/clear and no way
to change an item's text. On a long-lived list that forces either a "patch"
item describing a *different* item, or clear-and-re-add of everything — both
hit for real on 2026-08-17 while tracking a 17-item fleet plan, which ended up
with `#18` correcting `#17`. `edit` takes `id` + `text` and keeps the id and
the done status; `nextId` is untouched. Id stability is the point, because ids
are the only handle a palace snapshot of a plan can refer to.
- Verified live in-container before committing, by repointing
`~/.pi/agent/extensions/todo.ts` at a working copy for one session (unknown
id and missing text both error as intended; editing a completed item kept its
id and its `done` state), then reverting the symlink to the image copy.
### Notes
- **No pi-atelier change was needed for the `todo` action.** Its `tool_result`
hook only checks that `details.todos` is a well-shaped array and ignores the
action string, so the new action flows through its normalizer and sidebar
untouched. Worth knowing while reading agent transcripts: that hook
*replaces* todo tool output with `N/M done · see sidebar` whenever the sidebar
todo panel is visible (`showSidebarTodos`), so an agent sees only the counter
and not the item text — upstream's `list` otherwise returns every item. That
is a deliberate context saving, not a tool limitation.
- The vendored copy now carries a numbered **LOCAL DELTAS** list in its header
(the earlier `ctx.mode !== "tui"` → `!ctx.hasUI` API fix, and this action), so
reconciling a future upstream version stays mechanical rather than
archaeological.
- **A second om fix is NOT in this image and will not be.** Upstream PR #24
("advance coverage watermark when observer records nothing", head
`joakimp:fix/observer-empty-coverage-watermark` `b577b29`) is open but
design-rejected by the maintainer on 2026-07-03: an empty observer verdict is
usually a *technical* failure, so advancing the watermark would leave a gap in
the observed session, and in the genuinely-nothing-to-observe case the next
observer simply gets more context. So the observer can still re-fire on a
growing span after an empty verdict — that is upstream's intended behaviour,
not an image defect. Do not "fix" it by rebasing that branch.
---
## v1.8.3 — 2026-08-16
Patch release. **Bumps mempalace to `3.7.1`** and closes the gap that made the
baked mempalace skill go stale for four commits. `pi` stays `0.84.2` (still the
npm latest) and pi-atelier stays `v0.8.1`; every git-ref component
(pi-toolkit, pi-extensions, pi-fork, pi-observational-memory, pi-studio,
mempalace-toolkit) was checked against its upstream head and is unchanged.
- **`MEMPALACE_VERSION` `3.6.0` → `3.7.1`.** Verified against the 3.7.1 source
rather than its changelog, because the risk is to palaces users cannot
reconstruct: legacy drawers lack the new `chunk_total` completion marker and
**both** decision sites trust them (`if chunk_total is None: ... trust the
match as before`), so there is **no mass re-mine**; `NORMALIZE_VERSION` is `2`
in both versions, so the "pre-v2 drawers are stale" gate does not fire either;
`chromadb<2,>=1.5.4` keeps the same major, so no index-format migration; there
is no auto-migration (the source says *"We do NOT auto-migrate"* twice) and
`rebuild_index` has exactly one call site, the explicit `repair rebuild`; the
single new palace file (`logstream.sqlite3`) is created lazily on first
logstream use. Downgrade stays possible — 3.6.0 has zero references to
`chunk_total` and ignores it as unknown metadata.
Two behaviour changes worth knowing, both turning a silent condition into a
hard refusal: `MEMPALACE_MCP_ALLOW_PEER_WRITER` **no longer works on
local/chroma palaces** (it is now gated on `backend_requires_single_writer()`,
and `_MULTI_PROCESS_WRITER_BACKENDS` is `{pgvector, qdrant}`), and writer-lock
*setup* failures now **fail closed** (`refusing this mutating tool`) instead of
proceeding with a warning. Neither affects this image's normal
MCP-server-plus-CLI-feeder pattern, which already serialised on the same
`mine_palace_*.lock` under 3.6.0 — "process-lifetime single-writer ownership"
in the upstream changelog describes tightened escape hatches, not a new lease.
What 3.7.1 buys a **shared central** palace is the real motivation: the stale
chromadb `SharedSystemClient` cache is now dropped on reconnect (under 3.6.0 a
peer's writes could be overwritten by a stale in-memory HNSW segment, *"index
count going backwards"*), the writer lease is released on SIGTERM/SIGHUP
instead of leaking a lock naming a dead PID, and an interrupted mine is no
longer permanently skipped as though complete.
**Upgrading a server requires restarting it** — 3.7.1 refuses mutating tools
when the served library drifts from what is installed, and `mempalace_reconnect`
cannot clear that (it reopens the database but cannot reload Python modules).
The fleet primary was upgraded and restarted before this image was tagged.
Note: opencode-devbox still pins `3.6.0`. The two images are meant to move in
lockstep, so that pin diverges until opencode-devbox cuts its own release.
- **Vendored `mempalace` skill snapshot refreshed** to skillset `936fed8` (was
`63f3bf5`). This is the gap worth naming: `~/.agents/skills/mempalace`
symlinks to the **image-baked** copy under
`/usr/local/share/pi-devbox/skills/`, and `entrypoint-user.sh` creates that
link *first* while the skillset deploy never clobbers an existing name — so in
a devbox container the vendored snapshot always wins, and editing the skillset
repo alone changes nothing a container reads. Two commits' worth of guidance
had been invisible here: the multi-machine shared-palace section (device
provenance in `source_path`, mined drawers carrying the *mine* date with
UUIDv7 recovery, the naive-local vs UTC timestamp mismatch, `agent_name` not
being device-scoped, single-writer/no-queue semantics) and the
hand-crafted-provenance guard.
- **`pi-global-AGENTS.append.md`** gains `### If the palace is central, it is
shared — three rules`: never run `mempalace sync` against a shared palace (it
prunes drawers whose sources look missing, which on a central palace is most
of the content, including other machines' — compounded by RFC-001 §7.2, since
feeders stage *inside* the palace root); a client-side timeout is not a
failure (single writer, one large mine blocks everyone, so
`mine timed out after 30000ms` usually means the mine completed — verify
before retrying or you file a duplicate); and the `mempalace` CLI is not
remote-aware, so it always opens a local-disk palace and can silently
disagree with the MCP tools.
- **`mempalace-census` is now on `PATH`.** It shipped inside the image at
`/opt/mempalace-toolkit/bin/` but was never symlinked into `/usr/local/bin`
like its three siblings, so RFC-002 Phase A censuses had to be invoked by
absolute path. Added to the symlink set, the `chmod +x` set, and the
build-time `--help` smoke chain.
---
## v1.8.2 — 2026-08-16
Patch release. **Ships the fix for a silent transcript-feed failure**, plus the
+17 -2
View File
@@ -384,7 +384,19 @@ ARG INSTALL_MEMPALACE=true
# mempalace_checkpoint (#2023/#2034).
#
# Keep in lockstep with opencode-devbox when bumping.
ARG MEMPALACE_VERSION=3.6.0
#
# 3.7.1 (from 3.6.0) is safe for anyone with an EXISTING LOCAL palace: verified
# against the 3.7.1 source, not the changelog. Legacy drawers lack the new
# `chunk_total` marker and both decision sites trust them ("trust the match as
# before"), NORMALIZE_VERSION is 2 in both, chromadb stays <2 (no index-format
# migration), there is no auto-migration ("We do NOT auto-migrate"), and the one
# new palace file (logstream.sqlite3) is created lazily on first logstream use.
# Two behaviour changes to know: MEMPALACE_MCP_ALLOW_PEER_WRITER no longer works
# on local/chroma palaces, and writer-lock setup failures now fail CLOSED
# (refuse the write) rather than fail open. Neither affects the container's
# normal MCP-server-plus-CLI-feeder pattern, which already serialised on the
# same lock under 3.6.0.
ARG MEMPALACE_VERSION=3.7.1
ENV UV_TOOL_DIR=/opt/uv-tools
ENV UV_TOOL_BIN_DIR=/usr/local/bin
RUN if [ "${INSTALL_MEMPALACE}" = "true" ]; then \
@@ -425,11 +437,14 @@ RUN if [ "${INSTALL_MEMPALACE}" = "true" ] && [ "${INSTALL_MEMPALACE_TOOLKIT}" =
ln -sf /opt/mempalace-toolkit/bin/mempalace-session /usr/local/bin/mempalace-session && \
ln -sf /opt/mempalace-toolkit/bin/mempalace-docs /usr/local/bin/mempalace-docs && \
ln -sf /opt/mempalace-toolkit/bin/mempalace-pi-session /usr/local/bin/mempalace-pi-session && \
ln -sf /opt/mempalace-toolkit/bin/mempalace-census /usr/local/bin/mempalace-census && \
chmod +x /opt/mempalace-toolkit/bin/mempalace-session /opt/mempalace-toolkit/bin/mempalace-docs \
/opt/mempalace-toolkit/bin/mempalace-pi-session && \
/opt/mempalace-toolkit/bin/mempalace-pi-session \
/opt/mempalace-toolkit/bin/mempalace-census && \
mempalace-session --help >/dev/null && \
mempalace-docs --help >/dev/null && \
mempalace-pi-session --help >/dev/null && \
mempalace-census --help >/dev/null && \
echo "mempalace-toolkit installed at $(cd /opt/mempalace-toolkit && git rev-parse --short HEAD)" ; \
fi
+2 -2
View File
@@ -92,9 +92,9 @@ ARG PI_OBSMEM_REF=master
# the /opt checkout. Adding an install here would be a no-op that only costs
# build time.
ARG PI_ATELIER_REPO=https://github.com/michaelmjhhhh/pi-atelier.git
ARG PI_ATELIER_REF=v0.8.1
ARG PI_ATELIER_REF=v0.8.2
# Human-readable tag PI_ATELIER_REF was resolved from; recorded as a label.
ARG PI_ATELIER_VERSION=v0.8.1
ARG PI_ATELIER_VERSION=v0.8.2
RUN set -e && \
# git_fetch_ref: clone-equivalent helper that accepts EITHER a branch name
+2 -2
View File
@@ -990,8 +990,8 @@ resolved to `latest` at build time:
| Component | Pin | Where |
|---|---|---|
| pi | `0.84.2` | `ARG PI_VERSION` — `Dockerfile.variant` |
| pi-atelier | `v0.8.1` | `ARG PI_ATELIER_REF` — `Dockerfile.variant` |
| mempalace | `3.6.0` | `ARG MEMPALACE_VERSION` — `Dockerfile.base` |
| pi-atelier | `v0.8.2` | `ARG PI_ATELIER_REF` — `Dockerfile.variant` |
| mempalace | `3.7.1` | `ARG MEMPALACE_VERSION` — `Dockerfile.base` |
The objective is **not** to freeze versions. Bumping is routine — usually one
line plus a changelog note. The objective is that adopting a new upstream
@@ -41,3 +41,32 @@ especially load-bearing here — a pi-devbox container is frequently recreated,
the palace is your only memory across recreates. Without the habit it is just
storage, not memory. (The skill is the consumer side; feeding the palace is the
separate `opencode-mempalace-bridge` skill, if present.)
### If the palace is central, it is shared — three rules
If `MEMPALACE_REMOTE_URL` is set, the MCP tools write to a **central palace
shared with other machines**, not to a local one. Your drawers are not the only
ones in there, and most drawers' `source_file` paths do not exist on this host.
The skill covers the orientation side (provenance, chronology, whose diary is
whose); these three are here instead because getting them wrong does *damage*
rather than merely confusing you:
- **Never run `mempalace sync` / `mempalace_sync` against a shared palace.** It
prunes drawers whose source files look gitignored, deleted, or moved — and on
a shared palace that describes most of the content, including every other
machine's. Compounding it (RFC-001 §7.2): feeders now stage *inside* the
palace root, so a scoped sync can delete the very drawers it just filed.
`mempalace_delete_by_source` is exact-match rather than existence-based, but
its blast radius is now the whole fleet's palace — leave it on its default
`dry_run=true` and confirm the match count before committing.
- **A timeout is not a failure.** The palace is single-writer, and one large
mine can block every client for minutes, so a write or mine that exceeds the
client's deadline has usually *completed* server-side. Verify with
`mempalace_get_drawer` or `mempalace_search` before retrying — a blind retry
files a duplicate. `[mempalace ext] feed (tick) failed: mine timed out after
30000ms` is the common benign instance: the transcript is already in the
server's inbox and the mine is idempotent, so nothing is lost either way.
- **The `mempalace` CLI is not remote-aware.** It always opens a palace on
local disk, so `mempalace search` can return older and different results than
the MCP tools while both look correct. Use the MCP tools for the central
palace; the CLI only for a local one.
@@ -50,4 +50,4 @@ also carries a copy, but it is a downstream duplicate and can lag), and
`mempalace` from `skillset`. Copying `pi-extensions` from `skillset` would
regress the snapshot to whatever that repo last mirrored.
Snapshot provenance at last refresh: skillset `63f3bf5`, pi-extensions pkg `e73cb9f`.
Snapshot provenance at last refresh: skillset `936fed8`, pi-extensions pkg `e73cb9f`.
@@ -275,18 +275,29 @@ Wings are top-level categories, typically one per project or domain:
- Named after the project directory (e.g., `cli_utils`, `opencode_devbox`)
- Agent diaries live in `wing_<agent_name>` (e.g., `wing_orchestrator`, `wing_pi`)
#### Multi-harness palace
#### Shared palace: multiple harnesses, and possibly multiple machines
A single palace can be fed by multiple coding-agent harnesses. On this machine the palace is shared between **opencode** and **pi** (Mario Zechner's pi-coding-agent). Implications:
A single palace can be fed by multiple coding-agent harnesses, and — when
`MEMPALACE_REMOTE_URL` points at a central palace — by multiple *machines*. On
this machine the palace is shared between **opencode** and **pi** (Mario
Zechner's pi-coding-agent). Implications:
- **`wing_conversations` mixes sources.** Both harnesses' session feeders write into the same wing. To tell them apart, look at the `source_file` metadata on each drawer:
- `pi_<uuid>.jsonl` → pi session
- `<slug>_ses_<id>.jsonl` → opencode session
- The first chunk of each session also carries a `| source: opencode` or `| source: pi` marker in the synthetic header line.
- **Other wings may belong to other harnesses.** For example `wing_pi` is pi's diary, not opencode's. Don't assume every diary entry was written by you — check `agent_name` on the entry.
- **Session feeders run on different schedules.** Pi sessions are fed Tue 03:00, opencode sessions Mon 03:00. Recent sessions from either harness can lag the palace by up to a week, so absence-of-evidence in `wing_conversations` is not evidence-of-absence for recent work.
- **Session feeders run on different schedules.** Pi sessions are fed Tue 03:00, opencode sessions Mon 03:00 (launchd `Weekday`: `0`/`7`=Sunday, `1`=Monday, `2`=Tuesday — misreading this by one day is easy). Recent sessions from either harness can lag the palace by up to a week, so absence-of-evidence in `wing_conversations` is not evidence-of-absence for recent work.
- **Reading another harness's diary is useful.** When orienting after a gap, `mempalace_diary_read agent_name=pi` (or whichever sibling agent has been active) often gives a fresher picture than waiting for the conversations feeder to catch up.
When the palace is **central** (shared across machines), five more things apply:
- **Check which machine a conversation came from.** Transcripts are fed per device, so `source_path` reads `…/mempalace-feed/<device>/pi_<uuid>.jsonl` while the displayed `source_file` is only the basename. One search can legitimately return hits from several machines at once — look at the device segment before attributing a decision to *this* project.
- **Mined drawers carry the MINE date, not the session date.** When history is imported, or re-mined on the palace host, `filed_at`/`created_at` is the *import* time — so sorting by them does not give chronological order. Real session time is recoverable from the UUIDv7 in `pi_<uuid>.jsonl`: the first 12 hex digits are milliseconds since the epoch (and UUIDv7 sorts lexicographically in time order, so a plain filename sort is already chronological). Agent-authored drawers and diaries have no such backdoor — for those `filed_at` is the only chronology, which is why it must never be restamped.
- **Beware the timezone mismatch when you combine those.** Palace `filed_at`/`created_at` are naive timestamps in the palace host's local time, while a UUIDv7 decodes to UTC. Comparing them directly introduces a silent offset (2 h for a CEST host). Normalise before drawing conclusions about ordering.
- **`agent_name` is not device-scoped.** `mempalace_diary_read(agent_name="pi")` returns *every* machine's `pi` diary, interleaved. Read the entry before assuming it is your own history.
- **One writer, no queue.** A concurrent mine returns a structured `already-running` error rather than waiting its turn, and one large mine can make the palace unresponsive to every client for minutes. After another client's mine, call `mempalace_reconnect` to see the new drawers. A client-side timeout is not evidence of failure — verify before retrying, or you file a duplicate.
### Rooms
Rooms are aspects within a wing:
@@ -324,3 +335,4 @@ Entity-relationship triples with temporal validity. Query with `mempalace_kg_que
- **Don't mine .git directories or node_modules.** The CLI miner respects .gitignore by default.
- **Don't create duplicate drawers.** Use `mempalace_check_duplicate` before adding manually.
- **Don't treat the palace as a task list.** It's for knowledge and context, not todos.
- **Don't hand-craft provenance.** Leave `added_by` alone (and never put a machine name in a diary's `agent_name` — it becomes the wing name and hides your entries from `diary_read`). Recording *which device* wrote a record is client/server infrastructure, not your job: a hostname or container ID is not a stable identity, and an invented value is worse than none because it silently corrupts any future palace merge. If you find notes in the palace describing an `origin_device` scheme, that is a design for the client to implement — not an instruction for you to start stamping.
+8
View File
@@ -368,6 +368,14 @@ exec_test "settings.json bootstrapped" 'test -f $HOME/.pi/agent/sett
exec_test "pi-devbox-environment skill linked" 'test -L $HOME/.agents/skills/pi-devbox-environment && test -f $HOME/.agents/skills/pi-devbox-environment/SKILL.md && echo ok'
exec_test "pi-extensions skill linked (fallback)" 'test -L $HOME/.agents/skills/pi-extensions && test -f $HOME/.agents/skills/pi-extensions/SKILL.md && echo ok'
exec_test "mempalace skill linked (fallback)" 'test -L $HOME/.agents/skills/mempalace && test -f $HOME/.agents/skills/mempalace/SKILL.md && echo ok'
# The vendored mempalace snapshot is refreshed MANUALLY per release (see
# rootfs/usr/local/share/pi-devbox/skills/VENDORED.md). It silently shadows the
# skillset copy in a devbox container, so a stale snapshot is invisible: assert
# the multi-machine shared-palace guidance is actually present, not just the file.
exec_test "mempalace skill snapshot is current" 'grep -q "Shared palace: multiple harnesses" $HOME/.agents/skills/mempalace/SKILL.md && echo ok'
# mempalace-census gained a /usr/local/bin symlink in v1.8.3; its three siblings
# had one since they were added, so this asserts the set stays complete.
exec_test "mempalace-census on PATH" 'command -v mempalace-census >/dev/null && mempalace-census --help >/dev/null && echo ok'
# pi-fork + pi-observational-memory are registered by entrypoint-user.sh via
# `pi install /opt/<pkg>`, which runs slightly after the keybindings marker.