{"openapi":"3.1.0","info":{"title":"aicoolies Public API","version":"1.0.0","description":"Catalog, dataset, health, discovery, and MCP endpoints for aicoolies.com. Public reads require no credential; MCP community writes accept a scoped GitHub-bound personal access token.\n\n## Permissions\n\nPublic catalog reads need no credential. submit_correction and report_price_change require correction:write; sync_stack requires stack:write; reply_to_room requires room:write; submit_run requires run:write; and upvote_tool requires vote:write. Owners create and revoke these GitHub-bound personal access tokens in first-party settings. New tokens default only to correction:write and stack:write. Human /dev profiles, comments, and account settings continue to use a first-party GitHub OAuth session. aicoolies is deliberately not an OAuth authorization server and issues no OAuth access tokens; /.well-known/oauth-authorization-server answers 404 with that explanation rather than a fabricated document. The machine-readable model is at /.well-known/oauth-protected-resource (RFC 9728).\n\n## Versioning\n\nThe current major version is 1. Every response carries `API-Version: 1`. Version-pinned paths live under `/api/v1`; the unversioned paths are permanent aliases of the current major. A breaking change ships under a new prefix, and the outgoing major then answers with `Deprecation` (RFC 9745), `Sunset` (RFC 8594), and `Link; rel=\"deprecation\"` for at least 180 days before removal. Policy: https://aicoolies.com/developers#versioning.\n\n## Errors\n\nEvery 4xx and 5xx is an RFC 9457 problem document served as `application/problem+json`, with a machine-readable `code`, a human-readable `detail`, and a `type` URI that resolves to the matching anchor on the developer portal.\n\n## Rate limits\n\nAdvisory quotas: agent-api 120/60s, dataset 60/60s, mcp 120/60s. Responses carry RateLimit-Policy, RateLimit, and the RateLimit-Limit/-Remaining/-Reset trio; a 429 adds Retry-After. Values seen through a shared cache may be a few seconds stale.","contact":{"name":"aicoolies","url":"https://aicoolies.com/developers","email":"rasitakyol@digitalkarinca.com"},"license":{"name":"Catalog datasets: CC-BY-4.0. API contract: MIT.","url":"https://creativecommons.org/licenses/by/4.0/"}},"externalDocs":{"description":"aicoolies developer portal","url":"https://aicoolies.com/developers"},"servers":[{"url":"https://aicoolies.com","description":"Production"}],"security":[],"x-api-version":1,"x-version-path-prefix":"/api/v1","x-deprecation-policy":{"minimum_notice_days":180,"signals":["Deprecation","Sunset","Link; rel=\"deprecation\""],"documentation":"https://aicoolies.com/developers#versioning"},"x-rate-limits":{"policies":[{"name":"agent-api","requests":120,"window_seconds":60},{"name":"dataset","requests":60,"window_seconds":60},{"name":"mcp","requests":120,"window_seconds":60}],"headers":["RateLimit-Policy","RateLimit","RateLimit-Limit","RateLimit-Remaining","RateLimit-Reset","Retry-After"]},"x-error-format":"application/problem+json","tags":[{"name":"Agents","description":"JSON indexes for research agents"},{"name":"Datasets","description":"CC-BY 4.0 bulk files"},{"name":"MCP","description":"Model Context Protocol"},{"name":"Discovery","description":"Machine-readable contracts"},{"name":"Pages","description":"HTML pages with markdown content negotiation"},{"name":"Ops","description":"Liveness"}],"paths":{"/api/agents/context":{"get":{"operationId":"getAgentContext","summary":"Filterable JSON site index for research agents","description":"Returns the aicoolies catalog as a typed JSON index of tools, comparisons, reviews, stacks, use cases, categories, and tags. Supports conditional GET via If-None-Match. CORS is * for GET and OPTIONS. Responses carry RateLimit headers so a client can self-throttle.","tags":["Agents"],"security":[],"parameters":[{"name":"category","in":"query","required":false,"description":"Category slug. Limits tools and related records to that category.","schema":{"type":"string","examples":["ai-native-ides"]}},{"name":"include","in":"query","required":false,"description":"Comma-separated collections to include. Allowed: tools, comparisons, reviews, stacks (deprecated, always empty), use_cases, categories, tags.","schema":{"type":"string","examples":["tools,reviews"]}},{"name":"compact","in":"query","required":false,"description":"When true, each included collection is an array of slugs only.","schema":{"type":"boolean","default":false}}],"responses":{"200":{"description":"Catalog index","headers":{"API-Version":{"description":"Major version of the API contract that produced this response.","schema":{"type":"string","examples":["1"]}},"RateLimit-Policy":{"description":"Advisory quota for this endpoint family, in the draft-ietf-httpapi-ratelimit-headers format.","schema":{"type":"string","examples":["\"agent-api\";q=120;w=60"]}},"RateLimit":{"description":"Remaining requests (r) and seconds until the window resets (t).","schema":{"type":"string","examples":["\"agent-api\";r=119;t=60"]}},"RateLimit-Limit":{"description":"Requests allowed per window.","schema":{"type":"integer","examples":[120]}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer","examples":[119]}},"RateLimit-Reset":{"description":"Seconds until the current window resets.","schema":{"type":"integer","examples":[60]}},"ETag":{"description":"Strong validator. Send it back as If-None-Match to get a 304.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/AgentContext"},{"$ref":"#/components/schemas/AgentContextCompact"}]}}}},"304":{"description":"Not modified — the ETag sent in If-None-Match still matches.","headers":{"API-Version":{"description":"Major version of the API contract that produced this response.","schema":{"type":"string","examples":["1"]}},"RateLimit-Policy":{"description":"Advisory quota for this endpoint family, in the draft-ietf-httpapi-ratelimit-headers format.","schema":{"type":"string","examples":["\"agent-api\";q=120;w=60"]}},"RateLimit":{"description":"Remaining requests (r) and seconds until the window resets (t).","schema":{"type":"string","examples":["\"agent-api\";r=119;t=60"]}},"RateLimit-Limit":{"description":"Requests allowed per window.","schema":{"type":"integer","examples":[120]}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer","examples":[119]}},"RateLimit-Reset":{"description":"Seconds until the current window resets.","schema":{"type":"integer","examples":[60]}},"ETag":{"description":"Strong validator. Send it back as If-None-Match to get a 304.","schema":{"type":"string"}}}},"400":{"description":"Invalid include value or unknown category slug","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limit exceeded. Retry-After carries the wait in seconds.","headers":{"API-Version":{"description":"Major version of the API contract that produced this response.","schema":{"type":"string","examples":["1"]}},"RateLimit-Policy":{"description":"Advisory quota for this endpoint family, in the draft-ietf-httpapi-ratelimit-headers format.","schema":{"type":"string","examples":["\"agent-api\";q=120;w=60"]}},"RateLimit":{"description":"Remaining requests (r) and seconds until the window resets (t).","schema":{"type":"string","examples":["\"agent-api\";r=119;t=60"]}},"RateLimit-Limit":{"description":"Requests allowed per window.","schema":{"type":"integer","examples":[120]}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer","examples":[119]}},"RateLimit-Reset":{"description":"Seconds until the current window resets.","schema":{"type":"integer","examples":[60]}},"Retry-After":{"description":"Seconds to wait before retrying this endpoint family.","schema":{"type":"integer","examples":[60]}}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Server error","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/agents/meta":{"get":{"operationId":"getAgentMeta","summary":"Collection counts and freshness probe","description":"Cheap freshness document for agents. The ETag matches /api/agents/context so a client can skip the full payload. Supports conditional GET via If-None-Match. CORS is * for GET and OPTIONS. Responses carry RateLimit headers so a client can self-throttle.","tags":["Agents"],"security":[],"responses":{"200":{"description":"Counts and latest-updated timestamps","headers":{"API-Version":{"description":"Major version of the API contract that produced this response.","schema":{"type":"string","examples":["1"]}},"RateLimit-Policy":{"description":"Advisory quota for this endpoint family, in the draft-ietf-httpapi-ratelimit-headers format.","schema":{"type":"string","examples":["\"agent-api\";q=120;w=60"]}},"RateLimit":{"description":"Remaining requests (r) and seconds until the window resets (t).","schema":{"type":"string","examples":["\"agent-api\";r=119;t=60"]}},"RateLimit-Limit":{"description":"Requests allowed per window.","schema":{"type":"integer","examples":[120]}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer","examples":[119]}},"RateLimit-Reset":{"description":"Seconds until the current window resets.","schema":{"type":"integer","examples":[60]}},"ETag":{"description":"Strong validator. Send it back as If-None-Match to get a 304.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentMeta"}}}},"304":{"description":"Not modified — the ETag sent in If-None-Match still matches.","headers":{"API-Version":{"description":"Major version of the API contract that produced this response.","schema":{"type":"string","examples":["1"]}},"RateLimit-Policy":{"description":"Advisory quota for this endpoint family, in the draft-ietf-httpapi-ratelimit-headers format.","schema":{"type":"string","examples":["\"agent-api\";q=120;w=60"]}},"RateLimit":{"description":"Remaining requests (r) and seconds until the window resets (t).","schema":{"type":"string","examples":["\"agent-api\";r=119;t=60"]}},"RateLimit-Limit":{"description":"Requests allowed per window.","schema":{"type":"integer","examples":[120]}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer","examples":[119]}},"RateLimit-Reset":{"description":"Seconds until the current window resets.","schema":{"type":"integer","examples":[60]}},"ETag":{"description":"Strong validator. Send it back as If-None-Match to get a 304.","schema":{"type":"string"}}}},"429":{"description":"Rate limit exceeded. Retry-After carries the wait in seconds.","headers":{"API-Version":{"description":"Major version of the API contract that produced this response.","schema":{"type":"string","examples":["1"]}},"RateLimit-Policy":{"description":"Advisory quota for this endpoint family, in the draft-ietf-httpapi-ratelimit-headers format.","schema":{"type":"string","examples":["\"agent-api\";q=120;w=60"]}},"RateLimit":{"description":"Remaining requests (r) and seconds until the window resets (t).","schema":{"type":"string","examples":["\"agent-api\";r=119;t=60"]}},"RateLimit-Limit":{"description":"Requests allowed per window.","schema":{"type":"integer","examples":[120]}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer","examples":[119]}},"RateLimit-Reset":{"description":"Seconds until the current window resets.","schema":{"type":"integer","examples":[60]}},"Retry-After":{"description":"Seconds to wait before retrying this endpoint family.","schema":{"type":"integer","examples":[60]}}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Server error","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/agents/exclusion":{"get":{"operationId":"getAgentExclusion","summary":"Slug lists for exclusion-style sync","description":"Returns slug arrays for tools, comparisons, and reviews so an agent can detect deletions. Supports conditional GET via If-None-Match. CORS is * for GET and OPTIONS. Responses carry RateLimit headers so a client can self-throttle.","tags":["Agents"],"security":[],"parameters":[{"name":"category","in":"query","required":false,"description":"Optional category slug filter.","schema":{"type":"string","examples":["ai-cli-agents"]}}],"responses":{"200":{"description":"Slug lists","headers":{"API-Version":{"description":"Major version of the API contract that produced this response.","schema":{"type":"string","examples":["1"]}},"RateLimit-Policy":{"description":"Advisory quota for this endpoint family, in the draft-ietf-httpapi-ratelimit-headers format.","schema":{"type":"string","examples":["\"agent-api\";q=120;w=60"]}},"RateLimit":{"description":"Remaining requests (r) and seconds until the window resets (t).","schema":{"type":"string","examples":["\"agent-api\";r=119;t=60"]}},"RateLimit-Limit":{"description":"Requests allowed per window.","schema":{"type":"integer","examples":[120]}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer","examples":[119]}},"RateLimit-Reset":{"description":"Seconds until the current window resets.","schema":{"type":"integer","examples":[60]}},"ETag":{"description":"Strong validator. Send it back as If-None-Match to get a 304.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentExclusion"}}}},"304":{"description":"Not modified — the ETag sent in If-None-Match still matches.","headers":{"API-Version":{"description":"Major version of the API contract that produced this response.","schema":{"type":"string","examples":["1"]}},"RateLimit-Policy":{"description":"Advisory quota for this endpoint family, in the draft-ietf-httpapi-ratelimit-headers format.","schema":{"type":"string","examples":["\"agent-api\";q=120;w=60"]}},"RateLimit":{"description":"Remaining requests (r) and seconds until the window resets (t).","schema":{"type":"string","examples":["\"agent-api\";r=119;t=60"]}},"RateLimit-Limit":{"description":"Requests allowed per window.","schema":{"type":"integer","examples":[120]}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer","examples":[119]}},"RateLimit-Reset":{"description":"Seconds until the current window resets.","schema":{"type":"integer","examples":[60]}},"ETag":{"description":"Strong validator. Send it back as If-None-Match to get a 304.","schema":{"type":"string"}}}},"400":{"description":"Unknown category slug","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limit exceeded. Retry-After carries the wait in seconds.","headers":{"API-Version":{"description":"Major version of the API contract that produced this response.","schema":{"type":"string","examples":["1"]}},"RateLimit-Policy":{"description":"Advisory quota for this endpoint family, in the draft-ietf-httpapi-ratelimit-headers format.","schema":{"type":"string","examples":["\"agent-api\";q=120;w=60"]}},"RateLimit":{"description":"Remaining requests (r) and seconds until the window resets (t).","schema":{"type":"string","examples":["\"agent-api\";r=119;t=60"]}},"RateLimit-Limit":{"description":"Requests allowed per window.","schema":{"type":"integer","examples":[120]}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer","examples":[119]}},"RateLimit-Reset":{"description":"Seconds until the current window resets.","schema":{"type":"integer","examples":[60]}},"Retry-After":{"description":"Seconds to wait before retrying this endpoint family.","schema":{"type":"integer","examples":[60]}}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Server error","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/data/tools.json":{"get":{"operationId":"getToolsDataset","summary":"CC-BY 4.0 tools dataset","description":"Full aicoolies tool catalog as JSON. Licensed CC-BY 4.0, attribution aicoolies.com. The community namespace contains anonymous public aggregates that never alter editorial Score or verdicts. content_updated_at and verified_at have distinct semantics; as_of remains a deprecated v1 alias of content_updated_at. Supports conditional GET via If-None-Match. CORS is * for GET and OPTIONS. Responses carry RateLimit headers so a client can self-throttle.","tags":["Datasets"],"security":[],"responses":{"200":{"description":"Tools envelope","headers":{"API-Version":{"description":"Major version of the API contract that produced this response.","schema":{"type":"string","examples":["1"]}},"RateLimit-Policy":{"description":"Advisory quota for this endpoint family, in the draft-ietf-httpapi-ratelimit-headers format.","schema":{"type":"string","examples":["\"dataset\";q=60;w=60"]}},"RateLimit":{"description":"Remaining requests (r) and seconds until the window resets (t).","schema":{"type":"string","examples":["\"dataset\";r=59;t=60"]}},"RateLimit-Limit":{"description":"Requests allowed per window.","schema":{"type":"integer","examples":[60]}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer","examples":[59]}},"RateLimit-Reset":{"description":"Seconds until the current window resets.","schema":{"type":"integer","examples":[60]}},"ETag":{"description":"Strong validator. Send it back as If-None-Match to get a 304.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ToolsDataset"}}}},"304":{"description":"Not modified — the ETag sent in If-None-Match still matches.","headers":{"API-Version":{"description":"Major version of the API contract that produced this response.","schema":{"type":"string","examples":["1"]}},"RateLimit-Policy":{"description":"Advisory quota for this endpoint family, in the draft-ietf-httpapi-ratelimit-headers format.","schema":{"type":"string","examples":["\"dataset\";q=60;w=60"]}},"RateLimit":{"description":"Remaining requests (r) and seconds until the window resets (t).","schema":{"type":"string","examples":["\"dataset\";r=59;t=60"]}},"RateLimit-Limit":{"description":"Requests allowed per window.","schema":{"type":"integer","examples":[60]}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer","examples":[59]}},"RateLimit-Reset":{"description":"Seconds until the current window resets.","schema":{"type":"integer","examples":[60]}},"ETag":{"description":"Strong validator. Send it back as If-None-Match to get a 304.","schema":{"type":"string"}}}},"429":{"description":"Rate limit exceeded. Retry-After carries the wait in seconds.","headers":{"API-Version":{"description":"Major version of the API contract that produced this response.","schema":{"type":"string","examples":["1"]}},"RateLimit-Policy":{"description":"Advisory quota for this endpoint family, in the draft-ietf-httpapi-ratelimit-headers format.","schema":{"type":"string","examples":["\"dataset\";q=60;w=60"]}},"RateLimit":{"description":"Remaining requests (r) and seconds until the window resets (t).","schema":{"type":"string","examples":["\"dataset\";r=59;t=60"]}},"RateLimit-Limit":{"description":"Requests allowed per window.","schema":{"type":"integer","examples":[60]}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer","examples":[59]}},"RateLimit-Reset":{"description":"Seconds until the current window resets.","schema":{"type":"integer","examples":[60]}},"Retry-After":{"description":"Seconds to wait before retrying this endpoint family.","schema":{"type":"integer","examples":[60]}}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Server error","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/data/comparisons.json":{"get":{"operationId":"getComparisonsDataset","summary":"CC-BY 4.0 comparisons dataset","description":"Published aicoolies comparisons as JSON with tool slugs, content update, source check, and editorial verification dates. The deprecated as_of alias remains for v1 readers. Licensed CC-BY 4.0. Supports conditional GET via If-None-Match. CORS is * for GET and OPTIONS. Responses carry RateLimit headers so a client can self-throttle.","tags":["Datasets"],"security":[],"responses":{"200":{"description":"Comparisons envelope","headers":{"API-Version":{"description":"Major version of the API contract that produced this response.","schema":{"type":"string","examples":["1"]}},"RateLimit-Policy":{"description":"Advisory quota for this endpoint family, in the draft-ietf-httpapi-ratelimit-headers format.","schema":{"type":"string","examples":["\"dataset\";q=60;w=60"]}},"RateLimit":{"description":"Remaining requests (r) and seconds until the window resets (t).","schema":{"type":"string","examples":["\"dataset\";r=59;t=60"]}},"RateLimit-Limit":{"description":"Requests allowed per window.","schema":{"type":"integer","examples":[60]}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer","examples":[59]}},"RateLimit-Reset":{"description":"Seconds until the current window resets.","schema":{"type":"integer","examples":[60]}},"ETag":{"description":"Strong validator. Send it back as If-None-Match to get a 304.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ComparisonsDataset"}}}},"304":{"description":"Not modified — the ETag sent in If-None-Match still matches.","headers":{"API-Version":{"description":"Major version of the API contract that produced this response.","schema":{"type":"string","examples":["1"]}},"RateLimit-Policy":{"description":"Advisory quota for this endpoint family, in the draft-ietf-httpapi-ratelimit-headers format.","schema":{"type":"string","examples":["\"dataset\";q=60;w=60"]}},"RateLimit":{"description":"Remaining requests (r) and seconds until the window resets (t).","schema":{"type":"string","examples":["\"dataset\";r=59;t=60"]}},"RateLimit-Limit":{"description":"Requests allowed per window.","schema":{"type":"integer","examples":[60]}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer","examples":[59]}},"RateLimit-Reset":{"description":"Seconds until the current window resets.","schema":{"type":"integer","examples":[60]}},"ETag":{"description":"Strong validator. Send it back as If-None-Match to get a 304.","schema":{"type":"string"}}}},"429":{"description":"Rate limit exceeded. Retry-After carries the wait in seconds.","headers":{"API-Version":{"description":"Major version of the API contract that produced this response.","schema":{"type":"string","examples":["1"]}},"RateLimit-Policy":{"description":"Advisory quota for this endpoint family, in the draft-ietf-httpapi-ratelimit-headers format.","schema":{"type":"string","examples":["\"dataset\";q=60;w=60"]}},"RateLimit":{"description":"Remaining requests (r) and seconds until the window resets (t).","schema":{"type":"string","examples":["\"dataset\";r=59;t=60"]}},"RateLimit-Limit":{"description":"Requests allowed per window.","schema":{"type":"integer","examples":[60]}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer","examples":[59]}},"RateLimit-Reset":{"description":"Seconds until the current window resets.","schema":{"type":"integer","examples":[60]}},"Retry-After":{"description":"Seconds to wait before retrying this endpoint family.","schema":{"type":"integer","examples":[60]}}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Server error","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/data/reviews.json":{"get":{"operationId":"getReviewsDataset","summary":"CC-BY 4.0 reviews dataset","description":"Published aicoolies editorial reviews with 0–100 scores for overall, speed, privacy, and developer experience. Licensed CC-BY 4.0. Supports conditional GET via If-None-Match. CORS is * for GET and OPTIONS. Responses carry RateLimit headers so a client can self-throttle.","tags":["Datasets"],"security":[],"responses":{"200":{"description":"Reviews envelope","headers":{"API-Version":{"description":"Major version of the API contract that produced this response.","schema":{"type":"string","examples":["1"]}},"RateLimit-Policy":{"description":"Advisory quota for this endpoint family, in the draft-ietf-httpapi-ratelimit-headers format.","schema":{"type":"string","examples":["\"dataset\";q=60;w=60"]}},"RateLimit":{"description":"Remaining requests (r) and seconds until the window resets (t).","schema":{"type":"string","examples":["\"dataset\";r=59;t=60"]}},"RateLimit-Limit":{"description":"Requests allowed per window.","schema":{"type":"integer","examples":[60]}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer","examples":[59]}},"RateLimit-Reset":{"description":"Seconds until the current window resets.","schema":{"type":"integer","examples":[60]}},"ETag":{"description":"Strong validator. Send it back as If-None-Match to get a 304.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReviewsDataset"}}}},"304":{"description":"Not modified — the ETag sent in If-None-Match still matches.","headers":{"API-Version":{"description":"Major version of the API contract that produced this response.","schema":{"type":"string","examples":["1"]}},"RateLimit-Policy":{"description":"Advisory quota for this endpoint family, in the draft-ietf-httpapi-ratelimit-headers format.","schema":{"type":"string","examples":["\"dataset\";q=60;w=60"]}},"RateLimit":{"description":"Remaining requests (r) and seconds until the window resets (t).","schema":{"type":"string","examples":["\"dataset\";r=59;t=60"]}},"RateLimit-Limit":{"description":"Requests allowed per window.","schema":{"type":"integer","examples":[60]}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer","examples":[59]}},"RateLimit-Reset":{"description":"Seconds until the current window resets.","schema":{"type":"integer","examples":[60]}},"ETag":{"description":"Strong validator. Send it back as If-None-Match to get a 304.","schema":{"type":"string"}}}},"429":{"description":"Rate limit exceeded. Retry-After carries the wait in seconds.","headers":{"API-Version":{"description":"Major version of the API contract that produced this response.","schema":{"type":"string","examples":["1"]}},"RateLimit-Policy":{"description":"Advisory quota for this endpoint family, in the draft-ietf-httpapi-ratelimit-headers format.","schema":{"type":"string","examples":["\"dataset\";q=60;w=60"]}},"RateLimit":{"description":"Remaining requests (r) and seconds until the window resets (t).","schema":{"type":"string","examples":["\"dataset\";r=59;t=60"]}},"RateLimit-Limit":{"description":"Requests allowed per window.","schema":{"type":"integer","examples":[60]}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer","examples":[59]}},"RateLimit-Reset":{"description":"Seconds until the current window resets.","schema":{"type":"integer","examples":[60]}},"Retry-After":{"description":"Seconds to wait before retrying this endpoint family.","schema":{"type":"integer","examples":[60]}}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Server error","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/agents/context":{"get":{"operationId":"getAgentContextV1","summary":"Filterable JSON site index for research agents","description":"Returns the aicoolies catalog as a typed JSON index of tools, comparisons, reviews, stacks, use cases, categories, and tags. Supports conditional GET via If-None-Match. CORS is * for GET and OPTIONS. Responses carry RateLimit headers so a client can self-throttle. Version-pinned alias of /api/agents/context; both paths run the same handler. Versioning and deprecation policy: https://aicoolies.com/developers#versioning.","tags":["Agents"],"security":[],"parameters":[{"name":"category","in":"query","required":false,"description":"Category slug. Limits tools and related records to that category.","schema":{"type":"string","examples":["ai-native-ides"]}},{"name":"include","in":"query","required":false,"description":"Comma-separated collections to include. Allowed: tools, comparisons, reviews, stacks (deprecated, always empty), use_cases, categories, tags.","schema":{"type":"string","examples":["tools,reviews"]}},{"name":"compact","in":"query","required":false,"description":"When true, each included collection is an array of slugs only.","schema":{"type":"boolean","default":false}}],"responses":{"200":{"description":"Catalog index","headers":{"API-Version":{"description":"Major version of the API contract that produced this response.","schema":{"type":"string","examples":["1"]}},"RateLimit-Policy":{"description":"Advisory quota for this endpoint family, in the draft-ietf-httpapi-ratelimit-headers format.","schema":{"type":"string","examples":["\"agent-api\";q=120;w=60"]}},"RateLimit":{"description":"Remaining requests (r) and seconds until the window resets (t).","schema":{"type":"string","examples":["\"agent-api\";r=119;t=60"]}},"RateLimit-Limit":{"description":"Requests allowed per window.","schema":{"type":"integer","examples":[120]}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer","examples":[119]}},"RateLimit-Reset":{"description":"Seconds until the current window resets.","schema":{"type":"integer","examples":[60]}},"ETag":{"description":"Strong validator. Send it back as If-None-Match to get a 304.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/AgentContext"},{"$ref":"#/components/schemas/AgentContextCompact"}]}}}},"304":{"description":"Not modified — the ETag sent in If-None-Match still matches.","headers":{"API-Version":{"description":"Major version of the API contract that produced this response.","schema":{"type":"string","examples":["1"]}},"RateLimit-Policy":{"description":"Advisory quota for this endpoint family, in the draft-ietf-httpapi-ratelimit-headers format.","schema":{"type":"string","examples":["\"agent-api\";q=120;w=60"]}},"RateLimit":{"description":"Remaining requests (r) and seconds until the window resets (t).","schema":{"type":"string","examples":["\"agent-api\";r=119;t=60"]}},"RateLimit-Limit":{"description":"Requests allowed per window.","schema":{"type":"integer","examples":[120]}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer","examples":[119]}},"RateLimit-Reset":{"description":"Seconds until the current window resets.","schema":{"type":"integer","examples":[60]}},"ETag":{"description":"Strong validator. Send it back as If-None-Match to get a 304.","schema":{"type":"string"}}}},"400":{"description":"Invalid include value or unknown category slug","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limit exceeded. Retry-After carries the wait in seconds.","headers":{"API-Version":{"description":"Major version of the API contract that produced this response.","schema":{"type":"string","examples":["1"]}},"RateLimit-Policy":{"description":"Advisory quota for this endpoint family, in the draft-ietf-httpapi-ratelimit-headers format.","schema":{"type":"string","examples":["\"agent-api\";q=120;w=60"]}},"RateLimit":{"description":"Remaining requests (r) and seconds until the window resets (t).","schema":{"type":"string","examples":["\"agent-api\";r=119;t=60"]}},"RateLimit-Limit":{"description":"Requests allowed per window.","schema":{"type":"integer","examples":[120]}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer","examples":[119]}},"RateLimit-Reset":{"description":"Seconds until the current window resets.","schema":{"type":"integer","examples":[60]}},"Retry-After":{"description":"Seconds to wait before retrying this endpoint family.","schema":{"type":"integer","examples":[60]}}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Server error","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/agents/meta":{"get":{"operationId":"getAgentMetaV1","summary":"Collection counts and freshness probe","description":"Cheap freshness document for agents. The ETag matches /api/agents/context so a client can skip the full payload. Supports conditional GET via If-None-Match. CORS is * for GET and OPTIONS. Responses carry RateLimit headers so a client can self-throttle. Version-pinned alias of /api/agents/meta; both paths run the same handler. Versioning and deprecation policy: https://aicoolies.com/developers#versioning.","tags":["Agents"],"security":[],"responses":{"200":{"description":"Counts and latest-updated timestamps","headers":{"API-Version":{"description":"Major version of the API contract that produced this response.","schema":{"type":"string","examples":["1"]}},"RateLimit-Policy":{"description":"Advisory quota for this endpoint family, in the draft-ietf-httpapi-ratelimit-headers format.","schema":{"type":"string","examples":["\"agent-api\";q=120;w=60"]}},"RateLimit":{"description":"Remaining requests (r) and seconds until the window resets (t).","schema":{"type":"string","examples":["\"agent-api\";r=119;t=60"]}},"RateLimit-Limit":{"description":"Requests allowed per window.","schema":{"type":"integer","examples":[120]}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer","examples":[119]}},"RateLimit-Reset":{"description":"Seconds until the current window resets.","schema":{"type":"integer","examples":[60]}},"ETag":{"description":"Strong validator. Send it back as If-None-Match to get a 304.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentMeta"}}}},"304":{"description":"Not modified — the ETag sent in If-None-Match still matches.","headers":{"API-Version":{"description":"Major version of the API contract that produced this response.","schema":{"type":"string","examples":["1"]}},"RateLimit-Policy":{"description":"Advisory quota for this endpoint family, in the draft-ietf-httpapi-ratelimit-headers format.","schema":{"type":"string","examples":["\"agent-api\";q=120;w=60"]}},"RateLimit":{"description":"Remaining requests (r) and seconds until the window resets (t).","schema":{"type":"string","examples":["\"agent-api\";r=119;t=60"]}},"RateLimit-Limit":{"description":"Requests allowed per window.","schema":{"type":"integer","examples":[120]}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer","examples":[119]}},"RateLimit-Reset":{"description":"Seconds until the current window resets.","schema":{"type":"integer","examples":[60]}},"ETag":{"description":"Strong validator. Send it back as If-None-Match to get a 304.","schema":{"type":"string"}}}},"429":{"description":"Rate limit exceeded. Retry-After carries the wait in seconds.","headers":{"API-Version":{"description":"Major version of the API contract that produced this response.","schema":{"type":"string","examples":["1"]}},"RateLimit-Policy":{"description":"Advisory quota for this endpoint family, in the draft-ietf-httpapi-ratelimit-headers format.","schema":{"type":"string","examples":["\"agent-api\";q=120;w=60"]}},"RateLimit":{"description":"Remaining requests (r) and seconds until the window resets (t).","schema":{"type":"string","examples":["\"agent-api\";r=119;t=60"]}},"RateLimit-Limit":{"description":"Requests allowed per window.","schema":{"type":"integer","examples":[120]}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer","examples":[119]}},"RateLimit-Reset":{"description":"Seconds until the current window resets.","schema":{"type":"integer","examples":[60]}},"Retry-After":{"description":"Seconds to wait before retrying this endpoint family.","schema":{"type":"integer","examples":[60]}}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Server error","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/agents/exclusion":{"get":{"operationId":"getAgentExclusionV1","summary":"Slug lists for exclusion-style sync","description":"Returns slug arrays for tools, comparisons, and reviews so an agent can detect deletions. Supports conditional GET via If-None-Match. CORS is * for GET and OPTIONS. Responses carry RateLimit headers so a client can self-throttle. Version-pinned alias of /api/agents/exclusion; both paths run the same handler. Versioning and deprecation policy: https://aicoolies.com/developers#versioning.","tags":["Agents"],"security":[],"parameters":[{"name":"category","in":"query","required":false,"description":"Optional category slug filter.","schema":{"type":"string","examples":["ai-cli-agents"]}}],"responses":{"200":{"description":"Slug lists","headers":{"API-Version":{"description":"Major version of the API contract that produced this response.","schema":{"type":"string","examples":["1"]}},"RateLimit-Policy":{"description":"Advisory quota for this endpoint family, in the draft-ietf-httpapi-ratelimit-headers format.","schema":{"type":"string","examples":["\"agent-api\";q=120;w=60"]}},"RateLimit":{"description":"Remaining requests (r) and seconds until the window resets (t).","schema":{"type":"string","examples":["\"agent-api\";r=119;t=60"]}},"RateLimit-Limit":{"description":"Requests allowed per window.","schema":{"type":"integer","examples":[120]}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer","examples":[119]}},"RateLimit-Reset":{"description":"Seconds until the current window resets.","schema":{"type":"integer","examples":[60]}},"ETag":{"description":"Strong validator. Send it back as If-None-Match to get a 304.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentExclusion"}}}},"304":{"description":"Not modified — the ETag sent in If-None-Match still matches.","headers":{"API-Version":{"description":"Major version of the API contract that produced this response.","schema":{"type":"string","examples":["1"]}},"RateLimit-Policy":{"description":"Advisory quota for this endpoint family, in the draft-ietf-httpapi-ratelimit-headers format.","schema":{"type":"string","examples":["\"agent-api\";q=120;w=60"]}},"RateLimit":{"description":"Remaining requests (r) and seconds until the window resets (t).","schema":{"type":"string","examples":["\"agent-api\";r=119;t=60"]}},"RateLimit-Limit":{"description":"Requests allowed per window.","schema":{"type":"integer","examples":[120]}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer","examples":[119]}},"RateLimit-Reset":{"description":"Seconds until the current window resets.","schema":{"type":"integer","examples":[60]}},"ETag":{"description":"Strong validator. Send it back as If-None-Match to get a 304.","schema":{"type":"string"}}}},"400":{"description":"Unknown category slug","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limit exceeded. Retry-After carries the wait in seconds.","headers":{"API-Version":{"description":"Major version of the API contract that produced this response.","schema":{"type":"string","examples":["1"]}},"RateLimit-Policy":{"description":"Advisory quota for this endpoint family, in the draft-ietf-httpapi-ratelimit-headers format.","schema":{"type":"string","examples":["\"agent-api\";q=120;w=60"]}},"RateLimit":{"description":"Remaining requests (r) and seconds until the window resets (t).","schema":{"type":"string","examples":["\"agent-api\";r=119;t=60"]}},"RateLimit-Limit":{"description":"Requests allowed per window.","schema":{"type":"integer","examples":[120]}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer","examples":[119]}},"RateLimit-Reset":{"description":"Seconds until the current window resets.","schema":{"type":"integer","examples":[60]}},"Retry-After":{"description":"Seconds to wait before retrying this endpoint family.","schema":{"type":"integer","examples":[60]}}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Server error","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/data/tools.json":{"get":{"operationId":"getToolsDatasetV1","summary":"CC-BY 4.0 tools dataset","description":"Full aicoolies tool catalog as JSON. Licensed CC-BY 4.0, attribution aicoolies.com. The community namespace contains anonymous public aggregates that never alter editorial Score or verdicts. content_updated_at and verified_at have distinct semantics; as_of remains a deprecated v1 alias of content_updated_at. Supports conditional GET via If-None-Match. CORS is * for GET and OPTIONS. Responses carry RateLimit headers so a client can self-throttle. Version-pinned alias of /data/tools.json; both paths run the same handler. Versioning and deprecation policy: https://aicoolies.com/developers#versioning.","tags":["Datasets"],"security":[],"responses":{"200":{"description":"Tools envelope","headers":{"API-Version":{"description":"Major version of the API contract that produced this response.","schema":{"type":"string","examples":["1"]}},"RateLimit-Policy":{"description":"Advisory quota for this endpoint family, in the draft-ietf-httpapi-ratelimit-headers format.","schema":{"type":"string","examples":["\"dataset\";q=60;w=60"]}},"RateLimit":{"description":"Remaining requests (r) and seconds until the window resets (t).","schema":{"type":"string","examples":["\"dataset\";r=59;t=60"]}},"RateLimit-Limit":{"description":"Requests allowed per window.","schema":{"type":"integer","examples":[60]}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer","examples":[59]}},"RateLimit-Reset":{"description":"Seconds until the current window resets.","schema":{"type":"integer","examples":[60]}},"ETag":{"description":"Strong validator. Send it back as If-None-Match to get a 304.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ToolsDataset"}}}},"304":{"description":"Not modified — the ETag sent in If-None-Match still matches.","headers":{"API-Version":{"description":"Major version of the API contract that produced this response.","schema":{"type":"string","examples":["1"]}},"RateLimit-Policy":{"description":"Advisory quota for this endpoint family, in the draft-ietf-httpapi-ratelimit-headers format.","schema":{"type":"string","examples":["\"dataset\";q=60;w=60"]}},"RateLimit":{"description":"Remaining requests (r) and seconds until the window resets (t).","schema":{"type":"string","examples":["\"dataset\";r=59;t=60"]}},"RateLimit-Limit":{"description":"Requests allowed per window.","schema":{"type":"integer","examples":[60]}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer","examples":[59]}},"RateLimit-Reset":{"description":"Seconds until the current window resets.","schema":{"type":"integer","examples":[60]}},"ETag":{"description":"Strong validator. Send it back as If-None-Match to get a 304.","schema":{"type":"string"}}}},"429":{"description":"Rate limit exceeded. Retry-After carries the wait in seconds.","headers":{"API-Version":{"description":"Major version of the API contract that produced this response.","schema":{"type":"string","examples":["1"]}},"RateLimit-Policy":{"description":"Advisory quota for this endpoint family, in the draft-ietf-httpapi-ratelimit-headers format.","schema":{"type":"string","examples":["\"dataset\";q=60;w=60"]}},"RateLimit":{"description":"Remaining requests (r) and seconds until the window resets (t).","schema":{"type":"string","examples":["\"dataset\";r=59;t=60"]}},"RateLimit-Limit":{"description":"Requests allowed per window.","schema":{"type":"integer","examples":[60]}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer","examples":[59]}},"RateLimit-Reset":{"description":"Seconds until the current window resets.","schema":{"type":"integer","examples":[60]}},"Retry-After":{"description":"Seconds to wait before retrying this endpoint family.","schema":{"type":"integer","examples":[60]}}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Server error","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/data/comparisons.json":{"get":{"operationId":"getComparisonsDatasetV1","summary":"CC-BY 4.0 comparisons dataset","description":"Published aicoolies comparisons as JSON with tool slugs, content update, source check, and editorial verification dates. The deprecated as_of alias remains for v1 readers. Licensed CC-BY 4.0. Supports conditional GET via If-None-Match. CORS is * for GET and OPTIONS. Responses carry RateLimit headers so a client can self-throttle. Version-pinned alias of /data/comparisons.json; both paths run the same handler. Versioning and deprecation policy: https://aicoolies.com/developers#versioning.","tags":["Datasets"],"security":[],"responses":{"200":{"description":"Comparisons envelope","headers":{"API-Version":{"description":"Major version of the API contract that produced this response.","schema":{"type":"string","examples":["1"]}},"RateLimit-Policy":{"description":"Advisory quota for this endpoint family, in the draft-ietf-httpapi-ratelimit-headers format.","schema":{"type":"string","examples":["\"dataset\";q=60;w=60"]}},"RateLimit":{"description":"Remaining requests (r) and seconds until the window resets (t).","schema":{"type":"string","examples":["\"dataset\";r=59;t=60"]}},"RateLimit-Limit":{"description":"Requests allowed per window.","schema":{"type":"integer","examples":[60]}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer","examples":[59]}},"RateLimit-Reset":{"description":"Seconds until the current window resets.","schema":{"type":"integer","examples":[60]}},"ETag":{"description":"Strong validator. Send it back as If-None-Match to get a 304.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ComparisonsDataset"}}}},"304":{"description":"Not modified — the ETag sent in If-None-Match still matches.","headers":{"API-Version":{"description":"Major version of the API contract that produced this response.","schema":{"type":"string","examples":["1"]}},"RateLimit-Policy":{"description":"Advisory quota for this endpoint family, in the draft-ietf-httpapi-ratelimit-headers format.","schema":{"type":"string","examples":["\"dataset\";q=60;w=60"]}},"RateLimit":{"description":"Remaining requests (r) and seconds until the window resets (t).","schema":{"type":"string","examples":["\"dataset\";r=59;t=60"]}},"RateLimit-Limit":{"description":"Requests allowed per window.","schema":{"type":"integer","examples":[60]}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer","examples":[59]}},"RateLimit-Reset":{"description":"Seconds until the current window resets.","schema":{"type":"integer","examples":[60]}},"ETag":{"description":"Strong validator. Send it back as If-None-Match to get a 304.","schema":{"type":"string"}}}},"429":{"description":"Rate limit exceeded. Retry-After carries the wait in seconds.","headers":{"API-Version":{"description":"Major version of the API contract that produced this response.","schema":{"type":"string","examples":["1"]}},"RateLimit-Policy":{"description":"Advisory quota for this endpoint family, in the draft-ietf-httpapi-ratelimit-headers format.","schema":{"type":"string","examples":["\"dataset\";q=60;w=60"]}},"RateLimit":{"description":"Remaining requests (r) and seconds until the window resets (t).","schema":{"type":"string","examples":["\"dataset\";r=59;t=60"]}},"RateLimit-Limit":{"description":"Requests allowed per window.","schema":{"type":"integer","examples":[60]}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer","examples":[59]}},"RateLimit-Reset":{"description":"Seconds until the current window resets.","schema":{"type":"integer","examples":[60]}},"Retry-After":{"description":"Seconds to wait before retrying this endpoint family.","schema":{"type":"integer","examples":[60]}}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Server error","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/data/reviews.json":{"get":{"operationId":"getReviewsDatasetV1","summary":"CC-BY 4.0 reviews dataset","description":"Published aicoolies editorial reviews with 0–100 scores for overall, speed, privacy, and developer experience. Licensed CC-BY 4.0. Supports conditional GET via If-None-Match. CORS is * for GET and OPTIONS. Responses carry RateLimit headers so a client can self-throttle. Version-pinned alias of /data/reviews.json; both paths run the same handler. Versioning and deprecation policy: https://aicoolies.com/developers#versioning.","tags":["Datasets"],"security":[],"responses":{"200":{"description":"Reviews envelope","headers":{"API-Version":{"description":"Major version of the API contract that produced this response.","schema":{"type":"string","examples":["1"]}},"RateLimit-Policy":{"description":"Advisory quota for this endpoint family, in the draft-ietf-httpapi-ratelimit-headers format.","schema":{"type":"string","examples":["\"dataset\";q=60;w=60"]}},"RateLimit":{"description":"Remaining requests (r) and seconds until the window resets (t).","schema":{"type":"string","examples":["\"dataset\";r=59;t=60"]}},"RateLimit-Limit":{"description":"Requests allowed per window.","schema":{"type":"integer","examples":[60]}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer","examples":[59]}},"RateLimit-Reset":{"description":"Seconds until the current window resets.","schema":{"type":"integer","examples":[60]}},"ETag":{"description":"Strong validator. Send it back as If-None-Match to get a 304.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReviewsDataset"}}}},"304":{"description":"Not modified — the ETag sent in If-None-Match still matches.","headers":{"API-Version":{"description":"Major version of the API contract that produced this response.","schema":{"type":"string","examples":["1"]}},"RateLimit-Policy":{"description":"Advisory quota for this endpoint family, in the draft-ietf-httpapi-ratelimit-headers format.","schema":{"type":"string","examples":["\"dataset\";q=60;w=60"]}},"RateLimit":{"description":"Remaining requests (r) and seconds until the window resets (t).","schema":{"type":"string","examples":["\"dataset\";r=59;t=60"]}},"RateLimit-Limit":{"description":"Requests allowed per window.","schema":{"type":"integer","examples":[60]}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer","examples":[59]}},"RateLimit-Reset":{"description":"Seconds until the current window resets.","schema":{"type":"integer","examples":[60]}},"ETag":{"description":"Strong validator. Send it back as If-None-Match to get a 304.","schema":{"type":"string"}}}},"429":{"description":"Rate limit exceeded. Retry-After carries the wait in seconds.","headers":{"API-Version":{"description":"Major version of the API contract that produced this response.","schema":{"type":"string","examples":["1"]}},"RateLimit-Policy":{"description":"Advisory quota for this endpoint family, in the draft-ietf-httpapi-ratelimit-headers format.","schema":{"type":"string","examples":["\"dataset\";q=60;w=60"]}},"RateLimit":{"description":"Remaining requests (r) and seconds until the window resets (t).","schema":{"type":"string","examples":["\"dataset\";r=59;t=60"]}},"RateLimit-Limit":{"description":"Requests allowed per window.","schema":{"type":"integer","examples":[60]}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer","examples":[59]}},"RateLimit-Reset":{"description":"Seconds until the current window resets.","schema":{"type":"integer","examples":[60]}},"Retry-After":{"description":"Seconds to wait before retrying this endpoint family.","schema":{"type":"integer","examples":[60]}}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Server error","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/health":{"get":{"operationId":"getHealth","summary":"Process and database health","description":"Returns ok when the app can reach PostgreSQL. Used by uptime checks and the container healthcheck, not by agents for catalog data.","tags":["Ops"],"security":[],"responses":{"200":{"description":"Healthy","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Health"}}}},"503":{"description":"Database unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HealthError"}}}}}}},"/openapi.json":{"get":{"operationId":"getOpenApiDocument","summary":"OpenAPI 3.1 document","description":"Machine-readable description of the aicoolies public API, including this operation. YAML alias: /api/openapi.yaml.","tags":["Discovery"],"security":[],"responses":{"200":{"description":"OpenAPI 3.1 object","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpenApiDocument"}}}}}}},"/.well-known/mcp.json":{"get":{"operationId":"getMcpManifest","summary":"MCP discovery manifest","description":"Short MCP server discovery document (RFC 8615 well-known URI): name, description, icon, and the Streamable HTTP endpoint. Richer variants live at /.well-known/mcp and /.well-known/mcp/server-card.json.","tags":["MCP"],"security":[],"responses":{"200":{"description":"Manifest JSON","content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpManifest"}}}}}}},"/.well-known/mcp":{"get":{"operationId":"getMcpDiscovery","summary":"MCP endpoint and capability discovery","description":"Lists the protocol versions this aicoolies MCP server speaks, its transport endpoints, its capabilities, and its authentication requirements (none for the public catalog tools).","tags":["MCP"],"security":[],"responses":{"200":{"description":"Discovery document","content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpDiscovery"}}}}}}},"/.well-known/mcp/server-card.json":{"get":{"operationId":"getMcpServerCard","summary":"MCP server card","description":"Server card describing the aicoolies MCP server: protocol versions, transport, capabilities, and the full tool list with input schemas, so a client can inspect the tools before connecting.","tags":["MCP"],"security":[],"responses":{"200":{"description":"Server card JSON","content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpServerCard"}}}}}}},"/mcp":{"post":{"operationId":"postMcp","summary":"MCP Streamable HTTP endpoint","description":"JSON-RPC 2.0 MCP server over Streamable HTTP. Anonymous initialize, tools/list, and catalog calls remain compatible. submit_correction/report_price_change require correction:write; sync_stack requires stack:write; reply_to_room requires room:write; submit_run requires run:write; and upvote_tool requires vote:write. A signed Mcp-Session-Id carries clientInfo.name without server-side session state. Accept must list application/json and text/event-stream.","tags":["MCP"],"security":[{},{"personalAccessToken":[]}],"parameters":[{"name":"MCP-Protocol-Version","in":"header","required":false,"description":"Protocol version negotiated during initialize. An unsupported value is answered with HTTP 400.","schema":{"type":"string","examples":["2025-11-25"]}}],"requestBody":{"required":true,"description":"JSON-RPC 2.0 request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JsonRpcRequest"}}}},"responses":{"200":{"description":"JSON-RPC 2.0 response","headers":{"MCP-Protocol-Version":{"description":"The version this response speaks, after negotiation.","schema":{"type":"string","examples":["2025-11-25"]}},"API-Version":{"description":"Major version of the API contract that produced this response.","schema":{"type":"string","examples":["1"]}},"RateLimit-Policy":{"description":"Advisory quota for this endpoint family, in the draft-ietf-httpapi-ratelimit-headers format.","schema":{"type":"string","examples":["\"mcp\";q=120;w=60"]}},"RateLimit":{"description":"Remaining requests (r) and seconds until the window resets (t).","schema":{"type":"string","examples":["\"mcp\";r=119;t=60"]}},"RateLimit-Limit":{"description":"Requests allowed per window.","schema":{"type":"integer","examples":[120]}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer","examples":[119]}},"RateLimit-Reset":{"description":"Seconds until the current window resets.","schema":{"type":"integer","examples":[60]}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/JsonRpcResponse"}}}},"202":{"description":"Notification or response accepted; no body."},"400":{"description":"Parse error, invalid JSON-RPC envelope, or unsupported protocol version","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JsonRpcResponse"}}}},"401":{"description":"Write tool is missing a valid active bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JsonRpcResponse"}}}},"403":{"description":"Bearer token does not have the write tool scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JsonRpcResponse"}}}},"406":{"description":"Accept does not explicitly include both application/json and text/event-stream.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JsonRpcResponse"}}}},"429":{"description":"Rate limit exceeded. Retry-After carries the wait in seconds.","headers":{"API-Version":{"description":"Major version of the API contract that produced this response.","schema":{"type":"string","examples":["1"]}},"RateLimit-Policy":{"description":"Advisory quota for this endpoint family, in the draft-ietf-httpapi-ratelimit-headers format.","schema":{"type":"string","examples":["\"mcp\";q=120;w=60"]}},"RateLimit":{"description":"Remaining requests (r) and seconds until the window resets (t).","schema":{"type":"string","examples":["\"mcp\";r=119;t=60"]}},"RateLimit-Limit":{"description":"Requests allowed per window.","schema":{"type":"integer","examples":[120]}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer","examples":[119]}},"RateLimit-Reset":{"description":"Seconds until the current window resets.","schema":{"type":"integer","examples":[60]}},"Retry-After":{"description":"Seconds to wait before retrying this endpoint family.","schema":{"type":"integer","examples":[60]}}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/.well-known/oauth-protected-resource":{"get":{"operationId":"getOAuthProtectedResourceMetadata","summary":"OAuth 2.0 protected resource metadata","description":"RFC 9728 metadata for the aicoolies API resource. Public catalog reads need no authorization; MCP writes use GitHub-bound scoped personal access tokens, while human account routes use a first-party session.","tags":["Discovery"],"security":[],"responses":{"200":{"description":"Protected resource metadata","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OAuthProtectedResourceMetadata"}}}}}}},"/llms.txt":{"get":{"operationId":"getLlmsTxt","summary":"llms.txt overview for language models","description":"Markdown overview of aicoolies: what the catalog covers, the named developer resources, and the machine-readable files. /llms.txt is the short index; /llms-full.txt expands the core catalog, while sitemap.xml is the complete URL inventory.","tags":["Discovery"],"security":[],"responses":{"200":{"description":"llms.txt body","content":{"text/plain":{"schema":{"type":"string"}}}}}}},"/tools/{slug}":{"get":{"operationId":"getToolPage","summary":"Tool page as HTML or markdown","description":"Canonical aicoolies page for one tool. Supported public catalog and guide URLs honour content negotiation: send Accept: text/markdown for the markdown rendition, or append .md to the path. Responses carry Vary: Accept so a shared cache keeps the two renditions apart.","tags":["Pages"],"security":[],"parameters":[{"name":"slug","in":"path","required":true,"description":"Tool slug, for example cursor.","schema":{"type":"string","examples":["cursor"]}},{"name":"Accept","in":"header","required":false,"description":"text/html (default) or text/markdown. An Accept header that excludes both is answered with HTTP 406.","schema":{"type":"string","enum":["text/html","text/markdown"],"default":"text/html"}}],"responses":{"200":{"description":"Tool page in the negotiated representation","headers":{"Vary":{"description":"Always includes Accept and Accept-Encoding.","schema":{"type":"string","examples":["Accept, Accept-Encoding"]}}},"content":{"text/html":{"schema":{"type":"string"}},"text/markdown":{"schema":{"type":"string"}}}},"404":{"description":"No such tool. The markdown rendition lists recovery links.","content":{"text/html":{"schema":{"type":"string"}},"text/markdown":{"schema":{"type":"string"}}}},"406":{"description":"Neither text/html nor text/markdown is acceptable to the client.","content":{"text/plain":{"schema":{"type":"string"}}}}}}}},"components":{"schemas":{"Problem":{"type":"object","description":"RFC 9457 problem details. Served as application/problem+json on every 4xx and 5xx from the public API. Branch on `code`, which is a closed set; `detail` is prose for humans.","required":["type","title","status","code","detail"],"properties":{"type":{"type":"string","format":"uri","description":"Stable URI for this error class; resolves to the docs anchor."},"title":{"type":"string","description":"Short, human-readable summary of the error class."},"status":{"type":"integer","description":"HTTP status code, repeated for convenience."},"code":{"type":"string","description":"Machine-readable error code.","enum":["invalid_parameter","unknown_category","malformed_request","unsupported_protocol_version","not_found","method_not_allowed","rate_limited","internal_error","database_unavailable"]},"detail":{"type":"string","description":"What went wrong for this specific request."},"error":{"type":"string","description":"Mirror of detail, kept for clients written before the move to RFC 9457."},"instance":{"type":"string","description":"Path of the request that produced the error."},"policy":{"type":"string","description":"Rate-limit policy name, on 429 only."},"retry_after_seconds":{"type":"integer","description":"Seconds to wait before retrying, on 429 only."}}},"AgentContext":{"type":"object","required":["schema_version","generated_at","base_url","counts","payload_etag"],"properties":{"schema_version":{"type":"integer","description":"Additive response schema version. Existing v2 fields remain available as compatibility aliases."},"generated_at":{"type":"string","format":"date-time","description":"Deterministic catalog snapshot timestamp, not the request wall-clock time. Stable while payload_etag is stable."},"base_url":{"type":"string","format":"uri"},"counts":{"$ref":"#/components/schemas/CatalogCounts"},"payload_etag":{"type":"string","description":"Validator for the default unfiltered context. Filtered and compact representations can carry a different HTTP ETag."},"tools":{"type":"array","items":{"$ref":"#/components/schemas/AgentTool"}},"comparisons":{"type":"array","items":{"$ref":"#/components/schemas/AgentComparison"}},"reviews":{"type":"array","items":{"$ref":"#/components/schemas/AgentReview"}},"stacks":{"type":"array","deprecated":true,"description":"Editorial stacks were retired; this field is kept for v1 compatibility and is always empty.","items":{"$ref":"#/components/schemas/AgentStack"}},"use_cases":{"type":"array","items":{"$ref":"#/components/schemas/AgentUseCase"}},"categories":{"type":"array","items":{"$ref":"#/components/schemas/AgentCategory"}},"tags":{"type":"array","items":{"$ref":"#/components/schemas/AgentTag"}}}},"AgentContextCompact":{"type":"object","description":"Slug-only representation returned by /api/agents/context?compact=true. Omitted collections remain absent when include is used.","required":["schema_version","generated_at","base_url","counts","payload_etag"],"properties":{"schema_version":{"type":"integer"},"generated_at":{"type":"string","format":"date-time","description":"Deterministic catalog snapshot timestamp."},"base_url":{"type":"string","format":"uri"},"counts":{"$ref":"#/components/schemas/CatalogCounts"},"payload_etag":{"type":"string","description":"Validator for the default unfiltered full catalog snapshot."},"tools":{"type":"array","items":{"type":"string"}},"comparisons":{"type":"array","items":{"type":"string"}},"reviews":{"type":"array","items":{"type":"string"}},"stacks":{"type":"array","deprecated":true,"description":"Editorial stacks were retired; this field is kept for v1 compatibility and is always empty.","items":{"type":"string"}},"use_cases":{"type":"array","items":{"type":"string"}},"categories":{"type":"array","items":{"type":"string"}},"tags":{"type":"array","items":{"type":"string"}}}},"AgentTool":{"type":"object","required":["slug","name","status"],"properties":{"slug":{"type":"string"},"name":{"type":"string"},"status":{"type":"string","enum":["active","graveyard"]},"tagline":{"type":["string","null"]},"short_description":{"type":["string","null"]},"official_url":{"type":["string","null"],"format":"uri"},"categories":{"type":"array","items":{"type":"string"}},"tags":{"type":"array","items":{"type":"string"}},"use_cases":{"type":"array","items":{"type":"string"}},"is_open_source":{"type":"boolean"},"license":{"type":"string","enum":["open-source","source-available","proprietary"],"description":"License category. Empty CMS license follows the open-source checkbox: checked is open-source, unchecked is proprietary."},"is_recommended":{"type":"boolean"},"pricing_model":{"type":["string","null"]},"pricing_summary":{"type":["string","null"]},"pricing_plans":{"type":"array","items":{"$ref":"#/components/schemas/PublicPricingPlan"}},"sources":{"type":"array","items":{"$ref":"#/components/schemas/PublicSource"}},"alternatives":{"$ref":"#/components/schemas/ExplicitAlternatives"},"content_updated_at":{"type":"string","format":"date-time","description":"Editorial content timestamp (contentModifiedAt). Falls back to the CMS updatedAt when that stamp is unset."},"verified_at":{"type":["string","null"],"format":"date-time"},"source_checked_at":{"type":["string","null"],"format":"date-time","description":"Most recent date when all cited primary sources were rechecked."},"updated_at":{"type":"string","format":"date-time","description":"Backward-compatible v2 alias of content_updated_at."}}},"AgentComparison":{"type":"object","required":["slug","title"],"properties":{"slug":{"type":"string"},"title":{"type":"string"},"intro":{"type":["string","null"]},"verdict":{"type":["string","null"]},"tool_slugs":{"type":"array","items":{"type":"string"}},"winner_tool_slug":{"type":["string","null"]},"sources":{"type":"array","items":{"$ref":"#/components/schemas/PublicSource"}},"content_updated_at":{"type":"string","format":"date-time","description":"Editorial content timestamp (contentModifiedAt). When unset, publishedAt, then createdAt, then CMS updatedAt."},"verified_at":{"type":["string","null"],"format":"date-time"},"source_checked_at":{"type":["string","null"],"format":"date-time"},"updated_at":{"type":"string","format":"date-time","description":"Backward-compatible v2 alias of content_updated_at."}}},"AgentReview":{"type":"object","required":["slug"],"properties":{"slug":{"type":"string"},"title":{"type":"string"},"tool_slug":{"type":["string","null"]},"summary":{"type":["string","null"]},"verdict":{"type":["string","null"]},"score_overall":{"type":["integer","null"]},"score_speed":{"type":["integer","null"]},"score_privacy":{"type":["integer","null"]},"score_dev_experience":{"type":["integer","null"]},"evidence_status":{"type":["string","null"],"enum":["not-evidenced","partial","verified",null]},"evidence_badge":{"type":"string","enum":["verified","documented","partial","not-evidenced","unclassified"],"description":"Resolved public evidence label. tested_at, tested_version, and test_environment are null when this is documented."},"rubric_version":{"type":["string","null"]},"tested_at":{"type":["string","null"],"format":"date-time","description":"Hands-on test date. Null when evidence_badge is documented."},"tested_version":{"type":["string","null"],"description":"Tested product version or dated SaaS state. Null when evidence_badge is documented."},"test_environment":{"type":["string","null"],"description":"Reproducibility context for a hands-on record. Null when evidence_badge is documented."},"test_artifact_url":{"type":["string","null"],"format":"uri"},"sources":{"type":"array","items":{"$ref":"#/components/schemas/PublicSource"}},"content_updated_at":{"type":"string","format":"date-time","description":"Editorial content timestamp (contentModifiedAt). When unset, publishedAt, then createdAt, then CMS updatedAt."},"verified_at":{"type":["string","null"],"format":"date-time"},"source_checked_at":{"type":["string","null"],"format":"date-time"},"updated_at":{"type":"string","format":"date-time","description":"Backward-compatible v2 alias of content_updated_at."}}},"AgentStack":{"type":"object","deprecated":true,"description":"Editorial stacks were retired; this field is kept for v1 compatibility and is always empty.","required":["slug","title"],"properties":{"slug":{"type":"string"},"title":{"type":"string"},"intro":{"type":["string","null"]},"verdict":{"type":["string","null"]},"tool_slugs":{"type":"array","items":{"type":"string"}},"budget_range":{"type":["string","null"]},"sources":{"type":"array","items":{"$ref":"#/components/schemas/PublicSource"}},"content_updated_at":{"type":"string","format":"date-time"},"verified_at":{"type":["string","null"],"format":"date-time"},"source_checked_at":{"type":["string","null"],"format":"date-time"},"updated_at":{"type":"string","format":"date-time","description":"Backward-compatible v2 alias of content_updated_at."}}},"AgentUseCase":{"type":"object","required":["slug"],"properties":{"slug":{"type":"string"},"name":{"type":"string"},"description":{"type":["string","null"]},"sources":{"type":"array","items":{"$ref":"#/components/schemas/PublicSource"}},"content_updated_at":{"type":"string","format":"date-time"},"verified_at":{"type":["string","null"],"format":"date-time"},"source_checked_at":{"type":["string","null"],"format":"date-time"},"updated_at":{"type":"string","format":"date-time","description":"Backward-compatible v2 alias of content_updated_at."}}},"AgentCategory":{"type":"object","required":["slug","name"],"properties":{"slug":{"type":"string"},"name":{"type":"string"},"description":{"type":["string","null"]},"tool_count":{"type":"integer"},"sources":{"type":"array","items":{"$ref":"#/components/schemas/PublicSource"}},"content_updated_at":{"type":"string","format":"date-time"},"verified_at":{"type":["string","null"],"format":"date-time"},"source_checked_at":{"type":["string","null"],"format":"date-time"},"updated_at":{"type":"string","format":"date-time","description":"Backward-compatible v2 alias of content_updated_at."}}},"AgentTag":{"type":"object","required":["slug"],"properties":{"slug":{"type":"string"},"content_updated_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time","description":"Backward-compatible v2 alias of content_updated_at."}}},"AgentMeta":{"type":"object","required":["schema_version","generated_at","counts","latest_updated","verification_coverage","payload_etag"],"properties":{"schema_version":{"type":"integer"},"generated_at":{"type":"string","format":"date-time"},"counts":{"$ref":"#/components/schemas/CatalogCounts"},"latest_updated":{"$ref":"#/components/schemas/LatestUpdated"},"verification_coverage":{"$ref":"#/components/schemas/VerificationCoverage"},"payload_etag":{"type":"string"}}},"AgentExclusion":{"type":"object","required":["generated_at","tools","comparisons","reviews","stacks"],"properties":{"generated_at":{"type":"string","format":"date-time"},"tools":{"type":"array","items":{"type":"string"}},"comparisons":{"type":"array","items":{"type":"string"}},"reviews":{"type":"array","items":{"type":"string"}},"stacks":{"type":"array","deprecated":true,"description":"Editorial stacks were retired; this field is kept for v1 compatibility and is always empty.","items":{"type":"string"}}}},"CatalogCounts":{"type":"object","description":"Record count per collection.","properties":{"tools":{"type":"integer"},"comparisons":{"type":"integer"},"reviews":{"type":"integer"},"stacks":{"type":"integer","deprecated":true,"description":"Editorial stacks were retired; this field is kept for v1 compatibility and is always empty."},"use_cases":{"type":"integer"},"categories":{"type":"integer"},"tags":{"type":"integer"}}},"LatestUpdated":{"type":"object","description":"Newest updatedAt per collection, or null when the collection is empty.","properties":{"tools":{"type":["string","null"],"format":"date-time"},"comparisons":{"type":["string","null"],"format":"date-time"},"reviews":{"type":["string","null"],"format":"date-time"},"stacks":{"type":["string","null"],"format":"date-time","deprecated":true,"description":"Editorial stacks were retired; this field is kept for v1 compatibility and is always empty."},"use_cases":{"type":["string","null"],"format":"date-time"},"categories":{"type":["string","null"],"format":"date-time"},"tags":{"type":["string","null"],"format":"date-time"}}},"VerificationCoverage":{"type":"object","description":"Record-wide editorial verification coverage. Tags are omitted because their schema has no verification field.","properties":{"tools":{"$ref":"#/components/schemas/VerificationCoverageRow"},"comparisons":{"$ref":"#/components/schemas/VerificationCoverageRow"},"reviews":{"$ref":"#/components/schemas/VerificationCoverageRow"},"stacks":{"$ref":"#/components/schemas/VerificationCoverageRow","deprecated":true,"description":"Editorial stacks were retired; this field is kept for v1 compatibility and is always empty."},"use_cases":{"$ref":"#/components/schemas/VerificationCoverageRow"},"categories":{"$ref":"#/components/schemas/VerificationCoverageRow"}}},"VerificationCoverageRow":{"type":"object","required":["total_count","verified_count","missing_verification_count","coverage_ratio","oldest_verified_at","latest_verified_at"],"properties":{"total_count":{"type":"integer"},"verified_count":{"type":"integer"},"missing_verification_count":{"type":"integer"},"coverage_ratio":{"type":"number","description":"Verified records divided by total records."},"oldest_verified_at":{"type":["string","null"],"format":"date-time"},"latest_verified_at":{"type":["string","null"],"format":"date-time"}}},"PublicSource":{"type":"object","required":["label","url"],"properties":{"label":{"type":"string"},"url":{"type":"string","format":"uri"}}},"PublicPricingPlan":{"type":"object","required":["name","amount","currency","billing_period","unit","limits","is_starting_plan","source_url","source_checked_at"],"properties":{"name":{"type":"string"},"amount":{"type":["number","null"]},"currency":{"type":["string","null"]},"billing_period":{"type":"string"},"unit":{"type":["string","null"]},"limits":{"type":["string","null"]},"is_starting_plan":{"type":"boolean"},"source_url":{"type":"string","format":"uri"},"source_checked_at":{"type":"string","format":"date-time"}}},"ExplicitAlternatives":{"type":"object","required":["provenance","source","order","items"],"properties":{"provenance":{"type":"string","enum":["explicit"]},"source":{"type":"string","enum":["tools.alternatives"]},"order":{"type":"string","enum":["stored"]},"items":{"type":"array","items":{"type":"object","required":["position","tool_slug","provenance","source"],"properties":{"position":{"type":"integer"},"tool_slug":{"type":"string"},"provenance":{"type":"string","enum":["explicit"]},"source":{"type":"string","enum":["tools.alternatives"]}}}}}},"DatasetLicense":{"type":"object","required":["schema_version","license","attribution"],"properties":{"schema_version":{"type":"integer"},"license":{"type":"string","enum":["CC-BY-4.0"]},"license_url":{"type":"string","format":"uri"},"attribution":{"type":"string"},"attribution_url":{"type":"string","format":"uri"},"base_url":{"type":"string","format":"uri"},"generated_at":{"type":"string","format":"date-time"},"count":{"type":"integer"}}},"ToolsDataset":{"type":"object","required":["schema_version","license","tools","count"],"properties":{"schema_version":{"type":"integer"},"license":{"type":"string","enum":["CC-BY-4.0"]},"license_url":{"type":"string","format":"uri"},"attribution":{"type":"string"},"attribution_url":{"type":"string","format":"uri"},"base_url":{"type":"string","format":"uri"},"generated_at":{"type":"string","format":"date-time"},"count":{"type":"integer"},"tools":{"type":"array","items":{"$ref":"#/components/schemas/DatasetTool"}}}},"DatasetTool":{"type":"object","required":["slug","name","url","status","community","content_updated_at","as_of"],"properties":{"slug":{"type":"string"},"name":{"type":"string"},"url":{"type":"string","format":"uri"},"status":{"type":"string","enum":["active","graveyard"]},"tagline":{"type":["string","null"]},"short_description":{"type":["string","null"]},"official_url":{"type":["string","null"],"format":"uri"},"categories":{"type":"array","items":{"type":"string"}},"tags":{"type":"array","items":{"type":"string"}},"use_cases":{"type":"array","items":{"type":"string"}},"alternative_slugs":{"type":"array","items":{"type":"string"}},"is_open_source":{"type":"boolean"},"license":{"type":"string","enum":["open-source","source-available","proprietary"],"description":"License category. Empty CMS license follows the open-source checkbox: checked is open-source, unchecked is proprietary."},"is_recommended":{"type":"boolean"},"pricing_model":{"type":["string","null"]},"pricing_summary":{"type":["string","null"]},"pricing_plans":{"type":"array","items":{"$ref":"#/components/schemas/PublicPricingPlan"}},"sources":{"type":"array","items":{"$ref":"#/components/schemas/PublicSource"}},"community":{"$ref":"#/components/schemas/DatasetToolCommunity"},"content_updated_at":{"type":"string","format":"date-time","description":"Editorial content timestamp (contentModifiedAt). Falls back to the CMS updatedAt when that stamp is unset."},"verified_at":{"type":["string","null"],"format":"date-time"},"source_checked_at":{"type":["string","null"],"format":"date-time","description":"Most recent date when all cited primary sources were rechecked."},"as_of":{"type":"string","format":"date-time","description":"Deprecated v1 alias of content_updated_at."}}},"DatasetToolCommunity":{"type":"object","description":"Anonymous public Community aggregates. These values are separate from editorial Score, verdicts, and catalog fields.","required":["upvotes","rating_avg","rating_count","stacked_by","co_stacked_with","open_rooms","verified_runs"],"properties":{"upvotes":{"type":"integer","description":"Upvotes excluding the current verified maker's own vote."},"rating_avg":{"type":["number","null"],"description":"Mean published rating rounded to two decimals; null when rating_count is 0."},"rating_count":{"type":"integer","description":"Published ratings excluding the current verified maker's own rating."},"stacked_by":{"type":"integer","description":"Public consenting profiles that stack this tool."},"co_stacked_with":{"type":"array","items":{"type":"string"},"description":"Tool slugs sharing at least three distinct public stack profiles."},"open_rooms":{"type":"integer","description":"Visible tool rooms whose state is open."},"verified_runs":{"type":"integer","description":"Independent verified runs summed only from active task/version cohorts with at least three runs. Below-threshold cohorts publish as zero."}}},"ComparisonsDataset":{"type":"object","required":["schema_version","license","comparisons","count"],"properties":{"schema_version":{"type":"integer"},"license":{"type":"string","enum":["CC-BY-4.0"]},"license_url":{"type":"string","format":"uri"},"attribution":{"type":"string"},"attribution_url":{"type":"string","format":"uri"},"base_url":{"type":"string","format":"uri"},"generated_at":{"type":"string","format":"date-time"},"count":{"type":"integer"},"comparisons":{"type":"array","items":{"$ref":"#/components/schemas/DatasetComparison"}}}},"DatasetComparison":{"type":"object","required":["slug","title","url","content_updated_at","as_of"],"properties":{"slug":{"type":"string"},"title":{"type":"string"},"url":{"type":"string","format":"uri"},"tool_slugs":{"type":"array","items":{"type":"string"}},"intro":{"type":["string","null"]},"verdict":{"type":["string","null"]},"winner_tool_slug":{"type":["string","null"]},"sources":{"type":"array","items":{"$ref":"#/components/schemas/PublicSource"}},"published_at":{"type":["string","null"],"format":"date-time"},"content_updated_at":{"type":"string","format":"date-time","description":"Editorial content timestamp (contentModifiedAt). When unset, publishedAt, then createdAt, then CMS updatedAt."},"verified_at":{"type":["string","null"],"format":"date-time"},"source_checked_at":{"type":["string","null"],"format":"date-time"},"as_of":{"type":"string","format":"date-time","description":"Deprecated v1 alias of content_updated_at."}}},"ReviewsDataset":{"type":"object","required":["schema_version","license","reviews","count"],"properties":{"schema_version":{"type":"integer"},"license":{"type":"string","enum":["CC-BY-4.0"]},"license_url":{"type":"string","format":"uri"},"attribution":{"type":"string"},"attribution_url":{"type":"string","format":"uri"},"base_url":{"type":"string","format":"uri"},"generated_at":{"type":"string","format":"date-time"},"count":{"type":"integer"},"reviews":{"type":"array","items":{"$ref":"#/components/schemas/DatasetReview"}}}},"DatasetReview":{"type":"object","required":["slug","title","url","content_updated_at","as_of"],"properties":{"slug":{"type":"string"},"title":{"type":"string"},"url":{"type":"string","format":"uri"},"tool_slug":{"type":["string","null"]},"score_overall":{"type":["integer","null"],"description":"0–100 aicoolies Score v1."},"score_speed":{"type":["integer","null"]},"score_privacy":{"type":["integer","null"]},"score_dev_experience":{"type":["integer","null"]},"summary":{"type":["string","null"]},"verdict":{"type":["string","null"]},"evidence_status":{"type":["string","null"],"enum":["not-evidenced","partial","verified",null]},"evidence_badge":{"type":"string","enum":["verified","documented","partial","not-evidenced","unclassified"],"description":"Resolved public evidence label. tested_at, tested_version, and test_environment are null when this is documented."},"rubric_version":{"type":["string","null"]},"tested_at":{"type":["string","null"],"format":"date-time","description":"Hands-on test date. Null when evidence_badge is documented."},"tested_version":{"type":["string","null"],"description":"Tested product version or dated SaaS state. Null when evidence_badge is documented."},"test_environment":{"type":["string","null"],"description":"Reproducibility context for a hands-on record. Null when evidence_badge is documented."},"test_artifact_url":{"type":["string","null"],"format":"uri"},"sources":{"type":"array","items":{"$ref":"#/components/schemas/PublicSource"}},"published_at":{"type":["string","null"],"format":"date-time"},"content_updated_at":{"type":"string","format":"date-time","description":"Editorial content timestamp (contentModifiedAt). When unset, publishedAt, then createdAt, then CMS updatedAt."},"verified_at":{"type":["string","null"],"format":"date-time"},"source_checked_at":{"type":["string","null"],"format":"date-time"},"as_of":{"type":"string","format":"date-time","description":"Deprecated v1 alias of content_updated_at."}}},"Health":{"type":"object","required":["status","database"],"properties":{"status":{"type":"string","enum":["ok"]},"database":{"type":"string","enum":["connected"]}}},"HealthError":{"type":"object","required":["status","message"],"properties":{"status":{"type":"string","enum":["error"]},"message":{"type":"string"}}},"OpenApiDocument":{"type":"object","description":"An OpenAPI 3.1 document.","required":["openapi","info","paths"],"properties":{"openapi":{"type":"string","enum":["3.1.0"]},"info":{"type":"object","required":["title","version"],"properties":{"title":{"type":"string"},"version":{"type":"string"},"description":{"type":"string"}}},"servers":{"type":"array","items":{"type":"object","additionalProperties":true}},"paths":{"type":"object","additionalProperties":true},"components":{"type":"object","additionalProperties":true}}},"McpManifest":{"type":"object","required":["name","description","endpoint"],"properties":{"name":{"type":"string"},"description":{"type":"string"},"icon":{"type":"string","format":"uri"},"endpoint":{"type":"string","format":"uri"}}},"McpDiscovery":{"type":"object","required":["mcp_version","server_name","endpoints","capabilities"],"properties":{"mcp_version":{"type":"string","description":"Newest protocol version supported."},"supported_mcp_versions":{"type":"array","items":{"type":"string"}},"server_name":{"type":"string"},"server_version":{"type":"string"},"endpoints":{"type":"object","properties":{"streamable_http":{"type":"string","format":"uri"}}},"capabilities":{"type":"object","properties":{"tools":{"type":"boolean"},"resources":{"type":"boolean"},"prompts":{"type":"boolean"},"sampling":{"type":"boolean"},"roots":{"type":"boolean"}}},"authentication":{"type":"object","properties":{"required":{"type":"boolean"},"methods":{"type":"array","items":{"type":"string"}}}},"documentation":{"type":"string","format":"uri"},"privacy_policy":{"type":"string","format":"uri"}}},"McpServerCard":{"type":"object","required":["protocolVersion","serverInfo","transport","tools"],"properties":{"$schema":{"type":"string","format":"uri"},"version":{"type":"string"},"protocolVersion":{"type":"string"},"supportedProtocolVersions":{"type":"array","items":{"type":"string"}},"serverInfo":{"type":"object","properties":{"name":{"type":"string"},"version":{"type":"string"}}},"transport":{"type":"object","properties":{"type":{"type":"string","enum":["streamable-http"]},"url":{"type":"string","format":"uri"}}},"capabilities":{"type":"object","additionalProperties":true},"tools":{"type":"array","items":{"$ref":"#/components/schemas/McpTool"}}}},"McpTool":{"type":"object","required":["name","description","inputSchema"],"properties":{"name":{"type":"string"},"description":{"type":"string"},"inputSchema":{"type":"object","additionalProperties":true}}},"OAuthProtectedResourceMetadata":{"type":"object","description":"RFC 9728 OAuth 2.0 Protected Resource Metadata.","required":["resource"],"properties":{"resource":{"type":"string","format":"uri"},"resource_name":{"type":"string"},"resource_documentation":{"type":"string","format":"uri"},"resource_policy_uri":{"type":"string","format":"uri"},"bearer_methods_supported":{"type":"array","items":{"type":"string"}},"scopes_supported":{"type":"array","items":{"type":"string"}},"authorization_details_types_supported":{"type":"array","items":{"type":"string"}}}},"JsonRpcRequest":{"type":"object","required":["jsonrpc","method"],"properties":{"jsonrpc":{"type":"string","enum":["2.0"]},"id":{"type":["string","number","null"]},"method":{"type":"string","description":"MCP method, for example initialize, tools/list, or tools/call."},"params":{"type":"object","additionalProperties":true}}},"JsonRpcResponse":{"type":"object","required":["jsonrpc"],"properties":{"jsonrpc":{"type":"string","enum":["2.0"]},"id":{"type":["string","number","null"]},"result":{"type":"object","additionalProperties":true},"error":{"$ref":"#/components/schemas/JsonRpcError"}}},"JsonRpcError":{"type":"object","required":["code","message"],"properties":{"code":{"type":"integer","description":"JSON-RPC 2.0 error code."},"message":{"type":"string"},"data":{"type":"object","additionalProperties":true}}}},"securitySchemes":{"githubOAuth":{"type":"oauth2","description":"Human sign-in only. aicoolies acts as an OAuth 2.0 client of GitHub and requests the two identity scopes listed here — the narrowest set that can populate a public developer profile. It never requests repository, organization, or GitHub write scopes.","flows":{"authorizationCode":{"authorizationUrl":"https://github.com/login/oauth/authorize","tokenUrl":"https://github.com/login/oauth/access_token","refreshUrl":"https://github.com/login/oauth/access_token","scopes":{"read:user":"Read the public GitHub profile (id, username, avatar) of the signer-in.","user:email":"Read the verified email address on that GitHub account."}}}},"sessionCookie":{"type":"apiKey","in":"cookie","name":"payload-token","description":"First-party session cookie issued after GitHub sign-in. Scoped to the signed-in account: it can read and write only that user profile, its stack, its subscriptions, and its comments. Third-party clients cannot obtain one, which is why no account route appears in this document."},"personalAccessToken":{"type":"http","scheme":"bearer","bearerFormat":"aicoolies PAT","description":"GitHub-bound personal access token created at /settings/tokens. Optional for anonymous MCP reads; required by submit_correction, report_price_change, sync_stack, reply_to_room, submit_run, and upvote_tool with the matching scope."}}}}