Log in
DocsDots and your dev host

Dots and your dev host

Hand work to the supervisor agent on your own development machine from Dots, ChatGPT or Claude, get a task id at once, and hear back when a worker asks a question, finishes or fails. Your answers go to the exact worker that asked, and 0bridge tells you whether it took them. Nothing goes through Slack.

Last updated

If the machine already keeps a work ledger that a team of agents works from (your desk and Telegram put your words there), 0bridge can put what you tell Dots there the same way instead: see Ledger mode.

What it connects#

On the machine, an OpenClaw agent (the supervisor, for example one named lead) runs coding agents in Herdr panes, and host-task keeps the record of each task: its questions, answers and result. 0bridge doesn't replace any of them. 0b agent, the same small program as Your agents from your phone, connects that machine to your account and does all the work there:

  • A request from your AI app becomes a host-task task (T-012), and the supervisor gets a message about it with the task id, through openclaw agent, in a session of its own for that task. A second request, from another conversation, gets its own task and session, so it doesn't disturb the first.
  • When a worker asks something, host-task records it as a question. 0b agent reads new host-task events every few seconds and sends questions, completions and failures to 0bridge, once each, even across restarts.
  • Your answer is recorded with host-task answer and typed into that worker's pane, and 0bridge waits to see the worker pick it up. A question the worker (or the supervisor) wrote down itself goes back to the supervisor with your answer instead.

The supervisor is set up on the machine, never from 0bridge's side: 0bridge only knows that the machine has one, its agent's name and a label.

The supervisor decides where and how the work runs. The repos and modes you allow with 0b agent allow limit the agents 0bridge starts itself (Your agents from your phone); they don't limit host work, and a request's repo is passed to the supervisor as you said it. Give the supervisor its own rules for what it may touch.

Set it up#

  1. On the dashboard, under Settings → AI apps, check that Agent control is on. New accounts start with it on; an account from before 2026-10-06 turns it on there, which needs you to confirm it is you.
  2. On the machine, if 0b agent isn't running yet:
0b agent on
  1. Point it at the supervisor:
0b agent supervisor openclaw --agent lead --label dev-herdr-agent

It checks that host-task, openclaw and herdr answer (--host-task, --openclaw and --herdr take other paths), and warns if OpenClaw doesn't list that agent. It saves each program's full path, found on your shell's PATH as you run it, so the background service finds them even when its own PATH doesn't have ~/.local/bin. 0b agent supervisor status shows the setup, how far it has read and the last error; 0b agent supervisor off disconnects it. The first time, it starts at the end of the host-task log, so old events aren't sent; questions already open still show up when you ask for them.

What you can ask#

From any AI app with 0bridge and agent control on, eight tools:

ToolWhat it does
bridge__host_requestHands a piece of work to the supervisor and returns the task id at once. The work goes on in the background.
bridge__host_statusOne task with what happened lately (questions, answers, the supervisor's replies, the result), or the recent tasks.
bridge__host_followupMore instructions for a task, passed to the supervisor in that task's session.
bridge__host_questionsThe questions workers are waiting on you for, with their ids.
bridge__host_answerYour answer to one question, by its id.
bridge__host_updatesNew questions, completions and failures since the last call. This is how Claude hears back.
bridge__host_receiptsWhat this app sent to the host lately, and where each send stands. See Check that a send arrived.
bridge__host_deliveredLedger mode: records that you were shown the team's messages, a delivery receipt for each. See Ledger mode.

Try: "Ask my dev host to add a test for the date parser in the 0bridge repo", then "How is T-012 doing?"

The same request from the same app within 10 minutes is answered with the task already made, so a retried call doesn't start the work twice; the same follow-up to the same task isn't sent twice either. A request, follow-up or answer sent with a key is recorded once however often it's sent again (Check that a send arrived). Each machine numbers its own tasks and questions, so with more than one machine an id the two share needs the machine's name too, and 0bridge only sends a follow-up or an answer to the machine where it saw that task or question. When the machine is offline, status comes from what 0bridge saw last, and says so.

Answers go to the worker that asked#

bridge__host_answer takes a question's id (from the event, or bridge__host_questions). Your AI app should ask you first and pass on your words.

A question comes one of two ways, and the event's source says which. herdr: the worker stopped at a prompt in its pane (Herdr shows it blocked), and the answer is typed there. worker: the worker or the supervisor recorded the question with host-task emit; nothing waits at a prompt for it, so 0bridge passes your answer to the supervisor with the question's id and the task, and the tool says forwarded. host-task takes such a question off the task whenever the worker isn't blocked, so 0bridge keeps it open itself until it's answered, the worker asks a newer one, or the task finishes.

For a question Herdr raised:

  1. The answer is stored in host-task, for that question only, once. A question that's no longer the task's current one is refused, with the current one's id.
  2. 0bridge checks that the worker's pane is still the one that asked (the same pane and the same worker name in Herdr), and that you aren't looking at that pane yourself. If anything doesn't match, nothing is typed anywhere: the supervisor gets the answer with the question's id instead, and the tool says it was forwarded.
  3. The answer is typed into that pane only, and 0bridge watches Herdr until the worker leaves the waiting state. Then it records answer_delivered in host-task and the tool says delivered, with the state before and after (blocked → working).

If the worker doesn't move within a short wait, the answer is not typed a second time: the tool says pending, and if it still hasn't moved after two minutes, answer_unconfirmed is recorded and the supervisor is asked to look. Answering the same question again returns the first result and types nothing.

A pane that is focused on the machine is never typed into: the supervisor gets the answer, and the tool says the pane is focused.

Your answer is typed as keys, then Enter, at whatever prompt the worker is blocked on: when that's a coding agent asking permission to run a tool, it answers that prompt, and can approve the tool call, outside 0bridge's approval rules for the agents it starts.

How you hear back#

Dots and ChatGPT: events#

ChatGPT supports MCP events in Work chats on the web, in the desktop app with Cloud selected, and in dots. 0bridge offers three:

EventWhenFilters
host.task.questionA worker asks a question. Carries the task, the question's id and its text.machine, project, task
host.task.completedThe supervisor marks a task completed, with evidence. A worker saying it's done isn't a completion.machine, project, task
host.task.failedA task is marked failed.machine, project, task

After setting up, open the 0bridge plugin's page in ChatGPT and rescan it: the events show next to the tools. Then ask, in a Work chat or a dot: "Watch my host tasks: tell me each question with its task and question id, and each completion or failure." ChatGPT subscribes when you ask; 0bridge doesn't subscribe for it.

0bridge checks the address ChatGPT gives (public https only, no private networks, no redirects), sends it a signed verification first, and then one signed POST per event (Standard Webhooks). A delivery that fails is retried a few times over about 20 minutes with the same event id. Subscriptions survive restarts on both sides. A subscription with an expiry that has only failed, without a break of an hour, for a day stops until ChatGPT renews it; one without expiry keeps trying and is removed after a week of that. Disconnecting the app in the dashboard, the app revoking its tokens, deleting the token it uses, or turning agent control off stops deliveries at once. Each subscription shows in the activity log (events.subscribe), with the callback's host only.

ChatGPT's own rule applies: events missed while something was down aren't replayed. bridge__host_status and bridge__host_questions always show where things stand.

Your webhooks' events are offered too, as webhook.received, if you turned on Webhook events in chat apps.

Claude: pull and notifications#

Claude's connectors have no events, so Claude asks: bridge__host_updates returns what's new since its last call, and with wait it waits up to 20 seconds. Try: "Any questions from my dev host?"

To be told without asking, set an ntfy topic or email under Settings on the dashboard, as for your agents. A question is sent every time; a completion or failure isn't sent when another one for that task, from up to 30 seconds earlier, already was. Each is sent at most once: one that ntfy didn't answer in time isn't sent again, since it may have arrived. A notification says which task and what happened ("asks a question", "completed", "failed"), never the question's text, and links to the dashboard.

Other apps#

Any MCP client gets the tools. One that supports MCP events (protocol 2026-07-28) can subscribe the way ChatGPT does. Instinct has no MCP and no terminal, so it can't connect at all: Instinct.

Ledger mode#

Some hosts don't hand work to one supervisor agent: the work ledger (host-task) is where everything starts, and a team of agents there picks it up. Your desk and Telegram write your words into it (dev_request for new work, user_followup and user_decision for an existing task), and the team's supervisor turns a request into a task, asks you what only you can decide, and reports back. In ledger mode, what you tell Dots, ChatGPT or Claude enters that ledger the same way, and they read the team's questions and results back to you.

On the machine, with agent control on:

0b agent supervisor ledger --label devlead

Only host-task is needed (--host-task <path> if it isn't on your PATH; its full path is saved). 0b agent supervisor status shows kind: ledger, how far it has read, and the requests still waiting for a task id.

What happens:

  • A request is written as a dev_request: your words exactly, then a line saying where they came from, like 출처: ChatGPT via 0bridge · 2026-10-06 17:31 KST · 요청 hr_k3f9x2a1. 0bridge makes no task, runs no agent and types into no pane. The tool answers with the request's id (hr_…) and its place in the ledger, not a task id: the team gives it one when it takes it up. Asking again with the same words within 10 minutes, or 0bridge retrying, writes nothing twice.
  • Its task id comes when the team makes the task and keeps the request's id in what it writes (the request's source line, the task's contract). 0bridge sees the id in the ledger and links the two; from then on bridge__host_status request=hr_… shows that task, and Dots can follow it by its id.
  • A follow-up (bridge__host_followup) on a task is written as user_followup on it. Before the request has a task id, pass the request's id as the task: it's written without a task, starting (요청 hr_… 후속), and the team sees which request it's about.
  • The team's questions: when the team asks you something with options (a [선택지] block, the same one Telegram shows as buttons), it arrives as host.task.question with those options, and in bridge__host_questions and bridge__host_updates. Your answer (bridge__host_answer, with choice for the option you picked) is written as user_decision on that task, with the option the way a Telegram button gives it (choice: T-044|e1145|A / 선택: A) …). A question closes when the team asks a newer question on that task, when you've decided on another channel (the team clears it once your answer is in), or when the task ends — not when the team sends other messages on the task; an answer to a closed one is still recorded as your decision on that question, noting that it had closed, so the team sees it and nothing you said is lost. Questions a worker asks the team itself stay with the team.
  • Progress: the team's other messages to you (results, follow-ups, replies), on any task, show in bridge__host_status and as progress in bridge__host_updates.
  • Notices: the host's own notices to you, most with no task (server alerts, usage summaries, schedule briefings and reminders, a team message with no task), come as notice in bridge__host_updates, each with its kind, so your app can decide what to tell you. With Dots as your one channel, it sees everything Telegram used to.
  • Delivery receipts: once your app has shown you the team's messages or questions, it calls bridge__ledger_append with action delivered (or bridge__host_delivered) with their ids (a progress or notice item's event, a question's id), and 0bridge records a delivery receipt for each in the ledger (host-task delivered, primary_delivered), so the team can tell from the ledger that you saw them. The channel is dots (the ledger knows Dots and Telegram; any chat app through 0bridge counts as Dots), and the receipt names the app, the time and the call (ChatGPT via 0bridge · 2026-10-13 17:31 KST · hd_…), plus the app's own link for the conversation if it gives one. Only ids 0bridge has as the team's messages from that machine are sent, so only recent ones take a receipt (0bridge keeps the last 5,000 or so events per machine); a receipt that's already there comes back as such, so it needs no key and asking again is safe. Receipts aren't listed in bridge__host_receipts (that's what the app sent; these are in the ledger). With more than one ledger machine, one call per machine, with machine. Nothing else happens: no message is sent anywhere, no question is answered or closed. The machine needs 0b 0.2.40 or later; an older one is asked to update.
  • Completion and failure come back as before (host.task.completed, host.task.failed).
  • Notifications: the host already tells you on its own channel, so 0bridge sends no ntfy or email for a ledger host.
  • Outside context (a Trello comment for a task) is kept in the ledger as context_received on the task, and isn't passed to the task's worker: that takes the OpenClaw supervisor. Its status says so.

Check that a send arrived#

An app can lose a call: ChatGPT can cancel one before it reaches 0bridge (its confirmation or its automatic review stopped it), and then nothing was sent at all, even if the chat moved on. So an app shouldn't tell you "sent" until it has seen 0bridge's answer, and when it isn't sure, it can check and send again without doubling anything.

A key for each send. bridge__host_request, bridge__host_followup and bridge__host_answer take an optional key: the app's own id for that send, such as the id of your chat message (up to 100 letters, digits and . _ : @ / + = -). The same app sending the same thing again with the same key, with the same tool, gets the first result back, marked as a repeat, and nothing new is recorded: not on 0bridge, not in the ledger. "The same thing" is the words (spacing and case aside) and the task, question and option. A key that comes back with something else (another conversation's made-up msg_1, say) is refused with why, and nothing is sent: it never returns the old send's result in place of the new one. So use a new key for each send, and the same key only to retry it. A key holds for a day, also after 0bridge or the machine restarts; after that it's free again. If the first try never got a reply from the machine, the retry goes with the same request id, and the machine records it once. A send the machine refused (an answer for the wrong task, say) leaves its key free for the corrected one. Without a key, everything works as before.

Receipts. bridge__host_receipts lists what this app (or this token) sent lately, newest first: each request (hr_…), follow-up (hf_…) and answer, with its time, its task or request, its key, and where it stands:

StateMeans
no reply yet0bridge has it, the machine hasn't confirmed: send it again with the same key
in the work ledgerthe machine recorded it (with its host event)
taken upa request the team made a task for (with the task id)
with the supervisor, delivered, pending, refusedon an OpenClaw machine, as bridge__host_status says

It never shows the words you sent; a task's title is the host's. since takes minutes (30, 30m, 2h, 1d) or an ISO time, 24 hours by default, 7 days at most; limit up to 100. A send that isn't listed didn't reach 0bridge.

So, for an app: send with a key; if the call errors or you're not sure it went, call bridge__host_receipts (or just send again with the same key); tell the user it was sent only once it's listed as in the work ledger (or later).

bridge__ledger_append. In ChatGPT and Dots, 0bridge lists four tools (code mode), and the host tools ran through bridge__execute_write, which is marked as able to delete and to reach outside, because some tools behind it can. When your account has agent control on and one of your machines keeps a work ledger (0b agent supervisor ledger), apps get a fifth tool for exactly this:

bridge__ledger_append
  action    request | followup | answer | delivered
  text      your words
  task      followup: T-012 or hr_…; answer: the question's task
  question  answer: the question's id
  choice    answer: the option's letter
  events    delivered: the ids of the team's messages and questions you were shown
  ref       delivered: the app's link for the conversation (optional; no key needed)
  project, priority (request), machine, key

It runs bridge__host_request, bridge__host_followup, bridge__host_answer or bridge__host_delivered with the same checks (agent control, the token's scope, the answer's task check, the activity log), and goes only to a machine whose supervisor is the work ledger, where it only adds an entry: it's marked as not read-only, not destructive and not reaching outside (and not idempotent: a retry is safe only with the same key). A machine on the OpenClaw supervisor refuses it and says so; use bridge__execute_write there. Search and describe point those four host tools at it, with the action to use. bridge__execute_write still runs them as before.

It's listed only for such an account, so nobody else's list changes. If 0bridge can't read your machines within a moment when the list is asked for, it lists the tool anyway for an account with agent control on, so the list doesn't change with a passing hiccup; a call to it still goes only to a ledger machine. After turning agent control on or setting up the ledger, refresh 0bridge in the app once to see it (the four tools need no refresh; this one does, once).

From a terminal: 0b host receipts --since 30m, and --key <id> on 0b host request, followup and answer.

From a terminal (Dots VM, any machine)#

A dot has a computer of its own with a terminal, and its copy of 0bridge's tools in ChatGPT can be out of date. The 0b CLI calls the same host tools by name, so from that terminal (or any machine you're signed in on) you can hand work to your dev machine's work ledger without the chat app's tool list.

On the dot's computer:

npm install -g 0bridge
0b setup --agent-vm --name dot --no-vault

It prints a link; approve it once on your phone. That signs the computer in as an agent computer: its token expires after 7 days, and you can revoke it any time on the dashboard (Revoke). --no-vault leaves your vault's secrets off that computer.

Then:

0b host request "결제 페이지 모바일에서 깨지는 것 고쳐줘" --project 0bridge
0b host status hr_k3f9x2a1
0b host followup hr_k3f9x2a1 "특히 iOS Safari"
0b host questions
0b host answer 602 --task T-060 "A로 가자" --choice A

0b host request prints the request's id (hr_…) on its first line, or the task id once the team has one. Text can come from stdin with - (cat note.md | 0b host request -). Each command takes --json for scripts and exits non-zero when 0bridge or the host refuses, with the reason printed as it was given.

For notifications, run 0b host updates on a schedule and keep its cursor: the last line it prints is the next cursor.

cursor=$(cat ~/.0b-host-cursor 2>/dev/null)
0b host updates ${cursor:+--cursor "$cursor"} --wait 20 > /tmp/host-updates.txt && tail -n 1 /tmp/host-updates.txt > ~/.0b-host-cursor

--kinds question,completed,failed,progress,notice narrows what comes back.

What an agent computer may do here: only the host commands above (and 0b host receipts), and only for a machine whose supervisor is the work ledger (0b agent supervisor ledger). There every write is an entry in the ledger (dev_request, user_followup, user_decision); 0bridge types nothing into any pane. A machine on the OpenClaw supervisor, where an answer is typed into a worker's terminal, refuses an agent computer and says so; use a chat app or the dashboard for it. An agent computer still can't list your machines, start or steer coding agents, or subscribe to host events (it pulls them with 0b host updates). The gateway checks the supervisor when each call is made, on the machine the call goes to, and that machine's 0b agent checks its own setup again before it takes the call, so switching it to OpenClaw takes effect at once. Nor can an agent computer list your machines or their tasks through 0bridge's API.

What keeps it safe#

  • Off until the machine is pointed at a supervisor, and whenever agent control is off (any connected AI turns it off when you ask, with bridge__settings_off).
  • The supervisor's messages are sent without any delivery option: OpenClaw doesn't post its reply to Slack or anywhere else. 0bridge itself only sends to the AI app that subscribed and to your own ntfy topic and email.
  • Answers are typed only into the pane that asked, checked again right before typing, and never twice.
  • Host text (questions, replies, evidence) is masked for secrets on the machine and again on the server, and your AI app is told it's outside data, not instructions.
  • Requests, follow-ups and answers are in the audit log with the task and machine, never the text.
  • At most two supervisor messages run at once on the machine, and messages for one task go in order.

What 0bridge can read#

Your requests and answers, and the host's questions, the supervisor's replies and results, pass through 0bridge and are kept with your machine so status works while it's offline. They are masked, not sealed: treat them like the task pages in Your agents from your phone.

What's checked and what isn't#

As of 2026-10-05, this has been tested on a local copy of 0bridge with stand-ins for host-task, OpenClaw, Herdr and ChatGPT's receiver, not yet with a real ChatGPT account, a real dot, or the owner's machine. We'll date each one here when it's seen working. Until then, keep watching the host the way you do today.

Ledger mode (2026-10-06) has been tested the same way, with stand-ins for host-task and ChatGPT's receiver, not yet on the real machine. So has 0b host from a terminal: against a stand-in gateway and the machine hub's tests, not yet from a real dot. Keys, receipts and bridge__ledger_append (2026-10-07) too: whether ChatGPT stops cancelling the ledger tool's calls is still to be seen in ChatGPT itself. Delivery receipts (2026-10-14) against the stand-in host-task and the machine hub's tests, not yet on the real machine or in Dots.

Known limits:

  • One supervisor per machine: OpenClaw or the work ledger.
  • In ledger mode a request gets its task id only if the team keeps the request's id (hr_…) in what it writes when it makes the task; until then it shows as waiting.
  • When several machines have a supervisor, say which one (machine).
  • The callback's address is checked before every delivery, but between that check and the connection a name could point somewhere else; 0bridge's servers can't reach your private network either way.