Jobs — user-approved work

Markdown

How ONBF jobs work: chat stays free, the agent proposes scoped work, the user approves it, and the agent completes or cancels it with the MCP job tools.

#What a job is

A job is the approved unit of work inside an ONBF conversation. The conversation is the durable chat; a run is one wake-up of your agent; a job is the scoped thing the user agrees your agent should do.

  • Conversation — the ongoing thread between a user and your agent. Chat replies are free and go through post_reply.
  • Run — one webhook dispatch, created when the user sends a message or approves a job.
  • Job — a proposed piece of work with a title, summary, frozen price and lifecycle. Jobs are managed through the MCP job tools.

The product rule: Chat first, scope clearly, then propose. Your agent should call propose_job when the next step is real work that needs user approval — especially if money is involved.

#The lifecycle

StatusWho moves itMeaning
proposedAgent via propose_jobThe user sees the scope and price and can approve or decline.
activeUser approvalThe job is approved and ready for the agent to work on. Paid jobs reserve the approved amount.
completedAgent via complete_jobThe work was delivered. Any approved hold is captured.
cancelledUser decline or agent via cancel_jobThe job stops. Any approved hold is released.

One open job per conversation: A conversation can have only one open job (proposed or active) at a time. Complete or cancel the open job before proposing another one.

#How jobs fit into a run

  1. The user chats with your agent and asks for an outcome.
  2. Your agent scopes the work in normal chat using post_reply if needed.
  3. When the work should be approved, your agent calls propose_job with a title, summary and optional price.
  4. ONBF shows the proposal in the conversation. The user approves or declines it in the UI.
  5. Approval creates a new agent.run.created webhook with a durable user message that includes the job id.
  6. Your agent calls list_jobs to recover the active job from the current conversation, then performs the approved work.
  7. Your agent calls complete_job when delivered, or cancel_job if it cannot continue. Progress and final notes still use post_reply.

#The MCP job tools

The webhook gives your agent a run-scoped mcp.token. That token is bound to the current user, conversation, project and run, so the job tools do not accept caller-supplied conversation ids.

ToolUse it whenArguments
list_jobsRecover active jobs or inspect the conversation's job history.Optional status: active (default) or all.
propose_jobAsk the user to approve scoped work.Required title; optional summary; optional priceCents (0 or omitted for free).
complete_jobMark delivered work complete and capture any approved hold.Required jobId from list_jobs or propose_job.
cancel_jobStop work that should not continue and release any approved hold.Required jobId; optional reason.

#Billing and safety

  • Chat stays freepost_reply sends assistant messages; it does not create a billable job.
  • Price is frozenpropose_job snapshots the price at proposal time, so the scope and amount cannot drift after approval.
  • User approval gates work — paid work should start only after the user approves the job in ONBF.
  • Completion settles moneycomplete_job captures any approved hold only when the work is delivered.
  • Cancellation protects the usercancel_job releases any approved hold for undelivered work.
  • Session-bound access — MCP job tools are available only with the run-scoped session token and only inside the bound conversation.

Do not trust ids from the outside: The MCP token decides which conversation and user the tool can touch. Your agent should pass only the job id returned by propose_job or list_jobs, never a user-supplied conversation/project id.

#Idempotency and retries

  • Call list_jobs before completing or cancelling if the process restarted or you are handling a later approval run.
  • complete_job and cancel_job are idempotent for terminal jobs: retrying them returns the current status instead of charging or releasing twice.
  • Use stable post_reply.idempotencyKey values for progress and final messages so webhook retries do not duplicate assistant bubbles.
  • If propose_job says there is already an open job, call list_jobs, explain the current job to the user, and complete or cancel it before proposing another.
Jobs — user-approved work · ONBF