@AGENTS.md
Pydantic is the law. Everything else derives from it. You cannot add features that don't exist in Pydantic first.
This project was renamed to ragweld. The codebase and API still use tribrid in many places (config keys, module names, docs titles). This is expected.
- Do not attempt mass-renames of
tribrid->ragweld.
These files define what exists. If something isn't in these files, IT DOES NOT EXIST.
server/models/tribrid_config_model.py(~1000+ fields) — every tunable parameter, feature flag, thresholddata/models.json(~50+ model definitions) — LLM/embedding/reranker models, pricing, context windowsdata/glossary.json(~250 terms) — tooltip definitions
tribrid_config_model.py (PYDANTIC - SOUR
8541
CE OF TRUTH)
↓ pydantic2ts (uv run scripts/generate_types.py)
web/src/types/generated.ts (AUTO-GENERATED - DO NOT EDIT)
↓ imports
web/src/stores/*.ts (ZUSTAND STORES)
↓ wraps
web/src/hooks/*.ts (REACT HOOKS)
↓ uses
web/src/components/**/*.tsx (REACT COMPONENTS)
- Pydantic First — add field to config model before implementing anything
- No Hand-Written API Types — import from
generated.ts - No Adapters/Transformers — fix the Pydantic model instead
- Config Controls Everything — no hardcoded thresholds
- Field Constraints Are Law — UI/API must honor
ge/le/default
- Imports: qdrant_client, redis, langchain (LangGraph IS allowed)
- Terms: card/cards -> chunk_summary, golden questions -> eval_dataset, ranker -> reranker
- Smells:
class *Adapter,class *Transformer,class *Mapper,interfacein .tsx
- Does the feature need configurable parameters? → Add to
tribrid_config_model.pyFIRST - Does it need Pydantic types? → Add to config model, run
generate_types.py - Is it a new component? → Trace the chain: What hook? → What store? → What Pydantic model?
- Add to
tribrid_config_model.py(if configurable) - Add to
data/glossary.json(tooltip for the feature) - Run
uv run scripts/generate_types.py - Update store if needed
- Update hook if needed
- Update component
server/
├── models/ # Pydantic models - THE LAW
├── api/ # FastAPI routers
├── db/ # Database clients (Postgres, Neo4j)
├── retrieval/ # Search pipeline
├── reranker/ # MLX/LoRA reranker inference + artifacts
├── indexing/ # Chunking, embedding, graph building
├── training/ # Reranker training (LoRA fine-tuning)
└── services/ # Business logic
web/src/
├── types/generated.ts # AUTO-GENERATED from Pydantic - DO NOT EDIT
├── stores/ # Zustand stores
├── hooks/ # React hooks
├── components/ # React components
└── api/ # API client
data/
├── models.json # LLM model definitions
└── glossary.json # Tooltip definitions
uv run scripts/generate_types.py # Regenerate TS types (after ANY Pydantic change)
uv run scripts/validate_types.py # Verify type sync
uv run scripts/check_banned.py # Check banned patterns
./start.sh # Docker + Backend + Frontend
./start.sh --with-observability # + Prometheus + Grafana + Loki
./start.sh --no-frontend # Backend onlyDo NOT rely on "completion promises" alone. This repo prevents fake completion with a verification-based Stop hook that blocks stopping until checks pass.
- Stop hook:
.claude/hooks/verify-tribrid.sh— blocks stopping if validators/tests fail - Ralph loop: the
ralph-loopplugin keeps re-feeding the same prompt each iteration
- Start Claude Code from repo root:
cd /Users/davidmontgomery/ragweld - Restart Claude Code after changing
.claude/settings.json(hooks snapshot at startup) - Project config must include
enabledPlugins.ralph-loop@claude-plugins-official = trueand the Stop hook
/ralph-loop "Continue implementing TriBridRAG.
At the start of EACH iteration:
1) Read TODO.md and pick the first unchecked [ ] item.
2) Implement it end-to-end.
3) Run verification: check_banned, validate_types, pytest
4) Mark [x] only when truly done.
IMPORTANT: If Stop hook blocks, fix that exact failure." --max-iterations 200 --completion-promise "COMPLETE"- Monitor:
grep '^iteration:' .claude/ralph-loop.local.md - Cancel:
/cancel-ralph
Every change must be tested before completion. See .claude/rules/testing.md for full details.
- Temporary tests →
.tests/(gitignored) - Permanent tests →
tests/ - Zero-mocked tests enforced for new/edited tests
- No Playwright API mocking, no Python mocking, no skip stubs
For every major task or significant debugging session, create a dedicated .md file in auto memory
(~/.claude/projects/<project>/memory/) and link it from MEMORY.md under the appropriate heading.
Each file should capture:
- What was done and why
- Key decisions made
- Gotchas encountered
- Outcome / result
This ensures institutional knowledge accumulates across sessions.
- Can I add this field? → Is it in tribrid_config_model.py? No → Add it there first.
- Can I use this type? → Is it in generated.ts? No → Add to Pydantic first.
- Can I hardcode this value? → Should it be configurable? Yes → Add to config.
- Can I write an adapter? → No. Fix the Pydantic model.