// NO HAT HACKER
Documentation Portal
Licensed users only · 3-factor auth required

First login — set up Google Authenticator:

QR Code

Scan the QR, then enter the 6-digit code to confirm.

// NO HAT HACKER — Docs
Documentation Portal
// No Hat Hacker · Adamantware OU

Welcome. This portal contains technical documentation for all No Hat Hacker tools. Access is controlled by your license entitlement — sections unlock automatically when you purchase or register for a product.

Your access is shown in the sidebar. Locked sections require a license or demo registration for that specific tool.
The Sidekick Series

All Sidekick tools share a common design pattern:

PropertyValue
PlatformDebian / Kali Linux · x86-64
DistributionSingle static binary — no installer, no dependencies
InterfacesGUI (egui desktop app) + headless CLI
AuthEmail OTP → TOTP (Google Authenticator) → 30-min session
LicenseOnline validation · machine-fingerprint locked
License serverlicense.nohathacker.com
Quick Start (any Sidekick tool)
# Download from your portal, then: chmod +x eps-gui && ./eps-gui # GUI eps login # CLI: authenticate (30-min session) eps --help # CLI: see all commands
Account & Login
// authentication · session management

All No Hat Hacker tools use a unified 3-factor authentication flow. No passwords — ever.

Login Flow
Step 1 — enter your email address → server sends an 8-character code to your email (valid 10 min) Step 2 — enter the 8-char email code → server confirms your identity Step 3 — enter your Google Authenticator TOTP code → server returns a session token + db decryption key → session valid for 30 minutes
First Login — TOTP Enrollment

On your very first login, after the email code step you will be shown a QR code to scan with Google Authenticator. Scan it once and confirm with the first 6-digit code. From that point on, step 3 is just entering the rotating code from the app.

Google Authenticator, Authy, or any TOTP-compatible app works. The issuer is NoHatHacker.
CLI Login
eps login // No Hat Hacker — Login ───────────────────────────────────────────── Email address: you@example.com Sending code to you@example.com... done. Enter the 8-character code from your email: ABCD1234 Google Authenticator code: 482917 ───────────────────────────────────────────── [✓] Logged in as you@example.com [✓] License: COMMERCIAL [✓] Session valid for 30 minutes
Session Management
eps status # show session info + time remaining eps logout # clear session immediately eps login # re-authenticate (required after 30 min)

Session data is stored locally at ~/.config/eps/session.json. It contains your session token and the database decryption key. The file is set to 0600 permissions automatically.

Account Portal

Manage your license, download binaries, and view invoices at nohathacker.com/portal. Same 3FA login applies.

Email Pentest Sidekick
// EPS · v1.0.0 · Debian/Kali · x86-64

The most complete email security assessment framework in existence. This documentation covers installation, the 3FA login flow, each GUI module, and the full CLI reference.

Installation
# Download from your portal tar xzf eps-1.0.0-linux-x86_64.tar.gz cd eps-1.0.0-linux-x86_64/ chmod +x eps eps-gui # Optionally install system-wide sudo cp eps eps-gui /usr/local/bin/
EPS is a single statically-linked binary. No Python, no Docker, no system dependencies. Runs on any Debian/Kali x86-64 system from Debian 11+.
First Run
./eps login # authenticate first (CLI) ./eps-gui # launch GUI (login screen appears on startup)
GUI — Module Reference
⚡ Server

Built-in SMTP capture server. Bind to any host/port and receive test emails for callback and bounce analysis. No Postfix required.

# Equivalent CLI eps server --host 0.0.0.0 --port 2525 # Test it: telnet localhost 2525
📧 Send

Send individual test emails using built-in phishing scenarios or fully custom parameters. Supports DKIM signing, relay configuration, and evasion headers.

🎯 Campaign

Multi-target email delivery with per-target delay, relay rotation, and live log output. Loads target lists from the text area (one address per line).

⚠ Campaign mode is disabled in demo licenses.
🔍 Relay Hunter

CIDR-range SMTP scanner. Discovers open relays across IP ranges. Feeds discovered relays into the relay database for use in Send/Campaign.

# API keys accelerate discovery (optional) # FOFA, ZoomEye, Censys, Shodan — configure in Settings # CIDR scan works with zero API keys at concurrency 500
🗝 Creds

Live credential vault. Stores SMTP credentials found via spray or manual entry. Status tracked per credential (Live / Dead / Untested). Feeds directly into campaign relay rotation.

🌐 SPF Walk

Recursively resolves the full SPF authorisation tree for any domain. Every include:, redirect=, and nested mechanism exposed. Identifies which ESPs are authorised to send on behalf of the target.

🎭 Permutations

Domain permutation generator with live DNS validation. Surfaces all registered lookalike domains. Results are checked for MX records and classified by risk.

🧅 Dark Web

Tor-routed credential search across dark web paste sites and leak indexes. HIBP stealer log enrichment. Discovered credentials are automatically tested live against the target mail server.

Requires Tor to be running locally: sudo systemctl start tor
🔬 Headers

Email header forensic analyser. Paste raw email headers to extract routing path, authentication results (SPF/DKIM/DMARC), delivery timestamps, and MUA/MTA fingerprints.

💥 Spray

SMTP AUTH password spray. Single or multi-target. Bundled Ignis wordlists (10K, 100K, 1M). STARTTLS, configurable delay, stop-on-hit. Hits are saved to the credential vault automatically.

# CLI equivalent eps spray --host mail.target.com --port 587 \ --wordlist ignis-1M --targets users.txt
📊 Report

Professional HTML/PDF assessment report. Covers DMARC posture, credential hits, relay exposure, dark web leaks, and delivery results. Open in browser or save to file.

⚠ Report generation is disabled in demo licenses.
CLI Reference
CommandDescription
eps login3FA authentication (email OTP → TOTP) — required before any other command
eps statusShow current session: email, license type, minutes remaining
eps logoutClear session immediately
eps listList all built-in phishing scenarios
eps test <id> <target>Run a scenario against a target address
eps customSend a fully custom email (all fields via flags)
eps spraySMTP password spray
eps serverStart SMTP capture server
eps logsShow recent test log entries
eps reportGenerate HTML assessment report
🔬
DFIR Pentester Sidekick
Documentation for this tool is locked. Register for early access or purchase a license to unlock.
View on Arsenal →
🗝
CredDump Pentester Sidekick
Documentation for this tool is locked. Register for early access or purchase a license to unlock.
View on Arsenal →
InfraScan Pentester Sidekick
// IPS · v1.0.0 · Debian/Kali · x86-64

Network infrastructure pentesting with built-in intelligence. This documentation covers installation, the login flow, each GUI tab, the attack template library, gateway discovery, and the CLI reference.

Installation
# Download from your portal tar xzf ips-1.0.0-linux-x86_64.tar.gz cd ips-1.0.0-linux-x86_64/ chmod +x ips ips-gui # Optionally install system-wide sudo cp ips ips-gui /usr/local/bin/
IPS is a single statically-linked binary. No Python, no Docker, no system dependencies. Requires root (or sudo) for raw socket operations: nmap -sS, tshark, ARP scan, sub-interface creation for VLAN hopping.
First Run
sudo ./ips-gui # launch GUI (login screen on startup) ./ips scan --help # CLI reference
GUI — Tab Reference
📖 Scope

Set the target host/CIDR, port range, and output directory before running any attacks. These values are substituted into all templates via {host}, {port}, {outdir}, and {iface} placeholders.

⚡ Attack

50+ one-click attack templates organised by category. Select a template, review the command, and click Run. Output streams live. Findings are automatically extracted and added to the Results tab.

Template categories: Reconnaissance, Service Enumeration, Vulnerability Assessment, Exploitation, VLAN Discovery, Gateway Recon, Post-Exploitation, Lateral Movement, Exfiltration.

# Key templates Nmap Host Discovery T1046 — ping sweep, ARP probe ARP Sweep (arp-scan) T1018 — L2 discovery, bypasses ICMP block VLAN Tag Sniff T1040 — passive 802.1Q capture via tshark VLAN Hop via Sub-interface T1599 — auto tshark + sub-interface creation Gateway & Routing Map T1016 — ip route, ip neigh, traceroute Traceroute Multi-Path T1016 — trace to 3 destinations, asymmetry check Rogue Gateway Hunt T1016 — arp-n + nmap /24 management port scan Routing Protocol Detector T1040 — OSPF/EIGRP/RIP/BGP/HSRP tshark capture Static Route Audit T1016 — ip route show, ip rule, netstat -rn Gateway Device Fingerprint T1046 — nmap -sV -sC + curl banner for given host
📋 Results

All findings in a sortable, filterable table. Each finding has: severity (Critical/High/Medium/Low/Info), MITRE ATT&CK technique ID, title, target, timestamp, raw evidence block. Click any finding to expand the full evidence. Use the filter controls to drill into a specific severity or technique.

🗺 Topology

Live network topology map. Hosts auto-populate from scan output — even after clearing the output log. Positions are auto-arranged by subnet, then saved between sessions.

Controls:

  • Scroll wheel — zoom in/out toward cursor (0.15× to 4×)
  • Middle-drag or right-drag — pan the canvas
  • Left-drag on a node — reposition it (saved to disk)
  • Reset Layout — re-run auto-layout for all nodes
  • Clear All Hosts — wipe topology (does not affect findings)

Gateway diamonds: Blue diamond = confirmed default gateway from ip route. Red diamond = rogue/unexpected routing device. Amber diamond = alt gateway found during discovery.

🔍 Beyond-Gateway Probe

Incrementally probes private /24 ranges looking for networks reachable through detected gateways. Configure up to three seed networks (e.g. 10.0.0.0/24, 172.16.0.0/24, 192.168.0.0/24). The probe expands each seed across all 256 third-octets and ping-sweeps each /24 with configurable thread count (1–8, default 4).

# Safe thread settings Threads: 4 — default, balanced speed vs NIC load Threads: 8 — maximum, fast but higher resource use Aggression: -T3 (nmap) — hard-coded for safety (no -T5)
The Stop button kills all running nmap child processes individually (no process group kill). It is safe to stop at any time.
🔍 Gateway Intelligence (inside Beyond-Gateway Probe)

Click Discover Gateways to run the full rogue gateway detection chain:

  1. Routing table — reads ip route show, identifies default GW and suspicious non-default via entries
  2. Multi-path traceroute — traces to 8.8.8.8, 1.1.1.1, 9.9.9.9. Multiple hop-1 IPs = asymmetric routing alert
  3. Active /24 sweep — nmap ping-sweep of the local subnet derived from the default GW (catches rogue devices not in ARP cache)
  4. ARP cache merge — combines with arp -n / ip neigh show
  5. Fingerprint — nmap -sV -p 22,80,443,8080,8443,8291,8728,179 + curl banner grab per candidate. 30+ vendor signatures matched

Vendor coverage: pfSense, OPNsense, FortiGate, Palo Alto, F5 BIG-IP, Check Point, SonicWall, Juniper, MikroTik, Cisco, ClearOS, VyOS, Ubiquiti (UniFi / EdgeOS / AirOS), OpenWrt, DD-WRT, OpenMediaVault, Linksys, Zyxel, Netgear, SMC Networks, Huawei, D-Link, TP-Link, Alcatel-Lucent.

🌐 Intelligence

OSINT IP discovery using Shodan, Censys, FOFA, and ZoomEye. Requires API keys configured in the Vault tab. Results auto-populate the topology map.

🔑 Vault

Secure local storage for API keys (Shodan, Censys, FOFA, ZoomEye) and captured credentials. Keys are stored encrypted at ~/.config/ips/vault.json.

📄 Report

Generate a professional HTML report containing: engagement metadata, executive summary, severity scorecard, notes, the topology SVG as it is arranged on screen, per-finding index table, and full evidence blocks. Click Generate HTML Report — the file opens automatically in your browser.

The topology SVG is embedded at export time from the current node positions. Rearrange nodes to taste before generating the report.
CLI Reference
# Scan a target sudo ips scan --target 10.0.110.0/24 --template "Nmap Host Discovery" # Run the VLAN hop template sudo ips scan --template "VLAN Hop via Sub-interface" --iface eth0 # Beyond-gateway probe sudo ips bgp --net1 10.0.0.0/24 --net2 172.16.0.0/24 --threads 4 # Generate report from saved session ips report --session ~/.config/ips/sessions/latest --output report.html
Config & Data Paths
~/.config/ips/ — config root ~/.config/ips/vault.json — encrypted API keys + credentials ~/.config/ips/topology.json — saved node positions ~/.config/ips/scans/ — scan output files (auto-parsed by topology) ~/.config/ips/sessions/ — session history ~/.config/ips/reports/ — generated HTML reports
Troubleshooting
Permission denied on scan commands

Raw socket operations require root. Run sudo ips-gui or add the binary to sudoers for the specific capabilities you need.

tshark not found
sudo apt install tshark # When prompted, allow non-root users to capture (optional)
No hosts in topology after scan

IPS parses IPs from scan output files in ~/.config/ips/scans/ and from live output. If you cleared the output log, hosts already discovered are preserved in the persistent topology set. If no hosts appear, verify the template used {outdir} and that the scan completed successfully.

Stop button kills the GUI

This was fixed in v1.0.0. The stop logic now kills individual child PIDs only — never the process group. Update to v1.0.0 if you experienced this.

Coding Sidekick
// CSK · v1.0 · Linux / macOS / Windows · x86-64 / ARM64

An AI coding agent that fronts any model — Claude, GPT-4o, Gemini, or a local Ollama instance — with a rich terminal UI, 300+ built-in tools, team orchestration, and a built-in permission layer you can fully control. One binary, zero containers, no Node runtime.

Seamless Mesh. Every CS node in your WireGuard mesh automatically shares its AI resources (Ollama models, API-keyed providers) with every other node. A team member without an Anthropic key can route through a peer that has one. A machine with a GPU running local models shares them transparently. No configuration beyond a shared almanac.toml.

Built-in Project Management. CS enforces structured PM practices on every project — automatically. Missing SCOPE.md, WBS.md, TASKS.md, CHANGE_REQUESTS.md, or SCOPE_CREEP.md files are created at startup. The LOCKED pipeline ensures scope changes never silently overwrite committed work. Human workers and AI workers share the same plain-text files committed to git.
Installation
# Download from your portal tar xzf csk-1.0-linux-x86_64.tar.gz chmod +x cs sudo cp cs /usr/local/bin/ # Verify cs --version
CSK is a single statically-linked Rust binary. No Python, no npm, no Docker. The only runtime dependency is an API key for your chosen provider (or a local Ollama install for fully offline operation).
Quick Start
# Set your key once export ANTHROPIC_API_KEY=sk-ant-... # Start the TUI (recommended) cs --tui # Or use the plain REPL cs chat # Switch provider on the fly cs --provider openai --model gpt-4o --tui cs --provider ollama --model llama3.2 --tui # fully local, no key needed
Configuration

CSK reads config from two locations — global defaults first, then project-local overrides:

~/.config/coding-sidekick/config.toml # global ./coding-sidekick.toml # project-local (takes precedence)

Minimal config to set your default provider:

default_provider = "anthropic" [providers.anthropic] api_key_env = "ANTHROPIC_API_KEY" model = "claude-sonnet-4-6"
API keys are never written to the config file — only the name of the environment variable that holds the key. This makes config files safe to commit.
Providers

All providers are configured under [providers.<id>] blocks:

[providers.anthropic] api_key_env = "ANTHROPIC_API_KEY" model = "claude-sonnet-4-6" # or claude-opus-4-8, claude-haiku-4-5 [providers.openai] api_key_env = "OPENAI_API_KEY" model = "gpt-4o" # base_url = "https://openrouter.ai/api" # OpenAI-compatible proxy [providers.gemini] api_key_env = "GEMINI_API_KEY" model = "gemini-2.0-flash" [providers.ollama] model = "llama3.2" # base_url = "http://localhost:11434" # default; change for remote box
CLI Reference
# Core flags (all global — work with any subcommand) cs --tui # launch ratatui TUI cs --provider <id> # override provider cs --model <name> # override model cs --worker <id> # address a specific team worker cs --yes # auto-approve all tool confirmations (SirYesSir on) cs --plan # read-only mode — agent sketches plan, no writes cs --smart # parse aider-style edit blocks instead of tool calls cs --compact-tools # ship only ~25 core tools; rest available on demand # Subcommands cs chat # interactive stdin REPL (with full tool use) cs chat --tui # same, but with the TUI (task bar, queue, history) cs exec "do this task" # one-shot non-interactive — auto-yes, output to stdout cs trajectory export --format openai # export session for fine-tuning
Non-interactive Execution — cs exec

cs exec runs a single task with full tool use, all confirmations auto-approved, and the result streamed to stdout. It is designed to be called from scripts, pipelines, or other applications (such as HawkEye) that need AI reasoning without any human interaction.

Syntax
cs exec "<prompt>" [--var KEY=VALUE ...] [--model <model>] [--max-spend <usd>]
Variable substitution

Use {key} placeholders in the prompt and supply values with --var key=value. This lets callers build a prompt template once and inject runtime values (paths, credentials, scan targets) without string-concatenation hacks.

# Analyse a specific repository cs exec "Analyse the repository at {repo} for SQL injection vulnerabilities. \ Output a structured JSON report with file, line, severity, and remediation." \ --var repo=/home/user/myproject # Pass credentials for an authenticated scan cs exec "Log into {url} as {user} with password {pass}. \ Check for broken access control on the /admin routes." \ --var url=https://staging.example.com \ --var user=testadmin \ --var pass=s3cr3t # Read a long prompt from a file cat tasks/TASK-042.md | cs exec - # Capture the output for further processing RESULT=$(cs exec "Summarise the diff: $(git diff HEAD~1)" --model claude-haiku-4-5-20251001) echo "$RESULT" | jq .
Calling from another application
# Bash — capture response in a variable output=$(cs exec "Review {file} and list all TODO comments as JSON" \ --var file=src/auth.rs) echo "$output" # Python import subprocess, json result = subprocess.run( ["cs", "exec", "Analyse {repo} and return a JSON list of security issues", "--var", f"repo={repo_path}"], capture_output=True, text=True, check=True ) issues = json.loads(result.stdout) # Exit code: 0 = success, non-zero = error (license / provider / fatal tool failure) # Tool invocations are logged to stderr so stdout is clean for the caller
Key flags
--var KEY=VALUE substitute {KEY} in the prompt (repeatable) --model <name> override the model for this task only --max-spend <usd> hard cost cap; agent exits before exceeding it --smart smart (edit-block) mode for models without tool support --record record the trajectory for fine-tuning export - pass as the prompt argument to read from stdin
Security note: cs exec always runs with SirYesSir (auto-yes). The agent can read, write, and execute anything in the working directory. Run it in a container or with a restricted user account when the prompt or target is untrusted.
TUI — Terminal Interface

Launch with cs --tui. Three-pane layout: conversation (scrollable), input box, status bar.

Keyboard Shortcuts
  • Enter — send message (or queue it while agent is thinking)
  • ↑ / ↓ — cycle through sent-prompt history · navigate ask_user option list
  • Esc — clear input (or return to draft when browsing history)
  • PgUp / PgDn — scroll conversation
  • Ctrl+C — copy input field to clipboard
  • Ctrl+X — cut input field to clipboard
  • Ctrl+V — paste from clipboard into input
  • Ctrl+Y — yank last agent response to clipboard
  • Ctrl+Z — cancel the running task (aborts the agent turn; does not quit)
  • Ctrl+D — quit
  • y / n — answer a tool confirmation modal
  • Enter / 1–9 — confirm selected option in ask_user modal
  • Shift+drag — native terminal text selection (bypasses TUI mouse capture)
  • Click [×] — cancel a specific running task from the task bar
Slash Commands
/sir # toggle SirYesSir — auto-approves all tool confirmations /clear # clear conversation and message history /image <path> # attach an image to the next message (vision models) /help # show quick reference /quit # exit
Status Bar

The bottom line shows: provider chip · model chip · mode label · thinking indicator (●). When SirYesSir is active a bright green SIR YES SIR badge appears on the right so you always know the permission mode at a glance.

SirYesSir — Permission Toggle

By default CSK shows a confirmation modal any time a tool wants to write a file, run a bash command, or take any side-effecting action. SirYesSir bypasses this gate entirely — all confirmations are auto-approved instantly.

# TUI: toggle at any time during a session /sir # CLI: arm it from the start cs --yes --tui cs --dangerously-skip-permissions --tui # alias
When to use it: batch builds, long autonomous runs, scripted deployments. When to leave it off: any session where you want a human in the loop before the agent touches production files or runs network commands.
Team Mode — Multi-Worker Orchestration

Define named workers in opencode.toml, each with a pinned model, provider, skill set, and cost tier. The TUI queue is skill-aware: messages that match a free worker's skills are dispatched immediately in parallel, without blocking the main conversation thread.

Config example
# opencode.toml — multi-model, multi-skill setup default_provider = "anthropic" # Primary provider — handles the main conversation thread [providers.anthropic] model = "claude-haiku-4-5-20251001" # Worker 1 — heavy reasoning via a powerful remote model [[workers]] id = "architect" provider = "anthropic" model = "claude-opus-4-8" skills = ["architecture", "design", "review", "security audit", "hard bug"] cost_tier = 3 # 0=free/local 1=cheap 2=mid 3=premium # Worker 2 — fast local model, zero cost, no rate limits [[workers]] id = "local" provider = "ollama" model = "qwen2.5-coder:32b" base_url = "http://localhost:11434" skills = ["build", "lint", "format", "refactor", "explain", "summarize"] cost_tier = 0 # Worker 3 — web-grounded search via a search-native provider [[workers]] id = "searcher" provider = "perplexity" model = "sonar-pro" skills = ["search", "web", "lookup", "research", "find info", "latest"] cost_tier = 2
How the queue routes messages

When you type while the main agent is thinking, the queue checks your message against every free worker's skills list (case-insensitive substring match). If a match is found, the message is dispatched immediately to that worker — in parallel with the ongoing main turn. The queue pane shows all active lanes:

┌─ queue ──────────────────────────────────────────────────┐ Refactor the auth module to use the new session type ← main agent ▶ [architect] Review the API surface for security issues ← parallel worker ▶ [searcher] Latest CVEs for express.js 4.x ← parallel worker ⌛ Run the test suite and summarise failures ← queued (main) └──────────────────────────────────────────────────────────┘

Worker output appears in the conversation labeled [worker-id]: in cyan, separate from the main agent: thread. When a worker finishes, the next queued message matching that worker's skills is automatically dispatched — no manual routing required.

If no worker matches (or all matching workers are busy), the message stays in the queue and is submitted to the main provider when it finishes its current turn. Lower cost_tier workers are preferred when multiple workers match the same message.

CLI — address a worker directly
# Pin a session to one specific worker cs chat --worker architect --tui # Or just run normally — the queue routes by skill automatically cs chat --tui
Virtual Team of Coders

Six AI workers. One shared context file. A pipeline that takes an idea from a sentence to deployed code without you touching a keyboard between steps. Each worker is permanently wired to the phase it does best — the skill-aware queue handles all routing automatically.

The team roster
openai-plannerIdeation & task breakdown Provider : OpenAI (GPT-4o) Does : turns a raw idea into structured task files committed to git as .md Skills : idea, plan, tasks, spec, breakdown, feature, roadmap, brainstorm qwen-scoutScaffolding (runs before Claude) Provider : Ollama (qwen2.5-coder:32b — local) Does : reads task MD files, creates file stubs, folder structure, boilerplate Skills : scaffold, stub, init, skeleton, prepare, structure, boilerplate claude-engineerArchitecture & implementation Provider : Anthropic (claude-opus-4-8) Does : reads task MD + scaffolded stubs, writes production code and tests Skills : code, implement, architecture, design, write, build, function, class llama-translatorDocs localisation Provider : Ollama (llama3.2 — local) Does : translates all reference files from English into configured target languages Skills : translate, localise, language, i18n, spanish, french, german, portuguese gemini-visualImages & visual context Provider : Google Gemini (gemini-2.0-flash) Does : generates diagrams, banner images, annotated screenshots for docs Skills : image, diagram, visual, screenshot, banner, icon, figure, illustration gemma-deployerBuild, rsync & deploy Provider : Ollama (gemma3:12b — local) Does : runs build commands, rsyncs artefacts to remote servers, restarts services Skills : deploy, rsync, build, release, publish, ship, restart, upload
Full opencode.toml
# opencode.toml — Virtual Team of Coders # Place this at the root of your project alongside TEAM.md default_provider = "anthropic" # ── Main thread — lightweight model, steers the conversation ────────────────── [providers.anthropic] model = "claude-haiku-4-5-20251001" # ── Worker 1: OpenAI Planner — idea → structured task .md files ─────────────── [[workers]] id = "openai-planner" provider = "openai" model = "gpt-4o" api_key_env = "OPENAI_API_KEY" skills = ["idea", "plan", "tasks", "spec", "breakdown", "feature", "roadmap", "brainstorm"] cost_tier = 2 # ── Worker 2: Qwen Scout — scaffold before Claude codes ─────────────────────── [[workers]] id = "qwen-scout" provider = "ollama" model = "qwen2.5-coder:32b" base_url = "http://localhost:11434" skills = ["scaffold", "stub", "init", "skeleton", "prepare", "structure", "boilerplate"] cost_tier = 0 # free / local — always preferred if it matches # ── Worker 3: Claude Engineer — architecture and production code ─────────────── [[workers]] id = "claude-engineer" provider = "anthropic" model = "claude-opus-4-8" skills = ["code", "implement", "architecture", "design", "write", "build", "function", "class"] cost_tier = 3 # ── Worker 4: Llama Translator — localise all reference docs ────────────────── [[workers]] id = "llama-translator" provider = "ollama" model = "llama3.2" base_url = "http://localhost:11434" skills = ["translate", "localise", "language", "i18n", "spanish", "french", "german", "portuguese"] cost_tier = 0 # ── Worker 5: Gemini Visual — images, diagrams, visual context ──────────────── [[workers]] id = "gemini-visual" provider = "google" model = "gemini-2.0-flash" api_key_env = "GEMINI_API_KEY" skills = ["image", "diagram", "visual", "screenshot", "banner", "icon", "figure", "illustration"] cost_tier = 1 # ── Worker 6: Gemma Deployer — build, rsync, publish ────────────────────────── [[workers]] id = "gemma-deployer" provider = "ollama" model = "gemma3:12b" base_url = "http://localhost:11434" skills = ["deploy", "rsync", "build", "release", "publish", "ship", "restart", "upload"] cost_tier = 0
TEAM.md — shared context in the git root

TEAM.md is the single source of truth every worker reads at the start of a session. It lives in the repository root and is committed to git so all workers — and all humans — see the same information. Every worker reads it via their system prompt or a /context TEAM.md command before starting work.

# TEAM.md — Project shared context # Commit this file. Every worker reads it at session start. # Update server IPs, credentials, and URLs when they change. ## Project - **Name**: <your-project-name> - **Repo**: https://github.com/<org>/<repo> - **Main branch**: main - **Language(s)**: <e.g. Rust / TypeScript / Python> ## Workflow rules 1. Task specs live in `tasks/` as `TASK-NNN.md` files — one task per file. 2. `openai-planner` writes the task files; never edit them without logging the change. 3. `qwen-scout` creates file stubs for any new modules before `claude-engineer` codes them. 4. `claude-engineer` reads the task MD and the stubs; writes tests alongside implementation. 5. `llama-translator` runs after code is merged; translates all `docs/` files to target languages. 6. `gemini-visual` generates diagrams from architecture descriptions in task files. 7. `gemma-deployer` runs after the build passes; rsyncs artefacts and restarts services. ## Build machine - **Host**: <build-server-ip> - **User**: <build-user> - **SSH key**: `~/.ssh/id_build` (shared via 1Password vault: <vault-name>) - **Build command**: `make release` - **Artefact path**: `./dist/` ## Deploy targets | Env | Host | User | Web root | Restart cmd | |------------|-------------------|--------|-------------------------------|-------------------------------| | staging | <staging-ip> | deploy | /var/www/<app>/staging/ | `systemctl restart <app>`| | production | <prod-ip> | deploy | /var/www/<app>/prod/ | `systemctl restart <app>`| **rsync command (gemma-deployer uses this verbatim)**: ``` sshpass -p '<password>' rsync -av --delete \ -e "ssh -o StrictHostKeyChecking=no" \ ./dist/ deploy@<prod-ip>:/var/www/<app>/prod/ ``` ## Credentials (rotate quarterly — update here when you do) - **OpenAI API key env**: `OPENAI_API_KEY` — set in shell before running cs - **Gemini API key env**: `GEMINI_API_KEY` — set in shell before running cs - **Anthropic API key**: via `cs login` (browser OAuth) or `ANTHROPIC_API_KEY` env - **Ollama**: running locally at `http://localhost:11434` — no auth ## Target languages for translation `es` (Spanish), `fr` (French), `de` (German), `pt` (Portuguese) Translated files go in `docs/i18n/<lang>/` mirroring the English tree. ## Do not modify - `TEAM.md` — update via PR with team review - `opencode.toml` — only the tech lead changes worker config
Security note: Do not commit raw API keys or passwords to TEAM.md. Reference environment variable names and vault entries instead. If your repo is private and your team is trusted, short-lived deploy passwords are acceptable — rotate them regularly.
How the pipeline flows

Type one instruction. The skill queue fans it out to the right worker automatically. Here is the full idea-to-ship sequence:

Step 1 — You type the idea you: "brainstorm a payment retry system with exponential backoff" → skill match: "brainstorm" → openai-planner dispatched immediately Step 2 — Planner writes the spec [openai-planner]: Created tasks/TASK-042.md (retry logic spec, acceptance criteria, edge cases) Committed to branch feature/payment-retry via git tool Step 3 — You ask Qwen to scaffold you: "scaffold the payment retry module from TASK-042.md" → skill match: "scaffold" → qwen-scout dispatched [qwen-scout]: Created src/retry/mod.rs (empty stubs) Created src/retry/backoff.rs, tests/retry_test.rs Step 4 — Claude implements while Gemini starts on diagrams you: "implement TASK-042 and diagram the retry state machine" → "implement" → claude-engineer (parallel) → "diagram" → gemini-visual (parallel, same turn) [claude-engineer]: Wrote backoff logic, unit tests — all passing [gemini-visual]: Generated docs/img/retry-state-machine.png Step 5 — Llama translates docs you: "translate the retry docs to spanish and french" → skill match: "translate", "spanish", "french" → llama-translator [llama-translator]: Created docs/i18n/es/retry.md, docs/i18n/fr/retry.md Step 6 — Gemma builds and deploys you: "build and deploy to staging" → skill match: "build", "deploy" → gemma-deployer [gemma-deployer]: make release → OK rsync ./dist/ deploy@staging:/var/www/app/staging/ → OK systemctl restart app → OK

The queue pane shows all active lanes in real time:

┌─ queue ──────────────────────────────────────────────────────────────────────┐ main agent thinking… ▶ [claude-engineer] implement TASK-042 payment retry module ▶ [gemini-visual] diagram the retry state machine ⌛ translate the retry docs to spanish and french ← queued for llama └──────────────────────────────────────────────────────────────────────────────┘
Wiring the API keys and providers

Each provider needs its credentials available before cs starts. The cleanest approach is a per-project .env file sourced in your shell profile, or a [env] block in opencode.toml (not committed to git).

# .env (gitignored) — source this before running cs export OPENAI_API_KEY="sk-..." export GEMINI_API_KEY="AIza..." export ANTHROPIC_API_KEY="sk-ant-..." # or use: cs login # Ollama runs locally — no key needed, just keep the server up: ollama serve & ollama pull qwen2.5-coder:32b ollama pull llama3.2 ollama pull gemma3:12b
Giving all workers access to TEAM.md

Start every session by injecting TEAM.md into the context. CSK supports a /context command that reads a file and prepends it to the active conversation:

# At session start — loads TEAM.md into the shared context /context TEAM.md # Workers receive the context snapshot at dispatch time. # They see: the full conversation history up to that point # + TEAM.md if you loaded it # + the task message you typed

Alternatively, reference TEAM.md explicitly in your message: "Using the server details in TEAM.md, deploy to production." — the agent fetches and reads it via the read_file tool before acting.

Cost and speed expectations
Worker Model Cost tier Typical latency ────────────────────────────────────────────────────────────── openai-planner gpt-4o 2 (mid) 4–10 s qwen-scout qwen2.5-coder:32b 0 (free) 8–30 s (local GPU) claude-engineer claude-opus-4-8 3 (premium) 15–60 s llama-translator llama3.2 0 (free) 5–15 s (local GPU) gemini-visual gemini-2.0-flash 1 (cheap) 3–8 s gemma-deployer gemma3:12b 0 (free) 5–20 s (local GPU)

Three of the six workers run on local Ollama — zero API cost and no rate limits. Only the planner, engineer, and visual worker call external APIs. On a mid-range machine with a GPU, the entire idea-to-deploy loop for a medium feature typically completes in under two minutes, with all workers running in parallel wherever the dependency graph allows.

AI Mesh — Share Providers Across Machines

Run cs mesh serve on each machine in your WireGuard mesh. Every node exposes its local AI resources — Ollama models, Anthropic keys, OpenAI keys — through a lightweight OpenAI-compatible HTTP proxy on port 11435. Other CS nodes discover peers via a shared almanac.toml and use any model in the network as if it were local.

Context isolation guaranteed. Every request carries its full conversation history in the body (OpenAI format). The proxy builds a fresh, stateless context per request — no shared mutable state between concurrent calls. Two CS sessions from different projects hitting the same proxy node at the same time cannot interfere with each other.
Architecture
┌─────────────────────────────────────────────────────────────────────────┐ │ almanac.toml (shared file) │ │ node: home WG: 10.99.0.2:11435 → qwen2.5-coder:32b, llama3.2 │ │ node: office WG: 10.99.0.10:11435 → codestral:22b, claude key │ │ node: friend WG: 10.99.0.20:11435 → gemma3:12b, openai key │ └─────────────────────────────────────────────────────────────────────────┘ │ │ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ cs home │◄──────►│cs office│◄────────►│cs friend│ │ :11435 │ WireGrd │ :11435 │ WireGrd │ :11435 │ └─────────┘ └─────────┘ └─────────┘
Step 1 — Publish this node to the almanac
# On each machine, register itself in the local almanac cs mesh publish \ --node-id home \ --mesh-ip 10.99.0.2 \ --description "Home workstation — RTX 4090, 64 GB" \ --token my-shared-mesh-secret # The almanac lives at ~/.config/coding-sidekick/almanac.toml # Share it with peers via git, rsync, or the WireGuard mesh itself: scp ~/.config/coding-sidekick/almanac.toml user@10.99.0.10:~/.config/coding-sidekick/
Step 2 — Start the mesh proxy
# Bind to the WireGuard interface so only mesh peers can reach it cs mesh serve \ --bind 10.99.0.2:11435 \ --node-id home \ --description "Home workstation" \ --token my-shared-mesh-secret # Or run as a systemd service (see below) # Ollama models are auto-discovered from http://127.0.0.1:11434 # API keys are read from environment variables (ANTHROPIC_API_KEY, OPENAI_API_KEY, etc.)
Step 3 — Discover peers and get backends
# Ping every peer in the almanac, print what each offers cs mesh sync [home ] 10.99.0.2 (Home workstation — RTX 4090) ollama qwen2.5-coder:32b ollama llama3.2 ollama gemma3:12b anthropic [key configured] [office ] 10.99.0.10 (Office build server) ollama codestral:22b openai [key configured] # Write [[chat_backends]] entries for all reachable peers: cs mesh sync --write-backends # → creates mesh-backends.toml in the current directory
Step 4 — Add mesh peers to opencode.toml

Copy the backend blocks from mesh-backends.toml into your opencode.toml, or just paste the ones you want. The model field uses the prefix ollama: to tell the mesh proxy which local backend to use on the remote node.

# opencode.toml — using models from the mesh default_provider = "anthropic" [providers.anthropic] model = "claude-haiku-4-5-20251001" # Office node's Codestral (large code model, no local GPU needed) [[chat_backends]] id = "office-codestral" provider = "mesh" base_url = "http://10.99.0.10:11435" model = "ollama:codestral:22b" cost_tier = 0 mesh_token = "my-shared-mesh-secret" # Friend's OpenAI key (useful when Anthropic is rate-limited) [[chat_backends]] id = "friend-openai" provider = "mesh" base_url = "http://10.99.0.20:11435" model = "gpt-4o" cost_tier = 2 mesh_token = "my-shared-mesh-secret" on_rate_limit = "shift_then_wait" # CS rotates through backends automatically
Run as a systemd service
# /etc/systemd/system/cs-mesh.service [Unit] Description=CS Mesh AI Proxy After=network.target wg-quick@wg0.service [Service] User=youruser Environment=ANTHROPIC_API_KEY=sk-ant-... Environment=OLLAMA_HOST=0.0.0.0 ExecStart=/home/youruser/.local/bin/cs mesh serve \ --bind 10.99.0.2:11435 \ --node-id home \ --description "Home workstation" \ --token my-shared-mesh-secret Restart=on-failure [Install] WantedBy=multi-user.target # Enable and start systemctl enable --now cs-mesh
Model addressing reference
Model prefix in backend config What the proxy does on the remote node ────────────────────────────────────────────────────────────────────────── ollama:<name> Forward to local Ollama at :11434 claude-* / anthropic:* Use ANTHROPIC_API_KEY to call Anthropic gpt-* / openai:* Use OPENAI_API_KEY to call OpenAI gemini-* / google:* Use GEMINI_API_KEY to call Google Gemini
Quick reference
cs mesh publish --node-id home --mesh-ip 10.99.0.2 --token <secret> cs mesh serve --bind 10.99.0.2:11435 --node-id home --token <secret> cs mesh sync # ping peers, print capabilities cs mesh sync --write-backends # also write mesh-backends.toml cs mesh status # print almanac contents
Rate-Limit Handling

Configure what happens when the active provider returns a 429:

on_rate_limit = "shift_then_wait" # try every backup, then wait on last # options: "off" | "wait" | "shift" | "shift_then_wait" [rate_limit_wait] initial_probe_secs = 300 # first sleep on no-Retry-After 429 max_probe_interval_secs = 1800 max_total_wait_secs = 86400 [[chat_backends]] id = "openai-backup" provider = "openai" model = "gpt-4o" api_key_env = "OPENAI_API_KEY" cost_tier = 2
Hooks

Shell commands fired on lifecycle events. pre_tool_use with non-zero exit blocks the tool. All others are advisory.

[[hooks]] event = "pre_tool_use" tool = "bash" command = '''jq -e '.input.command | test("rm\\s+-rf\\s+/")' >/dev/null 2>&1 \ && { echo "refusing rm -rf /"; exit 1; } || exit 0''' [[hooks]] event = "post_tool_use" tool = "edit" command = '''jq -r .input.path | xargs -r -I{} sh -c 'case "{}" in *.go) gofmt -w "{}";; esac' ''' [[hooks]] event = "stop" command = "printf '\\a'" # beep when agent finishes a turn

Available events: pre_tool_use, post_tool_use, stop, user_prompt_submit. Each hook receives a JSON payload on stdin with the relevant context (event, tool name, input, output).

MCP Servers

Attach any MCP-compatible server — its tools register under mcp.<name>.<tool> and the agent uses them like native tools.

[[mcp_servers]] name = "fs" command = "uvx" args = ["mcp-server-filesystem", "/home/me/Documents"] [[mcp_servers]] name = "brave" command = "npx" args = ["-y", "@modelcontextprotocol/server-brave-search"] env = { BRAVE_API_KEY = "set-via-env" }
Config & Data Paths
~/.config/coding-sidekick/config.toml # global config ./coding-sidekick.toml # project-local (overrides global) ~/.local/share/opencode/trajectories/ # session JSONL for fine-tuning export ~/.local/share/opencode/history/ # conversation history per workspace
Troubleshooting
API key not found

CSK reads the key from the environment variable named in api_key_env. Make sure the variable is exported in the shell before running: export ANTHROPIC_API_KEY=sk-ant-.... You can also put it in [env] in the config file (not recommended for shared configs).

Model refuses to use tools / edit blocks instead

Some smaller or locally-hosted models do not support structured tool calls reliably. Add --smart to switch to aider-style edit-block parsing: cs --smart --tui. The agent outputs diffs in plain text and CSK applies them.

Rate limited constantly on Anthropic

Set on_rate_limit = "wait" or add an OpenAI backup under [[chat_backends]] with on_rate_limit = "shift". For a Max subscription, the --compact-tools flag cuts ~25k tokens per turn and significantly reduces the chance of hitting rate limits during long sessions.

TUI input not accepted when window is small

Add COLUMNS = "220" and LINES = "50" to the [env] block in your config. This pins the terminal dimensions so the readline input layer does not try to adapt to the physical window size.

CS Project Management
// Structured multi-agent workflow · git-native · human + AI compatible

CS ships a lightweight project management framework built around five plain-text Markdown files. Every worker — human or AI — reads and writes the same files. Git keeps everyone in sync. The LOCKED pattern prevents drift: once an item moves forward in the pipeline, it is frozen and future changes go through the proper channel.

The Five Documents
FilePurposeWritten by
SCOPE.mdWhat we are building — the authoritative scopeHuman or AI at project start
CHANGE_REQUESTS.mdChanges to scope that is already lockedAnyone who needs a change
SCOPE_CREEP.mdGood ideas that are out of scope right nowAnyone who spots one
WBS.mdWork Breakdown Structure — scope broken into modulesPM or AI after scope is set
TASKS.mdAtomic tasks workers claim, execute, and closePM or AI from WBS modules
The LOCKED Pattern

When an item is processed into the next layer of the pipeline, it receives a LOCKED marker and must never be modified again. To change it, open a new entry in the appropriate upstream register.

# Locking looks like this in any document: > LOCKED — processed into WBS-003 on 2026-06-16T14:22:00Z

This rule is absolute: locked = frozen. The pipeline that follows it is already built from that snapshot.

The Flow
Author writes SCOPE.md │ │ scope items processed → WBS.md → TASKS.md │ scope items get LOCKED tasks get CLAIMED → DONE │ │ Need to change a locked scope item? └─► CHANGE_REQUESTS.md ─► WBS.md ─► TASKS.md (CR gets LOCKED) │ │ Something out of scope? └─► SCOPE_CREEP.md ─► decision: promote to CR or reject (SC gets LOCKED)
New additions always go at the bottom of each file. Workers act only on items that are NOT locked. Locked items are historical record.
Initialising a Project
# Creates all five files in the current directory cs pm init "My Project" # Commit to git so every worker has the same baseline git add SCOPE.md CHANGE_REQUESTS.md SCOPE_CREEP.md WBS.md TASKS.md git commit -m "feat: initialise CS project management"
cs pm Commands
CommandEffect
cs pm init "Name"Create all five template files
cs pm statusPrint open/claimed/done counts for all files
cs pm task add "Title" WBS-001 "Description"Add a new TASK-NNN to TASKS.md
cs pm task grab TASK-001 worker-idClaim a task (OPEN → CLAIMED)
cs pm task done TASK-001 worker-id "Summary"Complete + LOCK a task
cs pm task release TASK-001 "reason"Release a claimed task back to OPEN
cs pm wbs add "Title" SCOPE-001 "Description"Add WBS-NNN module from a scope item
cs pm cr add "Title" HIGH "Description"Log a change request
cs pm sc add "Title" "noted during X" "Description"Log a scope creep item
cs pm lock SCOPE-001 SCOPE.md WBS-001Mark any item LOCKED (moved to target)
Task Lifecycle
OPEN │ ├─ worker grabs it ──► CLAIMED (Claimed-by + Claimed-at recorded) │ │ │ ├─ work done ──► DONE + LOCKED (permanent) │ │ │ └─ blocked/stuck ──► OPEN (released with reason) │ └─ BLOCKED (waiting on another task — lists blocked-by ID)
TASKS.md Entry Format
## [TASK-007] Add rate-limit backoff to mesh proxy **Module**: WBS-002 **Status**: CLAIMED **Claimed-by**: worker-ai-01 **Claimed-at**: 2026-06-16T09:00:00Z **Done-at**: — Implement exponential backoff in cs mesh serve when upstream returns 429. Respect the Retry-After header if present; default to 2s doubling to 60s cap.
Mesh File Sync — Bidirectional PM + Almanac

CS includes built-in rsync-based file sync between mesh nodes. Push PM files and the almanac to a peer, or pull from one — no manual rsync commands needed.

# Push PM files to peer node "office" (uses its mesh IP from almanac) cs mesh push-files office --remote-path /home/user/project # Also push the almanac so the peer discovers the full mesh cs mesh push-files office --remote-path /home/user/project --almanac # Pull latest PM files from the git-access node to your local project cs mesh pull-files git-node --remote-path /home/user/project # Pull PM files + almanac (SSH password auth) cs mesh pull-files git-node --remote-path /home/user/project --almanac \ --ssh-user deploy --ssh-pass secretpass
Git Bridge — Teams Without Shared Git Access

Not every worker needs a git account. One node holds the credentials and acts as the vault. All others sync through it using cs mesh push-files / pull-files.

# Typical workflow for a non-git worker: # 1. Pull latest PM state from the git node cs mesh pull-files git-node --remote-path /home/user/project --almanac # 2. Grab a task, do the work cs pm task grab TASK-007 my-worker-id # 3. Mark done, push updated TASKS.md back cs pm task done TASK-007 my-worker-id "Implemented rate-limit backoff" cs mesh push-files git-node --remote-path /home/user/project # 4. Git node commits + pushes to remote ssh git-node@10.99.0.2 "cd /path/to/project && git add -A && git commit -m 'worker2: TASK-007 done' && git push"
Document the git node's identity in a TEAM.md in the repo root so every worker knows who holds the keys and how to reach them. Print the git bridge help any time with cs pm git-bridge.
Best Practices
RuleWhy
Never edit SCOPE.md after the first LOCKED itemDownstream WBS and tasks are already built from that snapshot
One heading per scope item / taskThe cs pm parser relies on ## [ID] structure
Commit PM files after every state changeGit log = audit trail of who did what and when
AI workers should call cs pm status before grabbing a taskPrevents two workers from claiming the same task
Release rather than abandonRELEASED tasks reappear in the OPEN pool; abandoned tasks block the module
Scope creep is not a dirty wordSCOPE_CREEP.md captures ideas without polluting active scope
🏰
AD Pentester Sidekick
Documentation for this tool is locked. Register for early access or purchase a license to unlock.
View on Arsenal →
🚗
FlipperCarCommander
In development. Documentation will be available on release.
View on Arsenal →
AngieManager
In development. Documentation will be available on release.
View on Arsenal →
OpenCode
In development. Documentation will be available on release.
View on Arsenal →

Tor + WireGuard Machine Mesh

Infrastructure guide · Linux · Leave machines at the office, orchestrate from anywhere

This guide builds a private mesh network that lets you reach every machine you own — regardless of NAT, corporate firewalls, or dynamic IPs. WireGuard carries the fast day-to-day traffic. Tor hidden services act as an always-on fallback for SSH when the office firewall blocks UDP or the WireGuard connection drops. Together they give you a resilient, authenticated, zero-trust tunnel to any machine in your fleet.

Architecture
┌─────────────┐ WireGuard VPN ┌─────────────────────────┐ WireGuard VPN ┌──────────────────┐ │ Home / you │ ◄────────────────► │ VPS hub 10.99.0.1 │ ◄────────────────►│ Office machines │ │ 10.99.0.2 │ all mesh traffic │ (public IP, always on) │ spokes dial out │ 10.99.0.10+ │ └─────────────┘ └─────────────────────────┘ └──────────────────┘ │ Tor hidden services (SSH .onion fallback — works even if UDP is blocked by a firewall)

Hub-and-spoke, not full mesh. The VPS is the single WireGuard endpoint every spoke dials. Office machines never need an open inbound port — they initiate outbound UDP to the VPS on port 51820. From home you reach any office machine by routing through the VPS subnet (10.99.0.0/24). Tor is a parallel channel you fall back to when WireGuard is unavailable.

Step 1 — WireGuard on the VPS (hub)

Run these commands once on your public VPS. This machine becomes the hub every spoke dials in to.

# Install apt install wireguard # Generate the hub key pair wg genkey | tee /etc/wireguard/private.key | wg pubkey > /etc/wireguard/public.key chmod 600 /etc/wireguard/private.key cat /etc/wireguard/public.key # ← copy this, you'll paste it into each spoke

Create /etc/wireguard/wg0.conf on the VPS. Add a [Peer] block for every machine in the mesh.

# /etc/wireguard/wg0.conf (VPS hub) [Interface] Address = 10.99.0.1/24 ListenPort = 51820 PrivateKey = <VPS-PRIVATE-KEY> # cat /etc/wireguard/private.key # Forward traffic between peers and masquerade out to the internet PostUp = iptables -A FORWARD -i wg0 -j ACCEPT; \ iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE PostDown = iptables -D FORWARD -i wg0 -j ACCEPT; \ iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE # ── Peer: Home machine ───────────────────────────────────────────────── [Peer] PublicKey = <HOME-PUBLIC-KEY> AllowedIPs = 10.99.0.2/32 # ── Peer: Office machine 1 (build server) ────────────────────────────── [Peer] PublicKey = <OFFICE1-PUBLIC-KEY> AllowedIPs = 10.99.0.10/32 # ── Peer: Office machine 2 (deploy target) ───────────────────────────── [Peer] PublicKey = <OFFICE2-PUBLIC-KEY> AllowedIPs = 10.99.0.11/32 # Add more [Peer] blocks as you add machines — just assign the next .1x IP
# Open the WireGuard port on the VPS firewall ufw allow 51820/udp ufw allow 22/tcp # keep SSH for admin access # Enable IP forwarding (required for traffic between spokes) echo "net.ipv4.ip_forward=1" >> /etc/sysctl.conf && sysctl -p # Start WireGuard and enable on boot systemctl enable --now wg-quick@wg0 # Verify the interface is up wg show
Step 2 — WireGuard on each spoke (home + office)

Repeat on every machine you want in the mesh. Change Address to the unique IP for that machine (home = 10.99.0.2, office-1 = 10.99.0.10, office-2 = 10.99.0.11, etc.).

# Install (same on every machine) apt install wireguard # Generate this machine's key pair wg genkey | tee /etc/wireguard/private.key | wg pubkey > /etc/wireguard/public.key chmod 600 /etc/wireguard/private.key cat /etc/wireguard/public.key # ← paste this into wg0.conf on the VPS as a [Peer]
# /etc/wireguard/wg0.conf (spoke — change Address per machine) [Interface] Address = 10.99.0.10/24 # unique per machine: .2 home, .10 office-1, .11 office-2 … PrivateKey = <THIS-MACHINE-PRIVATE-KEY> [Peer] # VPS hub — the only peer a spoke needs PublicKey = <VPS-PUBLIC-KEY> Endpoint = <VPS-IP>:51820 AllowedIPs = 10.99.0.0/24 # route all mesh traffic via hub PersistentKeepalive = 25 # keep NAT hole open — critical behind office routers
# Bring up the interface and enable on boot systemctl enable --now wg-quick@wg0 # Test: ping another mesh machine ping 10.99.0.1 # VPS hub — should respond immediately ping 10.99.0.10 # office-1 — responds once that spoke is also up
Key exchange workflow: When you add a new machine, generate its key pair on that machine, add its public key as a [Peer] on the VPS, then run wg addpeer or restart wg-quick@wg0 on the VPS. No other spoke needs to change — they all route through the hub.
Step 3 — Tor hidden services (SSH fallback)

Install Tor on each office machine and expose its SSH port as a hidden service. This gives every machine a stable .onion address that works even behind the strictest corporate firewall — no port forwarding, no dynamic DNS needed.

# On each office machine apt install tor # Append to /etc/tor/torrc HiddenServiceDir /var/lib/tor/ssh_hs/ HiddenServicePort 22 127.0.0.1:22 systemctl restart tor # Read the machine's onion address — save this somewhere safe cat /var/lib/tor/ssh_hs/hostname # → xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.onion

The hidden service key lives at /var/lib/tor/ssh_hs/hs_ed25519_secret_key. Back it up — if you lose it, the onion address changes.

# Back up the hidden service keys (do this once, store offline) cp -r /var/lib/tor/ssh_hs/ ~/ssh-hs-backup/
Step 4 — ~/.ssh/config on the home machine

Set up SSH aliases so you can type ssh office1 for the fast WireGuard path and ssh office1-tor when WireGuard is down. Tor requires a local Tor instance running at 127.0.0.1:9050.

# ~/.ssh/config (home machine) # ── WireGuard paths (fast — use these day-to-day) ───────────────────────────── Host office1 HostName 10.99.0.10 User <your-user> IdentityFile ~/.ssh/id_ed25519 ServerAliveInterval 30 Host office2 HostName 10.99.0.11 User <your-user> IdentityFile ~/.ssh/id_ed25519 ServerAliveInterval 30 # ── Tor fallback paths (when office UDP is blocked or WG is down) ────────────── Host office1-tor HostName <office1-onion>.onion User <your-user> ProxyCommand nc -X 5 -x 127.0.0.1:9050 %h %p ServerAliveInterval 60 ConnectTimeout 60 # Tor circuits take a few seconds to build Host office2-tor HostName <office2-onion>.onion User <your-user> ProxyCommand nc -X 5 -x 127.0.0.1:9050 %h %p ServerAliveInterval 60 ConnectTimeout 60
# Install Tor on your home machine (needed to reach .onion addresses) apt install tor # starts automatically on port 9050 # Test the Tor path to office1 ssh office1-tor # first connect takes ~5 s to build a circuit — normal
Step 5 — Persistence and auto-reconnect

WireGuard reconnects automatically after a reboot — systemctl enable wg-quick@wg0 handles that. Office machines behind NAT need PersistentKeepalive = 25 (already in the config above) so the NAT mapping stays alive even when idle.

# Confirm both services survive a reboot on every machine systemctl is-enabled wg-quick@wg0 # should print: enabled systemctl is-enabled tor # should print: enabled # Check WireGuard peer handshake timestamps — non-zero = connected wg show wg0 latest-handshakes
Step 6 — Orchestrate with CSK

Document the mesh in your project's TEAM.md so every CSK worker knows which machine does what. The deployer worker can then SSH into any mesh machine by name.

## Mesh machines (add to TEAM.md) | Alias | WireGuard IP | Tor onion (fallback) | Role | |-----------|--------------|----------------------------------|-------------------| | office1 | 10.99.0.10 | <office1-onion>.onion | Build server | | office2 | 10.99.0.11 | <office2-onion>.onion | Deploy / staging | SSH user for all mesh machines: <your-user> SSH key: ~/.ssh/id_ed25519 (same key on all machines, added to ~/.ssh/authorized_keys) ## gemma-deployer rsync command template sshpass -p '<password>' rsync -av -e "ssh -i ~/.ssh/id_ed25519" \ ./dist/ <your-user>@10.99.0.11:/var/www/app/ # fall back: replace 10.99.0.11 with office2-tor and add -o ProxyCommand=…
# Example CSK session — run from home while office machines are in the mesh you: "build on office1 and deploy to office2" → [gemma-deployer]: ssh office1 'cd /project && make release' ← WireGuard path rsync -av ./dist/ youruser@10.99.0.11:/var/www/app/ ssh office2 'systemctl restart myapp' you: "translate the new docs and copy them to office1" → [llama-translator]: translated docs/i18n/es/ docs/i18n/fr/ → [gemma-deployer]: rsync docs/ youruser@10.99.0.10:/project/docs/
Quick reference
Command Purpose ─────────────────────────────────────────────────────────────────── wg show Show peers and handshake times wg-quick up wg0 Bring up WireGuard manually wg-quick down wg0 Bring it down ssh office1 Connect via WireGuard (fast) ssh office1-tor Connect via Tor (fallback) cat /var/lib/tor/ssh_hs/hostname Read the onion address systemctl restart tor Restart Tor (new circuit) ping 10.99.0.1 Ping VPS hub — mesh health check
Security model: WireGuard uses public-key cryptography only — no passwords traverse the tunnel. Office machines never open an inbound port; they dial out to the VPS. The Tor hidden service key is the only secret that needs backing up — lose it and the onion address changes. Rotate WireGuard keys annually or whenever a machine leaves the fleet: remove its [Peer] from the VPS and run wg syncconf wg0 <(wg-quick strip wg0).

HawkEye

HawkEye is a professional-grade, all-in-one vulnerability assessment platform built as a native desktop application. It covers every stage of a modern pentest or red-team engagement — from raw network discovery to exploit chaining, PDF report generation, and one-click push to your ticketing system.

v0.8 · Rust + egui · Linux / macOS / Windows

What Makes HawkEye Different

Most scanners are single-purpose: Nmap enumerates, Nuclei templates scan, ZAP fuzzes. HawkEye chains all of those engines together in a single workflow and adds capabilities found nowhere else at this price point:

CapabilityHawkEyeNessusBurp ProOpenVAS
Network-to-web full pipeline✅ Native❌ Web only⚠ Partial
Browser-engine DAST (CDP)✅ Phase 6
Kill chain / ATT&CK mapping✅ Phase 7
Parallel worker pool✅ 1–10
Scan history & delta diff
PDF + Jira/Linear/Slack push⚠ Add-on⚠ Add-on
Offline, no cloud SaaS required
Open-ended licensing❌ Per IP❌ Annual✅ Free

The Seven Phases

Every scan runs a configurable pipeline of up to seven phases. Each phase feeds findings into the next.

#PhaseEngine(s)Key outputs
1Network Discovery & NSENmap + NSE scriptsLive hosts, open ports, banners, Nmap NSE findings
2Internal CVE ScannerBuilt-in + NVD APIService-matched CVEs with CVSS, EPSS, KEV flag
3Nuclei TemplatesNuclei binary (9,000+ templates)Critical/High/Med/Low/Info findings per host
4Web Attack SurfaceKatana spider + API spec + CMS + OSV + OOBCrawled URLs, tech fingerprints, CMS CVEs, OOB callbacks
5Deep DASTInternal HTTP fuzzerSQLi (error/blind/time), XSS (stored/reflected), CSRF, JWT, LDAP/XPath injection
6Browser-Engine DASTChromium DevTools ProtocolDOM XSS, CSTI, prototype pollution, CORS misconfig, CSP analysis
7Kill Chain Engine & ReportsInternal pattern matcherATT&CK-mapped kill chains, remediation roadmap, PDF export, integration push

Core Design Principles

  • Native desktop, zero cloud dependency — all processing is local. Credentials never leave your machine.
  • Parallel work-stealing engine — up to 10 concurrent scan workers with automatic load balancing.
  • Scan history & delta diffing — compare any two scans to track remediation progress or detect regressions.
  • Pluggable integrations — push findings directly to Jira, Linear, Slack, or any webhook endpoint.
  • Report-grade output — one-click HTML and PDF reports suitable for client delivery.
HawkEye is a single self-contained binary. All Rust dependencies compile statically. Only optional external tools (Nmap, Nuclei, Chromium, Katana, Nikto, OpenVAS) need separate installation.

Installation & Setup

System Requirements

RequirementMinimumRecommended
OSLinux x86_64, macOS 12+, Windows 10+Linux (best tool compatibility)
RAM512 MB4 GB+ (browser DAST uses more)
Disk50 MB binary2 GB (Nuclei templates cached)
Rust toolchain1.78+ (build from source)Latest stable
OpenGLOpenGL 2.0 or VulkanGPU-accelerated desktop

Build from Source

HawkEye uses the Rust toolchain. Install Rust via rustup, then:

git clone https://github.com/mradamantware/HawkEye
cd HawkEye
cargo build --release
# Binary at: ./target/release/hawk_eye

On Linux you may need system libraries for the GUI backend:

# Ubuntu / Debian
sudo apt install libxcb-render0-dev libxcb-shape0-dev libxcb-xfixes0-dev \
                 libspeechd-dev libxkbcommon-dev libssl-dev

# Fedora / RHEL
sudo dnf install libxcb-devel libxkbcommon-devel openssl-devel

Optional External Tools

HawkEye can run without any of these, but each unlocks additional scan phases. Install only what you need.

ToolPhaseInstall
Nmap 7.9+1 — Network Discoverysudo apt install nmap
Nuclei 3.x3 — Nuclei Templatesgo install github.com/projectdiscovery/nuclei/v3/cmd/nuclei@latest
Katana4 — Web Spidergo install github.com/projectdiscovery/katana/cmd/katana@latest
Nikto4 — Web Checkssudo apt install nikto
Chromium6 — Browser DAST + PDFsudo apt install chromium-browser
OpenVAS / GVM4 — Imported findingsFollow GVM community docs
Metasploit5 Scenarios — PoC runsudo apt install metasploit-framework

First Launch

Run the binary directly — no install step required:

./target/release/hawk_eye

HawkEye creates its data directory at ~/.hawkeye/ on first launch. Scan history is stored at ~/.hawkeye/history/ as individual JSON files.

NVD API Key (Optional but Recommended)

Phase 2 queries the National Vulnerability Database. Without a key, requests are rate-limited to ~5/min. With a free NVD API key the limit is 50/min.

  1. Register at nvd.nist.gov/developers/request-an-api-key
  2. Paste the key into the API Keys panel in the Scan tab → Advanced → NVD API Key field

Running a Scan

The Scan Tab

When HawkEye launches it opens on the Scan tab. Everything needed to start a scan lives here, organized into collapsible panels.

Step 1 — Set Your Target

Enter a target in the Target field. Accepted formats:

FormatExampleNotes
Single IP192.168.1.10Scans one host
CIDR range10.0.0.0/24Enumerates all 254 hosts
Hostname / URLexample.comResolves DNS, then scans
Range notation10.0.1.1-5050 host sweep

Step 2 — Choose a Scan Profile

Profiles set the Nmap flags and enable/disable internal scanner modules. Select from the Profile dropdown:

ProfileNmap flagsBest for
Quick-T4 --top-ports 100Fast recon, large /16 ranges
Full-T3 -p- -sVComplete audit, all 65 535 ports
Web-T4 -p 80,443,8080,8443,8000 -sVWeb-focused, skips non-HTTP
Stealth-T1 -sS --randomize-hostsIDS evasion, red team ops
CustomYour own flagsAnything else
The Stealth profile requires root/administrator privileges for raw-socket SYN scanning.

Step 3 — Select the Scan Engine

The Engine toggle controls how Phase 1 finds services:

  • Nmap NSE — delegates entirely to Nmap with NSE scripts. Most compatible, produces detailed banners.
  • Internal — HawkEye's built-in TCP prober + banner grabber. No Nmap required.
  • Both — runs both in sequence and deduplicates findings. Most thorough.

Step 4 — Configure Parallel Workers

The Workers slider (1–10) sets how many hosts are scanned in parallel. Workers use a work-stealing queue — fast hosts free up workers immediately for the next host, avoiding the idle time of static batching.

WorkersTypical use caseStealth impact
1Single host or careful auditsNone
2–4Small /24 rangesLow
5–8Internal network sweepsMedium — IDS may alert
9–10Speed-critical CI/CD pipelinesHigh — not stealthy
When workers > 1, HawkEye displays an amber warning reminding you that parallel probes reduce stealth.

Step 5 — Start the Scan

Click ▶ Start Scan. The scan log panel below shows real-time output from all workers. A progress bar tracks hosts completed / total hosts. Findings appear in the Findings tab as they are discovered, without waiting for the scan to finish.

Click ⏹ Stop at any time — workers finish their current host then exit cleanly. All findings up to that point are preserved.

Advanced Panels

Expand the Advanced Scanning accordion for additional capabilities:

  • Subdomain Enumeration — passive + active subdomain discovery for a domain target.
  • Authentication — provide credentials (HTTP Basic, form login, token, cookie) so authenticated pages are scanned.
  • OpenVAS — import a GVM XML report to merge third-party findings into the same scan session.
  • OOB Listener — starts a local out-of-band callback server. Detected when Phase 4 injects OOB payloads.
  • API Spec — upload an OpenAPI / Swagger JSON spec to guide Phase 4 web enumeration.
  • API Keys — NVD API key for higher Phase 2 rate limits.

Phase Guide (1–7)

Phases run sequentially per host. Each phase receives the port/service data produced by the previous phase and adds new findings. You can enable or disable phases per profile.

Phase 1 — Network Discovery & Nmap NSE

The entry point for every scan. HawkEye first determines which hosts are alive (ICMP ping + TCP ACK on port 443), then scans open ports and optionally runs Nmap NSE scripts.

What it does

  • TCP SYN/connect scan across the configured port range
  • Service version detection (-sV)
  • OS fingerprinting (when run as root)
  • NSE script categories: vuln,safe,default
  • Banner grabbing on all open ports

Findings produced

Phase 1 findings include: open port disclosures, service version exposures, Nmap NSE vulnerability matches (e.g. EternalBlue, Heartbleed, ShellShock via dedicated scripts), and weak SSH algorithms.

Phase 2 — Internal CVE Scanner + NVD Enrichment

Using the service name and version strings collected in Phase 1, HawkEye queries the NVD API for known CVEs and matches them against its internal rule set.

What it does

  • Version-to-CVE matching via CPE strings
  • CVSS v3 score fetched per CVE
  • EPSS probability score fetched (daily exploit likelihood)
  • CISA KEV (Known Exploited Vulnerabilities) flag checked
  • Internal rules for common misconfigurations (anonymous FTP, weak SNMP community, default credentials)

EPSS & KEV Badges

Findings with a KEV flag are marked with a red KEV badge in the Findings tab — these are actively exploited in the wild and should be prioritised. EPSS scores above 10% appear as an orange badge showing the probability.

Phase 3 — Nuclei Templates

HawkEye invokes the Nuclei binary against every HTTP/HTTPS endpoint discovered in Phase 1. The community template library contains 9,000+ checks covering CVEs, misconfigurations, default credentials, exposed panels, and more.

Template categories run

By default HawkEye runs: cves, exposed-panels, misconfiguration, default-logins, technologies. Informational-only templates are filtered unless the profile includes them.

Rate limiting

Nuclei is invoked with -rate-limit 100 by default. Stealth profile reduces this to -rate-limit 10. You can override via the custom Nmap flags field (flags are forwarded to Nuclei as well).

Phase 4 — Web Attack Surface

Phase 4 maps the web attack surface of every HTTP endpoint. It combines five sub-engines:

Sub-engineWhat it finds
Katana spiderAll reachable URLs, forms, JS entrypoints, parameters
NiktoServer misconfigurations, version disclosures, dangerous HTTP methods
CMS scannerWordPress / Joomla / Drupal plugin & theme CVEs via WPScan-style matching
OSV.devOpen-source dependency CVEs via manifest files (package.json, requirements.txt)
OOB callbacksSSRF, blind XXE, blind command injection via the local OOB listener

API Specification scanning

If an OpenAPI or Swagger JSON spec is provided, Katana seeds its crawl from every endpoint defined in the spec. This ensures 100% endpoint coverage even for SPAs with no anchor links.

Phase 5 — Deep DAST

Phase 5 applies an internal HTTP fuzzer to every parameter and input discovered in Phase 4. It tests for injection classes that require crafted payloads and response analysis.

Attack classDetection method
SQL Injection — error-basedDatabase error signatures in response body
SQL Injection — blindBoolean diffing (true vs. false condition response delta)
SQL Injection — time-basedResponse delay ≥ 5 s on SLEEP/WAITFOR payload
XSS — reflectedInjected payload echoed unescaped in response
XSS — storedPayload stored, then retrieved on a second request
CSRFState-changing POST with no CSRF token detected
JWT vulnerabilitiesNone algorithm, weak secret, missing signature verification
LDAP injectionLDAP error strings in response
XPath injectionXPath error strings in response
Header injectionCRLF + Host header reflection

Phase 6 — Browser-Engine DAST

Phase 6 launches a headless Chromium instance controlled via the Chrome DevTools Protocol (CDP) to find vulnerabilities that only manifest in a fully rendered browser context — JavaScript-heavy SPAs, DOM manipulation, and browser-specific security controls.

CheckWhat is tested
DOM XSSJavaScript sinks: innerHTML, document.write, eval, location.href with taint tracking
Client-Side Template InjectionAngular, Vue, Handlebars template expression execution
Prototype PollutionObject prototype modification via URL parameters
CORS misconfigurationWildcard or reflected Origin in Access-Control-Allow-Origin
CSP analysisMissing, weak, or bypassable Content-Security-Policy headers
Subresource IntegrityThird-party scripts loaded without SRI hashes
Mixed contentHTTP resources loaded over HTTPS pages
Phase 6 requires Chromium. HawkEye auto-detects the binary at common paths (chromium, chromium-browser, google-chrome, google-chrome-stable). Set the CHROME_PATH environment variable to override.

Phase 7 — Kill Chain Engine & Report Engine

Phase 7 runs automatically after all hosts complete. It does not send new network traffic — it analyses the full findings corpus collected in Phases 1–6.

Kill Chain Pattern Engine

The engine applies 15 MITRE ATT&CK-mapped patterns to the finding set. Each pattern defines:

  • require_all — all of these finding types must be present
  • require_any — at least one of these must be present
  • bonus — these increase confidence if present

When a pattern matches, HawkEye builds a kill-chain narrative: a step-by-step description of how a real attacker would chain those specific findings into a full compromise path. Each chain includes MITRE technique IDs, suggested next steps, and a combined remediation strategy.

Remediation Roadmap

All findings are scored using the priority formula:

priority = (CVSS × 0.4) + KEV_bonus(2.0) + EPSS_bonus(1.5 if >10%) + severity_bonus
           clamped to [0, 10]

The roadmap sorts findings by priority and groups them by owner (Security team, DevOps, Development, Network team) with effort estimates (Quick Win / 1 sprint / Quarter).

Kill Chains Tab

After a scan, open the Kill Chains tab to view matched chains. Each chain card is expandable and shows:

  • Chain name and severity
  • Narrative description of the attack path
  • Step-by-step attack flow with MITRE technique IDs
  • Finding IDs that triggered the pattern
  • Suggested next steps for an attacker (useful for validating the finding)
  • Combined remediation recommendation

Scroll down in the Kill Chains tab to see the Remediation Roadmap — a prioritised table of all findings sorted by risk.

History Tab

Every completed scan is automatically saved to ~/.hawkeye/history/. The History tab lists all past scans. Select any two to generate a delta diff:

  • New findings — appeared in current scan, not in baseline
  • Regressions — previously fixed, now back
  • Persisted findings — still present in both scans
  • Fixed findings — in baseline but gone from current scan
A regression flag is set if any finding in the current scan matches a finding that was absent in the baseline — indicating a fixed vulnerability re-opened.

Findings & Reports

Findings Tab

The Findings tab is your central workspace for reviewing, filtering, and acting on discovered vulnerabilities.

Finding Cards

Each finding shows:

FieldDescription
Severity badgeCritical / High / Medium / Low / Info — colour-coded
TitleShort vulnerability name
Host : PortAffected target
ServiceProtocol or service name (http, ssh, ftp, …)
CVE IDLinked CVE if applicable
CVSS scoreNumeric severity score (0–10)
EPSS badgeProbability of exploitation in next 30 days
KEV badgeRed — actively exploited per CISA KEV catalogue
OWASP categoryOWASP Top 10 / API Top 10 mapping
StatusOpen / Acknowledged / Fixed (you set this manually)

Filters

Use the filter bar at the top of the Findings tab to narrow the list:

  • Severity filter — multi-select checkboxes (Critical, High, Medium, Low, Info)
  • Status filter — Open, Acknowledged, Fixed, All
  • Search box — full-text match against title, description, CVE, and host

Detail Panel

Click any finding to expand the detail panel. It shows:

  • Description — what the vulnerability is and why it matters
  • Evidence — raw proof: HTTP response excerpt, banner, payload that triggered the finding
  • Remediation — concrete fix guidance
  • References — CVE links, OWASP pages, vendor advisories

Report Tab

The Report tab generates client-ready output from the current scan session.

HTML Report

Click Generate HTML Report to produce a self-contained HTML file at ~/.hawkeye/reports/<scan-id>.html. The report includes:

  • Executive summary with finding counts by severity
  • Target scope and scan metadata (date, profile, engine)
  • Complete finding table with all fields
  • Kill chain narratives (if Phase 7 matched patterns)
  • Remediation roadmap sorted by priority
  • Classification footer (Confidential / Internal / Public)

PDF Export

With Chromium installed, click Export PDF to convert the HTML report to PDF using headless Chromium. The PDF is saved alongside the HTML file with a .pdf extension.

# HawkEye runs this internally:
chromium --headless --disable-gpu --no-sandbox \
         --print-to-pdf=report.pdf \
         --print-to-pdf-no-header \
         file:///path/to/report.html
If Chromium is not found, the Export PDF button is replaced with a note showing which paths were checked. Install Chromium or set CHROME_PATH.

Report Classification

Select a classification level from the dropdown before generating: Confidential (default), Internal, or Public. The classification banner appears on every page of the PDF and in the HTML header/footer.

CVE Lookup Tab

Use the CVE Lookup tab to search the NVD directly without running a scan. Enter a CVE ID (e.g. CVE-2021-44228) to fetch:

  • Full description and CVSS v3 vector
  • Affected CPE configurations
  • EPSS score
  • CISA KEV status
  • Published and last-modified dates

MITRE ATT&CK Tab

The MITRE tab renders a heatmap overlay of the ATT&CK Enterprise matrix. Techniques covered by findings from the current scan are highlighted. Hover a cell to see which findings map to that technique.

Scenarios Tab

The Scenarios tab lists pre-built attack scenarios for the most common vulnerability classes. Each scenario provides:

  • Prerequisite findings required
  • Manual exploitation steps
  • Metasploit module reference (if applicable)
  • Proof-of-concept code snippet
  • Estimated CVSS impact if exploited

Scenarios are matched to the current scan — only scenarios relevant to what was found are shown.

Integrations

HawkEye can push findings directly to your team's issue tracker, messaging platform, or any custom webhook endpoint. All integration configuration is stored locally and never leaves your machine.

Find the integration settings in Report tab → Push Integrations. Configure one or more targets, then click Push Findings to send all current findings.

Jira

Creates one Jira issue per finding using the Jira REST API v3.

FieldDescription
Base URLYour Jira instance root, e.g. https://yourcompany.atlassian.net
EmailJira account email address
API TokenPersonal Access Token from id.atlassian.com/manage/api-tokens
Project KeyThe project key, e.g. SEC
Issue Typee.g. Bug, Vulnerability, Security Risk

Issue description is formatted as Atlassian Document Format (ADF) with sections for Description, Evidence, Remediation, CVE, CVSS, OWASP, and Host. Severity maps to Jira priority: Critical → Highest, High → High, Medium → Medium, Low → Low.

# HawkEye calls:
POST https://yourcompany.atlassian.net/rest/api/3/issue
Authorization: Basic base64(email:token)
Content-Type: application/json

Linear

Creates one Linear issue per finding using the Linear GraphQL API.

FieldDescription
API KeyLinear personal API key from linear.app/settings/api
Team IDThe UUID of the target team (from Linear URL or API)

HawkEye uses the issueCreate mutation. Title, description (Markdown), and priority are set per finding. Labels are not set automatically — add them via Linear's API if needed.

# HawkEye calls:
POST https://api.linear.app/graphql
Authorization: Bearer <api_key>

Slack

Posts a colour-coded message attachment per finding to a Slack channel via an Incoming Webhook.

FieldDescription
Webhook URLYour Slack Incoming Webhook URL, e.g. https://hooks.slack.com/services/…

Create a webhook at api.slack.com/apps → Incoming Webhooks. Each finding is a separate attachment. Attachment colour maps to severity: Critical/High → red, Medium → amber, Low/Info → good (green).

Slack rate-limits Incoming Webhooks to 1 message per second per webhook. For scans with 50+ findings, the push may take a minute to complete. HawkEye does not batch findings into a single message to preserve per-finding severity context.

Generic Webhook

POSTs each finding as a JSON object to any HTTP endpoint. Suitable for SIEM ingestion (Splunk HEC, Elastic, Wazuh), custom dashboards, or in-house tooling.

FieldDescription
URLFull endpoint URL
MethodPOST or PUT
Auth HeaderOptional, e.g. Authorization: Bearer <token>

Each request body is a JSON object with the following fields:

{
  "id":          42,
  "title":       "Apache Log4Shell (CVE-2021-44228)",
  "severity":    "Critical",
  "host":        "10.0.1.15",
  "port":        8080,
  "service":     "http",
  "cve":         "CVE-2021-44228",
  "cvss":        10.0,
  "owasp":       "A06:2021 – Vulnerable Components",
  "description": "...",
  "evidence":    "...",
  "remediation": "..."
}

Push Behaviour

All enabled integrations are pushed simultaneously when you click Push Findings. HawkEye shows a per-integration status log — green for success, red for failure with the HTTP status code and error message.

HawkEye does not deduplicate across pushes. If you push twice, you will create duplicate issues. Use your tracker's deduplication rules or only push once per scan session.

Troubleshooting

SymptomLikely causeFix
Jira 401 UnauthorizedWrong email or API tokenRegenerate token at id.atlassian.com
Jira 400 Bad RequestIssue type name doesn't exist in projectCheck project's available issue types
Linear 200 but no issue createdWrong Team ID (UUID format required)Copy Team ID from Linear → Settings → API
Slack message not deliveredWebhook URL revoked or app removedRecreate webhook in Slack app settings
Webhook connection refusedEndpoint not reachable from this hostTest with curl -X POST <url> manually