1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
|
# Creating doot tasks as an agent
For a Claude instance with no access to this repo or the database. Everything goes through the
agent API on `https://doot.terst.org`.
## The one thing to know first
**A human approves every session, in a logged-in browser, and the session lasts one hour.**
There is no API key and no auto-approval — trust levels change how the prompt is labelled, not
whether it appears. Ask for a session when you are ready to use it, not at the start of a long
task, because the approval request itself expires in **5 minutes**.
## Getting a session
```bash
# 1. Ask. `name` is shown to the human approving; make it say who you are.
curl -sX POST https://doot.terst.org/agent/auth/request \
-H 'Content-Type: application/json' \
-d '{"name":"Claude (groceries)","agent_id":"claude-cli-1"}'
# -> {"request_token":"...","status":"pending"}
# 2. The human approves in the browser. Tell them to expect it.
# 3. Poll until it flips. Statuses: pending, approved, denied, expired.
curl -s "https://doot.terst.org/agent/auth/poll?token=$REQUEST_TOKEN"
# -> {"status":"approved","session_token":"...","expires_at":"..."}
```
Send the session token on every later call as `Authorization: Bearer <session_token>`. On a
401, the hour is up: request a new session rather than retrying.
## Creating a task
```bash
curl -sX POST https://doot.terst.org/agent/tasks \
-H "Authorization: Bearer $SESSION_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"title":"Renew the boat registration","source":"doot","due_date":"2026-11-20T00:00:00Z","priority":2}'
# -> {"status":"success"}
```
`title` and `source` are required. `source` is either:
- **`doot`** — a native task. Takes `due_date`, `priority`, `project_id`.
- **`trello`** — a Trello card. **Requires `list_id`**; `project_id` and `priority` are ignored.
`priority` defaults to 1 when omitted or 0. `due_date` is RFC 3339, or omit it for no due date.
### What this endpoint will not do
These fields exist on a doot task and **cannot be set here**. They are not rejected — they are
silently ignored, so a task created with them arrives without them:
- `description`
- `labels`
- `estimated_minutes`
- `project_name` (use `project_id`)
If a task needs any of those, create it and tell the human it needs editing, or use the web UI.
The response is `{"status":"success"}` with **no task id**, so you cannot chain a create into an
update. Read the task back from `/agent/context` if you need its id.
## Seeing what is already there
```bash
curl -s https://doot.terst.org/agent/context -H "Authorization: Bearer $SESSION_TOKEN"
```
Do this before creating anything. doot pulls from several sources and a task that looks missing
is often already there under a different wording.
## The other write operations
| | |
|---|---|
| `POST /agent/tasks/{id}/complete` | mark done |
| `POST /agent/tasks/{id}/uncomplete` | undo that |
| `PATCH /agent/tasks/{id}/due` | change the due date only |
| `PATCH /agent/tasks/{id}` | change the task |
| `POST /agent/shopping` | `{"name":..., "store":...}`, both required |
## If you only have a browser
`GET /agent/web/request`, `/agent/web/status` and `/agent/web/context` are the same flow in
HTML, for agents that cannot POST. They are read-only — there is no browser path that creates a
task.
## Errors
Plain text with the status, not JSON. `400` means the body was wrong (most often a missing
`title`, `source`, or `list_id` on a Trello task); `401` means the session expired; `500` means
doot accepted the request and failed to carry it out, so check before retrying — it may have
half-succeeded.
|