// developers
Build on Anvilry
Everything Sairam Ugge publishes on this site is also available to programs and AI agents: a free, read-only API, Markdown versions of the homepage and every content page, a plain-text index for language models and a Model Context Protocol server. There are no API keys, no sign-up and no cost. The documented routes apply no quota of their own, so please keep request volume reasonable. The machine-readable description is /openapi.json.
Read-only · no authentication · content is the same as the web pages · AI use is welcome (search and AI input yes, model training no, as set in robots.txt).
Quickstart
// the OpenAPI description
curl -sS https://anvilry.vercel.app/openapi.json
// the homepage as Markdown (content negotiation)
curl -sS -H 'Accept: text/markdown' https://anvilry.vercel.app/
// one case study as Markdown
curl -sS https://anvilry.vercel.app/work/pensieve.md
// the structured résumé
curl -sS https://anvilry.vercel.app/api/resume.json
// list the MCP server's tools
curl -sS -X POST https://anvilry.vercel.app/api/mcp/mcp \
-H 'Content-Type: application/json' \
-H 'Accept: application/json, text/event-stream' \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'Endpoints
| method | path | operationId | what it returns |
|---|---|---|---|
| get | / | getHomepage | Get the homepage as HTML or Markdown |
| get | /index.md | getHomepageMarkdown | Get the homepage as Markdown |
| get | /projects/{slug}.md | getProjectMarkdown | Get a project write-up as Markdown |
| get | /work/{slug}.md | getWorkMarkdown | Get a production case study as Markdown |
| get | /articles/{slug}.md | getArticleMarkdown | Get a article as Markdown |
| get | /notes/{slug}.md | getNoteMarkdown | Get a engineering note as Markdown |
| get | /api/resume.json | getResumeJson | Get the résumé as JSON Resume |
| get | /api/github/stats | getGithubStats | Get aggregate GitHub statistics |
| get | /llms.txt | getLlmsTxt | Get the llms.txt site index |
| get | /llms-full.txt | getLlmsFullTxt | Get the full text corpus |
| get | /feed.xml | getFeed | Get the RSS feed |
| get | /sitemap.xml | getSitemap | Get the XML sitemap |
| get | /robots.txt | getRobotsTxt | Get robots.txt and the AI content signal |
| get | /openapi.json | getOpenApiDocument | Get this OpenAPI document |
| post | /api/mcp/mcp | callMcpServer | Call the portfolio MCP server |
Markdown for agents
Every page that has a Markdown version answers to the standard Accept header. Ask the page URL for text/markdown and you get Markdown; ask for text/html (a browser does) and you get the page. Responses carry Vary: Accept so caches keep the two apart. The homepage and the project, work, article and note pages work this way, and each also has a fixed URL ending in .md (/index.md for the homepage) for clients that cannot set headers. Pages with no Markdown version ignore the header and return HTML, a request whose Accept header names Markdown but rules out both Markdown and HTML (for example text/markdown;q=0, text/html;q=0) gets 406 Not Acceptable, and a path that does not exist answers 404 with a short Markdown body that links to llms.txt and the sitemap.
Errors
The failures this API raises itself (an unknown path, a method a route does not accept, a request that is malformed, too large or too frequent, a feature that is switched off, a failing upstream service) use one JSON shape. Branch on code, show error to a person, and follow hint. The MCP endpoint reports protocol errors as JSON-RPC, as MCP clients expect, and operator-only routes keep their own answers.
{
"error": "No API route exists at this path.",
"code": "not_found",
"status": 404,
"hint": "List the real routes in /openapi.json; the developer guide is at /developers.",
"docs": "https://anvilry.vercel.app/developers#errors"
}| code | status | meaning |
|---|---|---|
| invalid_request | 400 | The request body or a parameter is missing, malformed or not allowed. |
| not_found | 404 | No API route or content item exists at this path. |
| method_not_allowed | 405 | The route exists but not for this HTTP method. |
| payload_too_large | 413 | The request body is bigger than the route accepts. |
| rate_limited | 429 | Too many requests from this client in the current window. |
| upstream_error | 502 | A third-party service this route depends on failed or returned nothing. |
| not_configured | 503 | The feature is switched off or missing its server-side configuration. |
MCP server
For an AI assistant the better door is the MCP server at https://anvilry.vercel.app/api/mcp/mcp (Streamable HTTP, read-only). Its tools return the profile, projects, case studies, search results, decisions and the résumé link. The MCP page has the tool table and copy-paste setup for Claude Desktop and Cursor.
Machine-readable files
- /openapi.json — OpenAPI 3.1 description of everything on this page
- /llms.txt — plain-text index for language models, with when to use this site
- /llms-full.txt — the whole grounding corpus in one document
- /api/resume.json — JSON Resume export
- /mcp — how to connect the MCP server to Claude Desktop or Cursor
- /feed.xml — RSS feed
- /sitemap.xml — the pages submitted to search engines
- /robots.txt — crawler rules and the AI content signal
What is not in the API
The site's AI assistant, its voice features and its error reporting power the web interface itself. They cost money to run, are rate limited per IP address and are not part of this API, so they are not described here. If you need something the API does not offer, or something is wrong, write to the contact page. How data sent to the site is handled is on the privacy page.