A Claude Code-style agentic CLI for penetration testing. Sandboxed (Docker), provider-agnostic (LiteLLM), with workflows and sub-agents.
Project description
Pentest Code
A Claude Code–style agentic CLI for penetration testing. Same terminal UI, same tool-loop feel — but every command runs inside an isolated Docker sandbox, it talks to any model provider via LiteLLM, and it can spin up workflows and sub-agents just like Claude Code.
╭──────────────────────────────────────────────────────────────╮
│ ✻ Welcome to Pentest Code │
│ │
│ /help for commands, /status for your setup │
│ cwd: /root/engagement │
│ sandbox: pentestcode_sandbox (running) · pentest-code-sandbox │
╰──────────────────────────────────────────────────────────────╯
model: anthropic/claude-sonnet-4-20250514 mode: manual (approve commands)
⏺ Bash(nmap -sV 10.0.0.5)
⎿ 22/tcp open ssh OpenSSH 8.9
80/tcp open http nginx 1.18.0
… +3 lines
⚠️ Authorised testing only. Use this exclusively against systems you own or have explicit written permission to test. You are responsible for staying in scope and complying with the law.
Highlights
| Feature | Details |
|---|---|
| Claude Code UI | Welcome box, ⏺ tool bullets, ⎿ result branches, live spinner, todo checklist, bordered prompt, inline approval menu, clay accent. |
| Two modes only | manual — approve every command; auto — nothing is asked. Toggle with shift+tab or /auto / /manual. |
| Docker-only sandbox | All commands execute via docker exec in a Kali-based container. No local-execution fallback — your host is never touched. |
| Any provider (LiteLLM) | Anthropic, OpenAI, Gemini, Groq, Mistral, DeepSeek, OpenRouter, Ollama/vLLM, or a LiteLLM proxy. Just set PENTESTCODE_MODEL. |
| Workflows | Scripted multi-step engagements (/workflow recon) defined in YAML. |
| Sub-agents | The Task tool spawns autonomous sub-agents that can recurse and fan out, sharing the sandbox + state. |
| Sandbox memory | A persistent sandbox_state.json records OS, installed tools/libraries, wordlists, engagement facts and findings — so the model never starts from zero. |
Requirements
- Docker installed and running (the only execution backend).
- Python 3.9+ on the host to run the CLI.
- An API key for whichever model provider you choose.
Install
pip install pentestcode
That's it — you do not need to clone the repo or run docker build yourself.
The sandbox image (Kali + common pentest tools) is defined by a Dockerfile
bundled inside the package, and Pentest Code builds it automatically on
first run. First launch takes a few minutes while the image builds.
Prefer to build it ahead of time, or inspect/customise the Dockerfile?
pentestcode build-sandbox # build + start the sandbox now, then exit
pentestcode --print-dockerfile # print the bundled Dockerfile
pentestcode --print-dockerfile > Dockerfile && docker build -t pentest-code-sandbox:latest .
From a clone (for development) the root Dockerfile is used automatically:
git clone https://github.com/Arpitpm23/pentestcode && cd pentestcode
pip install -e .
Set at minimum a model and its key (LiteLLM reads keys from the environment):
export PENTESTCODE_MODEL=anthropic/claude-sonnet-4-20250514
export ANTHROPIC_API_KEY=sk-ant-...
# …or OpenAI:
export PENTESTCODE_MODEL=openai/gpt-4o
export OPENAI_API_KEY=sk-...
# …or a local Ollama model (OpenAI-compatible):
export PENTESTCODE_MODEL=openai/llama3.1
export OPENAI_API_BASE=http://localhost:11434/v1
export OPENAI_API_KEY=ollama
Run
pentestcode # or: python -m pentestcode (aliases: ptc, pentest-code)
On first launch it will build/start the sandbox container and probe it once for installed tools (cached in the state file). Then you get the prompt.
Modes
- manual (default): every
Bashcommand,Write, andEditshows an inline approval box —Yes/Yes, don't ask again for <tool>/No, tell it what to do instead. Reads and searches never prompt. - auto: tools execute immediately with no prompts.
Switch anytime with shift+tab, or /auto / /manual / /mode.
Commands
/help show help
/status model, mode, sandbox and state summary
/mode [manual|auto] show or set the mode
/auto /manual switch mode
/model <name> switch model (LiteLLM format)
/state [refresh] show persistent sandbox state (refresh re-probes)
/sandbox [restart] sandbox status / recreate container
/workflows list workflows
/workflow <name> run a workflow (prompts for inputs)
/clear fresh conversation (keeps sandbox + state)
/exit quit (container keeps running)
Workflows
Built-ins live in pentestcode/workflows/; drop your own YAML into
.pentestcode/workflows/ and they show up automatically.
/workflows
/workflow recon # asks for: scope (e.g. 10.0.0.0/24)
/workflow web-audit # asks for: url
A workflow is an ordered list of steps; each step feeds a prompt to the agent
(steps share context, or set isolated: true to run as a dedicated sub-agent).
name: recon
description: External recon of a target scope.
inputs: [scope]
steps:
- name: Host discovery
prompt: "Discover live hosts in {scope}; save to loot/hosts.txt."
- name: Port scan (parallel)
isolated: false
prompt: "Scan each host; delegate one 'recon' sub-agent per host via Task."
Sub-agents
The model can call the Task tool to delegate focused work to an autonomous
sub-agent (e.g. one per host/service). Sub-agents:
- run their own tool loop with a specialised prompt (
recon/web/exploit/post/general), - share the same sandbox and the same
sandbox_state.json, - can spawn their own sub-agents up to
max_subagent_depth(default 3), - return only a final report to the parent (keeping context lean).
Limits live in .pentestcode/config.json (max_subagents, max_subagent_depth).
The sandbox-state file (memory)
./.pentestcode/sandbox_state.json is the agent's long-term memory of the
sandbox. It stores:
- OS + kernel, and a per-tool inventory (
present/missing, path), - installed Python libraries and available wordlists,
- engagement scope/targets/creds and durable findings + notes.
It is injected (compactly) at the top of every session, so the model doesn't
re-check what it already knows. The model curates it with the UpdateState
tool; you can view it with /state and force a re-probe with /state refresh.
A full re-probe only happens automatically when the sandbox image changes.
Architecture
pentestcode/
├── cli.py REPL: bootstrap sandbox, slash commands, prompt loop
├── agent.py agent loop: stream → tool-calls → observe; sub-agent spawn
├── llm.py LiteLLM client (streaming + tool-call reconstruction)
├── sandbox.py Docker-only executor (exec, cwd persistence, file I/O)
├── state.py persistent sandbox state + one-shot probe
├── prompts.py system prompts (main + sub-agent specialisations)
├── workflow.py YAML workflow engine
├── config.py modes / model / sandbox settings (env + JSON)
├── tools/ Bash, Read, Write, Edit, Grep, Glob, TodoWrite,
│ UpdateState, Task
├── ui/ theme + console (banner, tool render, spinner,
│ approval menu, bordered input) — the Claude Code look
└── workflows/ built-in recon.yaml, web-audit.yaml
Flow: cli starts the Docker sandbox and probes it → Agent sends the
conversation + tool schemas to the model via llm → tool calls are gated by the
mode (manual approval) and executed in the sandbox → results feed back into the
loop → durable knowledge is saved to the state file.
Extending
- New tool: subclass
Toolinpentestcode/tools/, setname,description,parameters(JSON schema),requires_approval, implementrun(args, ctx), and register it intools/__init__.py. - New workflow: add a YAML file to
.pentestcode/workflows/.
Notes & limits
- Multiple
Taskcalls in one turn run sequentially (readable terminal output), but there is no low cap — a parent can fan out up tomax_subagents. - The sandbox mounts
./loot→/root/engagementso scan output/loot persists. - SYN scans etc. need raw sockets — the container is started with
NET_RAW/NET_ADMIN(configurable inconfig.py).
License
MIT — see LICENSE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file pentestcode-1.0.2.tar.gz.
File metadata
- Download URL: pentestcode-1.0.2.tar.gz
- Upload date:
- Size: 42.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.9.25
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5e76f3ae296a2215164da10d8893862858c8b294402fc5530442f2ee7df9f64d
|
|
| MD5 |
e78aa1f1c96050f8831a011fd5d06372
|
|
| BLAKE2b-256 |
9a6f35ddc865b044273fbc9c08ef021a76433c2b7c8a6ee29d7e4cd8591d015a
|
File details
Details for the file pentestcode-1.0.2-py3-none-any.whl.
File metadata
- Download URL: pentestcode-1.0.2-py3-none-any.whl
- Upload date:
- Size: 45.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.9.25
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6dd98d05bc4fc91df102d30b9ae61e401f877b4b0329b7042e80f3a93c1e2e28
|
|
| MD5 |
76a1acc7396d02f947dd3b62bae9af8e
|
|
| BLAKE2b-256 |
0896920aa60ce022df6d57c8da6565e6acd9da3e51b3625be8e45c6e00956ad6
|