Decision Guard

Checks changed files against this workspace's saved decisions — so an agent can't quietly contradict a call your team already made.

streampilot-demo-app Seeded demo data
Changed files
run a check
Decision-covered
of changed files
Conflicts
above threshold 0.50
Replay misses
run the replay audit

Run a check

threshold 0.50
Choose a change set
$ git diff --name-only | decision-guard
decision-guard · streampilot-demo-app

Results

No check run yet

Decision coverage

    Decisions are saved from real sessions; anchors point at the files they govern.

    Replay audit

    --replay

    Re-reads recent session transcripts and counts sessions that edited decision-covered files while the applicable decision never appeared in recalled context.

    Reads the last 6 transcripts from this workspace.

    CLI & porting notes

    README excerpt for decision-guard — run instructions, scoring, and the proposed Rust MCP contract.

    Run it

    # no install — runs against the workspace you're already signed into
    npx @contextstream/decision-guard src/hooks/useTodos.ts
    
    # or pipe a diff
    git diff --name-only | decision-guard
    
    # audit recent sessions for silent contradictions
    decision-guard --replay --sessions 6

    Flags

    --threshold <0..1>Conflict cutoff, default 0.50
    --replayAudit recent session transcripts
    --jsonMachine-readable conflicts, for hooks and CI

    Scoring & exit codes

    EvidenceWeight
    Exact path anchor1.00
    Directory anchor0.60
    Symbol / keyword0.35

    A file's score is its strongest anchor. Symbol evidence alone never raises a conflict — it appears as supporting context. Superseded decisions surface for context only and never affect the exit code.

    Exit codes

    0No active conflicts
    1At least one active conflict
    2Check failed — bad input or workspace unreachable

    Sample caught conflict

    What the seeded Toggle refactor scenario prints:

    ✖ ACTIVE CONFLICT  src/hooks/useTodos.ts
      decision   DEC-208 · Todo toggle uses optimistic UI
      saved      2026-06-30
      rationale  Update local state immediately; reconcile on response.
      anchor     src/hooks/useTodos.ts  (exact path · 1.00, threshold 0.50)
      status     active
    
     2 active · 1 likely · 1 superseded context · exit 1

    Known limitations

    Replay only counts a miss when recalled context exists for the session; transcripts without recall data are excluded and reported separately, never guessed.

    Port to the Rust MCP server

    Proposed tool contract — the same call backs the CLI and the pre-edit hook, so they can't drift:

    tool check_change_against_decisions {
      input  { paths: string[], diff?: string }
      output { conflicts: Conflict[] }
    }
    
    struct Conflict {
      decision_id:    String,     // "DEC-208"
      title:          String,
      saved_at:       Date,
      rationale:      String,     // one line
      changed_path:   String,
      matched_anchor: String,
      match_type:     MatchType,  // ExactPath | Directory | Symbol
      score:          f32,        // conflict when ≥ 0.50
      superseded_by:  Option<String>,
    }

    Where the cs pre-edit hook calls it

    1. cs hook pre-edit fires before the agent mutates files, with the intended paths (or the parsed staged diff).
    2. The hook calls check_change_against_decisions(paths, diff?) on the MCP server.
    3. Active conflicts render as conflict cards in-session; the agent must continue explicitly or open the decision for review / supersession.
    4. Below-threshold and superseded matches annotate the session quietly — they never block.