Metadata-Version: 2.4
Name: pentestcode
Version: 1.0.1
Summary: A Claude Code-style agentic CLI for penetration testing. Sandboxed (Docker), provider-agnostic (LiteLLM), with workflows and sub-agents.
Author: Pentest Code
License: MIT
Project-URL: Homepage, https://github.com/Arpitpm23/pentestcode
Project-URL: Repository, https://github.com/Arpitpm23/pentestcode
Project-URL: Issues, https://github.com/Arpitpm23/pentestcode/issues
Keywords: pentesting,security,agent,llm,cli,claude-code
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: litellm>=1.44.0
Requires-Dist: rich>=13.7.0
Requires-Dist: prompt_toolkit>=3.0.43
Requires-Dist: docker>=7.0.0
Requires-Dist: pyyaml>=6.0
Requires-Dist: pydantic>=2.5.0
Provides-Extra: dev
Requires-Dist: pytest>=7.0; extra == "dev"
Requires-Dist: ruff>=0.1; extra == "dev"
Dynamic: license-file

# 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

```bash
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?

```bash
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:

```bash
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):

```bash
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

```bash
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 `Bash` command, `Write`, and `Edit` shows 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.

```bash
/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).

```yaml
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 `Tool` in `pentestcode/tools/`, set `name`,
  `description`, `parameters` (JSON schema), `requires_approval`, implement
  `run(args, ctx)`, and register it in `tools/__init__.py`.
- **New workflow:** add a YAML file to `.pentestcode/workflows/`.

## Notes & limits

- Multiple `Task` calls in one turn run **sequentially** (readable terminal
  output), but there is no low cap — a parent can fan out up to `max_subagents`.
- The sandbox mounts `./loot` → `/root/engagement` so scan output/loot persists.
- SYN scans etc. need raw sockets — the container is started with
  `NET_RAW`/`NET_ADMIN` (configurable in `config.py`).

## License

MIT — see [LICENSE](LICENSE).
