One shell, three tools, one rail
The left edge has three tools. HQ is where you run and configure the company. Work is the tasks and docs product we already have. Chat is channels where workers are members.
On the right sits a rail with three tabs: ✦ Polaris (the Chief of Staff), Activity and Doc. It stays open when you switch tools, so the conversation on the right is never lost. Task threads open in a side panel instead of replacing the page.
Underneath: realtime does not deliver events on the local stack, so the rail polls for now. The Doc tab is read-only in this version.
Today: what needs you, across your orgs
HQ › Today is one ranked queue of things only a person can do. In group mode it merges every org you belong to, with an org tag on each item. The kinds shown here are decide, blocked and review. Each item says how long it has waited and how many worker minutes it is blocking.
A delivery is done only when a person closes it. Accept marks the task done, credits the hours and records the rating once. Send back bills zero hours, and your note goes back to the worker as a new verbatim request.
Underneath: Today is a SQL function over the ledger, jobs and tasks, so items clear by themselves when the state changes. Rank is hours waiting × (1 + blocked worker minutes / 60). Closing goes through close_delivery, which only people can call.
The task ledger: every ask is kept, every ask is answered
Every comment a person writes on a task becomes a request in the task ledger, word for word. A worker reads every open request, not only the last comment, so an ask cannot get lost under fifty progress updates.
A delivery must answer each open request as done, declined with a reason, or acknowledged. If it misses one, it is rejected before anything is posted, and the worker fixes it in the same session. If the worker stalls twice, it stops retrying and asks the person who decides one question.
Underneath: code checks run first and need no model: an asked-for PDF must be attached, and "I could not…" without a declined request is refused. Then a critic on a different model, with a clean context, reviews the delivery.
✦ Polaris decides, and says why
A new task's default owner is "✦ Polaris decides", first in the owner picker. The Chief of Staff picks who does it and writes the reason on a routing card, along with who else it considered.
You can re-route, or take it yourself. The override is logged, because a dispatcher you cannot overrule is one you stop trusting.
Underneath: routing is a ladder, not a model reading everything. An explicit owner wins, then a rule, then a SQL shortlist by skills, rating and open load. Only an unclear shortlist reaches the Chief of Staff on the Think rung, and if it is still unsure it asks the decider one question. It never escalates to a premium provider.
Hiring only through the Chief of Staff
There is no "create worker" form. You tell the Chief of Staff about the gap, and it drafts a role card: mission, skills, tools, identity, how it starts, budget, who it reports to, and its rights.
The card is inert until a person accepts it. Nothing exists before that. One copy of each pending card shows on every surface, so you see it wherever you are.
Underneath: role cards are hire_proposals rows. The conversation in these screenshots is seeded: a real hiring conversation needs a model key, which the local stack does not have ("brain not connected").
Chat v1: workers are members of the room
Every org gets #general with every member, workers included. There are also project, private and direct channels, with one level of threads. Mention a worker and it answers in the thread. Type /task to turn a message into a task card.
Workers answer people, never other workers: a worker's message wakes nobody. Only the Chief of Staff can bring a worker into a channel.
Underneath: a person's message that mentions a worker queues one reply job. The worker reads the last 30 messages, the thread and its Mind files, then answers on the org's chat provider. Out of scope for v1: Slack read-in, reactions, pins and files.
Activity and the catch-up line
◔ Activity shows what happened while you were away, across everything you can see. A catch-up line on top counts deliveries, decisions waiting, proposals, stalls and assignments since you last looked, then folds the routine updates.
Anything that came from outside the company is quoted and labelled EXTERNAL. That way neither a person nor a worker mistakes it for an instruction.
Underneath: visibility follows the task, so moving a task into a private bucket hides its history. Notifications bundle into windows (default 11:00 and 16:00) and stay quiet from 21:00 to 08:00. A stuck worker's question reaches the decider at once.
Awareness: workers notice and propose, within a budget
Patrol is retired. Each worker's Mind file now lists what it watches: the org, a bucket or a task. When something it watches changes, the worker may propose a task or a direction. People accept, edit or say no.
Proposals land in Inbox under "Proposed by the workforce". Each one names the goal it serves.
Underneath: matching events fold into one pending watch job per worker, five minutes out. Per-day budgets cap proposals, comments and directions. A worker is never woken by its own events, chains stop at depth 3, and a storm breaker trips at 50 worker-caused events in one batch and tells the owner.
Mind files: one versioned file system for what workers follow
Identity, policy, goals, skills, playbooks and memory are all plain files with frontmatter. Each file has a scope (platform, org, bucket, worker, person), an enforcement level (must, default, advice) and a load mode (always, or on demand). No hidden prompts.
Owners and admins save new versions. Members propose changes, and owners merge or decline. Every run records the exact version of every file it used, so a wrong delivery can be traced to the policy it was given.
Underneath: one SQL function, resolve_mind(worker, task), builds the stack for both the web app and the runtime. The always-loaded part goes first in the prompt, byte for byte the same each run. Versions per run are stored in job_minds.
Models: rungs, our own endpoints first, a budget
Work runs on three rungs: Think (routing, planning, the step-up retry), Execute (the work) and Trivial (the critic and small classifications). Each org picks a provider and model per rung. Open models on RunPod come first. When a RunPod endpoint is cold, the job parks and waits; it does not spill to a paid provider.
A monthly budget is a soft stop: work jobs park, chat still goes through because a person is waiting. An org can lower a provider's data ceiling, never raise it. A single task can be pinned to Claude with "Needs Claude".
Underneath: an eval script replays recent briefs through a rung with the same gates and critic, and prints the gap to Sonnet as PASS or HOLD. Execute moves to RunPod only within 5 points of Sonnet, and the script never switches anything by itself.
Portfolio, Map and Workforce Pulse
Buckets are now areas or projects. An area lasts forever. A project ends, and carries an outcome, done criteria, a DRI, a target date and a status. Portfolio lists the active projects with health. Map shows who owns what and flags the gaps.
Workforce Pulse shows how the workers are doing. Every number is computed from the ledger, the jobs and the model calls, never typed in.
Underneath: the Map's "goal without project" gap cannot fire yet, because there is no goals table. Pulse on seeded data shows mostly n/a; the tiles fill once real deliveries are closed.
What is under the hood, and what is not done yet
Under the hood
- Events outbox. Every change is an event with a cursor per consumer. A new consumer starts at the end of the log, so a first deploy does not replay history.
- Scheduler. One atomic claim, ordered interactive, then prompt, then deferred, then by deadline and age. Only one writer per task at a time.
- Critic and gates. Code checks first, then a critic on a different model with a clean context. A second identical tool call is refused, a third stops the job.
- Data-class ceilings. The model gateway refuses to send data above a provider's ceiling. A policy naming an unconfigured provider is refused, never re-routed.
- Cost on every call. Tokens, cost, provider and rung, rolled up by job, task, worker and month.
- Verified. Full suite on the resized local VM, 17 Oct 14:50 Bangkok: 696 pass, 0 fail, 2 todo.
tscandnext buildgreen.
Not done yet
- Nothing is deployed. The live database was never touched. Everything runs on the local stack.
- Identities (worker email), Desks (a machine per worker) and Zones (workflows, chains) are not built. All three wait on decisions below.
- Known gaps. The Doc tab is read-only. A real hiring conversation needs a model key. Chat has no Slack read-in, reactions, pins or files. Mind files have no three-way merge and no rename or move.
Open decisions for Nestor
- Security migration on live. Three holes in the live app, fixed and tested on the branch. Independent of everything else.
- CI. Run
gh auth refresh -s workflowso the test workflow can land. - Go-live order. 16 migrations one file at a time, with the runtime deploys that ride along. Written in
GO-LIVE.md. - Worker email domain. Our own via Cloudflare Email Routing and Resend, or AgentMail. Blocks the first external effect.
- Fly token for desks. Zones wait on identities.
