Skip to content

Design: Perch Hub as the default chat surface for crow bots - #349

Open
kh0pper wants to merge 1 commit into
mainfrom
spec/perch-hub
Open

Design: Perch Hub as the default chat surface for crow bots#349
kh0pper wants to merge 1 commit into
mainfrom
spec/perch-hub

Conversation

@kh0pper

@kh0pper kh0pper commented Sep 10, 2026

Copy link
Copy Markdown
Owner

Docs only. No code, no behaviour change.

Perch Hub returns as a core, gateway-served page at /perch that lists every live bot session and owns the conversation. The bot board goes back to being the project-management board it is, optionally launching a bot from a card. The board's session drawer is deleted in phase 2, so there is one chat surface rather than two.

The finding that shrank this

The hub needs no new API. GET /dashboard/perch-api/roost already does the cross-bot aggregation in a single pass — one query for every bot def, one engine.list(), one bot_sessions query for card_id/control — and the interactive routes already carry the entire conversation. The hub is a client of a contract with 77 route tests behind it.

Decisions recorded

Question Decision
Whose sessions? Bot sessions only, from the interactive engine
How does it ship? Core, gateway-served — not a bundle
The board's drawer? Deleted
Where? /perch, deep-linkable as /perch#<sessionId>
Layout List and chat as two views

Both rejected alternatives are argued rather than asserted. Restoring the bundle would re-introduce the daemon, port 4210, the perch-token file, the install step and a second auth path — the supervised-child mechanism the retirement commit deleted precisely because perch-hub was its only user. Keeping both chat surfaces means every future change lands twice; the four defects fixed today (#346, #347, #348) were all in one surface.

Why this is worth doing

The drawer is a 480px desktop slide-over squeezed to 92vw. Today it took four PRs without becoming good: unlabelled controls, a plan-mode label losing a specificity fight, models listed as provider/id, a stringified object printed into every transcript, and a Send button that could not be reached at all. The operator's judgement was that the old hub was better on a phone, and that is structural — it was a full page in normal document flow with a capped, self-scrolling transcript and the composer directly beneath it.

The mobile rules learned today are carried as constraints, not suggestions: 100dvh over 100vh, a sticky composer, no unlabelled controls, full-bleed width, and a CDP assertion that Send is reachable with the transcript scrolled to the top — the measurement that caught the bug when a screenshot did not.

Scope

Phase 1 ships the hub alongside the drawer, so nothing breaks. Phase 2 moves Talk and dispatch to the hub and deletes the drawer.

Two siblings are named and explicitly excluded: making bundles/bot-engine core so pi ships in the base install (B), and provisioning models during onboarding (C). The hub depends on neither — it renders the engine_required state instead. Also out: the old hub's on-disk pi session list and its tmux spawner, which are a second session system.

Spec: docs/superpowers/specs/2026-09-09-perch-hub-design.md

Perch Hub returns as a core, gateway-served page at /perch, listing every
live bot session and owning the conversation. The bot board goes back to
being the project-management board it is, optionally launching a bot from
a card; the board's session drawer is deleted in phase 2 so there is one
chat surface rather than two.

The hub adds NO API. GET /roost already aggregates every bot def, one
engine.list() and the bot_sessions rows in a single pass, and the
interactive routes already carry the whole conversation. The hub is a
client of a contract that has 77 route tests behind it.

Records the decisions and the reasoning against the alternatives:
restoring the bundle (its own daemon, port, token file and supervised
child, all of which the retirement commit removed) and keeping both chat
surfaces (every future change lands twice; tonight's four defects were
all in one surface).

Carries the mobile rules learned the hard way today as constraints rather
than suggestions: 100dvh over 100vh, a sticky composer, no unlabelled
controls, full-bleed width, and a CDP assertion that Send is reachable
with the transcript scrolled to the top.

Scope boundaries are explicit. Making bundles/bot-engine core, and
provisioning models during onboarding, are named as siblings B and C and
kept out.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant