Skip to main content

Decide when work can move forward

Check an agent’s result against evidence your systems control: test results, artifact hashes, or a signed research grade. Millwork records the verdict, score, and named results; your application decides whether to release, revise, or stop the work.

Explore the Temporal research gate

Run the durable research example locally, then use its signed grade in the same output-check path.
Goal: try the included completion check, then use your own evidence to decide whether work is finished. You are done when: your customized check has a local passed: true report for complete evidence, a failed requirement, and an unavailable evidence source with no verdict. Run the sample without an organization key or evidence service, then connect your own records.

Candidate

Names an evidence ID. Its own completion claim cannot prove a tool ran, a test passed, or a file exists.

Your check

Reads trusted artifacts and test results, then applies your completion rules.

Outcome

Pass when the artifact hash matches and required tests pass. Reject a mismatch or failed test; return no verdict if the source is unavailable.

Where this pattern fits

The optional Temporal research example implements the first row; the local example above needs no Temporal setup. Use your own trusted records for the other workflows.
1

Create the example

Expected result: selected_recipe is d, selected_check ends in recipe-d-completion-evidence.mjs, deployed_check ends in selected-check.mjs, and next_action tests selected-check.mjs.
2

Run the local cases

Run the printed command:
Expected result: passed is true. Check the labelled outcomes if a case fails.
  • labelled.d-pass-trusted-evidence as a pass;
  • labelled.d-reject-failed-tests as a rejection;
  • labelled.d-reject-hash-mismatch as a rejection; and
  • labelled.d-technical-evidence-store as HTTP 500 with no verdict.
Recovery: if the CLI does not recognize --recipe, stop. Check the install guide for a recipe-capable version; until it lists one, use its non-recipe path. If a labelled case fails, inspect its named results. Fix the evidence lookup or completion rule, then rerun the same local command.
3

Connect your evidence source

Replace readTrustedEvidenceById with a read from the system that owns the facts. The example map is only an offline fixture. Keep these rules:
  1. look up evidence by a bounded, safe identifier;
  2. fetch artifact bytes, the recorded hash, and named test results from that source; compare the computed hash with the record and your required digest, then require every test ID in your code;
  3. keep required steps and allowed-tool rules in your code;
  4. expose every required fact as a named boolean result;
  5. use semantic judgment only for optional explanation quality or a rule that explicitly includes human review;
  6. reject when trusted evidence proves a requirement failed, and return a technical failure when the evidence source cannot answer.
The generated example shares one evidence-read promise between runHardCheck and scoreQuality. Preserve that sharing so the verdict and score use one trusted record.The output-check request contains only the candidate. Your service must fetch repository, CI, or artifact facts from its own trusted source. Rerun the Step 2 command against selected-check.mjs after your edits. Deploy only when your own pass, rejection, and technical-failure cases all pass.
4

Continue to deployment

Read the shared endpoint contract and reserved-probe limits. Your next executable step is Deploy and test HTTPS. Continue with Recipe 0 for connection, paid-run approval, receipt reading, and recovery. In the final receipt for a checked run, confirm required_test_ids_present, required_tests_passed, and artifact_hash_matches under named results.
Require the assistant to name the trusted source for every required result. Reject any design that reads proof only from candidate prose. Supply source credentials through your service, never chat. Approve endpoint test traffic and each paid Millwork run separately.

Run a durable research quality gate with Temporal

A research agent can draft and revise in a durable Temporal workflow while a grading service you control fetches cited and policy-required sources and judges the report. A separate output check verifies the signed result. Millwork records its verdict, quality score, and named reasons with the governed run; your application can use that record to release a report, request revision, reject it, or improve the next iteration. The included example contrasts an overbroad first report with a narrower report supported by the fetched sources. It tries up to two supplied drafts; you add your own agent and revision Activity to generate them. Goal: check a finished research report against evidence signed by your grading service before returning a verdict to Millwork. Local milestone: the workflow carries a signed grade, the offline cases pass, and the output check names a failed requirement without trusting facts supplied by the graded agent. The connected, governed outcome is a Millwork receipt for a run you explicitly approve; the local example does not make that paid run. You need Node.js 20 or newer and the Temporal CLI. The example’s npm ci installs the published Millwork CLI @millwork/solver@0.1.20 for its local cases; no global CLI install is needed.

Make this your check

Keep the output-check contract stable while you change the evidence and decision rules for your work: The check remains a bounded read of completed evidence. It does not start, wait for, or grade a workflow during Millwork’s request. Your agent supplies a report and starts a durable Temporal workflow. A courier Activity asks the check-owner grading service to fetch sources and judge the report. By default, the grader chooses every artifact citation plus every source required by its versioned policy; it refuses caller-supplied excerpts, support labels, and pass facts. It signs the evaluation, then signs a separate issuance bound to the exact workflow_id and run_id. The workflow carries those records in its capped close-event result. Your output check reads that exact completed run, verifies the signatures against pinned keys, re-derives the facts, and applies thresholds from its own configuration. It never starts or waits for a workflow. Follow the report from your agent through the grader you control to the Millwork receipt. The signed grade travels with the exact completed Temporal run; the output check reads it without repeating the long-running work.
The example computes quality_score from signed typed dimensions in the output check:
Each dimension is between 0 and 1. The check applies its own hard thresholds; a high score never overrides a failed required fact.
1

Run the research workflow locally

Copy the generated downloader below into temporal-example.mjs in a clean directory. Review it before running it. It fetches one JSON bundle from this docs site, checks its file list and all 32 files against fixed SHA-256 hashes, and refuses an existing target directory. It does not run a Millwork task or contact an evaluator.
Unpack the files:
Read the included README.md and source files, then install the example’s pinned dependencies and create local-only signing keys and a courier credential:
Keep .local-data/ private. The setup command creates new local keys; it is not a production key-rotation procedure. In separate terminals, start Temporal’s local service, the check-owner grading service, and the courier Worker:
From a fourth terminal, run npm run start. The local grader uses source fixtures and an offline evaluator, so this path needs no provider key or paid run. Replace those fixtures with sources fetched under your own policy when you adapt the example. Expected result: the client prints a candidate with the report and exact run IDs. The workflow carries signed records; its own pass claim is not authoritative. Temporal’s TypeScript quickstart documents this CLI command, a conventional Worker, and the local service at localhost:7233 (checked 2026-09-29).
2

Run the offline output-check cases

Run npm run cases from the example directory. It runs the offline trust and failure matrix and the local millwork verifier test contract cases, then prints a pass summary. Look for a pass in both parts. This test needs no Temporal server, external source fetch, evaluator key, or paid Millwork run. The matrix covers a valid attested report, self-grading and omitted-source attacks, forged or replayed records, source-fetch bounds, grader retry and budget failures, malformed evidence, the reserved probe, and Temporal unavailability. A failed requirement yields a rejection. An allowed Temporal connection or credential failure yields no verdict. The endpoint does no model inference or grader call during the Millwork request.Missing or malformed run_id values and workflow IDs outside your configured prefix reject before any Temporal call. The check never substitutes the latest run of a reused workflow ID.
3

Connect through Recipe 0

The sample endpoint binds to 127.0.0.1 for local use. For HTTPS deployment, put a reverse proxy on the same host in front of it, or deliberately change its host binding for your deployment.Use Recipe 0 to deploy and test HTTPS, connect the check, request approval for a paid run, and inspect its receipt. Connection and local tests do not approve a paid run. Look for the specific failed requirement under anchor_results; quality_score cannot turn a rejection into acceptance.Your application decides what to do with the verdict and named results. The receipt does not contain the report or authorize an automatic release.

Choose the evidence authority

These trust postures support different claims. The included cross-party path uses attested grading; choose the authority that matches your deployment before relying on a connected receipt. The signed grade does not prove that the report is universally correct or that no uncited source contradicts it. Its coverage claim is limited to the check-owned policy-required source set. In citation-only teaching mode, the author chooses the sources; an omitted contradictory source may go unchecked. Temporal Task Queues route work among Workers, and Worker identity is an optional human-readable string (checked 2026-09-29). This example treats neither as grader authentication. The local demo runs all processes on one machine; a cross-party deployment keeps the grader, its keys, and the output check under the check owner’s control.
The capped close-event result carries signed evaluation and issuance records, not an authoritative self-reported pass. The evaluation binds the artifact hash, source-selection policy, required and derived source-set digests, coverage outcomes, fetch hashes, typed judgments, evaluator version, and expiry. The issuance binds that evaluation to the exact Temporal workflow_id and run_id. The output check verifies both signatures against check-owner pinned keys, then computes its own named facts and hard decision. It rejects revoked keys and stale records.A pass means the report met the check owner’s policy against the sources that policy required. It is not open-world truth. The grader’s source policy, fetched content, evaluator calibration, and signing-key custody determine what the claim is worth. The graded agent cannot make its own support labels or thresholds authoritative by placing them in the candidate or workflow result. For network sources, keep an origin allowlist and validate every redirect and resolved address before connection; a blocked or missing source cannot pass.The candidate contains the report and exact run IDs, but no Millwork run ID. The check cannot prove that the report answers this particular governed task. A fresh signed run may be resubmitted within the configured window; freshness limits replay but does not prevent it. Keep source documents, raw evaluator responses, traces, and credentials in your systems, never in the candidate or receipt. String artifacts are hashed as UTF-8; JSON artifacts use canonical JSON so equivalent serialization keeps the same hash.Temporal’s TypeScript client reference distinguishes an exact run_id from the most recent run with the same workflow ID; its execution handle can read the recorded history (checked 2026-09-29). Keep the configured freshness window shorter than your Temporal namespace’s retention period (checked 2026-09-29). Once Temporal has removed a closed execution, the check rejects because its evidence is unavailable. Copy the signed records to your own store if you need longer retention; that requires adapting the endpoint’s evidence read and keeping the exact run binding.
For a CI job, have a check-owner service read the pinned build, artifact hash, and named test results, then sign its evaluation. The workflow carries that record to the same read-only endpoint; the check verifies it and applies the release policy it owns. A failed test is a rejection; an unavailable evidence source or endpoint-to-Temporal connection is a technical failure with no verdict. A report written by the build under test is not an independent test record.For paid evaluator or tool calls, keep the grader’s budget and admission separate from Millwork’s governed-run approval. The grader admits one bounded evaluation per artifact and policy key, records incurred or uncertain costs, and does not reissue an ambiguous paid call automatically. Repeated issuance for the same evaluation and exact run adds no evaluator work.The optional Jev path uses TypeSafe for narrow semantic judgments on excerpts fetched by the check-owner grader, such as whether a source supports a claim. Exact citation lookup and hard policy thresholds stay in code. It is disabled in the local path. To select it, the check owner must configure an HTTPS capped proxy with JEV_CAP_PROXY_URL and JEV_CAP_PROXY_TOKEN. That proxy enforces the admitted max_cost_units and returns authoritative_cost_units; the example does not send a provider key directly. TypeSafe’s HTTP request reference documents model, state, and questions; it does not document a per-request spend cap (checked 2026-09-29). For a Jev check without Temporal, start with Check citations with Jev. TypeSafe’s citation-check example uses code for quote matching and a typed Choice for contextual support, while its Score primitive grades a defined dimension (both checked 2026-09-29). The offline double is the default and runs in CI without a provider key. A live evaluator call needs your own private configuration and cost approval.Temporal’s Durable AI guide and integration catalog show other agent compositions (checked 2026-09-29). Its Serverless Workers are Public Preview as of that date; they are not needed for this example.