···11+{{define "title"}}Activity — Twister API{{end}}
22+{{define "content"}}
33+<h1>Activity</h1>
44+<p>Activity endpoints expose the recent ATProto event cache and a real-time
55+WebSocket proxy to the Bluesky Jetstream firehose. The cache is populated as
66+the indexer consumes the firehose.</p>
77+{{range .}}{{template "doc-entry" .}}{{end}}
88+{{end}}
99+{{template "layout" .}}
···11-{{define "title"}}Health Endpoints — Twister API{{end}}
11+{{define "title"}}Health — Twister API{{end}}
22{{define "content"}}
33-<h1>Health Endpoints</h1>
33+<h1>Health</h1>
44<p>Twister exposes two health check endpoints for monitoring and orchestration.</p>
55-66-<h2><code>GET /healthz</code></h2>
77-<p>Liveness probe. Returns 200 if the process is responsive. No dependency checks.</p>
88-99-<h3>Example Request</h3>
1010-<pre><code>curl https://your-domain/healthz</code></pre>
1111-1212-<h3>Response</h3>
1313-<pre><code>{"status": "ok"}</code></pre>
1414-<p>Always returns <code>200 OK</code>.</p>
1515-1616-<h2><code>GET /readyz</code></h2>
1717-<p>Readiness probe. Checks that the database is reachable by executing a test query.</p>
1818-1919-<h3>Example Request</h3>
2020-<pre><code>curl https://your-domain/readyz</code></pre>
2121-2222-<h3>Response (healthy)</h3>
2323-<pre><code>{"status": "ready"}</code></pre>
2424-<p>Returns <code>200 OK</code> when the database is reachable.</p>
2525-2626-<h3>Response (unhealthy)</h3>
2727-<pre><code>{"error": "db_unreachable", "message": "database is not reachable"}</code></pre>
2828-<p>Returns <code>503 Service Unavailable</code> when the database cannot be reached.</p>
2929-55+{{range .}}{{template "doc-entry" .}}{{end}}
306<h2>Usage</h2>
3131-<p>Configure your orchestrator (Railway, Kubernetes, etc.) to poll these endpoints:</p>
77+<p>Configure your orchestrator to poll these endpoints:</p>
328<table>
3333- <thead><tr><th>Endpoint</th><th>Purpose</th><th>Failure Action</th></tr></thead>
99+ <thead><tr><th>Endpoint</th><th>Purpose</th><th>Failure action</th></tr></thead>
3410 <tbody>
3511 <tr><td><code>/healthz</code></td><td>Liveness</td><td>Restart the process</td></tr>
3612 <tr><td><code>/readyz</code></td><td>Readiness</td><td>Remove from load balancer</td></tr>
···11{{define "title"}}API Docs — Twister{{end}}
22{{define "content"}}
33<h1>API Documentation</h1>
44-<p>Twister exposes a public JSON API for searching indexed <a href="https://tangled.org" target="_blank" rel="noopener">Tangled</a> content. No authentication is required for read endpoints.</p>
44+<p>Twister exposes a public JSON API for searching indexed
55+<a href="https://tangled.org" target="_blank" rel="noopener">Tangled</a> content.
66+No authentication is required for read endpoints.</p>
5768<h2>Base URL</h2>
79<pre><code>https://<your-twister-domain></code></pre>
88-<p>All endpoints are relative to the base URL. When using the search site, the API is on the same origin.</p>
1010+<p>All endpoints are relative to the base URL. When using the search site, the
1111+API is on the same origin.</p>
9121010-<h2>Response Shape</h2>
1111-<p>All responses are JSON. Successful responses return the resource directly. Errors return:</p>
1212-<pre><code>{
1313- "error": "error_code",
1414- "message": "Human-readable description"
1515-}</code></pre>
1313+<h2>Response shape</h2>
1414+<p>All responses are JSON. Successful responses return the resource directly.
1515+Errors return:</p>
1616+<pre><code>{"error": "error_code", "message": "what went wrong"}</code></pre>
16171718<h2>Endpoints</h2>
1819<table>
1919- <thead><tr><th>Method</th><th>Path</th><th>Description</th></tr></thead>
2020+ <thead><tr><th>Resource</th><th>Description</th></tr></thead>
2021 <tbody>
2121- <tr><td><code>GET</code></td><td><a href="/docs/search"><code>/search</code></a></td><td>Search indexed documents</td></tr>
2222- <tr><td><code>GET</code></td><td><a href="/docs/documents"><code>/documents/{id}</code></a></td><td>Fetch a single document</td></tr>
2323- <tr><td><code>GET</code></td><td><a href="/docs/health"><code>/healthz</code></a></td><td>Liveness probe</td></tr>
2424- <tr><td><code>GET</code></td><td><a href="/docs/health"><code>/readyz</code></a></td><td>Readiness probe</td></tr>
2222+ <tr><td><a href="/docs/search">Search</a></td>
2323+ <td>FTS5 keyword search over indexed documents</td></tr>
2424+ <tr><td><a href="/docs/documents">Documents</a></td>
2525+ <td>Fetch a single indexed document by stable ID</td></tr>
2626+ <tr><td><a href="/docs/actors">Actors & Repos</a></td>
2727+ <td>Actor profiles, repo records, and repo sub-resources</td></tr>
2828+ <tr><td><a href="/docs/issues">Issues</a></td>
2929+ <td>Issue detail and comments with pre-joined state</td></tr>
3030+ <tr><td><a href="/docs/pulls">Pull Requests</a></td>
3131+ <td>PR detail and comments with pre-joined status</td></tr>
3232+ <tr><td><a href="/docs/identity">Identity</a></td>
3333+ <td>Handle resolution and DID document lookup</td></tr>
3434+ <tr><td><a href="/docs/activity">Activity</a></td>
3535+ <td>Cached Jetstream events and real-time WebSocket stream</td></tr>
3636+ <tr><td><a href="/docs/profiles">Profiles & Backlinks</a></td>
3737+ <td>Social signals and Constellation backlinks counts</td></tr>
3838+ <tr><td><a href="/docs/xrpc">XRPC Proxy</a></td>
3939+ <td>Pass-through proxy to knots, PDS hosts, and Bluesky</td></tr>
4040+ <tr><td><a href="/docs/health">Health</a></td>
4141+ <td>Liveness and readiness probes</td></tr>
2542 </tbody>
2643</table>
27442845<h2>Pagination</h2>
2929-<p>List endpoints use <code>limit</code> and <code>offset</code> query parameters. The default limit is 20, maximum is 100.</p>
3030-3131-<h2>Filtering</h2>
3232-<p>Search supports filters via query parameters: <code>collection</code>, <code>type</code>, <code>author</code>, <code>repo</code>, <code>language</code>, <code>state</code>, <code>from</code>, <code>to</code>. See the <a href="/docs/search">search endpoint docs</a> for details.</p>
4646+<p>List endpoints use <code>limit</code> and <code>offset</code> query
4747+parameters. Defaults and maximums vary per endpoint — see each resource page
4848+for details.</p>
3349{{end}}
3450{{template "layout" .}}
···11+{{define "title"}}Issues — Twister API{{end}}
22+{{define "content"}}
33+<h1>Issues</h1>
44+<p>Issue endpoints fetch records and comments from an actor’s PDS.
55+Responses include a pre-joined <code>state</code> field derived from
66+<code>sh.tangled.repo.issue.state</code> records.</p>
77+{{range .}}{{template "doc-entry" .}}{{end}}
88+{{end}}
99+{{template "layout" .}}
···11+{{define "title"}}Profiles & Backlinks — Twister API{{end}}
22+{{define "content"}}
33+<h1>Profiles & Backlinks</h1>
44+<p>These endpoints surface derived social data from Constellation, the external
55+graph service. Both are best-effort: counts default to zero when Constellation
66+is not configured or unavailable.</p>
77+{{range .}}{{template "doc-entry" .}}{{end}}
88+{{end}}
99+{{template "layout" .}}
···11+{{define "title"}}Pull Requests — Twister API{{end}}
22+{{define "content"}}
33+<h1>Pull Requests</h1>
44+<p>Pull request endpoints fetch records and comments from an actor’s PDS.
55+Responses include a pre-joined <code>status</code> field derived from
66+<code>sh.tangled.repo.pull.status</code> records:
77+<code>open</code>, <code>closed</code>, or <code>merged</code>.</p>
88+{{range .}}{{template "doc-entry" .}}{{end}}
99+{{end}}
1010+{{template "layout" .}}
···11+{{define "title"}}XRPC — Twister API{{end}}
22+{{define "content"}}
33+<h1>XRPC</h1>
44+<p>XRPC endpoints provide a single-origin pass-through to Tangled knots, PDS
55+hosts, and the Bluesky public API. All query parameters are forwarded verbatim.
66+Responses are streamed back unchanged, making these suitable for browser clients
77+that cannot make direct cross-origin requests.</p>
88+{{range .}}{{template "doc-entry" .}}{{end}}
99+{{end}}
1010+{{template "layout" .}}