> ## Documentation Index
> Fetch the complete documentation index at: https://docs.dari.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Quickstart

> Build and run a router with a local policy and executor.

This guide creates a router with no provider credentials. The local executor makes the example runnable while showing the same API used by a real executor.

## Install

```bash theme={null}
mkdir my-router && cd my-router
bun init -y
bun add @mupt-ai/dari-router
```

The package is ESM and requires Node.js 22.19 or later, or Bun.

## Create `server.ts`

```ts theme={null}
import {
  createRouter,
  type RouterExecutor,
  type RoutingPolicy,
} from "@mupt-ai/dari-router";

const policy: RoutingPolicy = ({ request, candidates }) => {
  const text = request.items
    .filter((item) => item.type === "message")
    .flatMap((item) => item.content)
    .filter((part) => part.type === "text")
    .map((part) => part.text)
    .join(" ");
  const preferred = text.length > 80 ? "demo/strong" : "demo/fast";
  const model = candidates.find((candidate) => candidate.id === preferred)
    ?? candidates[0]!;
  return { model: model.id, reason: `Selected ${model.id}.` };
};

const executor: RouterExecutor = {
  execute({ request, model, decision }) {
    const text = `${model.id} handled ${request.protocol}: ${decision.reason}`;
    return {
      type: "complete",
      output: {
        content: [{ type: "text", text }],
        finishReason: "stop",
        usage: { inputTokens: 1, outputTokens: 1 },
      },
    };
  },
};

const router = createRouter({
  models: [
    { id: "demo/fast", executor: "demo", capabilities: { streaming: true } },
    {
      id: "demo/strong",
      executor: "demo",
      capabilities: { streaming: true, toolUse: true, imageInput: true },
      reasoningEfforts: ["off", "high"],
    },
  ],
  policy,
  executors: { demo: executor },
});

Bun.serve({ port: 3000, fetch: router.fetch });
console.log("Listening on http://localhost:3000");
```

Run it:

```bash theme={null}
bun run server.ts
```

On Node.js rather than Bun, replace `Bun.serve` with your web framework's handler adapter and run `node server.ts` — the `router.fetch` is a standard `Request`-to-`Response` handler.

## Send a request

```bash theme={null}
curl http://localhost:3000/v1/chat/completions \
  -H 'content-type: application/json' \
  -d '{"model":"my-router","messages":[{"role":"user","content":"Hello"}]}'
```

The response is OpenAI Chat Completions-shaped. The selected model is also reported in `dari_routing` and `X-Router-Selected-Model`. The caller's `model` value names your router; it does not force a candidate with that ID.

The same handler accepts `POST /v1/messages` for Anthropic Messages. Add `stream: true` to either request to receive that protocol's SSE stream.

## Use real models next

Replace the local executor with [`createPiRuntime`](/framework/pi-runtime), or keep your own transport and read [`Custom Executors`](/framework/custom-executors). Then choose a more capable policy from [`Policies`](/framework/policies).
