apps/pi and packages/db. Where the PLAN’s premise didn’t match the code, it’s flagged
with ❓ [needs Raymond: …] — do not paper over these in the published page.
Premise correction up front: the SOP/PLAN reference to a/reports/folder does not exist in code or skills. The real canonical persistence directory is/memory/.references/…is skill-relative, not an operator-facing org folder. Details below.
1. What the VFS actually is
Pi’s per-org “file system” is database-backed, not a real disk. Each file is a row in theVirtualFile Prisma model.
- Model:
packages/db/prisma/schema.prisma:1196-1208— fieldspath,content(@db.Text),isDirectory, scoped byorganizationIdwith@@unique([organizationId, path]). Every file belongs to exactly one org; a directory is just a row withisDirectory = true. - Class:
apps/pi/src/lib/virtual-fs.ts:22—class VirtualFS(db, organizationId), constructed per request/org (e.g.apps/pi/src/chat.ts:25,apps/pi/src/lib/run-agent.ts:148). Paths are normalized POSIX; the agent’s working directory is the VFS root/(run-agent.tsDEFAULT_CWD = '/').
CORE_ORG_ID = '__core__', virtual-fs.ts:11) that always wins on read and holds system files — including the
skills tree at /skills/**/SKILL.md. When an operator/Pi tries to write over a core file, the write
is intercepted and saved as a ProposedEdit for review, with the message “Core file ’…’ is
read-only. Your proposed changes have been saved for review.” (virtual-fs.ts:110-126). So org work
lives in the org layer; the shared skills/system files are read-only.
The tools Pi uses on the VFS
Registered inapps/pi/src/tools/core/virtual-fs/create-virtual-fs-tools.ts; spread into the agent
toolset via create-core-tools.ts:
| Tool | Does | File |
|---|---|---|
read | read a file (text + images), paged | .../virtual-fs/read.ts |
write | create/overwrite a file | .../virtual-fs/write.ts |
edit | exact find-and-replace | .../virtual-fs/edit.ts |
ls | list a directory | .../virtual-fs/ls.ts |
find | glob search by path pattern | .../virtual-fs/find.ts |
grep | regex/literal content search | .../virtual-fs/virtual-grep.ts |
delete | remove (recursive flag) | .../virtual-fs/delete.ts |
2. Standard folders — where files live
Confirmed conventions from code + skills:Root context files — apps/pi/src/lib/context-files.ts:10-15 (CONTEXT_PATHS)
| Path | What it holds |
|---|---|
/SOUL.md | Per-org persona / voice / values overlay (see §3) |
/IDENTITY.md | Pi’s self-identity for this org — name, creature, vibe, emoji |
/MEMORY.md | The long-term memory index — injected into the prompt every turn |
/BOOTSTRAP.md | One-time onboarding script; deleted after onboarding |
loadContextFiles
(context-files.ts:17-35, wired in apps/pi/src/systemPrompt/index.ts:117).
/memory/ — the canonical persistence directory (the real “reports”)
This is where durable artifacts go. The pattern across skills: write the canonical copy to a
deterministic /memory/… path; chat is only the working copy. Confirmed uses:
- Sub-agent large outputs →
/memory/<task_id>/<name>.md, returning a ref (systemPrompt/index.ts:194, 217). - Product Bible →
/memory/{account}-product-bible.md(apps/pi/core-skills/product-bible/SKILL.md:90). - Keyword-eval reports/followups →
/memory/keyword-eval-report-<orgId>-<YYYY-MM-DD>.md/-followups-…(apps/pi/core-skills/keyword-evaluation/SKILL.md:159, 184, 204). - SEO-debug reports →
/memory/debug-<slug>-<orgId>-<YYYY-MM-DD>.md, described as “the canonical artifact… Chat is the working copy” (apps/pi/core-skills/seo-debug/SKILL.md:242, 273, 288). - Analytics setup notes →
/memory/posthog.md,/memory/mixpanel.md(apps/pi/core-skills/posthog-setup/SKILL.md:48,mixpanel-analytics/SKILL.md:17).
/account-management/ — the structured operator workspace (AM cadence)
Fully specified in apps/pi/core-skills/account-management/SKILL.md:22-56:
/account-management/memory.md (SKILL.md:45-48, 271). Note
this is a different file from root /MEMORY.md — don’t conflate the two in the docs.
references/… is skill-relative — NOT an org folder
references/onboarding-weeks-1-4.md etc. are relative to a skill’s own directory in the
/skills tree (e.g. account-management/SKILL.md:91, 118, 243-250), read by Pi from within a loaded
skill. Do not document references/ as an operator-facing VFS directory.
3. How memory & soul work
Both are plain VFS files loaded into the system prompt each turn (not DB columns), viaformatContextFilesPrompt (context-files.ts:49-62):
- SOUL → injected in
<soul>with “Embody this persona and tone.” - IDENTITY → injected in
<identity>. - MEMORY → injected in
<memory>with “Use this memory to maintain continuity across sessions.”
context-files.ts:64-72):
- Before answering about prior work/decisions/people/preferences, Pi searches
MEMORY.md+memory/*.md, then reads only the needed lines (the “Memory Recall” rule). MEMORY.mdis truncated after line 200 in the prompt, so it’s kept as a concise index — detailed notes go in separate files under/memory/and are linked fromMEMORY.md. Organized by topic, not chronologically; stale entries get pruned.
/SOUL.md — the code comment says this is deliberate so “every org gets it on day one
without depending on a per-org VFS file being seeded” (systemPrompt/index.ts:46-53, workingStance
at :77-97). So /SOUL.md is an optional per-org overlay on top of an always-present stance —
an org with no SOUL.md still behaves correctly. The docs should not claim SOUL.md is required for
Pi to have a personality.
Onboarding / how it’s set up (apps/pi/src/lib/bootstrap.ts):
BOOTSTRAP_TEMPLATESseeds default/SOUL.md,/IDENTITY.md,/MEMORY.md,/BOOTSTRAP.md(bootstrap.ts:3-115);bootstrapContextFileswrites each only if absent (idempotent).- Triggered by
POST /api/v1/orgs/:orgId/bootstrap(apps/pi/src/routes/bootstrap.ts:7), auth-gated so the JWTorgclaim must equal the path org. - The seeded
/BOOTSTRAP.mdscripts the wake-up conversation: Pi talks with the operator to set name/nature/vibe/emoji, updatesIDENTITY.md, discusses and writesSOUL.md, then deletes/BOOTSTRAP.mdwhen done (bootstrap.ts:60-114). This is the code behind PLAN page 2.1.1 “Create the org & initialize Pi (memory + soul)“.
4. How an operator files work into the VFS
There is no dedicated “file this” tool and no magic phrase — filing goes through the ordinarywrite/edit tools, and where a thing lands is governed by the active skill’s convention. Three
patterns to teach:
-
Persist-to-
/memory/(the dominant pattern). Skills tell Pi to write the canonical artifact to a deterministic/memory/…filename and treat chat as the working copy. Real phrasing from code:seo-debug/SKILL.md:288: “Persist the report. The MD in/memory/is the canonical artifact. Chat is the working copy.”keyword-evaluation/SKILL.md:204: “Persist every run… must be written to/memory/. The chat output is not the canonical record.”product-bible/SKILL.md:90: “Write the bible to/memory/{account}-product-bible.md. Add a reference link inMEMORY.md.”
-
Append-to-notes (account-management). Told to record persistent knowledge, Pi reads the right
/account-management/notes/*.md, appends with a date stamp, one line per fact (account-management/SKILL.md:70, 168-172, 276). -
Honor an explicit path (fallback).
slide-deck/SKILL.md:141: “Save to wherever the user asked. If they didn’t specify, default to [the skill default].” This is the closest to a generic “file this under X” — Pi writes to a path you name, otherwise falls back to the skill’s convention.
/memory/… file and (per the product-bible/memory pattern) can add an index line
to MEMORY.md so it’s findable later.
/account-management/notes/client-preferences.md.
Not the same thing — the report tool. “File a report about a bug/gap” routes to the DB
FeedbackItem inbox via the report tool (systemPrompt/index.ts:127-157), not the VFS. Keep
this distinct on the page: save/file a document → /memory/ or /account-management/notes/;
report a problem with the platform → the feedback inbox.
Flags for Raymond (unconfirmed / premise corrections)
❓ [needs Raymond: the SOP "/reports/" folder — code uses "/memory/" instead. Confirm the docs should teach "/memory/" and drop "/reports/", or tell me where "/reports/" lives.]❓ [needs Raymond: "references/…" is skill-relative in code, not an operator VFS folder — confirm we should NOT teach it as a place operators file work.]❓ [needs Raymond: USER.md is referenced only inside the seeded BOOTSTRAP template and is NOT in CONTEXT_PATHS / not auto-loaded — is it an intentional context file or just onboarding scratch?]- Core working stance is hardcoded in the prompt (not SOUL.md) — documented above as fact from
systemPrompt/index.ts:46-53; flag only if the framing should change.