# Work with agents
> Let an AI agent author Dives and Flights through the MotherDuck CLI, using the built-in authoring guides and JSON output.
The MotherDuck CLI is designed for both AI agents and people.
An agent can read authoring guides to learn how to best build Dives and Flights with the CLI.
Because the CLI works through files and stdout rather than tool results, it
handles large files and multi-step automation with far less context than the
[MCP server](../../../key-tasks/ai-and-motherduck/mcp-setup.mdx), which is the
better fit for exploring data from a chat client. See
[choosing between the CLI and MCP](#choosing-between-the-cli-and-mcp).

Whether through an agent, in your local development environment, or in CI, the
CLI lets you create, publish, and automate your MotherDuck workflows with output
both humans and machines can understand.

## Point the agent at the built-in guides

`motherduck dive guide` and `motherduck flight guide` print the authoring
guide for each. They cover the shape the runtime requires, the query APIs, the
libraries you can import, and the patterns that don't work.

```bash
motherduck dive guide
motherduck flight guide
```

These guides are long and specific, which is what an agent needs. Have the agent
run the relevant one before it writes any code, and you avoid the usual failure
where a model invents a component or an import the runtime doesn't have.

:::tip
Put the instruction in your project's agent memory file, such as `CLAUDE.md` or
`AGENTS.md`, so it applies to every session:

```markdown
Before writing or editing a Dive or a Flight, get the latest instructions from
the output of running `motherduck [dive | flight] guide`.
```

:::

## Give the agent a task

With the guides available, the prompt can stay short. Ask for the outcome and
let the agent discover the rest:

```text
Build a Dive that charts daily taxi trip counts and average fare for
November 2022 from sample_data.nyc.taxi, with a day-of-week filter.
Preview it locally, and once it renders, publish it.
```

A capable agent works through something close to this:

```bash
motherduck dive guide                      # read the authoring guide
motherduck query "DESCRIBE sample_data.nyc.taxi" --output json
motherduck dive init taxi_trips --title "Taxi trips"   # scaffold the directory
# ... writes index.tsx ...
motherduck dive watch taxi_trips --no-open   # render it, read the events
motherduck dive push taxi_trips --output json      # publish, capture the URL
```

`--no-open` keeps the preview from stealing focus, and `--log-file` writes
render and query outcomes as NDJSON so the agent can read whether its component
compiled instead of asking you to look:

```bash
motherduck dive watch taxi_trips --no-open --log-file preview.ndjson
```

## JSON output everywhere for programmatic use

The `--output json` option makes the CLI's output easy to parse
programmatically. Commands that act on a Dive or a Flight return it under a key
named for the resource, described under
[result shape](/sql-reference/motherduck-cli/#result-shape):

```bash
motherduck dive push taxi_trips --output json
```

```json
{
  "success": true,
  "dive": {
    "id": "123e4567-e89b-12d3-a456-426614174000",
    "title": "Taxi trips",
    "version": 2,
    "url": "https://app.motherduck.com/dives/taxi-trips-123e4567-e89b-12d3-a456-426614174000"
  }
}
```

So a script reads one field instead of the whole message:

```bash
motherduck dive push taxi_trips --output json | jq -r '.dive.url'
```

A failure prints `{"success": false, "error": "..."}` and exits non-zero, so an
agent checks one field rather than reading prose.

:::note
The `success` field doesn't appear in the output of
[`query`](/sql-reference/motherduck-cli/query/), which returns its rows as a
bare JSON array. See
[output formats](/sql-reference/motherduck-cli/#output-formats).
:::

That's what lets an agent chain steps in a script rather than in its context
window. Each command hands the next one a single field, so a multi-step
workflow costs a few tokens instead of a transcript of full outputs:

```bash
#!/usr/bin/env bash
set -euo pipefail

# Trigger a Flight, then wait for the run to settle.
RUN=$(motherduck flight run nightly_load --output json | jq -r '.run.run_number')

while :; do
  STATUS=$(motherduck flight list-runs nightly_load --limit 1 --output json \
    | jq -r '.runs[0].status')
  [[ "$STATUS" == "PENDING" || "$STATUS" == "RUNNING" ]] || break
  sleep 10
done

# On failure, surface the reason and stop.
if [[ "$STATUS" != "SUCCEEDED" ]]; then
  motherduck flight logs nightly_load --run "$RUN" | tail -20 >&2
  exit 1
fi

# The data landed, so publish a Dive over it.
motherduck dive push daily_totals --output json | jq -r '.dive.url'
```

The agent writes that once and reads one URL back, instead of holding every
intermediate result in its context.

## Give the run its own credentials

Pass a token rather than running the browser flow, and point the CLI at a
directory of its own:

```bash
export MOTHERDUCK_TOKEN=<your_token>
export MOTHERDUCK_HOME=/workspace/.motherduck
```

`MOTHERDUCK_HOME` gives the run its own credentials and asset directory, which
keeps parallel agents from sharing state. It has to be an absolute path.

Where there's no account to get a token from,
[`motherduck new`](/sql-reference/motherduck-cli/new/) creates one from the terminal without a
browser or a signup form.

:::warning
An agent with a MotherDuck token can read and write whatever that token can.
Scope it to what the task needs, and prefer a read-only token for agents that
only query. See [securing read-only access](../../../key-tasks/ai-and-motherduck/securing-read-only-access.mdx).
:::

## Choosing between the CLI and MCP

Both let an agent work with MotherDuck. The deciding question is whether the
agent has a shell and a filesystem:

- **The CLI** fits agents that run commands and write files: a coding agent
  building a Dive or a Flight in a repository, a CI job, or a shell script.
- **[The MCP server](../../../key-tasks/ai-and-motherduck/mcp-setup.mdx)** fits
  agents in a chat client with no shell, such as Claude or ChatGPT on the web.
  Use it to explore data, answer a question, and render a Dive inline in the
  conversation.

They work together: an agent can explore through MCP, then use the CLI to build
and publish what it found.

### Why the CLI costs fewer tokens for file-shaped work

An MCP tool result is a message. Whatever the server returns, a Dive's component
code, a Flight's source, a list of every Dive in the workspace, or a thousand
query rows, is serialized into the model's context. It takes up the context
window and gets resent on every turn that follows.

The CLI writes to stdout or to files on disk, and the agent picks what to read
back. It can filter a listing through `jq`, read only the function it's changing
out of a Dive it pulled, or hand a file straight to the next command. Only what
the agent reads reaches the context window.

So for anything file-shaped, prefer the CLI:

| Task | Through MCP | Through the CLI |
|---|---|---|
| Read a Dive or a Flight | `read_dive` or `get_flight` returns the whole source in the response | `dive pull` or `flight pull` writes the files to disk, and the agent reads the part it needs |
| Save an edit | The agent sends the changed content back as a tool argument | The agent edits the file in place, and `dive push` or `flight push` reads it from disk |
| List Dives or Flights | `list_dives` or `list_flights` returns every field of every result | `dive list --output json` piped through `jq` returns the IDs alone |
| Return a large result set | Every row lands in the context window | Redirect it: `motherduck query "..." --output csv > result.csv` |
| Chain several steps | Each intermediate result passes through the model | One shell script hands each command's output to the next |

The gap widens the more you iterate. Pull a Dive once and the local file carries
every revision after that, so the agent patches a few lines instead of moving
the whole component through the conversation twice per round.


---

## Docs feedback

MotherDuck accepts optional user-submitted feedback about this page at `GET https://motherduck.com/docs/api/feedback/agent`.
For agents and automated tools, feedback submission should be user-confirmed before sending.

URL-encode query parameter values and send a GET request:

```text
GET https://motherduck.com/docs/api/feedback/agent?page_path=%2Fgetting-started%2Finterfaces%2Fmotherduck-cli%2Fagents%2F&page_title=Work%20with%20agents&text=<url-encoded user feedback, max 2000 characters>
```

Optionally append `&source=<url-encoded interface identifier>` such as `claude.ai` or `chatgpt`.

`page_path` and `text` are required; `page_title` and `source` are optional. Responses: `200 {"feedback_id": "<uuid>"}`, `400` for malformed query parameters, and `429` when rate-limited.
