Task Tracking & Auto-generation
Paid tier required
The Tasks API is available on Team and Enterprise plans only. Requests from a Starter team return HTTP 403.
Overview
xbrain tracks tasks as first-class objects alongside memory items and contacts. Tasks can be created in three ways: manually via the API or dashboard, automatically extracted from Granola meeting notes, or detected from chat messages by the task intent detector running in the LibreChat bridge.
Every task carries team_scope, project_scope,
visibility, confidence, truth_level,
source, and validation_status — the full 7-field
tagging contract. This means tasks participate in the same scoped retrieval
and truth-level promotion pipeline as the rest of the team's knowledge.
Three Creation Paths
Any authenticated user creates a task directly via the API or the team dashboard.
created_by is set to the user's ID. Assignee is validated to be a member
of the same team — cross-team assignment returns 422.
When the Granola integration ingests a meeting note,
Claude extracts action items and creates tasks automatically. These tasks have
created_by = NULL, marking them as system-generated. They appear in the
dashboard with a "from meeting" label.
The LibreChat bridge monitors chat messages for action intent ("I'll handle the deployment
tomorrow", "someone needs to review the contract"). When detected, it sets
metadata.contains_action=true on the memory item, and memory-api's background
hook _maybe_create_task_from_action creates the task with created_by = NULL.
Disabled by default — enable via TASK_INTENT_DETECTION=true in your .env.
Task Fields
| Field | Type | Description |
|---|---|---|
id |
UUID | Auto-generated primary key. |
title |
string | Task title. Required. |
description |
string | null | Optional longer description or context. |
status |
enum | todo (default), in_progress, done, cancelled. |
team_scope |
string | Team this task belongs to. Hard isolation. |
project_scope |
string | null | Sub-project within the team. null means team-wide. |
assignee_id |
UUID | null | User assigned to this task. Must be a member of the same team. |
due_date |
date | null | Optional due date in ISO 8601 format. |
source |
string | Origin: manual, granola:{note_id}, or chat:{message_id}. |
created_by |
UUID | null | NULL for system-generated tasks (meeting extraction, chat detection). |
visibility |
enum | team (default), project, or private. |
confidence |
float | 0.0–1.0. Set by the extraction pipeline. |
truth_level |
enum | Defaults to WORKING. |
validation_status |
enum | pending, approved, or rejected. |
API Reference
List tasks
bashGET /v1/tasks
# All tasks for the team
curl "https://api.grooveos.app/v1/tasks" \
-H "Authorization: Bearer $JWT" \
-H "X-Team-Scope: excalibur"
# Filter by status
curl "https://api.grooveos.app/v1/tasks?status=todo&project_scope=fundraising" \
-H "Authorization: Bearer $JWT" \
-H "X-Team-Scope: excalibur"
# Poll for new tasks since a timestamp (ISO 8601)
curl "https://api.grooveos.app/v1/tasks?since=2026-05-07T12:00:00Z" \
-H "Authorization: Bearer $JWT" \
-H "X-Team-Scope: excalibur"
Query parameters
| Parameter | Type | Description |
|---|---|---|
status |
enum | Filter by status: todo, in_progress, done, cancelled. |
project_scope |
string | Filter by project. Omit for all projects. |
since |
ISO 8601 timestamp | Return only tasks created or updated after this timestamp. Use for polling. |
limit |
integer | Max results (default 50, max 200). |
offset |
integer | Pagination offset. |
Create a task
bashPOST /v1/tasks
curl -X POST "https://api.grooveos.app/v1/tasks" \
-H "Authorization: Bearer $JWT" \
-H "X-Team-Scope: excalibur" \
-H "Content-Type: application/json" \
-d '{
"title": "Send pitch deck to investor",
"description": "Use latest v3 deck from Drive",
"status": "todo",
"project_scope": "fundraising",
"due_date": "2026-05-14",
"visibility": "team",
"confidence": 1.0,
"truth_level": "WORKING",
"validation_status": "pending"
}'
Update task status
bashPATCH /v1/tasks/{task_id}
# Mark as done
curl -X PATCH "https://api.grooveos.app/v1/tasks/t1a2b3c4..." \
-H "Authorization: Bearer $JWT" \
-H "X-Team-Scope: excalibur" \
-H "Content-Type: application/json" \
-d '{"status": "done"}'
# Status changes generate a differentiated audit entry:
# task.status_changed { from: "todo", to: "done" }
Team Dashboard
The built-in task dashboard is accessible at /tasks in the
projects-dashboard service (same port as the project board). It polls the Tasks API
every 30 seconds, displays tasks grouped by status, and lets team members mark tasks
as in-progress or done without touching the API directly.
The dashboard filters tasks by the team scope associated with the logged-in user's JWT — no configuration required.
Chat-based Task Detection
The LibreChat bridge includes a task_intent_detector that analyses
outgoing chat messages for action intent. When a message contains a commitment or
action item, the bridge sets metadata.contains_action=true on the
stored memory item.
memory-api's _maybe_create_task_from_action background hook then reads
this flag and creates a task with the message content as title, created_by = NULL,
and source = "chat:{message_id}".
Opt-in with a kill-switch
Chat detection is disabled by default to avoid unintended task noise.
Enable it per deployment with TASK_INTENT_DETECTION=true.
Set it back to false to disable immediately — no restart required.
env — .env# Enable task detection from LibreChat chat messages
TASK_INTENT_DETECTION=true
# Model used for intent detection (defaults to claude-haiku for low latency)
ANTHROPIC_TASK_INTENT_MODEL=claude-haiku-4-5-20251001