Codifies the rule after the 2026-10 incident where p2p and topology work pinned the CPU of a memory-constrained host. Lists the components that do not consult the governor yet. Signed-off-by: trvon <me@trevon.dev>
18 KiB
| description | argument-hint |
|---|---|
| YAMS repo supplement — conventions, structure, and repo-scoped rules | [TASK=<description>] [MODE=<engineering|bug-bounty>] [PHASE=<start|checkpoint|complete>] |
AGENTS.md (Repo Supplement)
Operating model (retrieval contract, execution loop, metadata, handoff,
ask-first list): docs/prompts/PROMPT-eng-codex.md. C++ design/TDD/assertion/
profiling flow: docs/prompts/PROMPT-yams-cpp-workflow.md. This file holds
only what is specific to this repository.
Repo Intent
Engineering on YAMS itself, plus scoped non-destructive bug-bounty research.
Dogfood YAMS as the distributed memory across sessions, agents, and handoffs —
yams grep/search/graph before local discovery, always (see the retrieval
contract in the prompt). The graph holds document, path, version, entity, and
semantic-neighbor relations; code-symbol nodes and calls/defined_in edges
were removed in v0.20, so answer "who uses X" with yams grep.
Development Memory
Store development audits, plans, decisions, and handoffs in YAMS with task/source/ phase metadata, not as new local Markdown documents. Keep repository instructions here; keep executable tests and raw benchmark artifacts in their normal locations. Before removing a local note after ingestion, hydrate its returned hash and verify the content. An add acknowledgement is not a successful read-back. If hydration fails, report the blocker and preserve the only recoverable copy until it is safe to remove; do not describe the migration as complete.
Mobile Host Consumers
When YAMS is embedded in a mobile app, treat libyams_mobile as a local corpus
SDK, not an inference or account SDK. Keep host UI focused on explicit import,
library, retrieval, result inspection, and confirmation-gated deletion. Do not
make a paid entitlement, account, or remote service a prerequisite for reading,
exporting, or deleting a person's local corpus.
Before asserting mobile support, record the exact native artifact, ABI version,
device/OS, and architecture slice. A host-only unit test proves lifecycle logic;
it does not prove that an Android .so or iOS XCFramework loads on hardware.
Keep physical-device claims separate and reproducible.
CLI Philosophy
- Clean default behavior over feature flags and one-off env vars.
- Add an env knob only when it materially improves usability/debugging/perf.
- Auto-select behavior when safe rather than exposing another switch.
- Remove temporary diagnostics once product behavior is clear.
Tuning Surfaces
- Tuning lives in typed config, not env vars: new search/topology/daemon knobs
go on the relevant config struct (
SearchEngineConfig,TopologyConfig, …) with a TOML key resolved throughConfigResolver(include/yams/daemon/components/ConfigResolver.h). - Benches/tests/callers set the typed field directly or write a per-test
config.toml(DaemonHarnessOptions::configPath) — never a freshYAMS_*env var. ExistingYAMS_SEARCH_TOPOLOGY_*/YAMS_EMBED_*overlays are test-only; keep them working, do not grow them. - Reaching for
std::getenvfor a tunable is the warning sign.
Repo Structure (Start Here)
- CLI entry points:
src/cli/· services:src/app/services/ - Search (grep/semantic):
src/search/· metadata/indexing:src/metadata/ - Storage engines:
src/storage/· vector DB/embeddings:src/vector/ - Daemon client/server/components:
src/daemon/· MCP:src/mcp/ - Tests:
tests/· vendored libs:third_party/(own git repos)
Conventions (Condensed)
- Formatting is mechanical:
.clang-format(LLVM base, 4-space, 100-col). - Naming: functions/vars
camelCase; typesPascalCase; constantskPascalCase; members trailing_; filessnake_case. Result<T>for fallible operations, explicit propagation.- Public/installable headers include other public YAMS headers through the canonical
<yams/...>include root. This validates installed-SDK layout and keeps includes stable when headers move. Use quoted relative includes only for private, non-installed implementation headers or explicit test/bootstrap exceptions. - Prefer
YAMS_HAS_*gates frominclude/yams/core/cpp23_features.hpp.
Engineering Quality Loop (C++)
- Design the seam first: observable behavior, boundary, smallest testable seam.
- Red before green: failing Catch2 test through public/repo-stable APIs; characterize existing behavior before refactors.
- Assertions: recoverable failures stay in
Result<T>;YAMS_ASSERT/YAMS_PRECONDITION/YAMS_POSTCONDITIONfor always-on invariants;YAMS_DCHECKfor debug-only consistency; expressions side-effect free. - Refactor under green tests; no broad rewrites without seam/test evidence.
- Measure before optimizing: workload + KPI + baseline, change one thing,
re-measure.
YAMS_*profiling macros only with a clear question.
Build Setup
- Configure/build through the repo script; it resolves Conan + Meson and prefers
Clang:
./setup.sh Debug(alsoRelease,Profiling,Fuzzing). - Build dirs are chosen per type:
Debug->build/debug(the unit-test lane;.clangdpoints here),Release->build/release,Profiling->build/profiling,Fuzzing->build/fuzzing. Override withYAMS_BUILD_DIR. The legacybuilddirname is still accepted by some helper scripts. - Debug enables TSAN by default; pass
--no-tsanfor faster local iteration. - Tests are opt-in outside Debug. If
meson compile -C <dir> <target>reportstarget not found, that dir was configured without tests; reconfigure withmeson setup --reconfigure <dir> -Dbuild-tests=true --wrap-mode=default. - One writer per build dir; never run parallel
meson compileinvocations.
Testing Conventions
- Catch2 v3; files end
_catch2_test.cpp; live intests/unit/<subsystem>/; registered intests/meson.build; targets named without_exe. - Compile:
meson compile -C build/debug -j4 <target>— never run parallel meson compiles (build-dir lock contention). - Run:
build/debug/tests/<target>ormeson test -C build/debug <name>. - Enable tracked hooks with
git config core.hooksPath .githooks. The default pre-push hook runs the blocking Linux+macOS CI gate, not coverage. Run coverage explicitly withYAMS_PREPUSH_COVERAGE=1 git push; it dispatchesscripts/run-local-coverage.sh, buildsbuild/coverage, prefers ccache and a fast linker override when available, runs the unit-suite fast path by default, and prints agcovrtext summary for pushed C/C++ / Meson changes. Opt into integration coverage withYAMS_COVERAGE_INCLUDE_INTEGRATION=1. UseYAMS_PREPUSH_GATE_SELF_TEST=1 git pushto prove hook wiring without the expensive build/test work. Temporary bypasses:YAMS_SKIP_PREPUSH_CI_GATE=1 git pushorYAMS_SKIP_COVERAGE_HOOK=1 YAMS_PREPUSH_COVERAGE=1 git push. - Optimize test overlap and suite shape, not away correctness. Keep a fast default correctness lane, but move stress/soak, migration, heavy log-capture, and multi-second wait tests into explicit slow suites or binaries instead of deleting them.
- Avoid repeated expensive bootstrap in broad suites when bootstrap is not the behavior under test: temp DB + pool + migration + daemon/KG setup should be reused, pre-seeded, or split into narrower binaries where safe.
- Prefer deterministic synchronization (
promise/future, latches, condition variables, observable state transitions) over fixed sleeps and long polling loops. If polling is unavoidable, keep deadlines tight and justify them. - Non-log-assertion tests should clamp log volume; verbose daemon/service logs belong in focused diagnostics/logging tests, not the default fast TSAN path.
- Split monolithic Catch2 binaries when one executable bundles many unrelated
files and blocks
meson testparallelism; preserve behavior coverage while improving failure locality and runtime. -DYAMS_TESTING=1gatestesting_*helpers in production headers.- RAII guards for global state (
ProfileGuard,EnvGuard,HwGuard); reset atomics/overrides between cases. - DynamicCap sentinel:
UINT32_MAX= unset (use it when resetting, not0).
Benchmarks & Experiments (local xplan)
The xplan harness is optional, gitignored local tooling and is not present in a
clean clone. When it is available, daemon KPI and search-engine
quality/latency ablations use it; do not invent parallel multi-arm shell
matrices. Organized default-system numbers: docs/benchmarks/index.md.
Per-run detail (gitignored):
build/benchmarks/<plan>/<stamp>/ (REPORT.md, ablation.md, metrics.csv).
Entry points
python3 tests/benchmarks/xplan/runner.py self-test
python3 tests/benchmarks/xplan/runner.py list-plans
python3 tests/benchmarks/xplan/runner.py download-beir # scifact + nfcorpus
python3 tests/benchmarks/xplan/runner.py run <plan> --build-dir build/release
python3 tests/benchmarks/xplan/runner.py report build/benchmarks/<plan>/<stamp>
python3 tests/benchmarks/xplan/runner.py compare <dirA> <dirB>
| Surface | Path |
|---|---|
| Default-system numbers | docs/benchmarks/index.md |
| Harness (how it works) | tests/benchmarks/xplan/README.md |
| Plans / workers | tests/benchmarks/xplan/plans/, …/workers/ |
| Artifacts | build/benchmarks/** (gitignored) |
Quality plans default to BEIR scifact. Do not rank search levers on
dataset=synthetic (ingest/load throughput only). Prefer
build/release/tests/benchmarks/retrieval_quality_bench for quality runs.
Search engine measurement loop
The primary optimization surface is src/search/ (SearchEngine, fanout,
fusion, rerank, topology assist). Topology is one optional assist path — not the
whole loop. Engine expansion (new stages, seams, fusion/rerank knobs) must be
driven by this loop, not intuition alone.
-
Name the lever — one typed
SearchEngineConfig/ topology field (or a tested seam extract). No new productYAMS_*env tunables. -
Pick a plan by question:
Question Plan Which hybrid component carries quality? search_component_ablationTopology-off control search_product_component_ablation(repeats=3)Current default vs topology off vs traced shadow search_shadow_cost(repeats=3)Vector fusion weight search_vector_weight_ablation(repeats=3)Vector weight multi-corpus gate search_vector_weight_0_20_multicorp(repeats=3)Graph-vector fusion weight search_graph_vector_weight_ablation(repeats=3) — parked for product defaults: only meaningful with topology assist; SCIENTIFIC/no-KG gates forcegraphVectorWeight=0Tiered execution on/off search_tiered_ablation(repeats=3)Multi-corpus transfer gate search_product_nfcorpus_gate(repeats=3)Compact engine overhead set subsystem_overheadPipeline / leg stages leg_stage_ablation(repeats=3)Rerank off vs replace vs blend simeon_rerank/simeon_rerank_beirRerank blend weight multi-corpus search_rerank_blend_multicorp(repeats=3)Per-query RR class analysis analyze_query_class.pyon armdebug.jsonlRouted vs global ANN at equal budgets topology_routing_budget_ablation(repeats=3)Topology construction purity topology_purity_validate(repeats=3)Ingest / load / repair / ops KPIs ingest_pipeline,retrieval_load, … -
Decision-grade runs use
repeats>=3. Bare Δ withrepeats=1is exploratory. Summary marks:*clears pooled stdev,~within noise, unmarked = n=1. -
Read quality × cost — primary columns include MRR (and friends) and
search_latency_ms_p50(plus expansion/path rates when topology is on). Mechanism rates fromdebug.jsonl(e.g. medoid vs seed-neighbor path,topology_vector_seeds_added_*) land in metrics viaretrieval_quality. -
Compare stamps with
runner.py comparebefore claiming a win. Do not rebuildbuild/releasemid-run (poisons arms). xplan skips meson compile when the bench binary already exists; force withYAMS_BENCH_FORCE_BUILD=1. -
Product default is hybrid_assist + shadow; topology-disabled hybrid is the explicit no-topology control. Shadow can perform counterfactual work, and stage tracing adds exact-control work: compare untraced timings separately. Experimental engine paths must beat the default hybrid on quality without a large latency regression, or stay opt-in / parked.
-
Catch2 first for seams and unit behavior (
tests/unit/search/); xplan is for multi-arm KPI and default-system ranking — not a substitute for TDD.
Workers (short)
retrieval_quality → BEIR quality + engine/topology counters (retrieval_quality_bench).
ingestion_e2e / retrieval_load / repair_ability / ops_timeline → daemon KPIs 2–5.
Ablation mapping: workers/ablation.py (search weight gates, ingest flags, topology
mode/expansion). Harness-only: YAMS_BENCH_*. Do not grow product YAMS_* for axes.
Plan hygiene
- Active topology decision plans:
topology_purity_validate,topology_routing_budget_ablation. - Product-path engine plans:
search_product_component_ablation,search_vector_weight_ablation,search_vector_weight_0_20_multicorp,search_tiered_ablation,search_product_nfcorpus_gate,search_rerank_blend_multicorp,search_product_clean_baseline. - Parked product levers (do not use for promote/kill of defaults):
search_graph_vector_weight_ablation(topology-only), path/tag/metadata/entity weight knobs on SCIENTIFIC (capability-gated to 0). - Superseded multi-arm topology plans:
tests/benchmarks/xplan/plans/archive/(historical only; not for promote/kill). - No new multi-arm shell scripts; wrappers under
scripts/ortests/benchmarks/scripts/only. - Prefer sanitizer builds for intermittent bench crashes:
build/asan-api|tsan-api|ubsan-api+YAMS_BENCH_SKIP_BUILD=1.
Branches, PRs & Promotion
- Feature PRs target
experimental;mainonly moves through the automated "promote experimental to main" draft PR, which lists everything onexperimentalnot yet onmain(not just the latest change). - Stacked PRs (a PR whose base is another PR's branch): merge bottom-up. Merge the
child into the parent branch before merging the parent, or retarget the child
to
experimentalfirst. A child merged into a parent branch that was already merged lands only on that branch and silently missesexperimental. - After merging a stack, verify nothing was stranded:
git cherry origin/experimental origin/<branch>must print no+lines. - Submodule (
third_party/*) PRs merge with a merge commit or rebase, never squash, and land before the YAMS PR that bumps the pointer, so the pinned SHA stays reachable from the submodule's default branch. - Merge method by PR kind:
- Feature PRs into
experimental: squash is fine. - Promotion PRs (
experimental→main) and back-merges (main→experimental): merge commit only. A squash copies the changes but not the commits, so Release Candidate rejects the next candidate with "candidate must contain the complete base history".
- Feature PRs into
- After every change to
main(a promotion, a release PR, or a direct commit), back-mergemainintoexperimental. Check withgit log --oneline origin/experimental..origin/main, which must print nothing. - Promotion PR bodies must not contain
BEGIN_COMMIT_OVERRIDE. Release Please applies the override to every commit in the PR and repeats it in the notes. - To pin a version (for example, when a
featwould otherwise bump the minor version), add aRelease-As: X.Y.Zfooter to a commit onmain.
Patterns To Reuse (High Signal)
TuneAdvisor: static inline atomics, relaxed reads for advisory knobs.InternalEventBus: typed channels keyed by string names.ResourceGovernor: check admission before heavy work.profiling.h:YAMS_*macros, no-op without Tracy.- Daemon async paths: Boost.Asio coroutines (
boost::asio::awaitable<…>).
Background Work & Resource Governor
YAMS must run on memory-constrained, non-Apple hosts. In October 2026 the daemon pinned a weak machine's CPU with p2p and topology work.
- Daemon code that starts a thread, posts a job, spawns a coroutine or arms a
periodic timer checks
ResourceGovernorfirst:canAdmitWork(),admitDeferrable(DeferrableWork::…)or its cap inScalingCaps. Admission is not enough for long jobs: a rebuild or scan that runs for seconds re-checks pressure between batches and yields. No free-running loops. - Worker counts come from
TuneAdvisoror the governor, nothardware_concurrency(). - Idle means no active non-health requests and empty queues. An open connection is not activity.
- Background work stops through a bounded, checked drain. A
void stop()that returns while work is still running is not a shutdown. - A new or changed background path needs a KPI on the constrained lane
(
setup.sh Profiling, Linux x86, pinned cores and RAM): idle CPU and RSS over time with the feature on. Profile before and after. Code reading is not evidence of a fix. - Gaps as of 2026-10:
BackgroundTaskManager,p2p_transport(accept thread, one thread per session, 5 s reconnect loop) andWriteCoordinatordo not consult the governor. Topology rebuilds and semantic maintenance are admitted throughadmitDeferrablebut then run to completion with no pressure check insideTopologyManager::runRebuild. Fix these before adding background work.
Bug-Bounty (Repo Use)
Scoped targets only; read-only/low-impact validation first; no persistence,
destructive payloads, or exfiltration; redact secrets before yams add; index
evidence as short reproducible notes (source=evidence).
Keep This File Lean
Generic agent behavior belongs in docs/prompts/PROMPT-eng-codex.md. No
session-specific skill catalogs here.