Reproduce the claim
“Empty messages are delivered” sounds specific enough to fix. The title names a behavior, and the body asks for a regression test. But the issue is still a claim, not evidence that the bug exists.
Issue claim → smallest probe → observed resultThe Investigator tests the premise against the repository before writing a specification.
Make the Issue Prove Itself
Create a read-only Investigator that reproduces or contradicts a reported bug inside Vercel Sandbox.
Hands-on Exercise 3.1
Connect the live services
The first two sections stayed local. Live investigation needs a repository connector and Vercel Sandboxes.
Link the directory. eve link creates or selects the Vercel project and pulls local OIDC credentials used by AI Gateway and Vercel Connect:
pnpm exec eve linkCreate a managed GitHub connector, install its GitHub App on your course repository only, and attach it to the linked project:
vercel connect create github --name signalworks-factory --triggers
vercel connect attach github/signalworks-factory --triggers --trigger-path /eve/v1/github
vercel connect listIf vercel connect is unavailable, update the CLI. The connector supplies short-lived installation tokens; do not create a personal access token or GitHub App key.
Add the course configuration to the linked project, then pull it locally:
vercel env add FACTORY_REPO --value YOUR_GITHUB_NAME/signalworks-software-factory
vercel env add FACTORY_LABEL --value factory
vercel env add FACTORY_BRANCH_PREFIX --value factory/
vercel env add FACTORY_SETUP_COMMAND --value "pnpm install --frozen-lockfile"
vercel env add GITHUB_CONNECTOR --value github/signalworks-factory
vercel env pull .env.localConfirm the five values. GITHUB_CONNECTOR must match vercel connect list, and FACTORY_REPO must name the connected personal repository. Refresh expired authentication with vercel env pull .env.local.
Build the Investigator
Open agent/lib/config.ts and set the fallback repository to your personal GitHub copy. Vercel Hobby projects use repositories owned by your personal account.
Create agent/subagents/investigator/sandbox.ts:
import { defineSandbox } from "eve/sandbox";
import {
createRepoEnvironment,
openRepoSandbox,
} from "../../lib/github/repo-sandbox.js";
export const environment = createRepoEnvironment();
export default defineSandbox(() => openRepoSandbox(environment));The exported environment is a Vercel Sandbox environment. eve build reads it before any session exists, so the export is required. The selector passed to defineSandbox() runs when the Investigator first needs its sandbox.
openRepoSandbox comes from the starter. It opens the session's sandbox, clones your repository into /workspace/repo if it isn't there yet, checks out the latest default branch, and runs FACTORY_SETUP_COMMAND. eve may run the selector more than once against the same sandbox, so every one of those steps is safe to repeat. The checkout stays isolated from the host filesystem.
Create agent/subagents/investigator/agent.ts:
import { defineAgent } from "eve";
import { MODELS } from "../../lib/models.js";
export default defineAgent({
description:
"Investigate a reported behavior against the real repository. Reproduce the claim and return command-backed evidence. Never modify files.",
model: MODELS.investigator,
});The root reads that description to decide when to delegate. What comes back is the Investigator's final reply, and a reply is text. We could ask for JSON in the instructions and hope, but Lesson 2.2 already showed that asking for JSON in prose doesn't create a typed boundary.
So the Investigator gets one tool whose input schema is the contract. Create agent/subagents/investigator/tools/submit_findings.ts with a small first version:
import { defineTool } from "eve/tools";
import { z } from "zod";
export default defineTool({
description:
"Submit the finished investigation. Call it once, as your last action, then reply with exactly the JSON it returns.",
execute(input) {
return input;
},
inputSchema: z.object({
claimSupported: z.boolean(),
evidence: z
.array(
z.object({
command: z.string().nullable(),
result: z.string(),
summary: z.string(),
})
)
.min(1),
}),
});eve validates every call against inputSchema before execute runs. A result with no evidence, or a claimSupported of "probably", comes back to the Investigator as an error it has to fix. The tool lives under the Investigator's own tools/ folder, so the root never sees it.
Add agent/subagents/investigator/instructions.md. Require the smallest disposable probe that can decide the claim, relevant output for every command, and cleanup before returning. The Investigator never edits product files, and it finishes by calling submit_findings.
Finally, add the bug-lane delegation to agent/instructions.md. Pass the complete work order because specialists do not inherit the root conversation.
Try It
Check discovery first:
pnpm typecheck
pnpm exec eve infoThe application should report one subagent. Then invoke the factory with the uppercase-channel fixture. This is the course's canonical non-interactive invocation command:
pnpm exec eve invoke "$(cat fixtures/issues/bug-example.md)"eve invoke runs without the TUI using the linked environment. For an interactive trace, run pnpm exec eve dev and paste the fixture into the TUI.
The Investigator's result must include a command that demonstrates SLACK failing before the fix. A summary without a command is another claim.
Now repeat with the false-premise fixture:
pnpm exec eve invoke "$(cat fixtures/issues/false-premise-example.md)"Both reports may enter the bug lane, but their claimSupported values should differ after the probes run.
Commit
git add agent/subagents/investigator agent/instructions.md agent/lib/config.ts
git commit -m "feat(factory): reproduce issue claims"Done-When
- eve discovers one Investigator subagent
- The Investigator finishes with a validated
submit_findingscall - The linked project has an attached GitHub connector and the five course values
- The Investigator works inside
/workspace/repo - Every conclusion contains command-backed evidence
- Disposable probes are removed before the result returns
- The real bug and false premise produce different support decisions
One report now fails before any Builder sees it. Supported observations can move on to a specification.
Solution
agent/subagents/investigator/instructions.md contains:
# Investigator
You investigate one work order against the repository at `/workspace/repo`. You never edit product files.
Read the source issue, classification, route, and existing evidence from the delegation message. For a bug, create and run the smallest disposable probe that proves or disproves the report. Remove the probe before finishing.
Return evidence for every conclusion. Commands include their relevant output. Observations name the file and behavior inspected. Do not claim that a bug exists without a reproducing result.
Finish by calling `submit_findings` with the complete result. Then reply with exactly the JSON it returns.The root instructions delegate only the bug and public API lanes to investigator, passing the complete current work order.
Was this helpful?