mirror of
https://github.com/paperclipai/paperclip-docs.git
synced 2026-11-07 06:16:07 -10:00
Ships the v2026.817.0 docs to live: the doc content that was authored and verified earlier, plus a full screenshot overhaul. The content half (`cdf81e2` and the nightly commits behind it) has already been reviewed. **The screenshots are the part that needs eyes** — `f24d734`, 342 PNGs. ## Screenshots Everything was recaptured against the release commit `213dabab4f8e1f3bb1803a2924c0fea1289fcd4c` (`upstream/candidate/release-2026.817.0`). The previous shots were 375 parent-commits stale (v2026.720.0), with 228 of 310 entries flagged pending. All 342 registry entries now carry that SHA. > ⚠️ Worth knowing: the release commit is **not** an ancestor of the parent's > `master`, and local `master` was four days *older* than it. Capturing against > `master` would have both missed release UI and leaked 93 post-tag commits' worth > of UI into the release docs. ### New coverage (34 entries) Three guides shipped with **no images at all** despite being 115–136 lines. They now have them: | Guide | Shots | |---|---| | `guides/day-to-day/decisions.md` | queue, an agent-proposed decision with its options, triage strip, filter panel, named queue, Decided curtain, empty state | | `experimental/status-cards.md` | board, New card dialog, and all four drawer tabs | | `experimental/task-chat.md` | thread, composer mode picker, side pane | | `reference/api/secrets.md` | the board-side Proposals tab | Chat-Style Tasks is captured in a **separate pass**: `enableTaskChatRedesign` is instance-wide, so leaving it on would have turned every classic issue/task/work-mode shot into the redesigned chat. ## Two defects that were already live Both were shipping in the docs before this PR: 1. **`issues/detail-chat.png` and the `tasks/*` shots were mostly plugin debug output.** The Kitchen Sink example plugin mounts a panel into the issue page that dumps the raw issue JSON, and the seed installed it. Those guides were illustrating a debug panel instead of the task page. The seed no longer installs it. 2. **The seeded task thread was a monologue** — four board-user messages in a row, because the board actor cannot post agent comments. It is now a real two-sided exchange. ## Targets repointed because the UI moved | Target | Why | |---|---| | `activity/*` | `Activity.tsx` deleted; `/activity` renders `pages/audit/CompanyActivity.tsx` | | `experimental/cloud-upstream` | `CloudUpstream.tsx` deleted; the route now redirects to `/company/export` | | `settings/*`, `plugins/*`, `adapters/*` | `/instance/settings/*` are legacy redirects now | | `dashboard/stale-tasks-panel` | panel removed from `Dashboard.tsx` — target dropped | Plus eight targets with **silent selector drift**. A failed interaction step falls back to "whatever state was reached", so these had been quietly producing wrong images — a plain inbox where the doc promised a mode picker, a whole dashboard where it promised one panel. Full table in `docs/user-guides/screenshots/SCREENSHOTS_PLAN_v2026.817.0.md` §C2. ## Pipeline Decisions, status-card summaries and secret proposals are all **agent-authored**, and the board actor the seed runs as is refused by every one of them (`"Agent run context required"`, `"Secret proposals require a verified run-bound agent token"`). Rather than insert rows behind the API, `seed-new-surfaces.mjs` borrows the two doors a real run already has — a board-minted agent API key, and a locally signed agent JWT — so every write goes through the production code path. Also: - `capture.mjs` records a real `captured_against` on a detached checkout instead of the literal string `"HEAD"` (which is what every pre-2026.817 entry recorded), and gains a `scrollTo` step for content below the fold. - `run.mjs` gains `--serve` for iterating on the seed, the task-chat phase, and a keeper that holds the demo board's issue statuses steady — the demo `process` agents finish runs without declaring a disposition, so the stalled-work sweep re-blocks issues every few minutes over a capture that runs far longer. ## Reviewing Light and dark both captured at 1440×900 @2x. The new surfaces are the ones to scrutinise; the rest is a like-for-like refresh. ### One leftover Dropping `dashboard/stale-tasks-panel` leaves `{light,dark}/dashboard/stale-tasks-panel.png` tracked but unused — they need deleting by hand. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 4.8 (1M context) <[email protected]> Co-authored-by: DevRel Gemini <[email protected]> Co-authored-by: Paperclip <[email protected]> Co-authored-by: Dotta <[email protected]> Co-authored-by: ClaudeCoder <[email protected]>
Screenshot pipeline
Automated capture of light + dark UI screenshots at 1440×900 @2x for use in the docs. Output PNGs land under docs/user-guides/screenshots/{light,dark}/ and are reviewed in a PR — they are never auto-pushed.
Prerequisites
- Parent repo present. The pipeline spins up a real Paperclip instance from source. Set
PAPERCLIP_REPOto its absolute path, or ensure it lives at the default location~/Documents/PaperclipAI/paperclip(the default resolved byconfig.mjs). See paperclip-localdev-runbook.md conceptually — the runner follows the samelocal_trusted/private/loopbackisolation pattern. - Playwright Chromium installed. Run once after
npm install:npx playwright install chromium pnpmavailable. The runner starts the parent's onboarding entrypoint viapnpm paperclipai onboard --yes --run.
One-command flow
npm run screenshots:refresh
What happens under the hood:
- Isolated instance.
run.mjsspawnspnpm paperclipai onboard --yes --runinside the parent repo with a throw-awayHOME/PAPERCLIP_HOMEunderos.tmpdir(),PORT=3197,PAPERCLIP_BIND=loopback,PAPERCLIP_DEPLOYMENT_MODE=local_trusted, andPAPERCLIP_DEPLOYMENT_EXPOSURE=private. The child process receives only a small allowlist of runtime environment variables, so real database URLs, provider keys, and GitHub tokens are not forwarded.- Parent
.envneutralized. The server also loads a.envfrom its working directory (the parent repo) via dotenv withoverride: false, which would otherwise re-inject the developer's real settings and defeat the allowlist.instanceEnv()therefore explicitly pins the keys that matter:DATABASE_URL=""(andDATABASE_MIGRATION_URL="") so the instance uses its own embedded Postgres instead of the parent's external database, andSERVE_UI="true"so the UI is served even if the parent's.envsetSERVE_UI=false. Because dotenv runs withoverride: false, these explicit values win over the parent.env. - Free embedded-Postgres port. Before that,
run.mjsruns a short config-generation pass (onboard --yespointed at an unreachable externalDATABASE_URL, so it writes a config without initializing the embedded cluster) and rewritesdatabase.embeddedPostgresPortto a guaranteed-free port discovered by scanning upward from 54329. This matters because onboard hard-codes embedded Postgres to 54329 with no env/flag override, and that's the same default a developer's real local Paperclip uses. Pinning a free port means a screenshot run started while your real instance is up can never collide with — or, worse, connect into and seed — your real database. (The generation pass must stay in external-DB mode: if it ever raninitdbon the scratch data dir, a half-finished cluster would make the real run skip init and fail withrole "paperclip" does not exist.) The direct-DB workspace seed (seed-execution-workspace.mjs) reads the live port back from the instance'spostmaster.pid/config.jsonand refuses to guess 54329.
- Parent
- Health check. Polls
http://127.0.0.1:3197/api/healthuntil 200 (up to 120 s). - Seed.
seed.mjscreates a minimal demo company ("Acme Robotics") plus a manager agent, a regular agent, a project, a goal, a routine, an issue, and a workspace. The company'sissuePrefixis auto-derived server-side (first three uppercase letters of the name →ACM) and cannot be set via REST, so the real prefix is captured and written to.seed-ids.jsonalongside the entity IDs (gitignored).routes.mjsreadscompanyPrefixfrom there, so routes always resolve to whatever the server assigned. Idempotent — re-running looks up the existing company first. - Sync registry.
sync-registry.mjsmerges route anddepends_onmetadata fromCAPTURE_TARGETSintoregistry.jsonwithout overwriting other fields. - Capture.
capture.mjsopens Chromium via@playwright/test, navigates each route in both light and dark themes (1440×900, deviceScaleFactor 2), and saves PNGs todocs/user-guides/screenshots/{light,dark}/<name>.png. The board theme is seeded via bothcolorSchemeemulation and alocalStorageinit script so the UI picks it up consistently. - Stamp. After capture,
registry.jsonentries are updated withcaptured_sha(parent git HEAD) andcaptured_against(branch/tag name). - Teardown. The server child process is killed and the scratch home is removed (
--keepskips the cleanup for debugging).
Overhaul mode
After a large UI/UX redesign — when every screen has changed — recapture everything in one pass:
npm run screenshots:refresh:all
This passes --all to capture.mjs, which ignores staleness and re-shoots every entry in CAPTURE_TARGETS.
Individual scripts
| Script | Command | What it does |
|---|---|---|
seed.mjs |
npm run screenshots:seed |
Seeds demo data against a running instance at BASE_URL. Writes .seed-ids.json. |
capture.mjs |
npm run screenshots:capture |
Captures screenshots against a running instance. Flags: --all, --only <substr>, --theme <light|dark|both>, --stale <file,...>, --base-url <url>, --keep. |
sync-registry.mjs |
npm run screenshots:sync-registry |
Syncs route + depends_on from routes.mjs CAPTURE_TARGETS into registry.json. Safe to run standalone. |
run.mjs |
npm run screenshots:refresh |
Full orchestrator: starts isolated instance → seeds → syncs registry → captures → tears down. Forwards --all, --only, --theme to capture.mjs. |
Route map
The full list of screenshots to capture, their routes, and their depends_on mappings is maintained in docs/user-guides/screenshots/SCREENSHOTS_TODO.md. routes.mjs is the machine-readable version of that same list — keep them in sync when adding new pages.
Rules
- Never run against live data. The pipeline always talks to the seeded demo instance on loopback port 3197.
PAPERCLIP_BIND=loopbackensures no external traffic. - Safe to run alongside your real local Paperclip. The screenshot instance pins its embedded Postgres to a free port (see "Isolated instance" above), so you do not need to stop a real instance first. It will not touch the real database on 54329.
- Output goes to a PR, never auto-pushed. After
screenshots:refresh, open a PR with the changed PNGs for human review. The pipeline does not push. - Always capture both themes. The renderer swaps variants at runtime — providing only one breaks dark- or light-mode users.