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, by perl: in .raider.yml (perl: false denies them), or else when an active pack requests them -- the bundled perl pack, detected in a Perl workspace. Switching such a pack with /pack or re-detecting it with /reload mounts 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-json writes JSON Lines: one compact object per event and line.
--msgpack -- one MessagePack map; text is written as UTF-8 str, never bin. Standard output is binary. --stream-msgpack writes one map per event, back to back (MessagePack objects delimit themselves).
--yaml -- one YAML document, starting with ---, UTF-8. --stream-yaml writes 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, cancelled or interrupted. These are the run states of the redesign (ADR 0009) that end a run and that the CLI can produce today; refused is reserved for when it can.
response -- the agent's final answer (completed only).
metrics -- the raider's cumulative metrics: raids, iterations, tool_calls, time_ms (completed only).
error -- the error message (failed only).
signal -- the signal that stopped the run, INT or TERM (interrupted only).
elapsed -- seconds the run took, to the millisecond.
session -- the session the run is recorded in (see "SESSIONS"): id and path of its journal. Missing with --no-session and 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 -- engine and, when there is one, model. A run interrupted during startup (reading the configuration or the prompt) has none: its stream is the interrupted state change and run.finished.
run.state -- state: running when the run starts, then the status it ends with (see "The document").
tool.call -- name and arguments of a tool call, before it runs; call, its id within the run (c1, c2, ...); status, dispatched.
tool.result -- call and name of the call; status (succeeded, failed when the tool reported an error, or cancelled for 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; and truncated (a boolean, true when content was 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) and content. 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:

  • https only; 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-internal releases them. Cloud metadata addresses (169.254.169.254, fd00:ec2::254, ...), the unspecified address, multicast and 240.0.0.0/4 are 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-chat runs as openai, anthropic as anthropic, gemini as gemini, ollama as ollama (native API), responses, perplexity-agent, anthropic-compat and aki on their own Langertha engines -- anthropic-compat without native structured output, through a synthetic tool and a forced tool choice instead (ADR 0007). The engine's url is the endpoint's base_url, whatever .raider.yml says; the other engine options of .raider.yml and -o apply as with -e. A dialect this raider has no adapter for is an error, and so is lmstudio: Langertha's native LM Studio engine has no tool calling.

  • The key comes only from -k or -o api_key=. Neither api_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 than api_key is an error. An endpoint without auth gets no key.

  • The origin. The endpoint's base_url must be https and 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 of provider inspect (--allow-internal releases 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_native is 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 inspect of 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 says failed. For config migrate: the migration was refused, also with --dry-run, or a step failed. For provider inspect: the manifest was refused, could not be fetched or is not valid (the document says refused or failed). For --provider also: its endpoint cannot be used (another origin, not https, 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 -o that is not KEY=VALUE, an unknown config subcommand, no prompt, more than one machine output flag, a machine output flag with -i, or an unknown format version; for config migrate a word after it or a machine output flag; for provider inspect also no target or more than one, a target that is no host or https origin, or a --stream-* flag; for --provider a target that is none, -e, -o engine=, -o url= or config explain with it, a model the manifest does not list, no -m where it lists several, or no -k where the endpoint needs a key; and --allow-internal without --provider.
3 -- configuration error: the config file (project or home; for config migrate the .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 --session that is no session id, --continue without any session, or more than one of --session, --continue and --no-session.
130, 143 -- a one-shot run was cancelled by SIGINT or interrupted by SIGTERM. On SIGINT (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 second SIGINT while it cancels, a SIGTERM, and with a machine format either signal during startup end the tool commands and write the interrupted document 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 second SIGINT does 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

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.