---
title: "Carry the Receipts"
description: "Define a typed work order, append observable evidence with eve tools, and configure a durable root session that can resume without losing the factory's decision trail."
canonical_url: "https://vercel.com/academy/creating-a-software-factory/carry-the-receipts"
md_url: "https://vercel.com/academy/creating-a-software-factory/carry-the-receipts.md"
docset_id: "vercel-academy"
doc_version: "1.0"
last_updated: "2026-11-04T22:26:48.351Z"
content_type: "lesson"
course: "creating-a-software-factory"
course_title: "Creating a Software Factory"
prerequisites:  []
---

<agent-instructions>
Vercel Academy — structured learning, not reference docs.
Lessons are sequenced.
Adapt commands to the human's actual environment (OS, package manager, shell, editor) — detect from project context or ask, don't assume.
The lesson shows one path; if the human's project diverges, adapt concepts to their setup.
Preserve the learning goal over literal steps.
Quizzes are pedagogical — engage, don't spoil.
Quiz answers are included for your reference.
</agent-instructions>

# Carry the Receipts

# Carry the receipts

Picture a run that pauses Friday afternoon and resumes after Monday's deploy. If its request, commands, and decisions lived only in the old process, the reviewer gets a confident answer with no usable history.

```ts title="agent/lib/work-order.ts"
export const evidenceSchema = z.object({
  details: z.string().optional(),
  kind: z.enum(["observation", "command", "test", "decision", "diff"]),
  recordedAt: z.iso.datetime(),
  summary: z.string().min(1),
});
```

A work order gives every station the same request, current status, route, and evidence. eve keeps that object attached to a durable session across model calls, sandboxes, redeploys, and approval pauses.

## Carry Evidence Across Every Pause

Create a durable work-order contract with tools that initialize work and append observable evidence.

## Hands-on Exercise 1.2

Create `agent/lib/work-order.ts`. Define these accepted values first:

```ts title="agent/lib/work-order.ts"
import { z } from "zod";

export const workTypeSchema = z.enum([
  "documentation",
  "bug",
  "public-api",
  "unknown",
]);
export const riskSchema = z.enum(["low", "medium", "high"]);
export const laneSchema = z.enum([
  "documentation",
  "bug",
  "public-api",
  "manual",
]);
```

Add `evidenceSchema` from the opening, then define `workOrderSchema`. Its source is always present. Classification and route are optional because intake has not made those decisions yet.

```ts title="agent/lib/work-order.ts"
export const workOrderSchema = z.object({
  classification: z.object({
    actionable: z.boolean(),
    confidence: z.number().min(0).max(1),
    questions: z.array(z.string()),
    rationale: z.string(),
    risk: riskSchema,
    type: workTypeSchema,
  }).optional(),
  evidence: z.array(evidenceSchema).default([]),
  id: z.string().min(1),
  route: z.object({
    approvalRequired: z.boolean(),
    lane: laneSchema,
    reason: z.string(),
  }).optional(),
  source: z.object({
    body: z.string(),
    number: z.number().int().positive(),
    title: z.string().min(1),
    url: z.url(),
  }),
  status: z.enum([
    "received", "needs-clarification", "routed", "investigating",
    "awaiting-approval", "building", "verifying",
    "ready-for-draft-pr", "stopped",
  ]),
});
```

Infer `Evidence` and `WorkOrder` types from the schemas. Add an `addEvidence` function that creates the timestamp and parses the updated object. Create the timestamp inside `addEvidence` rather than accepting it from tool input.

Create `agent/tools/create_work_order.ts` and `agent/tools/record_evidence.ts`. Each file becomes an eve tool, so their filenames become the tool names.

```ts title="agent/tools/create_work_order.ts"
import { defineTool } from "eve/tools";
import { z } from "zod";
import { workOrderSchema } from "../lib/work-order.js";

export default defineTool({
  description: "Create the typed work order for one GitHub issue.",
  execute(input) {
    return workOrderSchema.parse({
      evidence: [],
      id: `issue-${input.number}`,
      source: input,
      status: "received",
    });
  },
  inputSchema: z.object({
    body: z.string(),
    number: z.number().int().positive(),
    title: z.string().min(1),
    url: z.url(),
  }),
});
```

`record_evidence` accepts the current work order and one evidence record without `recordedAt`. It returns the entire updated work order.

Finally, configure the output budget and idle window for investigation, verification, and approval pauses. In `agent/agent.ts`, keep the starter's `sessionUsage` check and add `sessionTimeoutMs`:

```ts title="agent/agent.ts"
limits: {
  sessionUsage: ({ window }) => window.outputTokens >= 80_000,
  sessionTimeoutMs: 7 * 24 * 60 * 60 * 1_000,
},
```

`sessionUsage` runs before each model call and returns `true` once the session has written 80,000 output tokens. When that happens, eve pauses the turn and asks a person to **Continue** or **Stop**, so an accidental runaway loop waits for a decision instead of spending quietly.

A specialist's tokens count toward the root's usage, and each subagent session also checks its own usage against this same rule, because the stations author none of their own. The check is a ceiling, and it doesn't reserve or spend 80,000 tokens by itself.

Disable eve's general delegation tool at `agent/tools/agent.ts`:

```ts title="agent/tools/agent.ts"
import { disableTool } from "eve/tools";

export default disableTool();
```

`sessionTimeoutMs` measures idle time. eve's default window is much longer ([current default](https://eve.dev/docs/agent-config#runtime-limits)), and the clock restarts each time a turn settles. A session never expires while a turn is open, including one waiting for a person to approve a specification. Seven days means a work order nobody touches for a week gets closed out. General delegation stays off until we add named specialists with narrow jobs.

## Try It

Create `agent/lib/work-order.test.ts` with one new work order and one appended observation. Then run:

```bash
pnpm test agent/lib/work-order.test.ts
pnpm typecheck
pnpm exec eve info
```

The test should report two passing checks. eve should discover zero subagents and seven tools: our two authored tools plus eve's five defaults (`bash`, `read_file`, `write_file`, `web_fetch`, and `web_search`). The general `agent` tool no longer appears:

```text
Compile       ready
Diagnostics   0 errors, 0 warnings
Tools         7 tools
Subagents     0 subagents
```

\*\*Note: Inspect the trust boundary\*\*

Try to create a work order with `status: "looks-good-to-me"`. Zod should reject any state outside the defined workflow.

\*\*Warning: record\_evidence requires a timestamp\*\*

Use `evidenceSchema.omit({ recordedAt: true })` in the tool input. `addEvidence` creates the timestamp during execution.

\*\*Warning: eve exposes a general agent tool\*\*

The override must live at `agent/tools/agent.ts` and export `disableTool()` as its default value.

## Commit

```bash
git add agent
git commit -m "feat(factory): preserve durable evidence"
```

## Done-When

- [ ] Every work order carries its source, status, route, and evidence
- [ ] New work orders begin with an empty evidence list
- [ ] Evidence timestamps are created by the factory
- [ ] Root sessions close after seven idle days
- [ ] `eve info` reports seven tools, including `create_work_order` and `record_evidence`, and zero diagnostics

The work order can now outlive the process that created it. Only trusted GitHub events should be allowed to create one.

## Solution

The exercise contains the complete schemas, tool shape, and session limits. Compare `agent/lib/work-order.ts`, `agent/tools/record_evidence.ts`, and `agent/agent.ts` with the [`complete` folder](https://github.com/vercel/academy-starters/tree/main/creating-a-software-factory/complete) if a focused test fails.


---

[Full course index](/academy/llms.txt) · [Sitemap](/academy/sitemap.md)
