Skip to content

Project map

Where things are in Pi Pocket, for agents working on it. index.md lists every guide; AGENTS.md and self-editing.md have the rules for editing it while it runs; architecture.md explains how the parts depend on each other and the orderings they rely on; features.md says what each feature does.

bin/pi-pocket.js checks Node, then runs src/launcher/main.ts. The launcher reads its options (options.ts), asks how devices connect (access.ts: this device, LAN, Cloudflare quick tunnel, Tailscale), runs the server (src/server/main.ts) as a child, restarts it on exit code 75 or a crash, and keeps the tunnel up. term.ts draws its menu, panel, and QR code in the terminal. The server takes the data folder’s lock, opens one PocketApp, and serves it with http.ts.

  • pocket.sqlite: Pi Durable’s storage: conversations, entries, tasks, and Pi Pocket’s documents.
  • config.json: people, roles, hashed tokens, settings. push.json: VAPID keys and push subscriptions.
  • uploads/<conversation>/, worktrees/ (sessions’ git worktrees), extensions/ (the owner’s drop-ins), themes/ (the owner’s theme folders, and .removed/ for removed ones), browser/profile/ (the built-in browser’s profile; each session’s cookies live in memory only).

A module split into parts keeps its name for the part others import, with the rest in a folder of the same name beside it (http.ts and http/, browser.ts and browser/). Modules import what they use from the module that owns it; there are no barrels. PocketApp creates the app’s parts and hands each one the app; callers use them as fields (app.workspace.viewFile(…), app.attribution.requesterOf(…)).

File Owns
main.ts The server process: options, the port, signals, then PocketApp.open and createHandler
app.ts PocketApp: opening the harness, reading state back at startup (#recover), the commit coordinator (#committed), connected tabs and their peek tiles, access checks (canSee, requireSteer, requireDriver), the session list (each session’s subagents counted by state), every subagent for the subagents board (subagents, setBoard), hello, model list with Pi’s enabledModels scope (modelList), extensions on and off
attribution.ts Who Pi works for: who wrote each message to Pi or whose work it is (authors documents, from request ids), who queued each submission; read back at startup
room.ts One conversation’s live view for its tabs: Pi Durable’s view plus ROOM_DOCS, sent every 90 ms as changes; its peek tile (peek, at most once a second) for the tabs that show it (PocketApp.setPeeks)
projection.ts Entries as compact JSON for browsers; usageCost
timing.ts Every model stream timed: when it started, its first token, and its end, stamped on the response for the status line’s speed
entry-format.ts The kinds of Pi Pocket’s own entries, and the markers it writes into message text ([from: …], attached files). Stored data and the web app depend on their exact values
fence.ts Text from elsewhere between tags as data, for Pi: no closing tag survives inside it
docs.ts Every durable document Pi Pocket defines
host.ts, reload.ts PocketHost (what extensions get) and Approvals; the extension loader: built-ins in ORDER, drop-ins (never with a name Pi Pocket keeps, BUILT_IN_TOOLS), live reload
extension-web.ts What extension modules add to the app (web, their default export’s second argument): routes, the browser module and its files’ versions, events to it, commands (BUILT_IN_COMMANDS), cleanups; who may use each (mayUse), POCKET_API
lock.ts One process per data folder
errors.ts, paths.ts HttpError, describe, and input checks; ~ paths
File Owns
config.ts, auth.ts People and settings; cookies, tokens, invites
requests.ts Request ids, which say whose each message to Pi is (u: a person’s own, p: sent for a person)
collab.ts Chat, activity lines (addActivity), reactions, pins, notes, typing, take turns
alerts.ts, push.ts Push notifications: who hears about what; Web Push without dependencies (RFC 8291, 8292)
spend.ts Cost per conversation and person; limits, a team’s (linked sessions’) against the budget of the session that started it
File Owns
commands.ts What people ask of Pi: sessions, messages (with skills, templates, and mentioned files expanded), forks and resends, model and folder, reset, instructions, plan mode, goals, schedules, worktrees, notes Pi is told
resend.ts A message sent again: the task made with its fork that sends it
extension-commands.ts Extensions’ commands run: who may, a durable task per run that a retry finds and a restart never runs again, cards, and stopping
subagent-runs.ts How a subagent’s run ended, in the words its record keeps: for the subagent tool’s reports, and for what a person’s message to a failed subagent came to
shell.ts ! and !! commands: a background task per command that runs it and writes a pocket.shell entry; a restart cuts it off rather than running it again
schedules.ts, when.ts Scheduled messages (a durable task) and their time grammar
goals.ts “Done when” checks
titles.ts A short title for a session with a long first message, or one that runs a skill or prompt template, from the session’s own model
prompts.ts Pi’s prompt templates as slash commands, and /skill:name expanded
pi-sessions.ts Pi’s sessions from the terminal (~/.pi/agent/sessions/), read and never written: listing them, and one as a new session’s history, with Pi’s own context of it (compactions, context edits); commands.continuePiSession makes the session
skills.ts Which skills a session’s folder has, from where Pi’s CLI looks and in its order, with Pi’s project trust; the system prompt and /skill:name both use it. Reads and saves the owner’s answer to “trust this project?”
models.ts The models people can pick (marked for Pi’s enabledModels scope and when their sign-in needs renewing), the one a conversation runs with, finding one by name, and the thinking levels
project-model.ts Trusted project model/thinking defaults and fresh global-only settings read for each new session, validation, and safe errors; no resource paths or per-project run policy
model-names.ts Which models a text names, word by word: PiP passes or names a model only when its person named it
running.ts Running now, from Pi Durable’s task graph
pip.ts PiP, the owner’s assistant: its conversation (made on first open, kept out of the session list), what its tools do as its person, and the follows (a durable task each) that report to it when a session’s run ends
pip-compact.ts PiP’s context kept small: when it compacts itself, and its own summaries, written with what came from outside left out and counted in its spend
watches.ts A session’s PR watch: the durable task that looks at the PR with gh and tells Pi about failed checks, conflicts, and comments that count
hooks.ts Webhooks: making and removing them, letting a post in by its secret or GitHub’s signature, and turning it into a message for its person
repo-watches.ts Repository watches: PiP’s standing orders on a GitHub repository, and the durable task that looks at it and tells PiP or a session what happened
github.ts GitHub through gh: running it unattended, repository and PR names in every form, and whether gh’s account can push to a repository
memory.ts Memory: lessons Pi keeps across sessions, each for a project (a repository with its worktrees, or a folder) or everywhere; the lessons in force for a session, and people’s view, writes, and approvals
folder-favorites.ts Each person’s favorite folders (/api/folder-favorites): starring and unstarring one in a transaction, and each person’s list sent only to their own tabs
linked-sessions.ts Linked sessions (LinkedSessions, host.linkedSessions as LinkedSessionsApi in host.ts): starting a session from another and sending its first message, with a record of the call that makes a repeat find the first; the addresses each session knows its linked ones by; messages between them, sent once, as the person Pi works for, through Commands.submit; and a team’s bounds (10 sessions, one level, 20 messages without a person)
File Owns
workspace.ts app.workspace: which files a person may load or read through a conversation, the file viewer, the files for @ mentions, Changes, uploads, new folders from the folder picker
transcripts.ts app.transcripts: stored history as people read it: an entry (its own, or one a fork inherited), the images in it, what came before the active context, and the session as Markdown
files.ts The files in a session’s folder for @ mentions: git’s list, or a capped walk; kept briefly per folder, versioned, and compressed once. The file viewer’s reads, and the paths a message mentions
changes.ts, worktrees.ts, git.ts The Files tile’s Changes (and undoing a file there), per-session worktrees, and the git runner both use
branches.ts A session’s git branch: read from the repository’s HEAD for its view (Room looks every few seconds), listed and switched for the branch picker
export.ts A session as Markdown
File Owns
http.ts The one request handler: which part answers a path, and the error boundary that turns what it throws into a status
http/api.ts /api: signing in, the X-Pocket header, and the app-wide routes (people, sessions, Pi’s sessions from the terminal, peeks, the subagents board, spend, folders, settings, the models for subagents, extensions, providers, invites, restart)
http/conversation-routes.ts /api/c/:id: one conversation’s routes, after the API checked that the person may see it
http/browser-routes.ts /api/c/:id/browser: the Browser panel’s frames, console, and input
http/push-routes.ts /api/push: this device’s subscription, what to notify about, a test
http/hook-routes.ts /hook/:id/:secret: posts to webhooks, with no sign-in
http/events.ts Each tab’s events: the event stream (/api/events), or long polling (/api/poll) where a tunnel holds streams back
http/assets.ts The web app’s files, the vendored modules, the app’s content security policy, and image files
http/theme-routes.ts /themes/:id/:rev/…, a theme’s files for everyone signed in: its CSS as checked, from memory; its fonts and images from disk, opened as checked and sniffed
http/sign-in.ts /login, /join/:code, and /share before the service worker takes shares
http/artifacts.ts /a/…: an artifact as its own page, in a sandbox; /a/frame, the page a reply’s HTML runs in once someone taps Run
http/extension-routes.ts /api/x/:module/…, extension modules’ routes (after the API’s checks), and /x/:module/:rev/…, their browser modules’ files
http/io.ts What every route uses: reading a body, writing JSON, ApiRequest; a file to serve, read as it was checked (readChecked, opened); the policy an SVG is served with

The built-in browser: browser.ts and browser/

Section titled “The built-in browser: browser.ts and browser/”
File Owns
browser.ts Browsers: one headless Chromium for every conversation, started with the first page and stopped after the last; each conversation’s page
browser/page.ts BrowserPage: one conversation’s page: its events, screencast frames, console, navigation, and what Pi and people do to it
browser/cdp.ts The DevTools protocol over a pipe (--remote-debugging-pipe), and the Chromium process; BrowserError
browser/discovery.ts Finding a Chromium-based browser on this machine, and where its profile goes
browser/page-scripts.ts The scripts that run inside a page: the outline with refs for Pi, finding a target, selecting
browser/keys.ts Key names and combinations as key events
browser/viewport.ts, browser/urls.ts Page sizes and their presets; what people and Pi type, made into addresses
browser/local-servers.ts The web servers running on this machine, for the panel’s start screen
File Owns
providers.ts, net.ts Provider sign-ins, and those that need signing in again (a subscription its provider will not renew); HTTP settings for provider streams
gallery.ts The extension gallery (app.gallery, host.gallery): its index read and kept in the data folder’s gallery/, downloads checked against their pinned SHA-256, installs (off), updates with a diff, removal, the <name>.gallery.json provenance beside each, revoked versions, and Share’s draft entries
gallery/entry.ts The index’s format, read strictly: entries, file names in the drop-in folder’s rules, limits, compatibility, addresses. The index repository’s checks import it too
gallery/files.ts, gallery/fetch.ts An extension’s files in the drop-in folder: names checked, never through a link, a version put in place all or none with an undo journal that recover replays before extensions load; reading from other sites, https only, within size and time limits
gallery/diff.ts, gallery/share.ts A file’s change as a unified diff, for updates; whether a drop-in stands on its own, and the draft of its entry, for Share
gallery/themes.ts Themes from the gallery in the data folder’s themes/: a version written to a hidden folder, checked with readTheme, then put in place in one rename; the .gallery.json provenance in each; recovery at the start
lancet.ts Loads Lancet Guard from Pi’s install
omarchy.ts The Omarchy desktop’s current theme and wallpaper, read-only, for Follow desktop (/api/theme)
themes.ts, themes/ Theme folders (app.themes): the built-in ones in web/themes/ and the owner’s in the data folder’s themes/, read and checked (themes/format.ts: theme.json, colors.toml, limits; themes/css.ts: CSS’s tokens and the files it loads), each one’s last good version, watching, Duplicate, Remove, Edit with Pi
versions.ts Pi Pocket’s versions compared, for gallery entries’ and themes’ minPocket

Outside src/: flake.nix and nix/ build Pi Pocket with Nix (nix/package.nix) and run it as a NixOS service (nix/module.nix, with nix/manage-extensions.sh to copy declared drop-ins). nix/tests/ runs only under Nix; npm test skips it.

Each default-exports (host: PocketHost, web: ExtensionWeb) => Extension | Extension[] | void (web adds to the app: extensions/app.md) and is installed in this order: prompt (system prompt, with where Pi Pocket’s docs are), artifacts (artifact tool), browser (browser tool and its prompt section; through host.browsers), subagents (subagent tool and its tasks: anchors, reporters, and the courier that sends waiting reports to the parent together; a subagent runs on its session’s model, or one the owner allowed, and the app rebuilds the module when that list changes), agent-teams (Agent Teams, off by default: the team tool and its prompt section, through host.linkedSessions; its browser module agent-teams.js describes the tool’s calls with pocket.toolCall; it imports nothing of Pi Pocket’s but types, as a drop-in would), schedules (schedule tool; installs the schedule task), goals (hook after each answer), plan (tool hook and prompt section), guard (tool hook that asks for approval), codemode (codemode tool; a script’s calls go through the same hooks), memory (memory tool and the prompt section of lessons in force; through host.memory), pip (PiP’s tools, prompt, and follow task, through host.pip; only PiP’s conversation selects it, as PocketApp’s settings leave it out of every other conversation’s), triggers (the PR and repository watch tasks and the watch_pr tool, through host.watches and host.repoWatches; webhooks need it on), gallery (the extension gallery’s owner-only routes under /api/x/gallery/, through host.gallery, and its twice-daily look for revoked versions; it installs pocket-gallery, which tells the web app it is on).

Plain ES modules, loaded as they are. store.js holds the shared state, and nothing imports in a circle. Some modules do work when they load: back.js (it hears back and forward), store.js, ui.js (Markdown and sanitizer setup, document listeners), theme.js (the saved appearance, which prefs() reads, and safe mode, safe-mode.js, which it imports first), seen.js (when this browser last looked at each session), peeks.js, subagents-board.js (it tells the server while the board shows), browser-panel.js and files-panel.js (the panels’ saved widths), rich.js (gives Markdown its rich block), sheets.js (a step back for each sheet opened from another), transcript.js (it hears which answer a jump asked to see), extension-ui.js (it loads extensions’ browser modules as the server lists them, and hears their events), and app.js. store.set calls subscribers in the order they subscribed, so keep the order in which modules load when moving code between them.

File Owns
store.js State, the event stream (SSE, or long polling when a tunnel holds it back), api(), actions, workspaceOrder (the numbers, by session-tree.js)
back.js The back stack: routes and the layers over them (sheets, the drawer, panels that cover the screen, a file over the tree) as history entries, so back closes what opened last; useBack, pushRoute, goHome, the list put under a conversation opened straight away, taps let go that land on what just slid in
gestures.js Touch gestures, each following its own finger by its identifier, passive where they can be: sheets dragged down and the drawer dragged left to close (useDragToClose); on phones, swipes on the conversation (right back, left Files), in Files (right back), and up from the message box (the places); a swipe in from the left edge goes back in an iPhone’s home screen app
app.js Layout (tiled windows, and the subagents board in the conversation’s place), top bar (with what changed, from diff.js), notices, keyboard shortcuts, routing
transcript.js The conversation as turns: messages, Pi’s replies, its thinking and tool calls folded into groups that open into a timeline, extensions’ command cards, approvals, the live line (and Pi’s thinking above it), breadcrumbs (and linked-sessions.js, the links between linked sessions); a message from a linked session shows without its routing words
turns.js How the transcript reads a conversation, without drawing it: answers split into runs of words and groups of calls (itemsOf), a group in a line (summarize, with extensions’ own tools as extension-ui.js gives them: setCallSummary), and what a call came to from what its tool printed. No imports, so Node tests it
calls.js A tool call in one line, for the transcript’s timeline and peek tiles; extensions’ own tools as extension-ui.js gives them (setCallDescriber)
composer.js Message box, chips, the queue, plan and goal bars, @ file suggestions, ! commands, ↑ and Ctrl+R history, long-paste placeholders, the mic (voice.js), a subagent’s way back to its session, the status line under it (kept to one row)
subagents.js The subagents bar above the message box: each subagent’s state, what it was asked, and what it does now (its peek, through useOnScreen in peeks.js); Stop, open, put away. Its states and times (stateOf, nowDoing, elapsed, ordered) and failures dealt with (unresolved, dismiss, seeFailure) serve the board too
dock.js What sits above the message box (the queue, the bars) and how it shares the room with the conversation: bars whole, the queue and the subagents’ list sized to what is left, bars on one line when room is short
voice.js Dictation: the browser’s speech recognition into a message box (useDictation, words at the caret, the draft kept by the box’s own saving), the mic (MicButton), and Alt+V (toggleDictation, the newest box)
history.js What this browser sent, for ↑ and Ctrl+R
files.js @ mentions: the folder’s file list, fetched once and checked in the background, and matched here as people type
commands.js Slash commands (the app’s own, and extensions’), and prompt templates
trust.js Project trust: the bar that asks the owner whether to trust a session’s project for its own skills and its .pi/settings.json model defaults, and the sheet (/trust, the menu) that shows and changes the answer
sheets.js Which sheet is open, the component that shows it, and the nested-sheet back action supplied to Sheet through SheetBack
sheets/*.js One sheet (or a few close ones) each: the model and branch pickers, folder, extensions, providers, people and invites, the file viewer (FileView, which the Files tile shows too), find, spend, running now, schedules, webhooks, memory (the lessons Pi keeps, with the menu’s hint), worktree, Pi’s terminal sessions, appearance, shortcuts, the menu, a session’s actions, the extension gallery (gallery.js: browsing, an entry, its source, an update, sharing; galleryAvailable)
peeks.js Peek tiles: their switches (the top bar’s and the rail’s), which sessions get one and in what order, the column and the strip, the watch list
seen.js What this browser has seen: when it last looked at each session (markSeen), which runs ended since (finishedUnseen), and the server’s clock (fromServer). Peek tiles and the session list’s squares read it
chat.js People panel: presence roster, take-turns shortcut, chat bubbles, pins, notes; the chat sheet
avatar.js People’s avatars and colors, and folders’ colors
subagents-board.js The subagents board: every subagent in every session (the server’s subagents events, while it shows), soft state-colored cells and rounded session rows, the proportional state bar and filter pills, Needs you, the selected detail card (its peek), the arrows, and the phone’s layout
extension-ui.js Extensions’ browser modules: loading them as hello lists them (server.ui), pocket (the app’s API for them), and what they add: rail buttons (ExtensionRailButtons), menu rows, launcher actions, pages in the conversation’s place (ExtensionPage, state.page), and sheets (ExtensionSheet); one that fails, alone, and how their tools’ calls show (pocket.toolCall, given to calls.js and turns.js)
sessions.js The sidebar: the rail (RailNav: the tools, you, and, folded, numbered sessions) and the session list beside it (sidebar, drawer, a phone’s home screen), a line per session; selecting rows and archiving them with undo (setArchived), and a touch screen’s long press on a row, which opens sheets/session.js; linked sessions under the one that started them, with branch lines (session-tree.js, the tree as data)
home.js, signin.js The wide home screen; the sign-in screen
notify.js, sw.js Push, the icon badge, approvals from notifications, shares; the notifications sheet
share.js Share to Pi
ui.js htm binding, Markdown (code blocks colored and labeled, split into parts around the blocks rich.js draws), formatting, icons, Sheet and its optional SheetBack context, Switch, Keys, item (a menu row), usePresence (animate out), useSlide (sliding indicators), useSide (which side of the screen a region a theme may move is on), railState. Shared controls and inset .sheet-list groups are styled in style.css
theme.js Appearance: the theme (a theme folder’s stylesheets in the theme layer, swapped in as they change), the colors (palettes as CSS variables in the palette layer, a folder’s own, Follow desktop), tiling, motion, text size, sidebar shape, pins; the reveal; the cache index.html paints from; the owner’s default theme and colors for browsers whose person has not chosen
themes.js Omarchy’s themes as palettes, generated from /usr/share/omarchy/themes/*/colors.toml. themes/<id>/ holds the built-in theme folders (Pocket and Lantern); theme-surface.js lists the tokens and parts themes may rely on; safe-mode.js is ?noext=1
launcher.js The Ctrl/⌘+K launcher: search-type pills, local fuzzy matches and field highlights, leading result tiles and session status pills, live theme previews, combobox selection, focus isolation, and a New session action for each favorite folder (named as sheets/folder.js names them); app.js gives every logical opening a fresh identity
pip.js PiP’s panel over every screen (a rounded floating window in the corner, a bottom sheet on phones), fed by pipview events while open; its private file/image composer, the all-project pending-memory shortcut, its rail button, the mark that shows while it works or has news, and openPip, askPip, togglePip for the places, the launcher, /pip, and Alt+A
pip-attachments.js PiP’s browser-only text/file draft controller: account/conversation scoping, uploads, object URLs, and submit tokens; drafts survive panel closes and stale callbacks cannot change newer drafts
browser.js Whether the Browser panel is open, and opening an address in it
browser-panel.js The Browser panel: frames by long polling, taps, drags, wheel, and keys as input events, the live address bar, sizes, the console, the start screen’s local-server list
files-panel.js The Files tile: whether it is open and on which tab, the folder’s tree (folders read as they open), Go to file, the open file beside the tree, and the Changes tab
diff.js The diff viewer: one file’s diff (unified or split, line numbers, colors, changed words, hidden lines on request), DiffBlock for tool calls and replies, and DiffReview, every change file by file with viewed marks
diff-parse.js Diffs as data, without the DOM: unified diffs and Pi’s edit format as files, hunks, and lines; rows that pair changed lines by likeness; the words that changed
rich.js Code blocks in replies that show more than code (a page previewed, with Run; an SVG; a diff), given to Markdown at load (setRichBlock); HtmlPreview, Highlighted
run-frame.js RunFrame: a reply’s HTML run on a tap, in the server’s sandboxed /a/frame page, sized to fit it
highlight.js Syntax colors without dependencies: highlightLines gives escaped HTML with flat hl- spans per line, which diff.js marks changed words in

Manual refresh lives in src/server/model-refresh.ts, owned by Providers.modelRefresh; web/model-refresh.js shares the refresh and its feedback between the menu, Providers, and the launcher. test/model-refresh.test.ts checks local configuration, external sign-ins, provider isolation, cancellation, session use, and endpoint access.

PiP’s pip-window.js handles pointer resize zones and the account/browser size preference.

The menu in sheets/menu.js keeps Sheet’s focus, Escape, drag-to-close, and the sheet trail’s Back behavior. Its MenuFrame positions it below the top bar’s menu button at ≥700px, and adds arrow navigation and focus return; below that width it stays a bottom sheet. PlacesSheet uses the same three-column tiles.

  1. POST /api/c/:id/submit → commands.submit: checks access, turns, and spend, expands a template, then conversation.submit() with request id u:<userId>:<clientId>. The request id makes a retry a no-op and names the author.
  2. Pi Durable runs the generation and tool tasks, committing each step to pocket.sqlite. Extension hooks run inside those tasks.
  3. app.ts’s commit coordinator (#committed) hears every commit: spend counts usage first, then each document change updates what the app keeps in memory and the rooms that show it, and attribution.ts notes who each message is for.
  4. Each room sends its tabs what changed. store.js applies it, and Preact renders.
  • A document: define it in docs.ts. To show it live, add it to ROOM_DOCS and the view in room.ts, and read it in store.js.
  • A command: a method in commands.ts (check access first), a route in http/conversation-routes.ts (or http/api.ts for one that is not about a conversation), an action in store.js, then the UI.
  • A sheet: a component in web/sheets/, a case in sheetBody (web/sheets.js), and openSheet({ type }) where it opens.
  • Something back should close (a screen over the conversation, a view that takes another’s place on a phone): useBack(open, close) from web/back.js in the component that shows it. Sheets already have it.
  • A built-in extension: a file in extensions/ (its extension named pocket-…), its place in ORDER, its title in TITLES, and its tools in BUILT_IN_TOOLS (reload.ts), which no test checks.
  • A member of the extension API (on the host, web, pocket, or a command’s context): add it to types/pocket.d.ts with @since, and to its page in docs/extensions/reference/. test/public-types.ts (in npm run check) fails until the code and the types agree for the host, web, and a command’s context; for pocket, extension-ui.test.ts compares only the members’ names, so check its signatures by reading. A host member for built-ins only goes in Internal in public-types.ts instead.
  • A built-in slash command: web/commands.js, with its name kept from modules’ commands in BUILT_IN_COMMANDS (extension-web.ts).
  • A command of the owner’s own: a drop-in with web.command, not a change here (extensions/commands.md).
  • A page, rail button, or route that is the owner’s own: a drop-in with a web part, not a change here (extensions/app.md).
  • Browsers only see committed state. Nothing is shown before it is stored.
  • Document kinds, scopes, and fork settings are stored data: never change them.
  • Hooks get only memo and snapshot. Anything a replay must not repeat goes in a memo or behind an idempotent request id.
  • Whose work Pi does comes from request ids (requests.ts): a message sent for someone needs their id in its request id; one without it leaves Pi working for whoever it worked for before. At startup, what a crash kept out of the authors document is read back from Pi Durable’s records.
  • A tool is replay: "safe" only if running it twice is harmless.
  • Extensions reach the app only through PocketHost, and add to it only through web (extension-web.ts).
  • Server code is erasable TypeScript with .ts imports. Comments are plain sentences.

npm test runs every *.test.ts with Node’s test runner. helpers.ts provides a scripted model (scriptedModel(route): faux-1, faux-2, faux-vision), openApp (the same data folder again is a restart; now moves the clock), newSession, say, until, and fakeTab. The scripted model costs nothing: spend tests write pi.usage themselves. browser.test.ts drives a real Chromium, where one is installed, for the built-in browser, and the *-ui.test.ts files load the whole web app in it. docs-examples.test.ts loads the example extensions in docs/examples/ as drop-ins. extension-web.test.ts covers extension modules’ routes, browser module files, and events, extension-loader.test.ts the loader with a real registry, and extension-ui.test.ts their browser modules in the app, in Chromium. memory.test.ts checks the pending-lesson queue’s access and approval safety. linked-sessions.test.ts checks linked sessions: a repeated start or send acts once, a hidden origin stays hidden, the checks of whom Pi works for come first, and an unavailable model makes nothing. gallery.test.ts checks what the gallery takes from its index: a file name that leaves the extensions folder, a file whose hash differs, an install under a name that was on before (it stays off), a revoked version, and a theme that installs only as pinned and only when its CSS passes the theme check. turns.test.ts runs web/turns.js in Node: how the transcript groups Pi’s answers, and which calls can still run. voice.test.ts runs web/voice.js in Node with a stand-in speech recognizer: where dictated words land as people type. hooks.test.ts covers webhooks and fence.ts. The rest of the web app has no tests: check a change to it in a browser, on a copy (node test/serve.ts: this folder’s code, its own temporary data, a scripted model).

These pages describe Pi Pocket 0.14.0. Your copy has the pages of its own version in its docs/ folder.