> ## Documentation Index
> Fetch the complete documentation index at: https://docs.getmillwork.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Check your preview access with Echo

> Check your access without paying for a model run, then keep the Echo receipt.

**Goal:** Check your organization's access with **Echo**, a test run. Echo
does not call an external provider or spend provider credit. This starter check
has no platform fee. Live model runs have separate
[fees and model costs](/concepts/access).

**You are done with this diagnostic when:** the application state is `echo_proved`,
`next_action.type` is `done`, and you can retrieve the receipt for
`echo_execution_id`. A receipt is a record of the run without its prompt or
output.

This is not completed tenant setup and must not be reported as `ready`.
Full setup still needs a bounded live model result, provenance receipt,
remaining-credit view, and a supported public CLI version. Echo does not
prove that a model can answer a paid request.

## Before you begin

* Your organization is approved for the private preview.
* An organization owner invited you and granted `runs:view`, `runs:write`, and
  `arms:manage`.
* You have an organization API key in an approved secret store.
* You have Node.js 20 or 22.
* If you use the CLI, Millwork has explicitly provided a qualified preview artifact
  and its exact version.

There is no supported public CLI version yet. Do not install a package or copy a
version from a registry listing. If your invitation does not name an exact version,
stop and contact [support](mailto:support@getmillwork.dev).

<Steps>
  <Step title="Check the local CLI">
    Run these local checks only from a qualified preview artifact that Millwork
    explicitly provided. They do not make an API request, open a browser, or read the
    value of your API key.

    ```bash theme={null}
    millwork --version --json
    millwork docs --json
    millwork doctor --json
    ```

    `millwork --version --json` returns the local package version and the public support
    state. `supported_public_version` stays `null` until a published CLI passes the
    release gate.

    ```json theme={null}
    {
      "schema_version": 1,
      "package_version": "<version from your qualified preview artifact>",
      "supported_public_version": null,
      "public_cli_available": false
    }
    ```

    `millwork docs --json` returns this page with a privacy-safe referral tag.
    `millwork doctor --json` reports only whether a key is configured. It never prints
    the key.
  </Step>

  <Step title="Review a starter plan">
    Set `SOLVERAPI_API_KEY` through your approved secret store. Do not paste the value
    into a command, chat, ticket, or log. The default API base is
    `https://api.getmillwork.dev/v1`.

    Choose `starter` explicitly for this Echo-only check. The CLI's default
    template is a different flow that can ask you to approve paid model work.
    In an interactive terminal, run:

    ```bash theme={null}
    millwork tenant start --template starter
    ```

    For an agent or other non-interactive session, planning and applying must be two
    separate commands:

    ```bash theme={null}
    millwork tenant start --plan --json --template starter > millwork-plan.json
    ```

    Planning does not create a setup application, a provider resource, or paid
    work. A setup application records the steps you approve so you can return to
    the same progress. The `>` in the command saves the plan to a local
    `millwork-plan.json` file; Millwork does not create that file itself.

    Check that `template_id` is `starter`, `maximum_spend_usd` is `0`, and the
    only effects are creating or reusing a saved model option (an **arm**) and
    submitting Echo. The plan's `digest` identifies the exact plan you approve;
    `expires_at` is its expiry time. The plan includes these fields:

    ```json theme={null}
    {
      "template_id": "starter",
      "template_version": "1",
      "request_preset_id": "starter-public-sandbox-v1",
      "issued_at": "<ISO-8601 time>",
      "expires_at": "<ISO-8601 time>",
      "digest": "<exact plan digest>",
      "qualification": {
        "state": "approved",
        "next_action": { "type": "approve_plan", "detail": "<plain next step>" }
      },
      "catalog_row": null,
      "blockers": [],
      "effects": [
        {
          "id": "register_or_reuse_starter_arm",
          "description": "Create or reuse one template-managed model arm. No provider resource is created."
        },
        {
          "id": "submit_echo",
          "description": "Submit one Echo execution with routing.required_arm_id and no verifier."
        }
      ],
      "starter_credit": {
        "balance_usd": 0,
        "funded_state": "sandbox"
      },
      "maximum_spend_usd": 0,
      "file_manifest": [
        { "path": ".millwork/starter.json", "kind": "secretless_config" },
        { "path": ".env.example", "kind": "env_placeholders" },
        { "path": "examples/starter-echo.ts", "kind": "node_ts_example" }
      ]
    }
    ```

    The starter does not add a verifier, a check applied to a run. It does not
    connect a provider account or approve live model work.
  </Step>

  <Step title="Apply the exact plan">
    In an interactive session, approve only the starter plan you reviewed. For
    the separate-command flow, use the command below.

    Use the `digest` and `issued_at` from the same unexpired plan. The API requires one
    `Idempotency-Key`, which identifies the application across retries. The current
    preview CLI does not expose a
    supported public resume-key input. If an apply loses its response before it returns
    an `application_id`, stop and contact support instead of starting another apply.

    ```bash theme={null}
    millwork tenant start \
      --digest "<exact plan digest>" \
      --issued-at "<exact issued_at>" \
      --template starter
    ```

    Without `--write`, the application creates or reuses the template-managed arm and
    submits one Echo run. It does not write starter files. Add `--write` only after you
    approve the plan's `file_manifest`. Existing files are never overwritten.
  </Step>

  <Step title="Keep the application ID and check the receipt">
    Keep the `application_id` so you can inspect the same setup attempt. In the
    application response, look for `echo_proved`, `done`, and the Echo run ID:

    ```json theme={null}
    {
      "application_id": "<application ID>",
      "template_id": "starter",
      "template_version": "1",
      "state": "echo_proved",
      "completed_effects": [
        { "id": "register_or_reuse_starter_arm", "at": "<ISO-8601 time>" },
        { "id": "submit_echo", "at": "<ISO-8601 time>" }
      ],
      "result": null,
      "receipt": { "receipt_id": "<receipt ID>" },
      "managed_arm_id": "<arm ID>",
      "echo_execution_id": "<execution ID>",
      "next_action": {
        "type": "done",
        "detail": "Echo receipt is retrievable at GET /v1/receipts/:id."
      },
      "diagnostics": {
        "provider_resource_created": false,
        "files_written": false,
        "plan_digest": "<exact plan digest>"
      },
      "created_at": "<ISO-8601 time>"
    }
    ```

    After the CLI returns an application ID, inspect the same application with
    `GET /v1/tenant-template-applications/{applicationId}`. Resume the recorded
    `application_id`; do not start a second application to recover state.

    Fetch the receipt with `GET /v1/receipts/{echo_execution_id}`. Echo returns
    no model output: `result` stays `null`.
  </Step>
</Steps>

## Resolve an access result

Stop on any state other than `approved`. Follow its typed next action. Do not guess a
tenant, invitation, role, or access decision.

| State                          | Next action type                                 | What to do                                                                                                              |
| ------------------------------ | ------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------- |
| `no_credential`                | `apply_for_preview`                              | Sign in through the browser preview application. The application creates no tenant, key, credit, configuration, or run. |
| `preview_pending_or_rejected`  | `wait_for_preview_decision` or `contact_support` | Wait when pending. Contact support when rejected.                                                                       |
| `tenant_not_admitted`          | `contact_tenant_admin`                           | Ask the tenant administrator to confirm private-preview admission.                                                      |
| `organization_invite_required` | `ask_org_admin_to_invite`                        | Ask an organization administrator to invite you. The response does not confirm that an organization exists.             |
| `role_lacks_permission`        | `ask_owner_for_role`                             | Ask an owner for `runs:write` and `arms:manage`. This is not a preview-admission denial.                                |

API failures use `application/problem+json`. The shape is:

```json theme={null}
{
  "type": "<absolute problem URI ending in the error code>",
  "title": "<safe summary>",
  "status": 400,
  "detail": "<safe recovery detail when present>",
  "instance": "<request instance>"
}
```

Match the final path segment of `type`. Do not parse `title` or `detail` as a stable
error code.

## Recover safely

* **The digest expired or changed:** request a new plan and approve its new digest.
* **The idempotency key conflicts:** use the original plan digest with that key. Do
  not reuse the key for another plan.
* **The apply response was lost:** do not guess a key or start over. Use the returned
  `application_id` when available. Otherwise stop and contact support.
* **The session is non-interactive:** run `--plan --json`, review the result, then use
  a separate command with `--digest` and `--issued-at`.
* **A local file already exists:** inspect it. The CLI skips it instead of
  overwriting it.
* **An API call fails:** stop. Record the HTTP status, problem `type`, `title`,
  `instance`, and a short redacted excerpt. Do not include request bodies, headers,
  keys, prompts, or results.

<CardGroup cols={2}>
  <Card title="Check the Echo receipt" icon="check" href="/concepts/results-and-receipts">
    Understand what the receipt proves and what Echo does not test.
  </Card>

  <Card title="Get help" icon="life-buoy" href="/help/contact">
    Prepare a redacted support report without sharing a secret.
  </Card>
</CardGroup>
