使用说明
franken-agent-detection
A Rust crate with two layers for working with local coding-agent tools:
- Detection (always available, no features): which coding agents are installed on this machine, as one stable, JSON-serializable report.
- Connectors (
connectorsfeature and friends): read each agent's own session history into one normalized conversation model, with discovery, provenance, streaming and resumable ingestion. This is the parsing layercassbuilds its search index on.
cargo add franken-agent-detection # detection only
cargo add franken-agent-detection --features all-connectors # every connector
Everything is synchronous, local and read-only: no async runtime, no network, and no connector ever writes to an agent's store.
Detection
use franken_agent_detection::{
detect_installed_agents, AgentDetectOptions, AgentDetectRootOverride,
};
use std::path::PathBuf;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let report = detect_installed_agents(&AgentDetectOptions {
only_connectors: Some(vec!["codex".into(), "gemini".into()]),
include_undetected: true,
root_overrides: vec![AgentDetectRootOverride {
slug: "codex".into(),
root: PathBuf::from("/tmp/mock-codex"),
}],
})?;
println!(
"Detected {} of {}",
report.summary.detected_count, report.summary.total_count
);
Ok(())
}
| Item | Purpose |
|---|---|
detect_installed_agents |
Run filesystem probes and produce the full report |
AgentDetectOptions |
Connector filtering (only_connectors), include_undetected, root_overrides |
InstalledAgentDetectionReport |
format_version, installed_agents (slug, evidence, root paths), summary |
default_probe_paths_tilde |
The ~/… probe table, e.g. for remote probing over SSH |
AgentDetectError |
UnknownConnectors (slug not recognized) |
Slugs are normalized (claude-code → claude, oh-my-pi → omp, …);
unknown slugs are an explicit error. Probe roots honor the agents' own
environment overrides (CODEX_HOME, PI_CODING_AGENT_DIR, CLAUDE_CONFIG_DIR,
…) and root_overrides makes tests deterministic.
PI_SESSIONS_DIR adds a sessions location alongside ~/.pi/agent/sessions.
Setting PI_CODING_AGENT_DIR replaces that default agent home while keeping
the separate sessions override. A missing additive sessions directory does
not hide an existing default history.
Custom history stores use the same environment settings as their connectors:
| Agent | Environment settings | Detection policy |
|---|---|---|
| Gemini | GEMINI_HOME |
Replaces the default session root; accepts a directory or an admitted chats/session-*.json / .jsonl file |
| Qwen Code | QWEN_RUNTIME_DIR, QWEN_HOME |
Runtime directory takes precedence over the home override; detects current projects and legacy tmp stores without falling back from a missing configured root |
| Cline SDK | CLINE_SESSION_DATA_DIR, CLINE_DATA_DIR, CLINE_DIR |
Resolves the SDK session directory in that order while keeping legacy extension histories independently available |
| Continue | CONTINUE_GLOBAL_DIR |
Replaces the default ~/.continue home; relative paths resolve against the process working directory, and ~ remains literal |
| Kiro CLI v2 | KIRO_HOME |
Replaces ~/.kiro, including sessions/cli; a missing configured home does not select another profile |
| OpenCode | OPENCODE_STORAGE_ROOT, OPENCODE_SQLITE_DB |
Keeps legacy storage and SQLite independent, with default database candidates still available |
| Hermes | HERMES_SQLITE_DB, HERMES_HOME |
Prefers an existing explicit database, then $HERMES_HOME/state.db, then the default store |
| Crush | CRUSH_SQLITE_DB |
Prefers an existing explicit global database, with the default as fallback |
| Goose | GOOSE_SQLITE_DB, GOOSE_PATH_ROOT |
Resolves the database and JSONL sessions directory independently, including their default fallbacks |
| Cursor | CASS_CURSOR_PROJECTS_ROOT |
Replaces the Agent transcript root while retaining Composer detection |
These remain filesystem installation probes. A configured database path must
be a file; detection does not open databases or validate their schemas. The
probes work without optional connector features, while reading each store
requires its connector's feature. Explicit detector root_overrides stay
restricted to the supplied paths. Reported roots are candidate locations;
passing a database file as a scan context deliberately scopes applicable
connectors to that file.
Connectors
use franken_agent_detection::{
Connector, PiAgentConnector, ScanContext, ScanRoot, get_connector_factories,
};
use std::path::PathBuf;
fn main() -> anyhow::Result<()> {
// Default locations for one agent.
let ctx = ScanContext::local_default(PathBuf::from("/tmp/cass-state"), None);
for conversation in PiAgentConnector::new().scan(&ctx)? {
println!("{:?}: {} messages", conversation.title, conversation.messages.len());
}
// Every compiled-in connector, over explicit roots, streaming.
let ctx = ScanContext::with_roots(
PathBuf::from("/tmp/cass-state"),
vec![ScanRoot::local(PathBuf::from("/home/me/.codex"))],
None, // or Some(since_ms) for incremental scans
);
for (slug, make) in get_connector_factories() {
make().scan_with_callback(&ctx, &mut |conversation| {
println!("{slug}: {:?}", conversation.external_id);
Ok(())
})?;
}
Ok(())
}
Every connector produces NormalizedConversations: agent_slug,
external_id, title, workspace, source_path, timestamps, metadata,
and NormalizedMessages (role, author, content, created_at, structured
tool and skill invocations with skill/Skill/load_skill/use_skill
wrappers normalized via unwrap_skill_invocations, and the raw provider record
in extra). All 34 connector types (including MuseConnector) and scan
helpers (canonical_connector_slug, ScanProgressTick,
unwrap_skill_invocations, percent_decode_utf8) are re-exported at the crate
root. Connector-derived annotations live under extra.cass (for example branch
and context membership for Pi sessions, or cass.tool_call_count across
tool-using turns). extract_tokens_for_agent turns a message's extra into
exact API token usage where the agent records it (and an estimate otherwise)
while preserving model, provider (anthropic, openai, google, mistral,
xai, moonshot, deepseek, or explicit provider metadata), and
tool_call_count / has_tool_calls across all 34 connectors (including
qualified openclaw/<agent> multi-agent slugs and all canonical connector
aliases).
Claude Code session files of 32 MiB or larger retain compact metadata in
extra.cass instead of duplicating the full raw record. Reply identifiers are
preserved as strings at these locations:
| Identifier | Raw extra |
Compact extra |
|---|---|---|
| Message ID | message.id |
cass.message_id |
| Request ID | requestId |
cass.request_id |
Claude Code can repeat a reply's full token usage in multiple content-block
records. Compaction does not merge or remove normalized messages, and token
extraction is per record. Consumers aggregating usage should count each
identified (message_id, request_id) pair once within a conversation.
Compaction omits missing or non-string identifiers. Records without both
nonblank identifiers must not be merged under a shared default key.
Compaction retains the model, usage, tool-call count, and existing attachment
metadata without retaining the raw message content a second time.
Beyond scan:
| API | Purpose |
|---|---|
discover_source_files |
Pre-parse list of the files a scan will read (role, origin, size/mtime), so hosts can mirror sources before parsing |
scan_with_callback / supports_streaming_scan |
Emit conversations incrementally instead of materializing the corpus (supported by all 34 connectors) |
scan_with_source_boundaries / supports_source_boundaries |
Resumable ingestion: a pre-parse skip predicate and a per-source completion event (with required sidecars such as SQLite WALs), supported by 29 single-source connectors |
ScanRoot::remote + Origin + with_mirrored_source_path |
Scan synced copies of remote machines across all 30 store-based connectors (ScanRoot::mirrored_store), keeping host provenance |
ScanRoot::with_rewrite / with_agent_rewrite / with_mapping (apply_workspace_rewrite) |
Rewrite remote workspace prefixes (from -> to, optionally scoped to canonical agent slugs/aliases) and record metadata.cass.workspace_original across all 34 connectors |
ScanContext::with_progress_tick (progress_tick) |
Host stall-watchdog liveness callback (cass#373 Variant A), invoked per scanned source/session across all 34 connectors |
CASS_EXCLUDE_PATHS |
Comma/newline-separated files or directories that all 34 connectors skip before opening or parsing them. Entries match whole path components; relative, .. and symlinked spellings of an existing directory match too. Exact Codex JSONL exclusions cover both the plain and compressed (.jsonl.zst) representation |
Aider accepts an exact .aider.chat.history.md as its scan context, including
an intentionally selected archived copy. A missing exact file yields no
history. Directory contexts keep the existing Cass state-directory fallback,
but names such as cassie and cassette-player remain scoped to that
directory. CASS_AIDER_DATA_ROOT takes precedence over the context directory;
explicit ScanRoots take precedence over both.
The copilot / github-copilot connector reads VS Code chat stores and
extension exports. Copilot CLI histories belong to copilot_cli, including
when both connectors scan one supplied home directory. Detection and source
discovery use the same ownership split. Supplied VS Code session files and
native store containers remain scoped to that location, including empty or
missing stores; they do not fall back to unrelated live histories.
Native Copilot responses retain whole-turn output usage after append-log replay,
once per assistant response. Valid modelTotals take precedence over saved
completionTokens, including explicit zero totals. Per-model input, cache and
output counters are retained in extra.cass.model_totals; only output is
normalized as API usage because the saved input/cache relationship differs
between backends. Latest-call prompt counts and session-wide credits are not
added. Mixed-model turns retain their individual model labels without being
attributed to the selected model alone. Invalid or overflowing totals do not
fall back to an older saved count.
Cline reads extension task stores at tasks/<taskId>/ui_messages.json, with
api_conversation_history.json as the fallback when UI history is absent.
Legacy direct <store>/<taskId> layouts remain supported. Exact transcript
files, task directories, tasks directories and extension roots keep their
scope, and overlapping roots share one task selection. Native ask / say
records expose user, assistant and tool roles while preserving their raw
subtypes.
Cline also reads version-1 SDK lead-session snapshots at
~/.cline/data/sessions/<id>/<id>.messages.json, together with their neighboring
<id>.json manifests. CLINE_SESSION_DATA_DIR selects the sessions directory;
otherwise CLINE_DATA_DIR/sessions, CLINE_DIR/data/sessions, and the default
location apply in order. Overrides are trimmed literal paths without tilde
expansion. Explicit roots stay scoped. Source discovery includes the required
manifest, and a change to either file re-reads the complete session. Snapshot
order, message IDs, model identity, thought text and readable tool activity are
preserved in compact normalized messages without duplicating binary payloads.
When an SDK migration and its original Cline UI history are both in the supplied scope, the connector uses the original history followed by the resumed SDK turns. The copied cumulative usage before the native resume marker is counted once. Matching respects source origin; standalone SDK copies keep their saved history. SDK teammate/child artifacts and model-context compaction files are not imported as separate conversations.
Cline token extraction reads recorded tokensIn, tokensOut, cacheWrites
and cacheReads from request, deleted-request and subagent usage rows. These
are four independent buckets. Legacy request start/finish pairs retain all
transcript rows, with final counters attached to the start row under
extra.cass.token_usage; the finish row returns TokenDataSource::Suppressed
and contributes neither API usage nor an estimate. Only the four counters
are attached, without copying request payloads. Explicit zero and partial
counts remain API data; invalid fields and ordinary transcript text retain
the estimation fallback. The existing 100 MB task-file cap is unchanged.
SDK metrics use a different convention: inputTokens includes cache reads and
writes. Extraction separates the valid cache buckets while preserving the full
input total. Only assistant metrics count as API usage; SDK display-only
messages contribute neither usage nor estimates. Manifest-wide counters are
not added to per-message metrics.
Exclusion entries are literal paths, without shell or tilde expansion. An unset
or empty CASS_EXCLUDE_PATHS leaves scans unrestricted. Invalid Unicode,
unresolvable entries, or relative entries without a usable working directory
return an error from all 34 connectors' scan and discovery methods before
source hooks or parsing. All 34 connectors support streaming callback scans
(supports_streaming_scan() == true), workspace path rewrites
(ScanRoot::with_rewrite), and progress liveness ticks
(ScanContext::with_progress_tick). Twenty-nine connectors expose per-source
lifecycle boundary hooks (supports_source_boundaries() == true via
scan_with_source_boundaries()); the remaining 5 cross-source connectors
(cline, copilot, cursor, opencode, and qwen) correlate, splice, or
deduplicate sessions across multiple files/DBs before emitting conversations and
therefore report supports_source_boundaries() == false. All 30 store-based
connectors resolve remote mirror containers via ScanRoot::mirrored_store
(the remaining 4 project/explicit-root connectors — aider, chatgpt,
grok_bot, and pi_durable — scan project directories, single files, or OS
application caches directly). Absolute exclusion entries remain usable without a
working directory. The existing infallible Pi discover_sources and durable
store_diagnostics helpers log invalid-policy errors and return no sources;
pi_wire::try_discover_sources exposes the discovery error to direct callers.
Claude Code, Factory, Kimi, Kiro, Clawdbot, Vibe, OpenClaw, Muse, Grok, Prime and Gemini stop reading a transcript after an underlying I/O error and discard its incomplete contents. Their JSONL readers still skip individual malformed JSON or invalid UTF-8 records and retain later valid records. The shared line reader buffers only the current line and adds no full-transcript copy.
Vibe retains native assistant turns containing only reasoning or tool calls,
as well as ordinary text. Tool names and call IDs are exposed through
invocations; JSON-encoded arguments up to 64 KiB become structured values.
Larger arguments remain in the original extra record, and opaque reasoning
and image payloads do not enter searchable content. Each source row remains
one normalized message. Per-message token usage remains estimated because
Vibe stores its API counters separately as cumulative session statistics.
Similarly, Crush and Muse record API token counters at the session level in
conversation.metadata (prompt_tokens/completion_tokens for Crush;
usage.input_tokens/output_tokens for Muse), so per-message token extraction
preserves model and provider metadata while falling back to content estimation
rather than duplicating session totals across assistant turns. OpenCode 1.x
(SQLite and flat-file JSON) and 2.x (session_v2/session_message) preserve
per-message modelID, providerID, tokens (input, output, reasoning,
cache.read, cache.write), and cass.tool_call_count on extra, surfacing
positive API token counts via extract_tokens_for_agent("opencode", ...) and
falling back to content estimation for zero-initialized Tokens::default()
blocks. Aider and Grok Bot also extract structured NormalizedInvocation
entries (such as Aider #### /run / #### /git / #### /test commands and
Grok Bot tool_calls / tool_use / function_call blocks) alongside
per-message model and cass.tool_call_count metadata.
Continue reads IDE and CLI snapshots from
~/.continue/sessions/<sessionId>.json, or CONTINUE_GLOBAL_DIR/sessions.
Explicit home, global-home, session-directory and exact-file scopes stay
isolated; overlapping and symlinked paths yield each source once. The native
session ID must match the filename. The connector supports callback streaming,
source discovery and per-source completion hooks. Invalid or interrupted
snapshots never authorize a resume skip. The shared sessions.json list is
not a transcript and is not required to reconstruct a session.
Continue preserves ordered text, reasoning, tool calls, tool results and message
IDs. IDE tool-result rows take precedence over their duplicate copies in
toolCallStates.output; CLI inline results are emitted as tool messages. Typed
reading skips duplicated editor state, prompt/completion logs, retrieved context
and image payloads. Tool arguments up to 64 KiB become structured values;
larger arguments are omitted from normalized metadata. The original source
file remains available through source discovery. Native snapshots do not
record message timestamps, so those fields remain unset.
Continue usage is attached once to its assistant message, including replies with multiple text blocks or no text. Recorded completion tokens and input without cache activity are exposed as API counts. Cache-bearing prompt totals remain in compact metadata because the IDE's legacy Anthropic adapter and the CLI's provider adapters use different input/cache conventions. Display model aliases are kept separate from actual model IDs. Session-wide usage stays in conversation metadata and is never added to per-reply counts. These contracts follow the pinned Continue session writer and CLI history service.
Amp exposes its native per-assistant inputTokens, outputTokens,
cacheCreationInputTokens and cacheReadInputTokens as four disjoint API
buckets. Combined totalInputTokens, context limits, debug calls and thread
ledgers are not additional usage. Native streaming updates replace the saved
assistant snapshot, so multiple content blocks still contribute one observation.
Usage-only replies and explicit zero counts survive ingestion, and native
message IDs and timestamps remain available. The mapping is verified against
the vendor's published CLI artifact
and documented stream schema.
Cross-conversation fork reconciliation remains the consumer's responsibility:
Amp can retain a stale fork index after edits and reuse descendant message IDs,
so those fields alone cannot safely suppress copied usage.
Kiro's supported v2 JSONL store follows KIRO_HOME/sessions/cli, including
renamed profile copies, their session directories and exact transcript files.
The native override was introduced in Kiro 2.3.
JSON metadata sidecars, source provenance and existing message projection are
preserved. This support covers the v2 JSONL/JSON layout;
it does not infer a schema for Kiro v3 stores.
Gemini CLI JSONL sessions are replayed into their final message history.
Repeated native message IDs replace earlier versions in place; $patch
updates content and tool results, removes messages, or reorders surviving
IDs. $rewindTo removes its target and later messages, while $set.messages
replaces history with an authoritative checkpoint. Optional-kind metadata
headers and legacy messages without IDs remain supported. Replay keeps one
payload per surviving ID, and the existing 32 MiB metadata compaction
threshold is unchanged.
Gemini messages also retain stored thought summaries and tool activity when
ordinary text is empty. Each native message remains one normalized message;
tool names, call IDs and arguments are exposed through invocations.
Readable tool results are included in searchable content, while binary
result parts are omitted. Compact metadata does not duplicate the raw
thought, tool-call or result payloads.
Gemini token extraction reads the native per-message tokens fields in both
JSON and JSONL histories. The same six numeric fields survive metadata
compaction at 32 MiB. Cached tokens are separated from the prompt, tool-use
prompt tokens count as input, and generated thoughts count as output.
thinking_tokens describes the reasoning subset already included in output;
the aggregate counts it once. Invalid token fields are ignored, and messages
without usable API counts retain the existing estimation fallback.
Qwen Code reads current UUID-named JSONL sessions in
projects/<project>/chats/, including chats/archive/, alongside its legacy
tmp/<project>/chats/session-*.json histories. Native UUID fragments form one
message with the latest recorded usage, and parent links select the active
conversation branch. Thought text, tool calls and readable results, authored
user display text, and custom titles are preserved. Exact discovered files
and recognizable copied stores remain scoped to their supplied roots;
explicit scan roots exclude unrelated local stores. Configured Qwen paths
support the agent's tilde expansion and relative-path resolution.
Qwen also reads native subagent transcripts at
projects/<project>/subagents/<parentSessionId>/agent-<agentId>.jsonl.
Every record must agree on the parent session, agent and sidechain identity.
The external ID is an escaped JSON tuple of the original parent and agent IDs,
so filename sanitization cannot merge different agents. Completed rounds keep
their own usage once; separate tool-call records, bootstrap copies,
.jsonl.stream files and cumulative sidecar statistics add no API usage.
Optional .meta.json sidecars supply bounded descriptions, lineage and status
and participate in incremental selection. Reads are capped at 1 MiB, and a
missing or malformed optional sidecar does not discard the transcript.
The format follows the pinned Qwen subagent writer.
At 32 MiB, Qwen JSONL metadata retains reply identity, model, selected scalar usage fields and tool-call counts without duplicating the raw content or tool payloads. Its public token extractor keeps cached input separate and uses the recorded total to distinguish additional Google reasoning tokens from reasoning already included in OpenAI-compatible output. Ambiguous reasoning stays in metadata; total-only records retain estimation instead of receiving a guessed input/output split. Native transcript I/O failures discard the incomplete conversation. Qwen streams completed conversations; per-source completion hooks and the distinct managed-session format are not supported.
Claude Code streaming scans continue to deliver healthy sources after a source
open/read failure, then return an error with the failure count and the first
original I/O error. Failed sources emit no conversation or completion event.
The collecting scan() API remains all-or-error, so its caller receives no
partial vector. Conversation-callback and completion-callback errors stop
traversal immediately, including when a source error was already deferred.
Feature flags
| Feature | Enables |
|---|---|
connectors |
Connector framework and every connector that needs no extra dependencies |
chatgpt |
ChatGPT desktop, including AES-GCM encrypted v2/v3 conversations |
cursor, opencode, goose, hermes, crush, devin, shelley |
SQLite-backed stores for those agents |
openclaw-sqlite |
OpenClaw 2 per-agent SQLite transcripts (zstd events included) |
codex-zstd |
Codex rollouts compressed to rollout-*.jsonl.zst (Codex's local_thread_store_compression) |
copilot-vscdb |
Legacy VS Code Copilot chat sessions in state.vscdb |
pi-sqlite |
pi_agent_rust SQLite sessions for the Pi family |
pi-durable |
SQLite stores of Pi's experimental durable harness |
codebuff, grok-bot |
Codebuff / Freebuff shared history; Grok Bot desktop replicas |
all-connectors |
All of the above |
SQLite stores are read with FrankenSQLite opened read-only inside one read transaction, so a live WAL is seen as one coherent snapshot and nothing is recovered or checkpointed.
Coverage
| Slug | Agent | Storage read |
|---|---|---|
aider |
Aider | .aider.chat.history.md |
amp |
Amp | thread JSON |
antigravity |
Antigravity IDE and agy CLI |
transcripts and conversation stores |
chatgpt |
ChatGPT desktop | conversation JSON (encrypted generations with chatgpt) |
claude |
Claude Code | session JSONL (CLAUDE_CONFIG_DIR, XDG_CONFIG_HOME aware) |
clawdbot |
Clawdbot | session JSONL |
cline |
Cline | task JSON |
codebuff |
Codebuff / Freebuff (one shared store) | ~/.config/manicode chats |
codex |
Codex CLI | rollout JSONL (.jsonl.zst with codex-zstd) |
continue |
Continue IDE / CLI | native session JSON snapshots |
copilot / github-copilot |
VS Code Copilot Chat | chat-session JSON and append logs; legacy state.vscdb |
copilot_cli |
Copilot CLI | session event logs |
crush |
Charm Crush | SQLite |
cursor |
Cursor | state.vscdb and agent transcripts |
devin |
Devin CLI | sessions.db (detection-only without devin) |
factory |
Factory Droid | session JSONL |
gemini |
Gemini CLI | session JSON and event-sourced JSONL |
goose |
Goose | sessions.db and legacy JSONL |
grok / grok_bot |
Grok Build CLI / Grok Bot desktop | session logs / rolling replicas |
hermes |
Hermes Agent | state.db |
kimi, kiro, qwen, vibe, muse |
Kimi Code, Kiro CLI, Qwen Code, Mistral Vibe, Muse Code | their session logs |
omp |
Oh My Pi | session JSONL, profiles and XDG layouts |
openclaw |
OpenClaw | session JSONL; OpenClaw 2 SQLite |
opencode |
OpenCode | JSON files and opencode.db |
openhands |
OpenHands | conversation event JSON |
pi_agent |
pi-mono and pi_agent_rust |
session JSONL; SQLite sessions with pi-sqlite |
pi_durable |
Pi durable harness | main.jsonl commit logs; session.sqlite with pi-durable |
prime_agent |
Prime Agent | session JSONL |
shelley |
Shelley | shelley.db |
windsurf |
Windsurf | detection only |
Pi-family transcripts keep every branch of a session (abandoned branches stay searchable), and each message records whether it is on the active branch and in the active model context, with summaries, injected context and shell runs labeled by kind.
Design goals
- Keep output stable for downstream tooling and snapshot tests.
- Keep behavior explicit: connector normalization, unknown slugs, unsupported store versions and incomplete sources are reported, never guessed at.
- Stay local and read-only: filesystem and read-only SQLite access only.
- Stay runtime-neutral with a synchronous API.
Installation
For detection only:
[dependencies]
franken-agent-detection = "0.3" # detection
For the full parsing layer:
[dependencies]
franken-agent-detection = { version = "0.3", features = ["all-connectors"] } # parsing
From source:
git clone https://github.com/Dicklesworthstone/franken_agent_detection
cd franken_agent_detection
cargo test --locked --all-features
Toolchain & MSRV
- Default detection-only build (
default = [],rust-version = "1.85"): uses standard Rust 2024 edition syntax with zero optional dependencies. - Non-SQLite connector features (
connectors,codex-zstd,chatgpt): use Rust1.88+let-chains. - SQLite-backed connector features (
cursor,opencode,goose,hermes,crush,devin,shelley,openclaw-sqlite,pi-sqlite,pi-durable,all-connectors): depend onfrankensqliteandasupersync, which require the repository's pinnedrust-toolchain.toml(nightly-2026-08-31or newer). - Repository
.cargo/config.toml: setsrustflags = ["-Z", "threads=4"]for the pinned nightly toolchain; passRUSTFLAGS=""if building non-SQLite feature slices with a stable compiler inside a checkout of this repository.
Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
UnknownConnectors error |
Connector slug not recognized | Use known slugs (codex, claude, omp, gemini, …) |
| Empty detection results | No roots exist on this machine | Set include_undetected = true to inspect evidence |
| A connector scans nothing | Its storage needs a cargo feature (SQLite, crypto) | Enable the feature from the table above, or all-connectors |
| Non-deterministic tests | Real home-dir probing | Use root_overrides / explicit ScanRoots over temp directories |
| Stack overflow in SQLite tests | fsqlite's large debug-mode futures | .cargo/config.toml sets RUST_MIN_STACK; keep it when vendoring |
-Z threads=4 or asupersync MSRV error on stable |
Building repository checkout or SQLite features without rust-toolchain.toml |
Let rustup select rust-toolchain.toml, or pass RUSTFLAGS="" when building non-SQLite features on stable 1.88+ |
Limitations
- Default probe roots are opinionated; custom layouts need overrides or explicit scan roots.
- No background watching; scans run only when called (
since_tsmakes them incremental, source boundaries make them resumable). - Remote SQLite stores are not read: a live database and its WAL cannot be synced as one consistent snapshot. Index them on their own host.
About Contributions
About Contributions: Please don't take this the wrong way, but I do not accept outside contributions for any of my projects. I simply don't have the mental bandwidth to review anything, and it's my name on the thing, so I'm responsible for any problems it causes; thus, the risk-reward is highly asymmetric from my perspective. I'd also have to worry about other "stakeholders," which seems unwise for tools I mostly make for myself for free. Feel free to submit issues, and even PRs if you want to illustrate a proposed fix, but know I won't merge them directly. Instead, I'll have Claude or Codex review submissions via
ghand independently decide whether and how to address them. Bug reports in particular are welcome. Sorry if this offends, but I want to avoid wasted time and hurt feelings. I understand this isn't in sync with the prevailing open-source ethos that seeks community contributions, but it's the only way I can move at this velocity and keep my sanity.
License
MIT