Needs you: every decision an agent is waiting on, answerable from a phone
Release notes 2026-09-15 — the ask primitive and the Needs-you inbox (vocion-core#325, merged): approvals, rulings, merges and gates as one list with decision sheets, a recommended option, and an always-on Other.

Shipped: vocion-core#325, merged to main on 2026-09-15. Part of the 2026-09-15 release notes.
The outcome
An operator should be able to answer everything their agents are waiting on in one place, in a few minutes, from a phone. Before this change, that list did not exist as a thing. Approvals lived in the review queue, learning candidates on the learnings page, paused runs on their own pages, and anything that needed a ruling — an architecture question, a credential, a pull request a person has to merge — lived in a file or a chat message. Nothing counted it, and nothing was accountable for getting it answered.
What it is
Two additions to core.
The ask primitive. A row for anything that needs a person: kind is one of approval | input | ruling | credential | merge | recommendation | gate; title and a short body; options as { id, label, description?, recommended? } with at most one recommended; groupKey / groupTitle so several asks form one decision sheet; contextUrl and contextMd for the long form; a status that moves from open to approved | rejected | done | superseded; and the decision, note, actor and time once answered. The API is POST /api/v1/asks (an upsert on sourceRef, so re-filing the same question refreshes it instead of duplicating it), GET /api/v1/asks, GET /api/v1/asks/:id and POST /api/v1/asks/:id/decide. The full contract is in docs/entities/ask.md; the service is packages/core/src/services/AskService.ts.
The Needs-you inbox. /dashboard/inbox aggregates open asks with the rest of what waits on a human — pending review-queue proposals, paused or waiting mission, workflow and worker runs, pending learning candidates, worker runs that failed in the last day (packages/core/src/services/InboxService.ts). The header answers three things in one line each: What needs me, What changed, What happens next. Rows carry title, kind, who asked, age and risk, and nothing else.
How a decision feels
Each ask opens as one question on one screen. Options are tall rows with a consequence line under the label; the recommended option is pre-selected and marked; Other is always present and takes free text. Several asks with the same groupKey open as a stepper — one question, Next, a receipt of question → answer pairs with an Edit per row, then Submit all. Every decision with a note where the answer was reject or other is queued for the feedback classifier (packages/core/src/services/feedback/askFeedbackQueue.ts), so a correction becomes a learning candidate rather than a comment nobody re-reads.
The reference interaction was Claude Code's remote-control question flow on mobile. The design notes in the PR map each choice to a principle in the Product Design Manifesto: make the important things obvious, one obvious action, every interaction teaches the system something, hide complexity without hiding truth.
For workspaces already running
Additive. One table, one nav item with a live count, one adoption event (ask.decided). Nothing existing changes behaviour. An external process files asks with a tenant token:
curl -X POST "$VOCION_URL/api/v1/asks" \
-H "Authorization: Bearer $VOCION_TOKEN" -H 'content-type: application/json' \
-d '{"kind":"ruling","title":"Slack app: one per workspace or one per agent?",
"sourceRef":"ops:slack-granularity","risk":"medium",
"options":[{"id":"per-workspace","label":"One app per workspace","recommended":true},
{"id":"per-agent","label":"One app per agent"}]}'
and reads decisions back with:
curl "$VOCION_URL/api/v1/asks?status=decided&source=ops:&limit=50" -H "Authorization: Bearer $VOCION_TOKEN"
# → { items: [{ id, kind, title, status, decision, decisionNote, decidedBy, decidedAt, followUp, ... }], total, limit, offset }
status accepts open (default), decided, all or an exact status; source is a sourceRef prefix.
The screenshot above is a local workspace on fictional data.
Docs: docs/entities/ask.md.
Where this lives in the repo
- Table and migration:
packages/core/migrations/0091_ask.sql - Service (upsert on
sourceRef, decide with a 409 when not open,supersede):services/AskService.tsand its testsAskService.test.ts - Routes:
app/api/v1/asks/route.ts(POST upsert, GET list withstatus,source,agentSlug,kind,groupKey,limit,offset),[id]/route.ts,[id]/decide/route.ts; route tests inroute.test.ts - The aggregated "needs you" list and its badge count:
services/InboxService.ts - The screens:
dashboard/inbox/page.tsx(header + grouped list,features/dashboard/inbox/InboxList.tsx), the one-question screen and stepperAskSheet.tsx, the receiptAskReceipt.tsx, the group routeinbox/g/[groupKey]/page.tsx - Decision → learning candidate:
services/feedback/askFeedbackQueue.ts - Authorization: routes use the same
authApias the rest of/api/v1(tenant Bearer token or dashboard session);deciderequires theapprovecapability. Each decision is one row update — a sheet submits its asks one decide call at a time, so a partially answered sheet is a valid state, not a failure. - Contract:
docs/entities/ask.md