TEMPORARY / EXPERIMENTAL, at the owner's request, after deedy/qr-data-transfer (QRFerry).
Two panels: one loops a file as QR frames, the other scans them through the camera and
rebuilds it. Entirely client-side — nothing about a transfer reaches the server, which is
the point of the technique.
NOT RaptorQ, and that is the one real design decision here. QRFerry carries RFC 6330
fountain-coded symbols so a receiver can rebuild from ANY sufficient set of frames. This
uses a plain indexed carousel instead, for two reasons — the second being the deciding one:
1. RFC 6330 is days of work and unpleasant to debug.
2. The sender and receiver are being reimplemented on iOS and Android. A format one person
can re-derive from protocol.ts in an afternoon is worth more here than optical
efficiency. Every frame is independent, self-describing, and parses with a string split.
The cost is honest and written down: without fountain coding you must eventually capture each
specific frame, so a miss waits for the next pass rather than being covered by surplus. Fine
for a few hundred KB on a steady camera; it degrades where RaptorQ would start to pay for
itself.
Details that matter for the phone implementations:
- base64url, no padding — ':' and '/' would collide with the field separator.
- CRC-32 of the whole file in the meta frame, checked after reassembly. The test pins the
reference value for "123456789" (cbf43926) so any stock implementation will agree.
- The meta frame repeats every 12 frames, so a receiver joining late learns the filename and
total without waiting a full cycle.
- Error correction level L: frames are short-lived and repeated forever, so QR capacity is
better spent staying sparse enough to scan than on recovery.
16 tests over the protocol, which is the spec the other implementations should match.
The receiver needs a secure origin for camera access; over the tailnet with HTTPS that holds,
and it says so plainly rather than failing silently on plain http.
Adds qrcode and jsqr. @types/qrcode was already present and orphaned — its runtime package had
been removed with the chat-channel cleanup.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
deletes the last of the projects/apps cluster: the published-app store
(/api/apps + /api/app-serve), the project dev-server and its websocket
proxy (/api/dev-server + /api/dev-server-proxy), the shared html-rewrite
they were the only consumers of, and their frontend — the Preview panel,
the UserApp panel/header, useUserApps and the /settings/apps screen.
also drops getUserProjectsDir and getUserAppsDir, the ProjectType and
ProjectDefinition types, and the 'dev-server' websocket provider from
server.tsx. nothing on disk is touched.
1440 deletions, 31 insertions. tsgo clean.
the owner's work, committed as one unit rather than split: the registration
files (App.tsx, Dock, AppRegistry, hono.ts, the schema and db barrels,
ecosystem.config.cjs) all reference modules under src/servers/{api,sidecar}/wallet
and src/workspaces/officerdev/src/apps/Wallet, so committing the shared plumbing
on its own would leave a commit that does not build.
officer-wallet is a new pm2 peer holding seed material sealed under an owner
passphrase on top of VAULT_STORE_KEY, with an unlock ttl after which the root key
is wiped from memory. five backends: on-chain via esplora, and lnd, clnrest,
lndhub and nwc for lightning. bolt11 encode/decode is implemented in-tree.
no secrets in the diff — the key-shaped literals under sidecar/wallet are the
bolt11 spec vectors and the bip39 "abandon … about" vector. .env.example gains
placeholders only. bun test src/servers/sidecar/wallet: 38 pass, 0 fail.
not reviewed line by line; assembled and verified to build, not audited.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
a /invoices workspace screen replicating the parts of the invoiceshelf web ui
that are actually used: dashboard, invoices, estimates, recurring invoices,
payments, expenses, customers, items and reports.
one document editor serves invoices, estimates and recurring invoices — they
share the line-item table, the discounts, the taxes and the totals, and differ
only in a header strip. the arithmetic is a port of upstream's
use-document-calculations, rounding points included, because the server
re-validates the totals it is sent. money is integer minor units throughout and
is converted to major units at the edges only.
selection and editor state live in the url (`/invoices/:section`, `?selected=`,
`?edit=`), so the nav highlight is derived rather than held, back closes an
editor instead of leaving the screen, and a half-written form survives a reload.
sending a document is behind an explicit confirmation — it emails the customer.
built against the running 2.4.2 instance rather than the 3.0 checkout in
_references; the two differ materially. typechecked, not yet exercised in a
browser.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
officer-transmission is a new pm2 peer that owns the transmission rpc
connection and exposes a curated /_officer/* contract instead of proxying
raw rpc. it absorbs the three quirks callers otherwise have to know about:
the 409 x-transmission-session-id handshake, failures returned as
{"result": "..."} inside http 200, and basic auth where an empty username
must send no header at all.
/transmission is the ui, on the workspace/panel framework: a filter nav and
three sections (torrents, stats, settings). the torrent list is virtualised
with 30 available columns, multi-select, and a right-click menu; the detail
pane covers general, files as a real tree, peers and trackers. filters and
the open torrent live in the url, so a filtered view is a link.
phase 1 goal was parity with _references/transmission-web. follow-up work is
recorded in TODO.md.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
officer-headscale owns the whole Headscale contract: the registered servers and
their admin api keys, the >=0.29 version floor, and every multi-call composition
the ui needs. the platform side is auth+forward only and holds no headscale
credentials, so the existing /api/vpn/enroll route and its HEADSCALE_* env vars
are untouched and unrelated.
officer manages many servers rather than one. the owner registers each with a url
and a key generated on that server and switches between them; exactly one is
active, enforced by a partial unique index rather than by convention. keys are
encrypted at rest and never leave the sidecar — the list projection cannot return
one. registration validates before it saves: an unauthenticated GET /version to
prove something headscale-shaped is there and meets the floor, then an
authenticated call to prove the key works. an edit that moves either half
re-validates.
there is deliberately no transparent /api/v1/* passthrough. headscale serialises
every uint64 as a json string and its rest shape moved repeatedly below 0.29;
proxying raw would push all of that into the browser, which is the mistake the
soulseek panels made with 37 raw upstream calls.
the /headscale workspace is nav + view over the panel system. only the servers
section is implemented — nodes, users and pre-auth keys say so plainly rather
than rendering an empty table that reads as a failed fetch.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Being retired, so it is deleted rather than fixed — it had both defects dashboards just
had (edit dropping ?selected=, an abandoned edit following you onto the next item) and
repairing them was work for something on its way out.
Gone: the two screens and the panel apps, the three routes, the dock item and its entry
in the default dock paths (client and the three server-side copies), the page-title rule,
the app-registry entries, the barrel exports, the `projects` table with its queries and
row types, and the proj-meta/proj-layout/proj-terminals/proj-host-terminals branches in
the dashboards endpoint. The chat context and terminal state-key special cases for
`proj-layout-` went with them.
Deliberately kept: `getUserProjectsDir` in data-path.ts — the apps and dev-server routers
resolve user apps under the same on-disk Projects/ directory and are unrelated to this
feature. Nothing on disk is touched.
Needs `bun db:push` to drop the table; the schema change is the only thing standing
between the code and the database. One row was in it.
tsgo clean, 56/56 tests, no references left in src. Not yet exercised at runtime — the
restart is what will prove it.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Two panels (search + transfers) via WorkspaceView, coordinating over the
soulseek:refresh channel. Adds the page-title rule and documents the
route conventions in CLAUDE.md.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Backend GET /api/system-monitor/stats: one snapshot — CPU overall + per-core
(two /proc/stat samples), memory + swap (/proc/meminfo), disks (df), load,
uptime, top-20 processes (ps). Owner-only via the account gate.
- Frontend /system-monitor screen: polls every 2s; CPU/Memory/Disks cards with
bars + per-core mini-bars, top-processes table. Nav dock "Monitor" item.
- Register /music and /system-monitor in usePageTitle RULES so the browser tab
and editable header title update on those routes (/music was missing too).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Deletes all session persistence that isn't Claude's native transcript store, per
the "only harness-native session management survives" rule.
Backend: delete api/pi/storage.ts (meta.json+messages.json file store), the
api/saved-sessions router (+ unmount), the /pi/sessions REST endpoints, and the
storage.save/loadSession calls in the chat WS handler (in-memory session-manager
stays for live turns; no disk persistence — Claude's transcript is the record).
Also drops the Postgres saved_sessions layer: schema/chat.ts, queries/saved-sessions.ts,
its types and re-exports.
Frontend: delete state/useSavedSessions, ChatList, and the ChatHistory Widget
(all pure saved-session UI); slim ChatHeader to a label; strip the auto-load-latest
+ Save wiring from ChatPanelWrapper and ChatDetailPanel; drop the old resume path
from useChat and SessionListPage; remove the /chat/saved/:id route and the
useInitialData prefetch.
Behavior removed (intended): the Save-session button, email/project panels
auto-resuming the last chat, and /chat/saved/:id. /chat itself is unchanged —
already fully on Claude transcripts. The orphaned saved_sessions Postgres table
is dropped on the next `bun db:push`.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Deletes the Automation and NewAutomation screens, their /automation and
/new-automation routes, the Dashboard barrel exports, the dock item (+ default
dock path), and the page-title rule. TaskRunnerModal is kept — the file browser
still uses it to run tasks on files.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Each dashboard route now sets its own document.title (route→title map in
usePageTitleSync, mounted in DashboardLayout). The title also renders centered in
the top header; clicking it edits inline and updates the browser tab live —
per-tab only, reset on navigation/refresh (not persisted).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Add saved_sessions table and CRUD endpoints (save, list, resume, update, delete)
- Save is instant (no LLM summarization), stores exact conversation with tool calls
- Resume loads full message history into chat UI, sends transcript to agent on first message
- Auto-save updates DB after every agent response once a session is saved
- Delete old filesystem-based session/group management (sessions router, useChatSessions, useChatGroups)
- Clean up ChatHeader, SessionList, ChatDetailPanel for saved sessions flow
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Delete legacy hooks: useClaude.ts, useOpenCode.ts, usePiMono.ts, App.backup.tsx
- Update all components to use usePi instead of legacy hooks
- Replace useVisiblePiMonoModels/useClaudeModels/useOpenCodeModels with useVisiblePiModels
- Migrate from LegacyChatMessage to ChatMessage type throughout
- Update SessionBar to remove provider and archive props
- Simplify ChatDetailPanel to Pi-only (remove Claude/OpenCode components)
- Fix useChatSessions calls (remove provider parameter)
- Update user-settings types: provider now only 'pi' instead of legacy values
- Update PI_HARNESS_REBUILD.md to mark phases complete