There's a post going around where someone had one Claude Code session open two more on their Ubuntu box through kite's MCP. One child migrated a voice model before the old one went offline, another fixed their project tool, a third fixed kite itself. By their own account the migration finished code and passed review and CI by evening, then paused for sign-off; after they approved, it merged, versioned, shipped, and synthesized a real acceptance line on the new model. Impressive on paper. (Treat the timing and outcomes as one developer's unverified account, not a benchmark.)
But read the second half of that post, because that's where the actual engineering problem lives. The orchestration mostly worked. The human-in-the-loop channel is what fell apart.
The part that broke was the approval channel
Four failures, straight from the write-up:
- When a child session needed confirmation, it pushed to the phone. The notification never arrived. Two sessions sat waiting for over two hours until the person replied directly in the session.
- Confirmation requests timed out after about ten minutes. Reply after that, and the session no longer picked it up.
- When a child finished or got stuck, the parent that spawned it had no idea. Someone had to go look.
- Spawned sessions and manually opened ones blurred together, so you couldn't tell which was which.
None of those are orchestration bugs. They're all the same bug wearing different clothes: the control surface between a running agent and a human is fragile, ephemeral, and has no memory. A push that drops is gone. A request that times out can't be answered late. State that isn't written down can't be inspected.
This isn't unique to kite. The CCProgress plugin exists because a heavy Claude Code user couldn't see where a long task was in flight and didn't dare stop the session. The MatrixOne folks building snapshot/branch/diff/merge for agent writes said their real contribution is "a write path that can be stopped" and were careful to call the samples demos, not customer cases. DecisionsApi frames its whole value around routing, safety gates, and human review steps. Same signal from every direction: once agents start acting on their own, the scarce, breakable thing is the pause-and-confirm layer, not the model doing the work.
What's actually reusable here
The spawning logic is interesting but tied to a specific tool and machine. The reusable half is the approval relay sitting underneath it. Strip it down and it's three things:
- A durable queue that any child session can post an approval request into, and that never times out on its own. A request stays open until a human resolves it, whether that's ten minutes or ten hours later.
- A status row per spawned session: running, done, stuck, waiting. One place that always knows what every session is doing.
- A board where you read both and, when something is wedged, correct it by hand.
That's a backend and a small UI. It's buildable today, and the honest framing matters: the hard, durable part of AI agent development is usually this control plane, not the agent loop itself.
Building the relay on VicroCode
The queue and status table map cleanly onto a SQLite database. Two tables is enough to start.
`approvals`: an id, the session id that raised it, the action being requested, a payload, a `status` column (`waiting` / `approved` / `rejected`), who resolved it, and timestamps for created and resolved. Critically, no expiry logic. A row in `waiting` stays `waiting`. The timeout failure in the kite story was a design choice; here you simply don't make it.
`sessions`: a session id, a human-readable label so spawned work doesn't blur into your manual sessions, a `state` column (`running` / `done` / `stuck` / `waiting`), a last-heartbeat timestamp, and a free-text note.
Around that you put a Python backend. The natural way to do this on VicroCode is to run Python online as a hosted endpoint, so child sessions have a stable URL to hit instead of depending on a push that may silently drop. A few routes cover it:
- `POST /approvals` — a child posts a request, gets back an id, and polls or long-waits for resolution. Because the row never auto-expires, a late answer still lands.
- `GET /approvals?status=waiting` — everything currently blocking a human.
- `POST /approvals/{id}/resolve` — approve or reject.
- `POST /sessions/{id}/heartbeat` — a session reports state and timestamp. The parent that spawned work no longer has to guess; it reads this.
The board is a static HTML page served from the same project, calling those endpoints: a waiting-approvals column and a session-status table, with approve/reject buttons. When a session goes quiet or hangs, you flip its state or resolve a stuck approval directly. For the genuinely wedged cases, a built-in SQLite editor lets you open the table and fix a row by hand instead of writing a one-off migration script at 11pm. That's the "hand-correct from a board" piece made literal.
If you want approval decisions to be more than a yes/no button later, the pattern from DecisionsApi is worth borrowing: structured questions returning a choice plus confidence, which you could route through platform models via the Model Center and in-platform tool calls. But that's an enhancement. The queue earns its keep on day one.
Where the boundary actually is
Be clear about what this does not do, because the kite story is partly a story about a tool promising more than it delivered.
VicroCode does not open or run the agent sessions. It doesn't install an MCP server on your machine, doesn't spawn Claude Code, doesn't execute the migration. The relay is the thing the sessions talk to, not the thing that runs them. Your orchestration tool still lives on your box.
VicroCode also does not push to your phone. There's no native mobile notification channel here. What you get instead is the opposite of the thing that failed: a durable, pollable, always-queryable state you can open in a browser whenever you check, rather than a fire-and-forget alert that's gone if you miss it. If you want a phone ping, you wire your own notifier to the `GET /approvals?status=waiting` endpoint. That's deliberately outside the platform.
That trade is the whole point. The kite setup lost two hours because it bet everything on a push arriving in a ten-minute window. A relay that remembers, never expires a pending decision, and can be inspected and corrected by hand turns "the confirmation never reached my phone" from a stalled pipeline into a row you'll see the next time you glance at the board.
The agents will keep getting better at doing the work. The debrief from everyone actually running them says the same thing: build the part that lets a human stay in the loop without having to babysit it.