niceeval dependency, niceeval init has run, and you reached this page from the packaged INDEX.md. Speak with the user in their language. Treat the packaged documentation as the authority for every API, field, and CLI behavior; do not invent details from training memory.
Step 1: Explore the project, then confirm the path with the user
This step determines the rest of the workflow. Inspect the code first, present the findings for the user to confirm, and ask only about facts you could not discover. Do not open with a long questionnaire or make an unexamined assumption. Discover:-
What kind of Agent this is. Read the README,
package.jsondependencies, routes, and Agent-loop code. Identify the stack—AI SDK, LangGraph, OpenAI Agents SDK, Claude Agent SDK, or a custom loop—and the core use case, such as support, SQL, or coding work. -
How the frontend and Agent communicate. Is it HTTP, gRPC, or WebSocket? Is the protocol standard or custom: AI SDK UI Message Stream, OpenAI Responses or Chat Completions, an SDK event stream, or custom JSON/SSE frames? This decides whether a built-in Adapter needs no mapping or a custom
sendmust map events. - Whether the backend already has OTel. Look for OTel SDK initialization, AI SDK telemetry, LangSmith, OpenLLMetry, OpenInference, or related instrumentation. An existing setup makes Tier 2 nearly free.
-
Whether the user already has A/B tests or feature flags. Existing variation switches are an immediate Tier 3 entry point because an Experiment can pass them through as
flags. -
Which Judge to use. Semantic scoring with
t.judge.autoevals.*needs a Judge model separate from the Agent under test and an OpenAI-compatible/chat/completionsendpoint. Ask which key and Judge model the user wants. There is no built-in default. A missing key does not silently pass: a Judge assertion becomesunavailable, and a non-optional assertion makes the Attempterrored. Use precise assertions only when the user deliberately omits a Judge or explicitly chains.optional(). -
Whether the Agent itself needs a Sandbox. A coding-agent CLI, or a Skill, Plugin, Hook, or MCP server written for one, must modify files and run commands in an isolated workspace. It cannot use an HTTP-service-style
sendpath. RecommenddockerImageSandbox({ image: "node:24-slim" })by default, but confirm whether the local machine or CI has Docker and whether the user needs Vercel Sandbox or another remote provider. Use Docker when the user has no objection. The provider is declared on the Eval or Experiment; there is no CLI flag, project-wide default, or auto-detection. See Choose a Sandbox Provider.
- Tier 1 (send only): No application change. The full assertion set—text, Judge, multi-turn, tool, and HITL—already works here.
- Tier 2 (send + OTel): The application sends spans to NiceEval as well, which enables the call waterfall in
niceeval view. Existing instrumentation makes this nearly free. - Tier 3 (application changes + flags): Expose internal variations as
flagsfor feature A/B testing. Existing A/B switches are ready-made entry points.
Step 2: Configure a Judge
Configure the Judge service identified in Step 1. Judges use an OpenAI-compatible/chat/completions endpoint in niceeval.config.ts:
baseUrl. Supplying only a key sends the request to the official endpoint; the gateway credential then looks expired even though the endpoint was wrong.
Remember these points:
- Misconfiguration cannot pretend to pass. An unresolved model or key, rejected gateway authentication, or Judge timeout records the assertion as
unavailablewith a reason and makes the Attempterrored. A result that could not be judged is neither a pass nor the Agent’s failure. Use.optional()only when one assertion may deliberately be absent, such as an experimental assertion on a development machine without a key. - Verify the setup once. Run a lightweight eval against fixed text before calling the Agent:
t.judge.autoevals.closedQA("Does this text express success?", { on: "operation completed successfully" }).gate(0.8). Then use the receipt’s Run ID withniceeval show --run <runId> --page attempt-<attemptId>and confirm that each assertion has a score. - Do not silently skip a Judge during autonomous onboarding. First look for an available key, such as
NICEEVAL_JUDGE_KEYorDEEPSEEK_API_KEY. If one exists, pointapiKeyEnvat it and verify as above. Only when no key exists should the workflow use precise and shape assertions, and the final handoff must say that a Judge was not configured and why. - The Judge model must be separate from the Agent under test so a model does not score itself. See Judge for precedence and scoring shapes, and defineConfig Reference for the complete
judgefields.
Step 3: Write the three pieces
After reading the documentation selected in Step 1, write these in order:-
Adapter (
agents/*.tsor the user’s established directory). UsedefineAgentto implementsend; put static configuration in factory arguments rather than hard-coding it or readingprocess.env. See Adapter, defineAgent Reference, and Event Reference. Two common mistakes matter: connect the endpoint or mode that exercises the system’s core capability, not merely the easiest endpoint; and declareevidenceCoveragetruthfully. Mapping only final text does not justifycompleteEvidenceCoverage; a false claim is worse than a conservative one. -
Experiment (
experiments/*.ts). Reference the Adapter and declaremodel,flags,attempts, and related settings. Put model comparisons in separate experiment files, each with one pinnedmodel.evals: (eval) => booleandecides which evals each Experiment runs. Paths provide IDs and batch execution; reports consume physical results and coverage facts from the current Sample. -
Eval (
evals/*.eval.ts). Understand the application first, then write an eval around its real core use case. Read its README, routes, tool definitions, or system prompt. For a support Agent, ask a real support question; for a SQL Agent, use a real query task. Avoid a generic “hello” and a meta-question such as “what can you do?” Both fail to exercise the system’s work. Start with one input,t.succeeded(), and one assertion about the expected answer, but treat that shape as a connectivity scaffold rather than the delivery standard. Before you finish, meet both requirements:- An assertion must fail when the system hallucinates. Do not assert a word already present in the input. Asking “What is X?” then asserting that the answer contains “X” lets the Agent pass by repeating the prompt. Assert real expected facts, structure through
hasSections(), a real URL throughincludesUrl(), or semantic correctness throught.judge. - Add at least one negative case. Give the system input it should not be able to answer, such as a nonexistent table or unavailable topic. Assert that it clearly says it cannot find or perform the task rather than inventing a plausible result. This is often the most valuable early failure shape for an Agent connected to real data or retrieval.
- An assertion must fail when the system hallucinates. Do not assert a word already present in the input. Asking “What is X?” then asserting that the answer contains “X” lets the Agent pass by repeating the prompt. Assert real expected facts, structure through
- Do not call the system directly in-process. Even when the Agent runtime and eval share a codebase, the Adapter should use HTTP or the appropriate transport. Do not replace
fetchwith an import of the system under test. See Connect Your Agent for the reason. - Do not manage the system-under-test process from the eval. Do not spawn the application or open another port. The user starts it the normal way, such as
pnpm dev. When the Adapter cannot connect, report a clear “start the application first” error instead of launching it.
Step 4: Run and verify
niceeval show --run <runId> --page <planned-route> as you observe, edit, and rerun. See Viewing Results for the viewer workflow.
Diagnose an initial failure by its shape: a thrown fetch error means the application is not running or the URL is wrong. A failed t.succeeded() means the application returned a non-success status. If only a content assertion fails, the integration works; adjust the assertion or the application.
Step 5: Finish by telling the user what changed
Before summarizing, run this finish check. If any item fails, return to Step 3 and complete it; do not hide it in the final summary.- Eval inputs exercise the system’s core use case, not a meta-question or placeholder greeting.
- Every content assertion fails when the system repeats the input or hallucinates; its asserted terms are not already in the input.
- At least one negative case makes an unsupported request and asserts an explicit inability to complete it.
- When a key is available, the Judge is configured and a Judge score has appeared in
niceeval view. If no key exists, the summary explains that. - The Experiment’s declared
modelandflagsare actually consumed by the Adapter. There is no dead configuration or invented model value.
niceeval exp <experiment-path> and explicitly selected niceeval view commands, and what the first run showed. Do not refactor existing user code or add unrelated abstractions unless asked.
Step 6: Ask whether the user wants a deeper integration
After the summary, present optional next steps. For each one, explain what it enables, roughly how much code it changes, and what it buys. Let the user choose; do not continue on your own.
All of these are incremental Adapter or application changes. Existing evals do not need to change. See Integration Tiers for what each investment buys and when it is worthwhile. If Step 1 found existing OTel, proactively recommend the waterfall option because it costs almost nothing.