Human-in-the-Loop Task Manager for AI Agents
Docs / Tasks
Guide

Task Lifecycle

Everything about how tasks move from Claude to you and back. Status flows, replies, attachments, and how the agent picks up where it left off.

The Full Lifecycle

notstarted
task created
agent picks up
ongoing
agent working
completed
rejected

The agent sets notstarted → ongoing when it starts work, then transitions to completed or rejected based on your response. For human-assigned tasks, you control the status transitions from the dashboard.

Status Reference

notstarted
Default state when a task is created via task create. The task is queued and visible in the dashboard. The agent should immediately call task updateStatus with "status": "ongoing" when it starts working on it.
ongoing
The agent is actively working on this task. The dashboard shows a spinner. The human can still reply at any time, and the agent will receive the message via the notification channel.
completed
The task is done. Set by calling task updateStatus with "status": "completed". For human-assigned tasks, the human marks it complete from the dashboard. The task moves to the completed section.
rejected
The task was denied or cancelled. The human can reject from the dashboard, or the agent can set "status": "rejected" with task updateStatus if it can't complete the work. A task reply explaining why is good practice.

Creating Tasks (from Claude)

Claude calls task create whenever it needs human input. A well-formed task includes:

Claude creates a task
task {"action": "create", "payload": {
  "title": "Approve: Delete stale user sessions older than 90 days",
  "body": "I'm about to run this migration:\nDELETE FROM user_sessions WHERE created_at < NOW() - INTERVAL '90 days';\n\nEstimated rows affected: ~14,000\nThis is irreversible. Approve to proceed?",
  "assignee": "human"
}}
title
Short, action-oriented. Prefixing with "Approve:", "Review:", "Question:" helps you triage at a glance.
body
Full context — what Claude has done, what it needs, relevant code or diffs. Don't make the human dig.
assignee
"human" for tasks requiring your attention. "agent" for tasks Claude assigns to itself (self-tracking).

Run help {"action": "task.create"} for every field task create accepts. Plugins and gateways installed before the action tools may call createTask instead; the server still accepts the old names. See the MCP tools reference.

Replying to Tasks

From the dashboard, type your reply and hit send. Your message is instantly pushed to Claude via the notification channel. Claude receives it as a <channel> message in its context — no polling needed.

How it flows
H
Approved! But use UUID primary key instead of auto-increment. Also add index on expires_at.
Claude received your reply via notification channel.
Updating schema to use UUID pk + expires_at index...
C

The agent can also send replies back to a task thread using task reply — useful for progress updates, confirmations, or follow-up questions.

Attachments

Both Claude and humans can attach files to tasks. This is useful for sharing diffs, screenshots, logs, or config files.

Claude Attaches

Claude passes base64-encoded file data to task create or task reply in the attachments field of the payload.

task {"action": "reply", "payload": {
  "taskId": "...",
  "text": "Here's the diff",
  "attachments": [{
    "id": "att_001",
    "filename": "schema.diff",
    "mimeType": "text/plain",
    "data": "<base64>"
  }]
}}
Claude Downloads

When you attach a file in the dashboard, Claude receives the attachment ID and its link in the channel message. It calls task getAttachment to fetch it.

task {"action": "getAttachment", "payload": {
  "attachmentId": "att_xyz",
  "taskId": "0ZRgCquBZ7R",
  "format": "base64"
}}
// format "url" (the default) returns the link instead
// returns: { filename, mimeType, data }

Reading Task History

Claude can fetch the full message history of any task by calling task get with "includeConversation": true. This is useful when resuming a long-running task or re-reading instructions after a context reset.

task get example
task {"action": "get", "payload": {
  "taskId": "0ZRgCquBZ7R",
  "includeConversation": true,
  "limit": 20,
  "cursor": 0   // paginate with the cursor from the previous call
}}

// Returns the task, plus its conversation:
{
  id: "0ZRgCquBZ7R",
  title: "...",
  messages: [
    { role: "agent", text: "I'm about to delete 14k rows...", ts: "..." },
    { role: "human", text: "Approved, but use UUID...", ts: "..." }
  ],
  total: 2,
  cursor: null  // null = no more pages
}
Want the full tool reference?
All 7 MCP tools, their actions, and examples.