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.