SmartMemory
Concepts

Decision Memory

Part of the expertise layer. Read the overview →

SmartMemory tracks decisions as first-class memory objects with confidence scoring, provenance chains, and lifecycle management. Decisions capture not just what was decided, but why and how confident the system is.

Why Decision Memory Matters

Agents and users make decisions constantly. Without tracking them:

  • The same decision gets re-evaluated repeatedly
  • Contradictory decisions go unnoticed
  • There's no audit trail for "why did we choose X?"

Decision Memory solves this by storing decisions with full provenance, confidence scoring, and conflict detection.

Decision Types

TypeDescriptionExample
inferenceConclusion drawn from evidence"The performance issue is caused by N+1 queries"
preferenceStated or detected preference"User prefers dark mode for coding"
classificationCategorization of something"This issue is a security vulnerability"
choiceExplicit selection between options"We chose PostgreSQL over MySQL"
beliefHeld belief or conviction"Microservices are overused for small teams"
policyRule or guideline to follow"Always write tests before implementation"

Lifecycle

Decisions follow a lifecycle:

graph LR
    A[Created] --> B[Active]
    B --> C[Superseded]
    B --> D[Retracted]
    B --> B
  • Active: Current, valid decision
  • Superseded: Replaced by a newer decision (linked via SUPERSEDES edge)
  • Retracted: Withdrawn, no longer valid

Confidence Scoring

Each decision has a confidence score (0.0–1.0) that evolves over time:

from smartmemory.models.decision import Decision

decision = Decision(
    content="PostgreSQL is better for our use case",
    decision_type="choice",
    confidence=0.8
)

# Supporting evidence increases confidence (diminishing returns)
decision.reinforce("benchmark_result_id")
# confidence: 0.8 → 0.82

# Contradicting evidence decreases confidence (15% penalty)
decision.contradict("mysql_benchmark_id")
# confidence: 0.82 → 0.697

Automatic Decay

The DecisionConfidenceEvolver applies time-based decay:

  • Decisions inactive for 30+ days start losing confidence (5% per cycle)
  • Decisions below 0.1 confidence are automatically retracted
  • Recently reinforced decisions are protected from decay

Belief & Contest (Dempster-Shafer)

The single confidence scalar can't distinguish a contested decision (strong support and strong contradiction) from an unevidenced one — both look like "medium confidence". SmartMemory adds Dempster-Shafer evidence belief over the frame {hold, retract} to separate them:

FieldMeaning
belief_holdcommitted lower bound that the decision should stand
plausibility_holdupper bound (adds the ignorance band)
ignorancehow much is genuinely unknown (no evidence either way)
contesthow disputed the decision is — high only when support and contradiction are both strong

contest is included in decision API responses (so SDK/UI consumers get it without recomputation); the belief reads are computed properties. A decision with 3 supporting and 3 contradicting pieces of evidence reports contest ≈ 0.77 while an untouched decision reports contest = 0.0 — even though both show the same stability. See the decision belief contract.

Creating Decisions

Programmatic

from smartmemory.decisions.manager import DecisionManager

manager = DecisionManager(smart_memory)

decision = manager.create(
    content="We should use Redis for caching",
    decision_type="choice",
    confidence=0.85,
    domain="infrastructure",
    tags=["caching", "architecture"],
    evidence_ids=["benchmark_123", "analysis_456"],
)

Via Maya Commands

/decide We should use Redis for caching
/decide I prefer Python for backend work
/decide Always run tests before deploying

Via Extraction

The DecisionExtractor detects decisions in natural text:

from smartmemory.plugins.extractors.decision import DecisionExtractor

extractor = DecisionExtractor()
result = extractor.extract("""
I decided to use PostgreSQL for the new project.
I believe microservices are overkill for our team size.
We should always write integration tests for API endpoints.
""")

# result['decisions'] contains 3 detected decisions:
# - choice: "use PostgreSQL for the new project"
# - belief: "microservices are overkill for our team size"
# - policy: "always write integration tests for API endpoints"

It also extracts from reasoning traces:

from smartmemory.models.reasoning import ReasoningTrace

trace = ReasoningTrace(steps=[...])
decisions = extractor.extract_from_trace(trace)
# Decisions linked to the trace via PRODUCED edge

Querying Decisions

List Active Decisions

from smartmemory.decisions.queries import DecisionQueries

queries = DecisionQueries(smart_memory)

# All active decisions
decisions = queries.get_active_decisions()

# Filtered by domain and type
decisions = queries.get_active_decisions(
    domain="infrastructure",
    decision_type="choice",
    min_confidence=0.7,
)

Search by Topic

decisions = queries.get_decisions_about(topic="database")

Maya Commands

/beliefs                  # List all active decisions
/beliefs databases        # Search decisions about databases
/why PostgreSQL           # Explain why a decision was made

Provenance Chains

Every decision tracks its origin:

provenance = queries.get_decision_provenance(decision_id)

# Returns:
# {
#     "decision": Decision(...),
#     "reasoning_trace": ReasoningTrace(...) or None,
#     "evidence": [MemoryItem(...), ...],
#     "superseded": [Decision(...), ...],
# }

Causal Chains

Traverse cause-and-effect relationships:

chain = queries.get_causal_chain(
    decision_id,
    direction="both",   # "causes", "effects", or "both"
    max_depth=3,
)

# Returns:
# {
#     "decision": Decision(...),
#     "causes": [...],    # What led to this decision
#     "effects": [...],   # What this decision caused
# }

Conflict Detection

Find decisions that may contradict each other:

conflicts = manager.find_conflicts(decision)
# Candidate gate: semantic search + content-overlap heuristic.
# Results are ranked by pairwise contest severity (how confidently both decisions
# assert their contradictory claims), most-contested first.

# Drop weakly-held conflicts:
conflicts = manager.find_conflicts(decision, min_contest=0.3)

The REST route POST /memory/decisions/{id}/conflicts accepts the same min_contest query parameter.

Superseding Decisions

When a decision is replaced:

new_decision = Decision(
    content="Actually, MongoDB fits better for our document-heavy workload",
    decision_type="choice",
    confidence=0.9,
)

result = manager.supersede(
    old_decision_id,
    new_decision,
    reason="New benchmarks show MongoDB handles our access patterns better",
)
# Old decision marked as "superseded"
# SUPERSEDES edge created between new → old

Retracting Decisions

When a decision is no longer valid:

manager.retract(decision_id, reason="Requirements changed — JWT no longer needed")
# Decision status set to "retracted"
# Retracted decisions are excluded from active queries

Graduation from Plans

When a Plan completes, it can optionally graduate to a decision record — preserving the task decomposition as a permanent "we decided to do X" record:

from smartmemory.plans import PlanManager

plan_manager = PlanManager(memory)
result = plan_manager.create("Auth redesign", tasks=[...])

# ... tasks completed ...

# Graduate creates a decision with DERIVED_FROM edge back to plan
decision_id = plan_manager.complete(result["plan_id"], graduate=True)

The graduated decision has decision_type="choice", source_type="imported", and an evidence link to the original plan.

Graph Edges

Decision Memory introduces these edge types:

EdgeFrom → ToMeaning
PRODUCEDReasoningTrace → DecisionTrace generated this decision
DERIVED_FROMDecision → MemoryDecision based on this evidence
SUPERSEDESDecision → DecisionNew decision replaces old
CONTRADICTSDecision → DecisionDecisions conflict
INFLUENCESDecision → MemoryDecision affects other memories

Configuration

DecisionExtractor

from smartmemory.plugins.extractors.decision import DecisionExtractorConfig

config = DecisionExtractorConfig(
    min_confidence=0.7,       # Minimum confidence for extracted decisions
    min_content_length=20,    # Minimum content length
)

DecisionConfidenceEvolver

from smartmemory.plugins.evolvers.decision_confidence import DecisionConfidenceConfig

config = DecisionConfidenceConfig(
    min_confidence_threshold=0.1,  # Auto-retract below this
    decay_after_days=30,           # Start decay after inactivity
    decay_rate=0.05,               # 5% confidence loss per cycle
    enable_decay=True,
)

REST API

Decision Memory is exposed via 12 endpoints at /memory/decisions/:

MethodPathDescription
POST/createCreate a decision
GET/List active decisions
GET/searchSearch by topic
GET/pendingList pending decisions
GET/{id}Get a decision
POST/{id}/supersedeReplace a decision
POST/{id}/retractRetract a decision
POST/{id}/reinforceAdd supporting evidence
POST/{id}/contradictAdd counter-evidence
GET/{id}/provenanceFull provenance chain
GET/{id}/causal-chainCausal traversal
POST/{id}/conflictsFind conflicts

On this page