Library API
Polylogue is designed library-first. The CLI wraps the Python API.
The public Python surface is split into:
polylogue: archive-core access (Polylogue,SyncPolylogue,ArchiveStats,Session,Message,SearchResult)polylogue.archive: domain-model, query, projection, and semantic helpers- precise modules for higher-order semantic analysis, storage, and reporting
Basic Usage
import asyncio
from polylogue import Polylogue
async def main() -> None:
async with Polylogue.open() as archive:
# Full-text search (returns list[Session])
results = await archive.repository.search("error", limit=10)
for session in results:
print(f"{session.id}: {session.display_title}")
# Fluent filter by origin (lazy; terminals are async)
recent = await archive.filter().origin("claude-ai-export").limit(10).list_summaries()
for summary in recent:
print(f"{summary.id}: {summary.display_title}")
# Single session by id prefix
session = await archive.get_session("abc123")
asyncio.run(main())
Polylogue.open() is the async context manager; archive.repository is a
SessionRepository and archive.filter() returns a SessionFilter already
bound to the active archive — never construct SessionFilter directly.
Precise Module Imports
Semantic-analysis/reporting helpers are still public, but they are no longer re-exported from package roots. Import them from their actual modules:
from polylogue.archive.session.session_profile import build_session_profile, infer_auto_tags
from polylogue.archive.session.threads import build_session_threads
Durable archive insights are public too:
from polylogue import Polylogue
from polylogue.insights.archive import (
ArchiveCoverageInsightQuery,
ArchiveDebtInsightQuery,
SessionLatencyProfileInsightQuery,
SessionPhaseInsightQuery,
SessionProfileInsightQuery,
SessionTagRollupQuery,
)
async with Polylogue() as archive:
status = await archive.get_session_insight_status()
profiles = await archive.list_session_profile_insights(
SessionProfileInsightQuery(
provider="claude-code",
session_date_since="2026-03-16",
session_date_until="2026-03-16",
limit=25,
)
)
phases = await archive.list_session_phase_insights(
SessionPhaseInsightQuery(provider="claude-code", limit=25)
)
latency = await archive.list_session_latency_profile_insights(
SessionLatencyProfileInsightQuery(provider="claude-code", only_stuck=False, limit=25)
)
tags = await archive.list_session_tag_rollup_insights(
SessionTagRollupQuery(provider="claude-code", since="2026-01-01")
)
coverage = await archive.list_archive_coverage_insights(
ArchiveCoverageInsightQuery(provider="claude-code", group_by="day", since="2026-01-01")
)
debt = await archive.list_archive_debt_insights(
ArchiveDebtInsightQuery(only_actionable=True)
)
SessionProfileInsight exposes stable session semantics directly:
inferred_topicfirst_message_atcanonical_session_datetimestamp_sourceengaged_duration_msengaged_minutestool_active_duration_msworkflow_shapeworkflow_shape_confidenceterminal_stateterminal_state_confidenceenrichmentenrichment_provenancerepo_namesrepo_paths
SessionWorkEventInsight and SessionPhaseInsight expose timestamped timeline
rows that can be queried directly.
SessionLatencyProfileInsight exposes per-session runtime-shape signals:
median_tool_call_msp90_tool_call_msmax_tool_call_msstuck_tool_countmedian_agent_response_msmedian_user_response_mstool_call_count_by_category
The latency payload includes a construct-boundary string because these are archive-observed timing aggregates. They do not measure correctness, human attention, or total wall-clock productivity.
The merged SessionProfileInsight tier exposes probabilistic enrichment:
intent_summaryoutcome_summaryblockersconfidencesupport_levelsupport_signalsprovenance
The enrichment payload is intentionally folded into session profiles because it
is derived from the same per-session materialization row. Request
SessionProfileInsightQuery(tier="merged") when callers need both grounded
profile evidence and probabilistic enrichment in one payload.
Archive coverage and archive debt are public insights too:
ArchiveCoverageInsight: provider/day/week session, message, cost, and activity coverage rollupsArchiveDebtInsight: governed cleanup/repair debt with maintenance targets plus preview/apply/validation lineage
Filter Chain API
All examples below assume an open archive, where archive.filter() yields a
fresh SessionFilter bound to the active archive:
async with Polylogue.open() as archive:
# Chainable, lazy evaluation (terminals are async)
results = await (archive.filter()
.contains("error")
.contains("python") # AND
.origin("claude-ai-export", "chatgpt-export") # OR
.since("2025-01-01")
.has("thinking")
.limit(10)
.list()) # Terminal: await list(), first(), count(), delete()
# Exclusion filters
results = await (archive.filter()
.contains("error")
.exclude_text("warning")
.exclude_origin("gemini-cli-session")
.exclude_tag("archived")
.list())
# Lightweight summaries (no message loading)
summaries = await (archive.filter()
.origin("claude-ai-export")
.since("2025-01-01")
.list_summaries()) # Returns SessionSummary (no messages)
# Check if summaries are sufficient
f = archive.filter().origin("claude-ai-export")
if f.can_use_summaries():
results = await f.list_summaries() # Fast path
else:
results = await f.list() # Loads full sessions
# Custom predicates
results = await (archive.filter()
.where(lambda c: len(c.messages) > 50)
.list())
# Sorting and sampling
results = await (archive.filter()
.sort("tokens")
.reverse()
.sample(10)
.list())
# Session structure filters
roots = await archive.filter().is_root().list()
continuations = await archive.filter().is_continuation().list()
Available Filter Methods
| Method | Description |
|---|---|
.contains(text) |
FTS term (chainable = AND) |
.exclude_text(text) |
Exclude FTS term |
.origin(*names) |
Include origins (e.g. claude-ai-export, chatgpt-export) |
.exclude_origin(*names) |
Exclude origins |
.repo(*names) |
Require repository names |
.tag(*tags) |
Include tags |
.exclude_tag(*tags) |
Exclude tags |
.referenced_path(pattern) |
Require a touched-path substring |
.cwd_prefix(prefix) |
Require a working-directory prefix |
.action(*kinds) |
Require semantic action kinds |
.exclude_action(*kinds) |
Exclude semantic action kinds |
.tool(*names) |
Require normalized tool names |
.exclude_tool(*names) |
Exclude normalized tool names |
.has(*types) |
Content types: thinking, tools, summary, attachments |
.title(pattern) |
Title contains pattern |
.id(prefix) |
ID prefix match |
.since(date) |
After date (str or datetime) |
.until(date) |
Before date (str or datetime) |
.similar(text) |
Semantic similarity (requires vector index) |
.sort(field) |
Sort: date, tokens, messages, words, longest, random |
.reverse() |
Reverse sort order |
.limit(n) |
Max results |
.sample(n) |
Random sample |
.where(predicate) |
Custom filter predicate |
.is_root() |
Root sessions only |
.is_continuation() |
Continuation sessions only |
.is_sidechain() |
Sidechain sessions only |
.has_branches() |
Sessions with branching messages |
.parent(id) |
Children of a given parent |
Terminal Methods
| Method | Description |
|---|---|
.list() |
Execute and return list[Session] |
.list_summaries() |
Execute and return list[SessionSummary] (lightweight, no messages) |
.first() |
Execute and return first match or None |
.count() |
Execute and return count (uses SQL fast path when possible) |
.delete() |
Delete matching sessions (returns count deleted) |
.can_use_summaries() |
Check if list_summaries() is valid for current filters |
Ingestion
import asyncio
from polylogue import Polylogue
async def main():
async with Polylogue() as archive:
result = await archive.parse_sources()
return result.counts
counts = asyncio.run(main())
Async API
Polylogue provides a full async/await facade with concurrent operations:
import asyncio
from polylogue import Polylogue
async def main():
async with Polylogue() as archive:
# Concurrent queries
stats, recent, claude = await asyncio.gather(
archive.stats(),
archive.list_sessions(limit=10),
archive.list_sessions(origin="claude-ai-export"),
)
print(f"Total: {stats.session_count} sessions")
# Parallel batch retrieval (5-10x faster than sequential)
ids = [c.id for c in recent]
convs = await archive.get_sessions(ids)
# Search with evidence snippets
results = await archive.search("error handling", limit=20)
for hit in results.hits:
print(f"{hit.title}: {hit.snippet}")
# Parse files
result = await archive.parse_file("chatgpt_export.json")
# Explain import decisions without writing archive rows
explain = await archive.explain_import("chatgpt_export.json", source_name="chatgpt")
print(explain.produced.sessions, explain.entries[0].provider)
# Fluent filter (terminals are async)
convs = await archive.filter().origin("claude-ai-export").contains("error").limit(10).list()
# Rebuild search index
await archive.rebuild_index()
asyncio.run(main())
Async Methods
| Method | Description |
|---|---|
get_session(id) |
Get single session by ID |
get_sessions(ids) |
Parallel batch fetch (5-10x faster) |
list_sessions(origin, limit) |
List with optional filtering |
search(query, limit, source, since) |
Search returning evidence snippets; text matches report message evidence and Drive/Gemini provider_id / id / fileId / driveId attachment-id matches report attachment evidence |
parse_file(path, source_name) |
Parse a single export file |
parse_sources(sources, download_assets) |
Parse from configured sources |
explain_import(path, source_name, limit) |
Explain provider detection, artifact classification, parser mode, produced row counts, skips, and caveats without writing archive rows |
rebuild_index() |
Rebuild FTS5 search index |
stats() |
Archive statistics (returns ArchiveStats) |
filter() |
Fluent filter builder (sync, reuses SessionFilter) |
get_session_insight_status() |
Durable insight readiness/freshness summary |
get_session_profile_insight(id) |
Get one durable session-profile insight |
list_session_profile_insights(query) |
List durable session-profile insights |
get_session_latency_profile_insight(id) |
Get one durable session-latency insight |
list_session_latency_profile_insights(query) |
List durable session-latency insights |
find_stuck_session_latency_profile_insights(query) |
List sessions with stuck tool starts |
list_session_work_event_insights(query) |
List durable work-event insights |
list_thread_insights(query) |
List durable work-thread insights |
list_session_tag_rollup_insights(query) |
List durable tag-rollup insights |
list_archive_coverage_insights(query) |
List provider, day, or week archive coverage insights |
list_tool_usage_insights(query) |
Per-provider tool usage with explicit coverage gaps |
list_archive_debt_insights(query) |
List governed archive-debt insights |
See also: CLI Reference · Data Model · Configuration