Skip to main content

Retrieval

Retrieval is where Kindling earns its keep: getting the right context back out, predictably. It is mechanical and explainable — full-text search over what you actually stored, with a fixed ranking order and provenance on every result. There are no embeddings and no opaque relevance model.

The three tiers

A single retrieval returns results in three tiers, always in this order:

  1. Pins — user-marked priority items. Non-evictable; always first.
  2. Current summary — the active session/capsule summary, when one applies.
  3. Candidates — ranked full-text search hits over observations and summaries.
kindling search "authentication token"

├─ Pins (always returned, never evicted)
├─ Current Summary (active context, if present)
└─ Candidates (ranked FTS hits, with scores + provenance)

Pins

Pins are how you guarantee something is always surfaced. Pin an observation or a summary by ID:

kindling pin observation <id> --note "root cause — keep handy"
kindling pin summary <id>
kindling unpin <pin-id>

A pin may carry a --note explaining why it matters and an optional --ttl (in milliseconds) after which it expires.

Current summary

When a relevant capsule has a summary (produced on close), it is returned as the current summary — the distilled conclusion of an episode of work, surfaced ahead of raw observations.

Candidates

Everything else is ranked full-text search over observation and summary content, backed by SQLite FTS5. Each candidate carries a relevance score in the range 0.0–1.0 and an optional matchContext snippet showing why it matched.

Redacted observations are excluded by default. Programmatic retrieve calls can set includeRedacted: true to include them.

Result shape

interface RetrieveResult {
pins: { pin: Pin; target: Observation | Summary }[];
currentSummary?: Summary;
candidates: {
entity: Observation | Summary;
score: number;
matchContext?: string;
}[];
provenance: {
query: string;
scopeIds: ScopeIds;
totalCandidates: number;
returnedCandidates: number;
truncatedDueToTokenBudget: boolean;
providerUsed: string;
};
}

The provenance block makes every retrieval auditable: the exact query and scope used, how many candidates matched versus were returned, and which provider served the request.

Searching from the CLI

# Basic search
kindling search "authentication error"

# Narrow by scope
kindling search "auth" --session s-1 --repo ./my-project

# Cap the number of candidates (default 10)
kindling search "auth" --max 5

Human output groups results by tier:

Search Results for: "authentication error"
==================================================

Pins (1):

1. [PIN] 9c20…
Type: observation
Content: JWT validation failed: token expired
Note: root cause — keep handy

Candidates (2):

1. 5f1c… (score: 0.83)
Type: observation
Content: auth middleware rejects valid tokens after the upgrade
Time: 2026-06-20 10:31:04

Add --json for the full structured RetrieveResult, including scores and provenance.

Why mechanical retrieval

You should be able to find exactly what you stored, and understand why each result came back. Deterministic ranking plus provenance means results are reproducible and debuggable — important when an AI agent is consuming them as context rather than a human eyeballing a list.

Next