The Secretary
Fuse the insider SmolPaws cat with a board that manages the user's conversations — dispatch, track, act — talk to it in realtime voice, and ship the whole thing as an Agent Canvas Skin. The cat stops being a corner mascot and becomes the face of a secretary that runs your other agents for you.
STATUS: DESIGN epic smolpaws-08f (insider) epic smolpaws-3e1 (voice)
1The idea
The insider cat today is a presence: a corner avatar, a "call the cat" button, an identity that knows it runs on a local agent-server. Useful, but small. The next step gives it a job: be the user's secretary — the one agent whose whole purpose is to manage the user's other agents and conversations, so the human stops babysitting a dozen chats.
rbren/vibe-manager, the productized OpenHands/app-acm); those keep their name. Ours is the secretary — a named, avatar'd cat, closer in spirit to AmpCode's "Puck" than to a kanban tool.
Three things combine, and each already half-exists:
| Piece | Today | Becomes |
|---|---|---|
| The cat | Corner avatar + call-the-cat, insider identity shipped | The face and voice of the secretary. |
| The view | Nothing (a launcher) | A board of the user's conversations it manages. |
| The brain | Fixed toolbox in a spike | The real OpenHands agent via /v1/chat/completions. |
2Lineage: what the "manager" already proved
rbren/vibe-manager is the reference. A kanban SPA plus a per-workspace Manager automation (a 1-minute cron) that dispatches and tracks worker agent conversations. Its own words, from the Slack thread that kicked this off:
The mechanics worth stealing (all proven in that repo):
- A board per workspace — tickets flow pending → in_progress → needs_input / finished / verified.
- A manager is a conversation that spawns worker conversations — the deterministic cron only wakes the manager agent when the board's fingerprint changes, with loop guards so it can't churn.
- Live action summaries — the manager watches each worker's websocket and shows its latest tool action on the card.
- Mechanical transitions — PR merged → finished, push verified → finished — done in code, not by the LLM.
- It only manages what you put on the board; conversations created elsewhere don't appear. Good boundary.
This got productized as OpenHands/app-acm ("Agent Canvas Manager") and made the default Skin. So the pattern is blessed; our job is to give it a cat's face, a voice, and the SmolPaws shared memory — and to scope it to what one person actually needs.
3The agent as a brain — /v1/chat/completions
The unlock that makes the voice (and the secretary) real: the agent-server already exposes an OpenAI-compatible chat endpoint that runs the whole agent as an LLM.
POST /v1/chat/completions (X-Session-API-Key)
{ "model": "openhands_deepseek-v4-flash",
"messages": [{"role":"user","content":"Run: echo hi. Tell me the output."}],
"stream": true }
Verified live: it doesn't just chat — it runs the agent's tools inside the turn. Asked to run a shell command, it ran it; asked "how many conversations do I have", it did the work and answered with the real number. Prompt tokens ~12–24k per call (that's the full agent system prompt). Streaming works.
ask_the_agent(request) — and the agent does the rest.Related and useful: the same server has native ChatGPT-subscription auth (/api/llm/subscription/openai/* device flow, /api/llm/subscription/openai/models) — the secretary can run on a subscription, not just an API key.
4Voice: what the spike already showed
The realtime-voice spike (smolpaws-3e1.1, odie branch spike/realtime-voice) is the secretary's mouth and ears. Path A — an OpenAI Realtime model as the conversational brain, function-calling into our agent — was live-tested and feels good. What's proven:
- Full-duplex WebRTC voice with barge-in, in-browser mic/speaker.
- Both-side transcripts captured (user + cat) → the written chat record.
ask_the_agent→/v1/chat/completions→ real agent action, spoken back.- Auth on Engel's ChatGPT subscription (Codex token mints the Realtime ephemeral key), API key only as fallback.
/v1/chat/completions so the cat starts talking as tokens arrive, and/or a spoken "let me check…" filler the instant a tool call fires. Trivial lookups (count/list) keep a fast direct-REST path.5The secretary board
The cat's new home view. It is the manager board, re-skinned as SmolPaws and scoped to one person. The good news: we already have a working skeleton — Purr Projects (my current Canvas skin) is a read-only board over the agent-server's conversation list. It becomes the secretary board by adding tickets and actions.
What Purr Projects already gives us (~/workspace/skin): a Node app with npm run start, a skin.yaml with the SmolPaws theme, and handlers that read /api/conversations/search + per-conversation events/search with the injected X-Session-API-Key, never exposing it to the browser. What it lacks: a ticket store, dispatch, and the state machine. Those are the manager's contribution.
6Ship it as a Skin
The delivery vehicle is the Skins mechanism from OpenHands/OpenHands#16232 (open, all-hands-bot). A Skin is a git-backed per-instance UI: a repo with skin.yaml + a web app started with npm run start on OPENHANDS_SKIN_PORT, surfaced as the top sidebar item → an iframe tab, and it's the default landing tab. One skin per instance. The static server mounts a /skin-api management surface and reverse-proxies /skin-app (HTTP + WS).
That's exactly the shape Purr Projects already targets, so the secretary is "just" a richer skin. Engel's constraint on adopting the PR:
#16232 untouched upstream. If it changes upstream, we re-squash.7The endpoint is a conversation, not a completion
/v1/chat/completions as a "stateless, ephemeral completion" that can't show on the board. That was wrong. In agent-sdk (openhands-agent-server/.../openai/service.py) the endpoint calls start_conversation() and returns get_agent_final_response(): it runs the whole OpenHands agent — tools and all — as one turn, and the turn is a real, persisted conversation. It returns an X-OpenHands-ServerConversation-ID header, and you can reuse it on the next call to continue the same conversation.So the two "wirings" aren't stateless vs stateful — both are agent conversations. The real difference is only how you drive and observe them:
(a) /v1/chat/completions | (b) conversation API + event stream | |
|---|---|---|
| What it is | The full agent, one synchronous turn per call. Runs tools internally; returns only the final assistant text. | The same agent, driven message-by-message with the live event stream (every action/observation). |
| State | A real conversation — persisted, retrievable, reusable via the returned server-conversation id. | A real conversation — you hold the id from the start and watch it live. |
| Tool calls visible? | No — they happen, but you get the final text only (that's the point: clean answer for voice). | Yes — you see each tool call/result as events. |
| Shows on board? | Yes, if we want it to — it's a conversation; tag it on create and it gets a card like any other. | Yes — it's the same kind of conversation. |
| Best for | The voice brain: ask once, get the final answer back to speak. Simplest possible call. | The board's live on-card action summary, and dispatched workers you watch progress on. |
8Build plan
- Board view, fixed layout — design the columns + card (state, live action, model chip, links) as a deliberate layout; prototype against real conversations via the Purr Projects skeleton.
- Vendor Skins — squash
#16232onto our branch as one commit; confirm install/iframe/default-tab works locally. - Ticket store + state machine — add tickets bound to conversations; the pending→in_progress→needs_input→done transitions, mechanical where possible.
- Dispatch — the secretary (a
smolpawsAgent Profile conversation) creates worker conversations from tickets; caps concurrency; funnels/holds conflicts. - Live status — reuse Purr Projects' events read + a WS watch for the on-card action summary.
- Voice on top — graft the realtime spike in: the cat answers and dispatches by voice, streaming + filler for latency.
- Shared memory — the secretary reads/writes the SmolPaws store (smolpaws-08f.2) so it remembers across sessions and faces.
9Risks & open questions
| latency Full agent turn ~12 s | Stream /v1/chat/completions; speak a filler on tool-call start. Fast REST path for trivial lookups. |
| scope One board or per-workspace? | rbren's insight was one board per workspace. For a single user the secretary may want one board across workspaces, tagged. Decide before the ticket store. |
| Skins PR Not merged yet | Vendor as a squashed commit; don't touch #16232. Re-squash if it moves. Watch canvas_version range. |
| loop guard Cron churn | rbren hit a 50-run overnight loop; his fixes (fingerprint + capped retries + absorbing manager's own entries) are the template — don't reinvent, port the guard. |
| dispatch safety Voice can spawn work | Dispatch creates real conversations that run tools. Keep a confirm step for anything beyond read-only until trust is high; the spike's tools are read-only on purpose. |
| pretty Purr Projects layout | Fixed, designed layout — not the current auto-grouped grid. |
/v1/chat/completions), and the voice (our spike). The secretary is the assembly — a cat that runs your other agents, that you can talk to.