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 14:45:37 +00:00

6.3 KiB

Tasks

Autonomous agent scheduling. A task is a cron-driven or one-shot prompt 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) or workflow (instantiate a workflow in the service channel).

schedule: cron expression or once. Supported patterns: @hourly, @daily, @weekly, */N * * * * (every N minutes), full 5-field cron via robfig/cron/v3.

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.

Get Task

GET /tasks/:id

Auth: Owner or admin.

Update Task

PUT /tasks/:id

Partial update. All fields from create are accepted.

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.

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.

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",
  "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",
  "timezone": "America/New_York",
  "is_active": true,
  "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": "running|completed|failed|budget_exceeded|cancelled",
  "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. Creates or reuses a service channel (output_channel_id)
  4. Persists the user_prompt as a message in the service channel
  5. Runs CoreToolLoop (headless completion — same as streaming but no SSE)
  6. Enforces budgets: max_tokens, max_tool_calls, max_wall_clock
  7. On budget breach: status = budget_exceeded, owner notified
  8. On completion: updates last_run_at, calculates next_run_at

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 5.

Webhooks

Tasks with webhook_url fire a POST on completion:

{
  "task_id": "uuid",
  "run_id": "uuid",
  "status": "completed|failed|budget_exceeded",
  "output": "...",
  "tokens_used": 1234,
  "timestamp": "..."
}

Signed with HMAC-SHA256 using webhook_secret in the X-Switchboard-Signature header. Retry: 3 attempts, exponential backoff.