コンテンツにスキップ

Circuit

The knowledge graph engine -- FSRS scheduling + NetworkX graph + propagation + sqlite-vec.

Circuit

Circuit(db_path: str | Path = DEFAULT_DB_PATH, plasticity: Plasticity | None = None, embedder: Embedder | None = None, read_only: bool = False)

The knowledge graph engine — FSRS scheduling + NetworkX graph + propagation.

Circuit is the main entry point for spikuit-core. It owns the database, the in-memory NetworkX graph, and exposes all operations that external layers (CLI, agents, sessions) need.

Example
circuit = Circuit(db_path="brain.db")
await circuit.connect()

neuron = Neuron.create("# Functor\n\nA mapping between categories.")
await circuit.add_neuron(neuron)

spike = Spike(neuron_id=neuron.id, grade=Grade.FIRE)
await circuit.fire(spike)

await circuit.close()

Parameters:

Name Type Description Default
db_path str | Path

Path to the SQLite database file.

DEFAULT_DB_PATH
plasticity Plasticity | None

Tunable learning parameters (uses defaults if None).

None
embedder Embedder | None

Embedding provider for semantic search (optional).

None

current_transaction property

current_transaction: SpikuitTransaction | None

Return the active transaction, if any. Adapter-only API.

graph property

graph: DiGraph

Direct access to the NetworkX graph (read-only use).

transaction async

transaction(*, tag: str | None = None, actor_id: str, actor_kind: ActorKind = 'agent') -> AsyncIterator[SpikuitTransaction]

Open an explicit changeset.

All mutations performed inside the block (in v0.7.0+ commits) are buffered as events and flushed atomically on exit. Raising an exception aborts the changeset.

Parameters:

Name Type Description Default
tag str | None

Caller-supplied label, e.g. "ingest:papers-2026".

None
actor_id str

Free-form identifier of who initiated the change.

required
actor_kind ActorKind

One of "human", "agent", "system".

'agent'

Raises:

Type Description
TransactionNestingError

If a transaction is already active on this Circuit (nested transactions are not supported in v0.7.0).

connect async

connect() -> None

Connect to DB and load the graph + FSRS cards into memory.

add_neuron async

add_neuron(neuron: Neuron) -> Neuron

Add a Neuron to the circuit.

Initializes an FSRS card and auto-embeds content if an embedder is configured.

Parameters:

Name Type Description Default
neuron Neuron

The neuron to add.

required

Returns:

Type Description
Neuron

The same neuron (pass-through for chaining).

remove_neuron async

remove_neuron(neuron_id: str) -> None

Soft-retire a neuron and cascade-retire its synapses.

The neuron row stays in the database with retired_at set, preserving FSRS state and history. Its vector row is physically deleted to keep ANN recall undegraded. Synapses touching the neuron are cascade-retired. A neuron.retire event plus one synapse.retire event per cascaded synapse are emitted in the current (or implicit) transaction.

add_quiz_item async

add_quiz_item(item: QuizItem) -> QuizItem

Persist a quiz item with neuron associations.

Parameters:

Name Type Description Default
item QuizItem

The quiz item to store. Must have at least one neuron in neuron_ids with the PRIMARY role.

required

Returns:

Type Description
QuizItem

The persisted QuizItem (with auto-generated ID if empty).

Raises:

Type Description
ValueError

If no primary neuron is specified.

get_quiz_items async

get_quiz_items(neuron_id: str, *, role: QuizItemRole | None = None, scaffold_level: ScaffoldLevel | None = None) -> list[QuizItem]

Get quiz items associated with a neuron.

Parameters:

Name Type Description Default
neuron_id str

The neuron to look up.

required
role QuizItemRole | None

Filter by role (primary/supporting). None = any role.

None
scaffold_level ScaffoldLevel | None

Filter by scaffold level. None = any level.

None

Returns:

Type Description
list[QuizItem]

List of matching QuizItems, newest first.

remove_quiz_item async

remove_quiz_item(item_id: str) -> None

Delete a quiz item by ID.

add_synapse async

add_synapse(pre: str, post: str, type: SynapseType, weight: float = 0.5, confidence: SynapseConfidence = SynapseConfidence.EXTRACTED, confidence_score: float = 1.0) -> list[Synapse]

Add a Synapse between two neurons.

Bidirectional types (contrasts, relates_to) automatically create the reverse edge as well.

Parameters:

Name Type Description Default
pre str

Source neuron ID.

required
post str

Target neuron ID.

required
type SynapseType

Connection semantics.

required
weight float

Initial edge weight (default 0.5).

0.5
confidence SynapseConfidence

Provenance tag (EXTRACTED, INFERRED, AMBIGUOUS).

EXTRACTED
confidence_score float

Confidence score (0.0–1.0, meaningful for INFERRED).

1.0

Returns:

Type Description
list[Synapse]

List of created synapses (1 for directed, 2 for bidirectional).

Raises:

Type Description
ValueError

If either neuron does not exist in the circuit.

remove_synapse async

remove_synapse(pre: str, post: str, type: SynapseType) -> None

Soft-retire a synapse and emit a retire event.

Bidirectional types retire both directions.

list_synapses async

list_synapses(neuron_id: str | None = None, type: SynapseType | None = None) -> list[Synapse]

List synapses, optionally filtered by neuron or type.

Parameters:

Name Type Description Default
neuron_id str | None

If given, return synapses where this neuron is pre or post.

None
type SynapseType | None

If given, filter to this synapse type.

None

Returns:

Type Description
list[Synapse]

List of matching synapses.

set_synapse_weight async

set_synapse_weight(pre: str, post: str, type: SynapseType, weight: float) -> Synapse

Set the weight of an existing synapse.

Parameters:

Name Type Description Default
pre str

Source neuron ID.

required
post str

Target neuron ID.

required
type SynapseType

Synapse type.

required
weight float

New weight value.

required

Returns:

Type Description
Synapse

The updated Synapse.

Raises:

Type Description
ValueError

If the synapse does not exist.

merge_neurons async

merge_neurons(source_ids: list[str], into_id: str) -> dict

Merge multiple neurons into a target neuron.

Content from source neurons is appended to the target. Synapses are redirected, source links transferred, and source neurons removed.

Parameters:

Name Type Description Default
source_ids list[str]

IDs of neurons to merge (will be deleted).

required
into_id str

ID of the target neuron (survives).

required

Returns:

Type Description
dict

Summary dict with merge statistics.

Raises:

Type Description
ValueError

If any neuron does not exist or into_id is in source_ids.

predecessors_of_lineage async

predecessors_of_lineage(neuron_id: str) -> list[str]

Return parent neuron IDs recorded when neuron_id absorbed them.

Adapter-only read API for AMKB L2 lineage conformance.

prune_retired async

prune_retired() -> dict[str, int]

Physically delete all soft-retired neurons and synapses.

Escape hatch for spkt history prune. Event log is preserved. Does not emit events — this is historical garbage collection, not a lifecycle transition.

upsert_meta_neuron async

upsert_meta_neuron(meta_id: str, content: str) -> Neuron

Create or replace a _meta domain neuron.

_meta neurons are auto-generated descriptions of the Brain itself. They participate in retrieve() but are excluded from due/fire.

Parameters:

Name Type Description Default
meta_id str

The neuron ID (e.g. "_meta:overview").

required
content str

Markdown content for the neuron.

required

Returns:

Type Description
Neuron

The created or updated Neuron.

clear_meta_neurons async

clear_meta_neurons() -> int

Remove all _meta domain neurons.

Returns:

Type Description
int

Number of neurons removed.

generate_manual async

generate_manual(*, write_meta: bool = False) -> dict

Generate a user guide for this Brain.

Returns a dict with domain overview, sample topics, knowledge cutoff, coverage notes, and source attribution. Optionally writes _meta neurons.

Parameters:

Name Type Description Default
write_meta bool

If True, upsert _meta neurons with manual content.

False

Returns:

Type Description
dict

Dict with keys: domains, cutoff, coverage, sources, neuron_count.

fire async

fire(spike: Spike) -> Card

Record a review event, update FSRS state, and propagate activation.

This is the central method for all review operations. The full pipeline is:

  1. Record spike to DB
  2. FSRS: update stability, difficulty, schedule next review
  3. APPNP: propagate activation to neighbors (pressure deltas)
  4. Reset source neuron pressure
  5. STDP: update edge weights based on co-fire timing
  6. Record last-fire timestamp for future STDP

Parameters:

Name Type Description Default
spike Spike

The review event to process.

required

Returns:

Type Description
Card

The updated FSRS Card with new scheduling state.

get_card

get_card(neuron_id: str) -> Card | None

Get the FSRS Card for a neuron (from in-memory cache).

due_neurons async

due_neurons(*, now: datetime | None = None, limit: int = 20) -> list[str]

Return neuron IDs that are due for review.

near_due_neurons async

near_due_neurons(*, days_ahead: int = 2, limit: int = 20, exclude_ids: set[str] | None = None, now: datetime | None = None) -> list[str]

Return neuron IDs whose next review is within days_ahead days but not yet due. Used by interleaving to pull near-due work from other domains without breaking FSRS optimality significantly.

get_pressure

get_pressure(neuron_id: str) -> float

Get the current LIF pressure for a neuron.

decay_pressure

decay_pressure(*, now: datetime | None = None) -> None

Apply LIF leak to all neuron pressures.

commit_retrieval_boosts async

commit_retrieval_boosts() -> None

Persist all in-memory retrieval boosts to DB.

retrieve async

retrieve(query: str, *, limit: int = 10, filters: dict[str, str] | None = None) -> list[Neuron]

Retrieve neurons matching a query with graph-weighted scoring.

Scoring formula::

score = max(keyword_sim, semantic_sim)
        × (1 + retrievability + centrality + pressure + boost)

semantic_sim uses sqlite-vec KNN when an embedder is configured; otherwise only keyword matching is used. boost is accumulated through QABotSession feedback.

Parameters:

Name Type Description Default
query str

Search query text.

required
limit int

Maximum number of results.

10
filters dict[str, str] | None

Key-value filters. type and domain filter on the neuron table; other keys filter on source filterable metadata. Strict semantics: neurons without the key are excluded.

None

Returns:

Type Description
list[Neuron]

List of matching neurons, sorted by score descending.

ensemble

ensemble(neuron_id: str, *, hops: int = 2) -> list[str]

Get the N-hop neighborhood of a neuron.

Parameters:

Name Type Description Default
neuron_id str

Center neuron.

required
hops int

Radius of the ego graph (default 2).

2

Returns:

Type Description
list[str]

List of neighbor neuron IDs (excluding the center).

neighbors

neighbors(neuron_id: str) -> list[str]

Direct successors (outgoing synapses).

predecessors

predecessors(neuron_id: str) -> list[str]

Direct predecessors (incoming synapses).

embed_all async

embed_all(*, batch_size: int = 32) -> int

Backfill embeddings for all neurons that don't have one yet.

Parameters:

Name Type Description Default
batch_size int

Number of texts to embed per API call.

32

Returns:

Type Description
int

Number of neurons newly embedded.

add_source async

add_source(source: Source) -> Source

Add a Source to the circuit.

Parameters:

Name Type Description Default
source Source

The source to persist.

required

Returns:

Type Description
Source

The same source (pass-through for chaining).

get_source async

get_source(source_id: str) -> Source | None

Get a source by ID.

attach_source async

attach_source(neuron_id: str, source_id: str) -> None

Link a source to a neuron (idempotent).

detach_source async

detach_source(neuron_id: str, source_id: str) -> None

Remove the link between a neuron and a source.

list_sources async

list_sources(*, limit: int = 100) -> list[Source]

List sources.

update_source async

update_source(source: Source) -> None

Update source fields (pass the modified Source object).

get_neurons_for_source async

get_neurons_for_source(source_id: str) -> list[str]

Get neuron IDs attached to a source.

get_meta_keys async

get_meta_keys() -> list[dict]

Get distinct filterable/searchable keys with counts.

get_meta_values async

get_meta_values(key: str) -> list[dict]

Get distinct values for a metadata key.

get_domain_counts async

get_domain_counts() -> list[dict]

Get domain names with neuron counts.

get_stale_sources async

get_stale_sources(stale_days: int) -> list

Get URL sources older than stale_days since last fetch.

rename_domain async

rename_domain(old: str, new: str) -> int

Rename all neurons with domain=old to domain=new.

merge_domains async

merge_domains(sources: list[str], target: str) -> int

Merge multiple domains into target.

detect_communities async

detect_communities(*, resolution: float = 1.0) -> dict[int, list[str]]

Run Louvain community detection and persist results.

Uses an undirected projection of the graph. Results are stored in the DB and loaded into NetworkX node data.

Parameters:

Name Type Description Default
resolution float

Louvain resolution parameter. Higher values produce more communities.

1.0

Returns:

Type Description
dict[int, list[str]]

Mapping of community_id → list of neuron IDs.

get_community

get_community(neuron_id: str) -> int | None

Get the community ID for a neuron (from in-memory graph).

community_map

community_map() -> dict[str, int]

Return a mapping of neuron_id → community_id for all assigned neurons.

generate_community_summaries async

generate_community_summaries() -> list[dict]

Generate summary neurons for each community.

For each community, creates a community_summary neuron with member titles and domain info, linked to members via summarizes synapses. Replaces existing summaries on re-run.

Returns:

Type Description
list[dict]

List of dicts with summary neuron info per community.

consolidate async

consolidate(*, decay_factor: float = 0.8, weight_floor: float | None = None, similarity_threshold: float = 0.85, domain: str | None = None) -> dict

Generate a consolidation plan (dry-run).

Biologically-inspired 4-phase consolidation: 1. SWS (Replay): Discover latent synapses via embedding similarity 2. SHY (Downscaling): Decay weights, identify prunable synapses 3. REM (Interference): Detect near-duplicate neurons 4. Triage: Flag low-value neurons as forget candidates

Parameters:

Name Type Description Default
decay_factor float

Multiply all synapse weights by this (SHY phase).

0.8
weight_floor float | None

Prune synapses below this. Defaults to plasticity.weight_floor.

None
similarity_threshold float

Cosine similarity threshold for latent synapses / duplicates.

0.85
domain str | None

Optional domain filter (TMR-inspired targeted consolidation).

None

Returns:

Type Description
dict

A consolidation plan dict with actions and state_hash.

apply_consolidation async

apply_consolidation(plan: dict) -> dict

Apply a consolidation plan. Validates state hash first.

Parameters:

Name Type Description Default
plan dict

A plan dict from consolidate().

required

Returns:

Type Description
dict

Summary of applied actions.

Raises:

Type Description
ValueError

If the current graph state doesn't match the plan's hash.

stats async

stats() -> dict[str, object]

Overview statistics.

diagnose async

diagnose(*, weak_synapse_threshold: float = 0.2) -> dict

Run read-only brain health diagnostics.

Returns a structured dict with all health metrics: orphans, weak_synapses, domain_balance, community_cohesion, bridge_gaps, dangling_prerequisites, source_freshness, surprise_bridges.

domain_audit async

domain_audit() -> dict

Analyze domain ↔ community alignment and suggest actions.

Compares the user-assigned domain labels against the graph's natural community structure (Louvain) to find mismatches:

  • split: a domain spans multiple communities → suggest sub-domains
  • merge: multiple domains converge in one community → suggest merging
  • rename: keyword extraction hints at a better name

Returns a dict with domain_map, community_map, suggestions[].

progress async

progress(*, domain: str | None = None) -> dict

Generate a learner-focused progress report.

Returns per-domain mastery, retention rate, learning velocity, weak spots, and review adherence.