pycontextdb 0.1.1__tar.gz → 0.3.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (150) hide show
  1. pycontextdb-0.3.0/.github/CODEOWNERS +14 -0
  2. pycontextdb-0.3.0/.github/pull_request_template.md +10 -0
  3. pycontextdb-0.3.0/.github/workflows/ci.yml +64 -0
  4. {pycontextdb-0.1.1 → pycontextdb-0.3.0}/.github/workflows/publish.yml +10 -4
  5. {pycontextdb-0.1.1 → pycontextdb-0.3.0}/.gitignore +15 -0
  6. pycontextdb-0.3.0/.pre-commit-config.yaml +31 -0
  7. pycontextdb-0.3.0/CHANGELOG.md +107 -0
  8. pycontextdb-0.3.0/COMMERCIAL.md +40 -0
  9. pycontextdb-0.3.0/CONTRIBUTING.md +66 -0
  10. pycontextdb-0.3.0/NOTICE +10 -0
  11. {pycontextdb-0.1.1 → pycontextdb-0.3.0}/PKG-INFO +92 -13
  12. {pycontextdb-0.1.1 → pycontextdb-0.3.0}/README.md +80 -9
  13. pycontextdb-0.3.0/ai-tools/README.md +29 -0
  14. {pycontextdb-0.1.1 → pycontextdb-0.3.0}/assets/hero.png +0 -0
  15. pycontextdb-0.3.0/benchmarks/__init__.py +1 -0
  16. pycontextdb-0.3.0/benchmarks/trust_bakeoff.py +613 -0
  17. {pycontextdb-0.1.1 → pycontextdb-0.3.0}/contextdb/__init__.py +33 -3
  18. {pycontextdb-0.1.1 → pycontextdb-0.3.0}/contextdb/cli.py +22 -0
  19. pycontextdb-0.3.0/contextdb/client.py +1460 -0
  20. pycontextdb-0.3.0/contextdb/core/clock.py +43 -0
  21. {pycontextdb-0.1.1 → pycontextdb-0.3.0}/contextdb/core/config.py +65 -4
  22. {pycontextdb-0.1.1 → pycontextdb-0.3.0}/contextdb/core/exceptions.py +21 -0
  23. pycontextdb-0.3.0/contextdb/core/models.py +343 -0
  24. pycontextdb-0.3.0/contextdb/core/policy.py +138 -0
  25. pycontextdb-0.3.0/contextdb/core/slots.py +255 -0
  26. {pycontextdb-0.1.1 → pycontextdb-0.3.0}/contextdb/dynamics/evolution.py +31 -4
  27. {pycontextdb-0.1.1 → pycontextdb-0.3.0}/contextdb/dynamics/formation.py +68 -7
  28. pycontextdb-0.3.0/contextdb/dynamics/retrieval.py +251 -0
  29. pycontextdb-0.3.0/contextdb/dynamics/salience.py +78 -0
  30. pycontextdb-0.3.0/contextdb/dynamics/trust.py +373 -0
  31. {pycontextdb-0.1.1 → pycontextdb-0.3.0}/contextdb/graphs/base.py +2 -2
  32. {pycontextdb-0.1.1 → pycontextdb-0.3.0}/contextdb/graphs/causal.py +4 -3
  33. {pycontextdb-0.1.1 → pycontextdb-0.3.0}/contextdb/graphs/entity.py +6 -4
  34. {pycontextdb-0.1.1 → pycontextdb-0.3.0}/contextdb/graphs/semantic.py +6 -3
  35. {pycontextdb-0.1.1 → pycontextdb-0.3.0}/contextdb/graphs/temporal.py +2 -2
  36. {pycontextdb-0.1.1 → pycontextdb-0.3.0}/contextdb/integrations/__init__.py +6 -1
  37. pycontextdb-0.3.0/contextdb/integrations/act.py +125 -0
  38. pycontextdb-0.3.0/contextdb/integrations/livekit.py +67 -0
  39. pycontextdb-0.3.0/contextdb/integrations/pipecat.py +114 -0
  40. pycontextdb-0.3.0/contextdb/integrations/prompting.py +72 -0
  41. pycontextdb-0.3.0/contextdb/mcp.py +305 -0
  42. pycontextdb-0.3.0/contextdb/memory/factual.py +168 -0
  43. pycontextdb-0.3.0/contextdb/pool.py +69 -0
  44. {pycontextdb-0.1.1 → pycontextdb-0.3.0}/contextdb/privacy/audit.py +47 -38
  45. pycontextdb-0.3.0/contextdb/privacy/injection.py +43 -0
  46. {pycontextdb-0.1.1 → pycontextdb-0.3.0}/contextdb/privacy/pii_detector.py +24 -16
  47. {pycontextdb-0.1.1 → pycontextdb-0.3.0}/contextdb/privacy/retention.py +2 -2
  48. pycontextdb-0.3.0/contextdb/serve.py +416 -0
  49. {pycontextdb-0.1.1 → pycontextdb-0.3.0}/contextdb/store/__init__.py +3 -0
  50. pycontextdb-0.3.0/contextdb/store/base.py +156 -0
  51. pycontextdb-0.3.0/contextdb/store/factory.py +61 -0
  52. pycontextdb-0.3.0/contextdb/store/pg_sql.py +69 -0
  53. pycontextdb-0.3.0/contextdb/store/postgres_store.py +846 -0
  54. pycontextdb-0.3.0/contextdb/store/sqlite_store.py +1027 -0
  55. {pycontextdb-0.1.1 → pycontextdb-0.3.0}/contextdb/store/vector_index.py +77 -4
  56. {pycontextdb-0.1.1 → pycontextdb-0.3.0}/contextdb/utils/embeddings.py +88 -6
  57. {pycontextdb-0.1.1 → pycontextdb-0.3.0}/contextdb/utils/llm.py +87 -5
  58. pycontextdb-0.3.0/docs/api.md +111 -0
  59. {pycontextdb-0.1.1 → pycontextdb-0.3.0}/docs/architecture.md +36 -7
  60. pycontextdb-0.3.0/docs/index.md +57 -0
  61. pycontextdb-0.3.0/docs/migrations.md +24 -0
  62. pycontextdb-0.3.0/docs/multi_tenant.md +61 -0
  63. pycontextdb-0.3.0/docs/postgres.md +74 -0
  64. {pycontextdb-0.1.1 → pycontextdb-0.3.0}/docs/prompts.md +40 -8
  65. pycontextdb-0.3.0/docs/quickstart.md +74 -0
  66. pycontextdb-0.3.0/docs/serve.md +83 -0
  67. pycontextdb-0.3.0/docs/trust_policy.md +54 -0
  68. pycontextdb-0.3.0/legal/CLA-entity.md +67 -0
  69. pycontextdb-0.3.0/legal/CLA-individual.md +66 -0
  70. pycontextdb-0.3.0/legal/signed/README.md +3 -0
  71. {pycontextdb-0.1.1 → pycontextdb-0.3.0}/mkdocs.yml +5 -0
  72. {pycontextdb-0.1.1 → pycontextdb-0.3.0}/pyproject.toml +66 -4
  73. pycontextdb-0.3.0/scripts/check_release.py +138 -0
  74. pycontextdb-0.3.0/tests/evals/test_trust_model.py +1349 -0
  75. pycontextdb-0.3.0/tests/pg_util.py +48 -0
  76. pycontextdb-0.3.0/tests/test_version.py +18 -0
  77. {pycontextdb-0.1.1 → pycontextdb-0.3.0}/tests/unit/test_audit.py +19 -0
  78. pycontextdb-0.3.0/tests/unit/test_decision_scope.py +173 -0
  79. pycontextdb-0.3.0/tests/unit/test_evolution.py +43 -0
  80. pycontextdb-0.3.0/tests/unit/test_host_api.py +238 -0
  81. {pycontextdb-0.1.1 → pycontextdb-0.3.0}/tests/unit/test_init.py +2 -1
  82. pycontextdb-0.3.0/tests/unit/test_pg_sql.py +34 -0
  83. {pycontextdb-0.1.1 → pycontextdb-0.3.0}/tests/unit/test_pii_detector.py +26 -8
  84. pycontextdb-0.3.0/tests/unit/test_postgres_concurrency.py +179 -0
  85. pycontextdb-0.3.0/tests/unit/test_scoped_id_access.py +140 -0
  86. pycontextdb-0.3.0/tests/unit/test_serve.py +369 -0
  87. pycontextdb-0.3.0/tests/unit/test_trust_policy.py +103 -0
  88. pycontextdb-0.3.0/tests/unit/test_vector_scope.py +174 -0
  89. pycontextdb-0.1.1/.github/workflows/ci.yml +0 -39
  90. pycontextdb-0.1.1/contextdb/client.py +0 -516
  91. pycontextdb-0.1.1/contextdb/core/models.py +0 -151
  92. pycontextdb-0.1.1/contextdb/dynamics/retrieval.py +0 -130
  93. pycontextdb-0.1.1/contextdb/memory/factual.py +0 -58
  94. pycontextdb-0.1.1/contextdb/store/base.py +0 -67
  95. pycontextdb-0.1.1/contextdb/store/sqlite_store.py +0 -517
  96. pycontextdb-0.1.1/docs/api.md +0 -50
  97. pycontextdb-0.1.1/docs/index.md +0 -34
  98. pycontextdb-0.1.1/docs/quickstart.md +0 -48
  99. pycontextdb-0.1.1/tests/test_version.py +0 -9
  100. {pycontextdb-0.1.1 → pycontextdb-0.3.0}/.github/copilot-instructions.md +0 -0
  101. {pycontextdb-0.1.1 → pycontextdb-0.3.0}/LICENSE +0 -0
  102. {pycontextdb-0.1.1 → pycontextdb-0.3.0/ai-tools}/.cursorrules +0 -0
  103. {pycontextdb-0.1.1 → pycontextdb-0.3.0/ai-tools}/CLAUDE.md +0 -0
  104. {pycontextdb-0.1.1 → pycontextdb-0.3.0/ai-tools}/llms-full.txt +0 -0
  105. {pycontextdb-0.1.1 → pycontextdb-0.3.0/ai-tools}/llms.txt +0 -0
  106. {pycontextdb-0.1.1 → pycontextdb-0.3.0}/assets/README.md +0 -0
  107. {pycontextdb-0.1.1 → pycontextdb-0.3.0}/assets/architecture.png +0 -0
  108. {pycontextdb-0.1.1 → pycontextdb-0.3.0}/assets/benchmarks.png +0 -0
  109. {pycontextdb-0.1.1 → pycontextdb-0.3.0}/assets/performance.png +0 -0
  110. {pycontextdb-0.1.1 → pycontextdb-0.3.0}/assets/problem.png +0 -0
  111. {pycontextdb-0.1.1 → pycontextdb-0.3.0}/assets/quickstart.png +0 -0
  112. {pycontextdb-0.1.1 → pycontextdb-0.3.0}/benchmarks/run_benchmarks.py +0 -0
  113. {pycontextdb-0.1.1 → pycontextdb-0.3.0}/contextdb/agents/__init__.py +0 -0
  114. {pycontextdb-0.1.1 → pycontextdb-0.3.0}/contextdb/agents/memory_bus.py +0 -0
  115. {pycontextdb-0.1.1 → pycontextdb-0.3.0}/contextdb/agents/rl_manager.py +0 -0
  116. {pycontextdb-0.1.1 → pycontextdb-0.3.0}/contextdb/core/__init__.py +0 -0
  117. {pycontextdb-0.1.1 → pycontextdb-0.3.0}/contextdb/dynamics/__init__.py +0 -0
  118. {pycontextdb-0.1.1 → pycontextdb-0.3.0}/contextdb/graphs/__init__.py +0 -0
  119. {pycontextdb-0.1.1 → pycontextdb-0.3.0}/contextdb/integrations/autogen.py +0 -0
  120. {pycontextdb-0.1.1 → pycontextdb-0.3.0}/contextdb/integrations/crewai.py +0 -0
  121. {pycontextdb-0.1.1 → pycontextdb-0.3.0}/contextdb/integrations/langchain.py +0 -0
  122. {pycontextdb-0.1.1 → pycontextdb-0.3.0}/contextdb/integrations/openai_tools.py +0 -0
  123. {pycontextdb-0.1.1 → pycontextdb-0.3.0}/contextdb/memory/__init__.py +0 -0
  124. {pycontextdb-0.1.1 → pycontextdb-0.3.0}/contextdb/memory/experiential.py +0 -0
  125. {pycontextdb-0.1.1 → pycontextdb-0.3.0}/contextdb/memory/working.py +0 -0
  126. {pycontextdb-0.1.1 → pycontextdb-0.3.0}/contextdb/privacy/__init__.py +0 -0
  127. {pycontextdb-0.1.1 → pycontextdb-0.3.0}/contextdb/py.typed +0 -0
  128. {pycontextdb-0.1.1 → pycontextdb-0.3.0}/contextdb/utils/__init__.py +0 -0
  129. {pycontextdb-0.1.1 → pycontextdb-0.3.0}/contextdb/utils/migrations.py +0 -0
  130. {pycontextdb-0.1.1 → pycontextdb-0.3.0}/examples/customer_support.py +0 -0
  131. {pycontextdb-0.1.1 → pycontextdb-0.3.0}/examples/multi_agent_team.py +0 -0
  132. {pycontextdb-0.1.1 → pycontextdb-0.3.0}/examples/phone_agent.py +0 -0
  133. {pycontextdb-0.1.1 → pycontextdb-0.3.0}/examples/research_assistant.py +0 -0
  134. {pycontextdb-0.1.1/benchmarks → pycontextdb-0.3.0/tests}/__init__.py +0 -0
  135. {pycontextdb-0.1.1 → pycontextdb-0.3.0}/tests/conftest.py +0 -0
  136. {pycontextdb-0.1.1/tests → pycontextdb-0.3.0/tests/evals}/__init__.py +0 -0
  137. {pycontextdb-0.1.1 → pycontextdb-0.3.0}/tests/integration/__init__.py +0 -0
  138. {pycontextdb-0.1.1 → pycontextdb-0.3.0}/tests/integration/test_client.py +0 -0
  139. {pycontextdb-0.1.1 → pycontextdb-0.3.0}/tests/integration/test_langchain_integration.py +0 -0
  140. {pycontextdb-0.1.1 → pycontextdb-0.3.0}/tests/unit/__init__.py +0 -0
  141. {pycontextdb-0.1.1 → pycontextdb-0.3.0}/tests/unit/test_config.py +0 -0
  142. {pycontextdb-0.1.1 → pycontextdb-0.3.0}/tests/unit/test_embeddings.py +0 -0
  143. {pycontextdb-0.1.1 → pycontextdb-0.3.0}/tests/unit/test_formation.py +0 -0
  144. {pycontextdb-0.1.1 → pycontextdb-0.3.0}/tests/unit/test_graphs.py +0 -0
  145. {pycontextdb-0.1.1 → pycontextdb-0.3.0}/tests/unit/test_memory_bus.py +0 -0
  146. {pycontextdb-0.1.1 → pycontextdb-0.3.0}/tests/unit/test_models.py +0 -0
  147. {pycontextdb-0.1.1 → pycontextdb-0.3.0}/tests/unit/test_retention.py +0 -0
  148. {pycontextdb-0.1.1 → pycontextdb-0.3.0}/tests/unit/test_retrieval.py +0 -0
  149. {pycontextdb-0.1.1 → pycontextdb-0.3.0}/tests/unit/test_store.py +0 -0
  150. {pycontextdb-0.1.1 → pycontextdb-0.3.0}/tests/unit/test_vector_index.py +0 -0
@@ -0,0 +1,14 @@
1
+ # Maintainer review on the SDK and on anything that could ship a bad
2
+ # PyPI artifact.
3
+ # Username: https://github.com/gaufire
4
+
5
+ * @gaufire
6
+
7
+ /.github/ @gaufire
8
+ /legal/ @gaufire
9
+ /scripts/ @gaufire
10
+ /NOTICE @gaufire
11
+ /LICENSE @gaufire
12
+ /CONTRIBUTING.md @gaufire
13
+ /pyproject.toml @gaufire
14
+ /contextdb/ @gaufire
@@ -0,0 +1,10 @@
1
+ ## Summary
2
+
3
+ <!-- What changed, and why. Evals win over prose. -->
4
+
5
+ ## Checklist
6
+
7
+ - [ ] `pytest tests/evals/ -v` passes, or I explain why not.
8
+ - [ ] `contextdb.init`, `factual.add`, `factual.recall`, and `search` keep working; new fields have backward-compatible defaults.
9
+ - [ ] No new runtime dependency without a discussion first.
10
+ - [ ] Substantial contribution: I agree to the CLA in CONTRIBUTING.md (legal name and email in this description). Trivial typo PRs may skip this.
@@ -0,0 +1,64 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ branches: [main]
8
+
9
+ jobs:
10
+ # Gitleaks + pre-commit checks. Scans the staged diff (and on CI the
11
+ # full history via --no-git-log=false by default) for tokens. Runs in
12
+ # parallel with `test` so secret leaks fail the PR even if contributors
13
+ # skipped `pre-commit install` locally.
14
+ secret-scan:
15
+ name: Secret scan (gitleaks + pre-commit)
16
+ runs-on: ubuntu-latest
17
+ steps:
18
+ - uses: actions/checkout@v4
19
+ with:
20
+ # gitleaks needs the full history to scan across commits,
21
+ # not just the shallow checkout.
22
+ fetch-depth: 0
23
+
24
+ - uses: actions/setup-python@v5
25
+ with:
26
+ python-version: "3.12"
27
+ cache: pip
28
+
29
+ - name: Install pre-commit
30
+ run: pip install pre-commit
31
+
32
+ - name: Run pre-commit on all files
33
+ run: pre-commit run --all-files --show-diff-on-failure
34
+
35
+ test:
36
+ name: Test (Python ${{ matrix.python-version }})
37
+ runs-on: ubuntu-latest
38
+ strategy:
39
+ fail-fast: false
40
+ matrix:
41
+ python-version: ["3.10", "3.11", "3.12"]
42
+
43
+ steps:
44
+ - uses: actions/checkout@v4
45
+
46
+ - name: Set up Python ${{ matrix.python-version }}
47
+ uses: actions/setup-python@v5
48
+ with:
49
+ python-version: ${{ matrix.python-version }}
50
+ cache: pip
51
+
52
+ - name: Install package and dev dependencies
53
+ run: |
54
+ python -m pip install --upgrade pip
55
+ pip install -e ".[dev]"
56
+
57
+ - name: Lint with ruff
58
+ run: ruff check .
59
+
60
+ - name: Type-check with mypy
61
+ run: mypy contextdb --python-version ${{ matrix.python-version }}
62
+
63
+ - name: Run tests
64
+ run: pytest
@@ -8,8 +8,8 @@ permissions:
8
8
  contents: read
9
9
 
10
10
  jobs:
11
- build:
12
- name: Build distribution
11
+ inspect:
12
+ name: Inspect package contents
13
13
  runs-on: ubuntu-latest
14
14
  steps:
15
15
  - uses: actions/checkout@v4
@@ -25,6 +25,10 @@ jobs:
25
25
  - name: Build sdist and wheel
26
26
  run: python -m build
27
27
 
28
+ - name: Release-safety inspection
29
+ run: |
30
+ python scripts/check_release.py --dist dist --release-tag "${{ github.event.release.tag_name }}"
31
+
28
32
  - name: Upload dist artifacts
29
33
  uses: actions/upload-artifact@v4
30
34
  with:
@@ -33,10 +37,12 @@ jobs:
33
37
 
34
38
  publish:
35
39
  name: Publish to PyPI
36
- needs: build
40
+ needs: inspect
37
41
  runs-on: ubuntu-latest
38
42
 
39
- # Trusted-publisher flow: PyPI verifies this workflow via OIDC — no token needed.
43
+ # Trusted-publisher flow: PyPI verifies this workflow via OIDC.
44
+ # Require reviewers on this GitHub Environment so a published tag
45
+ # cannot reach PyPI without a human.
40
46
  environment:
41
47
  name: pypi
42
48
  url: https://pypi.org/project/pycontextdb/
@@ -55,3 +55,18 @@ Thumbs.db
55
55
  *.sqlite3
56
56
  team.db
57
57
  contextdb.db
58
+
59
+ # Secrets and scratch files — the 0.1.0 PyPI release shipped a .rtf
60
+ # containing a token because these patterns were not gated anywhere.
61
+ *.rtf
62
+ *.key
63
+ *.pem
64
+ *.p12
65
+ .env
66
+ .env.*
67
+ secrets/
68
+ Untitled*
69
+
70
+ # CLA acceptances (personal data — keep out of the sdist)
71
+ legal/signed/*
72
+ !legal/signed/README.md
@@ -0,0 +1,31 @@
1
+ # Run locally before each commit:
2
+ # pip install -e ".[dev]"
3
+ # pre-commit install
4
+ #
5
+ # Then every git commit is gated on the hooks below. CI also runs them
6
+ # via .github/workflows/ci.yml, so skipping locally is only a temporary
7
+ # papercut — the PR will fail.
8
+
9
+ repos:
10
+ # Secret scanning — the reason this file exists. Gitleaks scans the
11
+ # staged diff for tokens (PyPI, GitHub, AWS, Slack, generic
12
+ # entropy-high strings, ...). First run auto-downloads the binary.
13
+ - repo: https://github.com/gitleaks/gitleaks
14
+ rev: v8.30.0
15
+ hooks:
16
+ - id: gitleaks
17
+
18
+ # Lightweight second-layer checks from the standard pre-commit-hooks
19
+ # repo. `detect-private-key` catches PEM-style keys that gitleaks'
20
+ # default rules occasionally miss in non-standard encodings.
21
+ - repo: https://github.com/pre-commit/pre-commit-hooks
22
+ rev: v6.0.0
23
+ hooks:
24
+ - id: detect-private-key
25
+ - id: check-added-large-files
26
+ args: ["--maxkb=2048"]
27
+ - id: end-of-file-fixer
28
+ - id: trailing-whitespace
29
+ - id: check-yaml
30
+ - id: check-toml
31
+ - id: check-merge-conflict
@@ -0,0 +1,107 @@
1
+ # Changelog
2
+
3
+ ## Unreleased
4
+
5
+ ## 0.3.0 — 2026-08-18
6
+
7
+ Host API scope hardening:
8
+
9
+ - Every non-health HTTP route now runs the configured authentication,
10
+ including `/v1/trust_policy` and `/mcp`.
11
+ - An authenticated `user_id` (from `auth_hook`) can no longer be
12
+ overridden by the JSON body, `X-ContextDB-User` header, query string,
13
+ or MCP tool arguments; a conflict is a clear 400 (`ScopeConflictError`)
14
+ instead of a silent pick.
15
+ - `/mcp` propagates the authenticated scope into every tool call.
16
+ - ID-based `confirm` / `forget` verify the target belongs to the resolved
17
+ user scope; a foreign `memory_id` raises `MemoryNotFoundError`,
18
+ indistinguishable from a missing one. Same guarantee on SQLite and
19
+ Postgres stores.
20
+ - Anonymous loopback serving is unchanged and documented as *not* an
21
+ authorization boundary.
22
+
23
+ Decision-layer and PII correctness:
24
+
25
+ - `VerifyBeforeAct.decide()` / `confirm_pending()` accept an additive
26
+ per-call `user_id=` for shared clients; a scoped client still rejects a
27
+ foreign one.
28
+ - SEARCH and DECIDE audit entries now persist only the PII-processed form
29
+ of the query — the append-only chain must never hold raw PII.
30
+ - `pii_action="encrypt"` fails closed: without a key, `PIIDetector`
31
+ raises `ConfigError` instead of degrading to redact, and encryption
32
+ mode can never persist plaintext annotation originals.
33
+
34
+ Postgres and audit concurrency:
35
+
36
+ - Vector candidates are scoped by SQL *before* ranking — a large foreign
37
+ scope can no longer starve an in-scope hit out of the candidate budget.
38
+ - The process-local vector index tracks a global store revision; a write
39
+ from another instance or process forces a rebuild before the next
40
+ search (stale reads are no longer served indefinitely).
41
+ - Slot operations on Postgres serialize across processes via a
42
+ transaction-scoped advisory lock; audit-chain appends serialize
43
+ in-process (SQLite) and cross-process (Postgres), so the hash chain
44
+ cannot fork.
45
+ - Real Postgres concurrent-worker tests cover corroboration, slot
46
+ supersede, audit-chain integrity, and cross-worker recall
47
+ (`CONTEXTDB_TEST_POSTGRES_URL`).
48
+
49
+ Host-adoption work:
50
+
51
+ - `contextdb serve --http` (`pycontextdb[serve]`) — JSON API + `/mcp`, Bearer token, `auth_hook`.
52
+ - Per-call `user_id=` on add/recall/confirm/forget. Shared `init()` is the multi-tenant path; `ContextDBPool` is LRU if you still need one client per user.
53
+ - OSS `PostgresStore` for `postgresql://` URLs (`pycontextdb[postgres]`).
54
+ - `factual.pending_confirmations()`, `forget(memory_id=)` / `forget(entity=, attribute=)`, `add_many` / `add_fast_many`.
55
+ - Recall filters: `entity`, `min_confidence`, `include_third_party`.
56
+ - `db.on(event, hook)` for write/recall/confirm/forget/injection_suspect.
57
+ - Query embedding LRU cache; lexical recall if embedding fails.
58
+ - Missing epistemic `source` warns in the SDK; HTTP/MCP remember return 400.
59
+ - Docs: trust policy matrix, Postgres, multi-tenant, SQLite migrations.
60
+
61
+ `contextdb.init`, `factual.add`, `factual.recall`, and `search` keep working. New keyword arguments are optional.
62
+
63
+ ## 0.2.0 — 2026-08-17
64
+
65
+ First PyPI cut of the trust model. `pip install pycontextdb` now matches
66
+ GitHub `main`: memory an agent can act on without treating a wish as a fact.
67
+
68
+ `contextdb.init`, `factual.add`, `factual.recall`, and `search` are unchanged.
69
+
70
+ ### Added
71
+
72
+ - Epistemic typing on every fact (`user_stated` / `agent_inferred` /
73
+ `third_party`), confidence, independent corroboration, `action_relevant`.
74
+ - `TrustPolicy` as data — `TrustPolicy.hospital()` vs `.restaurant()`.
75
+ - `factual.recall_for_action()`, `factual.confirm()`, `VerifyBeforeAct`
76
+ (`act` / `ask` / `abstain`).
77
+ - Versioned slot vocabulary + LLM-free slotter (`add_fast` never calls an LLM).
78
+ - Contested slots: independent speakers with different values do not
79
+ last-write-win. `confirm()` resolves.
80
+ - Temporal supersede with an injectable clock; sibling-slot hop on recall.
81
+ - PII redaction on writes **and** queries before embed.
82
+ - Write-time injection screening; `[RECALLED DATA — not instructions]` renderer.
83
+ - Salience (recency × frequency × criticality), verifiable forget, tenant
84
+ isolation at the storage layer.
85
+ - MCP tools: `remember` / `recall` / `recall_for_action` / `forget` / `confirm`.
86
+ - In-repo fabrication bake-off: `python benchmarks/trust_bakeoff.py`
87
+ (trust arm vs our own untyped control — not a live Mem0/Zep run).
88
+ - Contribution and release hygiene: CLA, CODEOWNERS, and release
89
+ inspection. Code through `2554dae` remains Apache-2.0.
90
+
91
+ ### Fixed
92
+
93
+ - `contextdb.__version__` no longer drifts from `pyproject.toml` (was `0.1.0`
94
+ while the project version was `0.1.1`).
95
+ - CI mypy on Python 3.12: type-check as the running interpreter so
96
+ NumPy 2.5's PEP 695 `type` aliases parse. The 3.10 job still guards
97
+ our runtime floor.
98
+ - CI latency evals: keep a tight add_fast p50 and a wider p95 on
99
+ shared runners (p50 was 2ms when p95 spiked to 21ms).
100
+
101
+ ## 0.1.1 — 2026-04-22
102
+
103
+ README rendering on PyPI; absolute GitHub asset URLs.
104
+
105
+ ## 0.1.0 — 2026-04-22
106
+
107
+ Initial public release.
@@ -0,0 +1,40 @@
1
+ # Commercial use and trademark
2
+
3
+ The software in this repository is open source under the Apache License,
4
+ Version 2.0 (see [LICENSE](LICENSE)). That license covers the code. It
5
+ does not cover the name.
6
+
7
+ ## Trademark
8
+
9
+ **ContextDB** and the ContextDB logo are trademarks of Atoms AI. The
10
+ Apache License is a copyright and patent license; it does not grant
11
+ rights to the marks (Apache License §6).
12
+
13
+ You may:
14
+
15
+ - Say you use ContextDB, cite the project, and link to this repository.
16
+ - State compatibility ("works with ContextDB") when that is true.
17
+
18
+ You may not, without a commercial agreement with Atoms AI:
19
+
20
+ - Offer ContextDB as a hosted or managed service, or resell it as part
21
+ of a service, under the ContextDB name or branding.
22
+ - Use ContextDB or a confusingly similar mark as the name of a competing
23
+ product, hosted service, or company.
24
+ - Use the logo or word mark to imply endorsement by Atoms AI.
25
+ - Register domains, social handles, or trademarks that trade on the mark.
26
+
27
+ ## Resale and commercial agreements
28
+
29
+ If your company resells ContextDB as a service or as part of a service,
30
+ or wants OEM/embedded licensing, support, or a trademark arrangement,
31
+ contact **contextdb@atomsai.com** before you ship.
32
+
33
+ ## Attribution (optional)
34
+
35
+ Apache-2.0 does not require a public credit line. If you ship a product
36
+ that uses ContextDB and want to credit the project, the preferred form
37
+ is a visible **Built with ContextDB** link to
38
+ https://github.com/atomsai/contextdb — a courtesy, not a license
39
+ condition. Redistributors must still keep `LICENSE` and `NOTICE` as
40
+ Apache requires.
@@ -0,0 +1,66 @@
1
+ # Contributing to ContextDB
2
+
3
+ Thank you for wanting to improve ContextDB. This repository is the
4
+ Apache-2.0 ContextDB SDK: everything here works offline, with no feature
5
+ gates.
6
+
7
+ ## What we accept here
8
+
9
+ Trust and safety correctness, local runtime fixes, adapters, docs, and
10
+ evals. Evals win over prose: `pytest tests/evals/ -v`.
11
+
12
+ We do **not** accept:
13
+
14
+ - Feature gates of any kind — no license keys, no `if paid:` branches,
15
+ no flags that only work against a hosted service
16
+ - Imports of packages outside the declared dependencies
17
+ - Changes that loosen PII-before-embed or the hash-chained audit log
18
+
19
+ ## Contributor License Agreement
20
+
21
+ Trivial changes (typos, broken links, comment nits) do not need a CLA.
22
+
23
+ **Substantial contributions** (new or material code, evals, or docs that
24
+ are not typo-fixes) require a signed CLA **before** merge. The CLA grants
25
+ the project broad rights to distribute your contribution, including under
26
+ different license terms; code already released under Apache-2.0 stays
27
+ Apache-2.0.
28
+
29
+ 1. Read [legal/CLA-individual.md](legal/CLA-individual.md) (or
30
+ [legal/CLA-entity.md](legal/CLA-entity.md) if you contribute on
31
+ behalf of an employer).
32
+ 2. Open a pull request whose description includes:
33
+
34
+ > I have read and agree to the ContextDB CLA
35
+ > (legal/CLA-individual.md or legal/CLA-entity.md).
36
+ > Legal name: \<name\>. Email: \<email\>.
37
+
38
+ 3. Maintainers record acceptances under `legal/signed/` (gitignored
39
+ from the sdist; not a public dump of personal data).
40
+
41
+ We may enable a CLA bot later. The requirement is the signature, not
42
+ the bot.
43
+
44
+ ## Development
45
+
46
+ ```bash
47
+ pip install -e ".[dev]"
48
+ pre-commit install
49
+ ruff check .
50
+ mypy contextdb --strict
51
+ pytest
52
+ ```
53
+
54
+ Do not break `contextdb.init`, `factual.add`, `factual.recall`, or
55
+ `search`. New fields need backward-compatible defaults.
56
+
57
+ ## Review
58
+
59
+ [`.github/CODEOWNERS`](.github/CODEOWNERS) routes reviews. `LICENSE`,
60
+ `NOTICE`, `legal/`, and the workflows need a maintainer.
61
+
62
+ ## License of your contribution
63
+
64
+ By opening a substantial PR you agree the contribution is your original
65
+ work (or you have the right to submit it) and you offer it under
66
+ Apache-2.0 **and** the CLA.
@@ -0,0 +1,10 @@
1
+ ContextDB
2
+ Copyright 2026 Atoms AI and contributors
3
+
4
+ This product includes software developed by Atoms AI and contributors.
5
+ Licensed under the Apache License, Version 2.0. See LICENSE.
6
+
7
+ ContextDB and the ContextDB logo are trademarks of Atoms AI.
8
+ The Apache License does not grant permission to use the ContextDB
9
+ trademarks. For trademark and commercial licensing (including resale
10
+ or hosted services), contact contextdb@atomsai.com. See COMMERCIAL.md.
@@ -1,7 +1,7 @@
1
- Metadata-Version: 2.4
1
+ Metadata-Version: 2.5
2
2
  Name: pycontextdb
3
- Version: 0.1.1
4
- Summary: The unified context layer for AI agents — replacing the patchwork with a memory operating system
3
+ Version: 0.3.0
4
+ Summary: The unified context layer for AI agents — memory you can act on without treating wishes as facts
5
5
  Project-URL: Homepage, https://github.com/atomsai/contextdb
6
6
  Project-URL: Documentation, https://contextdb.dev
7
7
  Project-URL: Repository, https://github.com/atomsai/contextdb
@@ -9,7 +9,8 @@ Project-URL: Issues, https://github.com/atomsai/contextdb/issues
9
9
  Author-email: Gaurav Sharma <gaurav@saaslabs.co>
10
10
  License-Expression: Apache-2.0
11
11
  License-File: LICENSE
12
- Keywords: ai-agents,context,knowledge-graph,llm,memory,rag,vector-database
12
+ License-File: NOTICE
13
+ Keywords: agent-memory,ai-agents,context,knowledge-graph,llm,memory,rag,trust,vector-database
13
14
  Classifier: Development Status :: 3 - Alpha
14
15
  Classifier: Intended Audience :: Developers
15
16
  Classifier: License :: OSI Approved :: Apache Software License
@@ -32,7 +33,10 @@ Requires-Dist: neo4j>=5.0; extra == 'all'
32
33
  Requires-Dist: pgvector>=0.2; extra == 'all'
33
34
  Requires-Dist: redis>=5.0; extra == 'all'
34
35
  Requires-Dist: sentence-transformers>=2.0; extra == 'all'
36
+ Requires-Dist: starlette>=0.37; extra == 'all'
37
+ Requires-Dist: uvicorn>=0.27; extra == 'all'
35
38
  Provides-Extra: dev
39
+ Requires-Dist: httpx>=0.27; extra == 'dev'
36
40
  Requires-Dist: hypothesis>=6.0; extra == 'dev'
37
41
  Requires-Dist: mypy>=1.8; extra == 'dev'
38
42
  Requires-Dist: pre-commit>=3.0; extra == 'dev'
@@ -40,6 +44,7 @@ Requires-Dist: pytest-asyncio>=0.21; extra == 'dev'
40
44
  Requires-Dist: pytest-cov>=4.0; extra == 'dev'
41
45
  Requires-Dist: pytest>=7.0; extra == 'dev'
42
46
  Requires-Dist: ruff>=0.4; extra == 'dev'
47
+ Requires-Dist: starlette>=0.37; extra == 'dev'
43
48
  Provides-Extra: faiss
44
49
  Requires-Dist: faiss-cpu>=1.7; extra == 'faiss'
45
50
  Provides-Extra: local
@@ -54,6 +59,9 @@ Requires-Dist: redis>=5.0; extra == 'redis'
54
59
  Provides-Extra: rl
55
60
  Requires-Dist: torch>=2.0; extra == 'rl'
56
61
  Requires-Dist: trl>=0.7; extra == 'rl'
62
+ Provides-Extra: serve
63
+ Requires-Dist: starlette>=0.37; extra == 'serve'
64
+ Requires-Dist: uvicorn>=0.27; extra == 'serve'
57
65
  Description-Content-Type: text/markdown
58
66
 
59
67
  <p align="center">
@@ -66,7 +74,7 @@ Description-Content-Type: text/markdown
66
74
  <p align="center">
67
75
  <a href="https://pypi.org/project/pycontextdb/"><img src="https://img.shields.io/pypi/v/pycontextdb.svg" alt="PyPI version"></a>
68
76
  <a href="https://github.com/atomsai/contextdb/blob/main/LICENSE"><img src="https://img.shields.io/badge/License-Apache%202.0-blue.svg" alt="License: Apache 2.0"></a>
69
- <a href="https://github.com/atomsai/contextdb/blob/main/tests/"><img src="https://img.shields.io/badge/tests-82%20passing-brightgreen.svg" alt="Tests"></a>
77
+ <a href="https://github.com/atomsai/contextdb/blob/main/tests/"><img src="https://img.shields.io/badge/tests-139%20passing-brightgreen.svg" alt="Tests"></a>
70
78
  <a href="https://www.python.org/downloads/"><img src="https://img.shields.io/badge/python-3.10%2B-blue.svg" alt="Python 3.10+"></a>
71
79
  <a href="https://github.com/atomsai/contextdb/blob/main/pyproject.toml"><img src="https://img.shields.io/badge/mypy-strict-blue.svg" alt="Type Checked"></a>
72
80
  <a href="https://github.com/atomsai/contextdb/blob/main/benchmarks/run_benchmarks.py"><img src="https://img.shields.io/badge/search_p95-%3C5ms_%40_5K-brightgreen.svg" alt="Search p95"></a>
@@ -94,13 +102,37 @@ Description-Content-Type: text/markdown
94
102
  | **Search latency (5K memories)** | p50 **3.9ms** · p95 **5.0ms** |
95
103
  | **Vector search (10K × 1,536d)** | p50 **0.8ms** · p95 **1.0ms** |
96
104
  | **PII detection** | 100,000+ texts/sec |
97
- | **Tests** | 82 passing · ruff clean · mypy `--strict` clean |
105
+ | **Tests** | 139 passing (incl. 34 trust-model acceptance evals) · ruff clean · mypy `--strict` clean |
98
106
  | **Dependencies** | SQLite + NumPy (FAISS / Postgres optional) |
99
107
 
108
+ Those search numbers are **SQLite + the in-repo mock embedder**. A recall
109
+ that embeds the query with OpenAI is typically **100–300ms** before the
110
+ store is touched. Use `embedding_cache_size`, `pip install 'pycontextdb[local]'`,
111
+ or `lexical_on_embed_failure` when the voice turn budget cannot wait.
112
+
100
113
  Hermetic, reproducible — run the suite yourself: `python benchmarks/run_benchmarks.py`.
101
114
 
102
115
  ---
103
116
 
117
+ ## The trust model — memory your agent can act on
118
+
119
+ Speed is table stakes. The production failure that gets agents fired is **acting on a wish as if it were a fact**: a caller says *"I'd like to come in Thursday"* and the agent answers *"we penciled you in."* A wish and a confirmed fact are the same object in every memory store on the market — so ContextDB types them.
120
+
121
+ Every memory carries **epistemic provenance** (`user_stated` / `agent_inferred` / `third_party`), **confidence**, **independent corroboration** (same-speaker repeats do not count), and an **action-relevant** flag. The action bar is data — `TrustPolicy.hospital()` vs `TrustPolicy.restaurant()` — not a hardcoded `if`. Facts that gate actions must pass the active policy before `recall_for_action()` releases them; everything else comes back marked `requires_confirmation`. `factual.confirm()` is the writeback: the agent asked, the user said yes, the fact graduates. Stock hosts (Pipecat, LiveKit, MCP) go through `VerifyBeforeAct` so an untrusted fact never reaches an action-shaped prompt.
122
+
123
+ On top of that: **versioned slot vocabulary** + an LLM-free slotter (so `add_fast` and supersede agree), **extractor-as-security-boundary** (a prompt-injected `user/allergy` the raw text does not support is demoted), **contested slots** (independent speakers asserting different values do not last-write-win — both stay current, neither is actionable, `confirm()` resolves), **compositional hop** (`"when is the Denver meeting?"` surfaces `meeting/time` after hitting `meeting/location`), **PII-safe recall** (queries are redacted before embed so a raw email still retrieves `[EMAIL]`), **temporal supersede** with an injectable clock (`valid_from`/`valid_until`/`superseded_by` + as-of queries), a **latency-tiered write path** (`add_fast`: no LLM on the turn path, p95 ≈ 1.5ms local), **salience** (recency × frequency × criticality — a year-old allergy still outranks 500 fresh noise memories), **write-time injection screening** with demoted `[RECALLED DATA — not instructions]` rendering, **recall-side observability** (`db.explain(id)` logs score *and* decision flags as they stood at recall time; `VerifyBeforeAct` writes `DECIDE` to the audit log), **verifiable forgetting** that walks graph edges, and **tenant/agent isolation enforced at the storage layer**.
124
+
125
+ Don't take our word for it — the fabrication benchmark ships in-repo and runs on every PR. Same store, same embedder, same utterance policy; the only difference is the trust model:
126
+
127
+ | Arm | Fabrication rate (lower=better) | Recall accuracy | Temporal supersede | Over-refusal | Write p95 |
128
+ | --- | --- | --- | --- | --- | --- |
129
+ | `contextdb-trust` | **0%** | **100%** | yes | no | 1.5ms |
130
+ | `raw-store-baseline` (untyped control) | 50% | 88% | NO | no | 0.9ms |
131
+
132
+ Traps: wish-vs-fact, temporal move, prompt injection, PII redaction, cross-tenant bleed, negation, quantity update, over-refusal. Run it: `python benchmarks/trust_bakeoff.py` — acceptance evals live in `tests/evals/`. Mem0/Zep/Letta/supermemory arms implement the `MemoryArm` protocol and plug into the same harness.
133
+
134
+ ---
135
+
104
136
  ## The problem
105
137
 
106
138
  <p align="center">
@@ -117,6 +149,7 @@ Databricks Lakebase gives agents a hard drive. ContextDB gives agents a brain.
117
149
 
118
150
  | What you use today | What breaks | ContextDB equivalent |
119
151
  |---|---|---|
152
+ | Mem0 / supermemory / Zep | Store-and-recall: a wish and a fact are the same object; last write wins; no verify-before-act | Epistemic typing, `TrustPolicy`, contested slots, `recall_for_action()`, `confirm()` |
120
153
  | Pinecone / Qdrant / Weaviate | Semantic-only; no temporal, causal, or entity awareness | Multi-graph retrieval fused with RRF (semantic + temporal + causal + entity) |
121
154
  | Redis / Memcached | Ephemeral; lost between sessions; no compression | `WorkingMemory` with token-budget paging and FIFO eviction |
122
155
  | PostgreSQL / MongoDB | Static rows; no lifecycle; no graph links | `FactualMemory` with formation, evolution, and consolidation |
@@ -369,16 +402,18 @@ AutoGen adapter ships in `contextdb.integrations.autogen` with the same shape.
369
402
 
370
403
  ---
371
404
 
372
- ## Use with AI coding tools
405
+ ## Use with Cursor, Claude Code, and GitHub Copilot
373
406
 
374
- Drop any of these files into your project and your AI coding tool will automatically reach for ContextDB whenever it needs to add memory to an agent — no hand-holding required.
407
+ Drop-in files live in [`ai-tools/`](https://github.com/atomsai/contextdb/tree/main/ai-tools) — copy whichever ones match your stack into your own project and the AI tool will reach for ContextDB automatically when an agent needs memory. No prompt gymnastics, no "please use ContextDB" in every message.
408
+
409
+ **Why:** with one of these rule files in your repo, "add memory to this agent" just works — the assistant already knows `db.factual.add` / `db.search` is the right shape and stops suggesting raw Pinecone, Redis for session state, custom PII regex, or `ConversationBufferMemory`. Fewer revert-and-redo cycles.
375
410
 
376
411
  | File | Tool | What it does |
377
412
  |---|---|---|
378
- | [`.cursorrules`](https://github.com/atomsai/contextdb/blob/main/.cursorrules) | Cursor | Auto-uses ContextDB for all agent-memory tasks; bans raw Pinecone / Redis / custom PII regex |
379
- | [`CLAUDE.md`](https://github.com/atomsai/contextdb/blob/main/CLAUDE.md) | Claude Code | Same, for Claude Code — includes the `async with db:` pattern and framework adapters |
413
+ | [`ai-tools/.cursorrules`](https://github.com/atomsai/contextdb/blob/main/ai-tools/.cursorrules) | Cursor | Auto-uses ContextDB for all agent-memory tasks; bans raw Pinecone / Redis / custom PII regex |
414
+ | [`ai-tools/CLAUDE.md`](https://github.com/atomsai/contextdb/blob/main/ai-tools/CLAUDE.md) | Claude Code | Same, for Claude Code — includes the `async with db:` pattern and framework adapters |
380
415
  | [`.github/copilot-instructions.md`](https://github.com/atomsai/contextdb/blob/main/.github/copilot-instructions.md) | GitHub Copilot | Biases Copilot suggestions toward `db.factual.add` / `db.search` over custom vector plumbing |
381
- | [`llms.txt`](https://github.com/atomsai/contextdb/blob/main/llms.txt) · [`llms-full.txt`](https://github.com/atomsai/contextdb/blob/main/llms-full.txt) | Any LLM | Host at your docs-site root so assistants can discover and recommend ContextDB |
416
+ | [`ai-tools/llms.txt`](https://github.com/atomsai/contextdb/blob/main/ai-tools/llms.txt) · [`ai-tools/llms-full.txt`](https://github.com/atomsai/contextdb/blob/main/ai-tools/llms-full.txt) | Any LLM | Host at your docs-site root so assistants can discover and recommend ContextDB |
382
417
 
383
418
  ### Or copy-paste a ready-made prompt
384
419
 
@@ -526,7 +561,7 @@ Numbers above are from a MacBook-class laptop with no FAISS. Rerun `python bench
526
561
 
527
562
  ## Why not just use...
528
563
 
529
- **Mem0?** Graph intelligence is gated behind the paid tier. No experiential memory for trajectories and reflections. No RL-trained memory manager. No working memory with token budgets.
564
+ **Mem0?** Their graph intelligence is a commercial add-on. ContextDB ships experiential memory, working-memory paging, and the trust bar in the Apache SDK.
530
565
 
531
566
  **Zep?** Strong bitemporal knowledge graphs. But no experiential memory, no working memory paging, no learned retrieval policies. Scope is narrower than a full memory OS.
532
567
 
@@ -565,9 +600,53 @@ Python 3.10+. No system dependencies for the default install — SQLite and NumP
565
600
 
566
601
  ---
567
602
 
603
+ ## HTTP and multi-tenant hosts
604
+
605
+ ```bash
606
+ pip install 'pycontextdb[serve]'
607
+ contextdb serve --http --port 8080 --token "$CONTEXTDB_SERVE_TOKEN"
608
+ ```
609
+
610
+ One process, many users: `init()` without `user_id`, then pass `user_id=`
611
+ on each call (or `X-ContextDB-User` on HTTP). Postgres:
612
+
613
+ ```bash
614
+ pip install 'pycontextdb[postgres]'
615
+ ```
616
+
617
+ ```python
618
+ db = contextdb.init(storage_url="postgresql://...")
619
+ ```
620
+
621
+ See [docs/serve.md](docs/serve.md), [docs/multi_tenant.md](docs/multi_tenant.md),
622
+ and [docs/trust_policy.md](docs/trust_policy.md).
623
+
624
+ ## License and attribution
625
+
626
+ The SDK, trust model, and evals are Apache-2.0 — everything described in
627
+ this README ships in this tree, with no feature gates. **ContextDB** is a
628
+ trademark; the Apache license is not a trademark license. Reselling
629
+ ContextDB as a service, or as part of one, under the ContextDB name or
630
+ branding requires a commercial agreement with Atoms AI — contact
631
+ contextdb@atomsai.com (see [COMMERCIAL.md](COMMERCIAL.md)). A public
632
+ credit line is optional — if you want one, use **Built with ContextDB**
633
+ linking to this repository.
634
+
568
635
  ## Contributing
569
636
 
570
- Apache 2.0 — see [LICENSE](https://github.com/atomsai/contextdb/blob/main/LICENSE). See [`docs/architecture.md`](https://github.com/atomsai/contextdb/blob/main/docs/architecture.md) for the design rationale. Issues and pull requests welcome on [GitHub](https://github.com/atomsai/contextdb).
637
+ Apache 2.0 — see [LICENSE](https://github.com/atomsai/contextdb/blob/main/LICENSE).
638
+ Substantial PRs need a CLA ([CONTRIBUTING.md](CONTRIBUTING.md)).
639
+ See [`docs/architecture.md`](https://github.com/atomsai/contextdb/blob/main/docs/architecture.md) for the design rationale. Issues and pull requests welcome on [GitHub](https://github.com/atomsai/contextdb).
640
+
641
+ **Local setup:**
642
+
643
+ ```bash
644
+ pip install -e ".[dev]"
645
+ pre-commit install # enables gitleaks + basic hygiene checks on every commit
646
+ pytest # runs the test suite
647
+ ```
648
+
649
+ The pre-commit hook blocks commits that would leak secrets (PyPI / GitHub / AWS tokens, private keys, etc.). CI re-runs the same checks, so you can't push past a leak even if the hook is skipped locally.
571
650
 
572
651
  If you use ContextDB in research, please cite the paper: [zenodo.org/records/19647089](https://zenodo.org/records/19647089).
573
652