eve 0.9.8 → 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 +17 -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
@@ -1,17 +1,11 @@
1
1
  ---
2
2
  title: "Context Control"
3
- description: "Control what the model sees and when: instructions, skills, the workspace, and subagents."
3
+ description: "Control what an Eve agent's model sees and when, across instructions, skills, the workspace, and subagents."
4
4
  ---
5
5
 
6
- Eve gives you a few levers for controlling what the model sees and when it sees it.
6
+ Eve gives you a few levers for controlling what the model sees and when. `instructions.md` (or `instructions.ts`) is always on, `skills/` are available but loaded on demand, and the workspace and sandbox are visible through tools rather than pasted into the prompt.
7
7
 
8
- The most useful mental model is:
9
-
10
- - `instructions.md` (or `instructions.ts`) is always on.
11
- - `skills/` are available but loaded on demand.
12
- - The workspace and sandbox are visible through tools, not pasted into the prompt.
13
-
14
- ## 1. Base identity with `instructions.md`
8
+ ## Base identity with `instructions.md`
15
9
 
16
10
  Use `instructions.md` for the core contract of the agent.
17
11
 
@@ -22,9 +16,9 @@ used a tool.
22
16
 
23
17
  Keep this file focused on stable behavior that should apply on every turn.
24
18
 
25
- ## 2. Compose instructions in TypeScript with `instructions.ts`
19
+ ## Compose instructions in TypeScript with `instructions.ts`
26
20
 
27
- When you want to build the instructions prompt from typed helpers, lib code, or environment-derived values, author it as a module instead of markdown.
21
+ To build the instructions prompt from typed helpers, lib code, or environment-derived values, author it as a module instead of markdown.
28
22
 
29
23
  ```ts title="agent/instructions.ts"
30
24
  import { defineInstructions } from "eve/instructions";
@@ -37,13 +31,9 @@ export default defineInstructions({
37
31
 
38
32
  Module-backed instructions run once at build time. Eve captures the resulting markdown into the compiled manifest, so the runtime serves the same prompt every session without re-running the module.
39
33
 
40
- ## 3. Load procedures on demand with `skills/`
41
-
42
- Skills are not part of the always-on prompt by default.
43
-
44
- Instead, Eve advertises the available skills and adds a framework-owned `load_skill` tool. When the request clearly matches a skill description, or the user names a skill explicitly, the model activates that skill, and Eve appends the skill's markdown to the active instructions for later turn work.
34
+ ## Load procedures on demand with `skills/`
45
35
 
46
- That is how you keep rich procedures available without bloating every turn.
36
+ Skills stay out of the always-on prompt by default, which keeps rich procedures available without bloating every turn. Eve advertises the available skills and adds a framework-owned `load_skill` tool. When the request clearly matches a skill description, or the user names a skill explicitly, the model activates that skill, and Eve appends the skill's markdown to the active instructions for later turn work.
47
37
 
48
38
  ### Flat skill
49
39
 
@@ -62,48 +52,41 @@ When the task is novel or ambiguous, gather evidence first, then answer with the
62
52
  remaining uncertainty.
63
53
  ```
64
54
 
65
- Packaged skills are useful when you also want sibling files such as `references/`, `assets/`, or `scripts/` under the same skill directory. Those packaged paths show up under the runtime workspace root, so the model can inspect them with the normal file or shell tools instead of pasting all of that content into the prompt.
55
+ Packaged skills are useful when you also want sibling files such as `references/`, `assets/`, or `scripts/` under the same skill directory. Those paths show up under the runtime workspace root, so the model can inspect them with the normal file or shell tools instead of pasting their content into the prompt.
66
56
 
67
57
  See [Skills](../skills) for the full authoring model and install notes.
68
58
 
69
- ## 4. Put runtime files in the workspace, not the prompt
59
+ ## Put runtime files in the workspace, not the prompt
70
60
 
71
- Eve does not inline the entire authored surface into the prompt. Instead, it gives the model a shallow workspace hint and runtime tools to inspect deeper when needed. That keeps prompts smaller and makes file and command work explicit: skill files are available under the active workspace root, and the model can inspect them with the shared `bash` tool.
61
+ Eve does not inline the entire authored surface into the prompt. Instead, it gives the model a shallow workspace hint and runtime tools to inspect deeper when needed. Skill files are available under the active workspace root, and the model inspects them with the shared `bash` tool, which keeps prompts smaller and makes file and command work explicit.
72
62
 
73
63
  See [Sandbox](../sandbox) for the workspace and sandbox model.
74
64
 
75
- ## 5. Delegate to a specialist with a subagent
65
+ ## Delegate to a specialist with a subagent
76
66
 
77
- If a task deserves its own prompt and tool surface, use a local subagent instead of overloading the root agent. Subagents are a context-control tool too: they get their own `instructions.md`, their own tools, and their own sandbox, and they run inside their own delegated context instead of extending the root agent inline.
67
+ If a task deserves its own prompt and tool surface, use a local subagent instead of overloading the root agent. Subagents are a context-control lever too. They get their own `instructions.md`, tools, and sandbox, and they run inside their own delegated context instead of extending the root agent inline.
78
68
 
79
69
  See [Subagents](../subagents).
80
70
 
81
71
  ## Dynamic context with `defineDynamic`
82
72
 
83
- The levers above are static: authored once, the same on every session. When the right context depends on who is calling (their team, tenant, plan, or feature flags), resolve it at runtime instead. `defineDynamic` in `agent/instructions/` returns the per-session system prompt, and `defineDynamic` in `agent/skills/` returns the set of skills a caller can load. Both read `ctx.session.auth` or channel metadata, so a caller on the billing team gets the billing instructions and playbook while nobody else sees them. See [Dynamic capabilities](../guides/dynamic-capabilities) for the resolver API and when each event fires.
73
+ The levers above are static, authored once and the same on every session. When the right context depends on who is calling (their team, tenant, plan, or feature flags), resolve it at runtime instead. `defineDynamic` in `agent/instructions/` returns the per-session system prompt, and `defineDynamic` in `agent/skills/` returns the set of skills a caller can load. Both read `ctx.session.auth` or channel metadata, so a caller on the billing team gets the billing instructions and playbook while no one else sees them. See [Dynamic capabilities](../guides/dynamic-capabilities) for the resolver API and when each event fires.
84
74
 
85
- ## Choosing the right lever
75
+ ## Recommended context layout
86
76
 
87
- Use:
77
+ Pick the lever by what the context is for:
88
78
 
89
- - `instructions.md` for the agent's permanent identity.
79
+ - `instructions.md` for the agent's permanent identity. Keep it short and stable.
90
80
  - `instructions.ts` when you need to compose the prompt from typed helpers at build time.
91
- - `skills/` for optional procedures that should load only when needed.
92
- - a subagent when the task needs a different specialist surface.
81
+ - `skills/` for optional procedures that should load only when needed. Move long procedures here instead of into the always-on prompt.
82
+ - `tools/` to expose typed integrations.
83
+ - a subagent when the task needs a different specialist surface; use one only for real specialization boundaries.
93
84
  - the workspace or sandbox when the model should inspect files or run commands instead of relying on pasted instructions.
94
85
 
95
- ## A good pattern
96
-
97
- For most agents:
98
-
99
- 1. Keep `instructions.md` short and stable.
100
- 2. Move long procedures into `skills/`.
101
- 3. Expose typed integrations through `tools/`.
102
- 4. Use subagents only for real specialization boundaries.
103
-
104
86
  ## What to read next
105
87
 
106
- - [Tools](../tools)
107
- - [Skills](../skills)
108
- - [Subagents](../subagents)
109
- - [Hooks](../guides/hooks)
88
+ - [Tools](../tools): expose typed integrations the model can call.
89
+ - [Skills](../skills): the full authoring model for on-demand procedures.
90
+ - [Subagents](../subagents): delegate to a specialist with its own prompt and tools.
91
+ - [Dynamic capabilities](../guides/dynamic-capabilities): resolve per-session instructions and skills with `defineDynamic`.
92
+ - [Hooks](../guides/hooks): run code on session events to update the channel state that dynamic resolvers read.
@@ -1,13 +1,13 @@
1
1
  ---
2
2
  title: "The Harness"
3
- description: "The out-of-the-box agent loop and the built-in tools every Eve agent ships with, plus how to override or disable them."
3
+ description: "The out-of-the-box Eve agent loop and the built-in tools every agent ships with, plus how to override or disable them."
4
4
  ---
5
5
 
6
- The default harness is what every Eve agent ships with: the framework-owned agent loop, plus a set of built-in tools the model can call without you writing a line. You extend the base harness with capabilities specific to your agent. The loop itself, how a turn runs and checkpoints and resumes, lives in [Execution model & durability](./execution-model-and-durability).
6
+ The default harness is what every Eve agent ships with. It includes the framework-owned agent loop plus a set of built-in tools the model can call without you writing a line. You extend it with capabilities specific to your agent. The loop itself, how a turn runs and checkpoints and resumes, lives in [Execution model and durability](./execution-model-and-durability).
7
7
 
8
8
  ## Compaction
9
9
 
10
- A long session eventually fills the model's context window. The harness handles that for you: once the conversation crosses a fraction of the window (`thresholdPercent`, `0.9` by default), it summarizes the older turns into a compact form and keeps going, so the session continues instead of overflowing. The summary uses the active turn model unless you override it. Tune when and how it kicks in under [`compaction`](../agent-config#compaction) in `agent.ts`:
10
+ The harness keeps a long session from overflowing the model's context window. Once the conversation crosses a fraction of the window (`thresholdPercent`, `0.9` by default), it summarizes the older turns into a compact form and keeps going. The summary uses the active turn model unless you override it. Tune when and how it kicks in under [`compaction`](../agent-config#compaction) in `agent.ts`:
11
11
 
12
12
  ```ts title="agent/agent.ts"
13
13
  export default defineAgent({
@@ -18,11 +18,11 @@ export default defineAgent({
18
18
  });
19
19
  ```
20
20
 
21
- Compaction also preserves the framework's own tool state automatically. When the harness compacts history, it resets read-before-write tracking (so a write afterward re-reads the file whose read evidence was summarized away) and re-injects the active todo list, so the model keeps its task list across the summary. There is no per-tool hook to configure.
21
+ Compaction also preserves the framework's own tool state automatically. It resets read-before-write tracking (so a write afterward re-reads the file whose read evidence was summarized away) and re-injects the active todo list, so the model keeps its task list across the summary. There is no per-tool hook to configure.
22
22
 
23
23
  ## Built-in tools
24
24
 
25
- These ship with every agent, no imports. Discovery never runs them: the harness shows the model the tool descriptors first, then executes only what the model actually calls. The shell and file tools run inside the agent's single [sandbox](../sandbox); the rest run in the app runtime.
25
+ These ship with every agent, no imports. The harness shows the model the tool descriptors first, then executes only what the model actually calls; discovery never runs them. The shell and file tools (`bash`, `read_file`, `write_file`, `glob`, `grep`) live in the app runtime and proxy their work into the agent's single [sandbox](../sandbox); the rest run in the app runtime. The "Where it runs" column below names where each tool's effect lands.
26
26
 
27
27
  | Tool | Does | Where it runs |
28
28
  | ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------- |
@@ -46,9 +46,11 @@ Notes:
46
46
  - **`connection_search`** is the model-facing `connection__search` tool. A search surfaces a connection's tools by their qualified name (e.g. `connection__linear__list_issues`), and the model can then call them directly. It's registered only when the agent has connections.
47
47
  - **`web_search`** has no local executor; the provider runs it. To supply your own implementation, override it with `defineTool()`.
48
48
 
49
+ Review these built-in tools before production use. Disable, wrap, restrict, or require approval for any tool that can access the filesystem, network, shell, or sensitive data.
50
+
49
51
  ## Override a default
50
52
 
51
- Author a tool at the same slug and it takes over the built-in of that name. The file `agent/tools/write_file.ts` replaces the built-in `write_file` just by existing:
53
+ Author a tool at the same slug and it takes over the built-in of that name. The file `agent/tools/write_file.ts` replaces the built-in `write_file` by existing:
52
54
 
53
55
  ```ts title="agent/tools/write_file.ts"
54
56
  import { defineTool } from "eve/tools";
@@ -63,7 +65,7 @@ export default defineTool({
63
65
  });
64
66
  ```
65
67
 
66
- The framework defaults are importable from `eve/tools/defaults` (`bash`, `readFile`, `writeFile`, `glob`, `grep`, `webFetch`, `webSearch`, `todo`, `loadSkill`), so you can spread, wrap, or patch them. Skip the spread and your replacement owns its own context: a fresh `defineTool` for `todo` won't inherit the framework's durable state key.
68
+ The framework defaults are importable from `eve/tools/defaults` (`bash`, `readFile`, `writeFile`, `glob`, `grep`, `webFetch`, `webSearch`, `todo`, `loadSkill`), so you can spread, wrap, or patch them. Skip the spread and your replacement owns its own context. A fresh `defineTool` for `todo` won't inherit the framework's durable state key.
67
69
 
68
70
  ## Disable a default
69
71
 
@@ -75,11 +77,19 @@ import { disableTool } from "eve/tools";
75
77
  export default disableTool();
76
78
  ```
77
79
 
78
- Misspell the filename so it matches no known framework tool and it fails at resolve time, instead of silently doing nothing.
80
+ If the filename matches no known framework tool, resolution fails instead of silently doing nothing, so a typo surfaces at build time rather than removing the wrong tool.
81
+
82
+ ## When to override, disable, or author a new tool
83
+
84
+ Three moves shape the harness. The right one depends on whether the model should keep the built-in capability.
85
+
86
+ - **Override** when you want the same capability with different behavior. Spread the default from `eve/tools/defaults` and wrap it (logging, an extra guard, a different backend), and the model still sees a tool by that name. Spreading keeps the default's description, schema, and any framework state, such as the `todo` tool's durable state key. Drop the spread and your replacement owns its own context, losing that wiring.
87
+ - **Disable** when the model should not have the capability at all. A `disableTool()` sentinel removes the built-in, and the model never sees it. Reach for this to lock down `bash` or `web_fetch` in an agent that should not run shell commands or fetch arbitrary URLs.
88
+ - **Author a new tool** when you want a capability the harness does not ship. Give it a fresh slug under `agent/tools/` and it joins the built-ins instead of replacing one. See [Tools](../tools) for the authoring model.
79
89
 
80
90
  ## The opt-in `Workflow` tool
81
91
 
82
- There's also an experimental `Workflow` tool, shipped but off by default. To turn it on, re-export the opt-in marker from `agent/tools/workflow.ts`:
92
+ An experimental `Workflow` tool ships but stays off by default. To turn it on, re-export the opt-in marker from `agent/tools/workflow.ts`:
83
93
 
84
94
  ```ts
85
95
  export { ExperimentalWorkflow as default } from "eve/tools";
@@ -1,9 +1,9 @@
1
1
  ---
2
- title: "Execution Model & Durability"
3
- description: "How a session runs: durable conversations, turns that checkpoint at steps, and parked work that resumes later."
2
+ title: "Execution Model and Durability"
3
+ description: "How an Eve session runs. Durable conversations, turns that checkpoint at steps, and parked work that resumes later."
4
4
  ---
5
5
 
6
- A session is a durable conversation. It can run for days, and it survives process restarts and redeploys without any work on your part. You write the capabilities (tools, instructions, channels) and Eve runs the loop.
6
+ An Eve session is a durable conversation. It can run for days and survives process restarts and redeploys without any work on your part. You write the capabilities (tools, instructions, channels) and Eve runs the loop.
7
7
 
8
8
  ## Sessions, turns, and steps
9
9
 
@@ -13,38 +13,38 @@ Work nests in three levels:
13
13
  - **turn**: one user message and all the work it triggers (model calls, tool calls, reasoning) until the agent produces its response.
14
14
  - **step**: a durable checkpoint inside a turn (one model call and the tool calls it makes).
15
15
 
16
- Every turn runs as a durable workflow, built on the open-source [Workflow SDK](https://workflow-sdk.dev/) (Vercel Workflow when you deploy on Vercel). Eve checkpoints progress at each step and serializes durable state at that boundary. Your code runs inside a managed step, so tools, the sandbox, and subagents feel synchronous even though the session underneath them is durable.
16
+ Every turn runs as a durable workflow, built on the open-source [Workflow SDK](https://workflow-sdk.dev/) (Vercel Workflow when you deploy on Vercel). Eve checkpoints progress and serializes durable state at each step boundary. Your code runs inside a managed step, so tools, the sandbox, and subagents feel synchronous even though the session underneath them is durable.
17
17
 
18
18
  ## Resuming after a crash
19
19
 
20
- Crash the process, hit a timeout, or redeploy mid-turn, and the run picks up from the last completed step rather than replaying the whole turn. Re-running a step from the same input is idempotent. Your tool calls don't fire twice, so a resume never doubles up a side effect (a charge, an email, a write).
20
+ Crash the process, hit a timeout, or redeploy mid-turn, and the run picks up from the last completed step rather than replaying the whole turn. Completed steps never re-run; Eve replays the recorded result. A step interrupted mid-execution re-runs, so make non-idempotent side effects like charges or emails idempotent, or gate them with approval.
21
21
 
22
- There's nothing to configure here. Eve owns the workflow lifecycle, and sessions are durable by default.
22
+ There's nothing to configure. Eve owns the workflow lifecycle, and sessions are durable by default.
23
23
 
24
- You don't write workflow code directly. Workflow primitives (`start()`, `resumeHook()`, etc.) are an implementation detail of Eve's runtime layer; channels, tools, and hooks never touch them. When you do need session data from your own code, there are two supported surfaces: tools read the current session's metadata (id, turn, auth, parent lineage) via `ctx.session`, and [`defineState`](../guides/session-context) reads or writes session-scoped durable state. See [State](../guides/state) for the read/write model.
24
+ You don't write workflow code directly. Workflow primitives (`start()`, `resumeHook()`, etc.) are an implementation detail of Eve's runtime layer; channels, tools, and hooks never touch them. Two surfaces give your own code session data: tools read the current session's metadata (id, turn, auth, parent lineage) via `ctx.session`, and [`defineState`](../guides/state) reads or writes session-scoped durable state. See [State](../guides/state) for the read/write model.
25
25
 
26
26
  ## Parked work
27
27
 
28
- Some work has to wait: a human approving a [tool](../tools), an interactive OAuth sign-in for a [connection](../connections), or a long-running [subagent](../subagents). At those points the turn parks durably. The workflow suspends and holds no compute until the input it's waiting on shows up (a click, a callback, a child completing), even if that's much later. When it does, the conversation picks up exactly where it left off.
28
+ Some work has to wait, including a human approving a [tool](../tools), an interactive OAuth sign-in for a [connection](../connections), or a long-running [subagent](../subagents). At those points the turn parks durably. The workflow suspends and holds no compute until the input it's waiting on arrives (a click, a callback, a child completing), even if that's much later. When it does, the conversation picks up exactly where it left off.
29
29
 
30
30
  ## Message delivery and queueing
31
31
 
32
- Eve does not maintain a durable FIFO queue of user messages for a session today. The `continuationToken` is a resume handle for the session's current workflow hook, not a general message-queue address.
32
+ Eve does not maintain a durable FIFO queue of user messages for a session. The `continuationToken` is a resume handle for the session's current workflow hook, not a general message-queue address.
33
33
 
34
- When a session is waiting, a delivery to the current continuation token wakes the session and starts the next turn. When a turn is already active, additional deliveries may be accepted by the hook, but the runtime only drains them at specific workflow boundaries. If more than one delivery is already ready when the driver checks, Eve may fold them into the next turn; that drain is best-effort and depends on workflow and transport timing.
34
+ When a session is waiting, a delivery to the current continuation token wakes the session and starts the next turn. When a turn is already active, the hook may accept additional deliveries, but the runtime only drains them at specific workflow boundaries. If more than one delivery is ready when the driver checks, Eve may fold them into the next turn; that drain is best-effort and depends on workflow and transport timing.
35
35
 
36
- That means applications should not rely on concurrent sends to the same session behaving like a typical ordered chat queue. For deterministic behavior, send one user turn at a time: wait for `session.waiting` before sending the next message to the same session. If your channel can receive bursts while the agent is working, keep your own per-session queue in the channel or app layer, then deliver the next message after the session parks again. Separate sessions can still run independently.
36
+ So don't rely on concurrent sends to the same session behaving like a typical ordered chat queue. For deterministic behavior, send one user turn at a time and wait for `session.waiting` before sending the next message to the same session. If your channel can receive bursts while the agent is working, keep your own per-session queue in the channel or app layer, then deliver the next message after the session parks again. Separate sessions still run independently.
37
37
 
38
38
  ## Subagents
39
39
 
40
40
  A turn can hand work off to a [subagent](../subagents). Each subagent gets its own context and its own durable session; a declared subagent also gets its own sandbox, skills, and state. Nothing crosses the boundary implicitly.
41
41
 
42
- ## Ordering
42
+ ## How Eve orders session history
43
43
 
44
- Conversation history within a session is append-only. Turns land in order, and the tool calls inside a turn (plus their results) keep their order too. Read a session back and you see things in the order they happened.
44
+ Conversation history within a session is append-only. Turns land in order, and the tool calls inside a turn (plus their results) keep their order too. Read a session back and you see events in the order they happened.
45
45
 
46
46
  ## What to read next
47
47
 
48
- - [Sessions, runs & streaming](./sessions-runs-and-streaming): the handles you hold and the event stream you watch.
48
+ - [Sessions and streaming](./sessions-runs-and-streaming): the handles you hold and the event stream you watch.
49
49
  - [Security model](./security-model): the trust boundaries the runtime enforces.
50
50
  - [State](../guides/state): durable per-session memory that persists across step boundaries.
@@ -1,9 +1,9 @@
1
1
  ---
2
2
  title: "Security Model"
3
- description: "Trust boundaries, where secrets live, how credentials reach hosts, and what fails closed by default."
3
+ description: "Eve's trust boundaries, where secrets live, how credentials reach hosts, and what fails closed by default."
4
4
  ---
5
5
 
6
- Your agent runs across two contexts, with a trust boundary drawn between them and every secret kept on the trusted side. This page is the mental model to use when you're deciding what an agent (and the model driving it) is allowed to reach.
6
+ Your Eve agent runs across two contexts, with a trust boundary between them and every secret kept on the trusted side. Use this mental model when deciding what an agent (and the model driving it) is allowed to reach.
7
7
 
8
8
  ## Trust boundaries
9
9
 
@@ -16,13 +16,37 @@ Your agent runs across two contexts, with a trust boundary drawn between them an
16
16
 
17
17
  The app runtime is the trusted side. Your tool implementations, model calls, connections, state, and durable execution all run here, with `process.env` and full Node.js available. (On Vercel, this is a Vercel Function.)
18
18
 
19
- The sandbox is the isolated side. The model runs shell commands there through the built-in `bash`, `read_file`, `write_file`, `glob`, and `grep` tools. It gets its own `/workspace` filesystem, but no `process.env`, no secrets, and no path back into the app runtime. (On Vercel, each sandbox is a [Vercel Sandbox](https://vercel.com/docs/sandbox) microVM with hardware-level isolation.) The only thing that actually executes in the sandbox is shell commands. Even the built-in `bash`/`read_file`/`write_file` tools live in the app runtime and _proxy_ into the sandbox. The model sees tool definitions and results, never your secrets.
19
+ The sandbox is the isolated side. The model runs shell commands there through the built-in `bash`, `read_file`, `write_file`, `glob`, and `grep` tools. It gets its own `/workspace` filesystem, but no `process.env`, no secrets, and no path back into the app runtime. (On Vercel, each sandbox is a [Vercel Sandbox](https://vercel.com/docs/sandbox) microVM with hardware-level isolation.) Only shell commands execute in the sandbox. Even the built-in `bash`/`read_file`/`write_file` tools live in the app runtime and _proxy_ into the sandbox. The model sees tool definitions and results, never your secrets.
20
20
 
21
21
  A concrete trace makes the boundary clear. When the model calls a custom `charge_card` tool, its `execute` runs in the app runtime, reads `process.env.STRIPE_KEY`, calls Stripe, and returns `{ ok: true }`. The model sees only `{ ok: true }`: the key never leaves the app runtime, and nothing about the call touches the sandbox. The built-in `write_file` is the mirror image, running in the app runtime and proxying the write into the sandbox `/workspace`. Either way the model drives the work through tool calls and their results, never by holding a credential or reaching the runtime directly.
22
22
 
23
+ ## Data flow at a glance
24
+
25
+ ```mermaid
26
+ flowchart LR
27
+ User["User or channel provider"] --> Channel["Channel route and route auth"]
28
+ Channel --> Runtime["Eve app runtime and durable session"]
29
+ Runtime --> Model["Configured model provider or Vercel AI Gateway"]
30
+ Runtime --> Tools["Authored tools and connections"]
31
+ Tools --> Services["Customer-selected external services"]
32
+ Runtime --> Sandbox["Per-session sandbox"]
33
+ Sandbox --> Egress["Allowed sandbox network egress"]
34
+ Runtime --> Telemetry["Configured telemetry or eval provider"]
35
+ ```
36
+
37
+ Eve sends data where your agent configuration and runtime choices send it:
38
+
39
+ - Inbound channel data flows through the channel provider you configure, then into the Eve app runtime.
40
+ - Model inputs and outputs flow to the model or routing path selected in `agent.ts`, such as a Vercel AI Gateway model id or a provider-authored `LanguageModel`.
41
+ - Tool and connection calls flow to the external services, MCP servers, OpenAPI endpoints, and channels you configure.
42
+ - Sandbox commands can reach network destinations allowed by the sandbox network policy.
43
+ - Telemetry and eval data flows to the exporters and providers you configure in `instrumentation.ts` or eval settings.
44
+
45
+ Eve stores durable session and workflow state needed to resume conversations, stream events, replay completed steps, and show run observability. You are responsible for deciding whether the selected channels, model providers, connected services, sandbox egress destinations, telemetry exporters, retention settings, and deletion controls are appropriate for your data and use case.
46
+
23
47
  ## Credential brokering
24
48
 
25
- Sometimes the model needs _authenticated_ network access from inside the sandbox, like a `git clone` of a private repo or an authenticated `curl`, and there's no [tool](../tools) or [connection](../connections) to route it through. That's what credential brokering is for. On the Vercel Sandbox backend, auth headers get injected at the sandbox's network firewall for matching domains. The secret stays in the app runtime; the sandbox process only ever sees the response. See [Vercel Sandbox Credential Brokering](https://vercel.com/docs/sandbox/concepts/firewall#credentials-brokering) for the platform mechanism, and [Sandbox](../sandbox) for the Eve policy API.
49
+ Credential brokering gives the model _authenticated_ network access from inside the sandbox, like a `git clone` of a private repo or an authenticated `curl`, when there's no [tool](../tools) or [connection](../connections) to route it through. On the Vercel Sandbox backend, auth headers get injected at the sandbox's network firewall for matching domains. The secret stays in the app runtime; the sandbox process only ever sees the response. See [Vercel Sandbox Credential Brokering](https://vercel.com/docs/sandbox/concepts/firewall#credentials-brokering) for the platform mechanism, and [Sandbox](../sandbox) for the Eve policy API.
26
50
 
27
51
  ## Connection credentials
28
52
 
@@ -30,7 +54,7 @@ Sometimes the model needs _authenticated_ network access from inside the sandbox
30
54
 
31
55
  ## Channel verification
32
56
 
33
- A [channel](../channels/overview) is your agent's front door, which makes authenticating inbound traffic its job. The built-in platform channels follow two rules here, and so must any channel you write yourself:
57
+ A [channel](../channels/overview) is your agent's front door, so authenticating inbound traffic is its job. The built-in platform channels follow two rules, and so must any channel you write yourself:
34
58
 
35
59
  - **Verify signatures in constant time.** Platform channels (Slack, GitHub,
36
60
  Telegram, Twilio) verify the platform's HMAC signature over the raw request body
@@ -46,11 +70,11 @@ A custom channel that accepts dashboard-style webhooks should follow the same sh
46
70
 
47
71
  ## Authored markdown is data
48
72
 
49
- [Skill](../skills) and [schedule](../schedules) files are markdown with YAML frontmatter, and Eve treats that frontmatter strictly as data. The code-capable engines (`---js` / `---javascript`, which would `eval()` the frontmatter body the moment the file is parsed) are disabled. A fence like that throws rather than running. Frontmatter has to parse to a plain YAML object.
73
+ [Skill](../skills) and [schedule](../schedules) files are markdown with YAML frontmatter, and Eve treats that frontmatter strictly as data. The code-capable engines (`---js` / `---javascript`, which would `eval()` the frontmatter body the moment the file is parsed) are disabled, so such a fence throws rather than running. Frontmatter has to parse to a plain YAML object.
50
74
 
51
75
  ## Auth fails closed
52
76
 
53
- Routes reject unauthenticated traffic by default: if no `AuthFn` in the walk accepts the request, it gets a `401`, and admitting anonymous callers takes an explicit `none()`. The scaffold's `placeholderAuth()` keeps a half-configured app closed in production until you replace it. See [Auth & route protection](../guides/auth-and-route-protection) for the full walk and verifiers.
77
+ Routes reject unauthenticated traffic by default. If no `AuthFn` in the walk accepts the request, it gets a `401`, and admitting anonymous callers takes an explicit `none()`. The scaffold's `placeholderAuth()` keeps a half-configured app closed in production until you replace it. See [Auth & route protection](../guides/auth-and-route-protection) for the full walk and verifiers.
54
78
 
55
79
  ## Pre-production checklist
56
80
 
@@ -75,5 +99,5 @@ Before exposing an agent to real traffic:
75
99
 
76
100
  - [Auth & route protection](../guides/auth-and-route-protection): the full auth walk and verifier helpers
77
101
  - [Sandbox](../sandbox): backends, network policy, and brokering config
78
- - [Execution model & durability](./execution-model-and-durability): how durable sessions run
102
+ - [Execution model and durability](./execution-model-and-durability): how durable sessions run
79
103
  - [Connections](../connections): static-token and OAuth connections
@@ -7,7 +7,7 @@ Every Eve app speaks the same stable HTTP API to a [durable session](./execution
7
7
 
8
8
  ## The two handles
9
9
 
10
- Two handles do two jobs here, and mixing them up is the most common mistake. One handle creates and resumes a session; a different one streams and inspects it.
10
+ Two handles do two jobs, and mixing them up is the most common mistake. One handle creates and resumes a session; a different one streams and inspects it.
11
11
 
12
12
  - **`continuationToken`**: the resume handle. Use it to send a follow-up message to the same conversation. Owned by the channel.
13
13
  - **`sessionId` / `runId`**: the stream-and-inspect handle. Use it to attach to the event stream and watch a run. Owned by the runtime.
@@ -19,17 +19,17 @@ React, Vue, and Svelte apps reach for [`useEveAgent()`](../guides/frontend/overv
19
19
  ## Start a session
20
20
 
21
21
  ```bash
22
- curl -X POST http://127.0.0.1:2000/eve/v1/session \
22
+ curl -X POST http://127.0.0.1:3000/eve/v1/session \
23
23
  -H 'content-type: application/json' \
24
24
  -d '{"message":"Summarize the latest forecast."}'
25
25
  ```
26
26
 
27
- Eve responds right away. The JSON body carries a `sessionId` and a `continuationToken`, and the `x-eve-session-id` header tells you which durable session to stream.
27
+ Eve responds right away. The JSON body carries a `sessionId` and a `continuationToken`, and the `x-eve-session-id` header names the durable session to stream.
28
28
 
29
29
  ## Stream a session
30
30
 
31
31
  ```bash
32
- curl http://127.0.0.1:2000/eve/v1/session/<sessionId>/stream
32
+ curl http://127.0.0.1:3000/eve/v1/session/<sessionId>/stream
33
33
  ```
34
34
 
35
35
  The stream is newline-delimited JSON (NDJSON), one event per line:
@@ -64,6 +64,8 @@ The stream is newline-delimited JSON (NDJSON), one event per line:
64
64
 
65
65
  `reasoning.appended` and `message.appended` stream deltas as they arrive, and each one carries both the new delta and the cumulative text for the current block. The finalized block shows up on `message.completed` and `reasoning.completed`, which is the compatibility path for clients that don't render incremental streaming.
66
66
 
67
+ Note: consider the privacy, confidentiality, and user-experience implications for displaying, storing, or transmitting reasoning events in your application.
68
+
67
69
  `message.completed` can fire more than once in a turn: the agent often emits interim assistant text before a tool call. To tell tool-call narration from a terminal reply, check `message.completed.data.finishReason`. `step.completed.data.finishReason` mirrors the step outcome, and usage lives on `step.completed`.
68
70
 
69
71
  A delegated subagent publishes progress on its own child-session stream. The parent only emits `subagent.called` with a `childSessionId`, which a client uses to attach.
@@ -75,7 +77,7 @@ A delegated subagent publishes progress on its own child-session stream. The par
75
77
  Once the session is waiting (you'll see `session.waiting`), POST your follow-up to the session endpoint with the stored continuation token:
76
78
 
77
79
  ```bash
78
- curl -X POST http://127.0.0.1:2000/eve/v1/session/<sessionId> \
80
+ curl -X POST http://127.0.0.1:3000/eve/v1/session/<sessionId> \
79
81
  -H 'content-type: application/json' \
80
82
  -d '{"continuationToken":"<token>","message":"Now send the short version."}'
81
83
  ```
@@ -86,10 +88,10 @@ For deterministic ordering, send one follow-up at a time and wait for the next `
86
88
 
87
89
  ## Reconnect and rewind
88
90
 
89
- The stream is durable. Every event is recorded before a step completes, so it's all replayable. Pass `startIndex` to reconnect by event count and pick up where you dropped off, or rewind to the start:
91
+ The stream is durable. Every event is recorded before a step completes, so the whole stream is replayable. Pass `startIndex` to reconnect by event count and pick up where you dropped off, or rewind to the start:
90
92
 
91
93
  ```bash
92
- curl "http://127.0.0.1:2000/eve/v1/session/<sessionId>/stream?startIndex=<count>"
94
+ curl "http://127.0.0.1:3000/eve/v1/session/<sessionId>/stream?startIndex=<count>"
93
95
  ```
94
96
 
95
97
  ## Use the client from TypeScript
@@ -103,7 +105,7 @@ Start with the [TypeScript SDK](../guides/client/overview) guide. It covers basi
103
105
  `GET /eve/v1/info` returns a JSON inspection snapshot for the running agent: model, instructions, authored and framework tools, skills, channels, schedules, subagents, sandbox, connections, hooks, workflow, and workspace metadata. Local development accepts loopback requests; deployed Vercel targets require the route's OIDC auth.
104
106
 
105
107
  ```bash
106
- curl http://127.0.0.1:2000/eve/v1/info
108
+ curl http://127.0.0.1:3000/eve/v1/info
107
109
  ```
108
110
 
109
111
  The route uses the same default auth chain as the eve channel (`[localDev(), vercelOidc()]`). Locally it answers anonymously; a deployed Vercel target requires a valid OIDC bearer, with a same-project bypass for in-deployment callers. See [auth & route protection](../guides/auth-and-route-protection).
@@ -117,7 +119,7 @@ Every stream event runs four steps, in this order:
117
119
  3. **Hooks**: authored [hooks](../guides/hooks) subscribed to the event fire.
118
120
  4. **Dynamic resolvers**: [dynamic](../guides/dynamic-capabilities) tool, skill, and instruction resolvers fire, and `ctx.channel.metadata` already holds the freshly projected metadata from step 2.
119
121
 
120
- The order isn't incidental, it's structural. By the time a resolver or hook reads channel metadata, the channel has already updated its state and the projection is current.
122
+ The order is structural, not incidental. By the time a resolver or hook reads channel metadata, the channel has already updated its state and the projection is current.
121
123
 
122
124
  ## What to read next
123
125
 
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  title: "Connections"
3
- description: "Expose external MCP and OpenAPI servers to the model: with connection tokens the model never sees."
3
+ description: "Expose external MCP and OpenAPI servers to the model, with connection tokens the model never sees."
4
4
  ---
5
5
 
6
- A connection wires an agent into an external server you don't author: an MCP server (Linear, GitHub, a warehouse) or any HTTP API with an OpenAPI document. Eve handles the parts you'd otherwise hand-roll: it discovers the remote tools, surfaces them to the model, and brokers auth.
6
+ A connection wires an agent into an external server you don't author, either an MCP server (Linear, GitHub, a warehouse) or any HTTP API with an OpenAPI document. Eve handles the parts you'd otherwise hand-roll, discovering the remote tools, surfacing them to the model, and brokering auth.
7
7
 
8
8
  Connections live under `agent/connections/`. The runtime name comes from the filename, so `agent/connections/linear.ts` registers as `"linear"`. The model never sees a connection's URL or credentials. It discovers tools through the built-in `connection__search` and calls them by their qualified name, `connection__<connection>__<tool>` (e.g. `connection__linear__list_issues`).
9
9
 
10
10
  ## MCP connections
11
11
 
12
- `defineMcpClientConnection` points at an MCP server. All you have to supply is a `url` and a `description`:
12
+ `defineMcpClientConnection` points at an MCP server. Supply a `url` and a `description`:
13
13
 
14
14
  ```ts title="agent/connections/linear.ts"
15
15
  import { defineMcpClientConnection } from "eve/connections";
@@ -23,11 +23,11 @@ export default defineMcpClientConnection({
23
23
  });
24
24
  ```
25
25
 
26
- The `url` must speak Streamable HTTP or SSE. Write the `description` for the model, not for yourself. It shows up in `connection__search`, and the model leans on it to decide which connection to query.
26
+ The `url` must speak Streamable HTTP or SSE. Write the `description` for the model, not for yourself. It shows up in `connection__search`, and the model uses it to decide which connection to query.
27
27
 
28
28
  ### Static-token auth
29
29
 
30
- `getToken` returns a `TokenResult` (`{ token, expiresAt? }`), and Eve sends it as `Authorization: Bearer <token>` on every request. Because it runs on each connection attempt, you can mint a fresh token from wherever you keep secrets: an env var, a secrets manager, an internal vault, or your own OAuth exchange. If the token has a known TTL, set `expiresAt` (milliseconds since epoch) and Eve refreshes ahead of time rather than waiting for a `401`.
30
+ `getToken` returns a `TokenResult` (`{ token, expiresAt? }`), and Eve sends it as `Authorization: Bearer <token>` on every request. Because it runs on each connection attempt, you can mint a fresh token from wherever you keep secrets, including an env var, a secrets manager, an internal vault, or your own OAuth exchange. If the token has a known TTL, set `expiresAt` (milliseconds since epoch) and Eve refreshes ahead of time rather than waiting for a `401`.
31
31
 
32
32
  When `getToken` is the only auth, `principalType` defaults to `"app"`: one shared credential keyed across all sessions. Switch to `principalType: "user"` when each end-user carries their own token.
33
33
 
@@ -35,7 +35,7 @@ Eve resolves and caches connection tokens per step; they never land in conversat
35
35
 
36
36
  ### No auth
37
37
 
38
- Drop `auth` entirely for servers that need no token, like a localhost server during development or a public one:
38
+ Drop `auth` entirely for servers that need no token, such as a localhost server during development or a public one:
39
39
 
40
40
  ```ts
41
41
  export default defineMcpClientConnection({
@@ -44,9 +44,11 @@ export default defineMcpClientConnection({
44
44
  });
45
45
  ```
46
46
 
47
+ We recommend using no-auth connections only for services that are intentionally public, local-only, or otherwise protected outside Eve. Do not use no-auth connections for sensitive third-party services.
48
+
47
49
  ### Headers
48
50
 
49
- Reach for `headers` when the server wants a non-Bearer scheme (an API-key header) or some extra configuration. Headers stack on top of `auth`:
51
+ Use `headers` when the server wants a non-Bearer scheme (an API-key header) or extra configuration. Headers stack on top of `auth`:
50
52
 
51
53
  ```ts
52
54
  export default defineMcpClientConnection({
@@ -58,7 +60,7 @@ export default defineMcpClientConnection({
58
60
 
59
61
  ### Tool filters
60
62
 
61
- To narrow which remote tools the model sees, set exactly one of `tools.allow` or `tools.block`. Filtered-out tools just don't appear in `connection__search`:
63
+ To narrow which remote tools the model sees, set exactly one of `tools.allow` or `tools.block`. Filtered-out tools do not appear in `connection__search`:
62
64
 
63
65
  ```ts
64
66
  export default defineMcpClientConnection({
@@ -84,11 +86,13 @@ export default defineMcpClientConnection({
84
86
  });
85
87
  ```
86
88
 
87
- `never()` lets every call through, `once()` asks for approval the first time in a session, and `always()` asks every time. The pause and resume here is the same human-in-the-loop flow covered in [Tools](./tools).
89
+ `never()` lets every call through, `once()` asks for approval the first time in a session, and `always()` asks every time. The pause and resume is the same human-in-the-loop flow covered in [Tools](./tools).
90
+
91
+ For connection tools that can create, modify, delete, transmit, purchase, message, or access sensitive data, use approval, tool allow-lists, or other safeguards appropriate to the action.
88
92
 
89
93
  ## OpenAPI connections
90
94
 
91
- `defineOpenAPIConnection` turns any OpenAPI 3.x or Swagger 2.0 document into connection tools, one per operation. Pass an HTTPS URL Eve fetches at runtime, or an inline parsed object:
95
+ `defineOpenAPIConnection` turns any OpenAPI 3.x document into connection tools, one per operation. Pass an HTTPS URL Eve fetches at runtime, or an inline parsed object:
92
96
 
93
97
  ```ts title="agent/connections/petstore.ts"
94
98
  import { defineOpenAPIConnection } from "eve/connections";
@@ -104,10 +108,10 @@ Each operation becomes `connection__<connection>__<operationId>` (e.g. `connecti
104
108
 
105
109
  `auth`, `headers`, and `approval` work exactly as they do for MCP. There are two fields specific to OpenAPI:
106
110
 
107
- | Field | Purpose |
108
- | ------------ | --------------------------------------------------------------------------------------------------------------------------------------------------- |
109
- | `baseUrl` | Base URL operation paths resolve against. Optional; defaults to the document's first usable `servers` entry or Swagger `schemes`/`host`/`basePath`. |
110
- | `operations` | Filter keyed on `operationId` (`allow` or `block`). Mirrors `tools` on MCP connections, but names operations not tools. |
111
+ | Field | Purpose |
112
+ | ------------ | ----------------------------------------------------------------------------------------------------------------------- |
113
+ | `baseUrl` | Base URL operation paths resolve against. Optional; defaults to the document's first usable `servers` entry. |
114
+ | `operations` | Filter keyed on `operationId` (`allow` or `block`). Mirrors `tools` on MCP connections, but names operations not tools. |
111
115
 
112
116
  ## Interactive OAuth via Vercel Connect
113
117
 
@@ -128,7 +132,7 @@ export default defineMcpClientConnection({
128
132
 
129
133
  ## Self-hosted interactive OAuth
130
134
 
131
- Running your own OAuth? Use `defineInteractiveAuthorization` from `eve/connections`, which takes a three-method form. Eve mints a callback URL, parks the turn on a framework-owned webhook, and resumes once the token comes back. No Vercel Connect required. Interactive auth is always `principalType: "user"`, and the factory pins that for you.
135
+ To run your own OAuth, use `defineInteractiveAuthorization` from `eve/connections`, which takes a three-method form and needs no Vercel Connect. Eve mints a callback URL, parks (durably suspends) the turn on a framework-owned webhook, and resumes once the token comes back. Interactive auth is always `principalType: "user"`, and the factory pins that for you.
132
136
 
133
137
  ```ts title="agent/connections/linear.ts"
134
138
  import {
@@ -168,9 +172,18 @@ export default defineMcpClientConnection({
168
172
  });
169
173
  ```
170
174
 
171
- `getToken` runs before every tool call. `startAuthorization` and `completeAuthorization` are both-or-neither: provide one without the other and you get a definition error. The `challenge` rides along verbatim on the `authorization.required` event. Set `url` for redirect/device flows, `userCode` for a device code, `instructions` as the call to action when there's no URL, and `displayName` for the human-readable provider name channels show on the sign-in affordance (e.g. "Salesforce"). Drop `resume` when the provider keeps flow state server-side, so nothing has to cross the step boundary.
175
+ `getToken` runs before every tool call. `startAuthorization` and `completeAuthorization` are both-or-neither: provide one without the other and you get a definition error. The `challenge` rides along verbatim on the `authorization.required` event. Its fields:
176
+
177
+ | Field | Purpose |
178
+ | -------------- | ----------------------------------------------------------------------------------------- |
179
+ | `url` | The authorize URL for redirect or device flows. |
180
+ | `userCode` | The device code, for device flows. |
181
+ | `instructions` | The call to action when there's no URL. |
182
+ | `displayName` | Human-readable provider name channels show on the sign-in affordance (e.g. "Salesforce"). |
172
183
 
173
- `displayName` is presentation-only — the connection's path-derived name still keys the authorization scope, token cache, and callback URL. You can also set `displayName` on the `auth` definition itself (e.g. `auth: { ...connect("sfdc"), displayName: "Salesforce" }`); that definition-level value wins over one the strategy stamps on the challenge, and channels fall back to title-casing the connection name when neither is set.
184
+ Drop `resume` when the provider keeps flow state server-side, so nothing has to cross the step boundary.
185
+
186
+ `displayName` is presentation-only. The connection's path-derived name still keys the authorization scope, token cache, and callback URL. You can also set `displayName` on the `auth` definition itself (e.g. `auth: { ...connect("sfdc"), displayName: "Salesforce" }`); that definition-level value wins over one the strategy stamps on the challenge, and channels fall back to title-casing the connection name when neither is set.
174
187
 
175
188
  ### Signaling authorization state
176
189
 
@@ -192,24 +205,31 @@ To narrow a caught error, use `isConnectionAuthorizationRequiredError(err)` and
192
205
 
193
206
  ### Handling a revoked token mid-call
194
207
 
195
- `getToken` only runs _before_ a tool call, so a grant revoked while a tool is mid-flight first surfaces as a downstream `401` inside your `execute`. A plain throw there is just a tool error the model sees a failure and the cached bearer sticks around. Instead, map a provider `401` to `ctx.requireAuth()` (or rethrow `ConnectionAuthorizationRequiredError`). Eve then evicts the rejected token from its per-step cache and re-runs the consent flow with a fresh one, exactly as it does for a connection whose server rejects the bearer.
208
+ `getToken` only runs _before_ a tool call, so a grant revoked while a tool is mid-flight first surfaces as a downstream `401` inside your `execute`. A plain throw there is only a tool error, so the model sees a failure and the cached bearer sticks around. Instead, map a provider `401` to `ctx.requireAuth()` (or rethrow `ConnectionAuthorizationRequiredError`). Eve then evicts the rejected token from its per-step cache and re-runs the consent flow with a fresh one, exactly as it does for a connection whose server rejects the bearer.
196
209
 
197
210
  ```ts title="agent/tools/list_issues.ts"
198
- async execute(_input, ctx) {
199
- const { token } = await ctx.getToken();
200
- const res = await fetch("https://api.linear.app/graphql", {
201
- headers: { authorization: `Bearer ${token}` },
202
- });
203
- // The grant was revoked since getToken ran: re-challenge instead of
204
- // returning a dead-token error to the model.
205
- if (res.status === 401) ctx.requireAuth();
206
- return await res.json();
207
- }
211
+ import { defineTool } from "eve/tools";
212
+ import { z } from "zod";
213
+
214
+ export default defineTool({
215
+ description: "List open Linear issues.",
216
+ inputSchema: z.object({}),
217
+ async execute(_input, ctx) {
218
+ const { token } = await ctx.getToken();
219
+ const res = await fetch("https://api.linear.app/graphql", {
220
+ headers: { authorization: `Bearer ${token}` },
221
+ });
222
+ // The grant was revoked since getToken ran: re-challenge instead of
223
+ // returning a dead-token error to the model.
224
+ if (res.status === 401) ctx.requireAuth();
225
+ return await res.json();
226
+ },
227
+ });
208
228
  ```
209
229
 
210
230
  ### Authorization and approval together
211
231
 
212
- A tool can require both sign-in (`auth`) and a human approval. Today the model's approval gate runs before the tool's `execute`, so the order the user sees is **approve, then sign in**. Eve records the approval on session state the moment it's granted, and that record survives the sign-in park so when the turn resumes after authorization, the tool is not put through approval a second time. You get one approval and one sign-in, never a double prompt.
232
+ A tool can require both sign-in (`auth`) and a human approval. The model's approval gate runs before the tool's `execute`, so the order the user sees is **approve, then sign in**. Eve records the approval on session state the moment it's granted, and that record survives the sign-in park, so when the turn resumes after authorization the tool is not put through approval again. You get one approval and one sign-in, never a double prompt.
213
233
 
214
234
  ## What to read next
215
235