eve 0.10.0 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (91) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/README.md +14 -0
  3. package/dist/src/cli/banner.d.ts +6 -3
  4. package/dist/src/cli/banner.js +1 -1
  5. package/dist/src/cli/commands/init.js +1 -1
  6. package/dist/src/cli/dev/tui/agent-header.js +1 -1
  7. package/dist/src/cli/run.js +1 -1
  8. package/dist/src/evals/runner/run-evals.d.ts +1 -1
  9. package/dist/src/harness/input-requests.d.ts +20 -1
  10. package/dist/src/harness/input-requests.js +1 -1
  11. package/dist/src/harness/tool-loop.js +1 -1
  12. package/dist/src/internal/application/package.js +1 -1
  13. package/dist/src/protocol/message.d.ts +11 -2
  14. package/dist/src/protocol/message.js +2 -2
  15. package/dist/src/public/next/index.d.ts +1 -7
  16. package/dist/src/public/next/index.js +1 -1
  17. package/dist/src/public/next/vercel-output-config.js +1 -1
  18. package/dist/src/setup/scaffold/create/project.js +1 -1
  19. package/dist/src/setup/scaffold/create/web-template.d.ts +1 -1
  20. package/dist/src/setup/scaffold/create/web-template.js +27 -4
  21. package/dist/src/setup/scaffold/update/channels.js +1 -1
  22. package/docs/README.md +19 -5
  23. package/docs/agent-config.md +16 -19
  24. package/docs/channels/custom.mdx +24 -18
  25. package/docs/channels/discord.mdx +25 -13
  26. package/docs/channels/eve.mdx +24 -6
  27. package/docs/channels/github.mdx +41 -10
  28. package/docs/channels/linear.mdx +29 -36
  29. package/docs/channels/overview.mdx +16 -4
  30. package/docs/channels/slack.mdx +59 -32
  31. package/docs/channels/teams.mdx +19 -7
  32. package/docs/channels/telegram.mdx +23 -9
  33. package/docs/channels/twilio.mdx +28 -6
  34. package/docs/concepts/context-control.md +24 -41
  35. package/docs/concepts/default-harness.md +19 -9
  36. package/docs/concepts/execution-model-and-durability.md +14 -14
  37. package/docs/concepts/security-model.md +32 -8
  38. package/docs/concepts/sessions-runs-and-streaming.md +11 -9
  39. package/docs/connections.mdx +49 -29
  40. package/docs/evals/assertions.mdx +30 -29
  41. package/docs/evals/cases.mdx +10 -10
  42. package/docs/evals/judge.mdx +14 -14
  43. package/docs/evals/overview.mdx +15 -17
  44. package/docs/evals/reporters.mdx +19 -7
  45. package/docs/evals/running.mdx +2 -2
  46. package/docs/evals/targets.mdx +15 -4
  47. package/docs/getting-started.mdx +70 -31
  48. package/docs/guides/auth-and-route-protection.md +18 -12
  49. package/docs/guides/client/continuations.mdx +5 -13
  50. package/docs/guides/client/messages.mdx +2 -2
  51. package/docs/guides/client/output-schema.mdx +2 -2
  52. package/docs/guides/client/overview.mdx +4 -4
  53. package/docs/guides/client/streaming.mdx +6 -5
  54. package/docs/guides/deployment.md +22 -20
  55. package/docs/guides/dev-tui.md +85 -13
  56. package/docs/guides/dynamic-capabilities.md +24 -8
  57. package/docs/guides/dynamic-workflows.md +33 -12
  58. package/docs/guides/frontend/nextjs.mdx +28 -14
  59. package/docs/guides/frontend/nuxt.mdx +21 -4
  60. package/docs/guides/frontend/overview.mdx +11 -11
  61. package/docs/guides/frontend/sveltekit.mdx +20 -3
  62. package/docs/guides/frontend/use-eve-agent-svelte.mdx +106 -14
  63. package/docs/guides/frontend/use-eve-agent-vue.mdx +108 -15
  64. package/docs/guides/hooks.md +14 -60
  65. package/docs/guides/instrumentation.md +24 -18
  66. package/docs/guides/remote-agents.md +19 -15
  67. package/docs/guides/session-context.md +12 -12
  68. package/docs/guides/state.md +25 -9
  69. package/docs/instructions.mdx +18 -10
  70. package/docs/introduction.md +12 -12
  71. package/docs/legal.md +16 -0
  72. package/docs/meta.json +1 -0
  73. package/docs/reference/cli.md +101 -53
  74. package/docs/reference/meta.json +1 -1
  75. package/docs/reference/project-layout.md +39 -32
  76. package/docs/reference/typescript-api.md +1 -1
  77. package/docs/sandbox.mdx +25 -19
  78. package/docs/schedules.mdx +16 -14
  79. package/docs/skills.mdx +8 -6
  80. package/docs/subagents.mdx +39 -13
  81. package/docs/tools.mdx +13 -9
  82. package/docs/tutorial/connect-a-warehouse.mdx +16 -7
  83. package/docs/tutorial/first-agent.mdx +21 -11
  84. package/docs/tutorial/guard-the-spend.mdx +11 -9
  85. package/docs/tutorial/how-it-runs.mdx +10 -8
  86. package/docs/tutorial/query-sample-data.mdx +8 -8
  87. package/docs/tutorial/remember-definitions.mdx +5 -5
  88. package/docs/tutorial/run-analysis.mdx +13 -11
  89. package/docs/tutorial/ship-it.mdx +70 -14
  90. package/docs/tutorial/team-playbooks.mdx +33 -10
  91. package/package.json +1 -1
@@ -3,30 +3,48 @@ title: "Getting Started"
3
3
  description: "Install Eve, scaffold your first agent, give it a tool, and run it locally."
4
4
  ---
5
5
 
6
- Eve is a filesystem-first framework for durable agents: you write capabilities under `agent/`, and Eve runs the model loop, persists every session, and serves the agent over HTTP and platform channels. This guide gets a small app running locally and walks the current request loop end to end: build, run, message, stream, and follow up.
6
+ Eve is a filesystem-first framework for durable agents. You write capabilities under `agent/`, and Eve runs the model loop, persists every session, and serves the agent over HTTP and platform channels. You'll scaffold an app, add a tool, run it locally, then create, stream, and continue a session over HTTP.
7
+
8
+ Eve is currently in beta and subject to the [Vercel beta terms](https://vercel.com/docs/release-phases/public-beta-agreement). The framework, APIs, documentation, and behavior may change before general availability.
9
+
10
+ ## Prerequisites
11
+
12
+ - Node 24 or newer
13
+ - npm (bundled with Node)
14
+ - A model credential (see below)
15
+
16
+ The scaffold's default model is `anthropic/claude-sonnet-4.6`, which routes through the Vercel AI Gateway. Set one of these before you run the agent:
17
+
18
+ - A gateway model id needs `AI_GATEWAY_API_KEY`, or a `VERCEL_OIDC_TOKEN` pulled with `vercel link`.
19
+ - A direct provider id needs that provider's key, derived from the model prefix. For example, `anthropic/claude-...` needs `ANTHROPIC_API_KEY`.
20
+
21
+ You are responsible for selecting a model, provider, and channel appropriate for your data and use case, and for complying with each provider's terms (as listed per model) and data-processing requirements.
22
+
23
+ If you skip this, the dev TUI flags the missing credential and its `/model` command walks you through pasting a key or linking a project.
7
24
 
8
25
  ## Quick start
9
26
 
10
- Run `eve init` with `npx` before Eve is installed locally:
27
+ `npx` runs `eve init` without installing Eve first:
11
28
 
12
29
  ```bash
13
30
  npx eve@latest init my-agent
14
31
  ```
15
32
 
16
- The command creates an npm-managed child directory, uses Eve's default model, installs dependencies, initializes Git, and starts the development server — the interactive [terminal UI](./guides/dev-tui) opens; type a message and watch the model loop run. Pass `--channel-web-nextjs` to add the Web Chat application; every app ships the built-in HTTP channel (`agent/channels/eve.ts`) regardless. Stop the server before editing the generated agent. The command does not create a Vercel project or deploy.
33
+ The command:
17
34
 
18
- ## Prerequisites
35
+ - Creates an npm-managed child directory and uses Eve's default model
36
+ - Installs dependencies and initializes Git
37
+ - Starts the development server and opens the interactive [terminal UI](./guides/dev-tui)
19
38
 
20
- - Node `24.x`
21
- - npm (bundled with Node)
39
+ Type a message and watch the model loop run. Pass `--channel-web-nextjs` to add the Web Chat application. Every app ships the built-in HTTP channel (`agent/channels/eve.ts`) regardless.
22
40
 
23
- You also need a model credential. Set the provider or gateway key your model string requires (gateway ids like `anthropic/claude-opus-4.8` route through the Vercel AI Gateway), or link a Vercel project that supplies one.
41
+ `eve init` holds the terminal, so stop it with Ctrl+C to get your shell back before editing the generated agent. The command does not create a Vercel project or deploy.
24
42
 
25
- ## Manual installation
43
+ To add Eve to an existing project, run `eve init .` from a directory that already has a `package.json` and no `agent/` files yet. Eve adds the missing `eve`, `ai`, and `zod` dependencies without touching anything else the project owns. The Eve dependency and the Node engine come from the same release. Eve pins `engines.node` to the lowest major that release supports (for example `24.x`). It keeps an existing range only when every version that range allows stays within that major; otherwise it replaces the range and prints a warning.
26
44
 
27
- The quick start uses `eve init` for a guided scaffold. Run `npx eve@latest init <name>` from a parent directory, or create an empty directory first and run `eve init`, `eve init .`, or `eve init ./` inside it to run the same full scaffold there, including `package.json`. To add Eve to a non-empty existing app, use `npx eve@latest init .`: that add-agent flow requires a `package.json` and no existing `agent/` files yet, and Eve adds the missing `eve`, `ai`, and `zod` dependencies for you. Eve also ensures a compatible Node engine (for example `24.x`) is present; if an existing range is too narrow for the release, Eve updates it and warns you. Either way the final handoff runs the `eve dev` binary through the package manager, not the project’s own `dev` script.
45
+ ## Manual installation
28
46
 
29
- To wire Eve in by hand, declare a compatible Node runtime in `package.json`:
47
+ To wire Eve into an existing app by hand instead of using `eve init`, first declare a compatible Node runtime in `package.json`:
30
48
 
31
49
  ```json
32
50
  {
@@ -36,10 +54,10 @@ To wire Eve in by hand, declare a compatible Node runtime in `package.json`:
36
54
  }
37
55
  ```
38
56
 
39
- Then install Eve and author the two files the runtime needs:
57
+ Then install the dependencies and author the two files the runtime needs. The `eve init` scaffold adds `ai` and `zod` for you; by hand you install all three:
40
58
 
41
59
  ```bash
42
- npm install eve@latest
60
+ npm install eve@latest ai zod
43
61
  ```
44
62
 
45
63
  ### Project files
@@ -62,18 +80,19 @@ export default defineAgent({
62
80
  });
63
81
  ```
64
82
 
83
+ Before using real customer data, confirm the selected model provider's terms, routing path, and retention settings are appropriate for that data.
84
+
65
85
  Even at this size the agent can already do real work. The default harness gives it file, shell, web, and delegation tools out of the box. See [Default harness](./concepts/default-harness) for the full set and how to override or disable any of them.
66
86
 
67
87
  ### Add your first tool
68
88
 
69
- Whatever you name the file becomes the tool name the model sees. Create `agent/tools/get_weather.ts`:
89
+ The filename becomes the tool name the model sees, and it must be snake_case ASCII. Create `agent/tools/get_weather.ts`:
70
90
 
71
91
  ```ts
72
92
  import { defineTool } from "eve/tools";
73
93
  import { z } from "zod";
74
94
 
75
- // The runtime tool name comes from the filename, so the model sees this as
76
- // `get_weather`. Tool filenames must be snake_case ASCII.
95
+ // The model sees this tool as `get_weather`, from the filename.
77
96
  export default defineTool({
78
97
  description: "Get the current weather for a city.",
79
98
  inputSchema: z.object({ city: z.string().min(1) }),
@@ -87,29 +106,35 @@ Tools run in your app runtime with full `process.env`, not inside the [sandbox](
87
106
 
88
107
  ## Run the app
89
108
 
90
- From the app root:
109
+ A scaffolded app has a `dev` script, so from the app root run:
91
110
 
92
111
  ```bash
93
112
  npm run dev
94
113
  ```
95
114
 
96
- Useful commands:
115
+ The manual path authors no `dev` script. Run the binary through `npx` instead:
116
+
117
+ ```bash
118
+ npx eve dev
119
+ ```
120
+
121
+ Other commands the eve binary provides (prefix each with `npx`, or add a matching package.json script):
97
122
 
98
123
  - `eve info`: show the active routes and compiled artifacts
99
124
  - `eve build`: compile the agent into `.eve/` and build the host output
100
125
  - `eve start`: serve the built output
101
126
  - `eve dev`: start the local runtime and open the interactive [terminal UI](./guides/dev-tui)
102
127
 
103
- In the dev TUI, type a message and watch it happen in order: the `get_weather` call, its result, then the reply.
128
+ In the dev TUI, type a message and watch it happen in order. First the `get_weather` call, then its result, then the reply.
104
129
 
105
- The same CLI can point at a deployment. `eve dev https://your-app.vercel.app` drives a deployed app, which is handy for preview and production smoke tests. See [Deployment](./guides/deployment).
130
+ The same CLI can point at a deployment. `npx eve dev https://your-app.vercel.app` drives a deployed app, which is handy for preview and production smoke tests. See [Deployment](./guides/deployment).
106
131
 
107
132
  ## Send a message
108
133
 
109
134
  Every Eve app exposes the same stable HTTP API. Start a durable session:
110
135
 
111
136
  ```bash
112
- curl -X POST http://127.0.0.1:2000/eve/v1/session \
137
+ curl -X POST http://127.0.0.1:3000/eve/v1/session \
113
138
  -H 'content-type: application/json' \
114
139
  -d '{"message":"What is the weather in Brooklyn?"}'
115
140
  ```
@@ -124,35 +149,49 @@ The response comes back with two things you'll reuse:
124
149
  Attach to the session stream:
125
150
 
126
151
  ```bash
127
- curl http://127.0.0.1:2000/eve/v1/session/<sessionId>/stream
152
+ curl http://127.0.0.1:3000/eve/v1/session/<sessionId>/stream
128
153
  ```
129
154
 
130
- The stream is NDJSON, one lifecycle event per line. See [Sessions, runs & streaming](./concepts/sessions-runs-and-streaming) for the full list of events and what each one carries.
155
+ The stream is NDJSON, served as `application/x-ndjson; charset=utf-8`. For this run you'll see a handful of lifecycle events:
156
+
157
+ - `session.started`
158
+ - `actions.requested` (the `get_weather` call)
159
+ - `action.result`
160
+ - `message.completed` (the reply)
161
+ - `session.completed`
162
+
163
+ `reasoning.appended` and `message.appended` are optional live-streaming events. Clients that can't surface incremental output can ignore them and rely on `reasoning.completed` and `message.completed`.
164
+
165
+ Note: consider the privacy, confidentiality, and user-experience implications for displaying, storing, or transmitting reasoning events in your application.
166
+
167
+ The full set covers more lifecycle, human-in-the-loop, and authorization events, including `input.requested`, `turn.failed`, `authorization.required`, and `authorization.completed`. See [Sessions, runs and streaming](./concepts/sessions-runs-and-streaming) for every event and its data shape.
131
168
 
132
169
  ## Send a follow-up message
133
170
 
134
171
  When the session is waiting for the next user message, post a follow-up with the token:
135
172
 
136
173
  ```bash
137
- curl -X POST http://127.0.0.1:2000/eve/v1/session/<sessionId> \
174
+ curl -X POST http://127.0.0.1:3000/eve/v1/session/<sessionId> \
138
175
  -H 'content-type: application/json' \
139
176
  -d '{"continuationToken":"<token>","message":"Now do Queens."}'
140
177
  ```
141
178
 
142
- See [Sessions, runs & streaming](./concepts/sessions-runs-and-streaming) for the full contract.
179
+ See [Sessions, runs and streaming](./concepts/sessions-runs-and-streaming) for the full contract.
143
180
 
144
181
  ## Setting up with a coding agent
145
182
 
146
183
  If a coding agent (Claude Code, Cursor, and the like) is doing the setup, hand it this prompt:
147
184
 
148
- <CopyPrompt text="Set up an Eve agent for the user. Ask one question at a time. Use your prompt tools when available and do not guess. First ask what the agent should do. Then ask whether to create a new project or add it to an existing directory. For a new project, propose a name and ask the user to confirm it, then ask whether it should include Web Chat. Run `npx eve@latest init <target>`, adding `--channel-web-nextjs` if the user wants Web Chat. After scaffolding, read the relevant guide in `<project>/node_modules/eve/docs/`, replace the placeholder in `<project>/agent/instructions.md` with the purpose the user gave you, and do not start `eve dev` because it is interactive. Give the user the exact dev command printed by init.">
149
- Set up an Eve agent by asking what it should do, whether to create a new project, scaffold the
150
- current empty directory, or add Eve to an existing app, and whether a new project should include Web Chat, one question at a time.
151
- Run `npx eve@latest init <target>`, read the bundled docs, fill in agent/instructions.md, and give
152
- the user the dev command instead of starting the interactive server.
185
+ <CopyPrompt text="Set up an Eve agent for the user. Eve is a filesystem-first TypeScript framework for durable agents, published as the npm package eve. Read its docs: once eve is installed they are bundled in the package at node_modules/eve/docs; before eve is installed, read the published Introduction and Getting Started pages. If the project has no Eve app, scaffold one with `npx eve@latest init <name>`; add `--channel-web-nextjs` only when the user wants Web Chat. The init command installs dependencies, initializes Git, and starts the dev server, so run it in a controllable process and stop it with Ctrl+C before editing. To add Eve to an existing app, run `eve init .`, or install the dependencies by hand with `npm install eve@latest ai zod` (init adds ai and zod; the by-hand path needs all three). Make sure agent/agent.ts and agent/instructions.md exist, then add a first typed tool at agent/tools/get_weather.ts using defineTool from eve/tools with a Zod inputSchema and an inline execute. Start the dev server again, then exercise the HTTP API: create a session with POST /eve/v1/session, attach to GET /eve/v1/session/:id/stream, and send a follow-up with the returned continuationToken. Verify with the project's typecheck, adapt model and provider choices to the project, and do not commit unless the user asks.">
186
+ Set up an Eve agent: read the Eve docs (bundled at node_modules/eve/docs once eve is
187
+ installed), scaffold with `npx eve@latest init <name>` (or `npm install eve@latest ai zod` in an existing app), add
188
+ a typed tool at agent/tools/get_weather.ts, run it with `npm run dev`, then create a session, stream
189
+ it, and send a follow-up.
153
190
  </CopyPrompt>
154
191
 
155
- Once `eve` is installed, the complete docs ship at `node_modules/eve/docs/`, so the agent can read them locally instead of fetching anything.
192
+ Once `eve` is a dependency, the package bundles the full docs, so the agent can read them locally at `node_modules/eve/docs/` without fetching anything.
193
+
194
+ To add a platform channel after setup, run `eve channels add slack` from an interactive terminal. The init flags are covered in [Quick start](#quick-start).
156
195
 
157
196
  ## What to read next
158
197
 
@@ -160,5 +199,5 @@ Once `eve` is installed, the complete docs ship at `node_modules/eve/docs/`, so
160
199
  - [Channels](./channels/overview): reach the agent from Slack, Discord, or a web UI
161
200
  - [Frontend](./guides/frontend/overview): browser chat with `useEveAgent`
162
201
  - [TypeScript SDK](./guides/client/overview): call the agent from scripts or server-side code
163
- - [Sessions, runs & streaming](./concepts/sessions-runs-and-streaming): the durable session model
202
+ - [Sessions, runs and streaming](./concepts/sessions-runs-and-streaming): the durable session model
164
203
  - [Build an agent](./tutorial/first-agent): the full end-to-end walkthrough
@@ -3,21 +3,23 @@ title: "Auth & Route Protection"
3
3
  description: "Secure your agent's HTTP routes with an ordered auth walk, verifier helpers, and connection OAuth via Vercel Connect."
4
4
  ---
5
5
 
6
- Eve has two separate auth concerns, and this page covers both:
6
+ Eve has two independent auth systems:
7
7
 
8
- - **Route auth** (inbound): who is allowed to reach your agent's HTTP routes. It runs at the channel layer.
9
- - **Tool and connection auth** (outbound): how your agent signs in to an external service it calls, like an OAuth MCP server.
8
+ - **Route auth** (inbound) decides who can reach your agent's HTTP routes. It runs at the channel layer, gating the request before any model work runs.
9
+ - **Tool and connection auth** (outbound) is how your agent signs in to an external service it calls, like an OAuth MCP server. It happens later, when a tool or connection actually reaches out.
10
10
 
11
- They are independent. Route auth gates the request before any model work runs; tool and connection auth happens later, when a tool or connection actually reaches out. Start with route auth.
11
+ Start with route auth.
12
12
 
13
13
  ## Route auth
14
14
 
15
- Route auth runs at the channel layer. The policy lives on the HTTP channel factory (`agent/channels/eve.ts`) and guards three routes:
15
+ The route-auth policy lives on the HTTP channel factory (`agent/channels/eve.ts`) and guards three routes:
16
16
 
17
17
  - `POST /eve/v1/session`
18
18
  - `POST /eve/v1/session/:sessionId`
19
19
  - `GET /eve/v1/session/:sessionId/stream`
20
20
 
21
+ These routes are protected by the channel's auth policy. Eve fails closed by default: production browser traffic is rejected unless you configure an authenticator that accepts it, and anonymous access requires an explicit `none()`.
22
+
21
23
  `GET /eve/v1/health` is always public and skips the walk entirely, so load balancers and uptime monitors can probe it without credentials.
22
24
 
23
25
  ```ts title="agent/channels/eve.ts"
@@ -64,7 +66,7 @@ export default eveChannel({
64
66
 
65
67
  Put your own providers ahead of the catch-all helpers. Any entry that doesn't recognize the caller returns `null`, and the walk moves on.
66
68
 
67
- Want a precise status instead of a skip? Throw:
69
+ To reject with a precise status instead of skipping, throw:
68
70
 
69
71
  ```ts
70
72
  import { ForbiddenError, UnauthenticatedError } from "eve/channels/auth";
@@ -76,7 +78,7 @@ throw new UnauthenticatedError({
76
78
  throw new ForbiddenError({ message: "Not allowed on this workspace." }); // 403
77
79
  ```
78
80
 
79
- Any other thrown error follows the normal channel failure path. Building a custom channel on `defineChannel`? Call `routeAuth(request, auth)` from `eve/channels/auth` to reuse the same walk semantics.
81
+ Any other thrown error follows the normal channel failure path. When building a custom channel on `defineChannel`, call `routeAuth(request, auth)` from `eve/channels/auth` to reuse the same walk semantics.
80
82
 
81
83
  ## Verifier helpers
82
84
 
@@ -92,6 +94,8 @@ Any other thrown error follows the normal channel failure path. Building a custo
92
94
  | `jwtEcdsa(...)` | You verify asymmetric JWTs minted by another system. |
93
95
  | `oidc(...)` | You want Eve to verify OIDC-issued tokens from an arbitrary issuer. |
94
96
 
97
+ Exercise caution for agents that process non-public, sensitive, regulated, or production data unless you have implemented other access controls.
98
+
95
99
  ### `localDev()`
96
100
 
97
101
  Authenticates a synthetic `local-dev` principal, but only when the inbound request is addressed to a loopback hostname (`localhost`, `*.localhost`, `127.0.0.0/8`, or `::1`). The check keys off the request URL's hostname rather than the bare `process.env.VERCEL` flag, and that's deliberate: a deployment outside Vercel leaves `VERCEL` unset, so sniffing that flag alone would wave through all public traffic. There's one process-level exception. `vercel dev`, detected by `VERCEL=1` and `VERCEL_ENV=development` together, opens the local dev server even when it serves over a non-loopback host. Every other non-loopback request returns `null` and falls through.
@@ -106,7 +110,7 @@ Auth fails closed: routes reject unauthenticated traffic by default, and the OID
106
110
 
107
111
  #### `subjects` patterns and `vercelSubject(...)`
108
112
 
109
- Each `subjects` entry is matched against the token's `sub` claim, which Vercel shapes as `owner:<team>:project:<name>:environment:<env>`. Hand-writing that string is a footgun: a typo silently rejects every caller, and an over-broad `*` wildcard silently lets unrelated ones in. Build the pattern with `vercelSubject(...)` instead. It rejects malformed input at construction time and forces an explicit `environment` (defaulting to `"production"`):
113
+ Each `subjects` entry is matched against the token's `sub` claim, which Vercel shapes as `owner:<team>:project:<name>:environment:<env>`. Hand-writing that string is a footgun: a typo silently rejects every caller, and an over-broad `*` wildcard silently lets unrelated ones in. Build the pattern with `vercelSubject(...)` instead. It rejects malformed input at construction time, and defaults `environment` to `"production"` when you omit it, so an unspecified environment cannot silently accept preview or development tokens:
110
114
 
111
115
  ```ts
112
116
  import { vercelOidc, vercelSubject } from "eve/channels/auth";
@@ -205,14 +209,16 @@ Inside runtime code, `ctx.session.auth` carries the result of the channel's rout
205
209
 
206
210
  - `auth.current`: the caller on the active inbound turn.
207
211
  - `auth.initiator`: the caller that started the durable session.
208
- - A follow-up message updates `auth.current` but leaves `auth.initiator` alone. So when a different caller follows up on the same session, `auth.current` tracks the new caller for that turn while `auth.initiator` stays pinned to whoever started it.
212
+ - A follow-up message updates `auth.current` but leaves `auth.initiator` alone. When a different caller follows up on the same session, `auth.current` tracks the new caller for that turn while `auth.initiator` stays pinned to whoever started it.
209
213
  - Both are `null` only on internal runtime paths (subagents, for instance) that never went through an authored route. HTTP traffic always populates `auth.current`, since the walk either accepts with a `SessionAuthContext` or returns `401`.
210
214
 
211
- Use the principal on `auth.current` (or `auth.initiator`) to scope tools, resolve [dynamic capabilities](./dynamic-capabilities) per principal, or enforce tenant boundaries. There's no second per-session ownership ACL stacked on top of route auth: access is decided at the HTTP boundary, and the durable session just carries the caller snapshot forward into your runtime code.
215
+ Use the principal on `auth.current` (or `auth.initiator`) to scope tools, resolve [dynamic capabilities](./dynamic-capabilities) per principal, or enforce tenant boundaries. There's no second per-session ownership ACL stacked on top of route auth. Access is decided at the HTTP boundary, and the durable session carries the caller snapshot forward into your runtime code.
216
+
217
+ Route auth does not enforce session ownership. If multiple users or tenants can reach the same route, you must implement the per-user, per-tenant, or per-session authorization your application requires.
212
218
 
213
219
  ## Tool and connection auth
214
220
 
215
- Route auth decides who reaches your agent. Tool and connection auth is the flip side: how your agent reaches an external service that wants an interactive sign-in, like an OAuth MCP server. Both a connection and an individual tool can declare an `auth` strategy; Eve drives the sign-in, caches the token per step, and re-runs the call once the caller authorizes.
221
+ Tool and connection auth is how your agent reaches an external service that wants an interactive sign-in, like an OAuth MCP server. Both a connection and an individual tool can declare an `auth` strategy; Eve drives the sign-in, caches the token per step, and re-runs the call once the caller authorizes.
216
222
 
217
223
  ### On a connection
218
224
 
@@ -263,7 +269,7 @@ Declaring `auth` adds two accessors to the tool's `ctx`:
263
269
 
264
270
  Throw `ConnectionAuthorizationRequiredError` anywhere in `execute` (directly, via `requireAuth()`, or implicitly from `getToken()`) and you trigger the consent flow, keyed by the tool's name. Calling either accessor on a tool that does not declare `auth` throws.
265
271
 
266
- By default the sign-in affordance title-cases the tool's path-derived name a tool file named `sfdc_lookup.ts` renders "Sign in with Sfdc_lookup". Set `displayName` on the `auth` definition to control what users see instead: `auth: { ...connect("sfdc"), displayName: "Salesforce" }`. It is presentation-only; the tool's name still keys the authorization scope, token cache, and callback URL, and a definition-level `displayName` wins over one the strategy stamps on the challenge.
272
+ By default the sign-in affordance title-cases the tool's path-derived name, so a tool file named `sfdc_lookup.ts` renders "Sign in with Sfdc_lookup". Set `displayName` on the `auth` definition to control what users see instead, for example `auth: { ...connect("sfdc"), displayName: "Salesforce" }`. It is presentation-only. The tool's name still keys the authorization scope, token cache, and callback URL, and a definition-level `displayName` wins over one the strategy stamps on the challenge.
267
273
 
268
274
  ## What to read next
269
275
 
@@ -3,12 +3,12 @@ title: "Continuations"
3
3
  description: "Persist and resume Eve client sessions with continuation tokens, session IDs, and stream cursors."
4
4
  ---
5
5
 
6
- Eve hands back two different handles, and mixing them up is the most common mistake. The TypeScript client tracks both for you:
6
+ Every Eve client turn returns two handles, and mixing them up is a common mistake. The TypeScript client tracks both for you:
7
7
 
8
8
  - `continuationToken`: the resume handle. Use it to send the next user turn.
9
9
  - `sessionId`: the stream-and-inspect handle. Use it to attach to event history.
10
10
 
11
- `ClientSession` also tracks `streamIndex`, the count of events already consumed. Together those fields make a `SessionState`.
11
+ `ClientSession` also tracks `streamIndex`, the count of events already consumed. Together these three fields make a `SessionState`.
12
12
 
13
13
  ## Read and persist state
14
14
 
@@ -75,7 +75,7 @@ if (result.status === "completed") {
75
75
  }
76
76
  ```
77
77
 
78
- This matches the runtime contract: only waiting sessions can accept the next user input.
78
+ This matches the runtime contract, where only waiting sessions can accept the next user input.
79
79
 
80
80
  ## Multiple sessions
81
81
 
@@ -99,7 +99,7 @@ The shared `Client` only owns host, auth, headers, and reconnect settings. Conve
99
99
 
100
100
  ## Reconnect an existing stream
101
101
 
102
- If a session already has a `sessionId`, `stream()` attaches to that stream from the saved cursor:
102
+ When a session already has a `sessionId`, `session.stream()` reattaches to its stream from the saved cursor. Resuming a saved `SessionState` after a restart is the common reason to do this:
103
103
 
104
104
  ```ts
105
105
  const session = client.session(savedState);
@@ -109,15 +109,7 @@ for await (const event of session.stream()) {
109
109
  }
110
110
  ```
111
111
 
112
- Override the cursor when you want to replay from an earlier point:
113
-
114
- ```ts
115
- for await (const event of session.stream({ startIndex: 0 })) {
116
- console.log(event.type);
117
- }
118
- ```
119
-
120
- `stream()` is for attaching to an existing run. To send new user input, use `send()`.
112
+ `stream()` attaches to an existing run; to send new user input, use `send()`. For overriding the cursor with `startIndex` and the full reconnection model, see [Streaming](./streaming#open-a-stream-manually).
121
113
 
122
114
  ## What to read next
123
115
 
@@ -12,7 +12,7 @@ Pass a string to `send()` for plain text:
12
12
  ```ts
13
13
  import { Client } from "eve/client";
14
14
 
15
- const client = new Client({ host: "http://127.0.0.1:2000" });
15
+ const client = new Client({ host: "http://127.0.0.1:3000" });
16
16
  const session = client.session();
17
17
 
18
18
  const response = await session.send("What is the weather in Brooklyn?");
@@ -34,7 +34,7 @@ console.log(result.status, result.message);
34
34
  | `sessionId` | Session ID for streaming and inspection. |
35
35
  | `data` | Structured output when the turn requested an [output schema](./output-schema). |
36
36
 
37
- Failed runtime turns don't throw just because the stream includes `session.failed`. They return `status: "failed"`. Transport and route errors throw `ClientError`.
37
+ When the stream includes `session.failed`, the turn returns `status: "failed"` rather than throwing. Transport and route errors throw `ClientError`.
38
38
 
39
39
  ## Send a full turn payload
40
40
 
@@ -3,7 +3,7 @@ title: "Output Schema"
3
3
  description: "Request structured results from Eve client turns and read typed data from MessageResult."
4
4
  ---
5
5
 
6
- Pass `outputSchema` on a client turn when the caller needs structured data instead of only assistant text. The runtime makes the model satisfy the schema before the turn settles and emits the final payload as `result.completed`.
6
+ Pass `outputSchema` on a client turn when the caller needs structured data instead of only assistant text. The runtime makes the model satisfy the schema before the turn settles, then emits the final payload as `result.completed`.
7
7
 
8
8
  ## JSON Schema
9
9
 
@@ -26,7 +26,7 @@ const outputSchema = {
26
26
  required: ["title", "count"],
27
27
  } as const;
28
28
 
29
- const client = new Client({ host: "http://127.0.0.1:2000" });
29
+ const client = new Client({ host: "http://127.0.0.1:3000" });
30
30
  const session = client.session();
31
31
 
32
32
  const response = await session.send<Summary>({
@@ -1,9 +1,9 @@
1
1
  ---
2
- title: "Overview"
2
+ title: "TypeScript SDK Overview"
3
3
  description: "Call an Eve agent from TypeScript with Client, sessions, auth, and health checks."
4
4
  ---
5
5
 
6
- The `eve/client` entrypoint is the typed client for Eve's default HTTP API. Use it from scripts, server-to-server integrations, tests, evals, backend jobs, or custom UIs that want the session protocol without hand-writing the POST and NDJSON stream loop.
6
+ The `eve/client` entrypoint is the typed client for Eve's default HTTP API. Use it from scripts, server-to-server integrations, tests, evals, backend jobs, or custom UIs that want the session protocol without hand-writing the POST and NDJSON (newline-delimited JSON) stream loop.
7
7
 
8
8
  For browser chat UIs, start with [`useEveAgent`](../frontend/overview). For wire-level details, read [Sessions, runs & streaming](../../concepts/sessions-runs-and-streaming). The client sits between those two: lower level than the frontend hooks, higher level than raw HTTP.
9
9
 
@@ -15,11 +15,11 @@ A `Client` binds one host, auth policy, header policy, and stream reconnection b
15
15
  import { Client } from "eve/client";
16
16
 
17
17
  const client = new Client({
18
- host: "http://127.0.0.1:2000",
18
+ host: "http://127.0.0.1:3000",
19
19
  });
20
20
  ```
21
21
 
22
- `host` is the origin where the Eve routes are mounted. In a same-origin browser integration this is often `""`, but scripts and backend services usually name the full URL.
22
+ `host` is the origin where the Eve routes are mounted. In a same-origin browser integration this is often `""`; scripts and backend services usually name the full URL.
23
23
 
24
24
  ## Check health
25
25
 
@@ -3,7 +3,7 @@ title: "Streaming"
3
3
  description: "Consume Eve client stream events live, reconnect by event index, and aggregate turn results."
4
4
  ---
5
5
 
6
- Every send starts with a POST and then reads the session's NDJSON event stream. `MessageResponse` gives you two ways to consume that stream: aggregate it with `result()` or iterate it live.
6
+ Every `ClientSession.send()` call posts the turn, then reads the session's NDJSON (newline-delimited JSON) event stream. `MessageResponse` gives you two ways to consume that stream, aggregating it with `result()` or iterating it live.
7
7
 
8
8
  ## Aggregate a turn
9
9
 
@@ -42,7 +42,7 @@ for await (const event of response) {
42
42
  }
43
43
  ```
44
44
 
45
- `message.appended` and `reasoning.appended` are incremental events. The completed forms, `message.completed` and `reasoning.completed`, are the compatibility path for clients that don't render deltas.
45
+ `message.appended` and `reasoning.appended` are incremental delta events. Their completed forms, `message.completed` and `reasoning.completed`, are the compatibility path for clients that don't render deltas.
46
46
 
47
47
  ## Handle event types
48
48
 
@@ -117,21 +117,22 @@ for await (const event of session.stream({ startIndex: 0 })) {
117
117
 
118
118
  ## Abort a request
119
119
 
120
- Pass an `AbortSignal` to cancel the POST or stream:
120
+ Pass an `AbortSignal` to cancel the POST or stream. Arm the timeout before awaiting `send()` so it covers the POST as well as the stream:
121
121
 
122
122
  ```ts
123
123
  const controller = new AbortController();
124
+ const timeout = setTimeout(() => controller.abort(), 10_000);
124
125
 
125
126
  const response = await session.send({
126
127
  message: "Run a long analysis.",
127
128
  signal: controller.signal,
128
129
  });
129
130
 
130
- setTimeout(() => controller.abort(), 10_000);
131
-
132
131
  for await (const event of response) {
133
132
  console.log(event.type);
134
133
  }
134
+
135
+ clearTimeout(timeout);
135
136
  ```
136
137
 
137
138
  Once a response is aborted, create a new send for the next turn. Don't reuse the same `MessageResponse`.
@@ -1,9 +1,9 @@
1
1
  ---
2
2
  title: "Deployment"
3
- description: "A production checklist for shipping an Eve agent on Vercel: build output, env/secrets, sandbox backend, prewarm, auth, deploy, and verify."
3
+ description: "A production checklist for shipping an Eve agent on Vercel, covering build output, env and secrets, sandbox backend, prewarm, auth, deploy, and verify."
4
4
  ---
5
5
 
6
- You've got an agent running under `eve dev` and now you want it live. Eve runs the same way locally and on Vercel, so the move to production is mostly mechanical. Work through this checklist in order.
6
+ Eve runs the same way locally and on Vercel, so taking an agent from `eve dev` to production is mostly mechanical. Work through this checklist in order.
7
7
 
8
8
  ## 1. Build
9
9
 
@@ -13,16 +13,16 @@ You've got an agent running under `eve dev` and now you want it live. Eve runs t
13
13
  eve build
14
14
  ```
15
15
 
16
- On hosted Vercel builds you get the Vercel output bundle under `.vercel/output`. You also get Eve's compiled framework artifacts under `.eve/`: the discovery manifest, compiled manifest, diagnostics, and module map. Crack those open to see exactly which authored surface a deployment will load. For the artifact guide and what to do when `eve build` fails, see [instrumentation.ts](./instrumentation).
16
+ When `VERCEL` is set (every hosted Vercel build sets it), `eve build` writes the Vercel output bundle under `.vercel/output`. A plain local `eve build` skips that bundle. Either way you get Eve's compiled framework artifacts under `.eve/`, including the discovery manifest, compiled manifest, diagnostics, and module map. Open those to see which authored surface a deployment will load. For the artifact guide and what to do when `eve build` fails, see [Observability](./instrumentation).
17
17
 
18
- ## 2. Environment variables & secrets
18
+ ## 2. Environment variables and secrets
19
19
 
20
20
  Set these in your Vercel project's environment variables, never in source or compiled artifacts:
21
21
 
22
- - **A model credential.** Easiest is the Vercel AI Gateway: link a Vercel project and gateway model ids like `anthropic/claude-opus-4.8` authenticate through Vercel OIDC, with no provider keys to manage. To call a provider directly instead, set its key (for example `OPENAI_API_KEY`).
23
- - **Route-auth secrets**, for example `ROUTE_AUTH_BASIC_PASSWORD` and any JWT/OIDC signing keys referenced by your channel's `auth` (see [Auth & route protection](./auth-and-route-protection)).
22
+ - **A model credential.** The lowest-setup option is the Vercel AI Gateway. Link a Vercel project, and gateway model ids like `anthropic/claude-opus-4.8` authenticate through Vercel OIDC, with no provider keys to manage. To call a provider directly instead, set its key (for example `OPENAI_API_KEY`).
23
+ - **Route-auth secrets**, for example `ROUTE_AUTH_BASIC_PASSWORD` and any JWT/OIDC signing keys referenced by your channel's `auth` (see [Auth and route protection](./auth-and-route-protection)).
24
24
 
25
- Route-auth secrets never get serialized into the compiled discovery or module-map artifacts. The runtime re-materializes them from the authored channel definition instead. One caveat: if your deployment sits behind Vercel preview protection and you want to drive it with `eve dev`, set `VERCEL_AUTOMATION_BYPASS_SECRET` locally before launching.
25
+ Route-auth secrets are never serialized into the compiled discovery or module-map artifacts. The runtime re-materializes them from the authored channel definition instead. If your deployment sits behind Vercel preview protection and you want to drive it with `eve dev`, set `VERCEL_AUTOMATION_BYPASS_SECRET` locally before launching.
26
26
 
27
27
  ## 3. Sandbox backend
28
28
 
@@ -41,7 +41,7 @@ Leave `backend` off and Eve falls back to `defaultBackend()`, which picks the Ve
41
41
 
42
42
  ## 4. Build-time sandbox prewarm
43
43
 
44
- During hosted builds, Eve prewarms reusable Vercel sandbox templates so the first session doesn't eat the cold-start cost. A few things worth knowing:
44
+ During hosted builds, Eve prewarms reusable Vercel sandbox templates so the first session doesn't pay the cold-start cost:
45
45
 
46
46
  - Prewarm runs only when both `VERCEL` and `VERCEL_DEPLOYMENT_ID` are present.
47
47
  - A sandbox with no `bootstrap()` and no workspace seed files gets skipped.
@@ -53,7 +53,7 @@ During hosted builds, Eve prewarms reusable Vercel sandbox templates so the firs
53
53
 
54
54
  ## 5. Auth
55
55
 
56
- Swap any scaffolded `placeholderAuth()` for your real policy before the first production browser request hits the app. Both the framework default and the placeholder reject production browser traffic, so an unconfigured app fails closed rather than serving open routes. See [Auth & route protection](./auth-and-route-protection) for the full walk and the fail-closed guarantee.
56
+ Swap any scaffolded `placeholderAuth()` for your real policy before the first production browser request hits the app. Both the framework default and the placeholder reject production browser traffic, so an unconfigured app fails closed rather than serving open routes. See [Auth and route protection](./auth-and-route-protection) for the ordered auth walk and the fail-closed guarantee.
57
57
 
58
58
  ## 6. Deploy on Vercel
59
59
 
@@ -65,10 +65,6 @@ vercel deploy
65
65
 
66
66
  The deployed app serves the same stable health, session, and stream routes you've been hitting locally.
67
67
 
68
- ## How Eve sits behind a host framework
69
-
70
- You can deploy an Eve app on its own, or mount it inside a host web framework that owns the rest of the site (marketing pages, a dashboard, other API routes). The host keeps its own routing and serves Eve's routes through the framework integration. For mounting Eve in Next.js (`withEve`) and the other supported frameworks, see [Frontend](./frontend/nextjs). Either way, the agent surface and HTTP contract are identical.
71
-
72
68
  ## 7. Verify the deployment
73
69
 
74
70
  Smoke-test the live routes. Health first:
@@ -85,13 +81,13 @@ curl -X POST https://<your-app>/eve/v1/session \
85
81
  -d '{"message":"Hello from production"}'
86
82
  ```
87
83
 
88
- Attach to the returned stream:
84
+ The POST returns a JSON body whose `sessionId` identifies the new session. Attach to that session's stream with it:
89
85
 
90
86
  ```bash
91
87
  curl https://<your-app>/eve/v1/session/<sessionId>/stream
92
88
  ```
93
89
 
94
- Or poke at the deployment interactively with the dev TUI, which is handy for preview and production smoke tests:
90
+ Or drive the deployment interactively with the dev TUI, which is handy for preview and production smoke tests:
95
91
 
96
92
  ```bash
97
93
  eve dev https://<your-app>
@@ -103,20 +99,26 @@ eve dev https://<your-app>
103
99
 
104
100
  Once the agent is deployed, the platform auto-detects `eve` as the framework and surfaces an **Agent Runs** tab under your project's **Observability** view in the Vercel dashboard. From there you can browse sessions and drill into each conversation's trace.
105
101
 
106
- > The Agent Runs tab is currently gated: your Vercel team needs the feature enabled before it appears. If you don't see it, reach out to your Vercel contact to get your team enabled.
102
+ > The Agent Runs tab is currently gated. Your Vercel team needs the feature enabled before it appears. If you don't see it, reach out to your Vercel contact to get your team enabled.
103
+
104
+ Agent Runs is separate from the OpenTelemetry exporters configured in [Observability](./instrumentation). Those still work and are the recommended path if you want spans in Braintrust, Datadog, or another third-party backend.
105
+
106
+ ## How Eve sits behind a host framework
107
107
 
108
- Agent Runs is separate from the OpenTelemetry exporters configured in [`instrumentation.ts`](./instrumentation). Those still work and are the recommended path if you want spans in Braintrust, Datadog, or another third-party backend.
108
+ You can deploy an Eve app on its own, or mount it inside a host web framework that owns the rest of the site (marketing pages, a dashboard, other API routes). The host keeps its own routing and serves Eve's routes through the framework integration. Either way, the agent surface and HTTP contract are identical. For mounting Eve in Next.js (`withEve`) and the other supported frameworks, see [Frontend](./frontend/nextjs).
109
109
 
110
110
  ## Checklist
111
111
 
112
- - [ ] `eve build` succeeds and writes `.vercel/output`.
112
+ - [ ] `eve build` succeeds, and writes `.vercel/output` when `VERCEL` is set.
113
113
  - [ ] Provider keys and route-auth secrets are set in Vercel env vars.
114
114
  - [ ] The sandbox backend matches the environment (`vercel()` or `defaultBackend()`).
115
115
  - [ ] Build-time prewarm reused or built templates without failing.
116
116
  - [ ] `placeholderAuth()` is replaced with your real policy.
117
+ - [ ] `vercel deploy` succeeds.
118
+ - [ ] The health, session, and stream routes respond on the deployment URL.
117
119
 
118
120
  ## What to read next
119
121
 
120
- - [Auth & route protection](./auth-and-route-protection): secure the routes you deployed
121
- - [instrumentation.ts](./instrumentation): tracing, run tags, and the error catalog
122
+ - [Auth and route protection](./auth-and-route-protection): secure the routes you deployed
123
+ - [Observability](./instrumentation): tracing, run tags, and common failures
122
124
  - [Sandbox](../sandbox): backends, lifecycle, and credential brokering