Everything on this site is readable by software as well as people. This page lists the machine-readable surfaces, how to call them, and the policies behind them. All of it is public, read-only and needs no credentials.
Read any page as Markdown
Every HTML page on https://whyvanamali.com is also served as clean Markdown from the same URL (the acceptmarkdown.com convention):
- Send
Accept: text/markdownand the response isContent-Type: text/markdown; charset=utf-8withVary: Accept. - Or append
.mdto the path:/writing/<slug>.md,/index.md,/about.md. - Browsers and crawlers that do not ask for Markdown keep getting HTML. A client that accepts neither HTML nor Markdown gets
406 Not Acceptablewith the available types listed.
curl -H "Accept: text/markdown" https://whyvanamali.com/writing/the-new-employee
curl https://whyvanamali.com/writing/the-new-employee.md
Posts are authored in Markdown, so their body ships verbatim: absolute links, images and PDFs listed up top, margin notes inlined as blockquotes, previous and next links at the end. Unknown paths return a 404 Markdown body that points back at the indexes.
Indexes
- /llms.txt: a one-page guide to the site with one line per post, grouped by category.
- /sitemap.xml: every page and post, with real publication dates.
- /robots.txt: answer and citation engines are welcome everywhere public; training-only crawlers are asked to stay out.
JSON API
Base URL https://whyvanamali.com/api/v1. GET only, no authentication, Access-Control-Allow-Origin: *, responses cacheable for an hour at the edge.
| Endpoint | What it returns |
|---|---|
GET /api/v1/posts | Posts newest first. q searches title, tags, summary and body (title matches rank first; every term must appear); tag filters by one of the six categories; featured=true or false; limit (1 to 500, default 50) and offset page through; fields=slug,title,date trims the payload. |
GET /api/v1/posts/{slug} | One post: metadata, the authored Markdown body (content), the full Markdown representation (markdown), margin notes and the neighbouring posts. |
GET /api/v1/tags | The six categories with post counts and filtered archive URLs; ?sort=count puts the busiest first (default keeps the site's order). |
GET /api/v1/site | Who runs the site, the bio, the pages, the companion playbooks and where every machine-readable resource lives; ?fields=resources,counts trims the answer to those sections (name, url and description always come along). |
curl "https://whyvanamali.com/api/v1/posts?q=zerodha&limit=5"
curl https://whyvanamali.com/api/v1/posts/the-new-employee
curl https://whyvanamali.com/api/v1/tags
Errors
Every error is an RFC 9457 application/problem+json document with a stable code, a human-readable detail and a resolution hint.
| Status | Code | When |
|---|---|---|
| 400 | invalid_parameter | A query parameter is malformed or out of range. |
| 404 | post_not_found | No post has that slug. |
| 404 | api_route_not_found | There is no API route at that path. |
| 405 | method_not_allowed | Only GET, HEAD and OPTIONS are supported. |
| 429 | rate_limited | More than 120 requests in a minute from one client; wait Retry-After seconds. |
| 500 | internal_error | Something failed on the server. |
{
"type": "https://whyvanamali.com/docs#error-post_not_found",
"title": "Post not found",
"status": 404,
"detail": "No post has the slug 'nope'.",
"instance": "/api/v1/posts/nope",
"code": "post_not_found",
"resolution": "Slugs are the last segment of a post URL. List them at /api/v1/posts or search with /api/v1/posts?q=<terms>.",
"documentation_url": "https://whyvanamali.com/docs#errors"
}
Versioning and deprecation
/api/v1 is stable. A breaking change ships as a new major path (/api/v2) and the old one keeps working. Any deprecation is announced at least 90 days ahead with Deprecation and Sunset response headers (RFC 9745, RFC 8594) and a note on this page.
Rate limits
Each client (by IP address) may make 120 requests per minute across /api/v1. The rate limit is enforced per server instance, so it is approximate rather than exact. Every response carries the IETF RateLimit-Policy and RateLimit fields (for example "api-v1";q=120;w=60 and "api-v1";r=119;t=55) plus RateLimit-Limit, RateLimit-Remaining and RateLimit-Reset; past the limit the API answers 429 application/problem+json (rate_limited) with Retry-After in seconds. For bulk reads prefer /llms.txt, the sitemap, or the Markdown representation of pages.
OpenAPI
The API is described in OpenAPI 3.1 at /openapi.json (content type application/vnd.oai.openapi+json): one operationId per endpoint (listPosts, getPost, listTags, getSite), typed parameters and response schemas. An RFC 9727 API catalog at /.well-known/api-catalog links the description and this page.
MCP server
A Model Context Protocol server exposes the same archive as tools at https://whyvanamali.com/mcp (Streamable HTTP transport, no authentication, stateless, protocol revisions 2026-07-28, 2025-11-25, 2025-06-18, 2025-03-26).
| Tool | What it does |
|---|---|
search_posts | Search Krishna Veera Vanamali's essays by topic. Case-insensitive match across title, tags, summary and body; title matches rank first; every term must appear. Returns summaries with canonical URLs (use get_post for the full text). |
list_posts | Browse the writing archive newest first, optionally filtered by category or featured status, with limit/offset paging. Returns summaries with canonical URLs. |
get_post | Read one essay in full as Markdown, by slug (the last segment of its URL). Also returns metadata, attachments, margin notes and the neighbouring posts. |
list_tags | The six content categories with the number of posts in each and the filtered archive URL. sort=count puts the busiest categories first. |
get_site | Who Krishna Veera Vanamali is, what whyvanamali.com contains, the bio, the list of pages and companion playbooks, and where the machine-readable resources (docs, llms.txt, sitemap, OpenAPI, MCP) live. |
All tools are read-only and return structured output alongside text. Connect from Claude Code:
claude mcp add --transport http whyvanamali https://whyvanamali.com/mcp
Or add it to a client's MCP configuration:
{ "mcpServers": { "whyvanamali": { "url": "https://whyvanamali.com/mcp" } } }
Discovery: the server card is at /mcp/server-card, the location MCP reserves next to the endpoint, served as application/mcp-server-card+json (the same document is at /.well-known/mcp/server-card.json and /.well-known/mcp.json). It names the server and its version, gives the Streamable HTTP endpoint with the protocol versions it speaks, and lists the tools. The AI Catalog at /.well-known/ai-catalog.json points at the card, and the MCP Registry manifest is at /server.json. GET and DELETE on /mcp answer 405 because the server keeps no sessions and offers no standalone event stream.
Structured data
Every page carries schema.org JSON-LD: a Person (https://whyvanamali.com/#person) and a WebSite site-wide, BlogPosting and BreadcrumbList on posts, ProfilePage on /about and WebAPI on this page.
Questions
Email krishnavanamali1@gmail.com.