Decisions

DecisionLog

The decisions ledger at ~/.cc-transcript/decisions.db.

Usage

Source

DecisionLog(actor)

Opened in WAL mode with a busy timeout because cc-review’s Go daemon writes the same file concurrently. Durable by convention: rows are never auto-dropped. Requires a local disk — WAL does not work over NFS.

Example

>>> log = await DecisionLog.open()
>>> async with log:
...     await log.append(decision)
...     await log.attribute_tool(session_id, tool_digest=digest, near_ts_ms=ts)

Methods

Name Description
attribute_nearest() The decision nearest near_ts_ms for a digestless event.
attribute_tool() The nearest decision preceding near_ts_ms with this digest.
open() Opens the exact v1 decision ledger at path.
attribute_nearest()

The decision nearest near_ts_ms for a digestless event.

Usage

Source

attribute_nearest(
    session_id, *, event, near_ts_ms, kind=None, window_ms=300000
)

The documented-probabilistic path for Stop, UserPromptSubmit, and Notification fires, which carry no tool digest: filters by event (and kind when given), then picks the smallest absolute timestamp distance within the window, on either side of near_ts_ms.

Returns
Decision | None

The nearest matching decision, or None when none lies in

[near_ts_ms - window_ms, near_ts_ms + window_ms].
attribute_tool()

The nearest decision preceding near_ts_ms with this digest.

Usage

Source

attribute_tool(session_id, *, tool_digest, near_ts_ms, window_ms=300000)

Joins by digest equality plus time window only — never by message text. Repeated identical calls share a digest, so in tight loops the nearest-preceding pick is probabilistic; prefer event_uuid to disambiguate when the row carries one.

Returns
Decision | None

The matching decision, or None when no digest-equal row lies in

[near_ts_ms - window_ms, near_ts_ms].
open()

Opens the exact v1 decision ledger at path.

Usage

Source

open(path=None)

Decision

One row of the decision ledger.

Usage

Source

Decision(
    ts_ms,
    session_id,
    source,
    kind,
    source_file,
    event,
    action,
    tool_name=None,
    tool_digest=None,
    event_uuid=None,
    message=None,
    detail=dict()
)

Attributes

ts_ms: int

Integer-millisecond timestamp of the decision; part of the UNIQUE key, so re-running a writer is exactly idempotent.

session_id: SessionId

The Claude session UUID the decision fired in.

source: str

The writing system, e.g. captain-hook or cc-review.

kind: str

The writer’s decision taxonomy, e.g. the hook name.

source_file: str

The file the deciding hook was registered from; "" when the writer has no file provenance.

event: str

The Claude Code event, e.g. PreToolUse or Stop.

action: Action

What the decision did: allow, block, warn, nudge, or note.

tool_name: str | None

The tool under decision, for tool-shaped events.

tool_digest: ToolDigest | None

The cross-language content digest of the tool call; the preferred attribution key.

event_uuid: EventUuid | None

The transcript entry uuid, when the writer knows it; the preferred disambiguator for repeated identical calls.

message: str | None

The user-visible decision text, if any.

detail: Mapping[str, Any]
Structured extras, serialized to detail_json.

Action

Action=Literal["allow", "block", "warn", "nudge", "note"]

DECISIONS_DDL

DECISIONS_DDL="CREATE TABLE cc_review_decisions_schema_v1 (    id INTEGER PRIMARY KEY CHECK (id = 1),    component TEXT NOT NULL CHECK (component = 'cc-review-decisions-v1'),    schema_version INTEGER NOT NULL CHECK (schema_version = 1),    ddl_fingerprint TEXT NOT NULL,    object_fingerprint TEXT NOT NULL);TABLE decisions (    id INTEGER PRIMARY KEY,    ts_ms INTEGER NOT NULL,    session_id TEXT NOT NULL,    source TEXT NOT NULL,    kind TEXT NOT NULL,    source_file TEXT NOT NULL,    event TEXT NOT NULL,    action TEXT NOT NULL CHECK (action IN ('allow', 'block', 'warn', 'nudge', 'note')),    tool_name TEXT,    tool_digest TEXT,    event_uuid TEXT,    message TEXT,    detail_json TEXT NOT NULL,    UNIQUE (session_id, ts_ms, source, kind, tool_digest));INDEX idx_decisions_session_ts ON decisions (session_id, ts_ms);INDEX idx_decisions_tool_digest ON decisions (tool_digest);INDEX idx_decisions_source_file ON decisions (source_file);TABLE dispatch_heartbeats (    session_id TEXT NOT NULL,    event TEXT NOT NULL,    first_ts_ms INTEGER NOT NULL,    last_ts_ms INTEGER NOT NULL,    count INTEGER NOT NULL,    PRIMARY KEY (session_id, event));INDEX idx_heartbeats_session ON dispatch_heartbeats (session_id);"