pt-workflow
SkillSecurityAutonomous pentest campaign driver. Runs a scoped engagement end to end with no operator approvals - the deterministic driver (scripts/campaign.py) owns pass state, generates the killchain board from recon, and prints the exact next action (Skill + tool) every turn. Use when starting or resuming a pentest, "run the pt workflow", "work this CIDR/domain", or when handed a client SoW/scope to reach a stated objective or domain admin. Single agent, refuter-verified, wiki-first, tool-first. Deliverable is a client report.
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the pt-workflow skill
What this skill tells your AI
The instructions your AI receives, as published by encod3d-sec/torch in skills/workflow/pt-workflow/SKILL.md and read by ahel’s review.
The driver is the plan. Run one command, do exactly what it prints, record the result, repeat. The
gates are enforced by scripts/campaign.py; follow its output literally.
The loop
python3 scripts/campaign.py next
python3 scripts/campaign.py note <row> --arsenal <slug>
python3 scripts/campaign.py done <row> --poc <img> --kind req # | --dead R | --park Q | --find F
Start / resume
python3 scripts/campaign.py init --type pt- validatesscope.md+ envelope, repairs type/schema. An emptyscope.mdmust be filled from the client SoW first (CIDRs, domains, RoE, lockout policy). The lockout policy and any destructive-op limits live inscope.md, not here.- Passes 1-3 feed
state.md- rustscan/nmap/nxc/LDAP/kerbrute/BloodHound per the recon defaults, which yield toscope.md's allowed tooling. Read service output end to end. python3 scripts/campaign.py board- writes the 4a rows (plus 4b lateral/privesc/DCSync for the pentest approach). Refuses on empty state.- Enter the loop, depth-first, one open row at a time.
- When a shell/session lands on a host (reverse shell via
vm-scan.sh --win shell, or meterpreter via--win msf), record it:python3 scripts/campaign.py foothold <host> --win shell(or ride it on the closing find withdone ... --win). The driver flips that host'sstate.mdrow toaccess=foothold, routes its 4b lateral/privesc rows throughvm-rsh --win <win>(persistent session + operator visibility), and printstmux attach -t <eng>for takeover.
Gates
Same as the shared driver: G1 arsenal-first, G2 skill-first, G3 typed evidence, G8 tool-first. AD
attacks route through Skill(hunt-ad); local privesc through Skill(hunt-windows) /
Skill(hunt-macos); the driver names which per row.
Autonomy
No approvals. Out-of-envelope work parks to decisions.md; the loop never blocks. A spray is gated by
the lockout policy in scope.md (the envelope), never attempted blind. Destructive AD operations
(Zerologon and similar) park unless the envelope authorises them.
Model routing
Explicit per-role model assignment (the driver enforces the verifier gate; the rest is operating policy):
- Main brain - Opus 5 1M: the
campaign.pyloop, board/state, strategy, Burp/chrome-devtools, finding write-ups. This session. - Verifier - Opus (fresh context), MANDATORY: before any CONFIRMED,
campaign.py verify <F>prints an Opus refuter prompt; dispatch ONE fresh Opus agent that reads the raw PoC, tries to REFUTE, and writesverdicts/<F>.json.done --findrefuses unless that verdict exists, isrefuted:false, and cites the finding's PoC (anti-rubber-stamp). Fails CLOSED. - RTL - Opus (fresh context):
Skill(redteamlead)for direction at a fork or when a vector stalls. - Short tasks - Haiku:
Skill(wiki-arsenal)deep,Skill(delegate)(mechanical exploit-run),Skill(ingest)recon-parse. Bounded, fully-specified, single-shot ONLY.
The line that keeps quota safety: Haiku is allowed for a bounded single job, never for open-ended parallel hunting.
Manual login / MFA the agent cannot do headlessly (Smart-ID, an SSO/MFA prompt, a CAPTCHA) -> Skill(chrome-devtools-browser): a VISIBLE chromium on the VM desktop (scripts/browser-visible.sh) the operator logs into, driven + observed live via the chrome-devtools MCP to capture the authenticated session + real API calls.
Discipline
- Do NOT invoke
superpowers:brainstorming/writing-plansmid-run; keep no parallel task list. - Model routing (see
## Model routing): Opus-1M drives; Haiku for bounded short tasks; the mandatory Opus verifier gates every finding viaverdicts/<F>.json. No open-ended hunter fan-out. - Load-bearing requests through Burp when reachable; degrade to
capture.sh reqotherwise. - Scope, lockout policy and destructive-op limits come from
scope.md. - RCE-first: when >1 vector is open, take the one that yields code-exec first - it is the attack vector that carries impact; chase lower-impact classes only after code-exec is ruled out or the objective needs them (the driver ranks code-exec rows first).
- Read whole, not grep: when a sudoer has no findable password and cron/writable/SUID/group
vectors dead-end, READ
/etc/pam.d/{sudo,su}+/etc/sudoers.d/*whole - apam_ssh_agent_auth(hijack a forwarded agent socket -> passwordless sudo),pam_exec, or bareNOPASSWDline IS the vector; read linpeas output WHOLE, a keyword grep skips the tell. See [[linux-privesc]]. - Long tools: run pspy/linpeas/tcpdump via
bash scripts/vm-bg.sh <eng> <win> '<tool>'(stages to/dev/shm, runs in the stabilized shell,--read/--wait 120the logfile); never hand-roll a backgrounded watcher, and never retry a broken tool pattern >2x - switch method or callSkill(redteamlead).
Close-out
Run the printed chain: Skill(triage) -> Skill(evidence) -> Skill(report) -> Skill(learn).
The pentest deliverable is a client report, not a CTF walkthrough. The report generator must run
with PATH=/opt/prep_report/.venv/bin:$PATH or every finding loses its severity callout box.
If the driver is unavailable
Manual fallback: read Approach.md, take the top open row for the current host, run its wiki lookup
then its hunt skill, capture req evidence, mark [x]; on exhaustion one Deadends.md line + [!].
Signals
- GitHub stars
- 322
- Forks
- 44
- Last commit
- Sep 2026
Advanced
- Catalog kind
- skill
- Gateway key
pt-workflow- Source
- github.com/encod3d-sec/torch