# whyvanamali.com for agents and developers

Canonical: https://whyvanamali.com/docs

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/markdown` and the response is `Content-Type: text/markdown; charset=utf-8` with `Vary: Accept`.
- Or append `.md` to 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 Acceptable` with the available types listed.

```sh
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](https://whyvanamali.com/llms.txt): a one-page guide to the site with one line per post, grouped by category.
- [/sitemap.xml](https://whyvanamali.com/sitemap.xml): every page and post, with real publication dates.
- [/robots.txt](https://whyvanamali.com/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). |

```sh
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. |

```json
{
  "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](https://whyvanamali.com/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](https://whyvanamali.com/.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:

```sh
claude mcp add --transport http whyvanamali https://whyvanamali.com/mcp
```

Or add it to a client's MCP configuration:

```json
{ "mcpServers": { "whyvanamali": { "url": "https://whyvanamali.com/mcp" } } }
```

Discovery: the server card is at [/mcp/server-card](https://whyvanamali.com/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](https://whyvanamali.com/.well-known/ai-catalog.json) points at the card, and the MCP Registry manifest is at [/server.json](https://whyvanamali.com/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.
