SYSTEMS NOMINAL LAB LOG 2026

Overview

Mapache is an autonomous offensive-security agent. You give it an objective in plain language ("pentest 10.0.0.5", "find the IDOR in the app at http://target/") and it works the engagement one tool call at a time: it enumerates, exploits, escalates, and hands back a report of proven findings with remediation.

This directory is the full reference. Start with the overview, then dive into the area you care about.

First run

git clone https://github.com/slider-labs0/Mapache.git && cd Mapache
python3 -m venv .venv && source .venv/bin/activate
pip install -e .        # installs the `mapache` command
mapache setup           # interactive: pick a provider and a model
mapache serve           # launch the agent

Requires Python 3.10 or newer. Kali or ParrotOS is the recommended platform because the offensive toolchain is packaged there. For local models install Ollama; for cloud models set the provider key and pass --allow-cloud.

Safety

Mapache is for authorized security testing only: engagements you own or have written permission to test. It enforces a rules-of-engagement scope, but scope is a guardrail, not a guarantee. You are responsible for staying in bounds and for complying with applicable law. See Execution and OPSEC for the guardrails.

Architecture

Mapache runs one execution path: a ReAct (reason and act) loop. There is no hidden planner pipeline and no separate executor. The agent observes, acts with one tool, reads the real result, and decides the next step. This page explains the moving parts.

The agent loop

core/agent_controller.py holds AgentController, the orchestrator. Its _agent_loop is the heart of Mapache:

  1. Build the prompt (system prompt, attack state, task list, relevant playbooks, recent history) with the context builder.
  2. Ask the model for the next action. Native tool-calling models return a structured tool call; models without native tool-calling return JSON that the loop parses.
  3. Dispatch the chosen tool, enforce the rules-of-engagement scope first, and capture the real output.
  4. Fold the result back into the attack state and the conversation, then loop.

The loop is bounded by MAX_ITERATIONS so it can never run away, and it stops early when the model produces a final answer, when a loop policy halts it, or when a budget is exhausted.

One tool per step

Reading each real result before choosing the next step is what keeps Mapache grounded. It does not invent endpoints or assume a scan result. It acts, observes, and adapts. The model can still batch several independent tool calls in a single turn (for example, scanning two hosts at once); those dispatch concurrently and fold back in the order the model stated.

Attack state and the conversation chain

core/conversation_chain.py holds ConversationChain, which tracks the attack state across turns: the target, open ports, services, the current phase, discovered vulnerabilities, captured credentials, and flags. Key behaviors:

  • A freshly typed IP that differs from the current target overrides it and clears stale findings. This handles a lab machine getting a new IP mid-session.
  • Rescan keywords clear cached ports so a fresh scan is not skipped.
  • Tool outputs are compressed before they are re-injected, which prevents the context from overflowing on a long engagement.
  • A persistent task list (todos) survives across turns. The model seeds it with a plan, updates item status, and the loop re-injects a === TASK LIST === block every iteration so the model always sees mid-turn progress.

Phases and tool subsetting

Mapache models an engagement as phases: recon, enumeration, exploitation, post, and report. ConversationChain.active_tool_names exposes only the tools relevant to the current phase. This keeps the function-calling payload small enough for local models, which otherwise choke on a large tool schema. Certain tools (delegation, memory, generated tools, MCP tools) are pinned so subsetting never hides them.

The attack system prompt encodes a default workflow: recon, then enumerate, then exploit, then post, then report. It blocks exploitation before a scan has returned open ports, so the agent does not fire an exploit at a host it has not looked at yet.

The context builder

core/context_builder.py assembles the prompt and enforces a token budget (max_context_tokens, default 16384). It injects the system prompt, the live attack state, the task list, any relevant playbooks, and recent history. When native tool-calling is available, tool schemas go in the dedicated tools field; otherwise the tools are described in the prompt and the model is asked for JSON output.

Context compaction

When raw history outgrows its token budget, the controller summarizes the oldest turns into a running summary with a model call and drops those messages, instead of silently trimming them. The summary is prepended to the system prompt as "CONVERSATION SO FAR". Durable facts (targets, ports, versions, credentials, vulnerabilities, flags, paths, and what is pending) are kept verbatim. Compaction only fires when actually over budget and keeps a recent window, and it fails open to a plain trim if anything goes wrong.

Robust tool-call parsing

Local models mangle output in predictable ways. _parse_model_response tolerates JSON fenced in code blocks, JSON embedded in prose (a balanced, string-aware brace scan), and a missing type tag (inferred from the keys present). Output that clearly intended the protocol but is unusable is flagged as malformed; the loop feeds the error back and asks for a clean retry, bounded by MAX_REASKS. Incidental braces in a normal answer are not reasked.

Loop safety rails

  • No-progress and duplicate-call guard: within a turn, an identical tool call (same name and args) runs once; later repeats are short-circuited with the cached result and a nudge to change approach. This fixes the "fetch the same URL five times" loop.
  • Stall and loop detection aborts a turn early when the model spams duplicates or makes no progress, so a weak model does not burn the whole iteration budget going in circles.
  • Answer general knowledge directly: definitions and facts the model already knows are answered in plain text without tools, and a blocked lookup falls back to the model's own knowledge rather than being reported as the final answer.

The event bus

core/event_bus.py is the pub/sub backbone. The loop emits events (tool calls, findings, delegations, scope refusals, steering, duplicate calls). Observers subscribe without driving the loop. The audit log and the TUI dashboard are both event consumers, which is why they never slow the agent down.

Mid-run steering

A frontend can call AgentController.steer(text) to redirect a turn already in progress. Queued messages are drained at the top of each loop iteration and injected as operator steering. A freshly typed target or a rescan updates the attack state without disturbing the in-progress turn. This lets you correct the agent live without restarting the session.

Middleware

core/middleware.py provides composable loop middleware. Shipped middleware includes budget enforcement (stop gracefully at a token or time cap), a human-in-the-loop checkpoint slot, an offensive-vaccine loop (turn each confirmed vulnerability into a detection and remediation note), and a reflection and tactical-staging step. Middleware is opt-in and inert unless configured.

Model routing and multi-model agents

Mapache can run on a single model or orchestrate several models inside one engagement, each owning a role. This page explains the routing strategies, how to configure a multi-model team, and exactly how a sub-agent decides which model controls it.

The mental model

Configuring several providers in mapache setup does not run them all at once. Nothing runs until you start a session and give it a prompt, and each session runs one engagement. Which model does the work is decided by three things:

  1. The model you pin at launch (--model) or the default_model in config.
  2. The routing strategy (--strategy or default_strategy).
  3. The optional per-role model map (model_roles) and per-operator routing.

Strategies

A strategy decides how roles map to models. Roles are planner (strategy and decomposition), executor (runs the tools each turn, drives the loop), and verifier (checks the final answer). The ReAct loop itself runs as the executor role.

StrategyBehavior
single (alias solo)One model for every role: the model you pass with --model. No mixing.
autoBest-scoring model per role, drawn from the registry of available models.
pipelineDedicated model per role: quality-weighted planner and verifier, speed-weighted executor.
hybridCloud planner and verifier plus a local executor. Requires --allow-cloud.
swarmAuto routing plus the multi-agent supervisor. Activates operator fan-out at launch.

With a single model installed, every strategy collapses to that one model, so there is no behavior change until you actually have more than one model available.

For a clean model-versus-model comparison, pin --strategy solo with each --model so one model does the whole engagement. For a collaborative team, use per-role routing or swarm as described below.

Running one model per demo

mapache serve --model deepseek-chat        --strategy solo --allow-cloud
mapache serve --model kimi-k2-0711-preview --strategy solo --allow-cloud
mapache serve --model glm-4.6              --strategy solo --allow-cloud

Run them one after another. solo forces every role to the pinned model, so each run is purely that model.

Running several models as one team

Assign models to roles with model_roles in the config. The setup wizard offers this as its "customize per role" option, or you can write it directly. A compelling split for a cloud team:

{
  "allow_cloud": true,
  "default_model": "kimi-k2-0711-preview",
  "default_strategy": "pipeline",
  "model_roles": {
    "planner":  "deepseek-reasoner",
    "executor": "kimi-k2-0711-preview",
    "verifier": "glm-4.6"
  },
  "providers": {
    "deepseek": { "kind": "openai_compatible", "base_url": "https://api.deepseek.com",           "api_key": "${DEEPSEEK_API_KEY}", "models": ["deepseek-chat","deepseek-reasoner"], "enabled": true },
    "moonshot": { "kind": "openai_compatible", "base_url": "https://api.moonshot.ai/v1",          "api_key": "${MOONSHOT_API_KEY}", "models": ["kimi-k2-0711-preview"],            "enabled": true },
    "zhipu":    { "kind": "openai_compatible", "base_url": "https://open.bigmodel.cn/api/paas/v4", "api_key": "${ZHIPU_API_KEY}",    "models": ["glm-4.6"],                         "enabled": true }
  }
}

The ${...} placeholders read from the environment, so no secret is written to disk:

export DEEPSEEK_API_KEY=sk-... MOONSHOT_API_KEY=sk-... ZHIPU_API_KEY=...
mapache serve --allow-cloud --verify

--verify is important for a three-model team, because that is what fires the verifier role. Without it, only the planner and executor participate. Explicit model_roles overrides win regardless of strategy, because the router checks overrides before it consults the strategy.

The TUI dashboard shows the live role-to-model map in a "Models" panel, which is a clean on-screen proof that several models are working the same case.

How a sub-agent chooses its model

When the lead delegates a subtask or the supervisor deploys a specialist, the child agent's model is decided by a four-layer pipeline in _spawn_and_run, applied in order.

1. Inherit the lead's model

The child starts on the lead's routed model. By default it is on the same routed brain as the lead.

2. OPSEC pin (sensitivity can force local)

OpsecPolicy.decide inspects the operator and the shared attack state. If the work is sensitive, either because the operator prefers local (loot, credentials, post-exploit) or because the shared state already holds captured credentials, the sub-agent is pinned to a local model even when the lead is allowed cloud. This keeps loot and credentials on the host. It is a no-op when cloud is disabled (everything is local anyway), and it falls back to the current model with a warning if no local model is installed.

3. Per-operator role routing (the important layer)

Each operator declares a model role, and the child routes to that role's model through the routing engine, which honors your model_roles map. Reasoning-heavy specialists declare planner; action specialists default to executor:

OperatorDeclared roleExample model from the team above
recon, web, exploit, post, cloud, mobile, wireless, iot, ics, generalexecutorKimi
osint, exploit_dev, contract_auditor, reverser, analyst, coderplannerDeepSeek-Reasoner
verifier checkpoints (with --verify)verifierGLM

Reasoning specialists get the reasoning model; action specialists get the fast tool-caller. This happens automatically from the operator's declared role.

4. Cost and quality tier

Finally, for_tier(operator.tier) routes broad-discovery operators (recon, osint) to a cheaper model and the rest to a strong model. This only takes effect if you have configured a tiered provider; otherwise it is a no-op.

The key point

Mapache does not assign models by operator name. There is no table that says "recon always uses model X". It assigns by the role each operator declares, funneled through your model_roles and routing. That is why setting the three roles is all you need to orchestrate the whole swarm across three models.

Commands

  • /models shows the live routing table plus a per-model call count.
  • /pipeline <strategy> switches the strategy mid-session.
  • /swarm [on|off] toggles the multi-agent supervisor.
  • /opsec shows which operations are pinned local.

Multi-agent orchestration

Mapache can split an engagement into specialists that share one attack state. There are two ways this happens: the lead agent delegates a bounded subtask, or an autonomous supervisor routes the whole engagement across operators. This page covers both, the operator roster, and how work is coordinated.

Delegation

A built-in delegate(task, operator=...) tool lets the model spawn a focused child AgentController for one bounded subtask and get back only its conclusion. The child runs the named operator's focused system prompt and a small curated tool subset instead of the lead's generalist prompt and full toolset. On a local model this is a real win: a smaller payload and narrower decisions.

Recursion is bounded by MAX_DELEGATION_DEPTH (default 1), so a sub-agent is not offered the delegate tool and cannot spawn its own children endlessly. Delegation events fire on the event bus with the operator label, so the audit log and the dashboard both see them.

The shared blackboard

The child references the lead's attack state by reference, so its findings are live in the lead's state with no merge-back step. A guard stops a child's task wording from reassigning the target or wiping the shared findings. The child also shares the lead's event bus, so its tool calls, findings, and scope refusals land in the same engagement log. State mutations are safe for concurrent children.

Parallel fan-out

delegate_parallel(tasks=[{task, operator}, ...]) runs several operators concurrently over the shared blackboard, capped by MAX_FANOUT. This gives you several angles on the current host at once. On a single GPU the model calls serialize at the provider, so it is a correctness and orchestration win; once cloud routing serves the calls concurrently it becomes a wall-clock win as well.

The operator roster

Operators live in core/operators.py. Each carries a focused prompt, a curated tool subset, a declared model role, a cost tier, and role constraints (read-only, gated by rules of engagement, needs hardware, deconflict first). Naming one in delegate or letting the supervisor pick runs the child as that specialist.

OperatorTitleFocus
generalGeneral AgentGeneral, non-offensive tasks and questions (not a kill chain)
coderCoderWrite, run, and fix general code, scripts, and tooling
recon_operatorRecon OperatorBroad host and service discovery
osint_operatorOSINT OperatorPassive research and correlation
web_operatorWeb OperatorWeb application attack surface
exploit_operatorExploit OperatorService and application exploitation
post_operatorPost-Exploit OperatorPrivilege escalation, loot, pivoting
cloud_hunterCloud HunterCloud metadata, IAM, storage
contract_auditorContract AuditorSmart-contract and Web3 review
exploit_devExploit DeveloperWriting and running exploit code
reverserReverserBinary and firmware reversing
analystAnalystVulnerability research, exploit-chain construction
phisherPhisherSocial engineering, requires deconfliction
mobile_operatorMobile OperatorAndroid and iOS app testing
wireless_operatorWireless OperatorWi-Fi and radio
iot_operatorIoT OperatorDevice and firmware attacks
ics_operatorICS OperatorIndustrial control and OT, gated by scope
forensicatorForensicatorDFIR and purple-team analysis
supply_chain_operatorSupply Chain OperatorDependency and CI/CD compromise

There is also a vulnerability-research pipeline (scanner, detector, verifier, patcher, exploiter) and an engagement planner (soundwave) used by the supervisor.

Role constraints render into the prompt and reinforce the scope gate. /operators lists the roster, and a next-step suggester nudges the right specialist based on the open ports and services in the attack state.

The autonomous supervisor (swarm)

core/orchestrator.py holds the supervisor. With /swarm on (or default_strategy set to swarm), the supervisor autonomously routes the engagement across operators driven by the attack state, instead of relying on a single generalist agent to do everything.

The supervisor decides which specialist to deploy next from the current state, hands off, collects the specialist's conclusions into the shared knowledge, and continues. This is the mode to use when you want the most visible multi-agent action, and it is where the sub-agent model-selection pipeline in Model routing comes into play: each specialist can run on a different model based on the role it declares.

Success is evidence, not a flag

Mapache is a full-spectrum agent, not a capture-the-flag bot, so the supervisor's success signal is evidence-based: a captured flag, a confirmed vulnerability, or captured credentials all count as a solved objective. The engagement summary reports the number of findings, not a bare solved or unsolved flag.

The generalist fallback

The swarm is built for offensive engagements. If you hand it a general or coding objective, the offensive operators have no real job, so rather than flailing and reporting a failure, the swarm falls back to the lead agent once when it surfaces no evidence, so the task actually gets done. For a plain coding request, prefer running it without swarm (solo strategy with a coding model, or delegate to the coder operator); the fallback is a safety net, not the intended path.

Knowledge graph and the operation plan

The supervisor and the operators write into a disk-persisted knowledge graph (a findings store) so a freshly spawned specialist can query prior findings with a fresh context. There is also an operation plan (OPPLAN) that the model reads and updates (opplan_show, opplan_add, opplan_update) to keep long engagements coherent.

Trace streaming

Sub-agent activity streams through a scoped event bus, so the operator sees the child's tool calls and findings live rather than waiting for a summary at the end. In the CLI the transcript is colored by the active specialist so you can tell which operator is working.

Skills and playbooks

A skill is a compact playbook injected into the model's context at the right moment, so a weak model is grounded on the right technique without bloating every call. Mapache ships built-in playbooks for every domain and lets you author or import your own as SKILL.md files.

Built-in playbooks

Fifteen just-in-time playbooks cover the full spectrum: web, network service, credential, Active Directory, cloud, binary exploitation, mobile, social engineering, smart contracts and Web3, supply chain, ICS and OT, IoT and firmware, wireless, OSINT, and DFIR and purple team. Each one is a concrete, imperative body of guidance (tools, endpoints, payloads, proof) that is injected only while it is relevant.

The result is that Mapache is not web-only. Every domain operator has injected method.

How activation works (hybrid)

Mapache uses a hybrid of two activation mechanisms, chosen so the fast path stays free and offline while foreign skills still activate.

Predicate matching (the fast path)

Each built-in playbook carries a deterministic predicate over the attack state and the request: open ports, the target scheme, and keywords. When the predicate fires, the body is injected. This path is instant, offline, and free, and it is what the built-in domain playbooks use.

Model-based selection (for description-only skills)

For skills that carry a description but whose predicate does not fire, which is the case for trigger-less skills imported from other agents, a model reads a compact catalog of those skills and selects which apply to the current objective and attack state. The selection is cached by a signature of the engagement state, so the extra model call fires only when the situation materially changes, and any failure falls back to selecting nothing. This lets a foreign skill activate without hand-adding triggers, while the built-in playbooks keep their zero-cost predicate path.

Authoring a SKILL.md

A skill is a Markdown file with YAML frontmatter and a body. All trigger fields are optional; a skill with none never auto-injects on the fast path, and instead relies on model-based selection through its description.

---
name: lfi_ssrf
description: Local file inclusion and SSRF playbook
when_to_use: When a parameter takes a path or a URL
ports: [80, 443, 8080]
keywords: [lfi, ssrf, file=, url=]
target_scheme: [http, https]
phase: exploitation
tools: [http_request]
---
ACTIVE PLAYBOOK: describe the technique here. This body is injected into the model's
context verbatim whenever the skill matches, so write it as concrete, imperative
guidance: tools, endpoints, payloads, and how to prove the finding.

Fields:

  • name (required) and description (used for model-based selection).
  • when_to_use is a human-readable hint.
  • ports, keywords, and target_scheme are the fast-path triggers.
  • phase and tools are advisory.
  • allowed-tools is accepted for compatibility with skills authored for other agents.

The YAML parser handles inline lists, block-style lists, and multi-line scalars, so richer skills authored for other agents parse faithfully. It uses PyYAML when installed and a dependency-free parser otherwise.

Loading skills

Drop skills into ~/.mapache/skills/ (global) or <workspace>/skills/ (per project). Both layouts load:

  • Flat single files: skills/my_skill.md.
  • Nested packages: skills/my-skill/SKILL.md, discovered recursively.

A nested package can ship bundled resource files (scripts and reference documents) alongside its SKILL.md. When the skill activates, the injected text lists those files with their paths, so the agent can read a reference with its file tools or run a bundled script with code_run or shell. This is progressive disclosure: the playbook prose is always available, and the heavier resources are opened on demand.

Compatibility with skills authored for other agents

The container format (SKILL.md with YAML frontmatter and a Markdown body) matches the common convention, so the prose of another agent's skill is reusable and its name and description parse cleanly. Unknown frontmatter keys are ignored rather than causing errors. The differences to keep in mind:

  • Activation in Mapache is by trigger or by model-based selection over the description, not purely by the model reading the description at will.
  • Bundled scripts are surfaced for the agent to run with its existing tools rather than executed automatically.

To reuse a foreign skill, copy its SKILL.md into a skills directory, add trigger frontmatter if you want the fast path, and re-home any bundled scripts.

Skill synthesis

Mapache can also write a new skill from a proven chain. The synthesize_skill tool saves the current winning sequence of actions as a reusable, signed skill, so a technique that worked once can be replayed and shared.

Tools

Mapache drives roughly fifty registered tools plus a set of meta-tools. Tools are structured: the model calls them with typed arguments, the result comes back as structured output, and schema validation catches a malformed call so the model can self-correct. This page groups the toolchain by area.

Execution and files

  • shell runs a command on the active execution backend (local, Docker, or SSH).
  • code_run is a compile, run, and fix loop. It writes code (Python, C, C++, Go, Rust, Bash, and more), compiles it, runs it, and iteratively fixes it, staging into the active target and returning a structured verdict (compile failed, exit code, or ok). This is the exploit-writing primitive.
  • file_read, file_write, file_edit, file_list, and file_search operate on files.

Recon and network

  • nmap_scan runs structured port and service scans with schema validation. If the model omits the target, it is backfilled from the attack state.
  • kali_run and kali_list drive the packaged Kali tooling; searchsploit looks up ExploitDB.
  • Operators drive domain CLIs (aws, kubectl, frida, ghidra, jadx, gophish, and others) through shell and kali_run.

Web

  • http_request sends a structured HTTP request. Because it is structured JSON, payloads with quotes survive intact, unlike a shell curl. This is the primitive for API testing.
  • http_repeater records, replays, tampers, and diffs requests. It is the primitive behind broken-access-control and IDOR testing.
  • web_fetch and web_search read the surface web; tor_fetch routes through Tor.
  • browser is a real headless browser (Playwright) that renders JavaScript and single-page apps, so the agent sees what a user sees.
  • sqlmap and fuzz (ffuf) are disciplined wrappers around those classic tools.
  • Response-grounded acting nudges the agent off blind endpoint spraying and toward the target's real forms and endpoints.

Exploitation and cracking

  • msf_search and the Metasploit integration drive MSFRPC.
  • The Burp Suite integration uses the REST API and proxy.
  • john identifies and cracks hashes; hashcat and hydra are available through the Kali interface.

Grounding and research

  • cve_lookup correlates discovered services and versions to known CVEs with severity and exploit availability, from an offline catalog.
  • vuln_research starts the vulnerability-research pipeline (scanner, detector, verifier, patcher, exploiter).
  • A payload corpus with a search tool provides known-good payloads instead of guesses.

Memory and planning meta-tools

  • kg_query and kg_add read and write the knowledge graph (the findings store).
  • opplan_show, opplan_add, and opplan_update manage the operation plan.
  • The persistent task list is seeded by a plan response and updated with a todo update.

Delegation meta-tools

  • delegate(task, operator=...) spawns a focused specialist child for one subtask.
  • delegate_parallel(tasks=[...]) fans several operators out over the shared blackboard.

See Multi-agent orchestration for how these behave.

Self-authored tools

The create_tool meta-tool lets the model author a brand-new reusable tool at runtime. It writes the body of an async run function, which is compiled (errors are handed back for self-correction) and persisted as a hub-installable package under plugins/generated/<name>/ with a manifest carrying origin, usage, lifecycle state, phase, and a sha256 checksum. The tool registers into the tool registry and becomes callable on the next loop iteration, never in the same response that created it.

Trust model: an agent-written tool (origin self) loads freely; a downloaded tool (origin hub) is sha256-verified before it compiles and refuses to load if it has been tampered with. The startup loader is fail-soft, so a bad tool never breaks startup.

Model-facing tools: create_tool, tool_list_generated, tool_delete.

The curator (tool-library garbage collection)

Self-authored tools move through a reversible lifecycle: active, then stale, then archived, so the create-tools loop cannot pile up. A usage rule auto-demotes an unused tool to stale (a non-destructive label; using it promotes it back to active). The only permissioned step is stale to archived: /curate proposes stale tools one at a time and, on your per-tool approval, unregisters them and moves their folder out of the load path. /restore <name> reverses it, and /purge <name> hard-deletes an already-archived tool as a deliberate two-step.

MCP tools

Tools exposed by a connected Model Context Protocol server appear as ordinary Mapache tools named mcp__<server>__<tool>. See MCP and the skill hub.

Providers

A provider is where a model runs. Mapache talks to local models, cloud providers, and local gateways through one abstraction, so per-role routing can address local and cloud models interchangeably. This page lists the providers, how to configure them, and their model ids.

How providers work

Each provider entry in the config carries a kind, a base URL, an API key, a list of model ids it serves, and an enabled flag. A model id is routed to the provider that lists it; a model that no cloud provider claims falls back to the local Ollama provider. Cloud calls require --allow-cloud (or allow_cloud: true in config), and Mapache warns when a call sends target, scan, or credential context to a cloud model.

You can set keys three ways: type them in mapache setup, put them in the config file, or reference an environment variable with a ${VAR} placeholder so nothing secret is written to disk.

Local models: Ollama

The default provider. Install Ollama, run ollama serve, and pull a model:

ollama pull qwen2.5:32b
mapache serve --model qwen2.5:32b

Any locally installed model works without listing it. Ollama is the recommended primary test model source; qwen2.5:32b is a reliable tool-calling local model.

Context window

Ollama defaults a model's context window to a small value (often 4096 tokens), so a full Mapache prompt (system prompt plus tools plus attack state, roughly 12000 to 16000 tokens) overflows it and Ollama returns HTTP 400 "exceeds the available context size". Mapache requests a larger window automatically via options.num_ctx (default 16384), so any model can hold a real engagement prompt. Override it with the OLLAMA_NUM_CTX environment variable. A larger window uses more memory, so if a big model runs out of memory, lower OLLAMA_NUM_CTX, but keep it above your typical prompt size (around 13000) or large prompts will overflow again.

Cloud providers

ProviderKindBase URLKey env var
OpenRouteropenai-compatiblehttps://openrouter.ai/api/v1OPENROUTER_API_KEY
Anthropicanthropichttps://api.anthropic.comANTHROPIC_API_KEY
OpenAIopenai-compatiblehttps://api.openai.com/v1OPENAI_API_KEY
Grok (xAI)openai-compatiblehttps://api.x.ai/v1XAI_API_KEY
Nousopenai-compatible(Nous endpoint)NOUS_API_KEY
NVIDIA NIMopenai-compatible(NIM endpoint)NVIDIA_API_KEY

OpenRouter is convenient because one key reaches many frontier models (for example anthropic/claude-sonnet-4.6, openai/gpt-4.1, x-ai/grok-4).

Native Chinese providers

DeepSeek, Moonshot (Kimi), and Zhipu (GLM) are first-class providers, so you can paste a key straight from the vendor console without routing through an aggregator.

ProviderBase URLKey env varsModel ids
DeepSeekhttps://api.deepseek.comDEEPSEEK_API_KEYdeepseek-chat, deepseek-reasoner
Moonshot (Kimi)https://api.moonshot.ai/v1MOONSHOT_API_KEY or KIMI_API_KEYkimi-k2-0711-preview, moonshot-v1-128k, moonshot-v1-32k, moonshot-v1-8k
Zhipu (GLM)https://open.bigmodel.cn/api/paas/v4ZHIPU_API_KEY or GLM_API_KEYglm-4.6, glm-4.5, glm-4-plus, glm-4-air, glm-4-flash

All three are OpenAI-compatible, so Mapache speaks to them natively with no extra dependency. They support native tool-calling, which the agent loop needs.

Local gateways: OmniRoute

OmniRoute is a local OpenAI-compatible gateway that aggregates many providers, including free tiers. Configure it as a provider with kind openai-compatible, base URL http://localhost:20128/v1, and a dummy non-empty key (the gateway ignores auth on localhost). Pin a fixed model id to avoid the gateway rotating the backend per request.

Free-tier models routed this way have two practical limits: some forbid native tool-calling and some throttle aggressively. They are fine for light use but not for driving the full agent loop at speed. A capable local model or a paid cloud model is the right choice for real engagements.

Tool-calling versus JSON mode

Native tool-calling models receive tool schemas in the dedicated tools field. A model without native tool-calling (or a tier that forbids it) runs in JSON mode: the tools are described in the prompt and the model is asked for JSON that the loop parses into tool calls. Mapache selects the mode automatically per provider.

Choosing a model

  • For real engagements, use a capable local model (for example qwen2.5:32b) or a frontier cloud model.
  • Small or free-tier models struggle to drive the loop reliably.
  • For a multi-model team, see Model routing.

Execution and OPSEC

This page covers where Mapache runs its commands, how it anonymizes its traffic, how it stays inside an authorized scope, how it records what it did, and how it defends itself.

Execution backends

Every shell and tool command runs on an execution backend. The backend is selected in config (execution.backend) or with /backend.

  • Local: commands run on the host that runs Mapache. The default.
  • Docker: commands run inside a container through docker exec. This is how Mapache runs a Linux toolchain on a Windows host, and how it isolates an engagement from the host.
  • SSH: commands run on a remote host over SSH.

A backend returns a structured result (stdout, stderr, exit code) so tools behave the same regardless of where they run. Sub-agents can be given their own backend, so a specialist's shell and scans run in an isolated container while the lead coordinates.

Egress and anonymity

Mapache can route its attack traffic to hide the operator's origin. The egress mode is set in config (egress.mode) or with /egress:

  • direct: no anonymization.
  • proxy: route through an HTTP or SOCKS proxy.
  • tor: route through Tor. Mapache detects Tor and guides setup.

When egress is active the CLI shows it at startup, and web and fetch tools honor it.

Rules of engagement (scope)

An authorized test has a scope: the targets you are allowed to touch. Mapache enforces it with an optional scope.json in the working directory (or --scope <path>).

{
  "name": "ACME external pentest",
  "targets": ["10.10.10.0/24", "acme.example.com"],
  "forbidden_tools": ["msf_run"],
  "forbidden_patterns": ["rm -rf", "shutdown", "mkfs"],
  "allow_loopback": true
}
  • targets is an allowlist of IPs, CIDRs, and hostnames. Hostnames match subdomains.
  • forbidden_tools blocks named tools entirely.
  • forbidden_patterns blocks any argument matching a pattern (destructive commands).
  • allow_loopback permits local utility calls (default true).

The gate runs in the dispatch path, after the target is backfilled from the attack state and before the tool runs. An out-of-scope or forbidden call is refused, never dispatched, and the refusal is fed back to the model, which then changes approach. A defense-in-depth re-check covers generated-tool shell calls that bypass the controller, and sub-agents inherit the scope so delegation stays bounded.

Scope is inactive when no scope.json is present, so the default behavior is unchanged. Host extraction favors precision (IPs from any argument, bare hostnames only from target-shaped keys and URLs) so a wordlist path is not mistaken for a target. The CLI shows a startup banner, a /scope command, and a live refused line when a call is blocked.

The audit log

Mapache keeps an append-only JSONL trail of the whole session, fed purely by the event bus. It records every tool call with arguments and outcome, every finding (flag, credential, vulnerability, open port), every scope refusal, and the delegate and verify events, one flushed line per record so it survives a crash and is frozen after the session closes.

It is on by default (writes to engagements/, which is gitignored; disable with --no-engagement-log). /log shows it and /log export renders a Markdown findings list and timeline, which is the seed for the report.

Self-defense and containment

Mapache defends itself and contains the target side.

  • Prompt-injection shield: the agent is hardened against instructions embedded in a target's responses (a page, a banner, a file) trying to hijack the agent. Injected content is treated as data, not as operator instructions.
  • Isolated-lab containment: running the engagement through the Docker or SSH backend keeps the target's shell and tools off the host. The scope gate guards the target side; the injection shield guards the agent side.

OPSEC routing

When cloud is allowed, sensitive work can still be pinned to a local model so loot and credentials never leave the host. This is decided per sub-agent based on the operator and whether credentials have already been captured. See Model routing for the full pipeline, and /opsec to see which operations are pinned local.

Memory

Mapache remembers within an engagement, across engagements, and semantically. This page covers the memory subsystems and the cross-engagement learning that biases future runs.

Session memory

memory/session_memory.py holds the turn-by-turn history of the current session. It works with the conversation chain and context compaction so a long engagement stays coherent without overflowing the context window.

Notes

memory/note_store.py is a place for the agent to jot durable observations during an engagement. The model can record a note and recall it later. /memory shows the current memory state and /user records durable facts about the operator.

Knowledge store and semantic recall

memory/knowledge_store.py and memory/vector_store.py store findings and support semantic recall: the agent can retrieve a prior finding by meaning, not just by exact match. This is what lets a finding persist across sessions and surface again when it becomes relevant.

The knowledge graph (findings store)

A disk-persisted knowledge graph records findings as structured nodes so a freshly spawned specialist can query prior findings with a fresh context. This is the shared memory behind the multi-agent supervisor: the lead and every operator read and write the same graph. Model-facing tools are kg_query and kg_add.

The operation plan

The operation plan (OPPLAN) is a living plan the model reads and updates over a long engagement (opplan_show, opplan_add, opplan_update). It keeps the objective and the outstanding steps coherent when the engagement spans many turns and several operators.

Cross-engagement learning

Mapache keeps a cross-engagement learning store that records what worked on similar targets before and biases routing toward those approaches on a new but similar target. A target fingerprint is used to match, so a technique that won against a similar stack is surfaced as a prior-win hint. This is how Mapache gets better with use rather than starting cold every time.

What is stored where

  • Session history and the running summary live with the session.
  • Notes and knowledge live in the note and knowledge stores.
  • Findings live in the knowledge graph, which is shared across agents.
  • The engagement audit trail lives in engagements/ (see Execution and OPSEC).
  • Cross-engagement learning lives in its own store and persists between runs.

Middleware

Cross-cutting concerns (budget, human approval, defensive follow-up, reflection, route enumeration) are not hand-wired into the loop. They are composable middleware that hook well-defined slots, so they can be added or removed without touching the controller.

The framework

core/middleware.py defines the contract:

  • AgentMiddleware - a base class with three optional async hooks:
  • on_turn_start(ctx) - once, before the first model call of a turn.
  • on_iteration_start(ctx) - the top of every loop step.
  • on_turn_end(ctx, response) - once, after the turn produces its answer.
  • LoopContext - the mutable per-turn state passed to every hook. A middleware influences the loop by setting:
  • ctx.stop = True (with ctx.stop_reason) to end the turn now, or
  • ctx.inject.append("...") to add a user message before the next model call (steering, nudges, approvals). It also exposes ctx.controller, ctx.session_id, ctx.iteration, and a scratch dict middlewares can share within a turn.
  • MiddlewareChain - runs the registered middlewares at each slot, in order. A hook that raises is logged and swallowed, so one bad middleware cannot break the engagement. A ctx.stop short-circuits the remaining middlewares at that slot.

The default chain is empty; middleware is inert until registered (usually from a CLI flag). Register with controller.add_middleware(...).

Built-in middlewares

All live in core/agent_middlewares.py.

BudgetMiddleware

Stops the engagement once it exceeds a token or wall-clock budget. Checks the controller's cumulative token usage and elapsed time at each iteration and sets a graceful ctx.stop/ctx.stop_reason with a budget.exceeded event. Wired by --budget-tokens N / --budget-seconds S.

HITLMiddleware

A human-in-the-loop checkpoint gate. Fires on an every-N iterations cadence and/or on a phase change; a callback returns approve, deny (stop), or steer (inject a new instruction). Fail-open on a callback error, and the first iteration never gates. Distinct from per-tool dangerous-action confirmation. Wired by --hitl / --hitl-every N.

VaccineMiddleware

Defensive follow-up. On each newly confirmed vulnerability it generates a detection plus remediation note (a "vaccine"), records it to the knowledge graph as mitigating the vulnerability, and writes it to the workspace. Vaccinated once per vulnerability; a per-step cap bounds bursts. Wired by --vaccine.

ReflectionMiddleware

Every N steps it injects a structured self-critique: confirmed facts, current hypothesis, and the highest-value next action, so the agent reasons about what it has learned instead of drifting. Wired by --reflect / --reflect-every N.

RouteEnumMiddleware

Active route enumeration. Once, when a web target has few discovered endpoints, it probes a curated list of common routes through the tool dispatcher and folds the real hits (non-404) into the shared endpoints, then injects them so the agent uses real paths instead of guessing. Wired by --route-enum; the swarm runs the equivalent enumeration in the supervisor before routing.

Where the supervisor fits

The multi-agent supervisor is not a loop middleware; it is a control loop that drives sub-agent turns. Its anti-loop, fan-out, and route enumeration are described in multi-agent. A sub-agent is itself an AgentController, so any middleware registered on it hooks that sub-agent's loop.

Reporting

Mapache is evidence-first: success is a proven finding with severity, evidence, impact, and remediation, not a captured flag. This page covers how it turns an engagement into a report and what formats it exports.

The report builder

reporting/report_builder.py turns the audit-log records and the attack-state blackboard into a structured pentest report:

  • Findings for vulnerabilities, captured credentials, notable exposed services (telnet, SMB, RDP, Redis, and others), and flags, each with a severity and concrete remediation.
  • First-seen timestamps taken from the audit log.
  • An executive summary with a severity tally.
  • A methodology timeline.
  • A tool-activity appendix.

The builder is deterministic and offline. It makes no LLM call, so it is reproducible, testable, and never sends findings to a third party. This keeps the local-first OPSEC story intact from end to end.

Export formats

  • Markdown for readability and version control.
  • Self-contained HTML (print it to get a PDF).
  • SARIF for ingestion into code-scanning and security dashboards.
  • A bug-bounty draft for submission.

Optional secret redaction removes captured credentials from the exported copy.

Generate a report with /report [md|html|both], which writes to engagements/.

Grounding and scoring

Findings can be correlated to known CVEs with severity and exploit availability from an offline catalog (cve_lookup). An optional LLM narrative pass and precise CVSS scoring are layered enhancements on top of the deterministic core, so you can add polish without giving up reproducibility.

Why evidence-first matters

Most agents invent endpoints, field names, and payloads and then declare victory. Mapache reads a target's real forms, endpoints, and disclosed credentials into state, looks up payloads from an offline corpus, and detects dead attack vectors so it changes approach instead of spinning. A finding in the report is backed by the exact request or command that proved it, recorded in the audit log with a timestamp.

MCP and the skill hub

Mapache is extensible in two directions: it consumes tools from Model Context Protocol servers, and it installs and publishes community skills and tools through a hub.

MCP client

Mapache connects out to Model Context Protocol servers and exposes their tools as ordinary Mapache tools. It is a client: Mapache consumes MCP servers, it does not act as one.

How it works

Each server is launched as a subprocess and spoken to over the stdio transport: newline-delimited JSON-RPC 2.0 (initialize, then tools/list, then tools/call). A remote tool is wrapped as a normal tool, registered into the same tool registry and dispatcher as the built-ins, and namespaced mcp__<server>__<tool> to avoid collisions. Their names are pinned so phase-based subsetting keeps them exposed. Connection is fail-soft: a bad server never breaks startup, and clients are closed on exit.

Configuration

Servers are listed in a Claude-Desktop-style mcp.json (--mcp-config, default mcp.json; absent means MCP is off):

{
  "mcpServers": {
    "filesystem": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-filesystem", "."],
      "env": {}
    },
    "fetch": {
      "command": "uvx",
      "args": ["mcp-server-fetch"],
      "env": {}
    }
  }
}

The launcher is resolved through PATH, honoring PATHEXT, so a bare command like npx or uvx finds its real executable. This is what makes the canonical configuration work on Windows as well as Linux and macOS.

Note that a third-party MCP server can be broken upstream, independent of Mapache. When that happens Mapache logs the server as unavailable and continues, rather than failing to start.

Driving a browser like a user (Playwright MCP)

The Playwright MCP server lets Mapache drive a real browser the way a person does: it can navigate, click, type, fill forms, select options, upload files, take screenshots, inspect network requests, and capture an accessibility snapshot of the page that the model acts on by element. This is a richer, interactive complement to Mapache's built-in headless browser tool (which renders a page for reading).

Add it to your mcp.json:

{
  "mcpServers": {
    "playwright": {
      "command": "npx",
      "args": ["-y", "@playwright/mcp@latest", "--headless"],
      "env": {}
    }
  }
}

Its tools appear as mcp__playwright__browser_navigate, mcp__playwright__browser_click, mcp__playwright__browser_snapshot, mcp__playwright__browser_type, and so on (around two dozen). Notes:

  • The first run downloads the package and a browser, so give it a moment.
  • Drop --headless to watch the browser act (useful for a demo).
  • browser_run_code_unsafe executes arbitrary JavaScript on the page; only enable this server against targets you are authorized to test.
  • Mapache looks for mcp.json in the working directory you launch from (or the path you pass to --mcp-config), so put it where you run mapache serve.

The skill hub

The hub lets you browse, install, and publish reusable extensions. Three manifest types are supported:

  • A generated tool: a self-authored tool packaged for reuse.
  • An MCP server: an entry added to your mcp.json.
  • An external tool: a bring-your-own HTTP or command tool.

Installing

A hub is configured by pointing at a registry (a local path or an http(s) URL). Installing a generated tool writes a package to your generated-tools directory and re-verifies its sha256 before it loads. Installing an MCP server writes an entry into your mcp.json. A tampered package is refused before anything is written. /hub and the skill tools drive this from inside a session, and they degrade gracefully when no hub is configured.

Publishing

You can publish your own generated tool, MCP server entry, or external tool to a registry, so a technique that worked for you can be shared with a checksum as the integrity gate.

Which extension mechanism to use

  • Use MCP when you want to reuse an existing tool server that already speaks the protocol.
  • Use a self-authored tool when you want the agent to build a small tool on the fly (see Tools).
  • Use a skill when you want to teach the agent a technique rather than give it a new tool (see Skills and playbooks).
  • Use the hub to distribute any of these.

User interface

Mapache has three faces: the line-based CLI, an opt-in full-screen TUI with a live agent dashboard, and the setup wizard. It can also be operated remotely over Telegram and Discord. This page covers each, plus every slash command.

Launching

mapache serve                     # classic CLI
mapache serve --tui               # full-screen TUI with the dashboard
mapache serve --model qwen2.5:32b # pin a model
mapache setup                     # the setup wizard
mapache config show               # print the effective config
mapache version                   # print the version

The startup banner shows a large ANSI wordmark and the mascot, then a compact box of session facts (model, tool count, confirm and verifier state, memory counts, the rules of engagement, and the working directory).

The classic CLI

You type an objective at the prompt and the agent works it, streaming its reasoning and tool activity. A single background reader handles input, so you can type to steer a running turn (or answer a confirmation) without a second reader competing for the keyboard. The transcript is colored by the active specialist during delegation, so you can see which operator is working. In the classic CLI the strategy and per-role model routing print inline at startup.

The full-screen TUI dashboard

--tui opens a two-column layout:

  • Left column: the ANSI mascot and the scrolling transcript, over a bordered input box.
  • Right column: a live agent dashboard, a fixed-width stack of panels.

The dashboard panels:

  • Agent: the active operator and its accent color, the current phase, the most recent tool or command it called, and the team size. Sub-agent tool calls feed the HUD too, so in swarm mode you see the operators' actual commands live.
  • Models: the routing strategy and the per-role model map (planner, executor, verifier). This is where the model details live in the TUI, rather than front and center.
  • Target: the target, the open ports, and the vulnerability count.
  • Budget: elapsed time and tokens against any configured caps, and the tool-call count.
  • Running shells: any in-flight shell commands, with a spinner.
  • Recent tools: the last handful of tool calls.

The dashboard is fed by the same events the transcript uses, plus the status clock, so it updates live as the agent works without slowing it down. The full-screen view needs a real console; if the terminal cannot start a full-screen app, Mapache falls back to the classic CLI automatically.

The setup wizard

mapache setup walks you through configuration, with every question in its own titled panel:

  • Model provider: pick from local Ollama or a cloud provider.
  • API key: paste a key for a cloud provider, or leave it to an environment variable.
  • Model: pick a model id (a suggested list, or type your own).
  • Roles: use one model for everything, or customize per role (lead, executor, verifier), which writes the per-role model map.
  • Strategy: Auto (smart routing), Solo (one model), or Swarm (a multi-agent team).
  • Toolchain, Ollama, and a smoke test are shown as compact panels.

The wizard is idempotent: every prompt shows the current value as its default, and pressing Enter keeps it. Secrets are preserved: a key kept as an environment placeholder is never rewritten as a literal.

Remote operation

Mapache can run over Telegram and Discord with the full toolset. A single command launches both bots, and the async frontends can steer a running turn the same way the CLI can. Configure the bot tokens in the wizard or the config file.

Voice

Optional voice input and output are available behind a null default (--voice, --say, and the voice config section). Text-to-speech and speech-to-text are opt-in and require their optional packages.

Slash commands

Type these at the prompt during a session.

Session and help

  • /help shows the command list.
  • /clear clears the screen.
  • /exit, /quit end the session.
  • /history shows the conversation history.
  • /context shows what is in the current prompt context.
  • /debug toggles debug output.

Models and routing

  • /models shows the live routing table and per-model call counts.
  • /pipeline <strategy> switches the strategy (single, pipeline, auto, hybrid).
  • /swarm [on|off] toggles the multi-agent supervisor.
  • /opsec shows which operations are pinned to a local model.
  • /operators lists the operator roster.

State and memory

  • /chain shows the attack-state chain.
  • /hosts lists discovered hosts.
  • /memory shows memory state.
  • /user records a durable fact about you.
  • /cve looks up CVEs for a discovered service.
  • /synthesize saves the current proven chain as a skill.

Scope, logging, and reporting

  • /scope shows the active rules of engagement.
  • /log, /log export show and export the audit log.
  • /report [md|html|both] generates a report.

Execution and egress

  • /backend shows or sets the execution backend.
  • /egress shows or sets traffic anonymization.
  • /cwd shows the working directory.

Extensions and tools

  • /tools lists registered tools.
  • /integrations lists configured external tools.
  • /hub browses and installs from the skill hub.
  • /curate reviews stale self-authored tools for archiving.
  • /restore <name> restores an archived tool.
  • /purge <name> hard-deletes an archived tool.

Confirmation and voice

  • /confirm toggles per-action confirmation for dangerous operations.
  • /voice, /say control voice output.
  • /soul shows the agent persona.

Useful flags

  • --allow-cloud permits routing to cloud models.
  • --strategy <name> sets the routing strategy.
  • --verify enables the opt-in verifier step.
  • --scope <path> sets a rules-of-engagement file.
  • --mcp-config <path> sets the MCP server list.
  • --budget-tokens N, --budget-seconds S cap the engagement.
  • --attempts N enables multi-attempt self-consistency solving.
  • --tui opens the full-screen dashboard.

Configuration

Mapache reads a layered configuration: built-in defaults, then a global config file, then a project-level file, then environment variables, then command-line flags. Later layers win. This page documents the config file and the options.

Where config lives

  • Global: ~/.mapache/config.json, written by mapache setup.
  • Project: a config file in the working directory overrides the global one.
  • View the effective config with mapache config show, and the path with mapache config path. Secrets are redacted in the printed output.

Secrets

A value can be a literal, or an environment placeholder like ${DEEPSEEK_API_KEY}. The placeholder is resolved at load time, so a key supplied only by the environment is never written to disk as plaintext. The setup wizard preserves an existing placeholder when you press Enter.

Options

{
  "default_model": "qwen2.5:32b",
  "default_strategy": "single",
  "model_roles": {
    "planner": "deepseek-reasoner",
    "executor": "kimi-k2-0711-preview",
    "verifier": "glm-4.6"
  },
  "allow_cloud": false,
  "max_vram_gb": 12.0,
  "providers": {
    "ollama":   { "kind": "ollama",             "base_url": "http://127.0.0.1:11434", "enabled": true },
    "deepseek": { "kind": "openai_compatible", "base_url": "https://api.deepseek.com", "api_key": "${DEEPSEEK_API_KEY}", "models": ["deepseek-chat","deepseek-reasoner"], "enabled": true }
  },
  "messaging": { "telegram_token": "", "discord_token": "" },
  "execution": { "backend": "local" },
  "egress":    { "mode": "direct" },
  "integrations": [],
  "hub":       { "registry": "" },
  "voice":     { "enabled": false },
  "budget":    { "max_tokens": 0, "max_seconds": 0 },
  "hitl":      { "enabled": false, "every": 0, "on_phase_change": true },
  "vaccine":   { "enabled": false, "per_step_cap": 0 },
  "reflection":{ "enabled": false, "every": 0 },
  "flag_format": ""
}

Core

  • default_model: the model used when you do not pass --model.
  • default_strategy: single (alias solo), auto, pipeline, hybrid, or swarm. See Model routing.
  • model_roles: optional per-role model map (planner, executor, verifier), applied to the router at startup. Empty means every role uses the default model.
  • allow_cloud: permit routing to cloud models. Also set by --allow-cloud.
  • max_vram_gb: a hint for local routing.

Providers

Each entry has a kind (ollama, openai_compatible, or anthropic), a base URL, an optional API key, a list of model ids it serves, and an enabled flag. See Providers for the full list and the environment variables.

Messaging

telegram_token and discord_token enable the remote bots.

Execution and egress

  • execution.backend: local, docker, or ssh (plus backend-specific fields).
  • egress.mode: direct, proxy, or tor.

See Execution and OPSEC.

Middleware

  • budget: stop the loop gracefully at a token or wall-clock cap.
  • hitl: human-in-the-loop checkpoints (every N steps, or on a phase change).
  • vaccine: turn each confirmed vulnerability into a detection and remediation note.
  • reflection: inject a reflect-and-refocus checkpoint every N steps.

Extensions and other

  • hub.registry: a local path or an http(s) URL for the skill hub.
  • integrations: bring-your-own HTTP or command tool specs.
  • voice: text-to-speech and speech-to-text settings.
  • flag_format: an optional regex the candidate-flag verifier uses to recognize custom flags.

Environment variables

  • Provider keys: DEEPSEEK_API_KEY, MOONSHOT_API_KEY (or KIMI_API_KEY), ZHIPU_API_KEY (or GLM_API_KEY), OPENROUTER_API_KEY, ANTHROPIC_API_KEY, OPENAI_API_KEY, XAI_API_KEY, NOUS_API_KEY, NVIDIA_API_KEY.
  • Base URL overrides where supported, for example MOONSHOT_BASE_URL, ZHIPU_BASE_URL.
  • MAPACHE_STRATEGY maps to default_strategy.
  • OLLAMA_NUM_CTX sets the context window Mapache requests from Ollama (default 16384). See Providers.
  • NO_COLOR disables colored output.

Flags that override config

--model, --strategy, --allow-cloud, --scope, --mcp-config, --budget-tokens, --budget-seconds, --verify, --attempts, and --tui. Flags win over the config file.

Use cases

This page walks through end-to-end engagements across disciplines. Each one shows a target to practice against, the prompt to give Mapache, what the agent does, and what you get back. All targets here are ones you run yourself or are authorized to test.

A reminder: Mapache is for authorized testing only. Put a scope.json in your working directory so the rules-of-engagement gate is active (see Execution and OPSEC).

Web application pentest

Target: OWASP Juice Shop, a modern deliberately-vulnerable web app.

docker run --rm -p 3000:3000 bkimminich/juice-shop

Prompt:

You're authorized to test the web app at http://localhost:3000, which I own. Get
administrator access, prove it with concrete evidence, and give me a finding with
severity, impact, and remediation.

What happens: the web playbook activates because the target is a URL. Mapache reads the real login form and its endpoint with http_request (not a guessed path), tests the email field for SQL injection, uses the injection to log in as the administrator, confirms the admin token against an admin-only endpoint, and records an evidence-backed finding. Use /report both to export Markdown and HTML.

What you get: a report with the exact request that proved the finding, its severity, its impact, and how to remediate it.

Network and host pentest

Target: a lab host you own (for example a vulnerable VM on your own network).

Prompt:

Target is 10.0.0.5. Enumerate it, exploit any vulnerable service, escalate to root, and
report proven findings. Use -Pn on the scan.

What happens: the recon phase runs a structured nmap_scan (the target is backfilled if omitted), the attack state fills with open ports and services, the network-service or credential playbook activates from the ports, and the agent moves to exploitation only after the scan returns. Post-exploitation escalates and loots. If credentials are captured and a local model is installed, sensitive post-exploit work is pinned local.

What you get: findings for each vulnerable or exposed service, with remediation, plus a methodology timeline.

Cloud assessment

Target: a cloud account or a cloud-simulation lab you are authorized to test.

Prompt:

Assess the cloud posture reachable from this host. Check instance metadata, look for
over-permissive IAM and exposed storage, and report anything exploitable with evidence.

What happens: delegate to the Cloud Hunter operator (or let the supervisor pick it). It checks instance metadata, IAM, and storage through the cloud CLIs driven by shell. The cloud playbook grounds the technique.

Active Directory

Target: an AD lab you own.

Prompt:

Domain target is 10.0.0.10. Find a path to Domain Admin: enumerate the domain, hunt for
weak credentials and kerberoastable accounts, and report the path with evidence.

What happens: the Active Directory playbook activates. The agent enumerates the domain, looks for weak and reused credentials and kerberoastable accounts, and constructs a path to Domain Admin, recording each step.

Binary exploitation and exploit development

Target: a vulnerable binary you are analyzing.

Prompt:

Analyze ./vuln (attached in the working dir). Find the memory-corruption bug, then write
and run a working exploit with code_run that proves control of execution.

What happens: delegate to the Reverser and Exploit Developer operators, which declare the planner role so they run on the reasoning model. code_run writes the exploit, compiles it, runs it, and iterates on failures until it works, staging into the active backend.

Mobile application testing

Target: an Android APK you are authorized to test.

Prompt:

Test this Android app (apk in the working dir). Decompile it, look for hardcoded secrets
and insecure endpoints, and report findings.

What happens: the Mobile Operator drives the mobile toolchain (for example jadx and frida) through shell and kali_run, grounded by the mobile playbook.

A multi-model team demo

Goal: show three models collaborating on one engagement.

Set up per-role routing (see Model routing) with planner deepseek-reasoner, executor kimi, verifier glm, then:

mapache serve --allow-cloud --verify

Give it the web-app prompt above. The executor model drives the loop, the planner model does the reasoning-heavy analysis, and the verifier model validates the finding at the checkpoint. The TUI Models panel shows the role-to-model map live. Turn on /swarm for more visible specialist hand-off.

Capture the flag

Target: a CTF challenge you are solving.

Prompt:

Solve this challenge at http://localhost:8080. The flag format is CTF{...}.

What happens: pass --flag-format 'CTF\{.*\}' so the candidate-flag verifier recognizes a captured token in the right format. Use --attempts 3 for multi-attempt self-consistency on a hard challenge.

Bug bounty triage

Target: an asset in a program you are authorized to test.

Prompt:

Assess https://app.example.com within this scope. Focus on access-control and injection
flaws, and give me a bug-bounty draft for anything you can prove.

What happens: put the program scope in scope.json so the agent stays in bounds. The http_repeater tool is the primitive for the access-control testing. Export a bounty draft with the report tools.

DFIR and purple team

Target: logs or artifacts from an incident you are investigating.

Prompt:

Here are the logs in ./artifacts. Build a timeline of the intrusion and write detection
rules for what you find.

What happens: the Forensicator operator and the DFIR playbook drive the analysis. The offensive-vaccine middleware, if enabled, turns each confirmed issue into a detection and remediation note.

Tips that apply to every engagement

  • Put a scope.json in the working directory to keep the agent in bounds.
  • Add --budget-seconds 300 so a stuck weak model cannot run forever.
  • Use --verify to make success evidence-backed.
  • Use the --tui dashboard to watch the target, budget, tools, and running shells live.
  • Use a capable model. Small or free-tier models struggle to drive a full engagement.