axon <agent>

Run one instruction against one agent. The agent boots, the instruction runs to completion, the agent exits.

axon <ref> -p "<instruction>"   # ask the agent
axon <ref> -P <prompt>          # run a prompt it declares
axon <ref> -s <script>          # run one of its scripts
axon <ref> -a                   # open the terminal on it

There is no run verb — the reference is the command. See axon for how the binary tells a reference from a verb.

Ask an agent something

The common case: a quoted string goes straight to the model.

axon . -p "what changed in the last commit?"
axon . -p "summarise the readme"
axon @cody/zeno -p "is the auth boundary sound?"

The answer streams to stdout, so it pipes:

axon . -p "list every TODO with its file" > todos.txt
axon . -p "what does this error mean?" | pbcopy

Nothing needs to be declared in advance — no prompt file, no config. Quoting is what makes it a literal; see -p for the one rule.

The reference

axon . -p "audit the auth boundary"        # the agent in this directory
axon ./agents/scout -p "what changed?"     # a path
axon ~/work/zeno -p "what changed?"        # home-relative
axon @cody/zeno -p "what changed?"         # a package — installed, or fetched on a miss

. names the current directory. It is required rather than implied: a bare axon with no reference opens the TUI.

Resolution never boots. A missing path fails immediately; a missing package is fetched, prepared and cached.

-p and -P

Two flags, distinguished by case. Nothing is inferred from the value.

FlagInputBehaviour
-p-p "summarise the readme"Used verbatim as the instruction
-P-P code-reviewLooked up in the agent's declared prompts

The case split is deliberate. A single flag would have to guess whether explain is a prompt name or a one-word question — and either answer is wrong somewhere: guessing "name" makes one-word instructions unreachable, guessing "instruction" means the command silently changes meaning the day someone adds src/prompts/explain.vue. Case costs one keystroke and removes the ambiguity.

Repeated -p composes into a single instruction:

axon . -p "review the diff" -p "focus on error handling"

A -P prompt written as .vue is rendered — <script setup> runs and declared props are filled from the remaining flags. Installed prompts are namespaced by package (-P @cody/eslint-scout:scout) and cannot shadow one you wrote.

-s — a script

Invokes one of the agent's own scripts, from src/scripts/. Every other flag arrives as its args, -p included.

axon . -s triage
axon . -s triage -p "the login bug"
axon . -s close-plan --issueId bd-yiq
// src/scripts/triage.ts
const { prompt } = defineArgs<{ prompt: string }>()
await axon.request(prompt)

A script is not an instruction — it is the execution. The agent's code decides what to do, including whether to invoke the loop at all, so -p alongside -s is a value the script receives rather than a turn the CLI runs. Nothing is streamed for you; a script writes its own output.

-a — open the terminal

-a says the conversation continues in the TERMINAL, so nothing runs here: the instruction is handed over and delivered into the session the terminal opens.

axon @cody/zeno -p "summarise the readme" -a   # opens the TUI with the message queued

Each -p becomes its own queued message, in the order given — they land in the pending list above the input and are sent as the agent frees up, exactly as if you had typed them one after another:

axon @cody/zeno -p "read the readme" -p "then summarise it" -a

That is the one place repeated -p does not compose into a single instruction. Without -a there is one turn to run, so the parts join; with it there is a conversation to have, so they stay separate.

-s is excluded — a script IS the execution, and there is no message for a session to carry, so -a cannot mean "hand it over" there.

A reference with no instruction is already a destination, so -a is optional there — there is nothing to run, and opening the terminal is the only thing it can mean:

axon @cody/zeno                 # opens the TUI on it
axon @cody/zeno -a              # the same
axon "http://localhost:3101"    # attaches to something already running

Either way this outranks the remembered last agent: naming one is an explicit instruction, and the terminal opens on what you asked for rather than what you were last on.

The turn runs before the terminal opens, so the transcript is already there when it does — one conversation, continued, rather than an answer in the shell and a fresh session in the UI.

A URL is verified before anything is recorded: a typo should not cost a whole terminal boot to discover. A path or package is not, because there is nothing running to answer — the terminal reports a bad reference the same way ~ does.

There is no axon attach. It was a verb for something that is not an action: it did no work on the agent, it chose a destination.

Arguments

Any flag not listed under Options becomes a prompt argument.

axon . -P learn --domain tracing --depth 3
<script setup lang="ts">
defineProps<{ domain: string; depth?: string }>()
</script>

Ignored by -p, which is used verbatim and has nothing to render.

Options

FlagDefaultDescription
-p, --promptA literal instruction, used verbatim. Repeats compose
-PA prompt the agent declares, resolved and rendered
-s, --scriptOne of the agent's own scripts
-a, --attachfalseOpen the terminal when the work finishes. Implied when there is no instruction
--contextExtra context for the turn
--jobTag the run with the job directory it belongs to
--jsonfalsePrint one line of JSON to stdout and nothing else

--job is correlation only — it records the association in the run's liveness record and changes nothing about what executes.

Output

Agent text streams to stdout. Boot progress, diagnostics and errors go to stderr.

That split is the whole automation story: a redirect or a pipe gets only the answer, while a person watching a terminal still sees the boot happen. There is no flag to remember.

axon @cody/zeno -p "…" > answer.txt     # the file holds only the answer
axon @cody/zeno -s report | jq          # nothing but the script's own output

Progress draws only when someone is watching — never under --json, --quiet, or when stderr is not a terminal — and only once a boot has run long enough to be worth explaining. A warm agent boots in under a second and says nothing.

-s prints nothing on the script's behalf: a script that wants to say something writes to stdout itself.

Tool calls, kernel telemetry and the full causal record go to the session log under .agent/data/sessions/.

axon.ui.ask() receives unavailable — there is no connected host to answer.

Errors

ErrorMeaning
SCRIPT_NOT_FOUNDThe agent declares no script by that name; the available ones are listed
PROMPT_NOT_FOUNDNo prompt by that name; the available ones are listed
NOT_AN_AGENTThe reference resolved to a module, bench or cognet
ATTACH_UNREACHABLE-a on a URL that nothing answered
ATTACH_URL_INVALIDThe address has no scheme, or one that is not http(s)

See prompts/ for authoring what -P resolves, and Scripts for what -s invokes.