---
name: millwork
description: Set up Millwork, prepare and manage output checks, run tasks on saved models, and verify answers and receipts. Use for Millwork onboarding, output-check work, and recovery.
license: Apache-2.0
metadata:
  author: millwork
  version: "1.1.0"
---

# Millwork

Use Millwork to run tasks on saved AI models through one API and keep a receipt
of how each run was handled.

The copy of this guide at `https://docs.getmillwork.dev/skill.md` can be up to
24 hours old after a documentation release. The same guide at
`https://docs.getmillwork.dev/agents/millwork/skills/millwork/SKILL.md`
revalidates on each request.

## Choose the requested task

Start with the user's requested task. For preparing, connecting, testing, or
managing an output check, follow “Connect and use an output check” below. Use
“First answer with an agent” when the user asks to set up a model or get a
first answer. Reuse the selected organization, model, and check. Stop when the
requested setup is complete; preview a paid run only when the user asks to run
a task.

## First answer with an agent

Drive the existing public CLI until the user has an answer and its matching
receipt. The user supplies missing account/model choices, private credentials,
provider consent and explicit spending approval. Collect non-secret facts and
perform already-authorized steps yourself; do not ask the user to orchestrate
commands between browser consent and the answer.

If this assistant is already connected through the Millwork execution MCP
(`@millwork/solver-mcp`), use its tools instead of the CLI and follow
[execution MCP](https://docs.getmillwork.dev/mcp/execution.md). A run needs a
saved model, not only a catalog entry. Start with `solver_list_arms` and reuse
a saved model that matches what the human chose. If none matches, read
`solver_list_model_catalog`, let the human choose one entry, and save it with
`solver_enable_model_arm`, copying that entry's `arm_registration_template`
unchanged and keeping the returned `arm_id`. A new organization can list
catalog models and still have no saved model, and a live submission with no
eligible saved model fails. Prepare the exact paid-run preview, then call
`solver_submit` with a request key and `routing.required_arm_id` set to that
`arm_id`, so no other model can be selected. Read the run with the
read-only `solver_status`, `solver_result` and `solver_receipt`. The human sets
the organization key in the assistant's own MCP settings, never in the
conversation. If no key is set there, send the human to private key entry on
[terminal setup](https://docs.getmillwork.dev/get-started/tenant-start.md); that
continues as the CLI journey below.

For a live MCP submission on a server with host-isolated admission, the machine
host must approve the exact request and request key through its attested one-run
channel. A prompt, tool argument, launch environment, agent-written file, or
standing authorization cannot supply this authority. When `solver_submit`
returns `host_approval_required`, give the returned document only to the host
administrator. Retry the exact same arguments and request key after the host
writes it. Never mint a new key to hide an unknown result. If the installed
server does not report this capability, stop and report its installed version;
chat approval is not a substitute. Echo mode is free and does not need this
approval.

Millwork requires the documented organization access and Node.js 20 or 22.
All relative documentation paths below start at `https://docs.getmillwork.dev`.
Read [terminal setup](https://docs.getmillwork.dev/get-started/tenant-start.md)
for account prerequisites and private key entry. If a browser retrieval tool
refuses a public page, try direct HTTPS retrieval of its `.md` URL or
[the index](https://docs.getmillwork.dev/llms.txt). A tool refusal alone is not
a site outage. Docs MCP is optional; it cannot inspect account state.

### Resolve the CLI once

Start with `npx --yes @millwork/solver@latest --version --json`. Read its
`package_version` and retain that exact version for every
subsequent command: `npx --yes @millwork/solver@<verified-version> ...`.
An older global `millwork` can win when the package version is omitted.
`--yes` approves npm's download prompt, not a Millwork plan or paid run.
The commands below use `millwork` as shorthand for that verified npm command.
If the CLI prints an unversioned npm continuation command, replace its prefix
with the saved version while preserving all application, digest and request-key arguments.

Run `millwork doctor --json` and `millwork docs --json`. Do not print environment
variables or read the key file into the conversation. If the key is absent,
run `millwork tenant start` in the user's local interactive terminal and keep
the command open. A supported CLI opens the normal system browser to a private
    local page where the human enters a Millwork organization API key for the intended
organization. Never ask for the key in chat, read it from the clipboard or a
file, or put it in a shell argument. This page is account setup, not provider
setup, and it does not approve paid work. With a release that supports terminal
key entry, run `millwork tenant start --no-browser` in an interactive terminal,
including over SSH or without a graphical browser. Both stdin and stdout must
be TTYs. The human enters the organization key at the hidden prompt; the CLI
checks and saves it, then continues the same command. CI, `--json`, `--plan`
and `--dry-run` do not prompt for a key. If the resolved release predates the
chosen entry method, or the session is CI, scripted or non-interactive, direct
the human to the documented private terminal fallback; load `SOLVERAPI_API_KEY`
from a secret store for automation. `--json` stays
passive unless the human explicitly chooses `--open-browser`. Link to
[API keys](https://app.getmillwork.dev/keys). A key on a hosting service does
not configure this machine. Doctor checks configuration only; authenticate
with `millwork provider list --json` once the intended key is configured.

### Keep setup responses private

Before any saved-application inspection, apply, resume or browser command, create an owner-only working
folder with `umask 077` and `MILLWORK_SETUP_DIR="$(mktemp -d)"`. Keep its path
in this task. Redirect stdout to `"$MILLWORK_SETUP_DIR/application.json"` and
stderr to `"$MILLWORK_SETUP_DIR/browser.txt"`; do not print these files into
chat. Every command below that can return a consent link uses this routing.
Preserve an earlier response before replacing it when it is still needed.

`tenant show --json` also contains saved applications and can include consent
links. Capture it the same way. Read only a selected projection into the agent
transcript, for example:

```bash
node -e 'const fs=require("node:fs"); const d=JSON.parse(fs.readFileSync(process.argv[1],"utf8")); const a=d.applications?.[0] ?? d; console.log(JSON.stringify({application_id:a.application_id,application_key:a.application_key,retried_with_fresh_key:a.retried_with_fresh_key,state:a.state,next_action:a.next_action?.type,live_proof:a.live_proof,live_execution_id:a.live_execution_id,result_execution_id:a.result?.execution_id,receipt_id:a.receipt?.receipt_id}));' "$MILLWORK_SETUP_DIR/application.json"
```

Keep the full answer, consent URL and diagnostics local. For spending review,
read the model/payer from `diagnostics.requested`, the combined allowance
from `diagnostics.maximum_spend_usd`, and the model budget/runtime from
`diagnostics.request_policy.budget.max_cost_usd` / `max_runtime_s`. The
platform fee is combined allowance minus model budget; if either number is
missing or invalid, stop before paid approval. `live_proof` contains only the
digest and its issue/expiry times. Do not dump raw diagnostics. If no private terminal/output surface is available, use the
human's own terminal for the private step rather than expose its response.

### Inspect, choose and plan

Inspect any saved application with `millwork tenant show --application-id
"<saved application ID>" --json`. Without a saved ID, use the original template
and custom request key with `tenant show`; an unfiltered lookup can find a
different journey. Never create a new application to investigate a lost response.

If the user has not chosen, ask whether to use a model Millwork provides or
their own provider account. Discover actual availability with `provider list
--json`, `models list --json` and the plan's `byok_offerings`. An example in a
provider table is not availability evidence. Preserve the chosen organization,
source, authentication method, model and deployment; do not substitute a payer
or provider. Explain a single available choice; ask when several match.

When `tenant start` returns `setup_recovery.type: existing_ready_setup`,
explain that the application, completion time and model describe a saved
result. For an explicitly requested new setup, use `tenant start --new-setup
--json` with the user's template and model choices. Review its plan before
running `next_action.command`; retain `application_key` for retries. Do not
use `--new-setup` to investigate a lost response. See
[Start another setup](https://docs.getmillwork.dev/get-started/tenant-start#start-another-setup).

Use `tenant start --plan --json` for a Millwork-provided model. For the user's
provider account, add `--template byok-open-model`, then select `--source-id`
and `--served-variant-id` from the same offered row and re-plan with those
values. Preserve an explicit `--model-deployment-id` too. Review the exact
plan's effects, costs, `digest`, `issued_at` and expiry. The setup request
can already authorize its named non-spending effects; do not ask for another
approval of those effects. Apply using the same choices plus `--digest` and
`--issued-at` only within that authorization. A funded hosted plan can already include paid work at this stage.
A BYOK plan defers live spend to the later approval below. Save its returned
`application_id` and setup request key. If the CLI reports
`retried_with_fresh_key`, retain its `application_key` as that request key.
The CLI saves the replacement before retrying and keeps it after success.
On failure, read `next_action` locally: `recover_setup` continues the same
approved request after an uncertain response; `inspect_setup` only reads saved
state after a refusal or blocker. Address the reported problem before
continuing. Do not replay an expired or rejected approval. Keep the same
template, model and approval choices for recovery; once `application_id` is
available, continue that application.

### Use the user's normal browser

Say: “I'll open your normal browser for the private setup step. This setup is
saved; return here when you're done and I'll continue it.” Use the OS/default
browser, never the coding assistant's embedded browser for authentication,
provider approval, keys or billing. Do not force a browser brand or change the
default. In a local interactive flow the CLI already requests the OS browser.
In an agent JSON flow, once the user authorizes opening it, run:

```bash
millwork tenant start --application-id "<saved application ID>" --json --open-browser \
  > "$MILLWORK_SETUP_DIR/application.json" 2> "$MILLWORK_SETUP_DIR/browser.txt"
```

This presents the current step; opening a page is not consent or a connection
check. Opening or presenting consent in JSON mode does not poll for browser consent
or approve spending. An already queued live run can still be polled to its
result and receipt. Keep its output
on an owner-only local terminal/setup surface: JSON can contain a private
consent URL, and the presenter prints a private fallback link on stderr. Do not
stream either raw output into an assistant transcript, shared logs or evidence.
Capture it privately before reading only the non-secret fields needed for the
next action. Never pass the private URL to an assistant browser tool or a
plugin launch link. Public dashboard/key/billing/docs URLs may be shared in chat.

For SSH, a headless session, `--no-browser` or a failed launch, direct the user
to “Open in your browser” using the current private link on their local setup
surface and its expiry. If this client cannot expose such a private surface,
the user runs the saved continuation command in their own terminal once.
Resume agent orchestration after that private step. Do not ask for a URL,
authorization code or provider key in chat. Do not re-open a used approval link;
inspect the application first.

### Continue the same application explicitly

A bare `tenant start --application-id ... --json` presents existing state; it
does not consume completed browser consent. After the user finishes, perform
the existing consent observation on that same application:

```bash
millwork tenant start --application-id "<saved application ID>" \
  --resume-action poll_consent --idempotency-key "<new poll operation key>" --json \
  > "$MILLWORK_SETUP_DIR/application.json" 2> "$MILLWORK_SETUP_DIR/browser.txt"
```

Read the returned state and `next_action`. Consent may still be pending; keep
the setup saved and ask for the remaining browser action. A new observation
uses a new operation request key. A transport retry of that exact operation
retains its key; reusing a previous poll's key replays that old observation.
Do not spin indefinitely, create a second application or automatically retry
paid work. Consent can lead to connection checks and a free Echo test, within
the setup effects already approved. These are not the first live answer.

When `next_action.type` is `authorize_byok_live_proof` or
`authorize_pool_live_proof`, read `live_proof` and `diagnostics`: exact model,
payer, platform fee, model allowance, runtime and expiry. Ask the user to approve that concrete spending proposal.
Only after approval, submit its exact digest:

```bash
millwork tenant start --application-id "<saved application ID>" \
  --resume-action authorize_live_proof \
  --live-proof-digest "<approved live_proof.digest>" \
  --idempotency-key "<this approved operation key>" --json \
  > "$MILLWORK_SETUP_DIR/application.json" 2> "$MILLWORK_SETUP_DIR/browser.txt"
```

Initial-plan `--digest` / `--issued-at` and the later `--live-proof-digest`
authorize different stages. Never mix them or treat a refreshed proposal as
approved. Inspect an uncertain result before retrying the same operation;
never authorize another paid attempt automatically.

### Recover and verify

Follow the saved application's actual next action. Refresh an expired spending
proposal with `refresh_byok_readiness` for the user's provider account or
`refresh_pool_readiness` for a Millwork-provided model, using the same
`--application-id`, `--resume-action` and a new operation key. These refreshes
do not authorize spending. Review the new proposal before authorizing it.
`retry_consent`, `retry_connection_test` and `retry_deployment_sync` are distinct
recovery actions: use only the one the application requests, within the user's
existing approval; ask if its effects need a new choice or authorization.

Credential replacement uses the existing connection and the CLI's printed
[rotation continuation](https://docs.getmillwork.dev/cookbook/replace-a-provider-key.md).
Keep that attempt's request key and handoff ID while it is pending. If it
expires or fails, inspect the connection, then use the printed fresh-attempt
command within the user's replacement approval. Do not reuse a dead attempt
or create another connection. Capture these responses privately too.

Distinguish missing local key, rejected key, organization access, unavailable
provider/model, Millwork fee credit and provider billing. Use the reported
reason and [connection help](https://docs.getmillwork.dev/help/provider-connections.md).
Link to [Billing](https://app.getmillwork.dev/billing) for Millwork credit only;
do not invent a provider balance. Funding or refreshing never approves a run.

Verify a completed live execution with an available answer and a matching
receipt, using non-empty execution IDs from both. CLI completion supplies
`output` and `execution_receipt`; `result.execution_id`, `output.execution_id`
and the receipt's `execution_id` must agree. Check `mode: live`, terminal
success and the selected model/provider/payer where recorded. Keep requested
and provider-reported identity distinct; missing provenance proves neither.
Give the user the local answer location and receipt reference with recorded
costs. Keep answer content private unless the user explicitly requests it in
this conversation. “Connected,” a ready saved model, a catalog check or Echo alone is
not completion. If the answer is unavailable or the run failed, preserve the
IDs and explain the exact next action without claiming success.

## Connect and use an output check

Read [Connect an output check](https://docs.getmillwork.dev/guides/connect-an-output-check.md)
before changing verifier state.

### Discover the available path

For the CLI, resolve and retain one installed version, then run
`millwork verifier capabilities --json` before choosing commands or flags.
That discovery is offline, needs no account key, and reports the installed
version, supported commands, access vocabularies, and the
[verifier-dock contract](https://docs.getmillwork.dev/contracts/verifier-dock/v1.json).
Run `millwork verifier init output-check --recipe 0 --json` to create the
maintained adapter. From the same directory, run the returned `next_action`
unchanged. It currently is
`cd output-check && millwork verifier test --local --check selected-check.mjs --access authenticated --json`
for labelled local cases. Use `--access public` only if the endpoint accepts
requests without credentials. The
[deployment recipe](https://docs.getmillwork.dev/cookbook/output-checks/build-the-dock.md)
shows how to host that selected check. Connecting additionally requires an
approved organization, a privately configured organization key, `jq`, and a
compatible HTTPS endpoint. A local pass does not prove deployment or connection.

For the execution MCP, inspect the installed `tools/list`. The released
`@millwork/solver-mcp@0.2.16` includes `solver_list_verifiers`,
`solver_show_verifier`, `solver_connect_verifier`, `solver_test_verifier`,
and four protected-connection lifecycle tools. Use those installed tools
for a secretless connection; the key stays on Millwork's private page. An
older installed server may lack them, so use the CLI or dashboard then.
Pass the saved `verifier_id` on `solver_submit`. Never ask for an endpoint
secret in chat or an MCP input.

### Prepare, connect, and confirm

Follow the guide's maintained adapter and labelled local cases. If a local case
fails, stop and fix it. For public access, connect only an already-deployed
endpoint that accepts requests without credentials. For protected access, use
the maintained protected deployment recipe.

For protected human key entry, let the installed CLI open the person's normal
browser to the private Millwork page. In an interactive headless session,
`--no-browser` uses a hidden terminal prompt; the person may instead open
the private page link in their own browser. Do not use the assistant's
embedded browser for either path. Do not use `--json` or output redirection
for the hidden prompt. The assistant must not observe the key-entry session.
Retain the nonsecret verifier ID after completion.

For configured customer automation, capture JSON and stderr in an owner-only
directory. Expose only the allowlisted status, reason, handle, operation key,
verifier ID, and intent ID fields to the assistant. Automation may supply
`VERIFIER_CONNECTION_SECRET`; the assistant must not read, create, print, or
change it. Never pass a key through MCP, chat, arguments, logs, or a shared
artifact.

If protected initial setup returns `state: "action_required"`, retain its
`verifier_id` and `intent_id` as nonsecret identifiers. Keep `continue_url` on
the private local handoff surface. Have the person sign in to Millwork in their
normal browser with the same organization and an account that can manage
checks, then open that URL and enter the key privately. Finish the saved
connection with `millwork verifier continue --verifier-id <id> --intent-id
<intent> --json`, using the same organization API key. Confirm the result's
nested `connection.status` is `active` and `verifier_id` matches the saved ID.
Do not create another connection to investigate an uncertain response.

For a public connection, require `headline: ready`,
`probe.contract.validated: true`, and a nonempty verifier ID. For a protected
connection, first require its saved connection `status` to be `active` and its
verifier ID to be nonempty. Then run a fresh remote test with a new test request
key and require that test's ready headline, validated response contract, and
matching verifier ID. An ID from a failed or pending operation is not proof of
readiness. If the user's task was only to connect the check, report this
evidence and stop.

Every new remote test is a new observation and needs a fresh caller-owned
request key. Reuse that key only when recovering a lost response from that
exact test. The CLI's stable default can replay an earlier observation, so pass
`--idempotency-key` explicitly whenever the intent is to observe the endpoint
again.

### Run through the CLI

Proceed only when the user asked to run a task. Name the saved model, verifier
ID, task, and either the current model's proved preset or an explicit policy
with customer-chosen positive model budget, time limit, and data class. Run the
preview with `--json` when orchestrating it.

If `next_action.type` is `obtain_host_one_run_approval`, show the exact model,
payer, data classes, runtime, platform fee, model budget, combined allowance,
request hash, and replay key. Preserve the task and the replay key. Give the
user `host_approval.approval_file` and `host_approval.document`; only their
host administrator can create that file. When it exists, run the returned
`replay_command` exactly as printed. There is no approval prompt. Never tell
the user to approve the run in a terminal, and never claim `--yes` or your own
identity approves it. Treat `refresh_billing_configuration` as a separate
action that grants no spending approval. Assistant identity, JSON output, and
`--yes` are never permission.

If a submission response is lost after an attempt, retain the original command
and replay key and recover that same run. Do not remove `--json` as part of
unknown-outcome recovery, and do not create a new paid request.

### Run through the execution MCP

Use the host one-run approval flow described above. Prepare the exact task,
saved model, policy, output check, charges, and request key. Then follow the
installed schema with `task.objective`, `policy.data_classes`,
`policy.budget`, `routing.required_arm_id`, `verifier_id`, and a caller-owned
`idempotency_key`. If `solver_submit` returns `host_approval_required`, preserve
the exact arguments and request key while the host administrator acts. If the
submission outcome is unknown, retry those same arguments and request key; do
not create another paid request. A CLI replay command does not apply to MCP.

### Verify the same run

Retain the run ID. For CLI JSON, read the `execution`, `result`, and `receipt`
wrappers from that same response; for MCP, use the read-only status, result,
and receipt tools. Confirm the receipt's verifier ID matches the selected
check. Treat `is_correct: false` as a recorded rejection and keep
`quality_score` separate from correctness.

A missing verdict or `NOT CHECKED` is not itself a rejection or proof of a
technical failure. Read the run status and the receipt's `verification_checks`
to learn whether the customer check was attempted. Distinguish queued or
running work, a run that ended before the check, and an attempted customer
check with `technical_failure`. For `technical_failure`, report its evidence,
fix that cause, and run a fresh endpoint test before proposing another paid
task. Do not replace credentials based only on absent evidence.

### Recover or stop protected access

For protected-key replacement, configure the endpoint to accept the old and
new keys before starting `verifier replace`; remove the old key only after
Millwork confirms the switch. `verifier disconnect` stops Millwork use but
does not revoke the endpoint's copy. `verifier restore` always uses a new key.
When the CLI reports `unknown` or `pending`, use its exact continuation with
the same operation key and handle, capture it privately, and read the current
connection status before using the replacement key. Do not start a second
lifecycle operation to investigate a lost response.

If initial setup returned a verifier ID and intent ID for private entry, finish
that saved connection with the `verifier continue --verifier-id ... --intent-id
...` command above. If initial terminal setup was interrupted without those
references, inspect the existing connection before changing it again. Do not
create another connection to discover what happened.

## Public documentation

- Start with `/llms.txt` to find the relevant page.
- Read the page's prerequisites, steps, expected result, and recovery guidance.
- Use `/llms-full.txt` only when the complete public documentation is required.
- Use [the generated REST lifecycle reference](https://docs.getmillwork.dev/api-reference/output-checks.md)
  for output-check operations and the [verifier-dock contract](https://docs.getmillwork.dev/contracts/verifier-dock/v1.json)
  for the endpoint request and response. The OpenAPI file owns the exact HTTP fields.
- For a first integration, start with `/get-started/first-api-call.md` for a free
  test run over REST. Continue with `/get-started/builder.md` for a live model run.
- Use the documentation MCP to search and read these docs. Its `submit_feedback`
  tool sends a message to the docs team; show the proposed text and obtain approval
  before sending it. The documentation MCP cannot access the organization.
- For terminal setup, follow `/get-started/tenant-start.md`. The CLI calls an
  organization a tenant. Installation and account access are separate: follow
  the guide's organization and permission prerequisites before sending requests.
- The CLI setup guide includes the first paid model answer and follow-on tasks
  with the selected model. Use the human’s existing saved Millwork organization API key first,
  which a supported local CLI reuses without a manual export. If no key is saved,
  follow the browser or hidden-terminal entry rules above. Do not request or
  extract it through chat, clipboard, command arguments, logs, or agent tools.
  For automated or non-interactive use, follow the documented secret-store fallback.
  If needed, direct them to
  [Millwork dashboard → API keys](https://app.getmillwork.dev/keys)
  to create one for the intended organization. Never read or print the key.
  Browser consent and paid approval stay with the human.
- For a direct API alternative, read `/get-started/builder.md`. It shows how to
  choose a catalog model and submit a run with separate approval.

## Supported tasks

- Check the installed CLI with `millwork --version --json`, `millwork docs
  --json`, and `millwork doctor --json`. These commands check the local installation and configuration.
- Plan setup for an approved organization, review its exact effects within
  the user's authorization, then continue the same application. Obtain explicit
  spending approval before applying a plan whose effects include paid work. Use a model Millwork provides with
  the human's Millwork organization API key. Connect the human's own provider account only
  when they choose that option. In a non-interactive session, planning and
  applying are always separate commands.
- When the human chooses their own provider account, use `millwork provider list`
  for available providers and existing connections. Read the plan's
  `byok_offerings` for exact model choices. Do not pick the first row when
  there is more than one. Provider setup can reuse an existing connection.
  Read [provider setup](https://docs.getmillwork.dev/guides/connect-a-source.md#connect-from-your-terminal)
  for all nine offered providers, exact connect commands and key-management links.
  Initial key-entry setup needs exactly one active key from the intended
  provider scope: OpenAI project, Anthropic workspace, Google Cloud project
  for Gemini Developer API, Kimi project, or Fireworks/xAI/DeepSeek account.
  The human does not enter a generic account/project/workspace reference in
  the CLI. Link them to the provider-specific guidance returned by the CLI and
  keep the key on Millwork's private browser page.
- Use `provider connect <source-id>` or the equivalent BYOK template with
  `--source-id`. For a script, request `--plan --json`, then repeat the exact
  source/model or deployment choices with the approved digest and issue time.
  A custom journey request key is optional; keep it when continuing that journey.
- When CLI setup needs a browser, give the human the application ID, deadline
  and returned continuation command, including its npm form if needed.
  OpenRouter uses browser approval; key-entry providers use private key entry.
  New AWS Bedrock setup defaults to private Bedrock API-key entry; STS is explicit
  advanced setup. A saved connection keeps its existing method.
  Inspect the same application with `tenant show --application-id` after they
  finish, then use the explicit continuation operations above; `tenant start` can advance setup. For filtered/provider-connect starts,
  use the saved application ID, or the original explicitly chosen request key
  with `tenant show --template ... --idempotency-key ...`. An unfiltered lookup
  may find a different setup. Never transfer setup URLs through chat. API setup
  uses its handoff ID and documented requests.
- JSON output leaves browser launch to the agent or human only when authorized through
  `--open-browser`. It opens a current link, without polling for consent or
  approving paid work, and conflicts with `--no-browser`. Planning cannot open
  a browser. Keep browser-link, AWS credential-use and paid-plan deadlines separate.
- For rotation, preview the exact connection first, then obtain approval for
  the credential change. Continue with the printed request key and handoff ID;
  `--handoff-id` requires the original `--idempotency-key`. Pending JSON exits
  with code 2 and supplies the human action, deadline and continuation.
- Offer AWS Bedrock setup only when `aws_bedrock` appears in the available-provider
  list. Follow `/guides/connect-aws-bedrock.md`: new setup defaults to `api_key`.
  The human generates a short-term Bedrock API key and enters the key and the
  optional Region where it was generated privately; blank Region means
  `us-east-1`.
  Millwork lists the customer's system profiles and matches the model selected
  in the approved plan. No STS or Cost
  Explorer credentials are needed for this method. Never request the key in
  chat, decode it into AWS credentials, or infer its type or actual AWS expiry.
  Millwork's maximum 12-hour use window begins after successful form submission;
  AWS can expire or reject the key sooner. Do not claim automatic refresh.
- Use `--auth-scheme aws_sts_sigv4` only when the human explicitly selects
  advanced AWS STS. That form requires a complete temporary session and its
  actual AWS expiration, region and exact profile ARN. Never invent an expiry.
  Preserve the selected auth scheme when planning/applying from scripts and
  when continuing a saved setup; do not silently switch methods or fall back
  from API-key setup to STS. Existing connections keep their method.
  Renew access on the existing connection with the same auth scheme and source
  Region. API-key setup lists the profiles again and requires the same selected model. STS renewal also keeps
  the exact inference-profile ARN. A profile metadata check is separate from an
  approved model run.
- Use `millwork provider list` for an authenticated read of available providers
  and existing connections; it makes no model call. `doctor` checks only local
  configuration. A passing doctor check is not account authentication.
- Read the model catalog available to an organization. Preserve the human’s
  provider and payer choice. For a direct run on their chosen saved model, send
  its `arm_id` as `routing.required_arm_id`; do not silently omit it. For CLI
  model changes, choose the model key and deployment ID from the same row,
  review any new paid test and keep the prior selection if setup fails.
- Submit an approved run with public or made-up test data, poll or cancel it, and
  inspect its receipt, which never contains the prompt or output. Leave prompt and
  result content to the human.
- Guide the human through the provider’s documented setup method: browser
  approval for OpenRouter, private key entry for a key-entry provider,
  or the explicitly selected AWS STS method.
  Perform a connection test only after the human approves it.
- Guide the human through API key or provider credential replacement without
  reading or handling the secret. Use the existing connection ID for provider
  rotation, then verify the replacement test before ordinary API-key removal.
  Short-term Bedrock keys have no individual delete control. An old key or STS
  session keeps its existing AWS expiration; do not prescribe session-wide
  revocation for routine renewal or change a connection's auth method.
  Do not claim preserved settings mean an expired or revoked credential works.
- Before disconnecting, show the affected saved models and obtain approval.
  Disconnect only the named connection. Report scheduled credential deletion
  separately from provider revocation; a dispatched model call may finish.
  If that connection was selected, ask for a new model choice without fallback.
- Read run receipts (they never contain the prompt or output) and prepare a redacted
  support report.

## Safety rules

- Never request or expose existing prompts, model output, or customer data. For a
  human-approved documented run, use only public or made-up test data. Keep any new
  result local by default and return its location, status, model/provider and
  safe counts. Share the answer in this conversation only if explicitly
  requested; never include its content in support material.
- Never request or expose passwords, tokens, API keys, cookies, or provider
  credentials in the conversation, shared logs, evidence or launch URLs. A
  secure setup link is the one exception, and only toward its own human: hand it
  to the human who started this setup, or open it in their normal system
  browser, and keep it out of shared logs, evidence, support material and launch
  URLs. The user enters credentials through approved private input.
  Saved CLI responses may stay on the owner-only local surface described above.
- Use placeholders in commands. The human supplies secrets through an approved secret
  input or secure setup surface.
- Use `GET /v1/model-catalog` for available models. For connecting the human's
  own provider account, use `GET /v1/model-source-profiles` and that provider's
  documented setup. OpenRouter uses browser approval. Do not infer
  that a provider example proves it is connectable, or that a catalog entry
  guarantees current provider capacity.
- Follow the installation and configuration on `/sdk/typescript.md`,
  `/sdk/python.md`, or `/mcp/execution.md`.
  Use the version shown there and keep credentials out of the conversation.
- For CLI setup, follow `/get-started/tenant-start.md`. Read the installed
  package version with `millwork --version --json`; its output links to the guide.
- Keep requested and provider-reported model identities distinct.
- Do not infer model identity or the paying provider account when
  `model_provenance` is null. A directly saved model's receipt can identify the
  saved model and recorded usage without confirming which model actually answered.
- A model-usage budget stops further calls once recorded spend reaches it. A call
  already running can exceed that budget, and the platform fee is separate.
- Make one paid attempt. Use the documented same-operation transport retry and
  non-spending continuation above within existing approval. Do not fall back
  or start another paid attempt unless the human approves it. Before paid work, tell the human
  the configured platform fee charged when Millwork accepts a live run, the
  model-usage allowance, and which account pays for each. Read the current
  fee from the plan or prompt; the default is documented on `/concepts/access`.
- `--json` formats output; it does not make a command read-only. Applying an
  approved plan with its exact `digest` and `issued_at` approves its listed
  effects, including any paid work. A stale plan needs a fresh review; inspect
  the existing application before repeating a request whose result is uncertain.
- Ask before sending documentation feedback or email. Obtain approval before a request that creates, changes, cancels, rotates,
  revokes or deletes state, including free test runs and connection tests; do
  not ask again when the user has already approved those effects in this setup.
  Read-only and local checks are allowed. Paid work always requires the
  stage-appropriate explicit spending approval.
- On failure, stop and report safe problem fields and a short redacted excerpt.
  Inspect the run's status, events and receipt before another inference attempt.
  A provider/routing failure is not automatically an SDK failure or a reason
  to repeat browser approval. Match recovery to authentication, permission,
  model availability, rate/capacity or explicit provider credit as reported.
- Distinguish Millwork fee credit from provider-billed usage. `totals.usd` from
  `/v1/usage` combines platform fees and recorded model usage, not just the amount
  charged by Millwork. Do not call all model usage externally billed on an
  organization that also uses Millwork-provided models, or invent a provider
  balance when none is available.
- Do not guess missing values or claim success without the documented expected result.
- Collect safe context from the current project and terminal instead of asking the
  human to fill in a checklist. Ask one short question only when a required fact is
  unavailable.

## Default response shape

State the next useful action and what it should return. Run approved steps,
compare the response and continue toward the human’s task. Ask only for a
required missing fact or approval not already given. On failure, keep the
saved setup/run and explain its recovery. A plan is not task completion.
