Skip to content

Service API

The WackyTracky backend exposes a Connect RPC API. The web app uses this API for all operations (lists, tasks, search, metadata, and more). You can call it from scripts, other applications, or a CLI using HTTP and JSON.

Base URL

When the server is running (e.g. on port 8080), the API base URL is:

http://<host>:<port>/api

Example: http://localhost:8080/api

Each RPC has a procedure path under this base. The full URL for a procedure is:

<base>/wackytracky.clientapi.v1.WackyTrackyClientService/<MethodName>

Example: http://localhost:8080/api/wackytracky.clientapi.v1.WackyTrackyClientService/GetLists

Protocol

The service uses the Connect protocol (HTTP/JSON):

  • Method: POST
  • Request: Content-Type: application/json, body is a JSON object with the request message fields (empty {} for empty requests).
  • Response: Content-Type: application/json, body is a JSON object with the response message fields.
  • Errors: On failure, the server returns an appropriate HTTP status (e.g. 4xx/5xx) and a Connect error payload in JSON.

If your deployment uses HTTP authentication (e.g. the optional httpauthshim integration), include credentials in your requests (e.g. Authorization: Basic ... for Basic auth).

Quick start

Version (no arguments)

curl -s -X POST 'http://localhost:8080/api/wackytracky.clientapi.v1.WackyTrackyClientService/Version' \
  -H "Content-Type: application/json" \
  -d '{}'

Example response:

{"version":"1.9.0","commit":"abc123","date":"2025-01-15T12:00:00Z"}

Get lists

curl -s -X POST 'http://localhost:8080/api/wackytracky.clientapi.v1.WackyTrackyClientService/GetLists' \
  -H "Content-Type: application/json" \
  -d '{}'

Example response:

{"lists":[{"id":"list-id-1","title":"Inbox","countItems":5}]}

Create a task

curl -s -X POST 'http://localhost:8080/api/wackytracky.clientapi.v1.WackyTrackyClientService/CreateTask' \
  -H "Content-Type: application/json" \
  -d '{"content":"Buy milk #errands @home","parentListId":"<list-id>"}'

Use the list ID from GetLists. Omit parentListId to use the default list (implementation-dependent). Use parentTaskId to create a subtask.

Search tasks

curl -s -X POST 'http://localhost:8080/api/wackytracky.clientapi.v1.WackyTrackyClientService/SearchTasks' \
  -H "Content-Type: application/json" \
  -d '{"query":"#work -#done"}'

Query syntax is backend-dependent; the todo.txt backend supports plain terms, #tag, @context, and -term to exclude. See Search (SearchTasks) for details.

Mark a task done

curl -s -X POST 'http://localhost:8080/api/wackytracky.clientapi.v1.WackyTrackyClientService/DoneTask' \
  -H "Content-Type: application/json" \
  -d '{"id":"<task-id>"}'

Task IDs come from ListTasks or SearchTasks responses.

Reference

The full list of RPCs and request/response message types is in the API reference.

Machine-readable spec (OpenAPI)

A generated OpenAPI 3.1 description of every procedure and message is available at openapi.yaml. When the server is running, the same spec is also served at GET /openapi on your instance (e.g. http://localhost:8080/openapi). It is produced from the Protocol Buffers definition, so it always matches the running API. Use it to:

  • Feed the API to tools like Swagger UI, Redoc, or Postman.
  • Let an LLM or code generator discover endpoints, request/response shapes, and field types without reading prose.

Regenerate it with make in the protocol/ directory.

LLM discovery (llms.txt)

Running servers expose GET /llms.txt (e.g. http://localhost:8080/llms.txt) with a short guide for LLMs and automation: where to find the OpenAPI spec, how to call the HTTP API, and how to use the MCP server.

MCP server (for LLM assistants)

To let an LLM assistant (Claude Desktop, Cursor, etc.) read and manage your tasks directly, WackyTracky exposes an MCP server. When the HTTP server is running, connect at /mcp (Streamable HTTP). For local subprocess clients, use wt mcp over stdio.

Code generation

The API is defined with Protocol Buffers in protocol/wacky-tracky/clientapi/v1/wt.proto. You can generate client code using:

The web frontend uses the generated Connect-Web client; the Go server implements the same service.