NAME
raider - Autonomous CLI agent with filesystem and bash access
VERSION
version 0.503
SYNOPSIS
raider "Find all TODO comments in lib/ and summarize them"
raider -e openai -m gpt-4o "Run the test suite and fix any trivial failures"
raider -i -r ~/dev/myproject
raider --perl --pack testing-fu "Run prove -l t and explain failures"
raider --json "Summarize README.md" > result.json
raider --stream-json "Run the tests" | jq -c 'select(.type == "tool.call")'
raider config explain -m gpt-4o
raider config migrate --dry-run
raider session list
raider --continue "Now fix the first one"
raider provider inspect provider.example --json
raider --provider provider.example -m example-model -k "$KEY" "Summarize README.md"
raider hall start --acp-port 38421
raider acp prompt 127.0.0.1:38421 --raider bjorn "Summarize status"
DESCRIPTION
raider is the command line of Langertha::Raider::CLI: it runs Langertha::Raider::CLI::Main, which parses the options below and builds a Langertha::Raider::CLI for the working directory. That wires an LLM engine (via Langertha) to the file tools, bash (MCP::Run::Bash) and the web tools, then runs the Langertha::Raider multi-turn agent loop on your prompt. Optional profile, pack, and Perl-native tool flags let the same CLI load project agent instructions, persona/power bundles, and perl_eval / perl_check / perl_cpanm tools.
Settings of a project live in its config file: .raider/config.yml in the working directory, or else the legacy .raider.yml there. Both take the same keys; where this page names .raider.yml, the file in use is meant. When both exist, only .raider/config.yml is read: raider warns on standard error that it ignores .raider.yml, and config explain names the file in use and the ignored one. What raider saves (/model, --claude, --openai, --skills) goes to the file in use, and to .raider.yml when there is none.
Under the project file lies the home file ~/.raider/config.yml, with the same keys: built-in defaults, then the home file, then the project file, then the command line. The project replaces a home value, except that skills and no_detect add up and detect: rules are replaced per pack. raider never writes the home file. Run in the home directory itself, ~/.raider/config.yml is the project file and is read once. A home file that does not parse stops raider like a broken project file.
project_tools in ~/.raider/config.yml maps a workspace selector (*, a path glob starting with / or ~/, or a workspace name) to the home tools a project gets. Only the home file grants: in a project file it is ignored, and config explain says so. For now config explain only shows which selectors match the project and which tools they grant; nothing is mounted from it yet, and workspace names never match. An invalid project_tools stops raider with exit status 3.
The project instructions follow the same rule: .raider/instructions.md in the working directory, or else the legacy .raider.md there, is added to the default persona. Where this page names .raider.md, the file in use is meant. When both exist, only .raider/instructions.md is read, raider warns that it ignores .raider.md, and config explain names the ignored file under instructions:. The prompt-builder (/prompt) writes the file in use, and .raider.md when there is none.
raider config migrate [--dry-run] [-r DIR] moves the legacy files of a project to the new layout: .raider.yml to .raider/config.yml and .raider.md to .raider/instructions.md, each only when it exists. It first shows what it does -- per file the new file, the backup and whether the content changes -- and with --dry-run stops there. Each new file is written atomically with the legacy file's permissions, then the legacy file is renamed to .raider.yml.bak or .raider.md.bak, so afterwards the same settings are read from the new files; .raider/ is created with its .gitignore. A step that fails leaves its legacy file in use. An api_key (top level, default: or an engine section) is not copied into .raider/config.yml, which is meant to be shared: it is reported with where it was, never printed, and belongs in ~/.raider/config.yml or the engine's *_API_KEY variable; its lines are dropped (comments stay), and where that would change the meaning of the file the file is rewritten from its parsed content, which drops comments and says so. Nothing is merged: when a new file or a backup already exists, when .raider is no directory, or in the home directory itself (where .raider/config.yml is the home file), nothing is written and the exit status is 1. Only config migrate in front of the options is the subcommand. Its report is for humans only; there is no --json form.
Interactive mode (-i) opens a REPL with conversation history retained across turns. With Term::ReadLine::Gnu installed, line editing and persistent input history (~/.raider_history) are enabled automatically — including across Ctrl-C interrupts. Slash commands available in the REPL: /help, /clear, /metrics, /stats, /reload, /prompt, /skill, /skill-claude, /config, /model, /packs, /pack, /quit.
Two more line prefixes run shell commands, with $SHELL -c (/bin/sh without SHELL) in the root (--root); Ctrl-C while one runs ends the command, not raider. !CMD runs CMD on the terminal (less and vim work), prints a non-zero exit status, and sends nothing to the model and records nothing in the session. ?CMD runs CMD with its output shown as it comes and captured (standard input is /dev/null), then sends the command, its exit status and its output -- standard output and standard error, cut to its first and last 10000 characters when longer than 20000 -- to the model as the next prompt, recorded in the session like any other. A ?CMD ended by Ctrl-C sends nothing. A line that is only ! or ? is a prompt.
Subcommands are dispatched before normal raider startup: raider hall ... manages a Raider Hall daemon, and raider acp ... runs the bundled ACP client. raider config explain [options] takes the normal options and prints every effective setting with its source -- a command-line flag, a layer of the config file, an environment variable or the built-in default -- without writing the config file or contacting a model; /config prints the same inside the REPL. The options may also come first (raider -e openai config explain); there only the exact words config explain are the subcommand, any other prompt starting with config is sent as a prompt. raider provider inspect HOST fetches, validates and shows a provider's manifest, and raider --provider HOST runs on the endpoint it declares; see "PROVIDERS".
With --json, --msgpack or --yaml, raider prints one document describing the run instead of the human-oriented output, which is useful for scripting; --stream-json, --stream-msgpack and --stream-yaml follow the run as it happens. See "MACHINE OUTPUT".
When standard input is not a terminal, the REPL (-i) reads its lines from it and ends at its end.
TOOLS
The model gets one tool set per run, and the tool list in its prompt is generated from exactly the tools the engine is offered:
list_files,read_file,write_file,edit_file(Langertha::Raider::FileTools), confined to-r.bash(MCP::Run::Bash), a real shell started in-r, 120 seconds per command by default. It is not confined to-r.web_search,web_fetch(Langertha::Raider::WebTools).perl_eval,perl_check,perl_cpanm(Langertha::Raider::PerlTools) when granted: by--perl, byperl:in .raider.yml (perl: falsedenies them), or else when an active pack requests them -- the bundledperlpack, detected in a Perl workspace. Switching such a pack with/packor re-detecting it with/reloadmounts or unmounts them for the next raid.telegram_reply,hall_status,hall_spawn(Langertha::Raider::HallTools) only for a raider a Hall started (see "RAIDER_HALL_SOCKET").
raider config explain shows whether the Perl tools are mounted and why; --export-skill writes the same tool list as a table.
OPTIONS
-e, --engine NAME
The engine: anthropic, openai, deepseek, groq, mistral, gemini, minimax, cerebras, openrouter or ollama. Without it, -o engine=, then engine: in .raider.yml, then the first API key set in the environment (anthropic, openai, deepseek, groq, mistral, gemini, in that order; see "ENVIRONMENT") decide, else anthropic.
-m, --model NAME
The model. Without it, -o model=, then model: in .raider.yml, then a cheap per-engine default (claude-haiku-4-5, gpt-4o-mini, ...), else the engine's own default. openrouter needs one.
-k, --api-key KEY
The API key, over api_key: in .raider.yml and the engine's environment variable. With --provider the only source of the key, together with -o api_key=.
--provider HOST[:PORT] | https://HOST[:PORT]
Runs on the model endpoint a provider's manifest declares, for this one run; see "Using a provider". Not with -e, -o engine=, -o url= or config explain.
--allow-internal
With --provider (and provider inspect): releases loopback, private, link-local and reserved provider addresses; see "PROVIDERS".
-o, --option KEY=VALUE
An engine attribute (repeatable), e.g. -o temperature=0.2 -o response_size=4096, merged over .raider.yml; the command line wins. Integers, decimals and true / false become numbers. raider's own .raider.yml keys (engine, perl, packs=a,b, skills=a,b, detect, no_detect=a,b, preferred_lib_target) configure raider instead and never reach the engine.
-r, --root DIR
The working directory, default the current one. The file tools are confined to it, bash starts in it, and .raider/config.yml (or .raider.yml), .raider/instructions.md (or .raider.md) and .raider/ are read from it.
-M, --mission TEXT
The instructions: replaces the default persona and .raider.md for this run. Skills, packs and the tool list still apply.
--bare
An isolated context: no .raider.md, no skills, no packs:, no default packs, no detection. --pack NAME and /pack NAME still work.
-i, --interactive
The REPL. It is the default when standard input is a terminal and no prompt is given; -i also forces it otherwise.
--json[=N], --msgpack[=N], --yaml[=N]
Print one document for the run, see "MACHINE OUTPUT".
--stream-json[=N], --stream-msgpack[=N], --stream-yaml[=N]
Print the run as events while it happens, ending with the document; see "Streams".
--no-session
Record nothing; see "SESSIONS".
--session ID
Continue session ID: its conversation is replayed and the run (or the REPL) is recorded in it.
--continue
The same with the newest session of the project.
--max-iterations N
Hard cap on tool rounds per raid. Default 10000, effectively unlimited.
--no-color
No ANSI colors, as with ANSI_COLORS_DISABLED.
--trace, --no-trace
Show or hide the live progress of tool calls. On by default when standard output is a terminal; off with a machine output flag, where --trace sends it to standard error.
--perl
Mount the Perl tools (perl_eval, perl_check, perl_cpanm), see "TOOLS".
--pack NAME
Enable a pack (repeatable). Given at all, the listed packs replace packs: of .raider.yml and the default packs; detection still adds.
--no-pack NAME
Switch a pack off (repeatable), also a default or detected one.
--no-detect, --detect
Switch pack detection off, or on over detect: false in .raider.yml.
--claude
Load CLAUDE.md and .claude/skills/*/SKILL.md as skills. Saved to skills: in .raider.yml on first use.
--openai, --codex
Load AGENTS.md. Saved like --claude.
--skills DIR
Load the *.md files in DIR as skills (repeatable). Saved like --claude.
--customize-prompt
Start the REPL with the prompt-builder, which writes .raider.md with you (/prompt in the REPL).
--export-skill [PATH]
Write a plain-markdown "how to use raider" document for the current configuration (default RAIDER-SKILL.md in -r) and exit.
--export-claude-skill [PATH]
Write the same as a Claude Code SKILL.md with frontmatter (default .claude/skills/raider/SKILL.md in -r) and exit.
--version
Print the version of raider (Langertha::Raider) and of Langertha core on one line, raider VERSION (Langertha VERSION), and exit.
-h, --help
Print the option summary and exit.
MACHINE OUTPUT
--json, --msgpack and --yaml print one document for the run, once, when it has ended. --stream-json, --stream-msgpack and --stream-yaml print events while the run happens, the last of which carries that same document (see "Streams"). Nothing else goes to standard output: the live trace is off unless --trace asks for it, and then goes to standard error like every diagnostic. The six flags exclude each other; giving two is a usage error. A usage or configuration error (exit status 2 or 3) prints no document and no events, only its message on standard error.
The flags write the same model in three encodings:
--json-- a pretty-printed JSON object with sorted keys, UTF-8.--stream-jsonwrites JSON Lines: one compact object per event and line.--msgpack-- one MessagePack map; text is written as UTF-8str, neverbin. Standard output is binary.--stream-msgpackwrites one map per event, back to back (MessagePack objects delimit themselves).--yaml-- one YAML document, starting with---, UTF-8.--stream-yamlwrites one YAML document per event, each starting with---.
Every field and type is the same in all three encodings.
The document
A run that completed:
{
"elapsed" : 2.731,
"metrics" : { "iterations" : 2, "raids" : 1, "time_ms" : 2710.4, "tool_calls" : 1 },
"response" : "The README describes ...",
"status" : "completed",
"version" : 1
}
A run that failed:
{ "elapsed" : 0.42, "error" : "...", "status" : "failed", "version" : 1 }
A run cancelled by SIGINT (Ctrl-C; see "EXIT STATUS"):
{ "elapsed" : 3.912, "status" : "cancelled", "version" : 1 }
A run stopped by SIGTERM, by a second SIGINT while it is being cancelled, or by either signal before it started:
{ "elapsed" : 5.107, "signal" : "TERM", "status" : "interrupted", "version" : 1 }
version-- integer, the format version (see below).status-- how the run ended:completed,failed,cancelledorinterrupted. These are the run states of the redesign (ADR 0009) that end a run and that the CLI can produce today;refusedis reserved for when it can.response-- the agent's final answer (completedonly).metrics-- the raider's cumulative metrics:raids,iterations,tool_calls,time_ms(completedonly).error-- the error message (failedonly).signal-- the signal that stopped the run,INTorTERM(interruptedonly).elapsed-- seconds the run took, to the millisecond.session-- the session the run is recorded in (see "SESSIONS"):idandpathof its journal. Missing with--no-sessionand for a signal during startup.
Streams
A stream is a sequence of events, each flushed as soon as it happens. Every event has these fields:
version-- the format version, as in the document.type-- what happened (below).seq-- 1, 2, 3, ... within the run.time-- when, in epoch seconds with fractions.
The types of version 1, with the fields each adds:
run.started--engineand, when there is one,model. A run interrupted during startup (reading the configuration or the prompt) has none: its stream is theinterruptedstate change andrun.finished.run.state--state:runningwhen the run starts, then thestatusit ends with (see "The document").tool.call--nameandargumentsof a tool call, before it runs;call, its id within the run (c1,c2, ...);status,dispatched.tool.result--callandnameof the call;status(succeeded,failedwhen the tool reported an error, orcancelledfor a call a cancelled run cut off);ok(the same as a boolean);size, the length of the result text in characters;content, its first 1000 characters; andtruncated(a boolean, true whencontentwas cut). The cut limits how much of a tool's output reaches the stream, but it is no filter: a secret in a tool's arguments or output can still show up.message-- a finished assistant message:role(assistant) andcontent. Version 1 reports the final answer of the run.run.finished-- always the last event, also when the run failed. Its fields are exactly the document of "The document"; a consumer that only wants the result reads the last event.
A run that calls one tool, as --stream-json:
{"engine":"openai","model":"gpt-4o-mini","seq":1,"time":1790000000.1,"type":"run.started","version":1}
{"seq":2,"state":"running","time":1790000000.1,"type":"run.state","version":1}
{"arguments":{"command":"ls"},"name":"bash","seq":3,"time":1790000001.2,"type":"tool.call","version":1}
{"content":"...","name":"bash","ok":true,"seq":4,"size":42,"time":1790000001.3,"truncated":false,"type":"tool.result","version":1}
{"content":"There are ...","role":"assistant","seq":5,"time":1790000002.4,"type":"message","version":1}
{"seq":6,"state":"completed","time":1790000002.4,"type":"run.state","version":1}
{"elapsed":2.312,"metrics":{...},"response":"There are ...","seq":7,"status":"completed","time":1790000002.4,"type":"run.finished","version":1}
Token deltas are not part of version 1. New event types may appear within a version, so a consumer must skip types it does not know.
Versions
--json=N (--msgpack=N, --yaml=N, and the --stream-* flags) asks for format version N; the version belongs to the model, so it means the same in every encoding and for documents and streams alike. The only version is 1, which is also what the plain flags write; any other N is a usage error. Only the =N form carries a version -- in raider --json 2 ... the 2 is part of the prompt.
Within a version, fields are only ever added, never renamed, removed or changed in meaning, so a consumer must ignore fields it does not know. A breaking change is a new version, chosen with --json=2; the plain flag stays on the old version for at least one release after the new one ships.
SESSIONS
Every run is recorded in a session journal (ADR 0015): .raider/sessions/<id>.jsonl under the working directory (-r), one JSON object per line. A one-shot run starts a new session and names it on standard error (with a machine output flag, in the document's session instead); the REPL starts one with its first prompt and records every prompt of it there. --no-session records nothing.
Creating .raider/ also writes .raider/.gitignore excluding sessions/ and lib/, unless that file exists: a journal holds the whole output of every tool, so it is not committed by default. API keys never enter it.
A run is recorded as run.started, the input as message, every tool.call and tool.result (with the whole result text, where the stream cuts it), the answer as message, and run.finished with how it ended -- also when it failed or was interrupted. A /clear in the REPL is recorded as history.cleared. While a raider writes a session it holds a lock on it; a second writer fails at once instead of waiting. A journal that cannot be written in the middle of a run (a full disk) is a warning on standard error; the run goes on.
Wherever a command takes a session ID, a shorter form names it too: a unique start of the id (20260925-08) or its four hex digits at the end (3f2a). A form that fits more than one session is refused with the candidates listed.
raider session list # the project's sessions, newest first
raider session show ID # one session, event by event
raider session show ID --json # the whole journal as one document
raider session resume ID # the REPL, continuing session ID
raider --session ID "and now ..." # one more run in session ID
raider --continue "and now ..." # the same in the newest session
raider -i --continue # the REPL on the newest session
raider session fork ID # a new session with ID's history
raider session rm ID # delete session ID
session list shows id, number of runs, the state of the last run and the first prompt of each session; session show prints every event, then what the crash rules found. Both read without the lock, take -r for the project and a document format (--json, --msgpack, --yaml), as do session fork and session rm. As for config explain, the options may come first; there only session list and session show|resume|fork|rm followed by a session id are the subcommand, any other prompt starting with session is sent as a prompt.
session fork ID starts a new session in the same project whose session.created names the original in forked_from, and copies what a resume would replay as the conversation into it, as message events outside any run. The original is only read, not locked or changed; the fork has its own journal from then on and is continued like any session (session resume, --session). session rm ID deletes the journal and its lock file; it takes the lock first, so a session another raider has open is refused with exit status 4. Raider never deletes a session on its own.
Continuing a session (--session ID, --continue, session resume) takes its lock, replays the conversation -- the input and answer of every run that got an answer, and all recorded events into the full session history; after a history.cleared only what came later -- and records the new runs in the same journal. Nothing recorded is executed again. It reports what it found on standard error (in the REPL, under the banner): lines that could not be read, runs that never ended (they count as interrupted), and tool calls without a result, whose outcome is unknown. The context (.raider.md, packs, configuration) is built fresh, not replayed. A session another raider has open ends raider with exit status 4.
PROVIDERS
raider provider inspect HOST[:PORT] | https://HOST[:PORT] [--json] [--allow-internal]
fetches https://HOST[:PORT]/.well-known/langertha.json, the provider manifest of ADR 0007, validates it with Langertha::Manifest and shows what it declares: the provider id, the issuer, every endpoint (id, dialect, base URL, auth reference), every auth entry (id, type) and every model (id, endpoint, the capabilities it claims). Warnings follow for what this raider cannot use -- an endpoint dialect it has no adapter for, an auth type it cannot supply, a capability name Langertha does not know (treated as absent) -- and for an issuer that is not the origin the manifest came from or an endpoint on plain http or an internal address. extensions are shown as inert: kept as published, never interpreted, loaded or run. A manifest with a command-, code-, secret- or prompt-shaped field (command, exec, api_key, system_prompt, ...), an unknown field or another schema version is not valid.
Inspecting stores nothing, binds no credential and trusts nothing: the manifest states what the provider claims. The fetch sends no API key, no Authorization header and no cookie, and is bounded:
httpsonly; a target with userinfo, a query, a fragment or another path than the well-known one is a usage error.at most 1 MiB of body, 10 seconds from resolving the host to the last byte, and 3 redirects, each within the origin (scheme, host and port). A redirect to another origin is not followed; it is reported with its target and the manifest counts as
refused.the host is resolved once and every address it resolves to is checked; the request goes to a checked address, never to a second lookup of the name, while TLS still verifies the certificate against the name. Loopback, private (RFC 1918, shared address space, IPv6 unique local), link-local and reserved addresses are refused, unless
--allow-internalreleases them. Cloud metadata addresses (169.254.169.254,fd00:ec2::254, ...), the unspecified address, multicast and240.0.0.0/4are refused always. A host with one refused address among its addresses is refused.
--allow-internal releases loopback, private, link-local and reserved target addresses for this one inspection -- for a knarr or skeid you deliberately run on an internal address. Nothing remembers it.
Using a provider
raider --provider HOST[:PORT] | https://HOST[:PORT] [-m MODEL] [-k KEY] [--allow-internal] [options] [prompt...]
fetches and validates the manifest as provider inspect does (same limits and address rules) and runs on the endpoint of one of its models: one-shot, machine output and the REPL work as with -e. Nothing is stored and nothing is remembered: naming the host on the command line is the whole release, as with -o url=. raider provider add with a stored alias and credential is not there yet. The rules are provisional:
The model.
-m(or-o model=) must be a model id of the manifest. Without it the manifest must list exactly one model id; several are a usage error that lists them.model:in .raider.yml does not apply. A model listed on several endpoints runs on the one whose dialect raider has an adapter for; with more than one such endpoint raider does not choose and the run is refused.The engine follows from the endpoint's dialect:
openai-chatruns asopenai,anthropicasanthropic,geminiasgemini,ollamaasollama(native API),responses,perplexity-agent,anthropic-compatandakion their own Langertha engines --anthropic-compatwithout native structured output, through a synthetic tool and a forced tool choice instead (ADR 0007). The engine'surlis the endpoint'sbase_url, whatever .raider.yml says; the other engine options of .raider.yml and-oapply as with-e. A dialect this raider has no adapter for is an error, and so islmstudio: Langertha's native LM Studio engine has no tool calling.The key comes only from
-kor-o api_key=. Neitherapi_key:in .raider.yml nor any environment variable is used: a key for another provider never reaches this one. An endpoint with an auth reference needs a key (a usage error without one); an auth type other thanapi_keyis an error. An endpoint without auth gets no key.The origin. The endpoint's
base_urlmust behttpsand of the same origin (scheme, host, port) as the manifest; anything else is refused, so the key goes nowhere but the origin named on the command line. The endpoint's host is resolved and checked again before the run, under the rules ofprovider inspect(--allow-internalreleases it the same way). The engine then connects to the first of the checked addresses, never to a new lookup of the name (TLS still verifies the certificate against the host name), so a DNS answer that changes after the check cannot send the key elsewhere. A redirect to another host is never followed; the model requests are POSTs, which are not redirected at all, and the engine's synchronous requests (the REPL's/model) follow no redirect.A model that does not declare
tools_nativeis a warning on stderr, not an error: raider works through tool calls.
Failures are reported on stderr before anything runs, without a machine document: a usage error exits with 2, a provider that cannot be used as it is (refused, not fetched, not valid, an unknown dialect or auth type) with 1.
The provider document
--json, --msgpack and --yaml write one document (no stream):
{
"address" : "93.184.216.34",
"elapsed" : 0.214,
"final_url" : "https://provider.example/.well-known/langertha.json",
"manifest" : { "schema_version" : 1, "kind" : "langertha-provider", ... },
"notes" : [],
"redirects" : [],
"status" : "completed",
"url" : "https://provider.example/.well-known/langertha.json",
"version" : 1,
"warnings" : []
}
status is completed for a valid manifest, refused for a target address or redirect the rules above do not allow, and failed for anything else: the network, TLS, an HTTP status, a limit, invalid JSON or an invalid manifest. manifest is the validated manifest as "to_hash" in Langertha::Manifest writes it; warnings and notes are one sentence each; url is the manifest URL, final_url the one the body came from after redirects, address the address connected to. refused and failed carry error instead of manifest, and a redirect that was not followed its target in location. The version and compatibility rules are those of "Versions".
EXIT STATUS
0-- success, including--help,--version, the exports,config explain,config migrate(also with nothing to migrate, and--dry-run),session list,session show,session fork,session rm,provider inspectof a valid manifest and leaving the REPL.1-- the run failed: the engine, a tool or the network raised an error. With a machine output flag, the document saysfailed. Forconfig migrate: the migration was refused, also with--dry-run, or a step failed. Forprovider inspect: the manifest was refused, could not be fetched or is not valid (the document saysrefusedorfailed). For--provideralso: its endpoint cannot be used (another origin, nothttps, a refused address, a dialect or auth type this raider has no adapter for, no models, a model on several endpoints); see "Using a provider".2-- usage error: unknown option, a-othat is notKEY=VALUE, an unknownconfigsubcommand, no prompt, more than one machine output flag, a machine output flag with-i, or an unknown format version; forconfig migratea word after it or a machine output flag; forprovider inspectalso no target or more than one, a target that is no host orhttpsorigin, or a--stream-*flag; for--providera target that is none,-e,-o engine=,-o url=orconfig explainwith it, a model the manifest does not list, no-mwhere it lists several, or no-kwhere the endpoint needs a key; and--allow-internalwithout--provider.3-- configuration error: the config file (project or home; forconfig migratethe .raider.yml to migrate) cannot be read, the engine is unknown, or a pack detection rule is invalid.4-- the session to continue (--session,--continue,session resume) or to remove (session rm) is in use by another raider. A usage error (2) is also an unknown or ambiguous session, a--sessionthat is no session id,--continuewithout any session, or more than one of--session,--continueand--no-session.130,143-- a one-shot run was cancelled bySIGINTor interrupted bySIGTERM. OnSIGINT(Ctrl-C) raider cancels the run: it ends the tool commands still running, abandons a model request in flight, lets the run end at its next safe point and writes its document --cancelled, or what the run reached if it ended anyway -- or its events, or a note. A secondSIGINTwhile it cancels, aSIGTERM, and with a machine format either signal during startup end the tool commands and write theinterrupteddocument at once. Either way raider then dies of that same signal, so a shell reports 128 plus the signal number and a parent that waits for it sees a process killed by the signal. A model or embedding request that blocks the process (not an asynchronous one) holds a cancel up until it returns; the secondSIGINTdoes not wait.
The hall and acp subcommands keep their own exit statuses.
ENVIRONMENT
API keys come from the environment variables below only. Claude Code subscription/OAuth credentials are not consumed by this CLI; Anthropic usage goes through the API key path.
ANTHROPIC_API_KEY
The key of the anthropic engine. Set, it also makes anthropic the engine when nothing names one; so do the next five, in this order.
OPENAI_API_KEY
The key of openai.
DEEPSEEK_API_KEY
The key of deepseek.
GROQ_API_KEY
The key of groq.
MISTRAL_API_KEY
The key of mistral.
GEMINI_API_KEY
The key of gemini.
MINIMAX_API_KEY
The key of minimax. This one and the next two are only read for their engine; they never pick it.
CEREBRAS_API_KEY
The key of cerebras.
OPENROUTER_API_KEY
The key of openrouter.
BRAVE_API_KEY
Adds Brave to web_search, next to the keyless DuckDuckGo.
SERPER_API_KEY
Adds Serper to web_search.
GOOGLE_API_KEY
With "GOOGLE_CSE_ID", adds Google Custom Search to web_search.
GOOGLE_CSE_ID
The Custom Search engine id for "GOOGLE_API_KEY".
RAIDER_PACK_DIRS
Colon-separated directories searched for packs after the project's .raider/packs/, ~/.raider/packs/ and the bundled ones; see "build_packs" in Langertha::Raider::Packs.
HOME
Where ~/.raider/packs/ and the REPL history ~/.raider_history are.
ANSI_COLORS_DISABLED
Set, the output and the trace have no colors (--no-color and the machine output flags set it themselves).
RAIDER_HALL_SOCKET
The control socket of the Hall that started this raider. When it names a socket, the Hall tools telegram_reply, hall_status and hall_spawn are mounted; the Hall sets it, together with RAIDER_HALL_TELEGRAM_BOT, RAIDER_HALL_TELEGRAM_CHAT_ID and RAIDER_HALL_TELEGRAM_THREAD_ID for a Telegram mission (see Langertha::Raider::HallTools).
SEE ALSO
raider-hall -- the Hall daemon, also reachable as
raider hall
SUPPORT
Issues
Please report bugs and feature requests on GitHub at https://github.com/Getty/langertha-raider/issues.
IRC
Join #langertha on irc.perl.org or message Getty directly.
CONTRIBUTING
Contributions are welcome! Please fork the repository and submit a pull request.
AUTHOR
Torsten Raudssus <torsten@raudssus.de> https://raudssus.de/
COPYRIGHT AND LICENSE
This software is copyright (c) 2026 by Torsten Raudssus.
This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.