This repository has been archived on 2026-04-03. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
core/docs/ICD/tasks.md
2026-03-11 19:41:04 +00:00

8.8 KiB
Raw Blame History

Tasks

Autonomous agent scheduling. A task is a cron-driven, one-shot, or webhook-triggered execution in a headless service channel — no human participant in the loop.

Configuration

Global config keys (set via PUT /admin/settings/:key):

Key Default Description
tasks.enabled true Master kill switch for task scheduler
tasks.allow_personal true Allow non-admin users to create tasks
tasks.max_concurrent 5 Max tasks running simultaneously
tasks.personal_require_byok false Personal tasks must use BYOK provider

Default budget ceilings (overridable per task):

Key Default
tasks.default_max_tokens 4096
tasks.default_max_tool_calls 10
tasks.default_max_wall_clock 300 (seconds)

Personal Tasks

List My Tasks

GET /tasks

Returns tasks owned by the current user.

Auth: Authenticated.

Create Task

POST /tasks
{
  "name": "Morning News Digest",
  "description": "Summarize top tech news",
  "task_type": "prompt",
  "persona_id": "uuid|null",
  "model_id": "claude-sonnet-4-20250514",
  "system_prompt": "You are a news summarizer.",
  "user_prompt": "Summarize the top 5 tech news stories from today.",
  "schedule": "@daily",
  "timezone": "America/New_York",
  "max_tokens": 4096,
  "max_tool_calls": 10,
  "max_wall_clock": 300,
  "output_mode": "channel",
  "webhook_url": "https://...",
  "provider_config_id": "uuid|null",
  "notify_on_complete": false,
  "notify_on_failure": true,
  "tool_grants": ["web_search", "url_fetch"]
}

task_type: prompt (direct LLM execution), workflow (deferred — not yet implemented; creation is rejected at the API), or action (no LLM — relay/webhook only; requires task.action permission).

schedule: cron expression, once, or webhook. Supported cron patterns: @hourly, @daily, @weekly, */N * * * * (every N minutes), full 5-field cron via robfig/cron/v3. When schedule is webhook, the task fires only on inbound POST to its trigger URL.

output_mode: channel (default — output stays in service channel), note (creates a note from the output), webhook (POST result to URL).

Auth: tasks.create permission required. Additionally, task.action permission is required for task_type: "action".

Get Task

GET /tasks/:id

Auth: Owner or admin.

Update Task

PUT /tasks/:id

Partial update. Accepted fields: name, description, persona_id, model_id, system_prompt, user_prompt, workflow_id, tool_grants, schedule, timezone, is_active, max_tokens, max_tool_calls, max_wall_clock, output_mode, output_channel_id, webhook_url, provider_config_id, notify_on_complete, notify_on_failure.

Auth: tasks.create permission, must be owner.

Delete Task

DELETE /tasks/:id

Auth: tasks.create permission, must be owner.

Run Now (Manual Trigger)

POST /tasks/:id/run

Immediately executes the task regardless of schedule. Creates a new task run. Returns 409 if a run is already active or queued.

Auth: tasks.create permission, must be owner.

Kill Active Run

POST /tasks/:id/kill

Cancels the active run. Sets status to cancelled.

Auth: tasks.create permission, must be owner.

List Runs

GET /tasks/:id/runs

Returns run history for the task, most recent first.

Auth: Owner or admin.

Webhook Trigger (Inbound)

External systems fire a task by POSTing to its trigger URL.

POST /api/v1/hooks/t/:token

The :token is a per-task secret generated at creation time (returned in the trigger_token field). The request body is stored as trigger_payload on the run record and forwarded to the executor:

  • Prompt tasks: payload is prepended to the user prompt as context.
  • Action tasks: payload is relayed to the outbound webhook as-is.
  • Workflow tasks: (deferred) payload becomes initial stage data.

Returns 202 Accepted:

{
  "triggered": true,
  "run_id": "uuid",
  "task_id": "uuid"
}

Returns 409 Conflict if a run is already active or queued. Returns 410 Gone if the task is inactive.

Auth: None (token-based). The trigger token is the credential.

Rate limiting: Governed by global request rate limits. No per-task rate limiting in v0.28 — defer to a future version if needed.

Team Tasks

Team-scoped tasks visible to all team members, manageable by team admins.

List Team Tasks (Member)

GET /teams/:teamId/tasks

Returns tasks scoped to the team. Read-only for members.

Auth: Team member.

List Team Task Runs (Member)

GET /teams/:teamId/tasks/:id/runs

Auth: Team member.

Create Team Task (Admin)

POST /teams/:teamId/tasks

Same shape as personal task creation. Team scope is injected automatically.

Auth: tasks.create permission, team admin.

Update/Delete/Run/Kill Team Task

PUT    /teams/:teamId/tasks/:id
DELETE /teams/:teamId/tasks/:id
POST   /teams/:teamId/tasks/:id/run
POST   /teams/:teamId/tasks/:id/kill

Auth: tasks.create permission, team admin.

Admin Tasks

Platform-wide task management.

List All Tasks

GET /admin/tasks

Returns all tasks across all users and teams.

Auth: Platform admin.

Admin Run/Kill/Delete

POST   /admin/tasks/:id/run
POST   /admin/tasks/:id/kill
DELETE /admin/tasks/:id

Auth: Platform admin.

Task Object

{
  "id": "uuid",
  "owner_id": "uuid",
  "team_id": "uuid|null",
  "name": "Morning News Digest",
  "description": "...",
  "scope": "personal|team|global",
  "task_type": "prompt|workflow|action",
  "persona_id": "uuid|null",
  "model_id": "claude-sonnet-4-20250514",
  "system_prompt": "...",
  "user_prompt": "...",
  "workflow_id": "uuid|null",
  "tool_grants": ["web_search", "url_fetch"],
  "schedule": "@daily|once|webhook",
  "timezone": "America/New_York",
  "is_active": true,
  "trigger_token": "hex-string|null",
  "max_tokens": 4096,
  "max_tool_calls": 10,
  "max_wall_clock": 300,
  "output_mode": "channel|note|webhook",
  "output_channel_id": "uuid|null",
  "webhook_url": "https://...",
  "webhook_secret": "...",
  "provider_config_id": "uuid|null",
  "notify_on_complete": false,
  "notify_on_failure": true,
  "last_run_at": "...|null",
  "next_run_at": "...|null",
  "run_count": 42,
  "created_at": "...",
  "updated_at": "..."
}

Task Run Object

{
  "id": "uuid",
  "task_id": "uuid",
  "channel_id": "uuid|null",
  "status": "queued|running|completed|failed|budget_exceeded|cancelled",
  "trigger_payload": "...|null",
  "started_at": "...",
  "completed_at": "...|null",
  "tokens_used": 1234,
  "tool_calls": 3,
  "wall_clock": 45,
  "error": "...|null"
}

Execution

The TaskScheduler is a background goroutine polling every 30 seconds.

  1. Finds tasks where next_run_at <= now and is_active = true
  2. Skips if an active run exists (GetActiveRun returns non-nil)
  3. Adopts a queued run if one exists (from webhook trigger), otherwise creates a new run record
  4. Marks last_run_at (records when execution started, not when it finished)
  5. Creates or reuses a service channel (output_channel_id)
  6. Persists the user_prompt as a message in the service channel (with trigger payload prepended if present)
  7. For prompt tasks: runs CoreToolLoop (headless completion)
  8. For action tasks: skips LLM, relays trigger payload to webhook
  9. Enforces budgets: max_tokens, max_tool_calls, max_wall_clock
  10. On budget breach: status = budget_exceeded, owner notified
  11. On completion: calculates next_run_at

Workflow tasks: Not yet implemented. The API rejects task_type: "workflow" at creation time. Reserved for a future version.

Provider resolution: BYOK → team provider → global provider → routing policy. If tasks.personal_require_byok is true, personal tasks that don't have a BYOK provider fail at step 7.

Action tasks skip steps 69. They create the service channel, fire the outbound webhook with the trigger payload, and complete.

Webhooks (Outbound)

Tasks with webhook_url fire a POST on completion:

{
  "task_id": "uuid",
  "run_id": "uuid",
  "task_name": "Morning News Digest",
  "channel_id": "uuid",
  "status": "completed|failed|budget_exceeded",
  "completed_at": "2025-03-11T12:00:00Z",
  "output": "...",
  "tokens_used": 1234,
  "error": "...|null"
}

Signed with HMAC-SHA256 using webhook_secret in the X-Switchboard-Signature header. Retry: 3 attempts, exponential backoff (1s, 5s, 25s).

Task Chaining

Task A's outbound webhook_url can be Task B's trigger URL:

Task A (webhook_url) → POST /api/v1/hooks/t/<task-B-token> → Task B runs

This enables multi-step pipelines: CI failure → summarize with LLM → post to Slack. Each link is a separate task with its own type, budget, and notification preferences.