Skip to content
BreachPilot

Intelligence — Overview (tools/intelligence/)

AttackGraph v2, belief modelling, evidence provenance, attempt fingerprinting, structured schemas, and legacy adapters. 31 Python files across 6 subpackages + package __init__.py.

Wiring status (verified against callers — do not describe all of this as a Flow A primitive):

  • graph/active production path: wrapped by tools/api/graph_service.py and tools/api/graph_builder.py behind the WebUI attack-path DAG API (GET /api/v1/runs/{run_id}/graph, default-off via api.graph_route per tools/api/routes/graph.py:137); the store is also the killchain backend (tools/killchain/machine.py:30, tools/mcp_tools/killchain.py:101, lazily in tools/exploit_agent/runner/_impl.py:110 and tools/campaign/phases.py:779 when killchain.enabled).
  • adapters/legacy Flow B path (best-effort): legacy/observer.py:163 (ObserverAdapter.infer_confidence) and legacy/finding_verifier.py:214 (FindingAdapter.ensure_reproduction_steps) import them lazily; AttackPhaseBridge.to_orchestrator maps planner phases in tools/campaign/executor.py:526; the remaining adapters are test-only.
  • belief/, evidence/, fingerprint/, schemas/scaffold / test-only. Nothing in Flow A (main.py, the exploit loop, mcp_exploit_server.py) imports them; fingerprint.tracker.is_permanent_failure feeds ObserverAdapter.classify_dead_end (adapters/observer_adapter.py:96), which is in turn consumed by the legacy observer. SafeSchemaLoader has no production caller (verified: only tests import it).

Layout

SubpackageFilesPurposeStatus
belief/state.py, confidence.py, store.pyHypothesis state + confidence calculusscaffold (legacy adapter consumer)
evidence/reference.py, store.py, provenance.pyImmutable refs + store + lineagescaffold / test-only
fingerprint/attempt.py, tracker.pySafe retry/fingerprintingscaffold (tracker used by legacy adapter)
graph/types.py, store.py, merge.py, traversal.pyAttack graphactive (WebUI API)
schemas/base.py, validator.py, graph.py, outcome.py, planner.py, critic.py, strategy.pyLLM output contractsscaffold / test-only
adapters/planner_adapter.py, finding_adapter.py, memory_adapter.py, observer_adapter.py, target_graph_adapter.pyBridge to legacy surfaceslegacy Flow B (observer + finding adapters)

Belief (belief/)

state.py

SymbolKindLine
HypothesisStatusEnum`unknown
EvidencePolarityEnum`supporting
EvidenceObservationdataclassevidence_ref, polarity, weight, source, timestamp, independent, agent_interpretation
HypothesisStatedataclasshypothesis_id, statement, target, current_confidence, supporting/contradicting_evidence
BeliefStateclassadd_hypothesis, get, register_evidence/register_observation, next_discriminating_check, snapshot/load, top_unresolved, to_json/from_json

compute_status (confidence.py:119): CONFIRMED at confidence ≥ 0.75 with supporting evidence, REFUTED at ≤ 0.25 with contradicting evidence — a bare numeric claim without evidence never qualifies. Default update rule is BAYESIAN_BETA (pseudo-count K = max(2, independent_observation_count)); dependent (re-stated) evidence counts at 0.6 via _independence_bonus. NonModelConfidence / TaggedConfidence are separate non-belief scales (tool success, path viability, …) that must never be compared with hypothesis confidence.

store.py

SymbolKindLine
BeliefStoreclassupsert/get/delete/list_all/list_by_status/find_by_statement

In-memory store keyed by mission_id; persists nothing (caller persists). No confidence gating.


Evidence (evidence/)

reference.py

SymbolKindLine
EvidenceSourceEnum`tool_output
EvidenceLevelEnum`raw
EvidenceReferencedataclassref_id, source_tool, target, timestamp, content_hash, create/from_dict/to_dict/normalize

EvidenceReference.create(source_tool, target, timestamp, content, ...) hashes content (hash_content), normalize() collapses whitespace / strips controls / trims to 500 chars, _make_ref_id stable. CredentialRef.from_reference (graph/types.py:137) extracts credential refs from ev:credential:… strings.

store.py

SymbolKindLine
EvidenceStoreV2classput/get/list_all/find_by_source_tool/find_by_target/count

Immutable append-only keyed by ref_id.

provenance.py

SymbolKindLine
ProvenanceEntrydataclassevidence_id, source, produced_by, producing_action, timestamp, content_hash, parent_evidence_id, confidence
ProvenanceChainclasswalk, find_by_source, lineage, confidence_at, to_dict/from_dict
ProvenanceTrackerclassregister_root/register_derived, chain_for, summary

Root → leaf chain (provenance.py:39); confidence_at multiplies hop confidences (unknown id → 0.0); register_derived raises ValueError on self-parent or unknown parent. Built for the evidence DAG, not tied to HypothesisState.


Fingerprint (fingerprint/)

attempt.py

SymbolKindLine
AttemptStatusEnum`attempted
ActionFamilyEnum`recon_scan
Attemptdataclasstarget, service, action_family, parameters, hypothesis, technique_category, expected_observation; fingerprint()
RetryJustificationEnum`new_version_evidence
RetryJustifierclassevaluate(attempt, evidence_snapshot), describe
mask_secretsdefCopy with password/pass/secret/token/key values → "<redacted>"

fingerprint() canonicalizes (lowercased target/service/hypothesis/category/observation, order-insensitive sorted params) then sha256. RetryJustifier.evaluate diffs the snapshot against its previous_evidence key, first matching change wins. is_permanent_failure / PERMANENT_FAILURE_MARKERS live in tracker.py, not attempt.py.

tracker.py

SymbolKindLine
AttemptTrackerclassrecord, has_attempted, status_of, is_repetition, all_fingerprints, retry_history, register_evidence_change, summary, clear
is_permanent_failure(output)defCase-insensitive marker match (9 markers: scope, permission, unreachable, refused, not installed, …)

record dedups on fingerprint (repeat bumps repeat_count); is_repetition returns (bool, RetryJustification, detail) — terminal FAILED/REFUTED retries need material evidence change, BLOCKED is deliberately non-terminal. In-memory, one threading.Lock. No production caller outside tests and ObserverAdapter.classify_dead_end.


Graph (graph/)

types.py

SymbolKindLine
NodeTypeEnum`asset
EdgeTypeEnum`resolves_to
NodeStatusEnum`unknown
GraphNode / GraphEdge / GraphUpdatedataclassto_dict/from_dict, redact_properties, make_evidence_ref

GraphNode holds node_id, node_type, value, scope, properties, confidence, first_seen/last_seen, evidence_refs, observation/contradiction_count, status, source; to_dict redacts credential-like property values via redact_properties (credential|password|secret|token|key"***"). make_evidence_ref(source_tool, target, timestamp, content_hash, ...) returns ev: compact refs; _cred_evidence_ref points at protected-store entries. _enum_or_default safe coercion.

store.py

SymbolKindLine
AttackGraphStoreclassupsert_node/get_node/get_node_by_value/upsert_edge/delete_node/query_nodes/query_edges/neighbors/paths/summary/to_graph_nodes/to_graph_edges/close

SQLite-backed (agv2_nodes / agv2_edges / agv2_meta, UNIQUE(scope, node_type, value)); one threading.RLock, WAL mode. _norm_value case-folds IP/HOST/DOMAIN/ASSET/ENDPOINT. to_graph_nodes / to_graph_edges export full lists for GraphTraversal. TargetGraphV2Adapter bridges legacy TargetGraph reads, not the store backend.

traversal.py

SymbolKindLine
GraphTraversal(nodes, edges)classnodes_of_type, edges_of_type, neighbors, paths, path_exists, subgraph (no walk)

Pure queries over caller-supplied arrays (no store import, no cycles); all bounded (max_hops / max_length / max_paths / max_nodes, optional scope filter). paths enumerates simple paths cycle-safe; subgraph returns (nodes, internal_edges, boundary_edges).

merge.py

SymbolKindLine
GraphMergeEngine(store)classapply(graph_update), preview, _check_node_conflict, _conflict
GraphMergeConflictdataclassedge_type, node_value, reason, existing_confidence, proposed_confidence
GraphMergeErrorexceptionMissing edge endpoint (ValueError from the store, re-raised)

Applies GraphUpdate {node_updates[], edge_updates[], source_agent, timestamp, reason} — nodes first, then edges; conflicting node mutations are skipped, the rest still apply. Merge key is (scope, value) with case-folding (_CASE_FOLD_TYPES). Tolerance _CONFIDENCE_TOLERANCE = 0.2.


Schemas (schemas/)

FileExportContract
base.pyBaseSchema, ValidationResult{valid, errors, repaired, message}validate(raw), repair(raw, errors), coerce(raw), safe_load(raw); helpers _safe_enum, _require_str, _clamp_float
validator.pySafeSchemaLoader(validator, default_factory, schema_name)extract_json_block, parse_json_block, load(raw_json_str)
graph.pyGraphMutationProposal{node, edge, mutation, confidence, evidence_ref, reason}, GraphMutationSchema`mutation ∈ add_node
outcome.pyOutcomeAssessment{verdict, confidence, supporting/contradictory_evidence, criteria_satisfied/not_satisfied, next_recommended_evidence, explanation}, OutcomeAssessmentSchema`verdict ∈ confirmed
planner.pyPlannerProposal{hypothesis_id, statement, target, confidence, suggested_checks, …}, CandidatePath{steps, score, …}, HypothesisUpdate{statement, target, status, confidence, evidence_refs, reason} + 3 schemasStatement capped at MAX_STATEMENT_LEN = 500; CandidatePath.steps non-empty strings; `HypothesisUpdate.status ∈ open
critic.pyCriticReview{decision, objections, evidence_missing, alternate_explanations, stale_data, single_source, confidence, reasoning}, CriticReviewSchema`decision ∈ approve
strategy.pyStrategyReview{top_unresolved, uncertainty_areas, weak_assumption_paths, duplicate_work, recommended_evidence, overall_assessment, confidence}, StrategyReviewSchemaAll five list fields required (repair → [])

All schemas implement validate/repair/coerce (+ safe_load on the base) and log via log_validation/dump_telemetry. SafeSchemaLoader.load extracts the JSON block (fence-tolerant, bare {…}/[…]), validates, repairs once, coerces or falls back to default_factory(); never raises. See the Schema validator lifecycle section for the full flow.


Adapters (adapters/)

FileClassBridge
planner_adapter.pyPlannerAdapter + AttackPhaseBridgeplanning_score_to_confidence, task_confidence, attach_planning_metadata, to_orchestrator, to_attack_planner
finding_adapter.pyFindingAdapterensure_reproduction_steps, dedupe_findings, link_to_graph(verifier, target_graph, finding_row, node_map) — legacy TargetGraph, not v2 GraphUpdate
memory_adapter.pyMemoryAdapterremember_graded, find_existing, dedup_remember, confidence_rank
observer_adapter.pyObserverAdapterpopulate_hypothesis_evidence, populate_graph_updates, infer_confidence, classify_dead_end
target_graph_adapter.pyTargetGraphV2Adapterresolve_node_id, add_edge_by_value, edges_summary vs legacy target_graph.TargetGraph

Adapters are pure transforms + dedupe guards; no new persistence.


Belief store lifecycle (belief/store.py, belief/state.py, belief/confidence.py)

Per-mission hypothesis tracking. BeliefStore holds BeliefState objects keyed by mission id; each BeliefState holds HypothesisStates keyed by generated uuid.

SymbolKindLineDescription
BeliefStore.upsert(state)defstore.py:15Insert/replace by state.mission_id
BeliefStore.get(mission_id)defstore.py:19BeliefState or None
BeliefStore.delete(mission_id)defstore.py:23Remove if present (no-op otherwise)
BeliefStore.list_all()defstore.py:27Every state, insertion order
BeliefStore.list_by_status(status)defstore.py:31States with ≥1 hypothesis in status
BeliefStore.find_by_statement(statement)defstore.py:35States containing an exact-statement match
BeliefState.add_hypothesis(statement, target, entity="", provenance="")defstate.py:95Create hypothesis, return its uuid
BeliefState.register_evidence(hypothesis_id, evidence_observation)defstate.py:117Append (deduped by evidence_ref) + confidence update
BeliefState.register_observation(...)defstate.py:134DEPRECATED field-based wrapper
BeliefState.next_discriminating_check(hypothesis_id, available_checks)defstate.py:155Best un-attempted check, freshness order
BeliefState.snapshot() / load(snapshot_dict)defstate.py:173Plain-dict round-trip
BeliefState.top_unresolved(limit=5)defstate.py:188Highest uncertainty first, excludes CONFIRMED/REFUTED/EXHAUSTED
BeliefState.to_json() / from_json(payload)defstate.py:205JSON round-trip via snapshot/load
ConfidenceCalculator.update(rule, current, obs, state)defconfidence.py:89Dispatch one observation to a rule
DeterministicUpdater(rule).apply(hypothesis, observations)defconfidence.py:154Fold observations in order, return final confidence
compute_status(confidence, evidence_count, supporting_count, contradicting_count, exhausted)defconfidence.py:119Confidence → HypothesisStatus

Thresholds (confidence.py:22-24): CONFIRMED_THRESHOLD = 0.75, REFUTED_THRESHOLD = 0.25, SUSPECTED_LIKELY_BOUND = 0.45. Default rule is BAYESIAN_BETA (ConfidenceCalculator.default_rule); pseudo-count K = max(2, independent_observation_count). compute_status only returns CONFIRMED/REFUTED when evidence exists on the matching side — a bare numeric claim never qualifies.

store = BeliefStore()
state = BeliefState(mission_id="m1")
hid = state.add_hypothesis("SMB signing disabled", target="10.0.0.5")
state.register_evidence(hid, EvidenceObservation(
    evidence_ref="ev:nmap:10.0.0.5:abc123:ts",
    polarity=EvidencePolarity.SUPPORTING, weight=0.8))
store.upsert(state)

Implementation note: config.yaml carries outcome_judgment.confirmation_threshold/refutation_threshold/min_evidence_references/max_inconclusive_attempts (config.yaml:343-347) and memory.experience_time_decay_days (config.yaml:342); the exact call sites reading those keys were not re-verified here.


Evidence store lifecycle (evidence/store.py, evidence/reference.py, evidence/provenance.py)

Immutable, content-addressed references plus DAG lineage. EvidenceStoreV2.put is idempotent: same (source_tool, target, content_hash) returns the existing id.

SymbolKindLineDescription
EvidenceStoreV2.put(ref)defstore.py:28Store, return ref_id (existing id on dedup)
EvidenceStoreV2.get(ref_id)defstore.py:41Fetch or None
EvidenceStoreV2.list_all()defstore.py:46Insertion order
EvidenceStoreV2.find_by_source_tool(tool)defstore.py:51Filter by producing tool
EvidenceStoreV2.find_by_target(target)defstore.py:56Filter by target
EvidenceStoreV2.count()defstore.py:61Number stored
EvidenceReference.create(source_tool, target, timestamp, content, ...)classmethodreference.py:71Build with deterministic ref_id (sha256 hex [:16] of source_tool|target|timestamp|content_hash)
EvidenceReference.from_dict / to_dictdefreference.py:107Tolerant round-trip
EvidenceReference.hash_content(content)staticreference.py:142sha256 hex digest
EvidenceReference.normalize(excerpt)staticreference.py:147Collapse whitespace, strip controls, trim to MAX_EXCERPT_LEN = 500
ProvenanceTracker.register_root(...)defprovenance.py:135Root evidence (no parent)
ProvenanceTracker.register_derived(parent_id, child_id, ...)defprovenance.py:165Attach derived; ValueError on self-parent or unknown parent
ProvenanceTracker.chain_for(evidence_id)defprovenance.py:205Chain or None
ProvenanceChain.lineage(evidence_id)defprovenance.py:50Root → id path, or []
ProvenanceChain.confidence_at(evidence_id)defprovenance.py:66Product of hop confidences; unknown id → 0.0

EvidenceSource (reference.py:23): tool_output, banner, scanner, nvd_cve, exploit_db, manual, agent_observation, http_response, file_artifact, screenshot, note, target_side_oracle. EvidenceLevel (reference.py:40): raw, derived, summarized.

store = EvidenceStoreV2()
ref = EvidenceReference.create("nmap", "10.0.0.5", "2026-09-07T00:00:00Z", "<scan xml>")
ref_id = store.put(ref)  # second put of identical content returns the same ref_id

Graph merge and traversal (graph/store.py, graph/merge.py, graph/traversal.py, graph/types.py)

AttackGraphStore(db_path, scope="") (store.py:93) is SQLite-backed with UNIQUE(scope, node_type, value) dedup; values are case-folded for IP/HOST/DOMAIN/ASSET/ENDPOINT. upsert_node merges (max confidence, summed observation_count, order-preserving evidence-ref union); upsert_edge raises ValueError on a missing endpoint; delete_node cascades manually to touching edges.

SymbolKindLineDescription
AttackGraphStore.upsert_node(node)defstore.py:192Insert/merge, return node_id
AttackGraphStore.get_node(node_id)defstore.py:245Fetch or None
AttackGraphStore.get_node_by_value(node_type, value, scope="")defstore.py:251Same normalization as upsert
AttackGraphStore.upsert_edge(edge)defstore.py:263Insert/merge; ValueError if endpoint missing
AttackGraphStore.query_nodes(scope, node_type, status, value_substring, limit=200)defstore.py:323Filtered, bounded
AttackGraphStore.query_edges(scope, edge_type, source_id, target_id, limit=200)defstore.py:349Filtered, bounded
AttackGraphStore.summary()defstore.py:496Counts by type + totals
GraphMergeEngine(store).apply(graph_update)defmerge.py:54Nodes first, then edges; returns list[GraphMergeConflict], conflicting mutations skipped
GraphMergeEngine(store).preview(update)defmerge.py:80Dry run, no mutation
GraphTraversal(nodes, edges).neighbors(node_id, relation=None, max_hops=1, max_nodes=50)deftraversal.py:65Bounded BFS, (node, edge, distance) in discovery order
GraphTraversal(nodes, edges).paths(start, end, max_length=4, max_paths=10)deftraversal.py:106Simple paths, cycle-safe
GraphTraversal(nodes, edges).path_exists(a, b, max_hops=3)deftraversal.py:151Boolean over paths
GraphTraversal(nodes, edges).subgraph(node_ids, max_distance=1)deftraversal.py:159(nodes, internal_edges, boundary_edges)

Conflict rules (merge.py:88-111, tolerance _CONFIDENCE_TOLERANCE = 0.2): same value as different node types; CONFIRMED → REFUTED without evidence_refs; confidence swing beyond tolerance without evidence_refs. Merge key is (scope, value) with case-folding.

engine = GraphMergeEngine(store)
conflicts = engine.apply(GraphUpdate(node_updates=[node], edge_updates=[edge], source_agent="recon"))
if conflicts:
    preview = engine.preview(update)  # inspect without mutating

Schema validator lifecycle (schemas/base.py, schemas/validator.py)

Every schema follows validate → repair once → coerce/fallback, with telemetry on every load.

SymbolKindLineDescription
BaseSchema.validate(raw)abstractbase.py:83ValidationResult{valid, errors, repaired, message}
BaseSchema.repair(raw, errors)abstractbase.py:86Best-effort fixed copy
BaseSchema.coerce(raw)abstractbase.py:90Typed object; ValueError only when repair failed
BaseSchema.safe_load(raw)defbase.py:94Never raises: (object, result) or (None, result)
extract_json_block(text)defvalidator.py:15First balanced {…}/[…] block, fence-tolerant, None if absent
parse_json_block(text)defvalidator.py:63Extract + json.loads, None on failure
SafeSchemaLoader(validator, default_factory, schema_name).load(raw_json_str)defvalidator.py:82Extract → parse → validate → repair once → coerce/default; always log_validation
log_validation / dump_telemetrydefbase.py:28In-memory telemetry (+ optional JSONL path)
_safe_enum / _require_str / _clamp_floathelperbase.py:47Shared coercion primitives

Repair defaults (fail-safe, never toward certainty): graph mutation → update_confidence (GRAPH_MUTATIONS, graph.py:9); outcome verdict → unknown (OUTCOME_VERDICTS, outcome.py:9); planner status → open (PLANNER_STATUSES, planner.py:10, statements capped at MAX_STATEMENT_LEN = 500); critic decision → modify (CRITIC_DECISIONS, critic.py:9); strategy list fields → [] (REQUIRED_LIST_FIELDS, strategy.py:9). Confidence always clamped to [0,1].

loader = SafeSchemaLoader(CriticReviewSchema(), default_factory=lambda: CriticReview(decision="modify"), schema_name="critic")
review, result = loader.load(llm_text)  # never raises; result.repaired flags the repair path

Config keys

KeyDefaultConsumer
outcome_judgment.confirmation_threshold / refutation_threshold / min_evidence_references / max_inconclusive_attempts0.75 / 0.75 / 1 / 3 (config.yaml:343-347)OutcomeJudge via tools/exploit_agent/outcome_adapter.py:336 — Flow A judgment, not the v2 belief/ thresholds
memory.experience_time_decay_days90 (config.yaml:342)Experience-store decay; belief/confidence.py has no time-decay reader
agent.max_retries_per_task2 (config.yaml:520)Campaign per-module failure cap (tools/campaign/orchestrator.py:182), not the fingerprint tracker
No dedicated intelligence.* blockIntelligence is library-only; callers wire config explicitly

Implementation note: the pre-existing table mapped these keys to belief/* internals; the consumers above are what the grep verified. The v2 belief thresholds (CONFIRMED_THRESHOLD = 0.75, REFUTED_THRESHOLD = 0.25 in confidence.py) are module constants.

Tests

FileCovers
tests/test_intelligence_belief.pyHypothesisState/BeliefState thresholds + transitions
tests/test_intelligence_evidence.pyEvidenceReference/EvidenceStoreV2/ProvenanceTracker
tests/test_intelligence_evidence_adversarial.pySecret redaction, hash collision
tests/test_intelligence_fingerprint.pyAttempt.fingerprint, RetryJustifier, is_permanent_failure
tests/test_intelligence_fingerprint_adversarial.pyMasqueraded secrets + replay
tests/test_intelligence_graph_store.pyAttackGraphStore CRUD + neighbors/paths
tests/test_intelligence_graph_store_adversarial.pyDuplicate value norm, conflict merge
tests/test_intelligence_graph_types.pyGraphNode/GraphEdge ser/deser + redact
tests/test_intelligence_schemas.pyAll schemas validate/repair/coerce
tests/test_intelligence_schemas_adversarial.pyMalformed JSON block + overflow
tests/test_intelligence_adapter_planner.pyPlannerAdapter score↔confidence
tests/test_intelligence_adapter_graph.pyTargetGraphV2Adapter
tests/test_intelligence_adapter_finding.pyFindingAdapter dedupe
tests/test_intelligence_adapter_memory.pyMemoryAdapter grading
tests/test_intelligence_adapter_observer.pyObserverAdapter classify
tests/test_intelligence_adapter_adversarial.pyunsupported_confidence, AttackPhaseBridge unknown-input, idempotent wiring
tests/test_bel_adversarial.pyBelief thresholds under adversarial drift

Source map

  • tools/intelligence/__init__.py
  • tools/intelligence/belief/state.pyHypothesisStatus, EvidencePolarity, EvidenceObservation, HypothesisState, BeliefState
  • tools/intelligence/belief/confidence.pyConfidenceCalculator, DeterministicUpdater, compute_status, NonModelConfidence
  • tools/intelligence/belief/store.pyBeliefStore
  • tools/intelligence/evidence/reference.pyEvidenceSource, EvidenceLevel, EvidenceReference
  • tools/intelligence/evidence/store.pyEvidenceStoreV2
  • tools/intelligence/evidence/provenance.pyProvenanceEntry, ProvenanceChain, ProvenanceTracker
  • tools/intelligence/fingerprint/attempt.pyAttemptStatus, ActionFamily, Attempt, RetryJustification, RetryJustifier, mask_secrets
  • tools/intelligence/fingerprint/tracker.pyAttemptTracker, PERMANENT_FAILURE_MARKERS, is_permanent_failure
  • tools/intelligence/graph/types.pyNodeType, EdgeType, NodeStatus, GraphNode, GraphEdge, GraphUpdate, redact_properties, make_evidence_ref
  • tools/intelligence/graph/store.pyAttackGraphStore
  • tools/intelligence/graph/merge.pyGraphMergeEngine, GraphMergeConflict, GraphMergeError
  • tools/intelligence/graph/traversal.pyGraphTraversal
  • tools/intelligence/schemas/base.pyBaseSchema, ValidationResult, log_validation, dump_telemetry
  • tools/intelligence/schemas/validator.pyextract_json_block, parse_json_block, SafeSchemaLoader
  • tools/intelligence/schemas/graph.pyGraphMutationProposal, GraphMutationSchema
  • tools/intelligence/schemas/outcome.pyOutcomeAssessment, OutcomeAssessmentSchema
  • tools/intelligence/schemas/planner.pyPlannerProposal, CandidatePath, HypothesisUpdate + schemas
  • tools/intelligence/schemas/critic.pyCriticReview, CriticReviewSchema
  • tools/intelligence/schemas/strategy.pyStrategyReview, StrategyReviewSchema
  • tools/intelligence/adapters/planner_adapter.pyPlannerAdapter, AttackPhaseBridge
  • tools/intelligence/adapters/finding_adapter.pyFindingAdapter
  • tools/intelligence/adapters/memory_adapter.pyMemoryAdapter
  • tools/intelligence/adapters/observer_adapter.pyObserverAdapter
  • tools/intelligence/adapters/target_graph_adapter.pyTargetGraphV2Adapter
  • tools/api/graph_service.py — WebUI wrapper over graph/
  • tools/api/graph_builder.py — DAG builder over graph/
  • tools/killchain/machine.pyAttackGraphStore killchain consumer
  • tools/campaign/executor.pyAttackPhaseBridge.to_orchestrator consumer
  • legacy/observer.pyObserverAdapter legacy consumer
  • legacy/finding_verifier.pyFindingAdapter legacy consumer
source: repo docs (build sync)Edit this page on GitHub →