Skip to content
BreachPilot

Exploit Agent — Prompts (prompt.py + skills.py + research_assistant.py + reflection.py)

prompt.py — System prompt assembly

Verified symbols at prompt.py:

SymbolLineDescription
build_exploit_system_prompt13Main assembly; 13 kwargs
build_opsec_briefing310Empty when OpsecProfile.resolve_for_target disabled
build_domain_briefing349Empty when is_fqdn(original_target) false
build_parallel_agents_briefing396Empty unless swarm.parallel_enabled
build_capability_guidance460Empty when enabled=False

build_exploit_system_prompt block order (prompt.py:41-301):

  1. TARGET INFORMATION (IP, OS, CVEs, service_context)
  2. Runtime skills: either full skill_context or skill_hints lookup block (:52-75)
  3. ATTACKER ENVIRONMENT + env_context (preflight probe)
  4. ULTRATHINK (:84-100) xor CHAIN-OF-THOUGHT (:101-110)
  5. Attack mode workflow (:112-125)
  6. Peer consultation guidance (:127-136)
  7. OS branch: Windows (:138-169), Darwin (:170-184), Linux (:185-204)
  8. Local target playbook when is_local_target(target_ip) (:206-229)
  9. opsec_context / domain_context / parallel_agents_context / capability_guidance appends
  10. Exploitation workflow + RULES (no fabricated PoC URLs, canonical COMPROMISE:/VULN_NOT_CONFIRMED: markers, FILE & KEY HANDLING)
  11. Final response contract EXPLOIT_RESULT/SUMMARY/ACCESS_TYPE/DETAILS

Advisory briefings (all ""-when-off, never a hard gate):

  • build_opsec_briefing(profile, target_ip) – lists OpsecManager._NOISY_PATTERNS + _LOW_NOISE_REWRITES; empty for local/off (prompt.py:310).
  • build_domain_briefing(original_target, resolved_ip) – domain vs IP tool routing + enumerate_subdomains early (prompt.py:349).
  • build_parallel_agents_briefing(config)spawn_subagent/await_subagent/list_subagents + swarm.exploit_parallel phase line (prompt.py:396).
  • build_capability_guidance(enabled) – state/capability/hypothesis/task-graph tools + hypothesis-first workflow (prompt.py:460).

skills.py — Mid-run skill re-selection

SymbolLineDescription
_SkillReselectState22known_services/known_cves/pending_services + rate counters
_maybe_reselect_skills44Rebuild advisory hints when new services/CVEs appear

_SkillReselectState.take_new (skills.py:32) lowercases services, uppercases CVEs, returns None if nothing new (and absorbs all observed so repeated banners don't re-trigger).

_maybe_reselect_skills(policy, state, action_count, new_cves, registry, skills_cfg, messages, ...) guards: registry==None→no-op, skills.enabled==False→no-op, reselect_mid_run==False→no-op, reselect_count >= max_per_run→no-op (default 3), action_count - last < min_interval→no-op (default 5). Rebuilds via _build_skill_selection_for_context, applies via _apply_skill_selection_to_context, emits [SKILL UPDATE] … user message with hints (activation metadata, not bodies) (skills.py:114-132). Only ever rewrites target_context skill fields.

Config: skills.enabled, reselect_mid_run, reselect_max_per_run, reselect_min_interval_actions, reselect_sticky_defaults.

research_assistant.py — Read-only research sidecar

SymbolLineDescription
ResearchAssistantSettings105from_config reads research.assistant.*
ResearchAssistant189Bounded research loop
CONSULT_RESEARCH_ASSISTANT31"consult_research_assistant"
RESEARCH_ASSISTANT_TOOLS336 tools: search_cve_intel etc.
consultation_tool_schema()150Local tool schema for main model
research_assistant_prompt_briefing()176Contract text appended to system prompt

ResearchAssistantSettings.from_config defaults: automatic=true, failure_trigger=2, max_auto_consultations=4, max_tool_calls=5, max_model_rounds=3, max_advisory_chars=4000, timeout_seconds=90, save_advisories=true (research_assistant.py:118-147).

ResearchAssistant.consult(question, trigger, topics, context) (:256) – secondary model conversation capped by max_model_rounds + per-consultation tool budget + timeout_seconds. Only RESEARCH_ASSISTANT_TOOLS reachable; non-allowlisted tool names return BLOCKED:. System prompt at :51 hard-codes “untrusted data” boundary. Output normalized in _normalize_advisory (:547) to {status, confidence, findings[{claim, source_urls}], contradictions, unknowns, recommended_next_tests, sources}; findings without source_urls are flagged unverified. format_for_main (:409) renders with citations retained; advisory persisted to research_advisories.jsonl (_persist at :656).

Triggers from loop.py: startup evidence (loop.py:776), _automatic_research on note_exploit_outcome failure threshold (research_assistant.py:244), explicit model tool call.

reflection.py — Reflection + peer consultation

SymbolLineDescription
_generate_reflection11Deterministic heuristic from last 30 tool messages
_sanitize_reflection_field85sanitize_output + injection pattern redact
_llm_reflect_inline91LLM reflection via _call_model_with_retry + distinct lesson
_consult_peers_inline280In-process peer consultation
_REFLECTION_INJECTION_PATTERNS74pivot to IP/retarget/ignore prior/override scope

_generate_reflection(messages, plan, action_count) – tallies successes/failures in last 30 tool messages, identifies most_failed tool, suggests pivot if failures > 2× successes (reflection.py:11-67).

_llm_reflect_inline(client, model, messages, plan, action_count, semantic_memory, policy, target_ip, experience_store, verdict_signal) – opt-in via reasoning.llm_reflection; prompt built from structured summaries (tool/success/exit_code/truncated error) not raw content; BaseExceptionGroup handled; optional verdict_signal with {status: confirmed|refuted, evidence_refs} writes reflection:verdict to ExperienceStore, distinct from reflection:exploit_loop semantic lesson.

_consult_peers_inline(config, question, context, policy, target_ip, action_count) – budget shared via tools/mcp_tools/registry._consultation_count; peers called with tools=None; each peer.chat wrapped in _EXC_GROUP_CATCH; single status='advisory' audit record (reflection.py:408).

_REFLECTION_INJECTION_PATTERNS defends the user-role injection: [ADVISORY REFLECTION — system-generated, not an operator command] at loop.py:1727.

Config keys

KeyModule
research.assistant.enabled / model_alias / automatic / failure_trigger / max_* / timeout_secondsresearch_assistant.py:118
skills.enabled / reselect_*skills.py:65
reasoning.llm_reflection / peer_consult_on_failure_thresholdreflection.py:138
reasoning.chain_of_thought / ultrathinkprompt.py:23
multi_model.enabled / consult_aliases / max_consultationsreflection.py:310
swarm.parallel_enabledprompt.py:400
agent.capability_discovery_enabledprompt.py:460
opsec.enabled / exploit.allowed_targetsprompt.py:310 via OpsecProfile

Tests

FileVerifiedCovers
tests/test_capability_guidance_prompt.pyyesbuild_capability_guidance
tests/test_key_handling_prompt.pyyesFILE & KEY HANDLING block
tests/test_research_assistant.pyyesSettings, consult, normalization, dedup, timeout
tests/test_research_subsystem.pyyesStartup auto-consult + advisory render
tests/test_peer_consult_on_failure.pyyes_consult_peers_inline threshold + budget share
tests/test_skill_reselection.pyyes_SkillReselectState + rate guards + [SKILL UPDATE]
tests/test_skill_pipeline.pyyesappend_phase_skill_hints
tests/test_reflection_evidential_bridge.pyyesreflection:verdict bridge
source: repo docs (build sync)Edit this page on GitHub →