AgenticTodo

A human + AI co-working app for managing projects, tasks, and discussions.

AgenticTodo is designed for humans and AI agents to collaborate on task management. It provides a structured workflow system where both parties can create tasks, ask questions, make decisions, and track progress together.

Key Features

URLs

ServiceURL
App (Frontend)agentictodo.pages.dev
API (Backend)agentictodo-api.stefan-02a.workers.dev
Docsdocs-agentictodo.pages.dev

Tech Stack

LayerTechnology
FrontendReact + TypeScript + Vite + shadcn/ui + TailwindCSS
BackendCloudflare Workers + Hono
DatabaseNeon Postgres + Drizzle ORM
AuthBetter Auth (email/password)
HostingCloudflare Pages (frontend) + Workers (API)
Docs StorageCloudflare R2 (agentictodo-docs bucket)

Architecture

How the pieces fit together.

Frontend

React single-page application hosted on Cloudflare Pages. Auto-deploys from GitHub on push to main. Uses Vite for builds and shadcn/ui component library with TailwindCSS.

Backend

A Cloudflare Worker running Hono as the HTTP framework. Connects to Neon Postgres (serverless Postgres) via Drizzle ORM. Handles both user auth routes and the Agent API.

Database

Neon serverless Postgres. The schema uses cw_* prefixed tables (co-working) as the active system. Legacy tasks and projects tables exist but are deprecated — fully migrated to the unified cw_* tables.

Authentication

Better Auth with email/password. No Supabase — fully migrated to Neon + Better Auth. Bearer tokens stored in localStorage for cross-origin compatibility.

Docs Storage

An R2 bucket (agentictodo-docs) stores workspace documentation. Synced every 30 minutes from the local workspace. Accessible via the Agent API.

Data Flow

Browser (React SPA)
    ↓ HTTPS
Cloudflare Pages → Cloudflare Worker (Hono API)
                        ↓ TCP/HTTP
                   Neon Postgres
                        
Agent (AI/Bot)
    ↓ HTTPS + X-API-Key
Cloudflare Worker (Hono API)
    ↓
Neon Postgres

Authentication

How users and agents authenticate.

User Authentication (Better Auth)

Human users authenticate via email/password using Better Auth. The frontend stores the bearer token in localStorage for cross-origin compatibility.

Sign Up

POST /api/auth/sign-up/email
Content-Type: application/json

{
  "email": "user@example.com",
  "password": "your-password",
  "name": "Your Name"
}

Sign In

POST /api/auth/sign-in/email
Content-Type: application/json

{
  "email": "user@example.com",
  "password": "your-password"
}

Agent Authentication (API Keys)

AI agents and automation tools use API keys (prefixed with ak_). Keys are created in the app UI under the Agents section, with granular permissions.

Authorization: Bearer ak_your-api-key-here

Agent Permissions

PermissionDescription
read_tasksView tasks
create_tasksCreate new tasks
update_tasksUpdate existing tasks
delete_tasksDelete tasks
read_projectsView projects
create_projectsCreate projects
update_projectsUpdate projects
delete_projectsDelete projects
read_tagsView tags
create_tagsCreate tags
read_meetingsView meetings
create_meetingsCreate meetings

Core Concepts

The building blocks of AgenticTodo.

Projects

Containers for tasks. Each project has a name, color, status (active/archived), and owner. Projects group related work together and provide board views for task management.

Tasks

The fundamental unit of work. Tasks operate in one of two modes:

Tasks also have a priority (critical, high, medium, low) and an assignee (a person or "both").

Action Statuses

A second dimension on tasks indicating what needs to happen right now. This drives the Queue system.

StatusMeaning
readyReady to work on — no blockers
needs_specNeeds specification/objective before work can begin
needs_approvalWaiting for approval from someone
has_questionHas an open question that needs answering
needs_clarificationNeeds clarification on requirements
question_answeredA question was answered — review the answer
clarifiedClarification was provided — continue work
needs_reviewWork is done, needs review
needs_changesReview complete, changes requested
info_requestedAdditional information was requested

Subtasks

First-class tasks with a parent_task_id. They appear on the board with a parent link badge and inherit the project from their parent. In pipeline mode, subtask completion gates the parent task's progression.

Recurring Tasks

Templates that automatically generate task instances. A cron job runs at 6 AM Vienna time daily. Types:

Ephemeral recurring tasks auto-delete uncompleted instances from previous days.

Tags

Colored labels that can be attached to tasks for categorization and filtering.

Meetings

Scheduled blocks with a date, start time, and end time. Used for planning and calendar integration.

Agents

API keys with granular permissions for AI and automation access. Each agent has an owner, a set of permissions, and activity logging.

Pipeline Flow

The 7-column gated workflow for structured task management.

Pipeline mode enforces a disciplined progression through seven stages. Each transition has gate validation — you can't skip ahead without meeting the requirements.

Unplanned
New ideas land here
Breaking Down
Specifying & decomposing
Planned
Ready with subtasks
In Progress
Active work
Review
All subtasks done
Follow-Up
Final report submitted
Done
Complete ✓

Gate Requirements

Unplanned → Breaking Down

The task must have:

Use the POST /api/agent/tasks/:id/specify endpoint or fill these fields in the UI.

Breaking Down → Planned

The task must have at least one subtask. Use POST /api/agent/tasks/:id/breakdown to create subtasks and auto-advance.

Planned → In Progress

At least one subtask must be completed. This ensures work has actually started before the parent moves to "in progress".

In Progress → Review

All subtasks must be done or marked obsolete. No incomplete subtasks allowed.

Review → Follow-Up

A final report must be submitted via POST /api/agent/tasks/:id/final-report. The report must confirm that all spec criteria are met (via metadata specMet: true).

Follow-Up → Done

Requires explicit confirmation:

Mode Conversion

Tasks can be converted between simple and pipeline mode using POST /api/agent/tasks/:id/convert. Converting resets the status to the default for the new mode.

Queue System

Smart prioritized view of what needs attention.

The Queue is the default landing page. It shows all non-done tasks assigned to a person, sorted by urgency. You can view any person's queue.

Sorting Priority

Tasks are sorted by action status priority first, then task priority, then age:

PriorityAction StatusWhy it's urgent
1has_questionSomeone is blocked waiting for your answer
2needs_approvalWork is paused pending your approval
3needs_reviewCompleted work needs your review
4needs_clarificationRequirements need clarifying
5question_answeredYour question was answered — check it
6clarifiedClarification provided — continue
7needs_changesChanges requested after review
8readyReady to work on
9needs_specNeeds specification
10info_requestedInfo was requested

Queue Tabs

Discussion Threads

Structured communication on tasks.

Each task has a discussion thread with typed entries. The type determines behavior:

TypeBehavior
commentGeneral discussion — no side effects
questionSets task action status to has_question, auto-assigns to the other person
answerMarks parent question as answered, assigns back to question author. Sets action status to question_answered
decisionRecords a decision made on the task
status_changeSystem-generated when status changes
systemSystem-generated entries

Auto-Assignment Flow

  1. Stefan posts a question → task assigns to Cleo with status has_question
  2. Cleo posts an answer → task assigns back to Stefan with status question_answered
  3. When all questions are resolved → action status returns to ready

Agent API Overview

REST API for AI agents and automation.

Base URL

https://agentictodo-api.stefan-02a.workers.dev/api/agent

Authentication

Authorization: Bearer ak_your-api-key-here

API keys are created in the app UI. They start with ak_ and are hashed (SHA-256) server-side.

Response Format

All responses follow this shape:

// Success
{ "success": true, "data": { ... } }

// Error
{ "success": false, "error": "Error message" }

Endpoint Summary

ResourceEndpoints
ProjectsGET/POST /projects, GET/PUT/DELETE /projects/:id, GET/POST /projects/:id/tasks
TasksGET/POST /tasks, GET/PUT/DELETE /tasks/:id, POST /tasks/:id/move
Pipeline OpsPOST /tasks/:id/specify, /breakdown, /pickup, /complete, /block, /final-report, /follow-up
ThreadGET/POST /tasks/:taskId/thread, PATCH /tasks/:taskId/thread/:entryId
QueueGET /queue, GET /queue/counts
RecurringGET/POST /recurring-tasks, GET/PUT/DELETE /recurring-tasks/:id, POST /recurring-tasks/generate
TagsGET/POST/PUT/DELETE via legacy resource API
DocsGET /docs/tree, GET /docs/content/*

Projects API

Manage projects and their tasks.

GET /projects

List projects. Defaults to active projects.

Query ParamDescription
statusFilter by status (default: active)
owner_idFilter by owner ID

Response includes taskCounts — an object mapping status → count.

POST /projects

Create a new project.

{
  "name": "My Project",         // required
  "description": "Optional",
  "color": "#22c55e",           // default: green
  "owner_id": "user-uuid"      // default: authenticated user
}

GET /projects/:id

Get project details with task counts.

PUT /projects/:id

Update a project.

{
  "name": "New Name",
  "description": "Updated",
  "status": "active",
  "color": "#3b82f6",
  "owner_id": "user-uuid"
}

DELETE /projects/:id

Archive a project (sets status to archived).

GET /projects/:id/tasks

Get all tasks for a project, structured as a tree with nested subtasks. Each task includes an activityCount.

POST /projects/:id/tasks

Create a task in a project.

{
  "title": "Task title",          // required
  "description": "Optional",
  "priority": "medium",           // critical, high, medium, low
  "assignee": "cleo",             // or "stefan", "both", "unassigned"
  "parent_task_id": "uuid",       // for subtasks
  "status": "unplanned",          // default for pipeline mode
  "deadline": "2024-12-31",
  "target_date": "2024-12-25",
  "scheduled_date": "2024-12-20",
  "scheduled_start_time": "09:00",
  "scheduled_end_time": "17:00",
  "tag_ids": ["tag-uuid-1"]
}

GET /projects/:id/activity

Get recent activity for a project (last 50 entries).

Tasks API

CRUD operations on tasks.

GET /tasks

List tasks with filters.

Query ParamDescription
statusFilter by status
modeFilter by mode (simple or pipeline)
assigneeFilter by assignee name
project_idFilter by project
scheduled_dateFilter by scheduled date (YYYY-MM-DD)
deadline_beforeTasks with deadline before this date
todaySet to true to get tasks scheduled or due today

Response includes tags array on each task.

POST /tasks

Create a task (not tied to a project, or specify project_id).

{
  "title": "Task title",             // required
  "project_id": "uuid",
  "parent_task_id": "uuid",
  "description": "Details",
  "priority": "medium",
  "assignee": "cleo",
  "mode": "pipeline",                // default: pipeline
  "status": "unplanned",
  "action_status": "needs_spec",
  "deadline": "2024-12-31",
  "target_date": "2024-12-25",
  "scheduled_date": "2024-12-20",
  "objective": "What to achieve",
  "acceptance_criteria": "How to verify",
  "definition_of_done": "What done looks like",
  "tag_ids": ["tag-uuid"]
}

GET /tasks/:id

Get task details including subtasks, recent activity (last 20), and tags.

PUT /tasks/:id

Update a task. Any field from create can be updated. Pass tag_ids to replace all tags.

DELETE /tasks/:id

Delete a task and all its subtasks + activity.

POST /tasks/:id/move

Move a task to a new status with pipeline gate validation.

{
  "status": "breaking_down",
  "position": 0,                      // optional: reorder
  "completionNote": "Done!",          // optional: for subtask completion
  "followUpConfirmed": true,          // required for follow_up → done
  "noFollowUpNeeded": true            // or followUpTasksCreated: true
}

GET /tasks/:id/activity

Get all activity entries for a task.

POST /tasks/:id/activity

Add an activity entry to a task.

{
  "type": "comment",        // comment, question, result, specification, etc.
  "content": "Activity text",
  "author": "cleo",         // optional, defaults to authenticated user
  "metadata": {}            // optional
}

Pipeline Operations

Convenience endpoints for pipeline workflow actions.

POST /tasks/:id/specify

Set objective and move to breaking_down.

{
  "objective": "What we're building",       // required
  "acceptance_criteria": "How to verify",
  "definition_of_done": "What done means"
}

POST /tasks/:id/breakdown

Create subtasks and auto-advance to planned.

{
  "subtasks": [
    { "title": "Subtask 1", "description": "Details", "priority": "high", "assignee": "cleo" },
    { "title": "Subtask 2" }
  ]
}

Returns { task, subtasks }.

POST /tasks/:id/pickup

Pick up a task — sets status to in_progress and assignee to cleo.

POST /tasks/:id/complete

Mark task as done with a completion note.

{
  "content": "Task completed successfully",
  "metadata": {}
}

POST /tasks/:id/complete-subtask

Complete a subtask with a note. Auto-adds activity to both subtask and parent.

{
  "completionNote": "Implemented the feature"   // required
}

POST /tasks/:id/block

Block a task with a reason.

{
  "content": "Waiting for API access",
  "metadata": {}
}

POST /tasks/:id/final-report

Submit final report and move to follow_up.

{
  "content": "Summary of what was done...",   // required
  "metadata": { "specMet": true }             // required for gate validation
}

POST /tasks/:id/follow-up

Complete follow-up and move to done. Optionally create follow-up tasks.

{
  "tasks": [
    { "title": "Follow-up item", "priority": "medium", "assignee": "stefan" }
  ]
}

Returns { task, followUpTasks }.

POST /tasks/:id/convert

Convert between simple and pipeline mode.

{
  "mode": "pipeline"   // or "simple"
}

Thread Entries API

Discussion threads on tasks.

Note: Thread endpoints use the /api/tasks prefix (not /api/agent). They require user authentication (Bearer token), not agent API keys.

GET /api/tasks/:taskId/thread

Get all thread entries for a task, ordered by creation date. Includes author name.

POST /api/tasks/:taskId/thread

Add a thread entry.

{
  "type": "question",          // comment, question, answer, decision
  "content": "How should this work?",
  "parentEntryId": "uuid",    // required for answers (references the question)
  "isBlocking": false,
  "metadata": {}
}

Side effects:

PATCH /api/tasks/:taskId/thread/:entryId

Update a thread entry.

{
  "content": "Updated text",
  "questionStatus": "resolved"   // open, answered, resolved
}

Resolving the last open question resets the task action status to ready.

Queue API

Prioritized task views per person.

GET /queue

Get the current user's queue — all non-done tasks sorted by urgency.

Query ParamDescription
viewcleo, stefan, or both — view another person's queue

Each task in the response includes:

GET /queue/counts

Get badge counts for navigation — counts per action status plus totals.

// Response
{
  "success": true,
  "data": {
    "has_question": 3,
    "needs_approval": 1,
    "ready": 5,
    "total": 4,        // actionable items only (excludes ready/needs_spec)
    "all": 9           // total tasks in queue
  }
}

Recurring Tasks API

Manage recurring task templates and generation.

GET /recurring-tasks

List all recurring task templates for the authenticated user.

POST /recurring-tasks

Create a recurring task template.

{
  "title": "Daily standup notes",       // required
  "recurrence_type": "daily",           // required: daily, weekly, monthly, yearly, custom
  "description": "Optional details",
  "priority": "medium",
  "project_id": "uuid",
  "assigned_to": "cleo",
  "recurrence_rule": {                  // depends on type
    "interval": 1                       // daily: every N days
    // weekly: { "days": ["monday", "wednesday", "friday"] }
    // monthly: { "day_of_month": 15 } or { "week_of_month": 2, "day_of_week": "monday" }
    // custom: { "interval_days": 3 }
  },
  "is_ephemeral": false,               // auto-delete uncompleted past instances
  "is_active": true,
  "start_date": "2024-01-01",
  "end_date": "2024-12-31"             // optional
}

GET /recurring-tasks/:id

Get a single recurring task template.

PUT /recurring-tasks/:id

Update a recurring task template. Same fields as create.

DELETE /recurring-tasks/:id

Delete a recurring task template.

POST /recurring-tasks/generate

Trigger generation of recurring task instances for today. Normally called by the daily cron job at 6 AM Vienna time. Also cleans up old ephemeral instances.

Requires create_tasks permission for agent API keys.

// Response
{
  "success": true,
  "message": "Generated 3 recurring task instances",
  "generated": 3,
  "fromDate": "2024-06-15",
  "toDate": "2024-06-15"
}

Tags API

Manage colored labels for tasks.

Tags use the legacy resource API pattern at /api/agent/tags. Requires read_tags / create_tags / update_tags / delete_tags permissions.

GET /tags

List all tags for the authenticated user.

POST /tags

Create a new tag.

{
  "name": "bug",
  "color": "#ef4444"
}

GET /tags/:id

Get a single tag.

PUT /tags/:id

Update a tag.

DELETE /tags/:id

Delete a tag.

Assigning Tags to Tasks

When creating or updating tasks, pass tag_ids as an array of tag UUIDs:

// On create
POST /tasks
{ "title": "Fix bug", "tag_ids": ["tag-uuid-1", "tag-uuid-2"] }

// On update (replaces all tags)
PUT /tasks/:id
{ "tag_ids": ["tag-uuid-1"] }

Docs API (R2)

Access workspace documentation stored in R2.

GET /docs/tree

List all files in the docs R2 bucket.

// Response
{
  "success": true,
  "data": [
    { "path": "README.md", "size": 1234, "updated": "2024-06-15T10:00:00Z" },
    { "path": "notes/ideas.md", "size": 567, "updated": "2024-06-14T08:00:00Z" }
  ]
}

GET /docs/content/{path}

Get the content of a specific file.

// GET /docs/content/README.md
{
  "success": true,
  "data": {
    "path": "README.md",
    "content": "# My Doc\n...",
    "size": 1234,
    "updated": "2024-06-15T10:00:00Z"
  }
}

Database Schema

All tables in the Neon Postgres database.

Important: Tables prefixed with cw_ are the active unified system. The old tasks, projects tables are legacy and deprecated.

Auth Tables (Better Auth)

TablePurpose
userUser accounts (id, name, email, image, etc.)
sessionActive sessions with tokens and expiry
accountAuth provider accounts (email/password)
verificationEmail verification tokens

User Management

TablePurpose
profilesExtended user profiles
user_rolesRole assignments for users

Unified System (Active)

TableKey Columns
cw_projectsid, name, description, color, status, owner_id, created_by
cw_tasksid, project_id, parent_task_id, title, description, status, mode, action_status, priority, assignee, objective, acceptance_criteria, definition_of_done, deadline, target_date, scheduled_date, position
cw_task_tagstask_id, tag_id (join table)
cw_thread_entriesid, task_id, author_id, type, content, parent_entry_id, question_status, is_blocking, metadata
cw_activityid, task_id, project_id, author, type, content, metadata

Shared Tables

TablePurpose
tagsColored labels (id, name, color, owner_id)
meetingsScheduled meetings (date, time, title, notes)
agentsAPI key agents (name, api_key_hash, permissions, owner_id, is_active)
agent_activity_logsAudit log of agent API actions

Recurring Tasks

TablePurpose
recurring_tasksTemplates with recurrence rules (type, rule JSON, ephemeral flag)
recurring_task_skipped_datesDates to skip generation
recurring_task_tagsTags attached to recurring templates

Legacy Tables (Deprecated)

TableNote
projectsOld project system — replaced by cw_projects
tasksOld task system — replaced by cw_tasks. Still used by recurring task generation.
task_tagsOld tag joins
task_notesOld notes system
task_attachmentsOld attachments