Workflows
June 28, 2026 · View on GitHub
Authoritative Commands
make fmt # ruff format src/ tests/ examples/ scripts/
make lint # ruff check src/ tests/ examples/ scripts/
make type # mypy src/ examples/ scripts/ (examples + scripts gated too, #539)
make test # pytest --cov=contextweaver --cov-report=term-missing -q
make example # run all example scripts (includes architectures)
make architectures # run reference architecture scripts under examples/architectures/
make demo # python -m contextweaver demo
make ci # fmt + lint + type + test + drift-check + module-size-check + doc-snippets-check + readme-version-check + security-policy-check + example + demo
make ci-full # make ci + floor-deps + tool-smoke (the two isolated-env CI jobs; #710)
make floor-deps # prove declared dependency floors resolve + pass tests (mirrors the floor-deps CI job; needs uv; #710)
make tool-smoke # build the wheel + run the entry point via uvx/pipx (mirrors the Linux tool-run-smoke CI job; needs uv/pipx; #710)
make drift-check # one gate over every generated-artifact drift check (#522; in `make ci`)
make module-size-check # enforce the ≤300-line convention, frozen baseline (#456; in `make ci`)
make doc-snippets-check # execute README + curated docs Python snippets (#526; in `make ci`)
make docs # mkdocs build --clean (docs site — not part of CI)
make docs-serve # mkdocs serve (live preview)
make benchmark # run benchmark harness (non-gating; writes benchmarks/results/latest.json)
make benchmark-matrix # benchmark + per-backend × per-size matrix (#208) and per-namespace breakdown (#209)
make scorecard # render benchmarks/scorecard.md from benchmarks/results/latest.json
make scorecard-check # verify scorecard.md is up to date (gating CI step; exits non-zero on drift)
make sweep-scoring # weight sweep for ScoringConfig (#214); writes benchmarks/sweep_scoring.md
make context-rot # render context-rot demo JSON + docs/assets/context_rot.svg (#349)
make context-rot-check # verify context_rot.svg matches its committed JSON (gating CI step; exits non-zero on drift)
make readme-version-check # verify README package/comparison/roadmap refs and Python classifiers match sources (gating CI step; #347/#473/#531)
make security-policy-check # verify SECURITY.md supported series + relative links match pyproject.toml (gating CI step; #691)
make llms # regenerate llms.txt and llms-full.txt from canonical docs
make llms-check # verify llms.txt and llms-full.txt are up to date (gating CI step; exits non-zero on drift)
make gateway-scorecard-check # verify gateway scorecard Markdown matches its committed JSON (gating CI step)
make record-demos-check # verify committed asciinema casts match demo output (gating CI step)
make smoke-eval # deterministic, credential-free smoke evaluation (gating CI step on Python 3.12)
make weaver-conformance # round-trip + JSON-Schema validate the weaver-spec adapter
# (fetches schemas from raw.githubusercontent.com; CI runs it as a gate)
As of #474,
make cinow mirrors the gating CI checks a contributor can run offline: the consolidated generated-artifact drift gatemake drift-check(#522 — schemas, scorecards, recorded demos, llms.txt, context-rot SVG, and the public-API manifest #518), plusmake module-size-check(#456),make doc-snippets-check(#526),make readme-version-check(#347/#473/#531), andmake security-policy-check(#691). The individual*-checktargets still exist for granular use, but you no longer need to remember to run them separately before a PR.CI-only gates (not in
make cibecause they need the network or are heavy):make weaver-conformance(fetches schemas) and the docs build job.make smoke-eval(#392/#491) is gating on the Python 3.12 CI cell; the raw benchmark job remains informational. The two gating CI jobs that build isolated environments now have local equivalents —make floor-depsandmake tool-smoke(#710), bundled intomake ci-full; only the macOS cell oftool-run-smokestays CI-only.All targets invoke
$(PYTHON)(defaults topython3); override withmake <target> PYTHON=python3.11where no barepythonexists (#712).
make ci runs all declared targets in sequence. The CI-only gates above run on
every PR regardless; run them locally when the affected integrations change.
Command-Selection Rules
| Goal | Command |
|---|---|
| Quick format check | make fmt |
| Quick lint check | make lint |
| Full validation | make ci (always — do not skip targets) |
| Full validation + isolated-env jobs | make ci-full (#710; adds floor-deps + tool-smoke) |
| Verify dependency floors resolve | make floor-deps (#710; needs uv) |
| Wheel / entry-point smoke | make tool-smoke (#710; needs uv/pipx) |
| Run a single test | pytest tests/test_<module>.py or pytest -k "test_name" |
| Run all tests | make test |
| Verify examples work | make example |
| Interactive demo | make demo |
| Verify recorded demo casts | make record-demos-check |
| Build docs site | make docs |
| Live docs preview | make docs-serve |
| Run benchmark harness | make benchmark (non-gating; writes benchmarks/results/latest.json) |
| Run full per-backend × per-size matrix | make benchmark-matrix (#208 + #209) |
| Verify gateway benchmark scorecard | make gateway-scorecard-check |
| Run deterministic smoke evaluation | make smoke-eval (gating on the Python 3.12 CI cell) |
| Run scoring-weight sweep | make sweep-scoring (#214; writes benchmarks/sweep_scoring.md) |
| Add an eval for a feature | follow .github/prompts/add-eval.prompt.md (#216) |
| Regenerate llms.txt / llms-full.txt | make llms (after editing canonical docs) |
| Check llms.txt / llms-full.txt for drift | make llms-check (exits non-zero if regeneration needed) |
Do not use make test alone as a validation gate. Always run make ci before declaring a change complete — it includes example and demo verification that catch integration issues make test misses.
Setup (one-time)
pip install -e ".[dev]"
pre-commit install
Pre-commit hooks run ruff format, ruff check --fix, and file hygiene checks on every commit. Hooks may modify files — re-stage with git add if needed.
Preparing a Release
Before creating the release tag, refresh and commit the deterministic benchmark history for the package version:
make benchmark
python scripts/render_trend.py --snapshot <version> --from benchmarks/results/latest.json
make trend
make trend-check
The publish workflow verifies that benchmarks/results/history/<version>.json
exists and that benchmarks/trend.md matches the committed history. Latency is
excluded from release snapshots because it is host-dependent.
Adding a Feature
- Identify the relevant module (see module map in AGENTS.md).
- Modify only the targeted module.
- Update
protocols.pyif adding a new protocol. - Add tests in
tests/test_<module>.py. - Run
make ci— all declared targets must pass. - Update
CHANGELOG.mdunder## [Unreleased]. - Add Google-style docstrings to any new public APIs.
- Update examples/demos if the feature is user-facing.
- Update agent-facing docs if the pipeline or public API changed.
- If the feature can move
recall@k/dropped/dedup_removed/prompt_tokens, follow.github/prompts/add-eval.prompt.md(#216) to extend the gold set or scenarios and regeneratebenchmarks/scorecard.md. The sticky CI benchmark-delta comment (#211) surfaces any matrix-cell ⚠️ markers on the PR.
Definition of Done
A change is complete when all of the following are true:
-
make cipasses (all declared targets) -
CHANGELOG.mdupdated - Google-style docstrings on all new public APIs
- Type hints on all new public functions and methods
- Tests added for new functionality
- Examples/demos updated if the feature is user-facing
- Agent-facing docs updated if pipeline, public API, or conventions changed
Fixing a Bug
- Write a failing test that reproduces the bug.
- Fix the bug.
- Run
make ci. - Update
CHANGELOG.md. - If the bug revealed a reusable lesson, record it per the process in lessons-learned.md.
Adding a Store Backend
- Implement the store class in
src/contextweaver/store/<name>.py. - The class must implement the relevant protocol from
protocols.py. - Export from
src/contextweaver/store/__init__.py. - Add tests in
tests/test_store_<name>.py. - Update
StoreBundleif appropriate.
Adding an Adapter
- Create the adapter in
src/contextweaver/adapters/<protocol>.py. - Pure stateless converter — no state, no core-type leakage.
- External format dependencies stay at the adapter boundary.
- Add tests in
tests/test_adapters.py. - Add an example in
examples/.
Deprecating an API
Use the runtime machinery in src/contextweaver/_deprecation.py (issue #517);
do not call warnings.warn ad hoc.
- Add a
Deprecation(name, since, removal, instead)entry to the_SHIMStable in_deprecation.py(the single source of truth). Use the next minor forsinceand"1.0.0"forremovalunless decided otherwise. - At the call site, emit the warning:
warn_deprecated("<name>")inside a property/method/branch, or decorate a callable with@deprecated("<name>", since=..., removal=..., instead=...). Keep behavior identical; route in-library callers through a private helper so the canonical path does not trip the warning. - Migrate every in-repo caller (src, examples, docs snippets, tests) off the
deprecated surface; intentional shim tests assert the warning with
pytest.warns(DeprecationWarning). Thefilterwarningsgate inpyproject.tomlescalates first-party deprecations to errors, so a leftover caller fails CI. - Add the surface to the inventory table in
docs/upgrading.mdand aCHANGELOG.md"Deprecated" entry naming the replacement.
Documentation-only exception. Do not add a runtime warning when the only
call site would live in a module barred from side effects — a re-export-only
__init__.py (hard rule: only re-exports) or a pure-data module such as
types.py (invariant: no side effects in the data layer), or an internal
serialization key on a hot path. Keep the surface a plain alias/accessor, skip
steps 1–2 (no _SHIMS entry, no warn_deprecated), and record it as a
documentation-only row in docs/upgrading.md. The ToolCard alias is the
reference example.
Documentation Governance
When docs must be updated
- Any PR that changes the context pipeline stages, routing pipeline, or public API.
- Any PR that adds, removes, or renames a module.
- Any PR that changes project conventions, commands, or the definition of done.
Who triggers updates
- The author of the PR is responsible for updating docs in the same PR.
- Reviewers should check the review checklist for doc-update requirements.
Resolving contradictions
If two docs disagree:
AGENTS.mdis authoritative for agent guidance and shared rules.docs/architecture.mdis authoritative for architecture detail.Makefileis ground truth for command definitions.- Source code is ground truth for implementation details.
Fix the less-authoritative source to match.
Promoting lessons into canonical docs
When a lesson from lessons-learned.md represents a durable pattern:
- Add it to the appropriate canonical doc (
AGENTS.md,invariants.md, orworkflows.md). - Keep the lesson entry but mark it as promoted with a cross-reference.
Avoiding duplicate authority
Each piece of guidance should have exactly one canonical home. Use cross-references instead of copies. Exception: hard rules (the 2 auto-reject items) may be briefly restated in tool-specific override files for visibility, since those files may be the only context an agent loads.
Updating navigation tables
When adding a new canonical doc under docs/agent-context/, update the navigation tables in all three routing files:
AGENTS.md(Documentation Map).github/copilot-instructions.md(Canonical References).claude/CLAUDE.md(Canonical References)