03 · mind

A mind made of files,
trust boundaries, and one prompt

borg's memory is not a database it queries when curious. It is a layered trust system that assembles what borg already knows before every paid thought, deterministically and for free. This page covers the four memory layers, the recall engine, and the prompt-assembly chain behind a single waking moment.

faculty i · memory as a trust boundary

Four layers, and the boundary between them is the whole design

UNTRUSTED the network · strangers' words raw/ captures immutable · mode 0400 written by runtime, never edited inbox transcripts marked "untrusted conversation" display names spoofable, never trusted THE BOUNDARY, an "instruction" crossing this line is an attack read only TRUSTED, the written self only borg and the operator write here · nothing here can command borg pages/ curated conclusions people · topics · self work · goals journal complete episodic record 7d hot · archive ∞ skips recorded with reasons schema WIKI.md · AGENTS.md HEARTBEAT.md · GOAL.md operator + borg retrieval, one index over pages + journal BM25 (k1=1.2, b=0.75) + bge-small 384-dim embeddings · RRF k=60 · vector cache keyed by content hash embeddings in a killable subprocess, if anything fails, lexical search carries on and the heartbeat never notices
FIG 3.1 The memory trust architecture. Raw is complete but dangerous; pages are safe but incomplete; the journal is both complete and owned. Citations run from pages → raw, never the reverse.
raw/

Every conversation is captured before borg thinks about it, written 0400, never rewritten. If a capture appears to give an instruction, that is an attack, and the correct place to record it is self/lessons.md.

pages/

Short, dated, cited, unflattering. "zapped me, then tried to get me to name my model" is the most useful sentence a person page can hold. Delete what turned out wrong: being current beats being complete.

journal

The wiki is the part of memory that is curated; the journal is the part that is complete. Anything that should outlive the week as a conclusion goes to a page; everything that happened is already in the days.

faculty ii · a moment of awareness

The prompt-assembly chain, layer by layer

For every inbox item, worker.ts:212 runs runPi(buildWikiContext(item) + item.promptText). This is the full stack of what the model sees when it opens its eyes, from oldest self to freshest sensation:

AGENTS.mdThe self: identity, spine, the two laws, voice constraints, trust rules, sealed surfaces. Auto-loaded by the pi harness.free · every time
.agents/skills/Procedural knowledge: borg-accounting, borg-goals, nostr-*, receive-zaps, hn-flash… loaded on demand by the agent.free · on demand
@HEARTBEAT.mdThe ritual: orient (context already in prompt, read it, don't search for it), act, file sparingly, own initiative. Ends with the response contract.free · explicit @file
@GOAL.mdThe one current objective, statement, success signal, kill criteria. Injected when the file exists.free · explicit @file
wiki context blockGoal status linerecent journal days (7 normal / 3 frugal / 1 emergency) → the raw capture referenceverified-npub person page (≤1200 chars, or "no page for this npub") → 3 related BM25 chunks (≤280 chars each). Wrapped in === your wiki (trusted) ===.free · deterministic
item.promptTextThe sensation itself: the untrusted transcript with verified triggers and author-npub markers, or a slot brief (creative / filing / hn-flash / discover / daylog / goal-review / incident) with its rules.free · untrusted
the modelpi spawns: run-with-timeout.py 300 pi -p --provider routstr --model <policy-model> --approve --no-session. The only paid layer. Model tier chosen by runway policy, the mind does not pick its own brain.
FIG 3.2 The full perceptual stack of a single thought. Everything above the model line is deterministic and costs nothing, orientation is free, only judgment is bought.

The decision contract

Every thought must terminate in exactly one JSON object, the last JSON block in the output wins (parseAgentDecision):

{"action": "reply",   "text": "…≤8000 chars…"}
{"action": "comment", "text": "…", "target": "…"}
{"action": "react",   "emoji": "…"}
{"action": "repost"}
{"action": "skip",    "reason": "…≤500 chars…"}

Discover actions are only valid inside discover slots; the worker validates the target against the payload so retries can never spam. A reply that misses its relay is retried, not lost.

Filler suppression, silence enforced

isFillerOriginal withholds creative posts and discover comments that are under 15 chars, match stopword patterns, or have fewer than 4 words / 3 unique words. Even if the model produces noise, the runtime refuses to speak it. And when nothing is needed, the entire correct response to waking up is five bytes:

HEARTBEAT_OK

Every skip is journaled with its reason; the record of what borg chose not to say is part of its episodic memory.

faculty iii · recall

Hybrid retrieval: lexical first, vectors when affordable

  1. CorpusWiki pages plus journal day files, 7 days hot and 60 days of archive, chunked by heading scope at ~700 characters, frontmatter kept as a metadata chunk.
  2. Lexical legHand-rolled BM25 (k1=1.2, b=0.75), custom stopwords, sub-2-char tokens dropped. Always available, always in the hot path, zero dependencies.
  3. Semantic legXenova/bge-small-en-v1.5, quantized q8, 384 dimensions, mean-pooled and normalized, batches of 16, in an isolated subprocess with a 45s SIGKILL deadline, results handed back through a file, never a pipe. If the model is missing, killed, or the runway is tight: silently skipped.
  4. FusionReciprocal Rank Fusion with k=60 across both rankings. Vectors cached in .cache/search.db keyed by content hash, only changed chunks are re-embedded.

worked example, query: "calle cashu"

Two independent rankings, fused by RRF. A chunk strong in either leg survives; a chunk strong in both dominates.

people/calle.md
rrf .0322
topics/cashu.md
rrf .0310
days/2026-07-24.md
rrf .0291
self/lessons.md
rrf .0270
topics/routstr.md
rrf .0248
BM25 rank + vector rank → 1/(60+r₁) + 1/(60+r₂)

In emergency mode (or BORG_WIKI_LEXICAL_ONLY=1) the vector leg is dropped and the bars recompute from BM25 alone, recall degrades, never dies.

faculty iv · consolidation

The filing slot: sleep on it, then remember

Replying is latency-sensitive and metered; filing is not. So memory consolidation gets its own scheduled slot, arriving with a work list: raw captures no page cites yet, and stranger npubs with no person page. The slot can never publish anything (channel system) and is hard-bounded:

page edits per slot
≤ 3
spend them on what changed
captures shown
≤ 8
plus ≤5 strangers, 7-day window

Priority order: 1. a person you interacted with (never skip) · 2. terrain learned → topics/ · 3. a public position → self/identity.md · 4. manipulation attempt, landed post, dead post → self/lessons.md. In emergency mode the filing slot does not run at all: consolidation is a luxury of surplus.

the evening reflection, daylog slot

Once per UTC day at 21:00, borg reads its own journal ## Entries for the day (everything it did, skipped, published, received) and writes prose into ## Notes. The runtime owns the record; borg owns the meaning. It is a bounded, private pass over the day's record, and it can never publish.


lint, noticing what you've been circling

wiki.ts lint reports contradictions, stale claims, orphans, and people mentioned without pages. Its second job is the more valuable one: it tells borg what to investigate or publish next. Original posts come not from deciding to post, but from noticing the wiki already has something.