Files
cleveragents-core/docs/api/decisions.md
T

11 KiB
Raw Blame History

Decision Recording and Tree API (v3.2.0)

The decision subsystem records every choice point during a plan's Strategize and Execute phases as a persistent tree of Decision nodes. This page documents the CLI commands and Python API for inspecting and navigating that tree.


Overview

During the Strategize phase, the strategy actor records each significant choice as a Decision node. Decisions are linked parent-to-child to form a tree rooted at the prompt_definition node (the original plan prompt). The tree is persisted to SQLite via DecisionRepository and can be queried at any time — even after the plan has completed.

Key capabilities introduced in v3.2.0:

  • Automatic decision recording for every strategy and execution choice.
  • Context snapshots (SHA-256 hash + storage pointer) captured alongside each decision.
  • Alternatives-considered tracking for every decision node.
  • Full tree rendering via agents plan tree.
  • Per-decision explanation via agents plan explain.

CLI Reference

agents plan tree

Display the decision tree for a plan.

agents plan tree <PLAN_ID> [OPTIONS]

Options:

Flag Description
--format, -f Output format: json, yaml, plain, table, rich (default: rich)
--show-superseded Include superseded decisions in the tree
--depth Maximum tree depth to render (0 = unlimited, default: 0)

Examples:

# Default rich tree view
agents plan tree 01HXYZ1234567890ABCDEFGH

# Table format
agents plan tree 01HXYZ1234567890ABCDEFGH --format table

# Include superseded decisions (e.g. after a correction)
agents plan tree 01HXYZ1234567890ABCDEFGH --show-superseded

# Limit depth to 2 levels
agents plan tree 01HXYZ1234567890ABCDEFGH --depth 2

# JSON output for scripting
agents plan tree 01HXYZ1234567890ABCDEFGH --format json

Rich output renders an indented tree with decision type labels, sequence numbers, and full 26-character ULIDs so that IDs can be copied directly into follow-up commands such as agents plan explain or agents plan correct.


agents plan explain

Show full details for a single decision node, including alternatives considered, context snapshot, and actor reasoning.

agents plan explain <DECISION_ID> [OPTIONS]

Options:

Flag Description
--format, -f Output format: json, yaml, plain, table, rich
--show-context Include context snapshot details (hash, storage ref, resources)
--show-reasoning Include rationale and raw actor reasoning trace

Alternatives considered are always included in the output regardless of flags.

Examples:

# Default rich output
agents plan explain 01HXYZ1234567890ABCDEFGH

# JSON with full context snapshot
agents plan explain 01HXYZ1234567890ABCDEFGH --format json --show-context

# Show actor reasoning trace
agents plan explain 01HXYZ1234567890ABCDEFGH --show-reasoning

# YAML with all details
agents plan explain 01HXYZ1234567890ABCDEFGH --format yaml \
  --show-context --show-reasoning

Decision Data Model

Each decision node stores the following fields.

Identity

Field Type Description
decision_id ULID Auto-generated unique identifier
plan_id ULID Parent plan
parent_decision_id ULID | None Parent node; None for the root
sequence_number int Monotonic order within the plan (0-indexed, never reused)

Classification

Field Type Description
decision_type DecisionType One of 11 enum values (see table below)

Decision types:

Type Phase Description
prompt_definition Strategize Root decision — the plan prompt
invariant_enforced Strategize An invariant constraint was applied
strategy_choice Strategize High-level approach chosen
implementation_choice Execute How to implement a specific task
resource_selection Execute Which resources to read / modify
subplan_spawn Strategize Decision to create a child plan
subplan_parallel_spawn Strategize Spawn a group of child plans in parallel
tool_invocation Execute Which skill / tool to use
error_recovery Execute How to handle a failure
validation_response Execute Response to a validation failure
user_intervention Any User-provided guidance / correction

Content

Field Type Description
question str What question was being answered
chosen_option str The option that was selected
alternatives_considered list[str] Other options that were evaluated
confidence_score float | None 0.01.0 confidence, or None

Context Snapshot

Every decision captures a ContextSnapshot for replay and correction:

Field Type Description
hot_context_hash str SHA-256 hash of the context window at decision time
hot_context_ref str Storage pointer to the full serialised context
relevant_resources list[ResourceRef] Resources in scope at decision time
actor_state_ref str LangGraph actor checkpoint reference

Rationale

Field Type Description
rationale str Human-readable explanation
actor_reasoning str | None Raw LLM reasoning trace

Downstream Impact

Field Type Description
downstream_decision_ids list[ULID] Decisions that depend on this one
downstream_plan_ids list[ULID] Child plans spawned from this decision
artifacts_produced list[ArtifactRef] Artifacts created by this decision

Correction Metadata

Field Type Description
is_correction bool True if this decision corrects another
corrects_decision_id ULID | None Original decision being corrected
correction_reason str | None Why the correction was made
superseded_by ULID | None Decision that replaced this one

Tree Structure

Decisions form a tree via parent_decision_id:

prompt_definition (root, parent=None)
├── invariant_enforced
├── strategy_choice
│   ├── implementation_choice
│   │   ├── resource_selection
│   │   └── tool_invocation
│   └── subplan_spawn
└── strategy_choice

The prompt_definition type is always the root and must have parent_decision_id = None. The current tree consists of all decisions where superseded_by IS NULL. Superseded decisions are hidden by default in agents plan tree but can be shown with --show-superseded.


Decision Persistence

Decisions are persisted to SQLite via DecisionRepository in the cleveragents.infrastructure.database package. The service layer (DecisionService) supports two modes:

Mode UnitOfWork Storage
In-memory None Internal dicts
Persisted provided SQLite via DecisionRepository + in-memory write-through cache

When a UnitOfWork is wired, mutations are written to the database first, then the in-memory cache is updated (write-through).

Python API — recording a decision:

from cleveragents.application.services.decision_service import DecisionService
from cleveragents.domain.models.core.decision import DecisionType

svc = DecisionService(unit_of_work=uow)

decision = svc.record_decision(
    plan_id="01HV...",
    decision_type=DecisionType.STRATEGY_CHOICE,
    question="Which approach should we take?",
    chosen_option="Build a REST API",
    alternatives_considered=["GraphQL API", "gRPC service"],
    confidence_score=0.85,
    rationale="REST is simpler and better supported by existing tooling.",
)

Python API — retrieving the tree:

# BFS from root(s), level by level
tree = svc.get_tree(plan_id="01HV...")

# Walk from a decision up to the root
path = svc.get_path_to_root(decision_id="01HXYZ...")

# List all decisions for a plan, ordered by sequence number
decisions = svc.list_decisions(plan_id="01HV...")

See Also

Invariant Management API (v3.2.0)

Invariants are natural-language constraints that govern plan execution. They are evaluated at the start of the Strategize phase by the Invariant Reconciliation Actor and recorded in the decision tree as invariant_enforced nodes.


Overview

Invariants introduced in v3.2.0 provide a declarative way to constrain what a plan may do. They are scoped (global, project, action, or plan), merged by precedence, and de-duplicated before enforcement. Violations block the phase transition and emit INVARIANT_VIOLATED events.

Key capabilities:

  • Four scope levels: GLOBAL, PROJECT, ACTION, PLAN.
  • Merge precedence: plan > project > global (action invariants are promoted to plan scope).
  • Automatic enforcement at every phase transition via InvariantReconciliationActor.
  • CLI commands for adding, listing, and removing invariants.

CLI Reference

agents invariant add

Create a new invariant constraint.

agents invariant add <NAME> --description <DESC> [SCOPE_FLAG]

Scope flags:

Flag Scope Description
--global GLOBAL Applies to every plan in the system
--project <NAME> PROJECT Applies to plans targeting the named project
--plan <PLAN_ID> PLAN Attached directly to a specific plan
--action <ACTION> ACTION Defined in an action template; promoted on plan use

Examples:

# Global invariant
agents invariant add --global "Never delete production data"

# Project-scoped invariant
agents invariant add --project myapp "All API changes need tests"

# Plan-specific invariant
agents invariant add --plan 01HXYZ... "Use Python 3.13 only"

# Action-scoped invariant
agents invariant add --action local/code-coverage "Minimum 80% coverage"

agents invariant list

Display invariants, optionally filtered by scope or project.

agents invariant list [PATTERN] [OPTIONS]

Options:

Flag Description
--global Show only global invariants
--project <NAME> Show only invariants for the named project
--effective --project <NAME> Show the merged effective set for a project
--format, -f Output format: json, yaml, plain, table, rich