relay-knowledge 1.1.13

Graph-database-based knowledge graph project.
Documentation

English | 中文

relay-knowledge

relay-knowledge is a local-first knowledge substrate for graph-backed retrieval. It stores evidence, graph facts, code-repository structure, derived indexes, freshness state, diagnostics, worker proposals, audit records, and agent-facing context packs. It does not try to be a general agent runtime or final-answer generator.

Quick Start

The default local profile is zero configuration: runtime directories are resolved from platform defaults, SQLite is used locally, and deterministic semantic/vector read models are enabled without external services.

cargo build
target/debug/relay-knowledge status
target/debug/relay-knowledge ingest --source docs \
  --content "Rust async services isolate blocking SQLite work" \
  --entity Rust
target/debug/relay-knowledge query SQLite --source docs \
  --freshness wait-until-fresh

Use JSON output when scripting:

target/debug/relay-knowledge status --format json
target/debug/relay-knowledge health --format json
target/debug/relay-knowledge help --format json

Installing Releases

Stable releases are distributed through GitHub Releases with prebuilt archives for Linux x64/ARM64, macOS Intel/Apple Silicon, and Windows x64/ARM64. Verify the downloaded archive with checksums.txt before placing the binary on your PATH. GitHub artifact attestations cover the same archive digests and can be verified with gh attestation verify <artifact> -R coolplayagent/relay-knowledge. Linux GNU archives are built and checked against a glibc 2.31 baseline so they run on Ubuntu 20.04-class hosts and newer GNU/Linux distributions. Windows ARM64 archives are produced by the release workflow as cross-built artifacts until native Windows ARM64 CI runners are available.

Rust users can install the crate from crates.io:

cargo install relay-knowledge
relay-knowledge --version
relay-knowledge service doctor

Each GitHub Release also includes relay-knowledge-cli-skill-<tag>.tar.gz, a ClawHub-compatible skill that teaches LLM agents to use the relay-knowledge CLI for local graph and code-repository workflows. The skill package includes Linux x64 and Windows x64 binaries under assets/; agents prefer the matching bundled asset for the current operating system, CPU, and active command runner when it passes version --format json, and use PATH only as a fallback, when Linux glibc is older than 2.31, or when the user explicitly requests the system install. Windows .exe asset examples stay in PowerShell or cmd.exe instructions, not bash/POSIX command blocks. The generated SKILL.md metadata records the same numeric version as Cargo.toml. The skill package also carries a root-level README.md for registry and package consumers. The release workflow can publish the same generated skill layout to ClawHub when CLAWHUB_TOKEN is configured:

clawhub publish skills/relay-knowledge-cli \
  --slug relay-knowledge-cli \
  --name "Relay Knowledge CLI" \
  --version <version>

This skill-over-CLI path is separate from MCP/ACP protocol access.

Release Readiness Notes

Before tagging a new release, verify that user-facing entry points, installation guidance, release constraints, checksums, generated skill metadata, and version numbers still agree. The release-focused reading path is:

This documentation refresh is intentionally documentation-only; it does not change CLI, service, Web, indexing, retrieval, or release workflow behavior.

What Works Today

  • Hybrid GraphRAG context packs with BM25, local semantic signatures, local hashed-vector retrieval, graph evidence fallback, schema paths, temporal/community context, freshness metadata, truncation state, and ranking explanations.
  • Structured graph facts for evidence, entities, typed relations, claims, events, source spans, confidence, graph versions, and accepted/proposed grounding status; domain/graph/{multimodal,mutation,retrieval}/ keeps each contract with its direct tests.
  • Code repository registration, tree-sitter indexing, full/incremental refresh, worktree overlays, retrieval, context, freshness, scope, impact, and software projection live in named application subdomains; physical repo-set membership, freshness, refresh, status, and query owners avoid copied base facts, while interfaces/code_index_mode/ shares worktree semantics across CLI/Web; content/language/generated primitives, symbol/reference identity, source snapshots, verified blobs, safe filesystem access, and hashes have physical owners/tests.
  • Optional monorepo workspace detection for pnpm workspaces, Go workspaces (go.work), and Cargo workspace members. When CodeIndexRequest enables workspace detection, cross-repository import resolution maps unresolved imports to sibling packages via a workspace package-mapping table, providing target_hint metadata instead of silently dropping cross-repo references. CLI indexing keeps the default disabled, so single-repository indexing paths are completely unaffected. Ecosystem, workspace-format, manifest, package-prefix, and import-statement normalization rules are isolated in code::workspace::ecosystem; automatic set lifecycle/status, package mapping, cross-edge resolution, and target-file selection have paired-test owners; the facade only coordinates their acyclic workflow.
  • Software global projection for repository-scoped files, documentation topics, config/code relationships, dependencies, and unresolved SDK/API usage, exposed through repo software without query-time repository scans. Deterministic knowledge-map, documentation, dependency/build manifest, deployment, test, template, configuration, and source classification is isolated in the SQLite software file_role owner with direct sibling tests. The software root is a declaration-only facade: physical projection/, query_scope/, and schema/ owners contain refresh/read orchestration, bounded scope/filter SQL, and projection schema lifecycle with direct tests; software::graph separates file, topic, and relationship materialization/query/mapping into directly tested owners; software::dependency_usage::python is declared from its matching physical python.rs owner without a production path redirect; the software/lifecycle/ directory separates build, infrastructure-as-code, design, indexed-document, and shared syntax owners behind a small orchestration facade.
  • Local file-location indexing without Everything, Spotlight, Windows Search, locate, or other external search software: explicitly scan authorized roots; the physical file_index/scanner/ owner isolates bounded filesystem work and its unit contract, while SQLite/FTS5 serves name, path, extension, and directory queries.
  • Bounded index refresh queues whose physical SQLite metadata/, cursor_metadata/, diagnostics/, and task_queue/ owners separate codecs, cursor identity, observability, and lease-fenced transitions with direct tests.
  • Worker queues, deterministic fallback proposals, manual proposal acceptance, persistent audit events, silent-update operator state, and service definition generation; physical version-check subdomains pair config, cache, SemVer, release aggregation, and notice workflow with direct tests, then use a technology-neutral release-metadata port backed by bounded QoS-aware HTTP transport.
  • Service deployment topologies documenting embedded_cli, resident_single_process, resident_partitioned_sqlite, and future split worker control-plane/data-plane boundaries.
  • MCP Streamable HTTP and local ACP adapter access through the shared application service, with scope policy, QoS admission, cancellation, resources/prompts, durable audit metadata, and OTLP-ready agent metrics; the foundational HTTP and QoS owners are physically grouped in net/http/ and net/qos/, with their unit contracts colocated in each subdomain.
  • Real OTLP HTTP/protobuf traces and metrics export for resident service mode, with local diagnostics when Collector export fails.
  • Static Web diagnostics, categorized agent/model settings, persisted model provider profiles, and operation composers served by the Rust HTTP service on the same local port as /api/* and MCP when enabled.
  • Setup diagnostics and named setup profiles for local, read-only agent, platform service, and external embedding configurations.

Documentation

Key specs:

Development

Use the repository scripts by responsibility:

./setup.sh
./build.sh
./run.sh start --port 8791 --daemon
./run.sh status
./run.sh stop --force
./check.sh

The reusable domain model keeps its public domain::* facade while physical ownership follows five acyclic domain directories. domain/operations/runtime/ owns worker, proposal, audit, service-operator, and lifecycle contracts with direct tests; software/ groups request, dependency, graph, lifecycle, projection, and validation owners behind the operations facade. Shared API operation contracts live under api/operations, while stable request, response, status, and streaming contracts live under api/contracts; both roots only re-export named subdomains. The code domain likewise groups call-target policy, context, dependencies, graph records, repository contracts, index state, repository sets, staleness, views, and workspaces into directly tested physical owners instead of sharing flat implementation or test files.

Self-Iteration Harness

For unattended code and semantic/vector retrieval optimization experiments, start the independent Rust self-iteration harness documented in tools/self_iteration through the stable launcher:

./self-iterate.sh
./self-iterate.sh once
./self-iterate.sh loop --strategy unattended-layered
./self-iterate.sh chart

The launcher auto-builds the harness binary when needed. It stores v2 run history, progressive memory, reports, patches, and score curves under .git/relay-knowledge-self-iteration/ and only commits candidates that improve the configured score.

The research judge supports OpenAI-compatible HTTP or an open coding-agent CLI, defaulting to opencode when no backend is configured. The semantic/vector fixture inherits the same RELAY_KNOWLEDGE_* embedding environment as normal runtime commands and does not persist secrets in benchmark cases.

The unattended-layered strategy is tuned for 1-2 day runs. It performs short smoke-level Codex explores, validates promising candidates with the fast profile, persists resume state in .git/relay-knowledge-self-iteration/unattended-state-v2.json, and escalates to longer competitive-capability macro exploration when short attempts stall.

External repositories in the self-iteration evaluation set are pinned to documented commits. C/C++ adds tree-sitter-oriented generated syntax fixtures, and multilingual generated fixtures extend the same evaluation set. See Book 5, Chapter 6: C/C++ Syntax Self-Iteration Evaluation Set and Book 5, Chapter 7: Multilingual Syntax Self-Iteration Evaluation Set. The elastic long-budget model for large repository indexing, including the historical 180-second baseline, throughput calculation, and cap, is documented in Book 5, Chapter 12: Elastic Index Budgets.

Quality Gates

The underlying quality gates are:

cargo fmt --all -- --check
cargo clippy --all-targets --all-features -- -D warnings
cargo test --all-targets --all-features
cargo test --test relay_knowledge graphrag_fixture_dataset_scores_phase4_cases
cargo test --test benchmarks --all-features -- --nocapture
cargo llvm-cov --all-targets --all-features --fail-under-lines 90

CI installs the current stable Rust toolchain. Update local stable before the final Clippy gate so newly stabilized lints cannot pass locally and fail only after the branch is pushed.

OpenTelemetry dependencies are upgraded as one compatibility family: opentelemetry, opentelemetry_sdk, and opentelemetry-otlp stay on the same minor release, while tracing-opentelemetry uses the matching integration release. A partial family update is not release-ready because it can introduce duplicate telemetry traits and incompatible provider types.

The self-iteration harness runs its own product and harness quality checks in parallel dependency stages and defaults --jobs auto to the local CPU count.

The default fast profile also includes targeted code_index_recovery_cases, code_index_sqlite_lock_cases, and code_index_health_isolation_cases, plus a registration-language guardrail. These keep expired code-index leases, stale worker completions, dead-letter recovery, checkpoint lease renewal, duplicate-process SQLite lock avoidance, service health liveness, concurrent code-index task claiming, committed-scope code queries, and mixed-language registration safety from regressing without exhaustive large-repository workloads.

Runtime and Storage

The binary starts a Tokio runtime, and the shared application service exposes async entrypoints from the CLI boundary inward. application::runtime::status owns runtime/API diagnostic projection with direct sibling tests. Physical storage/contracts/ owners separate async errors, topology, graph, search, health, index, operational requests, code graph, canvas, repository code, and file-index contracts behind the stable root facade. SQLite storage is opened through that boundary; sqlite::store owns schema-aware connection lifecycle and bounded blocking workers, while the physical sqlite::graph/ domain assigns graph-fact transactions/evidence invariants to mutation, inspection/version reads to its mod.rs facade, and commit-time validity normalization to version, each with a directly paired test owner. Their direct sibling tests protect worker contention, mutation validation, state defaults, and stable evidence identities; sqlite/{evidence_identity,mutation_log,scope_filters,table_stats,store}/ are physical owners, storage-port mappings live under store/implementations.rs, and cross-owner persistence scenarios live under sqlite/tests/. The physical sqlite/schema/ module owns columns, initialization, compatibility markers, and migration without root path redirects, while sqlite/mod.rs only composes named adapter owners. The net::http::outbound owner contains client construction plus bounded raw JSON transport and response validation, while qos_client retains reqwest permit/body accounting; both attach direct sibling tests and the HTTP facade keeps configuration, server runtime, and cross-boundary integration contracts.

Physical application-service subdomains separate health, retrieval, service status, storage diagnostics/provider, watcher, and lifecycle workflows. Retrieval owns source-scope validation, freshness reconciliation, bounded search/rerank, and response budgets; the service facade retains construction and cross-owner composition. The domain graph::retrieval facade separately owns policy, backend status, diagnostics, evidence, hits, traversal provenance, and context-pack contracts.

The default storage topology is single_sqlite; application::runtime::storage exclusively validates this selection. Set RELAY_KNOWLEDGE_STORAGE_TOPOLOGY=partitioned_sqlite keeps global control state in the main database while repository, catalog, routing, diagnostics, status, totals, and checkpoint/file/lifecycle/retention indexing owners coordinate shards under the runtime data directory. Repository-set overlay refresh still requires single_sqlite until cross-shard import/export aggregation is implemented. After partitioned shard catalog rows become active, startup with single_sqlite fails fast; keep the partitioned topology enabled or perform an explicit rollback that clears the shard catalog and files. Shard routes are resolved from the current runtime data directory, so backups and restores must keep the main database and stores/repositories/ together. The control plane continues to own task leases, audit, operator state, topology catalogs, and diagnostics; data-plane shards only execute reads and writes authorized and budgeted by shared application services. See Service Deployment, Control Plane, and Data Plane for the full contract.

The storage contract includes the v1 code graph data surface for tree-sitter output. SQLite code_graph keeps a declaration-only facade over physical batch/, schema/, query/, and tests/ directories. schema owns DDL, batch owns transactional replacement, while its query owners keep bounded reads and direct tests.

SQLite writes stay on a single writer lane. Code queries, reports, graph reads, file queries, and health diagnostics use bounded read-only connections where SQLite WAL permits concurrent committed-snapshot reads.

After bulk code-index snapshot apply or checkpointed finalize, SQLite storage runs best-effort PRAGMA optimize and PRAGMA wal_checkpoint(PASSIVE). health --format json and graph inspection expose graph.sqlite diagnostics with journal mode, WAL size, last maintenance time, and any maintenance error. Maintenance timestamps and errors are persisted in SQLite so service restarts and one-shot worker exits do not erase the last attempt. Under partitioned_sqlite, those fields aggregate the control database and all active repository shard databases through read-only shard diagnostics. If any active shard cannot be inspected, the aggregate keeps the shard error and reports an unknown WAL size instead of presenting a partial total.

Public health is a liveness-safe read. It does not enqueue index refresh work, and under storage pressure it returns stale/degraded storage_busy diagnostics instead of waiting for indexing to finish.

Code Indexing

Code repository indexing currently parses Rust, Python, JavaScript/JSX, TypeScript/TSX, Go, Java, Kotlin, Scala, C, C++, C#, Ruby, PHP, Swift, Bash, SQL, Markdown, XML, Bazel/Starlark, Make, CMake, Dockerfile/Containerfile, Java properties, TOML, INI, YAML, JSON, Go module files, Ninja, Jinja2, and Go templates with tree-sitter grammars. Physical code::index subdomains separate filesystem delta, full/incremental snapshots, planning, impact paths, and deleted symbols; worktree overlays further separate change recording, directories, scope, plan, snapshot, and untracked policy with direct tests. The code::parser root contains only its facade, cross-domain tests, and named physical subdomains; shared chunks, manual extraction, node/range primitives, record materialization, syntax capture, and text validation each have a dedicated owner. Its languages root keeps C-family references, configuration definitions, enum members, and Markdown imports in physical, directly tested shared domains beside language-specific directories. Structured configuration parsing keeps call aggregation, language detection, key/value facts, knowledge-map facts, normalized records, and source-line primitives in directly tested physical code::config_files owners. code::parser::file separates shared parse contracts, parse-status diagnostics, text-only topics, route projection, and feature-flag projection into direct-tested owners; feature-flag comment shielding, boolean configuration scanning, and extractors likewise live in named, directly tested subdomains. The file facade retains parsing orchestration; unsupported or degraded files fall back to text chunks.

SQL files contribute schema object symbols such as tables, views and materialized views, functions and procedures, triggers, and types, plus SQL object references and function/procedure-call edges.

Same-scope local file, template, and build-target references are resolved during finalize when unambiguous. External or ambiguous configuration relationships stay unresolved metadata.

Registration rejects language filters so mixed-language repositories keep their full language surface; use query-time --language to narrow results.

C/C++ macro-heavy files can be conservatively recovered as parsed when errors are isolated to macro expansions, typedef-style external-header declarations such as Nginx/Kong module tables, GCC/Clang-style declaration attributes and inline extensions such as __attribute__((always_inline)), attribute((always_inline)), and __always_inline, bounded preprocessor directives, or recognized decorator-bearing declarations with declaration-shaped bodies. Recovery still requires reliable structured facts such as symbols, references, or imports.

C/C++ recovery keeps declaration-head token/type/qualifier recognition separate from function-signature, parameter, operator, method-suffix, postfix-attribute, and recovery-decorator recognition. The signature owner depends one-way on the lower declaration and literal-aware scan owners, and both carry direct sibling tests; the C-language adapter keeps declaration symbols, GCC recovery, lexical predicates, macro functions, node kinds, and preprocessor lifecycle in physical, directly tested owner directories, with parser-wide C/GCC scenarios under languages/c/tests/; the C++ adapter keeps deterministic tree-sitter classification in directly tested node_kinds/, and manual head rules, decorated type recovery, and structured/GCC-decorated function recovery in directly tested manual::{lexical,type_definitions,function_definitions} owners, while manual header recovery delegates byte-stable text, top-level scans, class/member name recognition, and nested member collection to directly tested cpp_header_recovery::{source_text,top_level_scan,declarators,member_collection} owners. These owners are real directory modules with direct sibling contracts, not facade files plus production path redirects.

Full Git repository indexing first discovers the tracked source layout; source/layout/discovery owns bounded root inference and effective filters, source/layout/path_scope owns normalized intersection and submodule-child projection, source/layout/selection owns Git/filesystem admission reasons, source/layout/scoped_snapshot owns source resolution, selected entries, effective filters, content hashes, and filesystem-ref consistency, source/layout/preview owns bounded exclusion/largest-file samples and preview counts, and source/layout/impact_partition owns stable in/out-of-scope change partitioning. SQLite snapshot persistence keeps repository attachment, metadata/scope import, and its direct legacy regression in code/snapshot/repository_import, while scope_tables owns the table-copy contract shared with incremental scope cloning. It then uses resource-bounded SQLite batches with durable checkpoints and a finalize phase for cross-batch references, includes, and call edges, so large scopes expose indexing progress without replacing the previous fresh scope until finalization succeeds.

Non-Git batch plans and delta snapshots recheck planned file content hashes before accepting live bytes, so a live edit cannot be committed under an older filesystem synthetic snapshot.

Non-Git source directories use filesystem synthetic snapshots. When no path filter is supplied, they default to source/config/documentation whitelisted roots and do not walk unrelated directories. Explicit path filters opt into matching broad build, cache, and dependency directories, and --path . opts into the whole root.

Incremental updates use the same source-layout policy when new files appear outside src/.

A cold full repo index queues a durable code-index task through storage::sqlite::code::tasks::queue and returns a task handle immediately. The CLI starts a bounded single-shot worker, non-interactive agents can call repo index-worker --task-id <id> --format json for one explicit drain attempt, and service run drains the same queue with a bounded code-index worker pool; application::runtime::worker owns endpoint validation and concurrency from RELAY_KNOWLEDGE_CODE_INDEX_MAX_IN_FLIGHT, plus one set-overlay refresh worker.

Local CLIs can query a deployed resident service with --remote <base-url> or RELAY_KNOWLEDGE_REMOTE_BASE_URL. Remote repository index commands submit durable tasks to the service and return task/status/checkpoint JSON; the remote service run --web worker pool drains those tasks rather than the local CLI running repo index-worker. Remote read-only repository graph commands (repo list, repo query, repo context, repo feature-flags, repo impact, repo report, repo software, and repo view) read service-host index state and preserve their CLI --kind arguments. Remote maintenance commands such as repo index --reset and repo index-worker are rejected by a remote-selected CLI and must be run on the service host; storage::sqlite::code::tasks::reset owns the atomic local reset. Remote dispatch validates the remote URL and outbound network settings before HTTP; unrelated local runtime and retrieval settings are validated only when a command falls back to local state.

Distinct task fingerprints are queued and leased independently, while identical full-index fingerprints reuse the active task.

repo query, repo context, and repo feature-flags with allow-stale continue serving the latest compatible completed scope when the requested ref and filters are still being indexed, marking the response stale rather than blocking behind the writer.

repo status reports active_task, checkpoint counters, and scope retention; storage::sqlite::code::tasks::status owns task lookup and the bounded queue projection, while checkpoint owns scope and latest-progress reads. repo list returns the stable status inventory of repositories with at least one completed indexed scope and omits registrations that have never completed indexing. Successful background tasks retain the active scope, the two latest completed scopes, and unfinished task scopes while pruning older repository scopes; storage::sqlite::code::tasks::retention owns that plan and its transactional cleanup.

Code-index task leases are attempt-scoped, with claim, renewal, listing, and bounded recovery owned by storage::sqlite::code::tasks::lease. Expired running leases are recovered to retry or dead-letter before claim/status paths report them; storage::sqlite::code::tasks::completion owns the lease-checked success, retry, and dead-letter transitions. Stale workers cannot complete or fail a reclaimed task, and active workers renew the lease before expensive batch parsing, after each committed checkpoint batch, around finalization, and before task completion.

Stores that do not implement the optional lease recovery/renewal hooks keep status and indexing reads compatible by treating those hooks as no-ops. Checkpoints expose updated_at_ms in JSON status so operators can distinguish slow progress from a stuck task.

Source Scopes and Overlays

Repository source scope is not limited to a top-level src/ layout. Index planning inspects tracked paths before parsing, so real source under external_deps/, packages/, modules/, plugins/, extensions/, Sources/, lib/, and nested JVM source roots is indexed by default.

Clean Git snapshots treat the tracked tree as the directory authority inside the registered and requested path scope. Tracked .cloudbuild/, .cid/, .build_config/, build/, dist/, vendor/, and third_party/ paths are eligible instead of being rejected by name.

Non-Git source directories do not have a tracked tree authority, so the default scan is whitelist based. Root-level supported source/config/docs files and source-like roots such as src/, include/, lib/, Sources/, packages/, modules/, plugins/, extensions/, docs/, and config/ are eligible, while build/, dist/, target/, node_modules/, vendor/, third_party/, cache, virtualenv, and coverage directories require explicit path opt-in.

That opt-in is path-specific: --path src must not hash node_modules/ or target/, while --path build or --path build/generated.rs opts into the matching broad directory and --path . opts into the whole root.

--path is the CLI flag for a path filter. Use it during repo register to store the indexed scope, and during repo query or repo feature-flags to narrow reads inside that scope. repo index does not accept --path; it indexes the registered scope for the selected --ref.

Default non-Git scans descend only into directories that can contribute whitelist content. Filtered non-Git scans descend only into requested paths and bounded discoverable source roots, so unrelated siblings such as private/ are skipped instead of being read before selector filtering.

Git probe failures on a directory with Git metadata, such as unsafe ownership or corrupt .git, fail loudly instead of falling back to non-Git filesystem indexing.

A default --path src registration is expanded for discovered source roots during indexing, while precise selector path filters still narrow queries and avoid widening into unrelated dependency trees.

Non-Git filesystem: snapshot ids are computed from the effective indexed scope after discovery, so unindexed file edits do not move the scoped ref. Queued synthetic refs, full-index batch reads, and incremental delta bytes are verified before live bytes are accepted, and incremental deletes still remove files from previously discovered roots.

Non-Git moving-ref resolution uses the effective path and language filters for the indexed scope. Non-Git impact path collection uses the same effective indexed filesystem filters, including explicit broad-directory opt-ins. For the normal non-Git workflow, register with the desired --path filter, then use repo index <alias> --ref HEAD and query --ref HEAD; the indexed commit recorded in status is the resulting filesystem:<hash> snapshot.

Git ref normalization for query/status paths uses cheap ref/tree resolution instead of walking the full tracked tree. Git branch, tag, and worktree selectors resolve to scoped commit/tree snapshots; indexed scopes remain queryable by explicit ref, rebase or force-moved heads require a new index before query, and same-tree branches reuse the same scope while preserving requested-ref audit metadata.

Worktree overlays use Git status for Git repositories. Their narrow worktree_overlay::mod facade delegates identity/snapshot assembly to snapshot, regular path classification and recording to change_recording, and bounded submodule transitions to the physical gitlinks/ subdomain. .gitignore-ignored untracked files are skipped, broad directories require explicit path opt-in, and every overlay behavior owner carries direct same-level unit tests. The physical code/source root separates change-status parsing, bounded declaration fallback, non-Git filesystem policy, filter constants, Git execution, ref/snapshot resolution, and source-root candidates into directly tested owner directories. Tracked-entry admission lives in changes/scope; bounded recursive tree enumeration and submodule-state reporting live in paired-test changes/tracked_entries; validated name-status loading lives in paired-test changes/diff; changes/submodule_repository owns safe worktree/gitdir resolution.

Gitlink and submodule source access is grouped under code/source/gitlink/. Tree commit detection, child-filtered entry discovery, initialized or deinitialized submodule blob reads, and worktree-root validation share a dedicated entries owner with direct unit tests; incremental and worktree overlay paths reuse that boundary. Two-sided submodule change classification, bounded nested-gitlink recursion, worktree/git-dir diff fallback, scoped entry expansion, and budget enforcement live in a separate diff owner. Impact orchestration, two-sided fallback merging, stable deduplication, and final budget validation live in the paired-test impact owner; gitlink::mod remains a declaration and re-export facade.

Registering the same repository root with an additional alias preserves prior aliases and resolves all aliases to the same repository id. repo remove <alias> deletes that repository's runtime registration, aliases, index scopes, tasks, repository-set membership and overlays, and software projections without deleting source files on disk; after removal, the same path or alias can be registered again.

Code Retrieval

Code graph v1 responses distinguish stable canonical_symbol_id values from snapshot-bound symbol_snapshot_id values. Reference, call, import, and SBOM dependency hits expose target_hint, resolution_state, confidence basis points, and confidence tier so unresolved, ambiguous, declared, or locked edges are visible instead of being reported as certain calls.

Import resolution covers local same-repository imports for every tree-sitter language listed above, including JavaScript/JSX, Kotlin, Scala, C#, PHP, Rust, and Swift. Package-manager or SDK imports without authorized indexed source remain unresolved edge metadata rather than parser degradation.

Python type-reference parsing separates literal-aware function-signature annotation scanning from tree-sitter node classification. The languages/python/annotations owner handles wrapped parameter and return annotations, default-expression boundaries, and file-local type parameters, with direct sibling tests; the Python module facade retains node-context and local-type-reference resolution.

Web route detection groups Express orchestration, import/factory and application/router alias discovery, call/path syntax, argument/handler parsing, bounded multiline statement aggregation, direct and chained registration recording, mount discovery, and mount materialization under one detect/express/ subdomain with direct unit tests for each owner. The physical detect/lexical/ boundary keeps Python static route strings and JavaScript comment/string/regex lexical state in separate language owner modules rather than a generic shared implementation across language boundaries. Spring annotation and Java type-scope detection is grouped under its own detect/spring/ subdomain; Java comment/text-block filtering and declaration recognition have a dedicated owner, while annotation path/method attribute parsing has another dedicated owner. Bounded multiline annotation aggregation is isolated from both, and mapping-kind and RequestMapping semantics have their own owner; every owner carries direct unit tests. Class-prefix derivation, method combination, URL joining, and route-fact deduplication are isolated in Spring materialization. Flask/FastAPI decorators, router mounts, and Python route materialization are grouped under detect/flask/; Python triple-quoted-string and comment lexical state, bounded multiline statement aggregation, and call-argument parsing each have dedicated owners with direct unit tests. Argument parsing owns top-level boundaries, keyword values, route paths, method collections, named handlers, router identifiers, and static-versus-dynamic mount prefixes. Router declaration, late-merge, include/register mount recording, and framework resolution share a separate router-state owner. Receiver URL expansion, mount-prefix joining, dynamic-prefix filtering, route-fact creation, and deduplication live in a dedicated materialization owner. Route decorators, add_url_rule, methods overrides, receiver/handler recognition, and Python-function binding share a registration owner.

Call graph retrieval resolves static same-repository cross-language edges for C/C++, Go cgo C.*, and Rust FFI/bindings paths. This is code-graph evidence, not full build-system or linker analysis.

Code repository lexical retrieval uses a SQLite FTS candidate table for symbols, references, calls, imports, SBOM dependencies, and chunks. Effective path filters apply before bounded scoring and graph-edge candidates use BM25. FTS planning is split across public plan, hybrid recall, normalized terms, and bounded compound-identifier owners with direct tests and one-way dependencies. Fuzzy symbol recall remains broad while typed graph edges stay narrow; scoring recognizes identifier parts, call direction, and declaration-shaped API chunks. SQLite code-store persistence is one physical storage::sqlite::code tree: batch, feature_flags, generated, impact, lifecycle, query, routes, schema, search, set, snapshot, symbols, tasks, tests, views, and workspace are named directories; behavior owners mount direct tests, cross-owner fixtures and regressions live under tests/, and the facade retains only composition and port implementation. The impact facade coordinates bounded retrieval while seed, evidence, and path_selection separately own graph seeds, SQLite evidence/hit mapping, and changed-path/language admission with paired tests. query::{hits,prepare}, tasks::worktree, set::refresh_tasks, and lifecycle::{cleanup,removal,report,status} belong to their real parents without production path redirects or duplicate file loading. Call retrieval is a real code::query::calls module tree: mod.rs only declares owners and re-exports the query entry point, search coordinates bounded identity/FTS paths, row_store owns SQL and decoding, identity_query owns directional exact gates, hit_projection owns scoring and hit conversion, execution_order owns call-site ordering, and display owns caller labels. Named children continue to own ambiguous targets, caller counts, direction filters, indirect binding recovery, site/context scoring, and target ranking without root path aliases; focused owners carry direct same-level tests. Cross-cutting ranking likewise uses the real code::query::scoring tree, whose directly declared API-sequence, chunk-path, initializer, flow, inline-usage, interface, lifecycle, local-callable, path-ranking, and proximity owners attach their same-level regressions without root aliases. Hybrid planning uses the real code::query::hybrid tree: chunk/direct gates, exact-path decisions, and bounded planning are direct owners, while shared hybrid regressions are assembled through a physical tests::hybrid module. Import retrieval is a real code::query::imports tree: its facade only coordinates layered fallback, row_store owns bounded direct/identifier/FTS SQL and decoding, hit_projection owns enrichment/ranking/hit conversion, scoring owns ranking signals, path_context owns path/target classification, binding_terms owns named-binding and usage-term extraction, and targets owns target-symbol and usage context; focused owners carry direct tests and dependencies stay one-way toward primitives. Reference retrieval is a directly declared physical code::query::references domain, not a root alias: identifier_text owns identifier scans, identity_gate bounds exact admission, call_shape owns call recognition, same_name_path owns source-file demotion, and type_context owns parameter/type affinity; all carry direct regressions. The sibling chunks owner keeps exact definition/reference fallback admission, declaration scoring, and canonical-leaf matching, while chunks::search owns layered FTS planning, SQL/value binding, row mapping, and chunk scoring. The code-query facade also declares symbols directly rather than through code_query_symbols; symbol retrieval keeps orchestration, exact/API identity admission, FTS planning, row decoding, ranking, bounded direct recovery, and typed function-value interpretation in named owners, each with direct tests. The code-query root contains only accuracy, api_identities, calls, chunks, conversion_terms, excerpts, hits, hybrid, identifiers, imports, line_ranges, prepare, references, relevance, routes, rows, sbom, scoring, symbols, and tests directories plus its facade. Cross-domain primitives are directory owners, behavior tests live beside their owner, and consumers use real module identities instead of flat siblings, code_query_* aliases, or root #[path] redirects. The shared code-query test root likewise contains only calls, field_filters, generated, hybrid, identity, line_context, ranking, score, and unit domains plus its declaration facade; the query-test facade declares each domain directly, and the code-store facade does not remount individual query regressions through cross-layer path attributes. Graph retrieval keeps deterministic token signatures, local hashed vectors, semantic overlap, cosine similarity, and identifier-aware lexical overlap in local_model/; aliases/, bm25/, bm25_fallback/, and the context, derived, label-trigram, and ranking directories own their named behavior and direct tests. The shared retrieval::terms owner exposes only normalized terms used by reranking. The physical read_model/ subdomain assigns DDL/retry to schema, rebuilds to migration, document writes to documents, shared candidates/BM25 mapping to candidate/bm25_hit, and retrieval orchestration to search; the sibling advanced/ subdomain separates relation/claim/event path assembly in path, temporal parsing and filtering in temporal, scoped summaries in community, shared event reads in event, and evidence grouping in support. SQLite graph-canvas projection likewise assigns request state/budgeting to context, stable node formatting to nodes, evidence/entity reads to knowledge, relation/claim/event reads to facts, and code facts to code, with owner-local tests and a validation-only facade.

Feature-flag extraction separates source-key rules, SDK receiver/call tracking, and shared literal-aware lexical primitives; each owner has direct sibling tests and the extractor facade only re-exports the stable internal surface. Repository-set orchestration assigns membership APIs to membership, moving-ref and fact-version freshness to status, set-specific storage errors to errors, and synchronous plus leased overlay rebuilds to refresh; the physical query/ domain separates pure overlay ranking in mod.rs, async member/fallback coordination in workflow, dependency API planning in plan, and ranking signals in domain_affinity and identity_coverage, with directly paired tests. SQLite repository-set persistence likewise separates member lifecycle/status mapping in code::set::membership from overlay status, refresh, import/export matching, and cross-edge reads in code::set::overlay; the code::set facade only re-exports their narrow entry points. Its paired-test manifest/ domain separates database coordination, Go workspaces, pnpm/package exports, module-key expansion, and bounded path/glob rules. The physical code::set root contains only manifest, membership, overlay, refresh_tasks, and tests directories plus its facade. The three behavior owners carry direct mod_tests.rs; cross-owner workspace coverage and fixtures are isolated under tests/, so flat implementation or test siblings cannot return beside manifest/. Code-index schema initialization keeps only ordering, legacy-column compatibility, and migration orchestration in the code::schema facade. Repository facts, durable index tasks, repository-set/workspace state, and FTS/retrieval indexes have separate schema owners with direct sibling contract tests. The search_backfill owner isolates one-time FTS document materialization for symbols, references, imports, dependencies, feature flags, calls, routes, and chunks, plus search-metadata synchronization and transactional call-document rebuilding after signature upgrades. Checkpointed indexing gives code::batch/{checkpoint,dependencies,persistence,session}/ physical owner directories with direct mod_tests.rs, and finalization similarly groups call targets/edges, files, imported/ordinary references, phases, search documents, and symbols into directly tested owners while cross-owner TypeScript cases live in finalize/tests; its imports/{module_paths,specifier,symbol_targets}/ owners pair bounded normalization/extraction/matching with direct mod_tests.rs beside the existing language subtree. Both facades retain only declarations and stable re-exports; shared code-identity import resolution separates context/module paths, symbol matching, and outcome mapping with direct sibling tests. SQLite index lifecycle keeps schema, cursor status, refresh diagnostics, metadata codecs, and durable task queue behavior in separate owners; its facade contains only direct re-exports.

repo query --kind sbom returns dependency inventory facts extracted during indexing from Cargo, npm, Go, Python, Maven effective pom.xml/BOM, Gradle, and Conan manifest or lock files. It does not execute package managers, contact registries, or provide vulnerability/license analysis.

Maven effective POM handling gives physical pom_path/, property_interpolation/, and xml/ owners direct tests; model/ separates coordinate aliases, dependency management, and plugin/execution inheritance into paired-test owners while its facade composes parent/profile/BOM resolution. Cross-owner review regressions remain under tests/, and all resolution uses indexed evidence only.

Call excerpts use a source_scope + symbol_snapshot_id chunk lookup and line containment so high fan-out caller/callee queries do not multiply one call edge across unrelated chunks.

Code repository queries also use bounded internal exact-text source fallback. The code::search::candidate_scope owner applies safe-path validation, deduplication, generated-path exclusion, path/language filters, and the 256-file budget before materialization. materialization owns commit re-verification, byte/read budgets, and temporary-tree lifecycle; scanner owns bounded excerpts and result ordering.

For non-Git filesystem commits, fallback first verifies that the current synthetic snapshot still equals the indexed filesystem: commit. If it has moved, fallback reports degradation instead of reading live files from a different snapshot.

Definition fallback chooses the last identifier-like query target, so command words in natural-language prompts are not searched as symbols.

If the FTS read model is unavailable, candidate-path lookup first uses indexed path and chunk terms to keep source fallback query-aware. When no query-aware candidates can be produced, it reports the read-model degradation instead of scanning lexicographic file prefixes.

Only source-plannable definition, reference, and single-identifier hybrid queries may return empty indexed results for source fallback. Import, symbol, caller, callee, and non-plannable hybrid queries surface the read-model error instead of silently returning false negatives.

When earlier lexical layers already produced usable hits, later FTS-layer outages preserve those partial hits and mark them degraded instead of clearing them or hiding the outage.

Missing external dependency source is reported as unresolved edge coverage metadata, not as degraded_reason. External dependency fallback searches use the unresolved target hint rather than arbitrary user query text, stay below structured import-graph evidence in ranking, and are marked with text_fallback so agents treat them as current-repository source evidence, not dependency-library graph evidence.

Candidate lookup, candidate-file, materialized-byte, and line-length budget failures degrade only the fallback layer. Structured code graph results remain available and report diagnostics.

For manual agent or maintainer inspection, prefer rg. If it is not installed, use bounded grep -RIn searches with VCS and build directories excluded rather than stopping source analysis.

GraphRAG, Workers, and Recovery

Hybrid retrieval uses SQLite-backed BM25, local semantic token signatures, local hashed-vector ANN, configurable external semantic/vector backend metadata, graph evidence fallback, schema-guided path traversal, temporal event retrieval, community summaries, and code graph documents.

It fuses candidates with reciprocal-rank fusion, applies a deterministic local rerank before final truncation, and returns a context pack with retriever sources, ranking and rerank explanations, entities, source spans, structured graph facts, direct graph path evidence, code artifacts, backend availability, freshness, truncation, and budget metadata. The BM25 read model indexes generated lexical aliases for entity labels and code symbols without returning those aliases as canonical labels.

Evidence can carry multimodal extraction metadata for text spans, image assets, OCR text, captions, image embeddings, tables, and layout regions. Derived OCR/caption/image evidence references a parent evidence item, retrieval groups those hits by parent to avoid duplicate context items, and background or maintenance workers commit OCR/caption/table/layout outputs through commit_multimodal_extraction rather than query hot paths.

Operational productization uses storage::sqlite::operations::schema to initialize and compatibly upgrade worker-task, proposal, audit, and operator tables; operations::worker_tasks, proposals, and audit_events separately own worker queues, proposal/conflict lifecycle, and audit writes/queries, while service_operator owns silent-update operator state and JSON row mapping. Multimodal ingest queues embedding/OCR/vision/extractor work; worker run-once calls a configured HTTP endpoint when available or creates a deterministic fallback proposal; proposal accept commits through the same graph mutation path; and service manager commands now expose staged install, upgrade, rollback, and uninstall lifecycle plans. Plan assembly, forward/rollback steps, checkpoint files, bounded process execution, step policy, and platform definitions use directly tested owners. Dry-run is the default; explicit service lifecycle ... --execute runs local file steps and platform service-manager commands with rollback steps if a later stage fails; failures return the failed step id.

The evaluation module provides a pure GraphRAG harness plus a CI fixture gate for exact fact, multi-hop, temporal, negative rejection, stale index, ambiguous entity, and code impact observations.

Graph commits also persist Phase 2 index recovery metadata. Mutation log entries record affected scopes, entity ids, evidence ids, and source hashes, including scope moves and structured-fact evidence references. Scoped index cursors track kind/scope/modality freshness plus source hash, backend cursor, and optional model name/dimension metadata for semantic/vector workers.

application::knowledge/{ingest,multimodal,file_freshness,index_refresh,map}/ owns each workflow and direct UT; their callers share the bounded refresh queue. Its physical task_queue/ owners separate planning, enqueue/upsert, lease recovery, completion, failure, and persisted record identity/decoding. All transitions remain lease-fenced, bounded, observable, and recovery-safe. index_refresh.stale_reasons explains index-family and scoped-cursor lag or failure by kind, scope, modality, lag versions, and last error.

CLI Contract

Current CLI commands use the compiled relay-knowledge binary with git-style subcommands:

The adapter groups global option/token parsing and command-family dispatch in the paired-test interfaces::cli::command::parse owner; shared flag-value and freshness validation live in command::values. CLI errors, grammar diagnostics, exit-code classification, and stderr encoding live in command::diagnostics; the root only re-exports these contracts and retains the process facade. Every command, files, grammar, knowledge, map, operations, remote, render, repo, repo_set, runtime, service, setup, spec, and version owner is a physical directory; behavior owners mount direct mod_tests.rs contracts, while the CLI root contains only those named domains, tests/, and mod.rs, without *_cli aliases or production path redirects. The repository family keeps command data in repo::mod, grammar and validation in paired-test repo::parser, and async service execution/rendering in paired-test repo::runner; repo::view owns the nested view contract and workflow instead of appearing as a CLI-root sibling. Machine-readable command metadata uses the physical spec::{data,files,repo,repo_set} module tree; repo::{lifecycle,indexing,retrieval} own repository builders and paired tests while data::{core,map,operations,service} own aggregation families. Process-free dispatch stays in runtime::dispatch; explicit versus environment remote selection and eligibility stay in runtime::selection.

relay-knowledge status --format json
relay-knowledge help repo query --format json
relay-knowledge ingest --source docs --content "Rust async services isolate blocking SQLite work" --entity Rust
relay-knowledge query SQLite --freshness wait-until-fresh --format json
relay-knowledge repo register /path/to/relay-knowledge --path src --format json
relay-knowledge repo index relay-knowledge --ref main --format json
relay-knowledge repo index-worker --task-id <task-id> --format json
relay-knowledge repo update relay-knowledge --base main --head HEAD --format json
relay-knowledge repo query relay-knowledge --query retry_policy --kind definition --ref HEAD --path src --language rust --freshness wait-until-fresh --limit 10 --format json
relay-knowledge repo context relay-knowledge --query "retry_policy callers imports" --ref HEAD --path src --freshness wait-until-fresh --limit 8 --max-context-bytes 16384 --format json
relay-knowledge --remote http://127.0.0.1:8791 repo query relay-knowledge --query retry_policy --kind definition --freshness wait-until-fresh --format json
relay-knowledge --remote http://127.0.0.1:8791 repo software relay-knowledge --kind relationships --ref HEAD --format json
relay-knowledge repo query relay-knowledge --query serde --kind sbom --ref HEAD --format json
relay-knowledge repo feature-flags relay-knowledge --query checkout --ref HEAD --format json
relay-knowledge repo software relay-knowledge --kind relationships --ref HEAD --format json
relay-knowledge repo-set create workspace --format json
relay-knowledge repo-set add workspace relay-knowledge --ref HEAD --priority 10 --format json
relay-knowledge repo-set remove workspace relay-knowledge --format json
relay-knowledge repo-set query workspace --query retry_policy --kind definition --format json
relay-knowledge repo impact relay-knowledge --base main --head HEAD --format json
relay-knowledge repo list --format json
relay-knowledge repo status relay-knowledge --format json
relay-knowledge graph inspect --format json
relay-knowledge index refresh --kind bm25 --format json
RELAY_KNOWLEDGE_FILE_INDEX_ROOTS=/opt/docs relay-knowledge files index --root /opt/docs --source local-files --format json
relay-knowledge files query "quarterly design pdf" --source local-files --freshness wait-until-fresh --format json
relay-knowledge worker status --format json
relay-knowledge worker run-once --kind ocr --format json
relay-knowledge proposal list --state proposed --format json
relay-knowledge proposal accept <proposal-id> --by reviewer --reason reviewed
relay-knowledge audit query --limit 50 --format json
relay-knowledge health --format json
relay-knowledge service doctor --format json
relay-knowledge service plan install --format json
relay-knowledge service plan upgrade --target-version 1.2.3 --format json
relay-knowledge service lifecycle install --dry-run --format json
relay-knowledge service definition write --format json
relay-knowledge service operator pause
relay-knowledge setup doctor --format json
relay-knowledge setup profile agent-readonly --format json
relay-knowledge version check --format json
RELAY_KNOWLEDGE_MCP_ALLOWED_SCOPES=docs relay-knowledge service run --web --mcp streamable-http
relay-knowledge query --help
relay-knowledge query -- --help

repo-set refresh rebuilds cross-repository import overlay edges from the indexed member snapshots. The overlay understands Go workspace/module manifests (go.work, go.mod) and pnpm workspaces (pnpm-workspace.yaml plus package package.json names, entry points, and exports). Nested go.work files only scope go.mod filtering to their own directory tree, pnpm package globs only match paths under the workspace root, and package keys are parsed from complete workspace/package manifest content retained during indexing. pnpm root packages are always included, a workspace without packages includes only the root package, and exports takes precedence over main/module entry aliases. Declared package exports entries also bind package subpath keys: conditional export objects select a single preferred runtime target, wildcard subpath exports map matching file patterns, and private files outside declared exports do not receive synthetic package subpath aliases. Imports that still cannot be matched to a member package are retained as unresolved cross edges with target hint evidence.

Kind Reference

--kind values are command-local. Do not reuse a value from one command family in another command just because the flag name is the same:

  • repo query --kind and repo-set query --kind select code retrieval intent: hybrid, symbol, definition, references, callers, callees, imports, or sbom. Use repo impact for impact analysis and repo feature-flags for feature flags instead of inventing query kinds.
  • repo software --kind selects repository-wide software graph slices: dependencies, sdks, files, topics, relationships, build, iac, design, or all.
  • index refresh --kind selects derived retrieval index families: bm25, semantic, or vector. Omitting --kind requests every supported index family.
  • worker status|run-once --kind selects background worker families: embedding, ocr, vision, or extractor.
  • map source add|update --kind labels knowledge-map source categories: repo, file, doc, config, db, ci, runtime, wiki, or monitoring.

Knowledge-map commands that read or write .knowledge/knowledge-map.yaml discover the repository root from the process start directory. Discovery walks up to the first .git or .knowledge marker and falls back to the nearest AGENTS.md for compatibility. If no repository marker is found, the command fails with a stable error instead of writing runtime state into the current directory. map agent-snippet does not require repository-root discovery.

CLI parameter meaning is part of the public contract. Skills and other LLM tools should inspect relay-knowledge help --format json before issuing commands. It describes each command path, operation, read/write effect, required parameters, defaults, allowed values, repeatability, examples, and notes.

Local file indexing roots must be absolute and present in RELAY_KNOWLEDGE_FILE_INDEX_ROOTS; application::runtime::file_index owns root normalization, stable root IDs, authorization and scan/query budgets before scanning. The application file_index subtree separates async APIs from the bounded scanner; its physical content/ domain assigns read-byte accounting, extraction/chunking, and capability-root reads to budget, extract, and read, each with a directly paired test. RELAY_KNOWLEDGE_FILE_INDEX_SCAN_TIMEOUT_MS sets the per-root timeout. files query --format json returns freshness, cursor, lag, bounded-rescan, and direct-source-read diagnostics; --freshness wait-until-fresh suppresses pending, degraded, or overflowed answers until a bounded scan completes.

SQLite file_index keeps metadata schema, transactional root updates, retirement, path FTS search, diagnostics, content, and cross-owner tests in physical directory owners; its facade only re-exports stable store boundaries. The nested content domain separately owns schema, identity, persistence, bounded FTS search, and fact-candidate extraction with paired tests; the store adapter retains the stable file_index::content::search boundary, while production and test files never mix beside root subdirectories.

File Watcher (fs.watch)

The resident service run process starts the file watcher for registered code repositories and pushes source-code changes into the durable code-index task queue automatically. It is enabled by default on supported platforms.

RELAY_KNOWLEDGE_WATCHER_ENABLED=true
RELAY_KNOWLEDGE_WATCHER_DEBOUNCE_MS=3000
RELAY_KNOWLEDGE_WATCHER_MAX_WATCH_DIRS=1024
RELAY_KNOWLEDGE_WATCHER_HASH_CACHE_CAPACITY=4096

The watcher root keeps config/, event_filter/, hash_cache/, and task_seed/ as directly tested owners; engine/ separates handles, the notify event loop, repository registration, task projection, and diagnostics. Events remain debounced, hash/path-filtered, and queued through existing leases, retry, and dead-letter handling. Diagnostics (state, watched repositories, event/drop and queued-task counts, degraded reason) appear in service status --format json.

Semantic and Vector Backends

Semantic/vector read-model metadata enters only through the env boundary; application::runtime::retrieval exclusively owns typed backend, rerank, and remote-embedding validation. Defaults are local; external metadata uses:

RELAY_KNOWLEDGE_SEMANTIC_BACKEND=external
RELAY_KNOWLEDGE_VECTOR_BACKEND=external
RELAY_KNOWLEDGE_LLM_PROVIDER=openai_compatible
RELAY_KNOWLEDGE_EMBEDDING_BASE_URL=https://api.example.com/v1
RELAY_KNOWLEDGE_EMBEDDING_API_KEY=...
RELAY_KNOWLEDGE_TEXT_EMBEDDING_MODEL=text-embed-3-small
RELAY_KNOWLEDGE_IMAGE_EMBEDDING_MODEL=clip-vit-b32
RELAY_KNOWLEDGE_EMBEDDING_DIMENSION=1536

RELAY_KNOWLEDGE_SEMANTIC_BACKEND and RELAY_KNOWLEDGE_VECTOR_BACKEND also accept local and disabled. Disabled read-model backends are excluded from semantic/vector retrieval execution and refresh scheduling; blank embedding model names fail during runtime configuration.

Settings and Graph Facts

The Web Settings page groups agent interoperability, retrieval defaults, and model providers. Agent/retrieval settings read the same redacted runtime and service diagnostics to prepare MCP exposure, scope policy, audit, and external model environment variables, including the configured MCP origin allow-list.

Model provider settings manage named chat/completion profiles, fallback policies, catalog refresh from models.dev, endpoint probes, and model discovery through /api/configs/model/*; model_provider::profiles owns profile CRUD, secret preservation and runtime-profile resolution; model_provider::profile owns public profile contracts, persisted shapes, and redacted projection; profile_config owns normalization and validation; model_provider::fallback owns fallback types, defaults, validation, and persistence; model_provider::catalog owns catalog contracts, cache fallback, refresh, and payload parsing; model_provider::connectivity owns probe/discovery contracts, QoS HTTP workflows, redaction, and diagnostics. Profile and fallback files live under the resolved config directory as model-profiles.json and model-fallback.json; the public catalog cache lives under the resolved cache directory as model-catalog-cache.json. Secret values are accepted only on save and are returned to the browser as configured booleans or redacted headers.

Profile updates preserve redacted stored header secrets unless a replacement value is supplied, and API callers can set clear_api_key=true to explicitly remove a stored API key during header-only migrations.

The CLI ingest command writes evidence plus entity labels. The shared API also accepts richer Phase 1 graph facts for adapters: evidence source_path, source span, confidence, lifecycle status, typed relations, claims, and events that reference evidence ids. Structured facts must cite supporting evidence, supplied confidence, span, and version-range fields are revalidated after deserialization, and retrieval only uses accepted or proposed evidence as context. Context pack items now expose direct graph_paths derived from those structured facts so agent callers can cite one-hop relation, claim, or event paths alongside raw fact provenance.

Web, MCP, and ACP

service run --web --mcp streamable-http starts the same-port Web diagnostics, /api/*, and resident MCP Streamable HTTP adapters on the configured local HTTP bind, defaulting to http://127.0.0.1:8791/ and http://127.0.0.1:8791/mcp. MCP is disabled unless requested by the command or RELAY_KNOWLEDGE_MCP_STREAMABLE_HTTP_ENABLED=true; graph tools require RELAY_KNOWLEDGE_MCP_ALLOWED_SCOPES unless RELAY_KNOWLEDGE_MCP_ALLOW_UNSPECIFIED_SCOPE=true is explicitly configured or the requested scope matches a code repository alias already registered in this runtime. The physical Web adapter keeps assets/, files/, model_config/, operation_request/, and code/ as named subdomains with directly paired tests; web/mod.rs only composes their routes and shared response/error boundary, while assembled-router file integration coverage remains facade-owned. The code/ domain assigns versioned repository routes to mod.rs, CLI-shaped index payload mapping to index_request, and code-view payload mapping to view_request, without flat feature siblings or production #[path] redirects. The physical MCP root groups audit, HTTP, JSON-RPC, metrics, notifications, prompts, resources, scope authorization, session state, tool contracts, and the tool registry into directly tested owner directories, while assembled protocol/tool scenarios and fixtures live under mcp/tests/. Its runtime/ subtree gives shared server state, HTTP transport lifecycle, JSON-RPC dispatch, cancellable tool execution, built-in read-only tools, and method-error mapping to runtime::{server,transport,dispatch,tool_runtime,builtin_tools,method_error}; code-tool schemas, requests, retrieval, and insights remain under focused code_tools owners. application::runtime::agent owns these endpoint, origin, scope, request-budget, and audit-queue settings. Registered repository aliases are promoted into a process-local MCP allow-list on first use; unknown scopes are still rejected with the missing scope and the exact RELAY_KNOWLEDGE_MCP_ALLOWED_SCOPES=<scope> repair hint.

The adapter validates initialize params, then issues an unpredictable Mcp-Session-Id. Clients must send notifications/initialized, then include that session header and MCP-Protocol-Version on later calls so ping, tool requests and notifications/cancelled stay bound to the issued session. Missing session headers are rejected with HTTP 400; unknown or evicted session IDs are rejected with HTTP 404.

MCP discovery is storage-cold: initialize, notifications/initialized, and tools/list register and return static schemas without opening SQLite. Storage opens lazily on the first storage-backed tool call, and the first tools/list per session records an initialize-to-tools-list cold-start metric. Code query tools return an explore_budget based on indexed file count, cap oversized result sets for agent context, reject free-text queries over 10,000 characters and path filters over 4,096 characters, and return compact outlines for container types when include_code=true.

The MCP tool surface includes graph retrieval, graph inspection, health, service status, index status, authorized code graph queries, one-call codegraph context packs, authorized software global-model queries, repository-set code graph queries, and authorized code impact analysis. Agent-facing kind selection reuses existing product kinds: relay_code_query handles code graph kinds, relay_codegraph_context composes bounded hybrid/definition/symbol entry queries with references, callers, callees, imports, snippets, budget, freshness, and truncation diagnostics, relay_software_query handles software global-model kinds, and relay_code_feature_flags handles configuration-driven feature flags. Common agent aliases such as dependency, configuration, and models normalize to the existing dependencies, relationships, and design kinds instead of creating duplicate kinds. MCP does not expose index refresh or repository indexing; run relay-knowledge repo index, relay-knowledge repo update, or relay-knowledge index refresh from an explicit CLI/Web workflow before MCP queries depend on fresh indexes.

The MCP server also advertises resources and prompts: resources expose service status, health, index status, and Prometheus text metrics; the graph-wide summary resource is advertised only when RELAY_KNOWLEDGE_MCP_ALLOW_UNSPECIFIED_SCOPE=true. Prompts provide retrieval and code-impact planning templates. /mcp/metrics exports a small Prometheus-compatible snapshot for graph version, index refresh backlog, dead letters, QoS request counts, and per-index stale state.

Agent requests write bounded in-process audit events with runtime identity, scope, freshness, QoS decision, budget, truncation, result count, and status; the physical interfaces/agent/audit/ owns the log and JSONL sink; policy/ owns shared validation and authorization policy, and both keep direct tests. Set RELAY_KNOWLEDGE_AGENT_AUDIT_SINK_ENABLED=true to mirror those events to the path-owned JSONL file logs/agent-audit.jsonl; its bounded async queue is controlled by RELAY_KNOWLEDGE_AGENT_AUDIT_QUEUE_DEPTH and capped at 65536 entries.

The local ACP session adapter exposes the same retrieval contract for agent-client sessions, including progress updates, cancellation, and context artifacts. Foreground service startup runs a recovery pass that refreshes stale index cursors before accepting resident adapter work.

Browser Checks

Web diagnostics, operation workspace, and browser integration checks:

./build.sh
./run.sh start --port 8791 --daemon
curl http://127.0.0.1:8791/api/health
uv sync --extra dev --no-default-groups
uv run --extra dev python -m playwright install --with-deps chromium
uv run --extra dev pytest tests/browser

The static workspace exposes health, GraphRAG, graph canvas, index, worker, and operation-composer diagnostics through the same bounded Rust HTTP service. See Web Workspace Capabilities for user workflows and Engineering Hard Constraints for the operation_request and assets ownership and sibling-test contracts.

Optional Hooks

Optional local hooks:

pre-commit install
pre-commit run --all-files