Keep next-page command payloads free of advisory prose and emit page-size or budget advice on a separate hint line. Normalize literal percent characters and valid path escapes consistently. Document and test quoting the full negative-filter query without relaxing unknown-option rejection.
Validated by paging continuation, percent-path, quoted argument, and strict-option regressions in the 593 default and 617 CUDA-enabled test suites.
Co-authored-by: Codex <[email protected]>
Concurrent daemons, retry policy, stale sym: fallback, warming reads,
and the shared tokenizer (lane B, ee503ec). Reconciliations:
- src/cli/emission.rs: lane C's `help` word arm stays first; the
execution arm now runs through retry::run_with_retry.
- src/source/acquisition.rs + acquisition/symbol.rs: lane D's symbol
split wins; AcquiredSource keeps D's SymbolSelection and adds B's
`freshness`; acquire_symbol's read_first closure calls B's
stale_symbol::acquire_symbol_entry (the republish wait is skipped for
parent views, so lane A's parent_show read_symbol path is unchanged).
parent_show.rs's two AcquiredSource literals gain `freshness: None`;
the stale-symbol test uses D's acquire(.., InvocationDirectory).
- src/source.rs: `freshness` renders before D's definitions/imports block.
- Lane A tests that open WorkspaceResults (home_index/tests.rs,
result_cache/tests.rs) create the store first, as B's create/open
split requires; production callers (coordinator start, local runs)
already create it.
- docs/index-contract.md: A's worktree read-path text kept; B's stale
sym: and warming-read rules condensed after it (file stays <=200 lines).
Worktree warming in workspace mode still answers from the parent index
(A's resolve_home_index, which never goes through a root daemon);
B's index_warming applies to a root's own unpublished index.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Lane E concept ranking: evidence lanes (qualified definitions,
identifier occurrences, phrase, all-terms), identifier evidence tiers,
the 0.7 path prior, rerank tiers, snippet choice, and the
concept-audit evaluation manifest.
Conversions made while merging:
- search_prepared runs lane E's concept lanes with lane C's bound
path filter: concept_lanes, the occurrence lane (its raw
substr(f.path,...) check is now paths.sql_clause("f.path")),
lexical/file lanes and semantic_lane::append all take `paths`.
- PathPrior::for_query reads query.path.includes() for test/doc
component checks instead of a raw prefix string.
- Lane D's declarations::is_test_path is deleted; declarations and
reference_sites call path_class::is_test_path, so fixtures/, bare
`test` stems and generic *_test stems are production paths there
too (D's classifier test moves evaluation/fixtures/x.dm to the
negatives).
- The A::b concept lane calls D's declarations::qualified_hits
(QualifiedName::matches) instead of lane E's own container matcher.
- The file-ranking section moves from index-contract.md (then over
200 lines) to a new docs/ranking-contract.md; links follow.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Every daemon tier (router, coordinator, root) now accepts on one thread
and answers on a bounded RequestPool (src/daemon/pool.rs: 16/8/4
workers, 64 queued); a full queue replies `daemon_busy: retry`.
Reconciliation, watching, root-gone detection, spool draining, and idle
work move to one maintenance thread (src/daemon/reconciler.rs), which
lowers its own priority only after the initial reconcile. Handlers
implement DaemonHandler (src/daemon/server.rs); each request's query
deadline starts at accept. The root daemon (src/cli/root_daemon.rs)
binds before any database work and answers `index_warming` for reads
until the first publication (explicit path reads still serve current
files); status reports `state: warming` without writing. Spooled
requests are claimed by rename to `<id>.claimed`.
Re-entry: workspace owner verbs and member semantic commands run via
cli::run_direct, never through the router still proxying the request
(the bare-status deadlock), and a router error is now the answer
instead of silently re-running the command directly. The router proxies
with a 28 s read timeout; clients wait 30 s (CLIENT_REPLY_WAIT, shared
with the spool) and retry read verbs once on EAGAIN/TimedOut,
daemon_busy, database is locked, or (after 2 s) index_warming
(src/cli/retry.rs).
Coordinators build a SemanticSession per request, create
workspace.sqlite3 once (WorkspaceResults::create/open), and never run
workspace index/init; `ws status` opens members query-only. Spawned
daemons are reaped by their own waiter thread (BackgroundChild) instead
of a racing waitpid(-1), and a losing startup race keeps polling the
winner. DiagnosticQueue is Sync so concurrent requests share it.
A `sym:` read whose file changed waits up to 3 s for a serving daemon to
republish, then re-extracts the definition from current bytes and
answers `verified: false, freshness: unpublished`; handle reads keep
`stale_source`.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Review fixes for concept ranking.
- Identifier queries rank in evidence tiers: a file whose stem is the
token (tick_rate.rs), then declaring files, then files using, binding
or importing it, then the rest. Exact ×3 applies to declarations only,
not locals, parameters or imports.
- The path prior multiplies each lane contribution once: lexical lanes
in the first fusion, semantic ranks in the re-fusion (was ×0.25 with
semantic). kind:file queries and, outside identifier queries, files
whose basename holds every term are never demoted; DOC_TERMS gains
md, agents, claude, guide; file: filters match path components.
- path_class: add spec/ and *_spec, drop fixtures/ (content packs keep
production code there).
- A::b adds a qualified definition lane (definitions of b whose
container or module path names A); the qualified occurrence lane uses
an IN subquery instead of a correlated EXISTS.
- Rerank tiers follow the fusion tiers and apply identifier evidence
only to identifier queries, so plain words are not pinned.
- Snippets prefer code unless a comment has two more terms; `"a" b "c"`
is no longer one literal.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Converts lane D's raw substr(f.path,...) prefix checks in
declarations::qualified_hits, reference_sites::references and the
structure_map directory query to BoundPathFilter::sql_clause, and makes
map's single-file mode use PathFilter::resolve_single_file; keeps
Phase 0's open_read/QueryDeadline in workspace show and C's
filter_diagnosis coverage part beside the refs summary.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Review follow-ups for lane C:
- The semantic lane uses the shared path filter, so `--features
semantic` compiles again.
- `search_prepared` binds the `PathFilter` once and passes the bound
filter to the exact, lexical, file, semantic, and live lanes and to
zero-hit diagnosis. Bound filters render inline SQL: nothing when
empty, `path>=lo AND path<hi` index ranges for root prefixes, and
`instr` for component matches.
- Root anchoring requires an indexed path continuing the value at `/`,
`.`, or its end, so `file:src` beside `src-tauri/` still reaches
`crates/a/src/`.
- `file:` values are percent-encoded like indexed paths (`%` kept).
- `PathFilter::resolve_single_file` lets `map ./src/x.rs` and
`map host.rs` list members; directory prefixes never do.
- Diagnosis counts in SQL and reads nearest-path candidates only for
values that matched nothing, ranked by relation and edit distance.
- Usage errors are also written to stderr; an empty `lang:` filters
nothing.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
- map: extern block items (including Rust 2024 `unsafe extern`, which
the pinned grammar parses as ERROR + block) carry the exact
`extern block` container; map filters on it instead of a LIKE prefix
that hid `mod externals` and `class ExternalApi` members.
- refs: collapse only same path, line, role and resolution; the count
lives in a new `Hit.repeats` field (JSON `repeats`, lines `×N`), so
`resolution` stays an enum. Test sites rank last whatever their role.
Qualified refs pre-filter owners in SQL.
- show: import trails follow up to four hops with a visited set,
resolve crate/self/super against the importing module (crate root =
path before the last `src/`, plus enclosing inline mods), report the
chain, and mark ties as `(1 of N)` with the tied declarations first
in `also:`. Import tracing moves to search/import_trail.rs.
- Qualified lookups keep the pre-filter truncation flag.
- Workspace `search 'sym:'` ranks by the invocation directory; the
directory is compared percent-encoded. Test scopes match any
`tests` container segment.
- Workspace map misses count as no home hits; `no_indexed_path` is
returned only when no member has a row.
- acquisition.rs splits into acquisition/{symbol,tests}.rs.
- Navigation contract moves to docs/navigation-contract.md with the
JSON fields; language contract documents the impl-container limit.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Free-text search now runs evidence lanes in fusion order: exact
definitions, identifier occurrences, phrase and all-terms FTS5 lanes,
then the any-term and filename lanes.
- A single identifier-shaped token (_, ::, camelCase, digits) weights
exact definitions x3, adds an occurrence lane, and ranks files that
define or use the token ahead of files lacking it.
- Two or more terms add a phrase lane (x2) and an all-terms lane; a
"quoted" literal runs the phrase lane alone and skips semantic.
- A deterministic path prior halves test and Markdown paths unless the
query names tests/docs, sets lang:text, or file: targets them.
- Rerank keeps phrase/identifier hits ahead of other hits and orders
within each tier.
- Previews pick the span line with the most distinct query terms.
Contracts: docs/index-contract.md (File ranking), retrieval, semantic
rerank, and the cli.md snippet sentence.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
show 'sym:' ranks namesakes by kind tier, then non-test before test
sites, then nearest the invocation directory (workspace cwd relative
to the member root), then path. The footer counts declarations apart
from imports (`definitions: N (+M imports)`). An import that outranks
every declaration is followed through its `use` spelling to the
original (`via: re-export of a::b at PATH:LINE`) or reported as not
indexed. `sym:A::b` matches `b` owned by impl/trait/class `A` or under
module path `A`, in search and show. Every word after `show sym:` and
`refs NAME` joins the query, so unquoted file:/lang:/kind: apply;
no_definition names active filters and the best unfiltered match.
refs honors file:/lang:/kind: (role or target kind) and qualified
names, orders declaration, code, imports, then tests, collapses one
path:line into a `×N` row, and reports `refs T sites in F files` in
single-repo and workspace coverage.
map FILE lists code items before fields, variants and mod rows and
drops the whole-file module and extern signatures (extern items now
record their block header as container; extraction revision 6).
map PREFIX gives one row per file naming its top-level items; an
unknown path fails with no_indexed_path and nearest paths.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Query surface fixes from the lunatic transcript audit:
- `file:` values OR when repeated and `-file:` excludes. A value matches
root-relative prefixes, else any path-component start
(`file:script/host` finds `crates/a/src/script/host.rs`). One
`PathFilter` (src/search/path_filter.rs) binds against the index and
compiles to a SQL predicate plus a Rust matcher shared by the exact,
lexical, and file lanes, `map`, and live regex.
- Unknown `lang:` values fail with `unknown_language` and list the
recorded languages; `md`/`markdown`/`toml`/`json` alias `text`.
- Empty filtered searches add `filter_diagnosis` to coverage: per-value
matched path counts, nearest paths by name, `lang:X matched 0 files`,
and combined or exclusion failures. Workspace pages group them by
member.
- Lines footers print the command: `next: more CURSOR` (first page adds
the `-n` or `-b` widening hint) and `next: show CURSOR`. JSON keeps
the bare cursor.
- `next`/`page` verbs, bare cursors, and handles get targeted
`unknown_command` hints; `help` prints help; clap usage errors are
plain unbudgeted text with a `more` tip for paging flags.
- `--help` lists `-file:`, `-n`, `-b`, and the `more` footer usage.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
`sym:` pages were in path order, so a widely imported type showed a
page of `use` lines before its definition (sym:TileCoord in lunatic
listed 18 imports first). Exact results now order declarations, then
modules, members, locals, and imports, keeping path order within each.
Validation: cargo test passes (379).
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Lines output of `show` now opens with `PATH [(MEMBER)] lines FIRST-LAST`
instead of a 64-hex revision and byte offsets, and explicit path reads
end with `verified: current file` (JSON `"source": "current_file"`)
rather than a bare `verified: false` that read as a failure. `show`
defaults to a 1500-token budget, never below a workspace page budget,
so a typical definition body fits in one read.
Validation: cargo test passes (377); plugin, evaluation, and navigation
replay checks pass.
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
`show 'sym:NAME [file:P] [lang:L] [kind:K]'` reads the best-ranked
definition with that exact name as a verified handle read: declarations
before modules, members, then locals and imports. The footer reports
`definitions: N` and up to five `also:` path locators, valid in single
repositories and workspaces alike; a missing name fails with
`no_definition`. `map` of a single file also lists its functions,
methods, constants, and macros.
Transcripts showed ~3k `grep -n "fn X" -A30` body reads and ~1k
single-file outline greps per three weeks; each is now one call.
Validation: cargo test passes (377).
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Search, refs, and map hits carry a snippet: the first line inside the
span that mentions a query term or the hit's name, preferring code over
comments, trimmed to 120 characters. Lines output prints it on an
indented ` LINE: TEXT` line under the hit; JSON adds `snippet`. Pages
keep snippets while at least eight hits (or all remaining) fit, then
fall back to locators. Regex hits drop the name column the snippet
already shows.
Agents re-ran trufflepig queries as grep because hits had coordinates
only; grep answers location and text in one call.
Validation: cargo test passes (373); plugin and evaluation tests pass;
navigation replay completes every scenario in the same 2 calls with
~12% more output.
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
An unselected query now searches only the home member, waiting up to
8 seconds for a freshly seeded home index to publish, and widens to all
members when home has no hits or no published index. Pages record the
outcome as `scope` and lines output appends it to the coverage line.
Explicit in:/ws:home/ws:all selectors never widen.
Transcripts showed agents' first workspace searches mixing unrelated
repositories into results, and fresh worktrees answering from other
members while home was warming.
Validation: cargo test passes (370); evaluation tests pass (60);
navigation replay scenarios all complete.
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Print --help and --version as plain, unbudgeted text; help ends with a
query and navigation summary. At the default budget, help was a
truncated JSON stub, and agents that asked for it switched to rg.
Make re: line-based like grep: ^ and $ match at line boundaries, and a
line with several matches yields one hit instead of repeats that
crowded pages (and interleaved across workspace members).
Validation: cargo test passes (369).
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Add personal skill installation for Codex and Claude Code, with
harness-specific session attribution and Claude SessionStart exports.
Preserve existing Claude hooks and configure narrow runtime access.
Share disk-backed spool and audit settings, correct audit parsing and
ordering, and stop router-owned child daemons during service upgrades.
Update the search workflow and navigation replay for compact results,
verified source reads, explicit relationship limits, and fallbacks.
Validation: 21 integration tests and 60 evaluation tests pass. Verify
four navigation replay scenarios, native skill discovery and Claude
hook execution, and search-to-source reads through the installed wrapper.
Automatic model selection and Claude-sandbox execution remain untested;
small exact-symbol comparisons do not establish token savings.
Co-authored-by: Codex <[email protected]>
Resolve the home member by Git common directory so a worktree of a
member, inside or outside its checkout, is searched under the member's
name with its own index cache, labelled in coverage as member@worktree.
Seed that cache from the member's extraction facts and embeddings,
exit a per-root daemon when its root disappears, sweep caches for
vanished roots from the router (also `system prune`), skip a linked
worktree's `.git` file, and teach the steer hook the same mapping.
Bound the history heartbeat stop so daemon exit never hangs.
Co-Authored-By: Claude Fable 5.1 <[email protected]>
Add --format lines for search, refs, map, more, and show: one tab
line per hit, a one-line coverage summary, and a key: value footer,
budgeted on the rendered text so pages carry more hits. JSON stays
the default and errors remain JSON. The agent wrapper injects the
flag, parses both shapes for its audit, and ignores stale session
markers; the skill documents the format and budget paging.
Co-Authored-By: Claude Fable 5.1 <[email protected]>
Muse's seccomp filter denies AF_UNIX connects and leaves only /tmp
writable, so the router now drains /tmp/trufflepig-<uid>/spool on its
idle tick and clients spool a request when the socket is unreachable
and the router heartbeat is fresh. The agent wrapper's audit fallback
moves to /tmp/trufflepig-<uid>/agent-audit, which trufflepig-audit
also reads.
Co-Authored-By: Claude Fable 5.1 <[email protected]>
Muse's seccomp filter returns EPERM on every AF_UNIX connect and its
cache mounts are read-only, so neither the router nor --no-daemon can
serve a sandboxed call. Say so instead of pointing at the router.
Co-Authored-By: Claude Fable 5.1 <[email protected]>
Ship a systemd user unit for `trufflepig system-serve` with
restart-on-failure and KillMode=process, install it with
`install.sh --systemd`, and have the session-start hook start the
service before falling back to a detached spawn. Sandboxed harnesses
could not recover once the router died; the coordinator error now
names the router and how to bring it back.
Also lands the search-steering hook: a PreToolUse hook that blocks or
nudges Grep/Glob/shell grep inside indexed repositories until
trufflepig-agent has been used, wired into Kimi and Muse, with its
decisions counted in trufflepig-audit. install.sh refreshes the
managed Kimi hook block on upgrade.
Co-Authored-By: Claude Fable 5.1 <[email protected]>
Cover the router's purpose, socket dir resolution, system verbs,
session-start strap, fallback chain, and routing exclusions in cli.md;
add the router contract to the index contract's daemon section.
Co-authored-by: Kimi-K3 <[email protected]>
Read [output].budget from workspace configuration and apply it when a
request passes no explicit -b/--budget. The space workspace uses 1200
so first pages hold about ten files instead of two.
Co-Authored-By: Claude Fable 5.1 <[email protected]>
Rerank the top 32 fused files with a pinned bge-reranker-v2-m3
cross-encoder, opt-in via --rerank or [semantic] rerank = true.
The shared worker runs the reranker on its own executor thread and
GPU (rerank_model_dir, rerank_gpu_uuid) with a 1500 ms deadline;
failures keep fused order and report rerank_status in coverage.
Adds the cuda_rerank evaluation arm and the measured development
replay: file recall@5 0.542 and recall@10 0.625 against 0.292 and
0.542 for file-first lexical on the same day.
Co-Authored-By: Claude Fable 5.1 <[email protected]>
Add one UUID-isolated inference worker, recoverable per-root preparation, validated content-key caches, and cache-only semantic retrieval. Bound query IPC and preserve lexical results on semantic failures. Fuse file-level lexical lanes and support workspace semantic opt-in. Limit inputs to 4096 model tokens and batches to 8192 padded tokens after GPU memory probes.
Co-authored-by: Codex <[email protected]>
Ignore local Trufflepig state. Document member daemon startup, publication freshness, and workspace versus root shutdown.
Validation: release build and install; automatic discovery and published coverage for all three workspace roots; git check-ignore and diff --check. Documentation reviewed against runtime implementation.
Co-authored-by: Codex <[email protected]>
Search explicit member roots with fair rank merging, compact coverage, and provenance within one output budget. Persist independent owner-qualified result snapshots and route source, context, and history reads without retargeting expired or changed identities. Reuse member daemons behind a workspace coordinator and share optional query inference.
Preserve root-scoped diagnostic receipts and repository-qualified session evidence. Verify configuration, source ownership, cache expiry, tiny budgets, partial writes, and semantic feature compilation; full suite plus targeted regressions pass.
Co-authored-by: Codex <[email protected]>
Document captured-tip navigation, exact historical identities, bounded diagnostics and sessions, publication observations, idle probes and semantic unloading. State actual coverage, resource bounds, and unmeasured limits; link navigation evaluation without agent-effectiveness claims.
Co-authored-by: Codex <[email protected]>