---
title: "Targets"
description: "Point evals at a local dev server or a deployment with the same eval files."
---

An eval target is always an HTTP URL. `eve eval` starts a local dev server, while `eve eval --url <url>` runs against an existing server or deployment — the same eval files work for both, which is what makes evals usable as end-to-end tests in CI.

The runner polls `/eve/v1/health`, verifies `/eve/v1/info`, and exposes the live target as `t.target` inside the `test` function.

## Target helpers

```ts title="evals/heartbeat.eval.ts"
import { defineEval } from "eve/evals";

export default defineEval({
  async test(t) {
    const { sessionIds } = await t.target.dispatchSchedule("heartbeat");
    await t.target.attachSession(sessionIds[0]!);
    t.completed();
    t.calledTool("send_report");
  },
});
```

- `t.target.fetch(path, init)` performs an authenticated fetch against the target — useful for channel and webhook ingress.
- `t.target.dispatchSchedule(id)` triggers a [schedule](../schedules) through the dev-only schedule route and returns the session ids it created. It works only against a target with dev routes enabled (the local `eve eval` dev server, or a deployment running in development mode), and throws otherwise.
- `t.target.attachSession(sessionId, { startIndex? })` consumes one turn from a session created outside the eval — by a channel or a schedule — so its events feed the run-level assertions.

Sessions attached this way are full `EveEvalSession`s: you can keep driving them with `send` and read their event streams. The run-level assertions on `t` (`t.completed()`, `t.calledTool(...)`) read the whole run, attached sessions included.

## What to read next

- [Running evals](./running): `--url` and the rest of the CLI in practice
- [Schedules](../schedules): the surface `dispatchSchedule` drives
- [Channels](../channels/overview): ingress you can exercise with `target.fetch`
