{"openapi":"3.1.0","info":{"title":"Agent Ledger API","version":"1.0.0","description":"Shared project memory for AI coding agents. A ledger of what your project decided, learned the hard way and forbade, plus a task queue, that Claude Code, Cursor, Codex and any MCP client read before they act and add to as they work. Agents stop repeating reverted changes, and a new session starts where the last one stopped.","contact":{"email":"support@agent-ledger.plxi.us","url":"https://agent-ledger.plxi.us/contact"},"termsOfService":"https://agent-ledger.plxi.us/terms"},"externalDocs":{"url":"https://agent-ledger.plxi.us/docs"},"servers":[{"url":"https://api-agent-ledger.plxi.us"}],"security":[{"apiKey":[]}],"paths":{"/v1/record":{"post":{"operationId":"ledgerRecord","summary":"Record an entry","description":"Write down something the next agent or teammate on this project must know: a decision and why it was made, a lesson from something that broke or was reverted, a guardrail (a rule not to break), a note, or a task to be done. Record a lesson whenever a change is rolled back or a fix took real digging, and a decision whenever an approach is chosen over another. `kind` is decision, lesson, guardrail, note or task; give a short `title`, the details in `body` (what happened, why, what to do instead) and optional `tags`. When this replaces an earlier entry, put its id in `supersedes` and the old one is retired with a pointer to this one. Recording the exact same entry again returns the existing one. Returns the entry with its id (KNOW-n, or TASK-n for a task).","x-credits":1,"externalDocs":{"url":"https://agent-ledger.plxi.us/docs#op-ledger-record"},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"project":{"type":"string","pattern":"^[A-Za-z0-9][A-Za-z0-9._/-]{0,99}$","description":"The project, usually the repository (\"owner/repo\" or a short name). Entries are kept per project."},"kind":{"type":"string","enum":["decision","lesson","guardrail","note","task"],"description":"What sort of entry this is."},"title":{"type":"string","minLength":1,"maxLength":200,"description":"One line saying what it is."},"body":{"type":"string","maxLength":20000,"default":"","description":"The details: what happened or was decided, why, and what to do instead."},"tags":{"type":"array","items":{"type":"string","minLength":1,"maxLength":40},"maxItems":10,"default":[],"description":"Words to find it by, such as the component it is about."},"supersedes":{"type":"string","pattern":"^((KNOW|TASK)-)?[1-9][0-9]{0,8}$","description":"The id of an entry this one replaces (KNOW-n); it is retired."}},"required":["project","kind","title"],"additionalProperties":false},"example":{"project":"acme/shop","kind":"lesson","title":"Captcha on checkout cut completed orders 5%","body":"Shipped a captcha on the checkout page in March and reverted it after two weeks: completed orders fell 5%. Bots only spike on release days.","tags":["checkout","captcha"]}}}},"responses":{"200":{"description":"Success. The body includes the credits charged.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"kind":{"type":"string"},"title":{"type":"string"},"body":{"type":"string"},"tags":{"type":"array","items":{"type":"string"}},"status":{"type":"string"},"superseded_by":{"type":["string","null"]},"reason":{"type":["string","null"]},"claimed_by":{"type":["string","null"]},"created_at":{"type":"string"},"credits":{"type":"integer","description":"Credits this call was charged."}},"required":["id","kind","title","body","tags","status","created_at","credits"]},"example":{"id":"KNOW-1","kind":"lesson","title":"Captcha on checkout cut completed orders 5%","body":"Shipped a captcha on the checkout page in March and reverted it after two weeks: completed orders fell 5%. Bots only spike on release days.","tags":["checkout","captcha"],"status":"active","superseded_by":null,"reason":null,"claimed_by":null,"created_at":"2026-10-20T06:00:00.000000+00:00","credits":1}}}},"400":{"description":"Invalid JSON or input. Not charged.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit, concurrency limit or monthly quota reached.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Temporarily unavailable. Retry with backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/recall":{"post":{"operationId":"ledgerRecall","summary":"Recall what the project knows","description":"Before planning a change, removing code that looks unnecessary, or repeating an approach, search the project's ledger for what was already decided, tried or forbidden. Put the area or change in `query`: any of its words match, best matches first, and a word in an entry's title counts for more than one in its body. Use the words that would appear in the entry, not the words of the symptom: 'captcha checkout' finds a note titled 'Captcha on checkout', while 'why did orders drop' finds nothing. Leave it empty for the newest entries. Retired entries are left out unless `include_retired` is true, so what comes back is what still holds. Filter by `kind` if you only want tasks, say. Free. Returns `entries`, each with its id, kind, title, body, tags and status.","x-credits":0,"externalDocs":{"url":"https://agent-ledger.plxi.us/docs#op-ledger-recall"},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"project":{"type":"string","pattern":"^[A-Za-z0-9][A-Za-z0-9._/-]{0,99}$","description":"The project, usually the repository (\"owner/repo\" or a short name). Entries are kept per project."},"query":{"type":"string","maxLength":500,"default":"","description":"Words about the change or area, such as \"checkout captcha bots\"."},"kind":{"type":"string","enum":["decision","lesson","guardrail","note","task"],"description":"Only entries of this kind."},"include_retired":{"type":"boolean","default":false,"description":"Include retired entries and done tasks."},"limit":{"type":"integer","minimum":1,"maximum":50,"default":10,"description":"The most entries to return."}},"required":["project"],"additionalProperties":false},"example":{"project":"acme/shop","query":"add a captcha to checkout"}}}},"responses":{"200":{"description":"Success. The body includes the credits charged.","content":{"application/json":{"schema":{"type":"object","properties":{"project":{"type":"string"},"entries":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"kind":{"type":"string"},"title":{"type":"string"},"body":{"type":"string"},"tags":{"type":"array","items":{"type":"string"}},"status":{"type":"string"},"superseded_by":{"type":["string","null"]},"reason":{"type":["string","null"]},"claimed_by":{"type":["string","null"]},"created_at":{"type":"string"}},"required":["id","kind","title","body","tags","status","created_at"]}},"credits":{"type":"integer","description":"Credits this call was charged."}},"required":["project","entries","credits"]},"example":{"project":"acme/shop","entries":[{"id":"KNOW-1","kind":"lesson","title":"Captcha on checkout cut completed orders 5%","body":"Shipped a captcha on the checkout page in March and reverted it after two weeks: completed orders fell 5%. Bots only spike on release days.","tags":["checkout","captcha"],"status":"active","superseded_by":null,"reason":null,"claimed_by":null,"created_at":"2026-10-20T06:00:00.000000+00:00"}],"credits":0}}}},"400":{"description":"Invalid JSON or input. Not charged.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit, concurrency limit or monthly quota reached.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Temporarily unavailable. Retry with backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/claim":{"post":{"operationId":"ledgerClaim","summary":"Claim a task","description":"Take a task before starting it, so another agent or teammate doesn't work on the same one. Give the task's `id` (TASK-n), or leave it out to take the oldest open task. `agent` names who is working on it (\"claude-code on dimaino's laptop\"). A task claimed by someone else is refused with already_claimed; claiming your own again is fine. When finished, mark it done with retire_entry. Free. Returns `task`, or null when there is no open task.","x-credits":0,"externalDocs":{"url":"https://agent-ledger.plxi.us/docs#op-ledger-claim"},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"project":{"type":"string","pattern":"^[A-Za-z0-9][A-Za-z0-9._/-]{0,99}$","description":"The project, usually the repository (\"owner/repo\" or a short name). Entries are kept per project."},"id":{"type":"string","pattern":"^((KNOW|TASK)-)?[1-9][0-9]{0,8}$","description":"The task to claim (TASK-n). Leave out to take the oldest open task."},"agent":{"type":"string","minLength":1,"maxLength":100,"description":"Who is taking it."}},"required":["project","agent"],"additionalProperties":false},"example":{"project":"acme/shop","agent":"claude-code"}}}},"responses":{"200":{"description":"Success. The body includes the credits charged.","content":{"application/json":{"schema":{"type":"object","properties":{"task":{"anyOf":[{"type":"object","properties":{"id":{"type":"string"},"kind":{"type":"string"},"title":{"type":"string"},"body":{"type":"string"},"tags":{"type":"array","items":{"type":"string"}},"status":{"type":"string"},"superseded_by":{"type":["string","null"]},"reason":{"type":["string","null"]},"claimed_by":{"type":["string","null"]},"created_at":{"type":"string"}},"required":["id","kind","title","body","tags","status","created_at"]},{"type":"null"}]},"credits":{"type":"integer","description":"Credits this call was charged."}},"required":["task","credits"]},"example":{"task":null,"credits":0}}}},"400":{"description":"Invalid JSON or input. Not charged.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit, concurrency limit or monthly quota reached.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Temporarily unavailable. Retry with backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/retire":{"post":{"operationId":"ledgerRetire","summary":"Retire an entry or finish a task","description":"Retire a decision, lesson, guardrail or note that is no longer true, so recall stops returning it, or mark a task done. Give its `id` and, for anything but a finished task, a short `reason`. To replace an entry with a new one, use record_entry with `supersedes` instead. Retiring again changes nothing. Free. Returns the entry with its new status.","x-credits":0,"externalDocs":{"url":"https://agent-ledger.plxi.us/docs#op-ledger-retire"},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"project":{"type":"string","pattern":"^[A-Za-z0-9][A-Za-z0-9._/-]{0,99}$","description":"The project, usually the repository (\"owner/repo\" or a short name). Entries are kept per project."},"id":{"type":"string","pattern":"^((KNOW|TASK)-)?[1-9][0-9]{0,8}$","description":"The entry (KNOW-n) or task (TASK-n)."},"reason":{"type":"string","maxLength":500,"description":"Why it no longer holds."}},"required":["project","id"],"additionalProperties":false},"example":{"project":"acme/shop","id":"KNOW-1","reason":"Bots are now stopped at the CDN."}}}},"responses":{"200":{"description":"Success. The body includes the credits charged.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"kind":{"type":"string"},"title":{"type":"string"},"body":{"type":"string"},"tags":{"type":"array","items":{"type":"string"}},"status":{"type":"string"},"superseded_by":{"type":["string","null"]},"reason":{"type":["string","null"]},"claimed_by":{"type":["string","null"]},"created_at":{"type":"string"},"credits":{"type":"integer","description":"Credits this call was charged."}},"required":["id","kind","title","body","tags","status","created_at","credits"]},"example":{"id":"KNOW-1","kind":"lesson","title":"Captcha on checkout cut completed orders 5%","body":"Shipped a captcha on the checkout page in March and reverted it after two weeks: completed orders fell 5%. Bots only spike on release days.","tags":["checkout","captcha"],"status":"retired","superseded_by":null,"reason":"Bots are now stopped at the CDN.","claimed_by":null,"created_at":"2026-10-20T06:00:00.000000+00:00","credits":0}}}},"400":{"description":"Invalid JSON or input. Not charged.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit, concurrency limit or monthly quota reached.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Temporarily unavailable. Retry with backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/usage":{"get":{"operationId":"getUsage","summary":"Usage and limits for the current billing period.","responses":{"200":{"description":"Usage summary.","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}},"components":{"securitySchemes":{"apiKey":{"type":"apiKey","in":"header","name":"X-API-Key"}},"schemas":{"Error":{"type":"object","required":["error"],"properties":{"error":{"type":"string","description":"Stable error code, listed in the API reference."},"message":{"type":"string"},"reset_at":{"type":"string","format":"date-time"}}}}}}