Metadata-Version: 2.4
Name: aegis-pentest
Version: 0.12.0
Summary: AEGIS — Adaptive Engagement & Generic Inspection Scanner
Author-email: Majd Bnat <hey@majdb.com>
License-File: LICENSE
Requires-Python: >=3.12
Requires-Dist: aiosqlite>=0.20
Requires-Dist: anthropic>=0.40
Requires-Dist: anyio>=4.0
Requires-Dist: dnspython>=2.6
Requires-Dist: fastmcp>=0.4
Requires-Dist: httpx>=0.27
Requires-Dist: jinja2>=3.1
Requires-Dist: packaging>=24.0
Requires-Dist: pydantic>=2.0
Requires-Dist: python-dateutil>=2.9
Requires-Dist: pyyaml>=6.0
Requires-Dist: rich>=13.0
Requires-Dist: sqlmodel>=0.0.21
Requires-Dist: structlog>=24.0
Requires-Dist: typer>=0.12
Description-Content-Type: text/markdown

# aegis · v0.11.0

**Adaptive Engagement & Generic Inspection Scanner**

An autonomous, AI-orchestrated web penetration testing agent. Aegis handles reconnaissance, fingerprinting, vulnerability discovery, verification, and reporting so the human pentester focuses on what actually requires human judgment.

---

## What it is

Aegis runs structured, methodology-driven engagements against web targets. It profiles the host environment, fingerprints the target stack, selects relevant tools and tests from the PTES + OWASP WSTG v4.2 playbook, executes them concurrently, and produces a verified findings report with remediation guidance.

It is not a Burp Suite replacement. It is the autonomous recon and vuln-discovery layer that feeds the human pentester, eliminating roughly 70% of routine busywork.

**Hard constraints built into the runtime:**

- Every engagement requires a signed `scope.yaml` before any network egress.
- Every outbound request is matched against in-scope and out-of-scope rules before the socket opens.
- Scope violations abort the current task and are written to the audit log.
- Destructive tools (`sqlmap`, `wpscan`, `commix`, `kerbrute`, `crackmapexec`, …) refuse to run without operator approval unless `scope.yaml` explicitly enables them.
- There is no `--force` flag that bypasses scope.

---

## Installation

### Option A — Docker (recommended, all tools pre-installed)

```bash
# Pull pre-built image (~4 GB) or build locally (~15-30 min)
aegis docker pull                          # from GitHub Container Registry
# OR
aegis docker build                         # build locally from Dockerfile

# Run an engagement
export ANTHROPIC_API_KEY=sk-ant-...
aegis docker run engagements/2026-acme

# Interactive shell with every tool on PATH
aegis docker shell

# Check image status and tool inventory
aegis docker status
```

The Docker image is based on **Kali rolling** and includes every tool in the catalog.

### Option B — PyPI

```bash
pip install aegis-pentest
# or
pipx install aegis-pentest
```

### Option C — Arch (AUR)

```bash
yay -S aegis-pentest
# or
paru -S aegis-pentest
```

Optdepends cover the full tool surface; install only what you need.

### Option D — Native install script (one-liner)

```bash
# Auto-detects Arch, Kali, Ubuntu/Debian, Fedora, macOS
curl -fsSL https://raw.githubusercontent.com/glorybnat/aegis-pentest/main/scripts/install.sh | bash

# Or from the repo
bash scripts/install.sh

# Build Docker image instead
bash scripts/install.sh --docker
```

### Option E — From source

```bash
git clone https://github.com/glorybnat/aegis-pentest.git
cd aegis-pentest
pip install -e .
cd tui && npm install && npm run build
```

After installing AEGIS, detect what's already on the host and fill in the rest:

```bash
aegis init                          # detect what's installed
aegis env tools --missing           # show what's missing + install commands
aegis env install --missing         # install everything (no-sudo tools)
aegis env install --missing --dry-run   # preview first
```

**Requirements:**

- Python 3.12+
- `ANTHROPIC_API_KEY` in environment
- Docker (Option A) or pentest toolchain (Option B–E)

---

## Quickstart

```bash
# Docker quickstart (zero host setup)
export ANTHROPIC_API_KEY=sk-ant-...
aegis docker build                          # or: aegis docker pull
aegis docker run engagements/2026-acme

# Native quickstart
# First run: profiles host, lists missing tools
aegis init

# Sync the knowledge base (NVD, GHSA, nuclei-templates, CISA KEV, FIRST EPSS)
aegis kb sync

# Create a new engagement
aegis engagement new --client "Acme Corp" --domain "acme.com"

# Fill in the authorization details
vim engagements/2026-05-acme/scope.yaml

# Optional: seed endpoints from an existing API spec or proxy trace
aegis ingest openapi engagements/2026-05-acme/spec.yaml --engagement engagements/2026-05-acme
aegis ingest postman engagements/2026-05-acme/collection.json --engagement engagements/2026-05-acme
aegis ingest har     engagements/2026-05-acme/burp.har       --engagement engagements/2026-05-acme

# Run
aegis run engagements/2026-05-acme

# Resume from the last completed phase after a crash or Ctrl+C
aegis run engagements/2026-05-acme   # picks up state.json automatically

# Generate report — md/html/json/sarif/h1/bugcrowd, or "all"
aegis report engagements/2026-05-acme --format html
aegis report engagements/2026-05-acme --format sarif    # GitHub/GitLab code scanning
aegis report engagements/2026-05-acme --format h1       # HackerOne JSON, one per finding
aegis report engagements/2026-05-acme --format bugcrowd # Bugcrowd VRT bundle
```

---

## scope.yaml

Aegis refuses to run without this file. No exceptions.

```yaml
engagement_id: "BL-2026-007"
client: "Acme Corp"
operator: "Majd Bnat <hey@majdb.com>"
authorization:
  document_ref: "SOW-2026-007.pdf"
  signed_date: "2026-05-12"
  expiry: "2026-06-12"
in_scope:
  domains:
    - "*.acme.com"
    - "api-staging.acme.io"
  ips:
    - "203.0.113.0/24"
out_of_scope:
  - "admin.acme.com"
  - "*.internal.acme.com"
rules_of_engagement:
  rate_limit_rps: 10
  business_hours_only: false
  destructive_tests: false
  no_credential_stuffing: true
  no_dos_tests: true
  confirm_before:                  # per-engagement gate for destructive tools
    - sqlmap
    - hydra
    - commix
```

---

## Architecture

```
                          aegis CLI
                              |
                      Engagement Manager
           (scope validation, lifecycle, audit log)
                              |
            +-----------------+-----------------+
            |                 |                 |
        Environment         Target          Methodology
         Profiler          Profiler           Engine
       (host info)      (fingerprint)      (PTES phases)
            |                 |                 |
            +--------+--------+--------+--------+
                              |
                       LLM Orchestrator
                   (Haiku / Sonnet / Opus)
                              |
         +----------+---------+----------+----------+
         |          |         |          |          |
        Tool    Knowledge  Findings    PTT       PoC
      Registry    Base       DB      Graph    Generator
     (173 tools) (NVD/GHSA  (SQLite) (aiosqlite) (14 types)
                +KEV/EPSS)
         |                              |
   Tool Executor               Hallucination Guard
  (async, sandboxed,          (output verification)
   destructive-gated)
         |
      Reporter
    (md/html/json/sarif/h1/bugcrowd)
```

The orchestrator runs a bounded loop per phase:

```
plan(phase_context) -> execute(action) -> observe(result) -> update(state)
  ^                                                               |
  +---------------------------------------------------------------+
                   until phase complete OR budget exceeded
```

Three independent budgets bound each phase: token budget, wall-clock time, and action count. Whichever trips first ends the phase and triggers finalize mode.

State is persisted to `<engagement_dir>/state.json` after every phase advance via atomic `tmp + os.replace`. Re-running `aegis run` against the same directory resumes at the last saved phase.

---

## Attack chain detection

Findings carry structured tags. The chain detector matches on tag sets, not title substrings. 22 chains ship out of the box — 7 legacy web chains, 10 modern web/API chains, and 5 Active Directory chains:

| Chain | Severity | Predicate (tag groups) |
|---|---|---|
| Account takeover via CORS + JWT | critical | `cors_wildcard` + jwt-family |
| Stored XSS + CSRF = session hijack | critical | `xss_stored` + `csrf` |
| SQL injection + weak crypto | critical | `sqli` + `weak_crypto` |
| SSRF + internal service exposure | high | `ssrf` + cloud/internal |
| SSRF + cloud metadata v1 | critical | `ssrf` + `cloud_metadata_v1` |
| Mass assignment + admin endpoint | critical | `mass_assignment` + `admin_endpoint` |
| Open bucket + reachable Lambda | high | `bucket_open` + `lambda_invoke` |
| Request smuggling → auth header bypass | critical | `request_smuggling` + `auth_header` |
| Cache poisoning → auth bypass | critical | `cache_poisoning` + `auth_cookie` |
| Prototype pollution → RCE sink | critical | `prototype_pollution` + `dangerous_sink` |
| JWT alg-confusion → privilege escalation | critical | `jwt_alg_confusion` + `privileged_endpoint` |
| Exposed `.git` → source code disclosure | high | `git_exposure` |
| Open registration + IDOR | high | `open_registration` + `idor` |
| Race condition → auth bypass | high | `race_condition` + auth |
| Kerberoasting → service account compromise | high | `ad_kerberoast` + `ad_spn` + weak/service |
| AS-REP roasting | high | `ad_no_preauth` + weak/user |
| DCSync → full domain compromise | critical | `ad_dcsync` + any AD creds |
| AdminSDHolder ACL backdoor | critical | `ad_adminsdholder` + any AD creds |
| Unconstrained delegation → ticket forge | critical | `ad_unconstrained` + any AD creds |

For engagements predating the tag rollout, a substring fallback still fires the legacy 7 rules against finding titles.

---

## Guided hunting

Chains are post-hoc detection — they fire when findings are already in the DB. Playbooks are the proactive counterpart: 24 entries in `src/aegis/analysis/vuln_playbooks.py` say "when you suspect X, run these probes; when you confirm X, hunt Y next".

| Field | Meaning |
|---|---|
| `vuln_class` | one of the `TAG_*` constants from `chains.py` |
| `severity_floor` | `critical` / `high` / `medium` / `low` / `info` |
| `preconditions` | state predicates (`has_params`, `has_login`, `has_jwt`, …) |
| `probes` | concrete `(tool_name, args_template, rationale)` tuples |
| `confirm_chain` | the `ChainRule.name` this playbook ultimately feeds, if any |
| `follow_ups` | other vuln classes to hunt next when this one fires |

Initial set (one playbook per chain tag):

`sqli`, `nosqli`, `cmdi`, `ssti`, `xxe`, `xss_stored`, `xss_reflected`, `ssrf`, `lfi`, `cloud_metadata_v1`, `bucket_open`, `request_smuggling`, `cache_poisoning`, `prototype_pollution`, `jwt_alg_confusion`, `jwt_weak_secret`, `csrf`, `idor`, `race_condition`, `mass_assignment`, `git_exposure`, `cors_wildcard`, `ad_kerberoast`, `ad_no_preauth`, `ad_dcsync`.

After every phase tick, `EngagementRunner._suggested_next` builds an escalation state from confirmed findings (tags + endpoints + tech stack) and runs `adaptive.escalate`. The top three actions are injected into the next observation summary as a `Suggested next probes` block; the model can act on them or ignore. Either way the recommendation is logged to `audit_event` with `event_type='escalation_suggested'` so `aegis stats` can answer "how often did the model take the suggestion?".

Tag inference (`src/aegis/analysis/tag_inference.py`) runs at the persistence boundary inside `FindingsDB.add_finding`. Findings get tags from a tool-base map (e.g. `impacket_get_userspns` → `[ad_kerberoast, ad_spn]`) plus a 31-rule substring matcher over the title + evidence text (distinguishing `jwt_alg_confusion` from `jwt_weak_secret`, `xss_stored` from `xss_reflected`, IMDSv1 in payloads tagging `cloud_metadata_v1`). Explicit tags from the caller are preserved.

---

## Token model

Aegis is designed to complete a full medium-scope engagement for under $2 in LLM tokens. This is achieved through several layered tactics:

| Tactic | Impact |
|---|---|
| Tiered model routing (Haiku handles ~70% of calls) | -60% cost |
| Prompt caching on system prompt + engagement context | -40% on input tokens |
| Parsed tool output, never raw stdout to the LLM | -80% on tool-heavy phases |
| Structured tool-use schema, no prose planning | -30% output tokens |
| Methodology-driven action space pruning | -50% wasted calls |
| SQLite-cached recon reused across phases | variable |
| Finding deduplication before LLM sees results | -10-30% |

Model tiers:

| Tier | Model | Used for |
|---|---|---|
| NANO | claude-haiku-4-5 | Parsing, classification, summarization |
| MAIN | claude-sonnet-4-6 | Planning, hypothesis generation, verification probes |
| DEEP | claude-opus-4-7 | Attack chain analysis, hard reasoning |
| LOCAL | ollama (optional) | Offline pre-classification |

The live cost meter runs in the terminal throughout each phase:

```
Phase: VULN_ANALYSIS  [>>>>>>>>--] 80%
Budget: $0.74 / $5.00   Tokens: 41.2k / 200k   Time: 12m / 60m
Tier breakdown: NANO 24% . MAIN 71% . DEEP 5%   Cache hit: 82%
```

---

## Tool catalog

Aegis exposes **173 MCP tools** wrapping **105 external binaries** plus orchestration primitives. Raw output is never passed to the LLM — each tool has a typed parser that produces structured `Finding` or `Observation` models. A nmap scan returning 47 open ports becomes 47 `OpenPort` observations of ~80 bytes each, not 200 KB of XML.

All tools degrade gracefully: if a binary is not installed, the tool returns a structured error with the exact install command.

| Category | Tools |
|---|---|
| **API ingest** | `aegis ingest openapi`, `aegis ingest postman`, `aegis ingest har` (writes Endpoint observations + paths.txt/params.txt wordlists) |
| **Subdomain enumeration** | subfinder, amass, assetfinder, findomain, dnsx, alterx, massdns, shuffledns, puredns, dnstwist, subdomain\_brute\_massive |
| **DNS recon** | dnsrecon, dnsx, massdns, fierce, crt.sh (cert transparency) |
| **OSINT / passive** | uncover (Shodan/Fofa/Censys/ZoomEye), shodan CLI, censys CLI, asnmap, passive\_intel, github\_discover, pwndb\_search, theharvester, spiderfoot, recon\_ng, google\_dorks |
| **Live host detection** | httpx, httpx\_batch, httprobe, naabu |
| **Port scanning** | nmap, naabu, masscan, rustscan |
| **Web crawling** | katana, gospider, hakrawler, getjs |
| **URL / archive recon** | gau, waybackurls, wayback\_recon, meg, unfurl, qsreplace |
| **Content discovery** | ffuf, feroxbuster, gobuster, dirsearch, wfuzz, content\_discovery, kiterunner |
| **Vhost fuzzing** | ffuf\_vhost |
| **Tech fingerprinting** | whatweb, httpx -tech-detect, cdncheck, tlsx |
| **WAF detection** | wafw00f, whatwaf |
| **TLS auditing** | sslscan, sslyze, tlsx |
| **Parameter discovery** | arjun, paramspider, gf (pattern filtering) |
| **XSS** | dalfox, kxss, crlfuzz, xsstrike, nuclei, aegis\_verify (xss probe) |
| **SQLi** | sqlmap*, nosqlmap*, nuclei, aegis\_verify (sqli / timing\_sqli probes) |
| **SSTI** | sstimap*, aegis\_verify (ssti probe) |
| **Command injection** | commix*, aegis\_verify (cmdi\_oob probe) |
| **HTTP smuggling** | smuggler* (CL/TE, TE/CL), h2csmuggler (HTTP/2 cleartext) |
| **CORS** | corsy |
| **SSRF / OOB** | oob\_init + oob\_poll (interactsh), aegis\_verify (ssrf\_oob / xxe probes) |
| **Race conditions** | race\_condition\_scan, aegis\_verify (race probe) |
| **OAuth** | oauth\_audit (open redirect, state bypass, PKCE) |
| **JWT attacks** | jwt\_audit (alg:none, RS256→HS256, weak secret) |
| **GraphQL** | graphql\_audit (schema walk, batch DoS, deep nesting, per-query auth probe, rate-limit burst), graphql\_cop |
| **WebSocket** | websocket\_test (injection, origin validation, auth) |
| **API discovery** | api\_discover, kiterunner, openapi\_audit |
| **IDOR** | idor\_check (cross-user object access) |
| **JS analysis** | js\_recon, linkfinder, secretfinder |
| **Header injection** | header\_injection\_scan (Host header, cache poisoning) |
| **403 bypass** | bypass\_403 (path tricks + header overrides) |
| **Prototype pollution** | aegis\_verify (prototype\_pollution probe) |
| **Secrets / SAST** | trufflehog, semgrep, bandit, safety, npm\_audit, retire\_js, secret\_scan |
| **Vulnerability scanning** | nuclei, nuclei\_fuzz, nuclei\_ai\_generate, wapiti, nikto |
| **CMS scanning** | wpscan*, cmseek, joomscan, droopescan |
| **Network / SMB** | enum4linux, smbmap, snmpcheck |
| **Active Directory** | impacket (`GetUserSPNs.py`, `GetNPUsers.py`, secretsdump.py), kerbrute*, bloodhound-python, ldapdomaindump, crackmapexec*, certipy |
| **Cloud config audit** | scoutsuite (AWS/Azure/GCP/Aliyun/OCI), cloudsplaining, pmapper, iamspy, azurehound, roadtools, gcp-iam-collector, gcp-scanner |
| **Cloud storage** | cloud\_enum, s3scanner, bucket\_finder, gitdumper, cloudfox |
| **Kubernetes** | kube\_bench, kube\_hunter, kdigger, kubectl-who-can |
| **Container / SBOM** | trivy, grype, syft |
| **Auth / brute force** | hydra* |
| **Subdomain takeover** | subjack, subzy, subdomain\_takeover\_scan |
| **Recon orchestration** | bbot (multi-module OSINT), interlace (parallel execution) |
| **Reporting** | aegis\_report (md / html / json / sarif / h1 / bugcrowd) |
| **Methodology** | wstg\_check (OWASP WSTG v4.2, 80+ checks) |
| **Attack graph (PTT)** | ptt\_add\_node, ptt\_update\_node, ptt\_get\_graph, ptt\_next\_targets, ptt\_spawn\_tasks, ptt\_summary |
| **Orchestration** | aegis\_hotlist (asset risk scoring), aegis\_compress\_context (context compression), aegis\_engagement\_status |
| **PoC generation** | generate\_poc (14 vuln classes: XSS, SQLi, SSRF, LFI, RCE, IDOR, open redirect, JWT, CORS, CSRF, HTTP smuggling, SSTI, XXE, prototype pollution) |
| **Output verification** | verify\_tool\_output (hallucination guard — validates tool output before Claude acts on it) |
| **Modern JS surface** | nextjs\_data\_probe, astro\_endpoint\_probe, source\_map\_extract, spa\_route\_discover |
| **Synthesised nuclei templates** | nuclei\_synth\_from\_probe, nuclei\_synth\_list |
| **Mobile + API extras** | mobsf\_static\_scan, dredd\_run, postman\_runner |
| **Tool documentation** | aegis\_tool\_help, aegis\_tool\_list\_help |

`*` marks tools that require operator approval before each run (destructive-gated).

---

## Tool playbooks

165 per-tool markdown playbooks ship inside the wheel under `aegis/_docs/tools/`. The agent fetches them on demand instead of carrying full flag references in the system prompt every turn.

| MCP tool | Returns |
|---|---|
| `aegis_tool_help(name)` | full markdown body — Purpose, Args, Common flags, Pitfalls, When to use, Example — plus typo `suggestions` when the name doesn't match |
| `aegis_tool_list_help(category)` | one-line index across all docs; filter by category (`network`, `vuln`, `ad`, `cloud`, `k8s`, …) |

Every doc follows a fixed schema so the model can rely on the section ordering:

```markdown
# tool_name
**Purpose:** one-sentence summary.

## Args
- arg (type): meaning

## Common flags worth knowing
- -X  short note

## Pitfalls
- short bullet

## When to use
- which phase, what precondition triggers it

## Example
`tool_name(target="…", flags="…")`
```

The 11 hot-path tools have hand-curated playbooks; the rest are scaffolded by `scripts/gen_tool_docs.py` from the existing docstring + `ToolSpec.install` hint. Override or hand-edit anything under `docs/tools/<category>/<name>.md` — the on-disk source layout wins over the packaged copy during editable installs.

---

## Verification probes

43 in-process probes (`aegis.verify.probes`) confirm findings without re-invoking external binaries. Each probe targets a specific class and emits a structured `ProbeResult`. Probes are HTTP-only by default and rate-limited per scope.

```
blind_cmdi, blind_cmdi_oob, blind_sqli, cache, cache_poisoning,
cmdi_oob, cors, cors_misconfig, csrf, csrf_missing, exposure,
file_exposure, headers, http_smuggling, jwt, jwt_alg_confusion,
lfi, misconfig, oauth, oauth_redirect, open_redirect, pp,
prototype_pollution, race, race_condition, redirect,
request_smuggling, smuggling, sqli, sqli_error, ssrf, ssrf_oob,
ssti, subdomain_takeover, takeover, template_injection,
timing_cmdi, timing_sqli, toctou, xml_injection, xss,
xss_reflected, xxe
```

---

## Reports and webhooks

Six output formats, all driven from the same `Reporter` context:

| Format | Use |
|---|---|
| `md` / `html` | human consumption |
| `json` | machine consumption with stable schema |
| `sarif` | GitHub Code Scanning, GitLab Security, Azure DevOps |
| `h1` | HackerOne submission — one JSON per finding under `reports/h1/` |
| `bugcrowd` | Bugcrowd VRT-mapped JSON bundle |

PII redaction is opt-in via `[reporting] redact_pii = true`. Sweeps emails, JWTs, AWS keys, GitHub PATs, Slack tokens, US SSNs, credit-card-shaped numbers, and phone numbers. IP redaction is a separate switch. Audit log records counts only — never content. Scope metadata (`engagement_id`, `client`) is intentionally preserved.

Live findings webhook via `aegis watch`:

```bash
aegis watch engagements/2026-acme \
    --webhook https://hooks.slack.com/services/... \
    --webhook-format slack \
    --webhook-min-severity high
```

Supported platforms: `slack` (Block Kit), `discord` (severity-coloured embeds), `linear` (issue title/description/priority), `json` (stable schema for n8n / Zapier).

---

## Environment profiling

On first run, `aegis init` profiles the host and derives auto-tuned concurrency settings:

```
Host: arch-workstation
  OS        Arch Linux (rolling, kernel 6.9.3-arch1-1)
  CPU       AMD Ryzen 7 5800X . 8 cores / 16 threads . 4.7 GHz
  Memory    32 GB total . 24 GB available
  Repos     core, extra, multilib, blackarch

Pentest toolchain: 28/35 detected
  nmap 7.95       nuclei 3.2.9      httpx 1.6.6
  ffuf 2.1.0      subfinder 2.6.6   katana 1.1.0
  sqlmap 1.8.5    wpscan 3.8.27     nikto 2.5.0
  gobuster 3.6.0  amass 4.2.0       gowitness 3.0.3

Missing: testssl.sh  feroxbuster  dnsrecon  arjun  paramspider  trufflehog
  -> Run: aegis env install --missing

Auto-tuned concurrency:
  nmap_parallelism=16   nuclei_concurrency=32   ffuf_threads=64
  httpx_concurrency=80  max_parallel_tools=4
```

---

## CLI reference

```
aegis init                                    First-run setup and env profile
aegis env show                                Display host profile
aegis env tools                               Tool inventory
aegis env install --missing                   Generate install commands for missing tools
aegis env refresh                             Re-detect host profile

aegis kb sync [--source nvd|ghsa|nuclei|kev|epss]   Sync knowledge base
aegis kb stats                                Knowledge base summary
aegis kb query --product nginx --min-cvss 7   Query CVEs

aegis engagement new --client X --domain Y    Scaffold engagement dir and scope.yaml
aegis engagement list                         List engagements

aegis ingest openapi <spec>  --engagement <dir>     Seed endpoints from OpenAPI / Swagger
aegis ingest postman <coll>  --engagement <dir>     Seed endpoints from Postman v2.x
aegis ingest har     <trace> --engagement <dir> [--replay]   Seed endpoints from a browser HAR; --replay re-issues each request and diffs the response

aegis run <dir> [--phase PHASE]               Run engagement (resumes from state.json)
aegis run <dir> --dry-run                     Preview planned actions
aegis run <dir> --budget-usd 2.00             Cap spend

aegis watch <dir> --webhook <url>             Live findings webhook
                  --webhook-format slack|discord|linear|json
                  --webhook-min-severity critical|high|medium|low|info

aegis report <dir> [--format md|html|json|sarif|h1|bugcrowd|all]   Generate report
aegis findings list <dir> [--severity high]   List findings
aegis findings suppress <finding-id> --reason "..."

aegis cost <dir>                              Detailed cost breakdown
aegis audit <dir>                             Full audit log
aegis stats [<root>] [--json]                 Cross-engagement metrics
aegis shells                                  Tool execution history (last scan)
aegis shells --all [--tool X] [--engagement Y]   Cross-engagement shell history (SQLite)

aegis docker build|run|shell|pull|status      Docker sub-app
```

All commands support `--json` for scripting, `-v/-vv/-vvv` for verbosity, `--quiet` for CI.

---

## Configuration

Global config lives at `~/.config/aegis/config.toml`. Any key can be overridden per engagement in `engagement_dir/config.toml`.

```toml
[api]
anthropic_api_key_env = "ANTHROPIC_API_KEY"

[models]
nano  = "claude-haiku-4-5-20251001"
main  = "claude-sonnet-4-6"
deep  = "claude-opus-4-7"

[models.local]
enabled  = false
endpoint = "http://localhost:11434"
model    = "qwen2.5:7b"

[budgets]
tokens_per_phase       = 30000
tokens_per_engagement  = 200000
usd_per_engagement     = 5.00
wall_time_per_phase_sec = 1800

[caching]
prompt_cache          = true
kb_cache_dir          = "~/.cache/aegis/kb"
fingerprint_cache_ttl_hours = 168

[tooling]
docker_isolate         = false
default_rate_limit_rps = 10
respect_robots_txt     = false

[reporting]
default_format    = "html"
include_audit_log = true
redact_pii        = false
redact_ips        = false
```

---

## Tech stack

| Layer | Choice |
|---|---|
| Language | Python 3.12+ |
| CLI | Typer + Rich |
| TUI | React + Ink (TypeScript) |
| Async | asyncio + anyio |
| HTTP | httpx (async, HTTP/2) |
| Models | Pydantic v2 |
| Storage | SQLite + SQLModel + Alembic |
| MCP | FastMCP |
| LLM | Anthropic SDK (Claude) |
| Templating | Jinja2 |
| Logging | structlog + rich |
| Packaging | uv (dev), hatch (build) |
| Testing | pytest + pytest-asyncio + respx (387 tests) |

---

## License

MIT. Use responsibly and only against systems you are authorized to test.

---

Built by [Majd Bnat](https://majdb.com)
