Developers
How developers and AI agents can use Sunny Patneedi’s site
Everything on this page is public and read-only. Use these resources to find, read and cite the site’s pages, and to call its API.
Last updated
Machine-readable resources
llms.txt
GET /llms.txtGuidance for AI assistants: when to use this site, which pages are authoritative, and how to describe Sunny’s work accurately. Read it before summarizing or citing the site.
Sitemap
GET /sitemap.xmlEvery public page, each with its last-modified date.
Markdown pages
Accept: text/markdown, or ?format=markdownEvery public page is also available as Markdown with the same text, headings and links. Responses vary by Accept, and each page’s Link header points to its Markdown version.
Structured data
<script type="application/ld+json">Each page’s HTML contains one schema.org JSON-LD graph that describes the site, Sunny Patneedi and his organization. Pages such as About and Contact add their own page type.
OpenAPI description
GET /openapi.jsonAn OpenAPI 3.1 description of the public pages, these discovery files and the API, readable from any origin. Its list of pages always matches the sitemap.
API catalog
GET /.well-known/api-catalogAn RFC 9727 API catalog (application/linkset+json) that links to the OpenAPI description, this page, the API health check and the API’s projects and profile endpoints.
robots.txt
GET /robots.txtCrawling rules. Public pages are open to every crawler; admin, sign-in, billing, payment and confirmation routes are excluded.
Authentication
None. Every page, file and endpoint on this page is public and read-only. There are no API keys, accounts or tokens.
API
Base URL: https://sunnypatneedi.com/api
The API returns JSON, and every response allows cross-origin reads (Access-Control-Allow-Origin: *).
GET /api/projectsEvery project on the projects page, current work first, with its purpose, audience, status and what that status means, last-checked date and verified link. Statuses and dates are exactly as the page shows them; a project without a check date is unverified.
GET /api/projects/{projectId}One project, by an id from /api/projects such as puddle. An unknown id returns a not_found error.
GET /api/profileSunny Patneedi’s public profile: name, title, the approved bios, career, current advisory role, the role he is looking for, verified profile links and how to get in touch. It contains no email addresses.
GET /api/healthzReports whether the API server is running. Returns {"status":"ok"}.
Every API response has a Link header that points to the OpenAPI description (rel="service-desc"), this page (rel="service-doc") and the API catalog (rel="api-catalog").
The projects and profile JSON is built from the same content as the pages and checked against them on every build. Everything else, including writing and frameworks, is available as HTML or Markdown; the OpenAPI description lists those pages as the getHomePage, getPage and getFrameworkGuide operations.
Rate limits
The API allows 120 requests per 60-second window for each client IP address. Every API response reports the limit and what is left of it, using the header fields from draft-ietf-httpapi-ratelimit-headers-11, an IETF draft that is not yet an RFC:
RateLimit-Policy: "default";q=120;w=60The policy: a quota (q) of 120 requests per window (w) of 60 seconds.
RateLimit: "default";r=119;t=60Requests remaining in the current window (r) and seconds until it resets (t).
Over the limit, the API returns 429 Too Many Requests with a Retry-After header, in seconds, and an error with the code rate_limited. Wait that long before retrying.
Each server instance keeps its own count, so rely on the headers rather than counting requests yourself.
Pages and discovery files have no rate limit of their own. The hosting platform may still challenge or block automated traffic.
Errors
API errors are RFC 9457 problem details, sent with Content-Type: application/problem+json. The site uses the same format for its 400, 404 and 405 errors when a request prefers JSON, for example with Accept: application/json. Browsers and other clients get HTML, Markdown or plain-text errors.
Fields
type: A URI for the kind of problem. Most link to their entry below.title: A short summary of the kind of problem.status: The HTTP status code.detail: What went wrong with this request.instance: The request path. Query strings are never included.code: A stable, machine-readable code. Branch on this field.hint: What to do next, with a link to the relevant documentation.violated-policies: Only on rate_limited errors: the rate-limit policies that were exceeded.
Error codes
bad_request4xx · APIThe API could not process the request. Check it against the OpenAPI description.
malformed_body400 · APIThe JSON request body could not be parsed.
invalid_path400 · SiteThe path has invalid percent-encoding, an encoded “..” segment or a NUL byte.
payload_too_large413 · APIThe request body is over 100 KB, or a form body has too many fields.
unsupported_media_type415 · APIThe request body uses an unsupported Content-Encoding or charset. Send UTF-8, uncompressed or with gzip, deflate or br.
not_found404 · API and siteNo page, file or API endpoint exists at this path.
method_not_allowed405 · API and siteThe method is not supported at this path. The Allow header lists the methods that are.
rate_limited429 · APIThe client went over the API rate limit. Wait the number of seconds in Retry-After. Its type is the IANA quota-exceeded problem type, https://iana.org/assignments/http-problem-types#quota-exceeded.
internal_error500 · APIThe API failed unexpectedly. Retry later.
Example: a page that does not exist, requested as JSON
curl -H "Accept: application/json" https://sunnypatneedi.com/no-such-pageHTTP/1.1 404 Not Found
Content-Type: application/problem+json; charset=utf-8
{
"type": "https://sunnypatneedi.com/developers#error-not-found",
"title": "Not found",
"status": 404,
"detail": "No public page or file exists at this path.",
"instance": "/no-such-page",
"code": "not_found",
"hint": "Find public pages in https://sunnypatneedi.com/sitemap.xml, or read https://sunnypatneedi.com/llms.txt for guidance."
}Example requests
Read a page as Markdown
curl -H "Accept: text/markdown" https://sunnypatneedi.com/aboutList projects with their status and last-checked date
curl https://sunnypatneedi.com/api/projectsGet one project
curl https://sunnypatneedi.com/api/projects/puddleGet the public profile
curl https://sunnypatneedi.com/api/profileGet the OpenAPI description
curl https://sunnypatneedi.com/openapi.jsonGet the API catalog
curl https://sunnypatneedi.com/.well-known/api-catalogCheck the API and see its rate-limit headers
curl -i https://sunnypatneedi.com/api/healthz
Response from the health check (some headers left out)
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
RateLimit-Policy: "default";q=120;w=60
RateLimit: "default";r=119;t=60
{"status":"ok"}Questions
For anything not covered here, use the contact page.