Skip to content
This repository was archived by the owner on Jul 6, 2026. It is now read-only.

Repository files navigation

berth-console

Always-on localhost observability + task control for the plan-factory (factory-run.sh --drive). Full product + technical spec lives in docs/SPEC.md.

What it is

A Linear-quality, keyboard-driven local web app that watches a configured list of repo roots for factory activity (.factory/results, .factory/state, plans/, git refs) and gives full observability (workers, waves, costs, gate/closer results) plus guarded task management (create/edit/reprioritize plan files) over them. One Hono Node process serves the API, SSE stream, and the built SPA on localhost:5599.

Install

pnpm run console:install-service

This copies service/com.berth-dev.berth-console.plist into ~/Library/LaunchAgents/, substituting this repo's absolute path, then launchctl bootstraps it (bootout-then-bootstrap if already loaded, so running it twice is safe). macOS only — the service is a launchd LaunchAgent; there is no equivalent wired for other platforms. Uninstall with launchctl bootout gui/$(id -u)/com.berth-dev.berth-console.

INSTALL_SERVICE_DRY_RUN=1 pnpm run console:install-service prints the planned actions without touching launchctl or the filesystem — this is the mode CI exercises (ubuntu-latest has no launchctl at all); a real install is a manual, owner-run step on this machine.

Config

apps/server/berth-console.config.json lists the watched repo roots ({"repos": ["/path/to/repo", ...]}) — only roots that actually contain .factory/ get watchers. Override the path with CONSOLE_CONFIG (used by tests/smokes to point at a fixture config instead).

  • PORT / CONSOLE_PORT — the server listens on 5599 by default; the plist sets CONSOLE_PORT=5599 explicitly (the code's actual env var name — see Maintenance notes in plans/008-service-ci-hardening.md for why this differs from the plan's literal wording).
  • Logs: data/logs/service.out.log / service.err.log, capped at 10MB — service/run.sh rotates an oversized log to <name>.1 (single generation, no compression) before exec-ing the built server on every service start.

Screens

  1. Phase Overview — wave stepper, live worker cards (model, elapsed vs. 45m cap, tool-call count), integration branch + PR badge, last closer verdict.
  2. Board — TODO / RUNNING / REVISE / REVIEW / DONE / BLOCKED columns, plan cards with a peek sheet, task create/edit/reject/reprioritize.
  3. Task Detail — plan markdown + tool timeline split view, run picker (worker/closer/fablefix/rev rounds), gate diagnostics, cost badge.
  4. Waves/DAG — dependency graph, per-wave gate ledger + closer verdicts.
  5. Usage — token/cost charts by model and day, factory-vs-interactive and sidechain filters, session drilldown, backfill progress.
  6. Events/Diagnostics — cross-repo feed (blocked/needs-owner/gate-fail/ diag/closer/crash) and a read-only artifact browser/viewer.

Keyboard map

Linear-style, everything routable (URL state):

Key Action
Space Peek (side-right overlay on Board)
j / k / / Walk cards under an open peek
Enter Promote peek to full route
Esc Back, focus retained
cmd+K Command palette

Recovery

  • Crash mid-tail: ingestion stores a durable byte offset in the SAME sqlite transaction as the rows it inserts, so a kill -9 mid-tail and restart resumes from that offset with no duplicate or missing events — proved by node scripts/smoke-phase8.mjs (starts the real built server, replays half a fixture run, kills it, restarts against the same data dir, replays the rest, asserts zero duplicate/gap seq values).
  • .factory/.gitignore is * — a driver --clean wipes the watched repo's .factory/results + .factory/state entirely, but console history is unaffected: sqlite (data/*.sqlite, gitignored, never committed) is the only durable history store.
  • Log rotation: service/run.sh caps data/logs/*.log at 10MB per file, rotating to a single .1 generation on every service start (see Config).

Standing checks

  • bash scripts/lint-write-paths.sh — CI gate enforcing the read-only invariants (.factory/ is never written; only apps/server/src/write/ mutates anything; git subprocess calls are confined to write/gitGuard.ts + the read-only allowlist in watch/gitState.ts). It is grep/regex-based (see the script's own comments) — a floor, not a guarantee: dynamic property access or indirect wrappers can evade it.
  • scripts/replay-fixture.sh + fixtures/worker-sample.jsonl — the standing test harness used by every scripts/smoke-phase*.mjs; no paid workers needed to test ingestion.
  • Real launchd verification (launchctl kickstart, reboot-sim via bootout/bootstrap) is a manual REVIEW-STEP on this machine — CI cannot exercise it (ubuntu-latest has no launchctl).

About

Merged into berth-dev/berth (console/). This repo is an archive.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages