pi-central 0.4.1 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -10,248 +10,184 @@
10
10
  <img alt="license" src="https://img.shields.io/npm/l/pi-central" />
11
11
  </p>
12
12
 
13
- **Pi Central** (/paɪ ˈsɛntrəl/) is a local dashboard for running, watching, and switching between
14
- multiple [Pi](https://pi.dev) coding-agent sessions that live in **different working directories**,
15
- while keeping every session inside its own **Agent Safehouse** sandbox.
13
+ **A local dashboard for running several [Pi](https://pi.dev) coding-agent sessions at once — each in its
14
+ own working directory, each inside its own sandbox.** /paɪ ˈsɛntrəl/
16
15
 
17
- The central station is the design brief: independent lines arrive, are dispatched, and are kept apart
18
- from one another. Pi Central does the same for agent sessions.
16
+ `pi` gives you one process, one session, one directory. Pi Central is the fleet you were missing:
19
17
 
20
- **Status: works end to end, verified, and published.** The version is deliberately not written down
21
- here: `pi-central --version` reports the version of the package it was actually shipped in, and a
22
- number restated in prose is a number that drifts. See [docs/RELEASING.md](docs/RELEASING.md).
18
+ - **See them all.** One rail with every session's state, cost and context burn — instead of three
19
+ terminals and three scrollbacks.
20
+ - **Answer them from one place.** The approval dock handles `confirm`, `select`, `input` and `editor`
21
+ for whichever session is blocked.
22
+ - **Keep them apart.** Each session gets its own Safehouse sandbox for its own directory. They cannot
23
+ read each other's files.
23
24
 
24
- ## Install it as an app
25
-
26
- Pi Central is a web app that installs to your dock. Start it once (see [Quick start](#quick-start)),
27
- open <http://127.0.0.1:8787>, and then install it from the browser's own menu:
28
-
29
- | Browser | How |
30
- |---|---|
31
- | **Safari** | *File → Add to Dock* |
32
- | **Chrome / Edge** | the install icon at the right end of the address bar, or *⋮ → Install page as app* |
33
- | **Firefox** | **not supported** — Mozilla has no PWA install on desktop. The service worker still works; use another browser for the dock icon. |
34
-
35
- You get the π mark in the dock and a window with no tab bar or address field.
36
-
37
- **It is not an offline app, deliberately.** Every screen is fed by the socket, so if the orchestrator is
38
- not running the installed app says `disconnected` and nothing else. A window that claimed to work
39
- offline would open onto a blank dashboard.
40
-
41
- ## The problem
42
-
43
- Pi has no fleet concept. One `pi` process owns one session and one working directory:
44
-
45
- - Sessions are JSONL files grouped by working directory under `~/.pi/agent/sessions/`.
46
- - RPC mode (`pi --mode rpc`) is a long-lived child process speaking JSONL over stdio.
47
- - There is **no daemon, no attach protocol, no socket registry, and no port**. Each RPC process
48
- privately owns its own stdin/stdout.
25
+ **Who this is for.** People who already run `pi` and want more than one session at a time.
26
+ Contributors: jump to [Working on this project](#working-on-this-project).
49
27
 
50
- So working on three repositories means three terminals, three scrollbacks, and no single place to
51
- see what is running, what is waiting for approval, or how much context each session has burned.
28
+ **Status: works end to end, verified, and published.** The version is deliberately not written here —
29
+ `pi-central --version` reports the version of the package it shipped in. See
30
+ [docs/RELEASING.md](docs/RELEASING.md).
52
31
 
53
- ## The non-obvious constraint
32
+ ## Requirements
54
33
 
55
- macOS Seatbelt sandboxing does **not nest**. A process already inside `sandbox-exec` cannot apply a
56
- second profile — `sandbox_init` returns `EPERM`. Safehouse's own profile documents this as not
57
- fixable with additional allow rules.
34
+ Check these first — Pi Central will not run without them, and it is better to know now.
58
35
 
59
- This single fact rules out the obvious design (a Pi extension that hosts other sessions in-process)
60
- and dictates the architecture: **the orchestrator must live outside any sandbox, and each session
61
- must be its own `safehouse` invocation.** See [docs/CONSTRAINTS.md](docs/CONSTRAINTS.md).
62
-
63
- It also means Pi Central must run from a **plain terminal** — not from an editor task, a sandboxed
64
- shell, or an agent harness. It checks this before binding a port and refuses to start with an
65
- explanation rather than failing confusingly later.
66
-
67
- ## Design in one picture
68
-
69
- ![The Pi Central dashboard. On the left, a session rail lists two sessions with their state and
70
- cost. In the middle, a transcript shows the reader's own prompt in a tinted block labelled YOU,
71
- followed by the agent's reasoning, two tool runs, and a live "responding" indicator. Below the
72
- transcript, a tool trace lists the last three commands with their durations. The right-hand panel is
73
- collapsed.](docs/images/dashboard.png)
74
-
75
- *A session mid-run. The rail carries the fleet, the transcript carries the conversation, and the tool
76
- trace carries what the agent actually ran. The right-hand panel — session facts, or a file browser —
77
- is **collapsed by default**; `Show panel` in the top bar opens it.*
78
-
79
- The layers behind that window:
80
-
81
- ```
82
- ┌──────────────────────────────┐
83
- │ Pi Central UI (localhost) │ session rail · transcript · approvals · tool trace
84
- │ React + Vite, TypeScript │ Markdown rendered inert (ADR-0006)
85
- └──────────────┬───────────────┘
86
- │ WebSocket over loopback (typed envelopes)
87
- ┌──────────────▼───────────────┐
88
- │ Orchestrator (unsandboxed) │ session registry · process supervision
89
- │ TypeScript on Node │ · one sandboxed pi process per session
90
- └──────────────┬───────────────┘
91
- │ spawn: safehouse --workdir <cwd> -- pi --mode rpc
92
- ┌─────────┼─────────┐
93
- ▼ ▼ ▼
94
- ┌──────┐ ┌──────┐ ┌──────┐
95
- │ pi │ │ pi │ │ pi │ one sandbox per working directory
96
- │ /a │ │ /b │ │ /c │ isolation preserved per session
97
- └──────┘ └──────┘ └──────┘
98
- ```
99
-
100
- Each session gets a correctly composed Safehouse profile for its own workdir. The orchestrator
101
- never runs untrusted content, so being outside the sandbox is safe by construction.
36
+ | | Why | Check |
37
+ |---|---|---|
38
+ | **macOS** | Safehouse (the sandbox) has no Linux backend yet. | `uname` |
39
+ | **[Pi](https://pi.dev)** | Pi Central supervises `pi --mode rpc`; it is not a fork of it. | `pi --version` |
40
+ | **[Safehouse](https://github.com/earendil-works/safehouse)** | Composes the per-session sandbox profile. | `safehouse --help` |
41
+ | **Node ≥ 22** | The orchestrator runs TypeScript directly. | `node --version` |
102
42
 
103
43
  ## Quick start
104
44
 
105
- **One process.** The orchestrator serves the built UI and the WebSocket from the same origin, so
106
- there is no dev server to start and no port to coordinate. It must run from a plain terminal (see
107
- the constraint above), and it prints the URL it is serving on — <http://127.0.0.1:8787> unless you
108
- passed `--port`.
109
-
110
- ### From npm — what a user does
111
-
112
45
  ```bash
113
- npm install --global pi-central
46
+ npm install --global pi-central # inert: this package runs no install scripts
47
+ npm audit signatures # verify BEFORE the first run
114
48
  pi-central
115
49
  ```
116
50
 
117
- Or without installing it at all:
51
+ It prints the URL it is serving — <http://127.0.0.1:8787> unless you passed `--port`. One process serves
52
+ both the UI and the socket, so there is no dev server to start.
118
53
 
119
- ```bash
120
- npx pi-central
121
- ```
54
+ > **Run it from a plain terminal.** Not from an editor task, a sandboxed shell, or an agent harness.
55
+ > macOS Seatbelt does not nest: `safehouse` applies its policy with `sandbox-exec`, which cannot run
56
+ > inside an existing sandbox. Pi Central checks this before binding a port and refuses with an
57
+ > explanation rather than failing confusingly later. ([C1](docs/CONSTRAINTS.md))
122
58
 
123
59
  Once it is running, [install it as an app](#install-it-as-an-app) and you will not need the terminal
124
60
  again until the next reboot.
125
61
 
126
- The package is **one bundled ESM file plus the built UI**, with a single runtime dependency (`ws`),
127
- and `pi-central --version` reports the version of the package it was actually shipped in.
62
+ ### Verify what you installed
128
63
 
129
- ### From a checkout — what a contributor does
64
+ `npm audit signatures` checks the **provenance attestation** every release carries — a signed statement,
65
+ minted by the release workflow's OIDC identity rather than a stored token, that this tarball came from
66
+ this commit via this workflow.
130
67
 
131
- ```bash
132
- npm install
133
- npm run ui:build # once, and after any UI change
134
- npm run server # the orchestrator, which also serves the UI
135
- ```
68
+ What it does **not** do: it is a check you have to run (npm does not refuse an unattested tarball), and
69
+ it answers *"did the publisher produce this?"* — not *"is the publisher trustworthy?"*. Pi Central runs
70
+ **outside** the sandbox with your privileges by design, because it is the component that spawns sandboxed
71
+ sessions. The attestation tells a tampered tarball from a genuine one; it cannot make a genuine tarball
72
+ safe.
136
73
 
137
- To build the publishable artifact from a checkout:
74
+ `npx pi-central` has no window to check in: it fetches and executes in one step. If you use it, pin an
75
+ exact version (`npx pi-central@<version>`, where `<version>` is what `pi-central --version` reports).
76
+ The number is not written here on purpose — a README that restates a version goes stale, and
77
+ `scripts/check-version.mjs` refuses to let one.
138
78
 
139
- ```bash
140
- npm run build:package # bundles the orchestrator, copies the built UI
141
- npm pack --dry-run # show exactly what would ship
142
- npm run serve:package # run the packaged binary from ./bin
143
- ```
79
+ ## Why it exists
144
80
 
145
- It ships as JavaScript — TypeScript cannot be loaded from `node_modules` — as one bundled ESM file
146
- plus the built UI. See [ADR-0011](docs/decisions/0011-distribution-and-update.md).
81
+ `pi` has no fleet concept. One process owns one session and one directory: sessions are JSONL files under
82
+ `~/.pi/agent/sessions/`, RPC mode is a long-lived child speaking JSONL over stdio, and there is **no
83
+ daemon, no attach protocol, no socket registry, no port**.
147
84
 
148
- Serving the UI from the orchestrator is not only convenience. A Vite dev server watches
149
- `packages/ui/src`, so an agent editing a component reloads the interface you are using out from
150
- under you, mid-edit, into a syntax-error overlay. A built UI removes the watcher. It also makes
151
- the `connect-src 'self'` in the CSP truthful by construction: the socket really is same-origin with
152
- the document. See [docs/DOGFOODING.md](docs/DOGFOODING.md).
85
+ So three repositories means three terminals, three scrollbacks, and no single place to see what is
86
+ running, what is waiting for approval, or how much context each session has burned.
153
87
 
154
- ### Working on the UI
88
+ ## How it works
155
89
 
156
- For hot reload while editing components, run the dev server instead — it proxies `/ws` to the
157
- orchestrator and still needs no configuration:
90
+ ![Pi Central's architecture: a browser UI talks over a loopback WebSocket to an orchestrator, which
91
+ runs outside any sandbox and spawns one pi process per session, each inside its own Safehouse
92
+ sandbox drawn as a separate dashed frame.](assets/architecture.svg)
158
93
 
159
- ```bash
160
- npm run server -- --no-ui # terminal 1 — socket only
161
- npm run ui:dev # terminal 2 — Vite, on http://localhost:5173
162
- ```
94
+ The two boxes on top are ordinary and unremarkable. **The three frames below are the design**: the
95
+ orchestrator sits *outside* every sandbox, and each `pi` sits *inside* its own, with no frame shared
96
+ between them.
163
97
 
164
- | Key | Action |
98
+ That shape is forced by one fact — **Seatbelt does not nest** ([C1](docs/CONSTRAINTS.md)). A process
99
+ already inside `sandbox-exec` cannot apply a second profile, so an architecture that hosted sessions
100
+ in-process would have no sandbox at all. The orchestrator must live outside and spawn one `safehouse`
101
+ invocation per session. Details in [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md).
102
+
103
+ ## Install it as an app
104
+
105
+ Pi Central is a web app that installs to your dock. Start it once (see [Quick start](#quick-start)),
106
+ open <http://127.0.0.1:8787>, then install it from the browser's own menu:
107
+
108
+ | Browser | How |
165
109
  |---|---|
166
- | `⌘N` | New session in an app-owned scratch workspace — no directory to choose |
167
- | `⌘⇧O` | Open in a directory (the secondary path) |
168
- | `Enter` | Send, or queue while a run is in progress |
169
- | `Esc` | Answer an open dialog → close a popover → stop the run. Never clears your draft |
110
+ | **Safari** | *File → Add to Dock* |
111
+ | **Chrome / Edge** | the install icon at the right end of the address bar, or *⋮ → Install page as app* |
112
+ | **Firefox** | **not supported** — Mozilla has no PWA install on desktop. The service worker still works; use another browser for the dock icon. |
113
+
114
+ You get the π mark in the dock and a window with no tab bar or address field.
170
115
 
171
- **Settings** (top of the window) shows which build is running, which protocol it speaks, and where
172
- Pi Central keeps sessions, workspaces and the agent root — facts that were previously only in the
173
- terminal's startup output. It has no preference controls yet, deliberately: update checking
174
- ([#55](https://github.com/sven1103-agent/pi-central/issues/55)) will add the first one, and it will be
175
- opt-in.
116
+ **It is not an offline app, deliberately.** Every screen is fed by the socket, so if the orchestrator is
117
+ not running the installed app says `disconnected` and nothing else. A window that claimed to work
118
+ offline would open onto a blank dashboard.
176
119
 
177
120
  ## What works, and what does not
178
121
 
179
122
  Stated plainly, because a dashboard that overstates itself is worse than one that does less.
180
123
 
181
- **Works:** multiple sandboxed sessions in different directories with verified isolation; live
182
- transcripts reconstructed from Pi's delta-only stream; the approval dock (`confirm` / `select` /
183
- `input` / `editor`) answerable for any session; a bounded tool trace with full traversal; history
184
- searchable by content, with a clear refusal when a session's directory is gone; agent-scoped
185
- credentials with the host's own credentials denied, and commits signed as the agent when the store is
186
- configured to sign.
124
+ **Works:** multiple sandboxed sessions in different directories with verified isolation; live transcripts
125
+ reconstructed from Pi's delta-only stream; the approval dock answerable for any session; a bounded tool
126
+ trace with full traversal; a read-only file tree and image viewer confined to the session's directory;
127
+ history searchable by content, with a clear refusal when a session's directory is gone; a session roster
128
+ that survives a restart; agent-scoped credentials with the host's own credentials denied, and commits
129
+ signed as the agent when the store is configured to sign.
187
130
 
188
- **Not yet:** no file navigation. It is an issue rather than a wish — see below.
131
+ **Not yet:** no file editing from the browser, no update checking, no export. Each is a tracked issue
132
+ rather than a wish.
189
133
 
190
134
  ## Working on this project
191
135
 
192
- Work is organised as **increments** (GitHub milestones) containing **slices** (issues). A slice is
193
- sized to land in one pull request and to be verifiable on its own.
194
-
195
- - [docs/INCREMENTS.md](docs/INCREMENTS.md) — what each increment delivers and why it is ordered
196
- that way
197
- - Issues — the slices, with acceptance criteria
198
- - [docs/ROADMAP.md](docs/ROADMAP.md) — the long view, including what is deliberately out of scope
136
+ Work is organised as **increments** (GitHub milestones) containing **slices** (issues). A slice is sized
137
+ to land in one pull request and to be verifiable on its own. See
138
+ [docs/INCREMENTS.md](docs/INCREMENTS.md) and [docs/ROADMAP.md](docs/ROADMAP.md).
199
139
 
200
140
  ```bash
141
+ npm install && npm run ui:build && npm run server # from a checkout
201
142
  npm test # unit + component tests, all packages
202
143
  npm run typecheck # two configs: Node libs and DOM libs cannot share one
203
144
  npm run check:docs # every reference in every Markdown file resolves
204
145
  npm run check:version # one version, declared once
205
- npm run ui:build # production build of the UI
206
146
  ```
207
147
 
208
- The `check:docs` step exists because this repository is docs-driven, and a reference to a deleted
209
- file still *looks* authoritative. It has caught real rot more than once. `check:version` exists for
210
- the same reason one level up: the version was previously claimed in three places — `package.json`,
211
- `README.md`, and a `CHANGELOG.md` heading — and three claims are three chances to disagree.
148
+ Serving the built UI from the orchestrator is not only convenience: a Vite dev server watches
149
+ `packages/ui/src`, so an agent editing a component would reload the interface you are using out from
150
+ under you. For hot reload, run the dev server deliberately — see
151
+ [docs/DOGFOODING.md](docs/DOGFOODING.md).
152
+
153
+ ### Keyboard
154
+
155
+ | Key | Action |
156
+ |---|---|
157
+ | `⌘N` | New session in an app-owned scratch workspace — no directory to choose |
158
+ | `⌘⇧O` | Open in a directory (the secondary path) |
159
+ | `Enter` | Send, or queue while a run is in progress |
160
+ | `Esc` | Answer an open dialog → close a popover → stop the run. Never clears your draft |
212
161
 
213
- Releases are described in [docs/RELEASING.md](docs/RELEASING.md).
162
+ **Settings** shows which build is running, which protocol it speaks, where Pi Central keeps sessions,
163
+ workspaces and the agent root, and how to verify the install.
214
164
 
215
165
  ## Documentation
216
166
 
217
167
  | Document | What it covers |
218
168
  |---|---|
219
- | [docs/USER-STORIES.md](docs/USER-STORIES.md) | What users need, and the constraints those needs create |
220
169
  | [docs/CONSTRAINTS.md](docs/CONSTRAINTS.md) | The Seatbelt nesting limit and its consequences (C1–C15c) |
221
170
  | [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) | Components, trust boundaries, lifecycle |
222
- | [docs/STACK.md](docs/STACK.md) | TypeScript/Node orchestrator, React UI, rendering pipeline |
223
- | [docs/PROTOCOL.md](docs/PROTOCOL.md) | The Pi RPC surface Pi Central depends on |
224
- | [docs/SANDBOX.md](docs/SANDBOX.md) | How safehouse is invoked per session, and what the composed policy denies |
171
+ | [docs/SANDBOX.md](docs/SANDBOX.md) | How Safehouse is invoked per session, and what the policy denies |
225
172
  | [docs/AGENT-SETUP.md](docs/AGENT-SETUP.md) | Creating the agent identity a session runs as: SSH key, gitconfig, signing, `gh` |
226
- | [docs/INCREMENTS.md](docs/INCREMENTS.md) | Increments, slices, and how work is sequenced |
227
- | [docs/DOGFOODING.md](docs/DOGFOODING.md) | Using Pi Central to develop Pi Central, and what breaks if you run it from the checkout you edit |
228
- | [docs/RELEASING.md](docs/RELEASING.md) | Cutting a release: the version source, the tag, provenance, and how to roll back |
229
- | [docs/ROADMAP.md](docs/ROADMAP.md) | Phases, verification status, and out-of-scope items |
230
- | [docs/OPEN-QUESTIONS.md](docs/OPEN-QUESTIONS.md) | Unresolved decisions |
173
+ | [docs/PROTOCOL.md](docs/PROTOCOL.md) | The Pi RPC surface Pi Central depends on |
174
+ | [docs/STACK.md](docs/STACK.md) | TypeScript/Node orchestrator, React UI, rendering pipeline |
175
+ | [docs/USER-STORIES.md](docs/USER-STORIES.md) | What users need, and the constraints those needs create |
176
+ | [docs/PRINCIPLES.md](docs/PRINCIPLES.md) | The nine rules, in full |
177
+ | [docs/DOGFOODING.md](docs/DOGFOODING.md) | Using Pi Central to develop Pi Central, and what breaks if you do |
178
+ | [docs/RELEASING.md](docs/RELEASING.md) | Cutting a release: the version source, the tag, provenance, rollback |
179
+ | [docs/INCREMENTS.md](docs/INCREMENTS.md) · [docs/ROADMAP.md](docs/ROADMAP.md) | How work is sequenced, and the long view |
231
180
  | [docs/decisions/](docs/decisions/) | Architecture decision records |
232
181
  | [packages/ui/DESIGN.md](packages/ui/DESIGN.md) | The UI design system, as implemented |
233
182
 
234
183
  ## Principles
235
184
 
185
+ Three that explain most decisions. The full nine are in [docs/PRINCIPLES.md](docs/PRINCIPLES.md).
186
+
236
187
  1. **Isolation is the feature.** Never trade per-session sandboxing for convenience.
237
- 2. **The orchestrator is the trust boundary.** It stays local, holds no untrusted content, and
238
- never executes model output.
239
- 3. **Pi is the source of truth.** Do not re-implement session semantics; consume RPC and the
240
- persisted session tree.
241
- 4. **Additive, not a replacement.** Pi Central supervises `pi`; it does not fork it.
242
- 5. **Local first.** No telemetry, no network egress beyond providers Pi already calls.
243
- 6. **Untrusted content is inert.** Transcripts and file contents are strings to display, never
244
- markup to execute — see [ADR-0006](docs/decisions/0006-untrusted-markdown-rendering.md).
245
- 7. **Confine the agents, not the user.** Safehouse constrains model-generated actions in a workdir.
246
- The orchestrator is a user-level app acting as the user, on the user's files — see
247
- [ADR-0007](docs/decisions/0007-filesystem-access-model.md).
248
- 8. **Never state something false.** A displayed value that is wrong is a defect, not a cosmetic
249
- issue: this project has shipped misleading counts, a mislabelled session id, and a permission
250
- error reported as a missing directory, and treats each as a bug.
251
- 9. **A peer, not a configurator.** Pi Central does not write into a user's Pi environment — no
252
- skills, no extensions, no settings. It reads what exists and writes only its own state. A
253
- defense does not require a new artifact in the environment it defends, and any setup a session
254
- needs is a documented action the user takes (see [docs/AGENT-SETUP.md](docs/AGENT-SETUP.md)).
188
+ 2. **Never state something false.** A displayed value that is wrong is a defect, not a cosmetic issue.
189
+ 3. **A peer, not a configurator.** Pi Central writes nothing into your Pi environment — no skills, no
190
+ extensions, no settings.
255
191
 
256
192
  ## License
257
193