Use Natural Language with postsale run
Say what you want in plain language: how the agent loop works, how to authorize money-moving work, and how to read what it did.
postsale run is how you describe shipping work in plain language and let Postsale's CLI agent choose the right tools. It is the fastest path when a task takes several steps, and it is the primary interface for AI hosts.
In this article, we will cover what you need before the first run, explain how the agent loop works, capture results the right way, authorize money-moving work safely, and resume conversations when work spans multiple prompts.
Real-World Example
We need rates for an order, then a shipment, then a label. We would rather say "ship this order with the cheapest carrier" than assemble three JSON bodies by hand.
Before We Begin
To use postsale run, you will need:
- A signed-in CLI session or
POSTSALE_TOKEN(Sign In and Credentials) ANTHROPIC_API_KEY(orANTHROPIC_AUTH_TOKEN) and/orOPENAI_API_KEY- Optional overrides:
POSTSALE_LLM_PROVIDER,POSTSALE_LLM_MODEL. On Anthropic the default model isclaude-opus-5; the provider adapter drops the model's thinking blocks, so they never appear in the narrative, the stream, the summary, ortool_calls - A healthy
postsale doctorresult when possible
If both provider keys are set and you do not override, Anthropic is selected. Doctor's llm_provider check shows what is active.
What postsale run does
- Builds a system prompt and exposes the agent tool set (orders, shipments, labels, reports, configuration, and more; see agent tools for the current list).
- Sends your intent to the model.
- Runs any tool calls through the same safety gates as the rest of the CLI.
- Returns tool results to the model until it finishes, hits the turn limit, or stops on a gate or error.
- Writes a completion envelope to stdout (or a stream of events with
--stream).
Default turn limit: 20 (--max-turns).
Progress, breadcrumbs, and prompts go to stderr. Data stays on stdout. Details: Output and exit codes.
Try a read-only run
Here's how:
- Ask something safe:
postsale run "list my carriers and origin addresses"- Capture the envelope:
postsale run "list my carriers" > /tmp/run.json- Inspect the summary and tools used (example with
jq):
jq '.summary, .turns, .tool_calls[].name' /tmp/run.jsonSuccess looks like one JSON object on stdout with a clear summary, a tool_calls list, and stop_reason such as end_turn.
See example intents
postsale run --examplesThis prints a JSON array of sample intents and commands. It is not a completion envelope.
Rehearse before you spend money
postsale run --dry-run "Ship order <order_id> with the cheapest carrier"High-risk tools are simulated. Some other writes can still hit the API. Always read simulated_effects and confirmed_effects. Full detail: Dry-run.
Purchase for real
When you intend to charge:
postsale run "ship order ord_abc123 with the cheapest carrier" --yesFor tighter control in unattended runs:
postsale run --authorize create_shipment,purchase_labels \
"ship order ord_abc123 with the cheapest carrier"Warning
--yes authorizes parent money-moving and destructive tools. It does not authorize a parallel batch. See [Parallel batches](./parallel batch.md) and Safety.
At a terminal, the agent path prints the same environment badge the direct money-moving commands print, but only at the moment it matters: right before a money-moving confirmation prompt and before a batch authorization. A red [PRODUCTION] badge, with a [test-label mode] suffix when POSTSALE_TEST_LABEL_MODE is set. A read-only run prints no badge, and nothing prints when stderr is not a terminal, so agents and unattended-run logs read the envelope instead.
Stream events for hosts
postsale run --stream "how many orders shipped this month?" 2>/dev/nullEach stdout line is one JSON event (tool_call_start, tool_call_end, text, complete, and more). Ctrl-C emits aborted and exits 130.
Continue a conversation
postsale conversations --human
postsale run --continue "now list origin addresses"
postsale run --continue <conversation_id> "follow up..."
postsale continue <conversation_id> # interactive multi-turn--interactive keeps prompting on stdin after each turn until you exit.
Options that change outcomes
| Flag | When to use it |
|---|---|
--yes | Unattended parent money or destructive tools |
--authorize | Least-privilege allowlist of tool names |
--dry-run | Rehearse high-risk tools |
--max-turns | Cap cost and runaway loops |
--stream | Evented consumers |
--provider / --model | Pin the LLM |
--continue | Multi-step human sessions |
Verify any flag with postsale run --help.
Good to Know
Untrusted customer data
Some tool results wrap customer-origin content (order notes, addresses) as untrusted for the model. Treat that text as data, not instructions, especially if you paste model output elsewhere.
Envelope fields you will rely on
| Field | Meaning |
|---|---|
summary | Natural-language answer |
data | Last successful tool payload, or blocked object |
tool_calls | Ordered log of tools |
turns | Loop iterations used |
stop_reason | Why the loop stopped |
provider / model | What ran |
warning | For example max_turns_reached |
simulated_effects / confirmed_effects | Dry-run and write honesty |
Preflight with empty stdout
Missing LLM keys, bad configuration, or an unknown continue id fail before an envelope is written. Check exit code and stderr.
Finding work
Prefer get_work_queue over inventing order status names. See Search and the work queue.
Working with agents
Hosts should treat AGENTS.md as the machine source of truth. A compact loadable summary lives in agent/QUICKREF.md.
Additional Reading
- Safety model
- Dry-run
- [Parallel batches](./parallel batch.md)
- Intent builders
- Ship one order
- Doctor and schema
On this page
Related