H4CKRF-6H05T is a HackRF co-pilot: an RF/SIGINT knowledge corpus and a
safety-gated control plane exposed over MCP. It knows the canon (modulation
families, common ISM/UNII bands, keyfob and paging protocols, decoder pipelines)
and it can act — safely — on the HackRF One. Every RF action funnels through
one deterministic execute_command chokepoint that classifies risk, checks
grants, asks for approval, and audits the result. The LLM never touches
libhackrf.
Inspired by M0MA-V3SP3R but for HackRF, with a laptop running Python instead of an Android app on a phone.
Three tiers, from knowing to analyzing to acting:
- Know — corpus tools (
knowledge_list_topics,knowledge_read,knowledge_search,knowledge_lookup_band,knowledge_lookup_modulation,knowledge_verify_claim). All read-only, allLOWrisk, cannot cause RF emission. - Analyze — DSP tools that operate on already-captured
.iqfiles (read_iq_summary,analyze_iq_modulation,analyze_iq_symbols,analyze_iq_spectrogram,decode_manchester,decode_pwm,decode_ppm,decode_nrz,decode_pocsag,decode_ads_b,decode_rtty,decode_ax25,decode_aprs). AllLOWrisk, cannot touch hardware. - Act — the HackRF surface (
get_device_info,sweep_spectrum,capture_iq,transmit_iq,grant_list,audit_query,sweep_spectrum_bulk,play_sequence). Every action goes through the funnel below.
Everything that could conceivably cause RF energy to leave the HackRF, or that opens the USB handle, or that reads raw IQ from the device, funnels through one deterministic chain:
ExecuteCommand → CommandExecutor.execute()
→ RiskAssessor.assess()
→ PermissionService.check() (for TX)
→ ApprovalPort.request() (for MEDIUM/HIGH)
→ HackrfDriver / HackrfSubprocess
There is no second MCP tool that reaches libhackrf. The LLM sees exactly one
tool, execute_command, discriminated by action. Knowledge and analysis
verbs land as new CommandAction values with fixed LOW risk — they inherit
the full audit trail and cannot bypass the gate. The funnel invariant is
stated in full in docs/architecture.md.
HackRF is a transceiver. The host gates TX by band, tier, and grant — BLOCKED bands (ADS-B, GPS, aviation voice, cellular downlink, maritime distress) are refused deterministically; everything else runs through the risk tiers. Legal compliance in your jurisdiction is on you. See docs/safety.md for the band table and grant model.
src/hackrf_agent/ the safety-gated MCP + CLI (installable Python package)
knowledge/ the RF/SIGINT corpus (markdown + records/*.json)
skills/hackrf/ the SKILL.md that tells an assistant to use the MCP
scripts/ user-facing shell/Python helpers (schema regen, fixtures)
docs/ long-form guides (architecture, safety, MCP host setup)
schemas/ JSON Schema for the execute_command envelope + records
tests/ unit + integration + mcp + e2e
See knowledge/MANIFEST.md for the corpus contents and layout.
Get from a fresh laptop to an interactive HackRF chat session. Covers macOS and Ubuntu.
- A HackRF One (rev A/B/C).
- A data-capable USB-A → USB-mini cable (charge-only cables won't enumerate).
- Python 3.11 or newer.
- An OpenRouter API key (get one at openrouter.ai).
pyhackrf is a Python wrapper around the system libhackrf library. The
library must exist before pip install will work end-to-end, and the
hackrf_info / hackrf_transfer CLI tools are what hackrf-agent doctor uses
to prove the device is alive.
macOS (Homebrew):
brew install hackrfThis installs libhackrf, the hackrf_* CLI tools, and firmware images under
$(brew --prefix)/share/hackrf/firmware/.
Ubuntu (22.04+):
sudo apt update
sudo apt install hackrf libhackrf-dev libhackrf0Install the udev rules so a non-root user can open the device:
sudo cp /usr/share/hackrf/53-hackrf.rules /etc/udev/rules.d/ 2>/dev/null || \
sudo tee /etc/udev/rules.d/53-hackrf.rules > /dev/null <<'EOF'
ATTR{idVendor}=="1d50", ATTR{idProduct}=="6089", MODE="0666"
ATTR{idVendor}=="1d50", ATTR{idProduct}=="604b", MODE="0666"
ATTR{idVendor}=="1d50", ATTR{idProduct}=="cc15", MODE="0666"
EOF
sudo udevadm control --reload-rules
sudo udevadm triggerUnplug and replug the HackRF after the rules land.
Plug in the HackRF, then:
hackrf_infoYou should see something like:
hackrf_info version: 2024.02.1
libhackrf version: 2024.02.1
Found HackRF
Index: 0
Serial number: 0000000000000000c86463dc2f4b6a1f
Board ID Number: 2 (HackRF One)
Firmware Version: 2024.02.1 (API:1.08)
Part ID Number: 0xa000cb3c 0x006b4762
If nothing appears:
- macOS:
system_profiler SPUSBDataType | grep -A 8 HackRFto confirm the OS sees it. Try a different USB-A port (skip hubs and USB-C dongles for the first test). - Ubuntu:
lsusb | grep 1d50should show the device. Ifhackrf_infoshows a permission error, the udev step above didn't take — replug or re-check the rules file.
Firmware old? Compare Firmware Version against the latest release at
github.com/greatscottgadgets/hackrf/releases.
To upgrade:
# macOS firmware lives here after `brew install hackrf`
hackrf_spiflash -w $(brew --prefix)/share/hackrf/firmware-bin/hackrf_one_usb.bin
# Ubuntu (path may vary by package version)
hackrf_spiflash -w /usr/share/hackrf/firmware-bin/hackrf_one_usb.binThen unplug/replug and rerun hackrf_info.
git clone https://github.com/charlesreid1/H4CKRF-6H05T.git
cd H4CKRF-6H05T
python3.11 -m venv .venv
source .venv/bin/activate
pip install -e '.[dev]'The [dev] extra pulls in pyhackrf (which links against the libhackrf you
installed in step 1) and the OpenAI SDK (for OpenRouter).
hackrf-agent reads OPENROUTER_API_KEY from the environment — nothing else.
Export it in your shell before launching the CLI:
export OPENROUTER_API_KEY=sk-or-v1-...Or keep the key in a git-ignored dotfile and source it per session:
# ~/.openrouter_api_key
export OPENROUTER_API_KEY=sk-or-v1-...source ~/.openrouter_api_keyThere is no .env auto-load — if the variable isn't in your shell environment,
hackrf-agent doctor and hackrf-agent chat will refuse to start.
The default model is deepseek/deepseek-v4-pro (defined once in
src/hackrf_agent/ai/llm_client.py as DEFAULT_MODEL). To use a different
OpenRouter model, create or edit ~/.hackrf-agent/config.toml:
model = "anthropic/claude-sonnet-5"This is read by the CLI on startup and passed to OpenRouterClient. In code,
you can also pass model="..." directly to the OpenRouterClient constructor.
hackrf-agent doctorAll four checks (home_dir, db_schema, api_key, hackrf) should be green.
If hackrf is red but hackrf_info worked in step 2, your shell can't find
the CLI on PATH — which hackrf_info and adjust.
hackrf-agent chatYou're in an interactive REPL. Try:
> what firmware is on the device?
> sweep the 433 MHz ISM band for 500 ms and tell me the top three peaks
RX-only commands run unattended. MEDIUM-risk commands prompt [y/N]; HIGH-risk
commands require typing CONFIRM. Ctrl-C aborts the current operation
and revokes any active TX grants; pressing Ctrl-C a second time within 2 s
stops the event loop and exits the process.
Before ever transmitting, issue a scoped grant:
hackrf-agent grant tx 433.05-434.79M --for 30m --max-gain 20See docs/safety.md for the grant model and band table.
hackrf-agent-mcp exposes the same safety-gated command surface as an MCP
server. Any MCP-aware host — Claude Desktop, Claude Code, Cursor, OpenCode,
mcp-cli, custom clients — can drive the radio through its tool, resource,
and elicitation surface.
hackrf-agent-mcpConfigure your host to spawn it on stdio. See docs/mcp.md for host config snippets, the full tool list, how approval works over MCP elicitation, resource URIs, and safety caveats.
Getting started + reference
- docs/cli.md — user-facing command reference.
- docs/mcp.md — use HackRF from any MCP-aware host (Claude
Desktop, Claude Code, Cursor, OpenCode,
mcp-cli, …). Tool list, host config snippets, approval flow, resources, and safety caveats. - docs/safety.md — what the risk gate does, and does not, protect. FCC citations, plain-English risk tiers, the grant model, the kill switch, and incident response.
- docs/execute_command_schema.md — the
LLM's one tool. One section per
CommandActionwith purpose, args, example, and risk tier. Auto-generated from the code. - docs/env_reference.md — every env var, every
config.tomlkey, every CLI flag in one table with precedence rules.
For CTF operators
- docs/ctf_playbook.md — first-60-seconds triage strategy for a mystery frequency or IQ file.
- docs/ctf_recipes.md — six end-to-end walkthroughs: unknown keyfob, POCSAG page hunt, LoRa CSS, APRS packet, spectrogram stego, mystery-modulation IQ.
- docs/rf_cheatsheet.md — one-page band and modulation reference.
- docs/field_kit.md — DEF CON prep: what to bring, home rehearsal, offline fallback when venue wifi dies.
- docs/prompting.md — how to talk to the co-pilot productively: templates, steering, anti-patterns.
- docs/iq_handling.md — IQ file formats, size math, handoffs to Inspectrum / URH / GQRX / SigMF.
- docs/warmup.md — smoke-test sequence to verify the stack is healthy before an event.
- docs/troubleshooting.md — symptom → fix FAQ for when something breaks mid-event.
Contributors
- docs/architecture.md — how the pieces fit together. The layer diagram, module map, risk-tier table, envelope schema, audit-log schema, and data-flow for one command.
- docs/development.md — contributor guide. Setup, test tiers, "add a new CommandAction" checklist, CI runners, release process.
- docs/ai-package.md — contributor reference for the
hackrf_agent.aipackage. - docs/tests.md — how to run each test tier, and what the tiers mean.
CLOUD (OpenRouter)
↕ execute_command({action, args, justification, expected_effect})
LAPTOP (Python)
HackrfAgent → CommandExecutor → RiskAssessor / PermissionService / ApprovalPort
↓ libhackrf via pyhackrf
HackRF One (USB peripheral)
The LLM never touches the USB handle, never sees raw IQ, and never
self-classifies risk. Every execute_command passes through one deterministic
funnel.
MIT — see LICENSE.