thymus-ai 1.0.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 (80) hide show
  1. thymus_ai-1.0.0/.github/workflows/ci.yml +42 -0
  2. thymus_ai-1.0.0/.github/workflows/release.yml +60 -0
  3. thymus_ai-1.0.0/.gitignore +228 -0
  4. thymus_ai-1.0.0/.pre-commit-config.yaml +23 -0
  5. thymus_ai-1.0.0/CLAUDE.md +170 -0
  6. thymus_ai-1.0.0/LICENSE +201 -0
  7. thymus_ai-1.0.0/NOTICE +4 -0
  8. thymus_ai-1.0.0/PKG-INFO +257 -0
  9. thymus_ai-1.0.0/README.md +222 -0
  10. thymus_ai-1.0.0/Thymus_Phase0_Schemas.md +679 -0
  11. thymus_ai-1.0.0/Thymus_Product_Roadmap.md +246 -0
  12. thymus_ai-1.0.0/Thymus_features.md +100 -0
  13. thymus_ai-1.0.0/demo/README.md +101 -0
  14. thymus_ai-1.0.0/demo/poison_demo.py +187 -0
  15. thymus_ai-1.0.0/pyproject.toml +65 -0
  16. thymus_ai-1.0.0/requirements.txt +6 -0
  17. thymus_ai-1.0.0/run_baseline.py +80 -0
  18. thymus_ai-1.0.0/tests/test_conflict.py +62 -0
  19. thymus_ai-1.0.0/tests/test_conflict_precision.py +58 -0
  20. thymus_ai-1.0.0/tests/test_console_roundtrip.py +108 -0
  21. thymus_ai-1.0.0/tests/test_feedback.py +54 -0
  22. thymus_ai-1.0.0/tests/test_guard_swap.py +68 -0
  23. thymus_ai-1.0.0/tests/test_nonblocking_audit.py +97 -0
  24. thymus_ai-1.0.0/tests/test_read_path.py +69 -0
  25. thymus_ai-1.0.0/tests/test_remote_policy.py +164 -0
  26. thymus_ai-1.0.0/tests/test_review_fixes.py +126 -0
  27. thymus_ai-1.0.0/tests/test_rules.py +76 -0
  28. thymus_ai-1.0.0/tests/test_thymus_engine.py +89 -0
  29. thymus_ai-1.0.0/tests/test_zep.py +66 -0
  30. thymus_ai-1.0.0/thymus/README.md +166 -0
  31. thymus_ai-1.0.0/thymus/__init__.py +80 -0
  32. thymus_ai-1.0.0/thymus/adapters/__init__.py +24 -0
  33. thymus_ai-1.0.0/thymus/adapters/base.py +276 -0
  34. thymus_ai-1.0.0/thymus/adapters/generic.py +61 -0
  35. thymus_ai-1.0.0/thymus/adapters/mem0.py +37 -0
  36. thymus_ai-1.0.0/thymus/adapters/zep.py +85 -0
  37. thymus_ai-1.0.0/thymus/detectors/__init__.py +16 -0
  38. thymus_ai-1.0.0/thymus/detectors/base.py +67 -0
  39. thymus_ai-1.0.0/thymus/detectors/conflict.py +116 -0
  40. thymus_ai-1.0.0/thymus/detectors/egress.py +37 -0
  41. thymus_ai-1.0.0/thymus/detectors/injection.py +171 -0
  42. thymus_ai-1.0.0/thymus/detectors/origin.py +36 -0
  43. thymus_ai-1.0.0/thymus/engine.py +68 -0
  44. thymus_ai-1.0.0/thymus/feedback.py +81 -0
  45. thymus_ai-1.0.0/thymus/policy.py +103 -0
  46. thymus_ai-1.0.0/thymus/remote.py +288 -0
  47. thymus_ai-1.0.0/thymus/rules/__init__.py +26 -0
  48. thymus_ai-1.0.0/thymus/rules/loader.py +135 -0
  49. thymus_ai-1.0.0/thymus/rules/packs/auth_bypass.json +33 -0
  50. thymus_ai-1.0.0/thymus/rules/packs/exfiltration.json +33 -0
  51. thymus_ai-1.0.0/thymus/rules/packs/financial.json +46 -0
  52. thymus_ai-1.0.0/thymus/rules/packs/impersonation.json +33 -0
  53. thymus_ai-1.0.0/thymus/rules/packs/manipulation.json +20 -0
  54. thymus_ai-1.0.0/thymus/rules/packs/obfuscation.json +44 -0
  55. thymus_ai-1.0.0/thymus/rules/packs/ops_redirect.json +35 -0
  56. thymus_ai-1.0.0/thymus/rules/packs/persistence.json +33 -0
  57. thymus_ai-1.0.0/thymus/rules/packs/policy_override.json +33 -0
  58. thymus_ai-1.0.0/thymus/rules/packs/privilege_escalation.json +33 -0
  59. thymus_ai-1.0.0/thymus/rules/packs/prompt_extraction.json +20 -0
  60. thymus_ai-1.0.0/thymus/rules/packs/safety_suppression.json +20 -0
  61. thymus_ai-1.0.0/thymus/rules/packs/secrets_pii.json +80 -0
  62. thymus_ai-1.0.0/thymus/rules/packs/tool_abuse.json +46 -0
  63. thymus_ai-1.0.0/thymus/types.py +196 -0
  64. thymus_ai-1.0.0/thymus_bench/__init__.py +10 -0
  65. thymus_ai-1.0.0/thymus_bench/backends/__init__.py +12 -0
  66. thymus_ai-1.0.0/thymus_bench/backends/base.py +47 -0
  67. thymus_ai-1.0.0/thymus_bench/backends/inmemory.py +88 -0
  68. thymus_ai-1.0.0/thymus_bench/backends/mem0_backend.py +135 -0
  69. thymus_ai-1.0.0/thymus_bench/corpus/benign_facts.json +18 -0
  70. thymus_ai-1.0.0/thymus_bench/corpus/conflict_cases.json +19 -0
  71. thymus_ai-1.0.0/thymus_bench/corpus/hard_negatives.json +86 -0
  72. thymus_ai-1.0.0/thymus_bench/corpus/minja_attacks.json +256 -0
  73. thymus_ai-1.0.0/thymus_bench/guards/__init__.py +15 -0
  74. thymus_ai-1.0.0/thymus_bench/guards/base.py +47 -0
  75. thymus_ai-1.0.0/thymus_bench/guards/null_guard.py +18 -0
  76. thymus_ai-1.0.0/thymus_bench/guards/thymus_guard.py +46 -0
  77. thymus_ai-1.0.0/thymus_bench/metrics.py +70 -0
  78. thymus_ai-1.0.0/thymus_bench/report.py +107 -0
  79. thymus_ai-1.0.0/thymus_bench/rule_report.py +108 -0
  80. thymus_ai-1.0.0/thymus_bench/runner.py +163 -0
@@ -0,0 +1,42 @@
1
+ name: CI
2
+
3
+ # Server-side enforcement of what pre-commit does locally: lint, format, tests.
4
+ # Runs on every push to master and on every pull request.
5
+ on:
6
+ push:
7
+ branches: [master]
8
+ pull_request:
9
+
10
+ jobs:
11
+ lint-and-test:
12
+ runs-on: ubuntu-latest
13
+ strategy:
14
+ fail-fast: false
15
+ matrix:
16
+ # The package declares requires-python >=3.10 — test the whole range so
17
+ # a version-specific break can't slip through.
18
+ python-version: ["3.10", "3.11", "3.12", "3.13"]
19
+ steps:
20
+ - uses: actions/checkout@v5
21
+
22
+ - name: Set up uv + Python ${{ matrix.python-version }}
23
+ uses: astral-sh/setup-uv@v6
24
+ with:
25
+ python-version: ${{ matrix.python-version }}
26
+
27
+ # Create the venv explicitly so this doesn't depend on setup-uv's default
28
+ # (v5 auto-created one, v6 does not) — then install into it and run tools
29
+ # via `uv run`.
30
+ - name: Install (dev extra)
31
+ run: |
32
+ uv venv
33
+ uv pip install -e ".[dev]"
34
+
35
+ - name: Ruff lint
36
+ run: uv run ruff check .
37
+
38
+ - name: Ruff format check
39
+ run: uv run ruff format --check .
40
+
41
+ - name: Tests
42
+ run: uv run pytest -q
@@ -0,0 +1,60 @@
1
+ name: Release
2
+
3
+ # Cut a release by pushing a version tag:
4
+ # git tag v0.2.0 && git push origin v0.2.0
5
+ # This builds the package, publishes it to PyPI via Trusted Publishing (OIDC —
6
+ # no API token stored anywhere), and creates a GitHub Release with auto notes.
7
+ #
8
+ # One-time setup on PyPI (https://pypi.org/manage/account/publishing/): add a
9
+ # "pending publisher" for project `thymus-ai`, owner `UltronLabs`, repo `Thymus`,
10
+ # workflow `release.yml`. After the first successful publish it becomes a normal
11
+ # trusted publisher.
12
+ on:
13
+ push:
14
+ tags: ["v*"]
15
+
16
+ # Default to read (needed to check out a private repo); jobs opt into more.
17
+ permissions:
18
+ contents: read
19
+
20
+ jobs:
21
+ build:
22
+ runs-on: ubuntu-latest
23
+ steps:
24
+ - uses: actions/checkout@v5
25
+ - uses: astral-sh/setup-uv@v6
26
+ with:
27
+ python-version: "3.12"
28
+ - run: uv build
29
+ - uses: actions/upload-artifact@v4
30
+ with:
31
+ name: dist
32
+ path: dist/
33
+
34
+ publish-pypi:
35
+ needs: build
36
+ runs-on: ubuntu-latest
37
+ permissions:
38
+ id-token: write # OIDC token for PyPI Trusted Publishing
39
+ steps:
40
+ - uses: actions/download-artifact@v4
41
+ with:
42
+ name: dist
43
+ path: dist/
44
+ - uses: pypa/gh-action-pypi-publish@release/v1
45
+
46
+ github-release:
47
+ needs: publish-pypi
48
+ runs-on: ubuntu-latest
49
+ permissions:
50
+ contents: write # to create the GitHub Release
51
+ steps:
52
+ - uses: actions/checkout@v5
53
+ - uses: actions/download-artifact@v4
54
+ with:
55
+ name: dist
56
+ path: dist/
57
+ - name: Create GitHub Release
58
+ env:
59
+ GH_TOKEN: ${{ github.token }}
60
+ run: gh release create "${GITHUB_REF_NAME}" dist/* --generate-notes --verify-tag
@@ -0,0 +1,228 @@
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[codz]
4
+ *$py.class
5
+
6
+ # C extensions
7
+ *.so
8
+
9
+ # Distribution / packaging
10
+ .Python
11
+ build/
12
+ develop-eggs/
13
+ dist/
14
+ downloads/
15
+ eggs/
16
+ .eggs/
17
+ lib/
18
+ lib64/
19
+ parts/
20
+ sdist/
21
+ var/
22
+ wheels/
23
+ share/python-wheels/
24
+ *.egg-info/
25
+ .installed.cfg
26
+ *.egg
27
+ MANIFEST
28
+
29
+ # PyInstaller
30
+ # Usually these files are written by a python script from a template
31
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
32
+ *.manifest
33
+ *.spec
34
+
35
+ # Installer logs
36
+ pip-log.txt
37
+ pip-delete-this-directory.txt
38
+
39
+ # Unit test / coverage reports
40
+ htmlcov/
41
+ .tox/
42
+ .nox/
43
+ .coverage
44
+ .coverage.*
45
+ .cache
46
+ nosetests.xml
47
+ coverage.xml
48
+ *.cover
49
+ *.py.cover
50
+ .hypothesis/
51
+ .pytest_cache/
52
+ cover/
53
+
54
+ # Translations
55
+ *.mo
56
+ *.pot
57
+
58
+ # Django stuff:
59
+ *.log
60
+ local_settings.py
61
+ db.sqlite3
62
+ db.sqlite3-journal
63
+
64
+ # Flask stuff:
65
+ instance/
66
+ .webassets-cache
67
+
68
+ # Scrapy stuff:
69
+ .scrapy
70
+
71
+ # Sphinx documentation
72
+ docs/_build/
73
+
74
+ # PyBuilder
75
+ .pybuilder/
76
+ target/
77
+
78
+ # Jupyter Notebook
79
+ .ipynb_checkpoints
80
+
81
+ # IPython
82
+ profile_default/
83
+ ipython_config.py
84
+
85
+ # pyenv
86
+ # For a library or package, you might want to ignore these files since the code is
87
+ # intended to run in multiple environments; otherwise, check them in:
88
+ # .python-version
89
+
90
+ # pipenv
91
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
92
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
93
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
94
+ # install all needed dependencies.
95
+ # Pipfile.lock
96
+
97
+ # UV
98
+ # Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
99
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
100
+ # commonly ignored for libraries.
101
+ # uv.lock
102
+
103
+ # poetry
104
+ # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
105
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
106
+ # commonly ignored for libraries.
107
+ # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
108
+ # poetry.lock
109
+ # poetry.toml
110
+
111
+ # pdm
112
+ # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
113
+ # pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python.
114
+ # https://pdm-project.org/en/latest/usage/project/#working-with-version-control
115
+ # pdm.lock
116
+ # pdm.toml
117
+ .pdm-python
118
+ .pdm-build/
119
+
120
+ # pixi
121
+ # Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control.
122
+ # pixi.lock
123
+ # Pixi creates a virtual environment in the .pixi directory, just like venv module creates one
124
+ # in the .venv directory. It is recommended not to include this directory in version control.
125
+ .pixi
126
+
127
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
128
+ __pypackages__/
129
+
130
+ # Celery stuff
131
+ celerybeat-schedule
132
+ celerybeat.pid
133
+
134
+ # Redis
135
+ *.rdb
136
+ *.aof
137
+ *.pid
138
+
139
+ # RabbitMQ
140
+ mnesia/
141
+ rabbitmq/
142
+ rabbitmq-data/
143
+
144
+ # ActiveMQ
145
+ activemq-data/
146
+
147
+ # SageMath parsed files
148
+ *.sage.py
149
+
150
+ # Environments
151
+ .env
152
+ .envrc
153
+ .venv
154
+ env/
155
+ venv/
156
+ ENV/
157
+ env.bak/
158
+ venv.bak/
159
+
160
+ # Spyder project settings
161
+ .spyderproject
162
+ .spyproject
163
+
164
+ # Rope project settings
165
+ .ropeproject
166
+
167
+ # mkdocs documentation
168
+ /site
169
+
170
+ # mypy
171
+ .mypy_cache/
172
+ .dmypy.json
173
+ dmypy.json
174
+
175
+ # Pyre type checker
176
+ .pyre/
177
+
178
+ # pytype static type analyzer
179
+ .pytype/
180
+
181
+ # Cython debug symbols
182
+ cython_debug/
183
+
184
+ # PyCharm
185
+ # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
186
+ # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
187
+ # and can be added to the global gitignore or merged into this file. For a more nuclear
188
+ # option (not recommended) you can uncomment the following to ignore the entire idea folder.
189
+ # .idea/
190
+
191
+ # Abstra
192
+ # Abstra is an AI-powered process automation framework.
193
+ # Ignore directories containing user credentials, local state, and settings.
194
+ # Learn more at https://abstra.io/docs
195
+ .abstra/
196
+
197
+ # Visual Studio Code
198
+ # Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore
199
+ # that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
200
+ # and can be added to the global gitignore or merged into this file. However, if you prefer,
201
+ # you could uncomment the following to ignore the entire vscode folder
202
+ # .vscode/
203
+ # Temporary file for partial code execution
204
+ tempCodeRunnerFile.py
205
+
206
+ # Ruff stuff:
207
+ .ruff_cache/
208
+
209
+ # PyPI configuration file
210
+ .pypirc
211
+
212
+ # Marimo
213
+ marimo/_static/
214
+ marimo/_lsp/
215
+ __marimo__/
216
+
217
+ # Streamlit
218
+ .streamlit/secrets.toml
219
+
220
+ # thymus-bench generated output
221
+ results/
222
+ results_mem0/
223
+
224
+ # all benchmark output dirs
225
+ results*/
226
+
227
+ # library: do not pin the lockfile
228
+ uv.lock
@@ -0,0 +1,23 @@
1
+ # Pre-commit hooks — run `uv run pre-commit install` once after cloning.
2
+ # On every commit: ruff lints (auto-fixing what it safely can) and formats the
3
+ # staged Python files. A commit is blocked if anything can't be auto-fixed.
4
+ #
5
+ # ruff pinned to match the version in pyproject's dev extra (keep them in sync).
6
+ repos:
7
+ - repo: https://github.com/astral-sh/ruff-pre-commit
8
+ rev: v0.15.20
9
+ hooks:
10
+ - id: ruff-check
11
+ args: [--fix]
12
+ - id: ruff-format
13
+
14
+ # Small, universal hygiene checks (no Python-code reformatting).
15
+ - repo: https://github.com/pre-commit/pre-commit-hooks
16
+ rev: v6.0.0
17
+ hooks:
18
+ - id: trailing-whitespace
19
+ - id: end-of-file-fixer
20
+ - id: check-yaml
21
+ - id: check-toml
22
+ - id: check-merge-conflict
23
+ - id: check-added-large-files
@@ -0,0 +1,170 @@
1
+ # CLAUDE.md — repo map & conventions
2
+
3
+ Orientation for anyone (human or AI) working in this repo. Read this first so you
4
+ don't have to re-derive the structure every session.
5
+
6
+ ## What this is
7
+
8
+ **Thymus** — a trust & hygiene layer ("immune system") for AI agent memory. It
9
+ screens every memory on the **write path** (provenance + injection + exfil
10
+ detection → trust score → **admit / tag / quarantine**) so poisoned memories never
11
+ reach the store (mem0, Zep, Letta, …). Targets OWASP Agentic Top-10 **ASI06**
12
+ (Memory & Context Poisoning).
13
+
14
+ Two things live here: **`thymus/`** = the product (the firewall library), and
15
+ **`thymus_bench/`** = the poisoning benchmark that proves it. On the benchmark,
16
+ Thymus takes attack-success from **100% → 0%** on live mem0 with **0%** false
17
+ positives.
18
+
19
+ ## Conventions (important)
20
+
21
+ - **Python env: use `uv`** — `uv venv`, `uv pip install`, `uv run python ...`. Not
22
+ pip/venv (system Python is Homebrew/PEP-668). Deps: `uv pip install mem0ai pillow`.
23
+ - **Lint + format: `ruff`** (dev dep; config in `pyproject.toml`). `uv run ruff check .`
24
+ and `uv run ruff format .` before committing. Note: detectors auto-register on
25
+ import, so before deleting any "unused" `import thymus` verify the file keeps a
26
+ `from thymus import …` (that runs `thymus/__init__.py` and does the registration).
27
+ - **Git commits: no `Co-Authored-By` / AI-attribution trailer.** Plain messages.
28
+ - **mem0 key** lives in `.env` (gitignored) as `MEM0_API_KEY=m0-...`. It's a dummy
29
+ account — safe to experiment. Load it into the shell before mem0 runs.
30
+ - **Generated output** (`results*/`, `.venv/`, `__pycache__/`) is gitignored.
31
+
32
+ ## How to run
33
+
34
+ ```bash
35
+ uv run python run_baseline.py # benchmark, in-memory, no keys
36
+ uv run python run_baseline.py --guard thymus # with the firewall
37
+ export MEM0_API_KEY=m0-... # (or source .env)
38
+ uv run python run_baseline.py --backend mem0 --guard thymus # vs live mem0
39
+ uv run python tests/test_thymus_engine.py # Phase 1 acceptance
40
+ uv run python demo/poison_demo.py --user acme-support-agent # live attack demo
41
+ ```
42
+
43
+ ## Directory hierarchy
44
+
45
+ ```
46
+ Thymus/
47
+ ├── CLAUDE.md # this file
48
+ ├── README.md # public overview + benchmark results + demo gif
49
+ ├── Thymus_Product_Roadmap.md # full phased plan (Phases 0–5)
50
+ ├── Thymus_Phase0_Schemas.md # MemoryEnvelope + TrustPolicy JSON schemas + bench spec
51
+ ├── requirements.txt # notes on optional mem0 install (stdlib-only core)
52
+ ├── run_baseline.py # benchmark CLI entry point (--backend/--guard/--out/--verbose)
53
+ ├── .env # local mem0 key (gitignored)
54
+
55
+ ├── thymus/ # ★ THE PRODUCT — the write-path firewall library
56
+ │ ├── README.md # package docs + how to extend (detectors/adapters)
57
+ │ ├── __init__.py # public API: screen(), wrap(), types, engine
58
+ │ ├── types.py # Candidate, Signal, Assessment, Verdict, enums (the vocabulary)
59
+ │ ├── engine.py # ScreeningEngine.screen / screen_read (runs detectors + policy + ledger)
60
+ │ ├── policy.py # TrustPolicy: base trust per tier − detector deltas → verdict + severity floor
61
+ │ ├── feedback.py # [P2] TrustLedger: review outcomes (mark_safe/release/delete) adjust origin trust
62
+ │ ├── detectors/ # ── EXTENSION POINT 1: pluggable detection ──
63
+ │ │ ├── __init__.py # registry + auto-registers built-ins; DEFAULT_DETECTORS
64
+ │ │ ├── base.py # Detector protocol (inspect(candidate, context)) + registry
65
+ │ │ ├── origin.py # provenance detector → 'untrusted_origin' flag
66
+ │ │ ├── injection.py # ★ precision-critical: override + sensitive-action + third-party
67
+ │ │ │ # scope, minus self-reference (catches MINJA, passes "call me Sam")
68
+ │ │ ├── egress.py # exfil detector: send-verb + external email/URL
69
+ │ │ └── conflict.py # [P2] fact-conflict: contradicts an existing high-trust memory
70
+ │ ├── rules/ # ── PACKAGE B: the declarative rule library (the moat) ──
71
+ │ │ ├── __init__.py # registers the `rules` detector into DEFAULT_DETECTORS
72
+ │ │ ├── loader.py # Rule + RuleDetector; co-occurrence matching (all_of/any_of, re:)
73
+ │ │ └── packs/*.json # 14 curated packs / 32 rules: financial, exfiltration, auth_bypass,
74
+ │ │ │ # safety_suppression, manipulation, secrets_pii, privilege_escalation,
75
+ │ │ │ # tool_abuse, persistence, impersonation, obfuscation,
76
+ │ │ │ # prompt_extraction, policy_override, ops_redirect
77
+ │ └── adapters/ # ── EXTENSION POINT 2: framework bindings ──
78
+ │ ├── __init__.py # re-exports MemoryAdapter, ProtectedMemory, wrap, GenericAdapter, ...
79
+ │ ├── base.py # MemoryAdapter ABC + ProtectedMemory (write screen + [P2] read screen) + wrap()
80
+ │ ├── mem0.py # Mem0Adapter (hosted MemoryClient + OSS Memory). New framework = copy this.
81
+ │ ├── generic.py # [P2] DictStore + GenericAdapter — dependency-free, fully testable
82
+ │ └── zep.py # [P2] Zep Cloud adapter (LIVE): thread.add_messages write, graph.search read
83
+ │ └── remote.py # [P3] HttpAuditSink (→ console; non-blocking bg worker, sync block_on_quarantine) +
84
+ │ # remote_engine (console-tuned thresholds/trust/detectors + custom rules)
85
+
86
+ ├── thymus_bench/ # ★ THE BENCHMARK — measures poisoning resistance
87
+ │ ├── __init__.py
88
+ │ ├── runner.py # plant corpus → wait for indexing → screen → fire triggers → metrics
89
+ │ │ # (content-based detection; guard swap = baseline vs protected)
90
+ │ ├── metrics.py # ASR / IAR / RCR / FPR / HN-FPR definitions
91
+ │ ├── report.py # console table + JSON + shareable Markdown ("mem0 raw vs +Thymus")
92
+ │ ├── rule_report.py # [Pkg B] per-rule precision report: attack coverage + per-rule FP rate
93
+ │ ├── backends/ # memory stores under test
94
+ │ │ ├── base.py # MemoryBackend protocol (add/search/get_all/reset) + Memory dataclass
95
+ │ │ ├── inmemory.py # zero-dep store mimicking mem0 semantics (token-overlap retrieval)
96
+ │ │ └── mem0_backend.py # real mem0 (hosted MemoryClient/OSS); async wait_ready, v2 search, namespacing
97
+ │ ├── guards/ # write-path guards the benchmark swaps between
98
+ │ │ ├── base.py # Guard protocol + benchmark-local Candidate/Assessment/Verdict
99
+ │ │ ├── null_guard.py # BASELINE: admits everything (the stock store)
100
+ │ │ └── thymus_guard.py # bridges the benchmark to the real thymus.ScreeningEngine
101
+ │ └── corpus/ # labeled test data
102
+ │ ├── minja_attacks.json # 8 query-only injection attacks (poison + trigger query + keywords)
103
+ │ ├── benign_facts.json # 12 safe memories (the false-positive denominator)
104
+ │ ├── hard_negatives.json # 6 legit imperatives ("always call me Sam") — must NOT be blocked
105
+ │ └── conflict_cases.json # [P2] labeled contradiction/compatible pairs for conflict precision/recall
106
+
107
+ ├── tests/
108
+ │ ├── test_thymus_engine.py # Phase 1 acceptance: attacks blocked, benign+hard-neg admitted, wrap() blocks
109
+ │ ├── test_conflict.py # [P2] fact-conflict: contradiction flagged, compatible fact admitted
110
+ │ ├── test_conflict_precision.py# [P2] conflict precision/recall on conflict_cases.json (100%/100%)
111
+ │ ├── test_read_path.py # [P2] read-path: 8/8 pre-seeded poisons contained at retrieval (retroactive)
112
+ │ ├── test_feedback.py # [P2] trust ledger: mark_safe cuts repeat FPs; delete lowers origin trust
113
+ │ ├── test_rules.py # [Pkg B] packs load; every attack hits a rule; 0 rule false positives
114
+ │ ├── test_zep.py # [P2] LIVE Zep integration (skips w/o ZEP_API_KEY): poison blocked before Zep
115
+ │ ├── test_console_roundtrip.py # [P3] LIVE blocking round-trip vs a running thymus-console (skips if unreachable)
116
+ │ ├── test_remote_policy.py # [P3] console-edited policy (thresholds/trust/custom rules) changes the SDK engine — unit + LIVE
117
+ │ └── test_guard_swap.py # harness sanity: a demo guard drops ASR without false positives
118
+
119
+ └── demo/ # launch/marketing assets
120
+ ├── README.md # how to run live, record, and regenerate
121
+ ├── poison_demo.py # 3-beat live attack vs real mem0 (--user, --auto, --keep); prints dashboard cue
122
+ ├── poison_demo.tape # VHS script to render the terminal video headlessly
123
+ ├── poison_demo.mp4/.gif # terminal-only recording
124
+ └── poison_demo_with_dashboard.mp4/.gif # terminal + real mem0 dashboard proof (embedded in README)
125
+ ```
126
+
127
+ ## The core flow (how a decision is made)
128
+
129
+ ```
130
+ Candidate ─▶ [ detectors ] ─▶ signals ─▶ [ policy ] ─▶ Assessment
131
+ origin/injection/egress base trust(tier) verdict:
132
+ (each emits Signal: − Σ trust_delta admit / tag /
133
+ flag + trust_delta) → thresholds + floor quarantine
134
+ ```
135
+
136
+ - **admit** = store clean · **tag** = store but flagged/down-weighted · **quarantine** = never stored, held for review.
137
+ - Verdict combination is most-restrictive-wins. Policy is tier-aware (untrusted origin lowers base trust) with a severity floor (a critical finding from an attacker-reachable origin is never silently admitted).
138
+
139
+ ## Extending it
140
+
141
+ - **New detector**: `@thymus.detectors.register` a class with `name` + `inspect(candidate)->list[Signal]`. No core change.
142
+ - **New framework** (Zep/Letta/LangMem): subclass `thymus.adapters.base.MemoryAdapter`, implement `store_add` / `store_search`. Nothing else changes.
143
+
144
+ ## Status
145
+
146
+ - **Phase 0** (schemas + benchmark) — done. See `Thymus_Phase0_Schemas.md`.
147
+ - **Phase 1** (write-path firewall) — done. `thymus/` package; 100%→0% ASR on live mem0.
148
+ - **Phase 2** (read-path + depth) — done (except access-blocked adapters). Read-path re-screening
149
+ (retroactive protection, 8/8 containment), fact-conflict detector (100%/100% precision/recall on
150
+ conflict_cases), feedback loop (TrustLedger), generic adapter. Detector contract carries `ScreenContext`.
151
+ Zep adapter is LIVE + integration-tested (`test_zep.py`). DEFERRED: Letta adapter (no account).
152
+ - **Package B** (rule library / the moat) — Declarative JSON rule packs + `RuleDetector`
153
+ (`thymus/rules/`), **32 rules across 14 packs** (financial, exfiltration, auth_bypass, safety_suppression,
154
+ manipulation, secrets_pii, privilege_escalation, tool_abuse, persistence, impersonation, obfuscation,
155
+ prompt_extraction, policy_override, ops_redirect), per-rule precision report (`thymus_bench/rule_report.py`):
156
+ 18-attack corpus, 100% attack coverage, 100% precision per rule (only the fuzzy `injection` code detector
157
+ carries FPs, by design). Ongoing track: keep growing packs + corpus.
158
+ - **Phase 3** (hosted console) — essentially done, in the separate `UltronLabs/thymus-console` repo
159
+ (Next.js 16 + Prisma 7 + Clerk auth/orgs). Done: dashboard/quarantine/audit/evidence pages, real
160
+ per-tenant data isolation (Clerk org or personal user id), per-tenant API keys, realtime SSE
161
+ streaming, the blocking approval round-trip (`thymus.remote.HttpAuditSink(block_on_quarantine=True)`
162
+ + console `GET /api/decisions/:id/status`, tested live via `test_console_roundtrip.py`), and policy
163
+ tuning — the FULL policy editor: quarantine/tag thresholds, per-tier base trust, floor severity,
164
+ detector on/off, per-built-in-rule on/off, and **custom rule authoring** (same `all_of` co-occurrence
165
+ format as the packs), with a draft→publish→numbered-version model and one-click rollback. Edited in
166
+ Settings, served to the SDK via `thymus.remote.remote_engine()`, which builds the `TrustPolicy` +
167
+ a `RuleDetector` (built-ins minus disabled + custom rules); tested via `test_remote_policy.py`
168
+ (unit + live). Remaining: Clerk production instance, webhook registration (needs a public URL),
169
+ the actual Railway deploy.
170
+ - **Next**: deploy `thymus-console` (Railway) for real launch, or start the launch/validation track.