Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

One-shot mode

One-shot mode runs a single prompt and exits, similar to bash -c. It takes --oneshot and the prompt through -p:

meka --oneshot -p "your prompt here"
git diff | meka --oneshot -p -      # `-p -` reads the prompt from stdin

The agent works through the prompt, tool calls included, and when the turn ends prints its answer: the last text block the model wrote, as markdown source, terminal or pipe alike, since the output is for the next tool rather than for reading. Nothing else is printed. The thinking, the tool calls and the rest of the process are logged, so -v shows them. A run interrupted with Ctrl+C exits 130, whatever it had printed by then.

A prompt without --oneshot is not a one-shot run: it seeds the first turn and then leaves you on the screen, which is the right default when you are working interactively and the first thing you want is already in your shell history.

--oneshot requires something to do, so it needs -p or --skill.

An empty or whitespace-only prompt is refused rather than sent.

Approvals have nothing to ask from here: there is no prompt to answer, so with the switch on every tool that needs approval is refused. meka says so once at startup and names each tool as it is refused, but the run is still less useful than it looks. Give a non-interactive run the level it needs with --permission, or use meka serve if you need a human in the loop over an API.

Examples

# Simple question
meka --oneshot -p "what is my current working directory?"

# File operations (requires workspace permission)
meka --oneshot --permission workspace -p "create a file called notes.txt with today's date"

# Search
meka --oneshot -p "find all TODO comments in this project"

# Web page
meka --oneshot -p "summarize https://blog.rust-lang.org"

Combining with other flags

All configuration flags work in one-shot mode:

# Use a specific profile
meka --oneshot --profile work -p "explain this codebase"

# With workspace permission
meka --oneshot --permission workspace -p "run 'cargo test' and summarize the results"

# Ask the provider for a whole reply rather than a stream
meka --oneshot --no-stream -p "read README.md and summarize it"

# Run one turn against an existing session
meka --oneshot -r 550e8400 -p "summarize what we decided"

JSON output

--format json keeps stdout empty during the turn and prints one object when it ends, so a script reads the whole turn at once rather than parsing a stream. Errors still go to stderr and the exit code; no object is printed for a turn that failed. A turn interrupted with Ctrl+C is reported, not failed: its object is printed with stop_reason set to interrupted, and the run exits 130 as it does without --format json.

meka --oneshot -p "how many files are here?" --format json
{
  "session_id": "550e8400-e29b-41d4-a716-446655440000",
  "profile": "work",
  "stop_reason": "end_turn",
  "text": "There are 14 files in this directory.",
  "tool_calls": [
    { "name": "file_find", "input": { "glob": "*" }, "is_error": false }
  ],
  "usage": {
    "input_tokens": 1180, "output_tokens": 42,
    "cache_creation_input_tokens": 0, "cache_read_input_tokens": 1024
  },
  "notices": [
    { "level": "warn", "text": "Approvals are on but nobody can answer here, so 'shell_execute' was refused without asking." }
  ],
  "compactions": []
}

stop_reason is end_turn, max_tokens, refusal (with refusal_text beside it when the model gave one) or interrupted. session_id is omitted, not null, for a turn interrupted before the session existed, which is the one way a run prints a report without one; every other field is always present. text is the assistant’s text with the rounds joined by a blank line, tool_calls lists every call in the order it was dispatched, and usage sums the rounds and the compactions the turn ran. notices is what meka itself said during the turn (a refused approval, a lost write, a declined MCP elicitation), each with a level of info or warn and its text; it is empty when meka raised none. compactions lists the compactions the turn ran, each in the shape of the HTTP API’s context.compacted event. The flag applies to --oneshot alone; a run without it is refused. meka account usage, whoami and stats take the same flag and values, and meka session export --format takes markdown or json.

Session behavior

One-shot mode creates a new session for each invocation, unless you point it at an existing one with -c (most recent) or -r <SESSION> (specific). Those run a single turn against that conversation and exit, which is the usual shape for scripting against a session built up earlier.

No session id is printed. --format json carries it as session_id, -v logs it, and -c resumes the most recent session without naming it:

meka -c

Piping

The answer goes to stdout and everything else to stderr, so meka -p … 2>/dev/null | next-tool hands the next tool only what you asked for. That holds for every command, not just this one.

A reader that stops reading is its own decision, and meka exits 0 for it:

meka -p "summarize this log" | head -20     # exits 0; head got its lines

A stdout that cannot take the answer is a different thing, and fails the run:

meka -p "summarize this log" > /full/disk   # exits non-zero, and says why on stderr

The distinction matters in a script: the first is how pipelines end, the second is data you asked for and did not get.