pycontextdb 0.2.0__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 (146) 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.2.0 → pycontextdb-0.3.0}/.github/workflows/ci.yml +0 -14
  4. {pycontextdb-0.2.0 → pycontextdb-0.3.0}/.github/workflows/publish.yml +3 -3
  5. {pycontextdb-0.2.0 → pycontextdb-0.3.0}/.pre-commit-config.yaml +1 -1
  6. pycontextdb-0.3.0/CHANGELOG.md +107 -0
  7. pycontextdb-0.3.0/COMMERCIAL.md +40 -0
  8. {pycontextdb-0.2.0 → pycontextdb-0.3.0}/CONTRIBUTING.md +11 -14
  9. {pycontextdb-0.2.0 → pycontextdb-0.3.0}/NOTICE +2 -1
  10. {pycontextdb-0.2.0 → pycontextdb-0.3.0}/PKG-INFO +46 -11
  11. {pycontextdb-0.2.0 → pycontextdb-0.3.0}/README.md +38 -10
  12. {pycontextdb-0.2.0 → pycontextdb-0.3.0}/contextdb/__init__.py +12 -2
  13. {pycontextdb-0.2.0 → pycontextdb-0.3.0}/contextdb/cli.py +22 -0
  14. {pycontextdb-0.2.0 → pycontextdb-0.3.0}/contextdb/client.py +313 -39
  15. {pycontextdb-0.2.0 → pycontextdb-0.3.0}/contextdb/core/config.py +30 -4
  16. {pycontextdb-0.2.0 → pycontextdb-0.3.0}/contextdb/core/exceptions.py +21 -0
  17. {pycontextdb-0.2.0 → pycontextdb-0.3.0}/contextdb/core/models.py +4 -0
  18. {pycontextdb-0.2.0 → pycontextdb-0.3.0}/contextdb/dynamics/evolution.py +3 -3
  19. {pycontextdb-0.2.0 → pycontextdb-0.3.0}/contextdb/dynamics/retrieval.py +14 -5
  20. {pycontextdb-0.2.0 → pycontextdb-0.3.0}/contextdb/dynamics/trust.py +17 -6
  21. {pycontextdb-0.2.0 → pycontextdb-0.3.0}/contextdb/graphs/base.py +2 -2
  22. {pycontextdb-0.2.0 → pycontextdb-0.3.0}/contextdb/graphs/causal.py +4 -3
  23. {pycontextdb-0.2.0 → pycontextdb-0.3.0}/contextdb/graphs/entity.py +6 -4
  24. {pycontextdb-0.2.0 → pycontextdb-0.3.0}/contextdb/graphs/semantic.py +6 -3
  25. {pycontextdb-0.2.0 → pycontextdb-0.3.0}/contextdb/graphs/temporal.py +2 -2
  26. {pycontextdb-0.2.0 → pycontextdb-0.3.0}/contextdb/integrations/act.py +35 -13
  27. {pycontextdb-0.2.0 → pycontextdb-0.3.0}/contextdb/mcp.py +94 -10
  28. {pycontextdb-0.2.0 → pycontextdb-0.3.0}/contextdb/memory/factual.py +50 -17
  29. pycontextdb-0.3.0/contextdb/pool.py +69 -0
  30. {pycontextdb-0.2.0 → pycontextdb-0.3.0}/contextdb/privacy/audit.py +47 -38
  31. {pycontextdb-0.2.0 → pycontextdb-0.3.0}/contextdb/privacy/pii_detector.py +24 -16
  32. {pycontextdb-0.2.0 → pycontextdb-0.3.0}/contextdb/privacy/retention.py +2 -2
  33. pycontextdb-0.3.0/contextdb/serve.py +416 -0
  34. {pycontextdb-0.2.0 → pycontextdb-0.3.0}/contextdb/store/__init__.py +3 -0
  35. pycontextdb-0.3.0/contextdb/store/base.py +156 -0
  36. pycontextdb-0.3.0/contextdb/store/factory.py +61 -0
  37. pycontextdb-0.3.0/contextdb/store/pg_sql.py +69 -0
  38. pycontextdb-0.3.0/contextdb/store/postgres_store.py +846 -0
  39. {pycontextdb-0.2.0 → pycontextdb-0.3.0}/contextdb/store/sqlite_store.py +210 -56
  40. {pycontextdb-0.2.0 → pycontextdb-0.3.0}/contextdb/store/vector_index.py +67 -4
  41. {pycontextdb-0.2.0 → pycontextdb-0.3.0}/contextdb/utils/embeddings.py +60 -0
  42. {pycontextdb-0.2.0 → pycontextdb-0.3.0}/docs/api.md +34 -10
  43. {pycontextdb-0.2.0 → pycontextdb-0.3.0}/docs/architecture.md +8 -4
  44. {pycontextdb-0.2.0 → pycontextdb-0.3.0}/docs/index.md +8 -4
  45. pycontextdb-0.3.0/docs/migrations.md +24 -0
  46. pycontextdb-0.3.0/docs/multi_tenant.md +61 -0
  47. pycontextdb-0.3.0/docs/postgres.md +74 -0
  48. {pycontextdb-0.2.0 → pycontextdb-0.3.0}/docs/quickstart.md +2 -2
  49. pycontextdb-0.3.0/docs/serve.md +83 -0
  50. pycontextdb-0.3.0/docs/trust_policy.md +54 -0
  51. {pycontextdb-0.2.0 → pycontextdb-0.3.0}/mkdocs.yml +5 -0
  52. {pycontextdb-0.2.0 → pycontextdb-0.3.0}/pyproject.toml +18 -9
  53. pycontextdb-0.2.0/scripts/check_open_core.py → pycontextdb-0.3.0/scripts/check_release.py +17 -102
  54. {pycontextdb-0.2.0 → pycontextdb-0.3.0}/tests/evals/test_trust_model.py +4 -3
  55. pycontextdb-0.3.0/tests/pg_util.py +48 -0
  56. {pycontextdb-0.2.0 → pycontextdb-0.3.0}/tests/unit/test_audit.py +19 -0
  57. pycontextdb-0.3.0/tests/unit/test_decision_scope.py +173 -0
  58. pycontextdb-0.3.0/tests/unit/test_host_api.py +238 -0
  59. pycontextdb-0.3.0/tests/unit/test_pg_sql.py +34 -0
  60. {pycontextdb-0.2.0 → pycontextdb-0.3.0}/tests/unit/test_pii_detector.py +26 -8
  61. pycontextdb-0.3.0/tests/unit/test_postgres_concurrency.py +179 -0
  62. pycontextdb-0.3.0/tests/unit/test_scoped_id_access.py +140 -0
  63. pycontextdb-0.3.0/tests/unit/test_serve.py +369 -0
  64. pycontextdb-0.3.0/tests/unit/test_vector_scope.py +174 -0
  65. pycontextdb-0.2.0/.github/CODEOWNERS +0 -16
  66. pycontextdb-0.2.0/.github/pull_request_template.md +0 -11
  67. pycontextdb-0.2.0/CHANGELOG.md +0 -49
  68. pycontextdb-0.2.0/COMMERCIAL.md +0 -78
  69. pycontextdb-0.2.0/OPEN_CORE.md +0 -107
  70. pycontextdb-0.2.0/contextdb/store/base.py +0 -71
  71. pycontextdb-0.2.0/tests/unit/test_open_core_boundary.py +0 -28
  72. {pycontextdb-0.2.0 → pycontextdb-0.3.0}/.github/copilot-instructions.md +0 -0
  73. {pycontextdb-0.2.0 → pycontextdb-0.3.0}/.gitignore +0 -0
  74. {pycontextdb-0.2.0 → pycontextdb-0.3.0}/LICENSE +0 -0
  75. {pycontextdb-0.2.0 → pycontextdb-0.3.0}/ai-tools/.cursorrules +0 -0
  76. {pycontextdb-0.2.0 → pycontextdb-0.3.0}/ai-tools/CLAUDE.md +0 -0
  77. {pycontextdb-0.2.0 → pycontextdb-0.3.0}/ai-tools/README.md +0 -0
  78. {pycontextdb-0.2.0 → pycontextdb-0.3.0}/ai-tools/llms-full.txt +0 -0
  79. {pycontextdb-0.2.0 → pycontextdb-0.3.0}/ai-tools/llms.txt +0 -0
  80. {pycontextdb-0.2.0 → pycontextdb-0.3.0}/assets/README.md +0 -0
  81. {pycontextdb-0.2.0 → pycontextdb-0.3.0}/assets/architecture.png +0 -0
  82. {pycontextdb-0.2.0 → pycontextdb-0.3.0}/assets/benchmarks.png +0 -0
  83. {pycontextdb-0.2.0 → pycontextdb-0.3.0}/assets/hero.png +0 -0
  84. {pycontextdb-0.2.0 → pycontextdb-0.3.0}/assets/performance.png +0 -0
  85. {pycontextdb-0.2.0 → pycontextdb-0.3.0}/assets/problem.png +0 -0
  86. {pycontextdb-0.2.0 → pycontextdb-0.3.0}/assets/quickstart.png +0 -0
  87. {pycontextdb-0.2.0 → pycontextdb-0.3.0}/benchmarks/__init__.py +0 -0
  88. {pycontextdb-0.2.0 → pycontextdb-0.3.0}/benchmarks/run_benchmarks.py +0 -0
  89. {pycontextdb-0.2.0 → pycontextdb-0.3.0}/benchmarks/trust_bakeoff.py +0 -0
  90. {pycontextdb-0.2.0 → pycontextdb-0.3.0}/contextdb/agents/__init__.py +0 -0
  91. {pycontextdb-0.2.0 → pycontextdb-0.3.0}/contextdb/agents/memory_bus.py +0 -0
  92. {pycontextdb-0.2.0 → pycontextdb-0.3.0}/contextdb/agents/rl_manager.py +0 -0
  93. {pycontextdb-0.2.0 → pycontextdb-0.3.0}/contextdb/core/__init__.py +0 -0
  94. {pycontextdb-0.2.0 → pycontextdb-0.3.0}/contextdb/core/clock.py +0 -0
  95. {pycontextdb-0.2.0 → pycontextdb-0.3.0}/contextdb/core/policy.py +0 -0
  96. {pycontextdb-0.2.0 → pycontextdb-0.3.0}/contextdb/core/slots.py +0 -0
  97. {pycontextdb-0.2.0 → pycontextdb-0.3.0}/contextdb/dynamics/__init__.py +0 -0
  98. {pycontextdb-0.2.0 → pycontextdb-0.3.0}/contextdb/dynamics/formation.py +0 -0
  99. {pycontextdb-0.2.0 → pycontextdb-0.3.0}/contextdb/dynamics/salience.py +0 -0
  100. {pycontextdb-0.2.0 → pycontextdb-0.3.0}/contextdb/graphs/__init__.py +0 -0
  101. {pycontextdb-0.2.0 → pycontextdb-0.3.0}/contextdb/integrations/__init__.py +0 -0
  102. {pycontextdb-0.2.0 → pycontextdb-0.3.0}/contextdb/integrations/autogen.py +0 -0
  103. {pycontextdb-0.2.0 → pycontextdb-0.3.0}/contextdb/integrations/crewai.py +0 -0
  104. {pycontextdb-0.2.0 → pycontextdb-0.3.0}/contextdb/integrations/langchain.py +0 -0
  105. {pycontextdb-0.2.0 → pycontextdb-0.3.0}/contextdb/integrations/livekit.py +0 -0
  106. {pycontextdb-0.2.0 → pycontextdb-0.3.0}/contextdb/integrations/openai_tools.py +0 -0
  107. {pycontextdb-0.2.0 → pycontextdb-0.3.0}/contextdb/integrations/pipecat.py +0 -0
  108. {pycontextdb-0.2.0 → pycontextdb-0.3.0}/contextdb/integrations/prompting.py +0 -0
  109. {pycontextdb-0.2.0 → pycontextdb-0.3.0}/contextdb/memory/__init__.py +0 -0
  110. {pycontextdb-0.2.0 → pycontextdb-0.3.0}/contextdb/memory/experiential.py +0 -0
  111. {pycontextdb-0.2.0 → pycontextdb-0.3.0}/contextdb/memory/working.py +0 -0
  112. {pycontextdb-0.2.0 → pycontextdb-0.3.0}/contextdb/privacy/__init__.py +0 -0
  113. {pycontextdb-0.2.0 → pycontextdb-0.3.0}/contextdb/privacy/injection.py +0 -0
  114. {pycontextdb-0.2.0 → pycontextdb-0.3.0}/contextdb/py.typed +0 -0
  115. {pycontextdb-0.2.0 → pycontextdb-0.3.0}/contextdb/utils/__init__.py +0 -0
  116. {pycontextdb-0.2.0 → pycontextdb-0.3.0}/contextdb/utils/llm.py +0 -0
  117. {pycontextdb-0.2.0 → pycontextdb-0.3.0}/contextdb/utils/migrations.py +0 -0
  118. {pycontextdb-0.2.0 → pycontextdb-0.3.0}/docs/prompts.md +0 -0
  119. {pycontextdb-0.2.0 → pycontextdb-0.3.0}/examples/customer_support.py +0 -0
  120. {pycontextdb-0.2.0 → pycontextdb-0.3.0}/examples/multi_agent_team.py +0 -0
  121. {pycontextdb-0.2.0 → pycontextdb-0.3.0}/examples/phone_agent.py +0 -0
  122. {pycontextdb-0.2.0 → pycontextdb-0.3.0}/examples/research_assistant.py +0 -0
  123. {pycontextdb-0.2.0 → pycontextdb-0.3.0}/legal/CLA-entity.md +0 -0
  124. {pycontextdb-0.2.0 → pycontextdb-0.3.0}/legal/CLA-individual.md +0 -0
  125. {pycontextdb-0.2.0 → pycontextdb-0.3.0}/legal/signed/README.md +0 -0
  126. {pycontextdb-0.2.0 → pycontextdb-0.3.0}/tests/__init__.py +0 -0
  127. {pycontextdb-0.2.0 → pycontextdb-0.3.0}/tests/conftest.py +0 -0
  128. {pycontextdb-0.2.0 → pycontextdb-0.3.0}/tests/evals/__init__.py +0 -0
  129. {pycontextdb-0.2.0 → pycontextdb-0.3.0}/tests/integration/__init__.py +0 -0
  130. {pycontextdb-0.2.0 → pycontextdb-0.3.0}/tests/integration/test_client.py +0 -0
  131. {pycontextdb-0.2.0 → pycontextdb-0.3.0}/tests/integration/test_langchain_integration.py +0 -0
  132. {pycontextdb-0.2.0 → pycontextdb-0.3.0}/tests/test_version.py +0 -0
  133. {pycontextdb-0.2.0 → pycontextdb-0.3.0}/tests/unit/__init__.py +0 -0
  134. {pycontextdb-0.2.0 → pycontextdb-0.3.0}/tests/unit/test_config.py +0 -0
  135. {pycontextdb-0.2.0 → pycontextdb-0.3.0}/tests/unit/test_embeddings.py +0 -0
  136. {pycontextdb-0.2.0 → pycontextdb-0.3.0}/tests/unit/test_evolution.py +0 -0
  137. {pycontextdb-0.2.0 → pycontextdb-0.3.0}/tests/unit/test_formation.py +0 -0
  138. {pycontextdb-0.2.0 → pycontextdb-0.3.0}/tests/unit/test_graphs.py +0 -0
  139. {pycontextdb-0.2.0 → pycontextdb-0.3.0}/tests/unit/test_init.py +0 -0
  140. {pycontextdb-0.2.0 → pycontextdb-0.3.0}/tests/unit/test_memory_bus.py +0 -0
  141. {pycontextdb-0.2.0 → pycontextdb-0.3.0}/tests/unit/test_models.py +0 -0
  142. {pycontextdb-0.2.0 → pycontextdb-0.3.0}/tests/unit/test_retention.py +0 -0
  143. {pycontextdb-0.2.0 → pycontextdb-0.3.0}/tests/unit/test_retrieval.py +0 -0
  144. {pycontextdb-0.2.0 → pycontextdb-0.3.0}/tests/unit/test_store.py +0 -0
  145. {pycontextdb-0.2.0 → pycontextdb-0.3.0}/tests/unit/test_trust_policy.py +0 -0
  146. {pycontextdb-0.2.0 → 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.
@@ -62,17 +62,3 @@ jobs:
62
62
 
63
63
  - name: Run tests
64
64
  run: pytest
65
-
66
- open-core:
67
- name: Open-core boundary
68
- runs-on: ubuntu-latest
69
- steps:
70
- - uses: actions/checkout@v4
71
-
72
- - name: Set up Python
73
- uses: actions/setup-python@v5
74
- with:
75
- python-version: "3.12"
76
-
77
- - name: Package-boundary and accidental-publication checks
78
- run: python scripts/check_open_core.py
@@ -25,9 +25,9 @@ jobs:
25
25
  - name: Build sdist and wheel
26
26
  run: python -m build
27
27
 
28
- - name: Open-core and accidental-publication inspection
28
+ - name: Release-safety inspection
29
29
  run: |
30
- python scripts/check_open_core.py --dist dist --release-tag "${{ github.event.release.tag_name }}"
30
+ python scripts/check_release.py --dist dist --release-tag "${{ github.event.release.tag_name }}"
31
31
 
32
32
  - name: Upload dist artifacts
33
33
  uses: actions/upload-artifact@v4
@@ -42,7 +42,7 @@ jobs:
42
42
 
43
43
  # Trusted-publisher flow: PyPI verifies this workflow via OIDC.
44
44
  # Require reviewers on this GitHub Environment so a published tag
45
- # cannot reach PyPI without a human (OPEN_CORE.md).
45
+ # cannot reach PyPI without a human.
46
46
  environment:
47
47
  name: pypi
48
48
  url: https://pypi.org/project/pycontextdb/
@@ -8,7 +8,7 @@
8
8
 
9
9
  repos:
10
10
  # Secret scanning — the reason this file exists. Gitleaks scans the
11
- # staged diff for tokens (PyPI, GitHub, AWS, Stripe, Slack, generic
11
+ # staged diff for tokens (PyPI, GitHub, AWS, Slack, generic
12
12
  # entropy-high strings, ...). First run auto-downloads the binary.
13
13
  - repo: https://github.com/gitleaks/gitleaks
14
14
  rev: v8.30.0
@@ -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.
@@ -1,9 +1,8 @@
1
1
  # Contributing to ContextDB
2
2
 
3
3
  Thank you for wanting to improve ContextDB. This repository is the
4
- **open-core SDK**. Read [OPEN_CORE.md](OPEN_CORE.md) before you write
5
- code. If the change belongs in hosted multi-tenant operations, it does
6
- not belong here.
4
+ Apache-2.0 ContextDB SDK: everything here works offline, with no feature
5
+ gates.
7
6
 
8
7
  ## What we accept here
9
8
 
@@ -12,9 +11,9 @@ evals. Evals win over prose: `pytest tests/evals/ -v`.
12
11
 
13
12
  We do **not** accept:
14
13
 
15
- - Cloud control-plane, billing, SSO, or entitlement code
16
- - Local license keys or `if paid:` branches
17
- - Imports of `contextdb_cloud` or any private cloud package
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
18
17
  - Changes that loosen PII-before-embed or the hash-chained audit log
19
18
 
20
19
  ## Contributor License Agreement
@@ -22,10 +21,10 @@ We do **not** accept:
22
21
  Trivial changes (typos, broken links, comment nits) do not need a CLA.
23
22
 
24
23
  **Substantial contributions** (new or material code, evals, or docs that
25
- are not typo-fixes) require a signed CLA **before** merge. The CLA lets
26
- Atoms AI relicense *future* contributions if dual-licensing ever
27
- matters. It does not change the Apache-2.0 grant on code already
28
- public through `2554dae`.
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.
29
28
 
30
29
  1. Read [legal/CLA-individual.md](legal/CLA-individual.md) (or
31
30
  [legal/CLA-entity.md](legal/CLA-entity.md) if you contribute on
@@ -50,7 +49,6 @@ pre-commit install
50
49
  ruff check .
51
50
  mypy contextdb --strict
52
51
  pytest
53
- python scripts/check_open_core.py
54
52
  ```
55
53
 
56
54
  Do not break `contextdb.init`, `factual.add`, `factual.recall`, or
@@ -58,9 +56,8 @@ Do not break `contextdb.init`, `factual.add`, `factual.recall`, or
58
56
 
59
57
  ## Review
60
58
 
61
- [`.github/CODEOWNERS`](.github/CODEOWNERS) routes reviews. Governance
62
- files (`OPEN_CORE.md`, `COMMERCIAL.md`, `LICENSE`, `legal/`, workflows)
63
- need a maintainer.
59
+ [`.github/CODEOWNERS`](.github/CODEOWNERS) routes reviews. `LICENSE`,
60
+ `NOTICE`, `legal/`, and the workflows need a maintainer.
64
61
 
65
62
  ## License of your contribution
66
63
 
@@ -6,4 +6,5 @@ Licensed under the Apache License, Version 2.0. See LICENSE.
6
6
 
7
7
  ContextDB and the ContextDB logo are trademarks of Atoms AI.
8
8
  The Apache License does not grant permission to use the ContextDB
9
- trademarks. See COMMERCIAL.md.
9
+ trademarks. For trademark and commercial licensing (including resale
10
+ or hosted services), contact contextdb@atomsai.com. See COMMERCIAL.md.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: pycontextdb
3
- Version: 0.2.0
3
+ Version: 0.3.0
4
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
@@ -33,7 +33,10 @@ Requires-Dist: neo4j>=5.0; extra == 'all'
33
33
  Requires-Dist: pgvector>=0.2; extra == 'all'
34
34
  Requires-Dist: redis>=5.0; extra == 'all'
35
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'
36
38
  Provides-Extra: dev
39
+ Requires-Dist: httpx>=0.27; extra == 'dev'
37
40
  Requires-Dist: hypothesis>=6.0; extra == 'dev'
38
41
  Requires-Dist: mypy>=1.8; extra == 'dev'
39
42
  Requires-Dist: pre-commit>=3.0; extra == 'dev'
@@ -41,6 +44,7 @@ Requires-Dist: pytest-asyncio>=0.21; extra == 'dev'
41
44
  Requires-Dist: pytest-cov>=4.0; extra == 'dev'
42
45
  Requires-Dist: pytest>=7.0; extra == 'dev'
43
46
  Requires-Dist: ruff>=0.4; extra == 'dev'
47
+ Requires-Dist: starlette>=0.37; extra == 'dev'
44
48
  Provides-Extra: faiss
45
49
  Requires-Dist: faiss-cpu>=1.7; extra == 'faiss'
46
50
  Provides-Extra: local
@@ -55,6 +59,9 @@ Requires-Dist: redis>=5.0; extra == 'redis'
55
59
  Provides-Extra: rl
56
60
  Requires-Dist: torch>=2.0; extra == 'rl'
57
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'
58
65
  Description-Content-Type: text/markdown
59
66
 
60
67
  <p align="center">
@@ -67,7 +74,7 @@ Description-Content-Type: text/markdown
67
74
  <p align="center">
68
75
  <a href="https://pypi.org/project/pycontextdb/"><img src="https://img.shields.io/pypi/v/pycontextdb.svg" alt="PyPI version"></a>
69
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>
70
- <a href="https://github.com/atomsai/contextdb/blob/main/tests/"><img src="https://img.shields.io/badge/tests-122%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>
71
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>
72
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>
73
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>
@@ -95,9 +102,14 @@ Description-Content-Type: text/markdown
95
102
  | **Search latency (5K memories)** | p50 **3.9ms** · p95 **5.0ms** |
96
103
  | **Vector search (10K × 1,536d)** | p50 **0.8ms** · p95 **1.0ms** |
97
104
  | **PII detection** | 100,000+ texts/sec |
98
- | **Tests** | 122 passing (incl. 34 trust-model acceptance evals) · ruff clean · mypy `--strict` clean |
105
+ | **Tests** | 139 passing (incl. 34 trust-model acceptance evals) · ruff clean · mypy `--strict` clean |
99
106
  | **Dependencies** | SQLite + NumPy (FAISS / Postgres optional) |
100
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
+
101
113
  Hermetic, reproducible — run the suite yourself: `python benchmarks/run_benchmarks.py`.
102
114
 
103
115
  ---
@@ -549,7 +561,7 @@ Numbers above are from a MacBook-class laptop with no FAISS. Rerun `python bench
549
561
 
550
562
  ## Why not just use...
551
563
 
552
- **Mem0?** Their graph intelligence is a commercial add-on. ContextDB ships experiential memory, working-memory paging, and the trust bar in the Apache SDK — hosted multi-tenant operations are a separate Cloud product ([OPEN_CORE.md](OPEN_CORE.md)).
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.
553
565
 
554
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.
555
567
 
@@ -588,14 +600,37 @@ Python 3.10+. No system dependencies for the default install — SQLite and NumP
588
600
 
589
601
  ---
590
602
 
591
- ## Open core
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
592
625
 
593
- The SDK, trust model, and evals are Apache-2.0. Hosted multi-tenant
594
- operations live in a private `contextdb-cloud` repo that depends on this
595
- package this package never depends on cloud. Entitlements are
596
- server-side. See [OPEN_CORE.md](OPEN_CORE.md) and
597
- [COMMERCIAL.md](COMMERCIAL.md). **ContextDB** is a trademark; the Apache
598
- license is not a trademark license.
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.
599
634
 
600
635
  ## Contributing
601
636
 
@@ -8,7 +8,7 @@
8
8
  <p align="center">
9
9
  <a href="https://pypi.org/project/pycontextdb/"><img src="https://img.shields.io/pypi/v/pycontextdb.svg" alt="PyPI version"></a>
10
10
  <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>
11
- <a href="https://github.com/atomsai/contextdb/blob/main/tests/"><img src="https://img.shields.io/badge/tests-122%20passing-brightgreen.svg" alt="Tests"></a>
11
+ <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>
12
12
  <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>
13
13
  <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>
14
14
  <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>
@@ -36,9 +36,14 @@
36
36
  | **Search latency (5K memories)** | p50 **3.9ms** · p95 **5.0ms** |
37
37
  | **Vector search (10K × 1,536d)** | p50 **0.8ms** · p95 **1.0ms** |
38
38
  | **PII detection** | 100,000+ texts/sec |
39
- | **Tests** | 122 passing (incl. 34 trust-model acceptance evals) · ruff clean · mypy `--strict` clean |
39
+ | **Tests** | 139 passing (incl. 34 trust-model acceptance evals) · ruff clean · mypy `--strict` clean |
40
40
  | **Dependencies** | SQLite + NumPy (FAISS / Postgres optional) |
41
41
 
42
+ Those search numbers are **SQLite + the in-repo mock embedder**. A recall
43
+ that embeds the query with OpenAI is typically **100–300ms** before the
44
+ store is touched. Use `embedding_cache_size`, `pip install 'pycontextdb[local]'`,
45
+ or `lexical_on_embed_failure` when the voice turn budget cannot wait.
46
+
42
47
  Hermetic, reproducible — run the suite yourself: `python benchmarks/run_benchmarks.py`.
43
48
 
44
49
  ---
@@ -490,7 +495,7 @@ Numbers above are from a MacBook-class laptop with no FAISS. Rerun `python bench
490
495
 
491
496
  ## Why not just use...
492
497
 
493
- **Mem0?** Their graph intelligence is a commercial add-on. ContextDB ships experiential memory, working-memory paging, and the trust bar in the Apache SDK — hosted multi-tenant operations are a separate Cloud product ([OPEN_CORE.md](OPEN_CORE.md)).
498
+ **Mem0?** Their graph intelligence is a commercial add-on. ContextDB ships experiential memory, working-memory paging, and the trust bar in the Apache SDK.
494
499
 
495
500
  **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.
496
501
 
@@ -529,14 +534,37 @@ Python 3.10+. No system dependencies for the default install — SQLite and NumP
529
534
 
530
535
  ---
531
536
 
532
- ## Open core
537
+ ## HTTP and multi-tenant hosts
538
+
539
+ ```bash
540
+ pip install 'pycontextdb[serve]'
541
+ contextdb serve --http --port 8080 --token "$CONTEXTDB_SERVE_TOKEN"
542
+ ```
543
+
544
+ One process, many users: `init()` without `user_id`, then pass `user_id=`
545
+ on each call (or `X-ContextDB-User` on HTTP). Postgres:
546
+
547
+ ```bash
548
+ pip install 'pycontextdb[postgres]'
549
+ ```
550
+
551
+ ```python
552
+ db = contextdb.init(storage_url="postgresql://...")
553
+ ```
554
+
555
+ See [docs/serve.md](docs/serve.md), [docs/multi_tenant.md](docs/multi_tenant.md),
556
+ and [docs/trust_policy.md](docs/trust_policy.md).
557
+
558
+ ## License and attribution
533
559
 
534
- The SDK, trust model, and evals are Apache-2.0. Hosted multi-tenant
535
- operations live in a private `contextdb-cloud` repo that depends on this
536
- package this package never depends on cloud. Entitlements are
537
- server-side. See [OPEN_CORE.md](OPEN_CORE.md) and
538
- [COMMERCIAL.md](COMMERCIAL.md). **ContextDB** is a trademark; the Apache
539
- license is not a trademark license.
560
+ The SDK, trust model, and evals are Apache-2.0 everything described in
561
+ this README ships in this tree, with no feature gates. **ContextDB** is a
562
+ trademark; the Apache license is not a trademark license. Reselling
563
+ ContextDB as a service, or as part of one, under the ContextDB name or
564
+ branding requires a commercial agreement with Atoms AI — contact
565
+ contextdb@atomsai.com (see [COMMERCIAL.md](COMMERCIAL.md)). A public
566
+ credit line is optional — if you want one, use **Built with ContextDB**
567
+ linking to this repository.
540
568
 
541
569
  ## Contributing
542
570
 
@@ -12,7 +12,10 @@ from contextdb.core.exceptions import (
12
12
  ContextDBError,
13
13
  MemoryNotFoundError,
14
14
  PrivacyError,
15
+ ScopeConflictError,
16
+ SourceRequiredError,
15
17
  StorageError,
18
+ UnauthorizedError,
16
19
  )
17
20
  from contextdb.core.models import (
18
21
  Edge,
@@ -25,8 +28,9 @@ from contextdb.core.models import (
25
28
  RetentionPolicy,
26
29
  )
27
30
  from contextdb.core.policy import TrustPolicy
31
+ from contextdb.pool import ContextDBPool
28
32
 
29
- __version__ = "0.2.0"
33
+ __version__ = "0.3.0"
30
34
 
31
35
  __all__ = [
32
36
  "Clock",
@@ -34,6 +38,7 @@ __all__ = [
34
38
  "ContextDB",
35
39
  "ContextDBConfig",
36
40
  "ContextDBError",
41
+ "ContextDBPool",
37
42
  "Edge",
38
43
  "Entity",
39
44
  "FrozenClock",
@@ -45,8 +50,11 @@ __all__ = [
45
50
  "PIIType",
46
51
  "PrivacyError",
47
52
  "RetentionPolicy",
53
+ "ScopeConflictError",
54
+ "SourceRequiredError",
48
55
  "StorageError",
49
56
  "TrustPolicy",
57
+ "UnauthorizedError",
50
58
  "__version__",
51
59
  "init",
52
60
  "utc_now",
@@ -70,7 +78,9 @@ def init(
70
78
  any I/O method, so ``init()`` itself does not touch the disk or network.
71
79
 
72
80
  Args:
73
- user_id: Optional user scope. Every write carries this as a filter.
81
+ user_id: Default user scope. Omit this and pass ``user_id=`` on
82
+ each call for a shared multi-tenant client. A scoped client
83
+ cannot be widened to another user.
74
84
  config: Pre-built configuration. When ``None`` one is constructed
75
85
  from ``kwargs`` and environment variables prefixed with
76
86
  ``CONTEXTDB_``.
@@ -52,6 +52,17 @@ def _build_parser() -> argparse.ArgumentParser:
52
52
  p_import = sub.add_parser("import", help="Import a ContextDB JSON dump.")
53
53
  p_import.add_argument("path")
54
54
 
55
+ p_serve = sub.add_parser("serve", help="Serve HTTP JSON (and /mcp) for non-Python hosts.")
56
+ p_serve.add_argument("--http", action="store_true", default=True, help="HTTP JSON API.")
57
+ p_serve.add_argument("--host", default="127.0.0.1")
58
+ p_serve.add_argument("--port", type=int, default=8080)
59
+ p_serve.add_argument("--token", default=None, help="Bearer token. Or CONTEXTDB_SERVE_TOKEN.")
60
+ p_serve.add_argument(
61
+ "--allow-anonymous",
62
+ action="store_true",
63
+ help="Allow unauthenticated requests (loopback only unless you pass this).",
64
+ )
65
+
55
66
  return parser
56
67
 
57
68
 
@@ -90,6 +101,17 @@ async def _run(args: argparse.Namespace) -> int:
90
101
  importer = JSONImporter(client)
91
102
  count = await importer.import_path(Path(args.path))
92
103
  print(f"Imported {count} memories from {args.path}")
104
+ elif args.command == "serve":
105
+ from contextdb.serve import serve_http
106
+
107
+ await serve_http(
108
+ client,
109
+ host=args.host,
110
+ port=args.port,
111
+ token=args.token,
112
+ allow_anonymous=args.allow_anonymous,
113
+ )
114
+ return 0
93
115
  else:
94
116
  return 1
95
117
  return 0