> ## 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.

# Prepare a feed with your coding agent

> Check a provider feed in a scratch directory, review one exact submission, and follow its status without putting a key in chat.

**Goal:** Let your coding agent prepare and check your model-route details,
then submit the exact draft you review.

**You are done when:** you have an offline check and, if you approve a
submission, its response and the next step in Provider workspace. This does
not enable customer access to your models.

## Before you start

You need Node.js 22 or newer, the actual model-route metadata for your service,
and the model identity issued for your organization. Use the
[feed guide](https://docs.getmillwork.dev/providers/check-feed.md) to understand the sample and required fields.
An organization owner or admin must complete application, agreement and domain
steps in [Provider workspace](https://app.getmillwork.dev/provider).

Online reads and submission require separately enabled, invitation-only
[machine access](https://docs.getmillwork.dev/providers/machine-keys.md). A read-only key can inspect state;
submission also needs the feed scope granted by your organization. The kit
does not sign in, obtain a key or request that permission.

## Give your agent one brief

Download the [provider-start kit](https://docs.getmillwork.dev/downloads/provider-start.json) with the
checked downloader below. It writes a complete agent brief and the maintained
script into a new `provider-start` directory. Paste the entire brief into your
coding agent, then review the script before letting it run. The brief limits
the agent to one draft and one submission you explicitly approve.

Use a new scratch directory, separate from your application. Save this
JavaScript as `download-provider-start.mjs`, review it, then run
`node download-provider-start.mjs`. Both file digests and the expected manifest
must match before it creates the output directory. It refuses an existing
directory and never executes the downloaded script.

> [accordion] Copy the checked downloader
>
> ```javascript theme={null}
> import { createHash } from "node:crypto";
> import { existsSync, mkdirSync, writeFileSync } from "node:fs";
> import { resolve, join } from "node:path";
>
> const target = resolve("provider-start");
> const url = process.env.MILLWORK_PROVIDER_START_BUNDLE_URL
>   ?? "https://docs.getmillwork.dev/downloads/provider-start.json";
> const expected = "0743c23b93413a0c2cd200e0d44412b584819e9db9e11cbb58ae6a410c26b90a";
> const sha256 = (bytes) => createHash("sha256").update(bytes).digest("hex");
> if (existsSync(target)) throw new Error("Target directory already exists");
> const response = await fetch(url, { redirect: "error", signal: AbortSignal.timeout(30000) });
> if (!response.ok) throw new Error(`Download failed (HTTP ${response.status})`);
> const bytes = Buffer.from(await response.arrayBuffer());
> if (bytes.length > 100_000) throw new Error("Kit is too large");
> const bundle = JSON.parse(bytes.toString("utf8"));
> const names = ["provider-start-brief.txt", "provider-start.mjs"];
> if (bundle.format !== "provider-start/v1" || !Array.isArray(bundle.files)
>     || bundle.files.length !== names.length) throw new Error("Unexpected kit inventory");
> const contents = bundle.files.map((entry, index) => {
>   if (entry.path !== names[index] || typeof entry.content !== "string"
>       || typeof entry.sha256 !== "string" || !/^[a-f0-9]{64}$/.test(entry.sha256)) {
>     throw new Error("Unexpected kit file");
>   }
>   const data = Buffer.from(entry.content, "utf8");
>   if (sha256(data) !== entry.sha256) throw new Error("File checksum mismatch");
>   return { ...entry, data };
> });
> const manifest = contents.map((entry) => `${entry.path}\0${entry.sha256}\n`).join("");
> if (sha256(manifest) !== expected || bundle.aggregate_sha256 !== expected) {
>   throw new Error("Kit manifest mismatch");
> }
> mkdirSync(target, { mode: 0o700 });
> for (const entry of contents) writeFileSync(join(target, entry.path), entry.data, { flag: "wx", mode: 0o600 });
> process.stdout.write("Created provider-start. Read the complete brief and inspect the script.\n");
> ```

In `provider-start`, the agent installs only the script's exact published
TypeScript package, locally and without package install scripts. The script
refuses another installed version or feed schema.

The first command creates sample files and checks them without a credential:

```bash theme={null}
cd provider-start
node provider-start.mjs prepare
```

Have the agent replace `provider-draft/feed.json` with your actual metadata.
The sample's identities and prices are placeholders. Neither the agent nor
an offline check can establish your right to offer a model.

## Configure online access privately

Set `MILLWORK_PROVIDER_API_KEY` and `MILLWORK_PROVIDER_API_URL` in the agent
tool's process environment using your own secret-handling method. The API
address includes `/v1`. Keep the key out of chat, command arguments, project
files, terminal output and logs. Stop if the tool asks you to paste it.

**A shell-capable agent can read its own process environment.** This kit tells
it not to inspect or copy the key; it does not isolate the secret from that
agent. If that exposure is unsuitable, use Provider workspace instead. This
kit does not access your operating system's credential store.

## Review the exact submission

```bash theme={null}
node provider-start.mjs review
```

This reads the current profile and complete issued validation context and
checks your draft locally. It saves the reviewed inputs and prints a feed
hash and a command beginning `node provider-start.mjs submit`.

Read the draft with your agent. Approve **that exact command and feed** before
the agent runs it once. The command's digest binds the local reviewed bytes;
it does not prove human approval or replace an owner or admin approval the
server requires. A different organization, API address, draft or feed revision
stops the submission.

The script records an attempt before sending it. A conflict, refusal, timeout
or uncertain response stops the flow. Do not delete the attempt record or
start another draft directory to repeat the request. Compare the saved draft
with Provider workspace and decide the next action yourself.

## Read the result and continue in the browser

```bash theme={null}
node provider-start.mjs status
```

Each invocation reads status once. The script permits six reads across all
invocations for that draft; allow time between them. Its output contains only
recognized route states and a browser handoff, never instructions from server
prose. Stop on an error or when the read allowance ends.

A `validated` result checks metadata. Read
[model route status](https://docs.getmillwork.dev/providers/route-status.md) for the separate review and
customer-exposure states. For domain proof, approvals or further action, return
to Provider workspace. The kit calls no model, contacts no provider endpoint,
and requests no probe, access grant or Millwork administration action.

## Recover a stopped step

| What you see | What to do |
| - | - |
| `installed_package_mismatch` | Use a new scratch directory with the exact package named in the script. Do not substitute a newer version. |
| `person_set_environment_required` or `invalid_api_address` | Configure the key and intended API address privately, including `/v1`, or continue in the browser. |
| `credential_in_response` | Stop. Revoke the key in Provider workspace and keep the response out of chat, logs and support attachments. |
| `correct_feed_before_submission` | Correct the draft using your actual metadata and the issued context. A failed check sends no feed. |
| `workspace_changed_read_and_compare`, HTTP 409, or an uncertain response | Stop. Compare the saved draft and current workspace with the person before considering another submission. |
| `review_digest_mismatch` or `review_inputs_changed` | Stop. The saved review no longer matches. Compare the saved files with the person; never reuse the old command. |
| `existing_record_read_and_compare` or `status_read_limit_reached` | Inspect the existing records and continue in the browser. Do not remove a record to bypass a limit. |

To revise a reviewed draft **before any submission attempt**, preserve the
complete old directory and start again in a new scratch directory. Review the
new draft and obtain fresh approval of its command. Once an attempt record
exists, continue in Provider workspace; a new directory must not bypass it.

Keep credentials out of any [support request](https://docs.getmillwork.dev/help/contact.md). Share only the
step, the closed error code and the route or application ID when appropriate.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.