Skip to content

dart agent

Juwon1405 edited this page Jun 5, 2026 · 3 revisions

dart-agent · Senior-analyst loop

The wrapper loop that orchestrates the agent's reasoning. dart-agent is the only Python package in the project that contains control flow for the agent. The other four (dart_mcp, dart_corr, dart_audit, dart_playbook) are typed surfaces, helpers, or data.


What it owns

  • The senior-analyst loop (DeterministicAnalyst.run() in dart_agent/src/dart_agent/__init__.py)
  • Two execution modes: deterministic and live
  • Hypothesis state machine (v1v2 → ... with confidence scoring)
  • The serializer that refuses to emit a finding without audit_id citation

What it does not own

  • The forensic functions themselves — those live in dart-mcp
  • Cross-artifact joins — those live in dart-corr
  • The audit chain — that lives in dart-audit
  • Any sequencing rule — those live in dart-playbook YAML

The agent is deliberately small. The whole loop is under 800 lines.


The loop, in pseudocode

hypothesis = initial_hypothesis(case_metadata)
audit_chain = AuditLogger(case=case_id)

for iteration in range(max_iterations):
    next_call = decide_next_call(hypothesis, playbook)
    if next_call is None:
        break

    inputs = next_call.args
    output = call_tool(next_call.name, inputs)        # via dart-mcp
    audit_id = audit_chain.log(next_call.name, inputs, output, ...)

    contradictions = correlate(output, prior_state)    # via dart-corr
    if contradictions:
        hypothesis = revise(hypothesis, contradictions)

    if hypothesis.confidence >= 0.9:
        break

emit_findings(hypothesis, audit_chain)

Five things to notice:

  1. The agent never bypasses dart-mcp. It cannot call anything that isn't on the MCP function catalog.
  2. Every tool call is logged before the result is consumed. The audit chain is not best-effort — it is load-bearing.
  3. Correlation runs before hypothesis revision. The agent does not get to decide whether to look for contradictions; dart-corr always runs.
  4. Revision is mandatory if dart-corr flags UNRESOLVED. The agent cannot "ignore" a contradiction.
  5. Findings cannot be emitted without audit_ids. The serializer asserts this.

Modes

Deterministic

python3 -m dart_agent --case CASE-ID --evidence /mnt/case-evidence

Uses a scripted decision policy (in dart_agent/decision.py) that mimics what a senior analyst would call next given the current state. No external service. Suitable for CI, reproducibility checks, and air-gapped runs.

Live

export ANTHROPIC_API_KEY=sk-ant-...
python3 -m dart_agent --case CASE-ID --evidence /mnt/case-evidence --mode live

Connects an actual Claude model (default: claude-haiku-4-5) over JSON-RPC stdio MCP. The model picks the next call based on its judgment, but the surface is the same 47-native-function set, and the read-only / audit-chain guarantees still hold.

See Live-mode for the wire-level details.


Files

dart_agent/src/dart_agent/
├── __init__.py        # public entry point + DeterministicAnalyst class
│                      # (loop, hypothesis state machine, finding serializer
│                      #  all live here — the agent is small enough to keep
│                      #  its control flow in a single file)
├── __main__.py        # CLI (argparse)
└── live.py            # live-mode (MCP stdio + Claude API)

The DeterministicAnalyst class in __init__.py is the senior-analyst loop. Its run() method walks four phases (_phase_timeline_phase_hypothesis_phase_validate_usb_phase_finalize) and emits a report() dict at the end. The live.py module is a thin alternative entry point that wires DeterministicAnalyst over MCP stdio + Claude API instead of direct Python imports.


See also

Agentic-DART

Concepts

The 5 packages

Reference

Running it

Case studies

Project


Project links

Clone this wiki locally