# Agents

Rebask is designed to work with agents, from the documentation to the APIs. We provide the tooling
your agents need to understand and use Rebask, so you don't have to.

> **Author's note**: Docs are hard because they hold up a mirror to the tool. They ask: is Rebask
> really as good and simple as I imagine? I take them seriously because the docs are where that
> promise is tested.
>
> I want Rebask to work like a hammer. A good hammer disappears in your hand: you do not think
> about it, or read a manual before every swing. You focus on the nail. The docs exist to make the
> hammer worthy of that focus.

## Cheatsheet

The [Rebask cheatsheet](https://www.rebask.com/cheatsheet) is the fastest entry point. It covers
setup, routing, rendering, caching, deployment, and the runtime APIs. Read it first, then follow its
links for the details.

Agents should use the [Markdown cheatsheet](https://www.rebask.com/cheatsheet.md). That is the
version intended for them.

## Documentation as Markdown

Every documentation page is available as Markdown. Request the `.md` URL, or send
`Accept: text/markdown`:

```bash
curl https://www.rebask.com/docs/routing/introduction.md
curl -H "Accept: text/markdown" https://www.rebask.com/docs/routing/introduction
```

The [llms.txt index](https://www.rebask.com/llms.txt) links every documentation page and points
agents at the cheatsheet first.

## `AGENTS.md`

Add this block to the `AGENTS.md` in a Rebask project:

```md
## Rebask

Read https://www.rebask.com/cheatsheet.md before changing Rebask routing, rendering, caching, or
deployment code. Follow its links for details. Request docs as Markdown with
`Accept: text/markdown` or a `.md` URL.
```

## Skill

Install the Rebask skill for coding agents:

```bash
npx skills add lfades/vext --skill rebask
```

The skill is a short pointer to the cheatsheet and the docs conventions. The cheatsheet remains the
source of truth.

## Verify changes

Run `vite build`. It fails for invalid route configuration and for a dynamic page that cannot
produce a shell.

At runtime, `x-rebask-cache` and `x-rebask-prerender` show cache and PPR behavior. See
[DevTools](./devtools.md#diagnostic-headers) for the headers and the Rebask panels.

## Markdown

Add a `markdown.md` file next to a [page](./routing/introduction.md#pages-and-layouts) for static
Markdown, or a `markdown.ts` file when the Markdown needs to be generated at request time:

```text
app/
  page.tsx
  markdown.md
  docs/[[...slug]]/
    page.tsx
    markdown.ts
```

A directory cannot define both `markdown.md` and `markdown.ts`. A Markdown file can live next to a
`page.tsx` but not [`route.ts`](./routing/route-handlers.md).

### `markdown.md`

```md
# Docs

This page is also available as Markdown.
```

The file content is served as `text/markdown` without parsing or rendering. It can be the only file
for a route, making the route Markdown-only. HTML and RSC requests to a Markdown-only route go
through the normal [404 response](./error-handling.md#unmatched-urls).

### `markdown.ts`

```ts
// app/docs/[[...slug]]/markdown.ts
import { routeParams } from "@rebask/core/request"

export default async function markdown() {
  const { slug } = await routeParams<{ slug?: string[] }>()
  const doc = await getDoc((slug ?? []).join("/"))

  if (!doc) return new Response("# Not found\n", { status: 404 })

  return doc.source
}
```

The default export receives no arguments. Use request APIs such as
[`routeParams()`](./server-runtime-apis.md#routeparams), [`headers()`](./server-runtime-apis.md#headers),
[`cookies()`](./server-runtime-apis.md#cookies), and
[`searchParam()`](./server-runtime-apis.md#searchparamname) when needed. Return a string or a
`Response`:

- A string is served as `text/markdown; charset=utf-8`.
- A `Response` can set a custom status, headers, or a stream.

Return a `Response` with status `404` when there is no Markdown for the request, or custom 404
markdown content.

Reading request APIs such as `headers()` makes the handler [dynamic](./rendering/ppr.md), so its
result is not cached.

## Markdown cache lifetimes

Markdown pages are static by default just like normal pages are. Use
[`cacheLife`](./caching/cache-lifetimes.md#cachelife) to change their lifetime:

```tsx
import { cacheLife } from "@rebask/core/cache"

export default function markdown() {
	cacheLife({ revalidate: 300, expire: 3600 })
	return "# Docs\n"
}
```

A Markdown handler that reads request APIs is not cached, regardless of `cacheLife`. An explicit
`Cache-Control` response header can also set the lifetime.

## Negotiation

Rebask serves the Markdown representation when a request includes `text/markdown` in `Accept` with a
positive quality value that does not rank below `text/html`. Requests that do not list Markdown fall
back to HTML, including requests with no `Accept` header.

Markdown responses set `Vary: Accept` and a canonical `Link` header. HTML responses for routes with
a Markdown file include an alternate `Link` to the `.md` URL. If a page has no Markdown
representation, a request that lists Markdown receives the HTML page.

## Markdown URLs

A page at `/docs/start` also has a Markdown URL at `/docs/start.md`. The root page uses `/.md`. Set
[`markdownUrls: false`](./configuration.md#rebask-markdownurls) to disable these URLs:

```ts
rebask({ markdownUrls: false })
```

Routes still answer `Accept: text/markdown` even with `markdownUrls` disabled.

## Not found markdown pages

If Markdown is requested for a URL that matches no page, Rebask uses the Markdown file of the
matching catch-all page marked [`notFound`](./error-handling.md#unmatched-urls) when one exists.
The response has status `404`, `cache-control: no-store`, and `x-robots-tag: noindex`. Without one,
Rebask returns a minimal Markdown 404.

## Prerendering markdown

During a build, Rebask prerenders Markdown for static paths and stores it in the cache.
Markdown that reads the request, such as through `cookies()` or `headers()`, stays dynamic.

For a Markdown-only route with dynamic params, you can export
[`prerenderParams`](./routing/introduction.md#prerenderparams) from `markdown.ts`:

```ts
export function prerenderParams() {
  return { params: [{ slug: "start" }], allowExtraParams: false }
}

export default function markdown() {
  return "# Start"
}
```

When a route has both `page.tsx` and `markdown.ts`, `prerenderParams` belongs in `page.tsx`.
Exporting it from both is an error.
