{"openapi":"3.1.0","info":{"title":"Maintenance Due","version":"0.1.0","description":"AI-native due engine and append-only service log. One API tree: JSON writes on /api/v1; agent reads on /api/v1/agent/* (text/plain). The personal bearer token is the tenant. Never invent intervals. JSON is not legacy."},"servers":[{"url":"/","description":"This origin"}],"tags":[{"name":"public","description":"No auth. Humans and agents."},{"name":"bootstrap","description":"Mint a personal token (creates the tenant)."},{"name":"write","description":"JSON writes under /api/v1. Auth required."},{"name":"agent","description":"Agent reads: Markdown as text/plain under /api/v1/agent."},{"name":"read","description":"JSON GET companions on the same /api/v1 tree."}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"Token from POST /api/v1/bootstrap. The token is the tenant. Do not send userId."}},"schemas":{"Error":{"type":"object","required":["code","message","retryable"],"properties":{"code":{"type":"string"},"message":{"type":"string"},"retryable":{"type":"boolean"},"hint":{"type":"string"}}},"Expr":{"description":"calendar | meter | or | and. OR is left-to-right, first hit wins. Nesting allowed.","type":"object"}}},"paths":{"/":{"get":{"tags":["public"],"summary":"Agent-addressed homepage with copy-paste Muse/Cursor prompt","responses":{"200":{"description":"text/html"}}}},"/health":{"get":{"tags":["public"],"summary":"Liveness","responses":{"200":{"description":"ok"}}}},"/llms.txt":{"get":{"tags":["public"],"summary":"Agent index","responses":{"200":{"description":"text/plain"}}}},"/AGENT_PROMPT.md":{"get":{"tags":["public"],"summary":"Copy-paste operating prompt","responses":{"200":{"description":"text/markdown"}}}},"/skill.md":{"get":{"tags":["public"],"summary":"Muse coach skill","responses":{"200":{"description":"text/markdown"}}}},"/muse/skill.md":{"get":{"tags":["public"],"summary":"Same skill (Muse connector path)","responses":{"200":{"description":"text/markdown"}}}},"/openapi.json":{"get":{"tags":["public"],"summary":"This OpenAPI document","responses":{"200":{"description":"application/json"}}}},"/api/openapi.json":{"get":{"tags":["public"],"summary":"Same OpenAPI document","responses":{"200":{"description":"application/json"}}}},"/mcp":{"get":{"tags":["public"],"summary":"Reserved Streamable HTTP MCP slot (stub, stateless)","responses":{"200":{"description":"text/plain reservation note"}}},"post":{"tags":["public"],"summary":"Reserved Streamable HTTP MCP slot (stub, stateless)","responses":{"200":{"description":"text/plain reservation note"}}}},"/api/v1/bootstrap":{"post":{"tags":["bootstrap"],"summary":"Mint account + personal token","description":"No Authorization. Rate-limited with Retry-After. Optional JSON { seed: true } creates Truck A with oil-change 5000 miles OR 200 engine hours. Token plaintext is returned once. Wrong later bearer does not mint a second account.","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"seed":{"type":["boolean","string"]}}}}}},"responses":{"201":{"description":"token, account_id, optional seed ids"},"429":{"description":"rate_limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/accounts":{"post":{"tags":["bootstrap"],"summary":"Alias of /api/v1/bootstrap","responses":{"201":{"description":"same as bootstrap"}}}},"/api/v1":{"get":{"tags":["read"],"security":[{"bearerAuth":[]}],"summary":"JSON pointer: write vs agent-read split","responses":{"200":{"description":"application/json"}}}},"/api/v1/agent":{"get":{"tags":["agent"],"security":[{"bearerAuth":[]}],"summary":"Agent catalog (text/plain Markdown)","responses":{"200":{"description":"text/plain"}}}},"/api/v1/agent/due":{"get":{"tags":["agent"],"security":[{"bearerAuth":[]}],"summary":"Due list for agents (text/plain)","responses":{"200":{"description":"text/plain"}}}},"/api/v1/agent/things/{id}":{"get":{"tags":["agent"],"security":[{"bearerAuth":[]}],"summary":"Thing history for agents (text/plain)","responses":{"200":{"description":"text/plain"}}}},"/api/v1/agent/things/{id}/due":{"get":{"tags":["agent"],"security":[{"bearerAuth":[]}],"summary":"Thing due list for agents (text/plain)","responses":{"200":{"description":"text/plain"}}}},"/api/v1/agent/things/{id}/history":{"get":{"tags":["agent"],"security":[{"bearerAuth":[]}],"summary":"Thing history alias (text/plain)","responses":{"200":{"description":"text/plain"}}}},"/api/v1/me":{"get":{"tags":["read"],"security":[{"bearerAuth":[]}],"summary":"Account id for this token (do not send it later)","responses":{"200":{"description":"account_id"}}}},"/api/v1/things":{"get":{"tags":["read"],"security":[{"bearerAuth":[]}],"summary":"List things","responses":{"200":{"description":"things[]"}}},"post":{"tags":["write"],"security":[{"bearerAuth":[]}],"summary":"Create a thing","responses":{"201":{"description":"thing"}}}},"/api/v1/things/{id}":{"get":{"tags":["read"],"security":[{"bearerAuth":[]}],"summary":"Get thing","responses":{"200":{"description":"thing"}}},"patch":{"tags":["write"],"security":[{"bearerAuth":[]}],"summary":"Update thing metadata","responses":{"200":{"description":"thing"}}},"delete":{"tags":["write"],"security":[{"bearerAuth":[]}],"summary":"Delete if no log rows","responses":{"200":{"description":"deleted"},"409":{"description":"append_only","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/things/{id}/services":{"get":{"tags":["read"],"security":[{"bearerAuth":[]}],"summary":"List services","responses":{"200":{"description":"services[]"}}},"post":{"tags":["write"],"security":[{"bearerAuth":[]}],"summary":"Create service (optional rule)","responses":{"201":{"description":"service"}}}},"/api/v1/services/{id}":{"get":{"tags":["read"],"security":[{"bearerAuth":[]}],"summary":"Get service + rule","responses":{"200":{"description":"service"}}},"patch":{"tags":["write"],"security":[{"bearerAuth":[]}],"summary":"Update service metadata","responses":{"200":{"description":"service"}}},"delete":{"tags":["write"],"security":[{"bearerAuth":[]}],"summary":"Delete if no events","responses":{"409":{"description":"append_only","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/services/{id}/rule":{"get":{"tags":["read"],"security":[{"bearerAuth":[]}],"summary":"Get rule","responses":{"200":{"description":"rule"}}},"put":{"tags":["write"],"security":[{"bearerAuth":[]}],"summary":"Create or replace explicit expression","responses":{"200":{"description":"rule"}}},"delete":{"tags":["write"],"security":[{"bearerAuth":[]}],"summary":"Remove rule","responses":{"200":{"description":"deleted"}}}},"/api/v1/things/{id}/readings":{"get":{"tags":["read"],"security":[{"bearerAuth":[]}],"summary":"List readings (append-only)","responses":{"200":{"description":"readings[]"}}},"post":{"tags":["write"],"security":[{"bearerAuth":[]}],"summary":"Append a meter reading","responses":{"201":{"description":"reading"}}}},"/api/v1/things/{id}/readings/{rid}":{"patch":{"tags":["write"],"security":[{"bearerAuth":[]}],"summary":"Forbidden — readings are append-only","responses":{"405":{"description":"append_only","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"put":{"tags":["write"],"security":[{"bearerAuth":[]}],"summary":"Forbidden — readings are append-only","responses":{"405":{"description":"append_only","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"tags":["write"],"security":[{"bearerAuth":[]}],"summary":"Forbidden — readings are append-only","responses":{"405":{"description":"append_only","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/services/{id}/events":{"get":{"tags":["read"],"security":[{"bearerAuth":[]}],"summary":"List completions","responses":{"200":{"description":"events[]"}}},"post":{"tags":["write"],"security":[{"bearerAuth":[]}],"summary":"Append a completion (resets last-done)","responses":{"201":{"description":"event"}}}},"/api/v1/services/{id}/events/{eid}":{"patch":{"tags":["write"],"security":[{"bearerAuth":[]}],"summary":"Forbidden — events are append-only","responses":{"405":{"description":"append_only","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"put":{"tags":["write"],"security":[{"bearerAuth":[]}],"summary":"Forbidden — events are append-only","responses":{"405":{"description":"append_only","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"tags":["write"],"security":[{"bearerAuth":[]}],"summary":"Forbidden — events are append-only","responses":{"405":{"description":"append_only","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/due":{"get":{"tags":["read"],"security":[{"bearerAuth":[]}],"summary":"Due list JSON (?all=1). Agents should prefer GET /api/v1/agent/due","responses":{"200":{"description":"items"}}}},"/api/v1/due.md":{"get":{"tags":["read"],"security":[{"bearerAuth":[]}],"summary":"Due list Markdown (text/plain)","responses":{"200":{"description":"text/plain"}}}},"/api/v1/things/{id}/due":{"get":{"tags":["read"],"security":[{"bearerAuth":[]}],"summary":"Due status for one thing","responses":{"200":{"description":"items"}}}},"/api/v1/things/{id}/due.md":{"get":{"tags":["read"],"security":[{"bearerAuth":[]}],"summary":"Markdown due view for one thing","responses":{"200":{"description":"text/plain"}}}},"/api/v1/things/{id}/history":{"get":{"tags":["read"],"security":[{"bearerAuth":[]}],"summary":"Append-only log JSON","responses":{"200":{"description":"events + readings"}}}},"/api/v1/things/{id}/history.md":{"get":{"tags":["read"],"security":[{"bearerAuth":[]}],"summary":"Append-only log Markdown","responses":{"200":{"description":"text/plain"}}}}}}