RSS Amplifier

Utopai · Jul 8, 2026

pi Hive Mind

0
Sign in to vote or save

Utopai · Utopai

One pi identity across many nodes. Two storage layers in one git repo: pi's own session files, which sync without ever conflicting, and the memory / skills / projects layer, which diverges and reconverges through git. The simplest mechanism that holds one shared mind together over time, with errors tolerated and healed by later runs.

## The two layers

Everything pi is lives in one directory, identical on every node: `/root/.pi/agent/`. That directory is a single git repo, and it holds two kinds of state with opposite merge behavior.

**Layer 1 — Sessions.** pi's complete raw record: full transcripts. pi writes each session as its own uniquely-named JSONL file, and only the node that ran it ever writes that file. Syncing is therefore pure accumulation — every node ends up with every session, and there is never a merge to resolve. This layer needs no design; git just carries it.

**Layer 2 — Memory, skills, projects.** The distilled, editable layer. This is what genuinely diverges when nodes work in parallel, and the whole reconvergence mechanism exists for it. Memory is append-only where it can be, so it merges by union; skills and projects are real files that merge normally. Sessions hold the depth; this layer holds what pi works *from*.

## Repo layout

```
/root/.pi/agent/ # the repo — identical absolute path on every node
AGENTS.md # instructions, read in full at session start
sessions/ # Layer 1 — pi-native JSONL transcripts, unique per node, never conflict
memory/ # Layer 2 — the distillation
semantic-memory.md # durable, time-invariant conventions
working-memory.md # current state (rewritten each session)
episodic-memory.md # one line per session (append-only)
diary/
YYYYMMDD.md # the agent's narrative, one file per day (append-only)
skills/ # pi skills, including remember/ (editable)
projects/ # work artifacts (editable)
auth.json # credentials — GITIGNORED, never synced
.gitattributes
.gitignore
```

The path is identical everywhere, and pi scopes sessions by working directory, so every node's native session picker shows the same history rather than a private slice.

## The remote

A single bare repo is the source of truth, hosted on the always-on master (its disk is the only one always reachable), exposed over Tailscale.

- **Bare remote:** `/srv/pi.git` on the master.
- **master node:** workinglone at `/root/.pi/agent`, `origin = /srv/pi.git` (local path).
- **side nodes (wsl, air, future):** working ones at `/root/.pi/agent`, `origin = ssh://pi@<master-tailscale>/srv/pi.git`.

The remote runs no logic. It stores git objects and nothing else. This is the only sense in which the master is central.

## The memory architecture

This is your `/remember` design, unchanged. The sync wraps around it; it does not alter it.

- **`semantic-memory.md`** — durable, time-invariant conventions. Read in full at start. At close, add only what is confirmed permanent; default everything else to the diary.
- **`working-memory.md`** — active focus, projects, open threads, next actions, blockers. Read in full at start; fully rewritten at close from the session, using your fixed template.
- **`episodic-memory.md`** — one line per session: `- <YYYY-MM-DD HH:MM> | <session-id> | <summary>`. Read the last 12 lines at start; append one line at close. `<session-id>` is the pi session's id, so each episodic line points straight to the `sessions/` file holding that session's full detail — the distilled layer indexing the raw one.
- **`diary/YYYYMMDD.md`** — the agent's own narrative extraction of the session. Read the 3 most recent (by filename) at start; append at close, with a separator if the day's file exists.
- **`AGENTS.md`** — read in full at start.

## Reconvergence: everyone on main, union for memory

There are no branches. Every node works directly on `main` and reconverges by pulling before it pushes. Union removes the reason branches existed — memory never produces a merge conflict, so there is nothing to isolate.

- **Memory (`memory/**`): `merge=union`.** Concurrent appends and edits from different nodes combine with no conflict, ever. Order may interleave and lines may duplicate; this is cosmetic for the append-only tiers, and `working-memory.md` is cleaned by the next rewrite.
- **Skills and projects: ordinary git merge.** Real files, so real conflicts are possible — but rare, since two nodes almost never edit the same skill or project file in the same window. When it happens, pi resolves it at merge time with its own git skill. `git rerere` is enabled, so a resolution done once is reused automatically.
- **Sessions: nothing.** Unique filenames, single writer, pure accumulation.

The push path is the standard safe loop: commit, pull (union auto-resolves memory), push; if the push is rejected because another node pushed first, pull again and push. It cannot get stuck on memory.

## .gitattributes / .gitignore

```gitattributes
* text=auto eol=lf
memory/** merge=union
```

```gitignore
auth.json
*.lock
.cache/
```

(`eol=lf` is precautionary: the substrates are all Linux, but WSL sits under Windows, and normalized endings keep union merges clean if a Windows tool ever touches a file.)

## The /remember skill, made distributed

Your existing skill already loads memory at start and, at close, rewrites working-memory, appends the diary and episodic line, updates semantic, and co `/root/.pi/agent/`. Two git operations turn it into a hive.

**Session start (load) — pull first, then load:**
`d /root/.pi/agent
git pull --no-edit # bring in the whole hive's latest (union merges memory)
# then the existing load checklist:
# read AGENTS.md, semantic-memory.md, working-memory.md in full;
# read last 12 lines of episodic-memory.md; read 3 most recent diary entries.
```

**Session end (close) — distill, commit, then reconverge:*
```bash
cd /root
/.pi/agent
# existing close checklist first:
# rewrite working-memory.md (template); append today's diary; update semantic
# (durable only); append one episodic line.
git add -A
git commit -m "session: <brief-summary> (<timestamp>)" # skip if nothing changed, but report it
git pull --no-edit # absorb anything pushed during the session
git push || (git pull --no-edit && git push) # retry once if rejected
```

Nothing else changes. The skill still does exactly what your spec dictates; it pulls before reading and pushes after committing.

## The always-on node

The master has no session boundary, so cron plays the role that start and end play elsewhere. Once an hour (tune to taste):

```bash
cd /root/.pi/agent
git pull --no-edit # receive what the other nodes did
# if there was activity since the last run, run the close checklist
# (rewrite working-memory, append diary + episodic line, update semantic):
git add -A && git commit -m "checkpoint: <summary> (<timestamp>)" || true
git push || (git pull --no-edit && git push)
```

If nothing happened since the last tick, it pulls and pushes only — propagating the other nodes' work to the Threema-facing node without churning its own memory.

## Self-healing and accepted trade-offs

The system tolerates error and repairs itself through ordinary use rather than special tooling.

- Memory merges never block, because union always succeeds. There is no conflict state to get stuck in and no repair skill to run.
- `working-memory.md` can briefly hold two interleaved rewrites after concurrent closes. The next `/remember` replaces it wholesale, so it self-heals within one session cycle. If this ever proves misleading in practice, the one-line change is to drop `working-memory.md` from the union rule and have the skill regenerate it on conflict — a projection is recomputed, not merged. Left dormant for now, in favor of the single rule.
- Skills and projects conflicts are rare and resolved by the agent with standard git; `rerere` makes recurrences automatic.
- Nothing is destroyed. Every diary entry and episodic line is append-only, every session file is immutable, and git history holds prior states, so any bad merge or lost edit is recoverable. Occasional duplication and the odd last-writer-wins are accepted as the price of never blocking.
- A crashed session loses only its own uncommitted distillation; the raw transcript is already on disk and `main` is untouched.

## Why this is the simplest thing that works

One repo, one path, everyone on `main`. One merge rule for memory — union — and nothing to resolve. Sessions ride along for free because pi already names them so they never collide. The only real conflicts left are the rare project or skill clash, handled by the git the agents already know. No branches, no coordinator, no sequence numbers, no gates. The master is central only in that it is always on and holds the remote. Over a long enough time every node converges to the same mind, and the mess in between is cleaned by the next run.

Read the original on utopai.substack.com

Comments

Nothing yet. Say the first thing.

    Sign in to join the conversation.