Project list
Returns all projects the user owns or has access to.
Responses
Successful response
projectobject · requiredA project organizes todos.
settingsobject · requireddoneCountnumber · requiredCount of todos in the DONE stage — O(1) ZCARD, kept accurate independent of what the paginated todo list has loaded. Todo count = todoIds.length - doneCount.
boardCountnumberTodos the board list (
todo.list) can actually page: shared, visible, not dismissed — any status. Optional for older backends.supportsPrivateTodosbooleanRuntime server capability, response-only (never persisted): this backend enforces
MY_PRIVATE_GROUPprivacy. Clients MUST fail closed — hide the private lane when absent — so a new frontend against an old backend can't create shared "private" todos.
Project create
Creates a new project for organizing todos.
Responses
Successful response
projectobject · requiredA project organizes todos.
settingsobject · requireddoneCountnumber · requiredCount of todos in the DONE stage — O(1) ZCARD, kept accurate independent of what the paginated todo list has loaded. Todo count = todoIds.length - doneCount.
boardCountnumberTodos the board list (
todo.list) can actually page: shared, visible, not dismissed — any status. Optional for older backends.supportsPrivateTodosbooleanRuntime server capability, response-only (never persisted): this backend enforces
MY_PRIVATE_GROUPprivacy. Clients MUST fail closed — hide the private lane when absent — so a new frontend against an old backend can't create shared "private" todos.
Project get
Returns a project with its settings.
path Parameters
projectIdstring · required
Responses
Successful response
projectobject · requiredA project organizes todos.
settingsobject · requireddoneCountnumber · requiredCount of todos in the DONE stage — O(1) ZCARD, kept accurate independent of what the paginated todo list has loaded. Todo count = todoIds.length - doneCount.
boardCountnumberTodos the board list (
todo.list) can actually page: shared, visible, not dismissed — any status. Optional for older backends.supportsPrivateTodosbooleanRuntime server capability, response-only (never persisted): this backend enforces
MY_PRIVATE_GROUPprivacy. Clients MUST fail closed — hide the private lane when absent — so a new frontend against an old backend can't create shared "private" todos.
Project share
Shares a project with another user by email.
path Parameters
projectIdstring · required
Responses
Successful response
idstring · requirednamestring · requireddescriptionstring · requiredprojectSettingsIdstring · requiredownerIdstring · requiredownerEmailstring · requiredisPublicboolean · requiredtodoIdsstring[] · requiredreadAccessIdsstring[] · requiredUser IDs with read access
writeAccessIdsstring[] · requiredUser IDs with write access
readAccessEmailsstring[] · requiredwriteAccessEmailsstring[] · requiredstatusrequiredisDefaultboolean · requiredcreatedAtnumber · requiredupdatedAtnumber · required
teamOwnerIdstringThe team this project belongs to, identified by its owner's user id. Set = a shared team project: every member of that team holds write access, and AI spend inside it is billed to that team's pool. This is the switch that decides WHOSE quota a member burns, so a project belongs to at most one team (enforced atomically in setTeamProjectAtomic).
Being replaced by
organizationId: the migration writes both, and once every reader is on organizationId this field goes away.organizationIdstringThe organization (better-auth organization plugin) this project belongs to. Same semantics as teamOwnerId — members get write access, spend bills to the org owner's pool — but keyed by the org's own id, so an org can outlive / change its owner. At most one per project.
businessContextIdstringThe project IS the brand: this is the attachment id of its brand page (markdown). Absent = a personal board (no brand card, analyzer or voice).
killSwitchobjectarchivedAtnumberdeletedAtnumber
Project unshare
Revokes a user's direct access to a project (by user id). The owner can't be removed.
path Parameters
projectIdstring · required
Responses
Successful response
idstring · requirednamestring · requireddescriptionstring · requiredprojectSettingsIdstring · requiredownerIdstring · requiredownerEmailstring · requiredisPublicboolean · requiredtodoIdsstring[] · requiredreadAccessIdsstring[] · requiredUser IDs with read access
writeAccessIdsstring[] · requiredUser IDs with write access
readAccessEmailsstring[] · requiredwriteAccessEmailsstring[] · requiredstatusrequiredisDefaultboolean · requiredcreatedAtnumber · requiredupdatedAtnumber · required
teamOwnerIdstringThe team this project belongs to, identified by its owner's user id. Set = a shared team project: every member of that team holds write access, and AI spend inside it is billed to that team's pool. This is the switch that decides WHOSE quota a member burns, so a project belongs to at most one team (enforced atomically in setTeamProjectAtomic).
Being replaced by
organizationId: the migration writes both, and once every reader is on organizationId this field goes away.organizationIdstringThe organization (better-auth organization plugin) this project belongs to. Same semantics as teamOwnerId — members get write access, spend bills to the org owner's pool — but keyed by the org's own id, so an org can outlive / change its owner. At most one per project.
businessContextIdstringThe project IS the brand: this is the attachment id of its brand page (markdown). Absent = a personal board (no brand card, analyzer or voice).
killSwitchobjectarchivedAtnumberdeletedAtnumber
Project createTodo
Creates a new todo in the project and optionally starts AI processing.
path Parameters
projectIdstring · required
Request Body
projectIdstring · requiredcontentstring · requiredagentSettingsobject · requiredAI AgentSettings configuration including model, system prompt, and MCP tools.
attachmentsobject[]scheduledTimestampnumbertodoIdstringgroupTagstringGroup slug. Empty/absent means ungrouped.
MY_PRIVATE_GROUPcreates a private todo owned by the authenticated creator (no separate visibility input).groupNamestringOptional display name to upsert for groupTag. Ignored for
MY_PRIVATE_GROUP.visiblebooleanVisible in the project's default todo list. Defaults to true; subagent runs (tfa-*) pass false. Hidden todos are still accessible by id.
autoDonebooleanWhen true, successful completion lands in DONE (strikethrough/terminal) instead of READY. For plumbing todos that don't need user ack.
parentTodoIdstringTodo whose agent shell spawned this one (tfa-cli reads $TODOFORAI_TODO_ID).
kind'orchestrator' forces visible:false and manual start (no agent run).
originHow the first message was produced (orchestrator threads).
Responses
Successful response
idstring · requiredprojectIdstring · requiredstatusrequiredagentSettingsIdstring · requiredcontentstring · requiredmessageIdsstring[] · requiredmessagesobject[] · requiredcreatedAtnumber · requiredlastActivityAtnumber · requiredscheduledTimestampnumber · required0 if immediate
groupTagstringProject-scoped group slug.
privateOwnerIdstringSet (server-side, from the creator) when the todo lives in
MY_PRIVATE_GROUP: only this user may read or modify it. Never accepted from clients.parentTodoIdstringTodo whose agent shell spawned this one (via tfa-cli).
kind'orchestrator': a per-tab orchestrator thread — the tab runs the agent loop itself and authors the assistant turns over the frontend socket. Always created with visible:false (off the board); listed via todo.listOrchestrators.
systemMessageIdstringcheckedBlockIdsstring[]User-checked blocks
actionableBlockIdsstring[]Blocks with code, commands, etc.
archivedAtnumberdeletedAtnumberdismissedAtnumberWhen the proposal was dismissed — bounds the analyzer's feedback window.
starredAtnumberStar/favorite timestamp; absent/0 = not starred
contributorIdsstring[]Users who sent messages into the todo, in order of first appearance ([0] = creator).
workflowVersionstringFor optimistic concurrency
visiblebooleanVisible in default project listings; defaults to true.
isPublicbooleanPublicly viewable (read-only) by anyone with the link, no login required.
commentsEnabledbooleanSigned-in non-members may comment on a public todo. Members can always comment.
autoDonebooleanPre-finished: the user checked it while the agent was still working, so the run's READY lands as DONE. Cleared once the todo reaches a terminal status.
statusRevnumberPer-todo transition counter at
status— travels WITH it, so a client knows which transition it holds.hasMoreMessagesbooleanTrue when
messagesholds only the newest page — older ones via todo.getMessages.importSourceobjectProvenance of an imported todo (see ImportSessionInput.source).
Project groups
Lists project todo groups, including empty groups.
path Parameters
projectIdstring · required
Responses
Successful response
slugstring · requirednamestring · required
descriptionstringOne-line strategic intent of the group — shown on the card and fed to the semantic router so future todos/recommendations land here.
pinnedbooleanPinned cards sort first on the wall.
archivedbooleanArchived cards leave the wall (still listed here so the picker can offer them).
ordernumberExplicit wall position (ascending). Unset groups trail in listing (creation) order.
totalnumberTodos in this group (ZCARD of the group index) — accurate regardless of what the paginated list loaded.
Project upsertGroup
Creates or renames a project todo group.
path Parameters
projectIdstring · requiredslugstring · required
Request Body
projectIdstring · requiredslugstring · required
namestringdescriptionstringOne-line strategic intent; empty string clears it, omitted = unchanged.
pinnedbooleanToggle pinned; omitted = unchanged.
archivedbooleanToggle archived; omitted = unchanged.
ordernumberExplicit wall position; omitted = unchanged.
Responses
Successful response
slugstring · requirednamestring · required
descriptionstringOne-line strategic intent of the group — shown on the card and fed to the semantic router so future todos/recommendations land here.
pinnedbooleanPinned cards sort first on the wall.
archivedbooleanArchived cards leave the wall (still listed here so the picker can offer them).
ordernumberExplicit wall position (ascending). Unset groups trail in listing (creation) order.
totalnumberTodos in this group (ZCARD of the group index) — accurate regardless of what the paginated list loaded.
Project surfaces
Lists the project's card surfaces — refs shown on the board as cards or group preview tiles.
path Parameters
projectIdstring · required
Responses
Successful response
idstring · requiredrefstring · requiredcreatedAtnumber · required
titlestringgroupstringGroup slug it renders inside; absent = its own wall card.
ordernumberWall / tile position (ascending); unset trails in creation order.
Project upsertSurface
Creates or updates a card surface: a ref (todo,
path Parameters
projectIdstring · requiredsurfaceIdstring · required
Request Body
projectIdstring · requiredsurfaceIdstring · requiredClient-chosen id (like a group slug): unknown creates, known patches (omitted = unchanged).
refstringRequired on create.
titlestringEmpty string clears.
groupstringEmpty string detaches it into its own wall card.
ordernumber
Responses
Successful response
idstring · requiredrefstring · requiredcreatedAtnumber · required
titlestringgroupstringGroup slug it renders inside; absent = its own wall card.
ordernumberWall / tile position (ascending); unset trails in creation order.
Project pressKillSwitch
Stops every running todo in scope now and blocks new starts until released. scope=user: your own runs; scope=project: everyone (owner only).
path Parameters
projectIdstring · required
Responses
Successful response
scoperequiredbystring · requiredatnumber · required
autoconstLatch tripped by the running limit rather than by a person.
Const value:
Project startFromTemplate
Start a TODO from a spec (with optional overrides) or from scratch — THE single accept path (start(spec) -> Todo). With propose: true the todo is created as PROPOSED (an analyzer suggestion the user accepts or dismisses) instead of starting.
path Parameters
projectIdstring · required
Request Body
projectIdstring · requiredProject to create the TODO in
specIdstringOptional spec ID — if provided, the spec is the base
proposebooleanCreate as a PROPOSED todo (analyzer suggestion): first message queued like a draft, not yours until accepted (Start) or dismissed. Requires specId.
notestringWhy this is proposed — folded into the todo content as a "Why this matters" line (propose only; no dedicated field on the todo).
titlestringProposal title override — becomes the content's first line, i.e. the ✧ row title (propose only; defaults to the spec name).
priorityProposal priority — folded into the content's "Why this matters" line when not medium (propose only).
groupDescriptionstringOne-line strategic intent to upsert for groupTag (propose only).
contentstringUser message / TODO content. Falls back to spec name+description if omitted
systemMessagestringSystem message override. If omitted and specId provided, uses the spec's body
agentNamestringAgent name for on-the-fly TODOs (no specId). Defaults to "Custom Agent"
modelstringComposer model pick for this run only (session override) — the agent keeps its own.
thinkingLevelscheduledTimestampnumberScheduling: omit for immediate start
attachmentsobject[]Attachments
groupTagstringGroup slug. Empty/absent means ungrouped.
groupNamestringOptional display name to upsert for groupTag.
autoDonebooleanPer-run: successful completion lands in DONE instead of READY (see CreateTodoInput).
Responses
Successful response
idstring · requiredprojectIdstring · requiredstatusrequiredagentSettingsIdstring · requiredcontentstring · requiredmessageIdsstring[] · requiredmessagesobject[] · requiredcreatedAtnumber · requiredlastActivityAtnumber · requiredscheduledTimestampnumber · required0 if immediate
groupTagstringProject-scoped group slug.
privateOwnerIdstringSet (server-side, from the creator) when the todo lives in
MY_PRIVATE_GROUP: only this user may read or modify it. Never accepted from clients.parentTodoIdstringTodo whose agent shell spawned this one (via tfa-cli).
kind'orchestrator': a per-tab orchestrator thread — the tab runs the agent loop itself and authors the assistant turns over the frontend socket. Always created with visible:false (off the board); listed via todo.listOrchestrators.
systemMessageIdstringcheckedBlockIdsstring[]User-checked blocks
actionableBlockIdsstring[]Blocks with code, commands, etc.
archivedAtnumberdeletedAtnumberdismissedAtnumberWhen the proposal was dismissed — bounds the analyzer's feedback window.
starredAtnumberStar/favorite timestamp; absent/0 = not starred
contributorIdsstring[]Users who sent messages into the todo, in order of first appearance ([0] = creator).
workflowVersionstringFor optimistic concurrency
visiblebooleanVisible in default project listings; defaults to true.
isPublicbooleanPublicly viewable (read-only) by anyone with the link, no login required.
commentsEnabledbooleanSigned-in non-members may comment on a public todo. Members can always comment.
autoDonebooleanPre-finished: the user checked it while the agent was still working, so the run's READY lands as DONE. Cleared once the todo reaches a terminal status.
statusRevnumberPer-todo transition counter at
status— travels WITH it, so a client knows which transition it holds.hasMoreMessagesbooleanTrue when
messagesholds only the newest page — older ones via todo.getMessages.importSourceobjectProvenance of an imported todo (see ImportSessionInput.source).