# Docs by AI Computer Company — Complete Agent Manual Collaborative markdown documents that AI agents read and edit over REST while humans edit the same document live in the browser. Server-side writes are applied as minimal diffs into the shared CRDT, so human collaborators' cursors survive every agent edit. API base: https://docs.aicomputercompany.com/api Share link for humans: https://docs.aicomputercompany.com/ AUTHORIZATION None. Possession of the unguessable document id (doc_) is the capability: anyone who knows the id can read and write that document. No API keys, no signup, no Authorization header needed. IDENTITY HEADERS (optional but recommended) x-actor-id: stable agent identity, must start with "agent_" (e.g. x-actor-id: agent_claude_main). 400 otherwise. x-actor-name: display name shown to humans (e.g. x-actor-name: Claude). Send both on every request so your edits, annotations, and revisions are attributed consistently. Omitting them creates a fresh anonymous agent actor per request. CONTENT The document body is plain markdown. Review state (annotations, comments, suggestions) is stored inline as CriticMarkup/RFM markup plus a YAML endmatter block; the editor hides it and clean export strips it. ================================================================================ LIFECYCLE: CREATE → READ → EDIT → PUSH ================================================================================ CREATE A DOCUMENT POST /api/docs Body: {"markdown": "# My Doc\n\n...", "title": "My Doc"} (both optional) → 201 {"document": {"id": "doc_…", …}, "latestRevision": {…}, "actor": {…}, "shareUrl": "https://docs.aicomputercompany.com/doc_…", "yjsWsUrl": "wss://…"} Give the shareUrl to humans; use document.id for all API calls. curl -X POST https://docs.aicomputercompany.com/api/docs \ -H 'Content-Type: application/json' \ -H 'x-actor-id: agent_demo' -H 'x-actor-name: Demo Agent' \ -d '{"markdown": "# Plan\n\nDraft.\n", "title": "Plan"}' READ (always read before editing) GET /api/docs/:id/raw → current markdown, text/plain GET /api/docs/:id/raw?numbered=1 → cat -n style: 6-char right-aligned line number, tab, line content GET /api/docs/:id → {"document", "latestRevision"} JSON curl https://docs.aicomputercompany.com/api/docs/doc_abc123/raw?numbered=1 EDIT (preferred for changes — exact str_replace semantics) POST /api/docs/:id/edit Body: {"old_string": "exact text in doc", "new_string": "replacement text", "replace_all": false} (replace_all optional, default false) Semantics (identical to the local-file Edit tool): - old_string must match the document text exactly, including whitespace. - old_string not found → 409 {"error": "old_string not found in document"} - old_string found more than once and replace_all is not true → 409 {"error": "old_string is not unique; provide more context or set replace_all"} Fix by including more surrounding context in old_string, or set "replace_all": true to change every occurrence. - old_string === new_string → 400. - success → 200 {"applied": true, "occurrences": n, "revisionHint": "rev_…"?} The edit is applied to the live document as a minimal diff — collaborators see it instantly and their cursors are preserved. curl -X POST https://docs.aicomputercompany.com/api/docs/doc_abc123/edit \ -H 'Content-Type: application/json' \ -H 'x-actor-id: agent_demo' \ -d '{"old_string": "## Old heading", "new_string": "## New heading"}' PUSH (full document replace — for wholesale rewrites) PUT /api/docs/:id/markdown Body: {"markdown": "", "checkpoint": true, (optional, default true: save a revision) "message": "why"} (optional revision message) → 200 {"document", "revision"} Server-side the new content is diff-applied into the live document (never a full delete+insert), so collaborator cursors survive even a full push. curl -X PUT https://docs.aicomputercompany.com/api/docs/doc_abc123/markdown \ -H 'Content-Type: application/json' \ -d '{"markdown": "# Rewritten\n\nAll new.\n", "message": "Full rewrite"}' SAVE-TO-LOCAL + PUSH-BACK WORKFLOW Work on the document with your normal local file tools, then push back: 1. curl https://docs.aicomputercompany.com/api/docs/doc_abc123/raw > doc.md 2. Edit doc.md locally (any editor/tool). 3. curl -X PUT https://docs.aicomputercompany.com/api/docs/doc_abc123/markdown \ -H 'Content-Type: application/json' \ -d "$(jq -Rs '{markdown: .}' < doc.md)" Prefer POST /api/docs/:id/edit for targeted changes while humans are editing — smaller diffs merge more gracefully than a full push. ================================================================================ HISTORY: CHECKPOINTS, REVISIONS, REVERT, EXPORT ================================================================================ POST /api/docs/:id/checkpoints Body: {"markdown"?: "...", "reason"?: "manual-save", "message"?: "..."} (markdown defaults to the latest revision content) → 201 {"document", "revision"} named save point GET /api/docs/:id/revisions → {"revisions": [...], "actors": {...}} GET /api/docs/:id/revisions/:revId → {"revision"} GET /api/docs/:id/revisions/:revId/raw → that revision's markdown POST /api/docs/:id/revert Body: {"revisionId": "rev_…"} → 201 {"document", "revision"} creates a new revision with the old content and diff-applies it to the live document. GET /api/docs/:id/export.md → markdown download GET /api/docs/:id/export.md?clean=1 → publishing export: strips all review markup (annotations/comments unwrapped, pending suggestions rejected, endmatter removed) GET /api/docs/:id/export.clean.md → clean export of the LIVE document content (export.md exports the latest saved revision) curl https://docs.aicomputercompany.com/api/docs/doc_abc123/export.md?clean=1 ================================================================================ REVIEW API — ANNOTATIONS, COMMENTS, SUGGESTIONS, VIEWS ================================================================================ REVIEW INDEX (read everything review-related) GET /api/docs/:id/review-index → {"source": "live"|"revision", "fileVersion": "rev_…", "index": {"items": [...]}, all review items with line numbers "annotations": [...]} items carrying a verdict, each with {id, line, verdict, refs, body, …} ANNOTATIONS (Layer 1 — spec-review verdicts anchored to exact text) POST /api/docs/:id/annotations Body: {"anchorText": "exact text to anchor to", (required) "occurrence": 1, (optional, disambiguates) "verdict": "valid" | "question" | "conflict", (required) "body": "your explanation", (required) "refs": ["a7"], (optional, ids of conflicting annotations) "checkpoint": false, "message": "..."} (optional) → 201 {"id": "a1", "line": 12, "revision": null|{…}} → 409 if anchorText is not found outside existing markup. Verdicts: valid = requirement is clear & consistent, question = needs clarification, conflict = conflicts with another requirement (use refs). POST /api/docs/:id/annotations/bulk (primary verb for a review pass) Body: {"annotations": [ ...same shape as above... ], "checkpoint": true, (default true) "message": "AI spec review"} → 201 {"created": [{id, …}], "failed": [{input, error}], "revision"} One revision for the whole pass; failed anchors don't abort the rest. POST /api/docs/:id/annotations/:targetId/resolve {"resolution"?: "..."} → {"ok": true, "revision"} marks status=resolved in endmatter DELETE /api/docs/:id/annotations/:targetId → {"ok": true, "revision"} removes markup + endmatter entry curl -X POST https://docs.aicomputercompany.com/api/docs/doc_abc123/annotations/bulk \ -H 'Content-Type: application/json' -H 'x-actor-id: agent_demo' \ -d '{"annotations": [ {"anchorText": "must support offline mode", "verdict": "valid", "body": "Confirmed in section 3.2"}, {"anchorText": "sync every 5 minutes", "verdict": "conflict", "body": "Conflicts with the realtime requirement", "refs": ["a1"]} ]}' COMMENTS & REPLIES (Layer 2 — verdict-less discussion) POST /api/docs/:id/comments Body: {"body": "comment text", (required) "anchorText": "...", "occurrence": 1} (optional; omit both for a document-level comment) → 201 {"id": "c1"|null, "revision"} POST /api/docs/:id/comments/:parentId/replies {"body": "reply text"} → 201 {"ok": true, "revision"} threaded under the parent POST /api/docs/:id/comments/:targetId/resolve {"resolution"?: "..."} → {"ok": true, "revision"} SUGGESTIONS (tracked changes humans accept/reject in the editor) Stored as CriticMarkup in the document text: {++added text++} {--deleted text--} {~~old~>new~~} POST /api/docs/:id/suggestions Body: {"kind": "addition" | "deletion" | "substitution", "anchorText": "insert after this text", (addition) "targetText": "text to delete/replace", (deletion/substitution) "occurrence": 1, (optional) "text": "new text", (addition/substitution) "body": "rationale shown in the review rail"} (optional) → 201 {"id": "s1", "revision"} → 409 if anchorText/targetText is not found. POST /api/docs/:id/suggestions/:targetId/accept → {"ok": true, "revision"} POST /api/docs/:id/suggestions/:targetId/reject → {"ok": true, "revision"} curl -X POST https://docs.aicomputercompany.com/api/docs/doc_abc123/suggestions \ -H 'Content-Type: application/json' \ -d '{"kind": "substitution", "targetText": "5 minutes", "text": "30 seconds", "body": "Match the SLA in section 2"}' VIEWS (Layer 3 — agent-generated side panels: gantt, coverage, prompts, digest, custom — see CUSTOM VIEWS below for pushing your own HTML UI) GET /api/docs/:id/views → {"views": [...], "currentRevisionId"} POST /api/docs/:id/views Body: {"kind": "gantt"|"coverage"|"prompts"|"digest"|, "title"?: "...", "payload": , "replace"?: true} (default true: upsert by kind) → 201 {"view"} DELETE /api/docs/:id/views/:viewId → {"ok": true} POST /api/docs/:id/views/:viewId/refresh-request → {"ok": true} human asked for a regenerate; emits a "refresh-requested" event for you GET /api/docs/:id/view-events?since=0&timeoutMs=25000 → {"events": [{seq, type, viewId, at}], "seq"} Long-poll: blocks until events newer than `since` arrive (or timeout). Event types: view-updated, view-deleted, refresh-requested. Loop on this to close the cycle: human edits → clicks refresh → you regenerate the view payload and POST it back. ================================================================================ CUSTOM VIEWS — PUSH YOUR OWN UI ================================================================================ Need a visualization that no built-in view kind covers? Push kind "custom" with a self-contained HTML/JS document and the app renders it in the Views pane. Build whatever you and the user need: charts, kanban boards, decision matrices, timelines. PAYLOAD POST /api/docs/:id/views Body: {"kind": "custom", "title": "Effort vs impact", (card header, optional) "payload": {"html": "…", (required, string, ≤ 1MB) "title": "..."}} (optional iframe title) → 201 {"view"}; 400 if payload.html is missing, not a string, or > 1MB. Upserts by kind like other views (one custom view per document by default; pass "replace": false to keep several). SANDBOX (the rules your HTML runs under) The document renders in