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.
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
1
Create the example
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:
Recovery: if the CLI does not recognize
passed is true. Check the labelled outcomes if a case fails.See the four local case results
See the four local case results
labelled.d-pass-trusted-evidenceas a pass;labelled.d-reject-failed-testsas a rejection;labelled.d-reject-hash-mismatchas a rejection; andlabelled.d-technical-evidence-storeas HTTP 500 with no verdict.
--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:- look up evidence by a bounded, safe identifier;
- 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;
- keep required steps and allowed-tool rules in your code;
- expose every required fact as a named boolean result;
- use semantic judgment only for optional explanation quality or a rule that explicitly includes human review;
- reject when trusted evidence proves a requirement failed, and return a technical failure when the evidence source cannot answer.
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.If an assistant helps with this recipe
If an assistant helps with this recipe
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’snpm 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 Each dimension is between 0 and 1. The check applies its own hard thresholds;
a high score never overrides a failed required fact.
quality_score from signed typed dimensions in the
output check:1
Run the research workflow locally
Copy the generated downloader below into
Unpack the files:Read the included Keep From a fourth terminal, run
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.Copy the downloader
Copy the downloader
README.md and source files, then install the example’s
pinned dependencies and create local-only signing keys and a courier credential:.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: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.
What the attested grade proves, and what it cannot prove
What the attested grade proves, and what it cannot prove
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.Adapt the recipe to CI or another evaluator
Adapt the recipe to CI or another evaluator
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.