omind 10.3.4__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 (207) hide show
  1. omind-10.3.4/.githooks/commit-msg +9 -0
  2. omind-10.3.4/.github/codeql/codeql-config.yml +9 -0
  3. omind-10.3.4/.github/dependabot.yml +21 -0
  4. omind-10.3.4/.github/workflows/codeql.yml +35 -0
  5. omind-10.3.4/.github/workflows/publish.yml +80 -0
  6. omind-10.3.4/.github/workflows/test.yml +246 -0
  7. omind-10.3.4/.gitignore +22 -0
  8. omind-10.3.4/.gitleaks.toml +19 -0
  9. omind-10.3.4/.woodpecker.yml +14 -0
  10. omind-10.3.4/AGENTS.md +156 -0
  11. omind-10.3.4/BACKLOG.md +957 -0
  12. omind-10.3.4/CHANGELOG.md +4826 -0
  13. omind-10.3.4/CONTRIBUTING.md +171 -0
  14. omind-10.3.4/LICENSE +201 -0
  15. omind-10.3.4/LessonsLearned.md +308 -0
  16. omind-10.3.4/PKG-INFO +794 -0
  17. omind-10.3.4/README.md +742 -0
  18. omind-10.3.4/SECURITY.md +33 -0
  19. omind-10.3.4/conformance.toml +18 -0
  20. omind-10.3.4/docs/audit.md +120 -0
  21. omind-10.3.4/docs/conveyor-factory.md +120 -0
  22. omind-10.3.4/docs/design/2026-08-27-roadmap-consensus.md +84 -0
  23. omind-10.3.4/docs/graph-demo/README.md +33 -0
  24. omind-10.3.4/docs/graph-demo/make_demo_vault.py +45 -0
  25. omind-10.3.4/docs/graph-demo/render_graph.py +71 -0
  26. omind-10.3.4/docs/graph.png +0 -0
  27. omind-10.3.4/docs/install-verification.md +211 -0
  28. omind-10.3.4/docs/manual-setup.md +155 -0
  29. omind-10.3.4/docs/mesh-ops.md +111 -0
  30. omind-10.3.4/docs/mesh.md +288 -0
  31. omind-10.3.4/docs/needle.md +94 -0
  32. omind-10.3.4/docs/retrieval.md +349 -0
  33. omind-10.3.4/docs/reviews/2026-08-27-multi-agent-review.md +298 -0
  34. omind-10.3.4/docs/screenshot.png +0 -0
  35. omind-10.3.4/docs/self-update.md +92 -0
  36. omind-10.3.4/docs/serve.md +112 -0
  37. omind-10.3.4/docs/troubleshooting.md +316 -0
  38. omind-10.3.4/e2e/README.md +105 -0
  39. omind-10.3.4/e2e/__init__.py +3 -0
  40. omind-10.3.4/e2e/conftest.py +57 -0
  41. omind-10.3.4/e2e/nodes.py +164 -0
  42. omind-10.3.4/e2e/providers.py +275 -0
  43. omind-10.3.4/e2e/sweep.py +34 -0
  44. omind-10.3.4/e2e/test_bootstrap.py +28 -0
  45. omind-10.3.4/e2e/test_mesh_sync.py +78 -0
  46. omind-10.3.4/e2e/test_provider_smoke.py +15 -0
  47. omind-10.3.4/extras/README.md +35 -0
  48. omind-10.3.4/extras/omi_enforce.py +139 -0
  49. omind-10.3.4/extras/omi_write.py +106 -0
  50. omind-10.3.4/pyproject.toml +144 -0
  51. omind-10.3.4/scripts/bootstrap.sh +190 -0
  52. omind-10.3.4/scripts/check-attribution.sh +83 -0
  53. omind-10.3.4/scripts/stress_append_lock.py +69 -0
  54. omind-10.3.4/scripts/test.sh +22 -0
  55. omind-10.3.4/src/omind/__init__.py +5 -0
  56. omind-10.3.4/src/omind/__main__.py +8 -0
  57. omind-10.3.4/src/omind/_omi_enforce.py +139 -0
  58. omind-10.3.4/src/omind/access.py +226 -0
  59. omind-10.3.4/src/omind/adapters.py +364 -0
  60. omind-10.3.4/src/omind/agents.py +3895 -0
  61. omind-10.3.4/src/omind/ai_usage.py +790 -0
  62. omind-10.3.4/src/omind/audit.py +553 -0
  63. omind-10.3.4/src/omind/backup.py +576 -0
  64. omind-10.3.4/src/omind/bench.py +717 -0
  65. omind-10.3.4/src/omind/checkpoint.py +367 -0
  66. omind-10.3.4/src/omind/cli.py +2015 -0
  67. omind-10.3.4/src/omind/clock.py +64 -0
  68. omind-10.3.4/src/omind/compliance.py +393 -0
  69. omind-10.3.4/src/omind/consolidate.py +277 -0
  70. omind-10.3.4/src/omind/corpus.py +88 -0
  71. omind-10.3.4/src/omind/deadline.py +145 -0
  72. omind-10.3.4/src/omind/embed.py +209 -0
  73. omind-10.3.4/src/omind/entities.py +479 -0
  74. omind-10.3.4/src/omind/filelock.py +206 -0
  75. omind-10.3.4/src/omind/fleet-sudo.sh +37 -0
  76. omind-10.3.4/src/omind/git-fresh-base.sh +87 -0
  77. omind-10.3.4/src/omind/graph.py +391 -0
  78. omind-10.3.4/src/omind/guard.py +6098 -0
  79. omind-10.3.4/src/omind/harness.py +808 -0
  80. omind-10.3.4/src/omind/help_system.py +65 -0
  81. omind-10.3.4/src/omind/hooks.py +1037 -0
  82. omind-10.3.4/src/omind/journal.py +364 -0
  83. omind-10.3.4/src/omind/learn.py +166 -0
  84. omind-10.3.4/src/omind/lint.py +337 -0
  85. omind-10.3.4/src/omind/loopguard.py +244 -0
  86. omind-10.3.4/src/omind/maintain.py +192 -0
  87. omind-10.3.4/src/omind/merge.py +461 -0
  88. omind-10.3.4/src/omind/mesh.py +1209 -0
  89. omind-10.3.4/src/omind/model_http.py +89 -0
  90. omind-10.3.4/src/omind/namehints.py +729 -0
  91. omind-10.3.4/src/omind/needle.py +344 -0
  92. omind-10.3.4/src/omind/notes.py +80 -0
  93. omind-10.3.4/src/omind/okf.py +152 -0
  94. omind-10.3.4/src/omind/omi-gate-reset.sh +52 -0
  95. omind-10.3.4/src/omind/omi-guard-hermes.sh +98 -0
  96. omind-10.3.4/src/omind/omi-guard.dsh.js +390 -0
  97. omind-10.3.4/src/omind/omi-guard.opencode.js +56 -0
  98. omind-10.3.4/src/omind/omi-guard.sh +239 -0
  99. omind-10.3.4/src/omind/paths.py +137 -0
  100. omind-10.3.4/src/omind/policy.py +955 -0
  101. omind-10.3.4/src/omind/proc.py +88 -0
  102. omind-10.3.4/src/omind/provision.py +2764 -0
  103. omind-10.3.4/src/omind/quickstart.py +530 -0
  104. omind-10.3.4/src/omind/recall.py +166 -0
  105. omind-10.3.4/src/omind/retrieve.py +500 -0
  106. omind-10.3.4/src/omind/rules.py +1131 -0
  107. omind-10.3.4/src/omind/scope_guard.py +73 -0
  108. omind-10.3.4/src/omind/searchindex.py +2064 -0
  109. omind-10.3.4/src/omind/secret-output-guard.sh +138 -0
  110. omind-10.3.4/src/omind/seeds.py +405 -0
  111. omind-10.3.4/src/omind/server.py +743 -0
  112. omind-10.3.4/src/omind/skills/omind/SKILL.md +37 -0
  113. omind-10.3.4/src/omind/skills/omind/agents/openai.yaml +4 -0
  114. omind-10.3.4/src/omind/store.py +1835 -0
  115. omind-10.3.4/src/omind/timeline.py +323 -0
  116. omind-10.3.4/src/omind/transfer.py +347 -0
  117. omind-10.3.4/src/omind/txn.py +429 -0
  118. omind-10.3.4/src/omind/unwritten.py +129 -0
  119. omind-10.3.4/src/omind/update.py +728 -0
  120. omind-10.3.4/src/omind/verify.py +779 -0
  121. omind-10.3.4/src/omind/web/__init__.py +3 -0
  122. omind-10.3.4/src/omind/web/app.py +255 -0
  123. omind-10.3.4/src/omind/web/static/app.css +841 -0
  124. omind-10.3.4/src/omind/web/static/app.js +1062 -0
  125. omind-10.3.4/src/omind/web/static/graph.js +336 -0
  126. omind-10.3.4/src/omind/web/static/index.html +91 -0
  127. omind-10.3.4/src/omind/web/static/vendor/fonts/bricolagegrotesque-1c7e673e77.woff2 +0 -0
  128. omind-10.3.4/src/omind/web/static/vendor/fonts/bricolagegrotesque-40c2cb34af.woff2 +0 -0
  129. omind-10.3.4/src/omind/web/static/vendor/fonts/bricolagegrotesque-fdb6b064da.woff2 +0 -0
  130. omind-10.3.4/src/omind/web/static/vendor/fonts/jetbrainsmono-028edbf560.woff2 +0 -0
  131. omind-10.3.4/src/omind/web/static/vendor/fonts/jetbrainsmono-0a7197f9e2.woff2 +0 -0
  132. omind-10.3.4/src/omind/web/static/vendor/fonts/jetbrainsmono-acf87d8659.woff2 +0 -0
  133. omind-10.3.4/src/omind/web/static/vendor/fonts/jetbrainsmono-c8b23d7bdf.woff2 +0 -0
  134. omind-10.3.4/src/omind/web/static/vendor/fonts/jetbrainsmono-d2761cb6ca.woff2 +0 -0
  135. omind-10.3.4/src/omind/web/static/vendor/fonts/jetbrainsmono-db1e206703.woff2 +0 -0
  136. omind-10.3.4/src/omind/web/static/vendor/fonts/newsreader-1c520e8540.woff2 +0 -0
  137. omind-10.3.4/src/omind/web/static/vendor/fonts/newsreader-2b5209ccd5.woff2 +0 -0
  138. omind-10.3.4/src/omind/web/static/vendor/fonts/newsreader-34eec9781a.woff2 +0 -0
  139. omind-10.3.4/src/omind/web/static/vendor/fonts/newsreader-72c495d39d.woff2 +0 -0
  140. omind-10.3.4/src/omind/web/static/vendor/fonts/newsreader-a6a2a4bf8d.woff2 +0 -0
  141. omind-10.3.4/src/omind/web/static/vendor/fonts/newsreader-f24c321523.woff2 +0 -0
  142. omind-10.3.4/src/omind/web/static/vendor/fonts.css +251 -0
  143. omind-10.3.4/src/omind/web/static/vendor/marked.min.js +69 -0
  144. omind-10.3.4/src/omind/web/static/vendor/purify.min.js +3 -0
  145. omind-10.3.4/src/omind/web/static/vendor/tailwind.css +2 -0
  146. omind-10.3.4/src/omind/web/tailwind/input.css +5 -0
  147. omind-10.3.4/src/omind/web/tailwind/tailwind.config.js +30 -0
  148. omind-10.3.4/src/omind/writecontext.py +463 -0
  149. omind-10.3.4/tests/conftest.py +259 -0
  150. omind-10.3.4/tests/test_access.py +106 -0
  151. omind-10.3.4/tests/test_adapters.py +803 -0
  152. omind-10.3.4/tests/test_agent_identity.py +75 -0
  153. omind-10.3.4/tests/test_agents.py +2203 -0
  154. omind-10.3.4/tests/test_ai_usage.py +368 -0
  155. omind-10.3.4/tests/test_audit.py +194 -0
  156. omind-10.3.4/tests/test_backup.py +453 -0
  157. omind-10.3.4/tests/test_bench.py +126 -0
  158. omind-10.3.4/tests/test_checkpoint.py +181 -0
  159. omind-10.3.4/tests/test_cli.py +317 -0
  160. omind-10.3.4/tests/test_cli_integration.py +323 -0
  161. omind-10.3.4/tests/test_clock.py +42 -0
  162. omind-10.3.4/tests/test_compliance.py +247 -0
  163. omind-10.3.4/tests/test_consolidate.py +113 -0
  164. omind-10.3.4/tests/test_corpus.py +65 -0
  165. omind-10.3.4/tests/test_embed.py +77 -0
  166. omind-10.3.4/tests/test_entities.py +397 -0
  167. omind-10.3.4/tests/test_filelock.py +214 -0
  168. omind-10.3.4/tests/test_graph.py +220 -0
  169. omind-10.3.4/tests/test_grok_client.py +336 -0
  170. omind-10.3.4/tests/test_guard.py +6251 -0
  171. omind-10.3.4/tests/test_harness.py +402 -0
  172. omind-10.3.4/tests/test_hook_shell_safety.py +149 -0
  173. omind-10.3.4/tests/test_hooks.py +992 -0
  174. omind-10.3.4/tests/test_journal.py +265 -0
  175. omind-10.3.4/tests/test_learn.py +94 -0
  176. omind-10.3.4/tests/test_lint.py +216 -0
  177. omind-10.3.4/tests/test_loopguard.py +140 -0
  178. omind-10.3.4/tests/test_maintain.py +127 -0
  179. omind-10.3.4/tests/test_merge.py +444 -0
  180. omind-10.3.4/tests/test_mesh.py +655 -0
  181. omind-10.3.4/tests/test_model_http.py +138 -0
  182. omind-10.3.4/tests/test_name_hints.py +495 -0
  183. omind-10.3.4/tests/test_name_timelines.py +729 -0
  184. omind-10.3.4/tests/test_needle.py +147 -0
  185. omind-10.3.4/tests/test_okf.py +188 -0
  186. omind-10.3.4/tests/test_policy.py +269 -0
  187. omind-10.3.4/tests/test_proc.py +78 -0
  188. omind-10.3.4/tests/test_provision.py +3005 -0
  189. omind-10.3.4/tests/test_quickstart.py +219 -0
  190. omind-10.3.4/tests/test_rare_term_preflight.py +138 -0
  191. omind-10.3.4/tests/test_retrieve.py +292 -0
  192. omind-10.3.4/tests/test_rules.py +1851 -0
  193. omind-10.3.4/tests/test_scope.py +78 -0
  194. omind-10.3.4/tests/test_scope_guard.py +49 -0
  195. omind-10.3.4/tests/test_searchindex.py +637 -0
  196. omind-10.3.4/tests/test_secret_output_guard.py +183 -0
  197. omind-10.3.4/tests/test_server.py +704 -0
  198. omind-10.3.4/tests/test_store.py +1117 -0
  199. omind-10.3.4/tests/test_transfer.py +258 -0
  200. omind-10.3.4/tests/test_txn.py +347 -0
  201. omind-10.3.4/tests/test_unwritten.py +76 -0
  202. omind-10.3.4/tests/test_update.py +520 -0
  203. omind-10.3.4/tests/test_verify.py +1184 -0
  204. omind-10.3.4/tests/test_web.py +306 -0
  205. omind-10.3.4/tests/test_windows_hook_shells.py +397 -0
  206. omind-10.3.4/tests/test_write_context.py +302 -0
  207. omind-10.3.4/uv.lock +4479 -0
@@ -0,0 +1,9 @@
1
+ #!/bin/sh
2
+ # SPDX-License-Identifier: Apache-2.0
3
+ # Copyright 2026 Aaron K. Clark
4
+ #
5
+ # Reject a commit that declares no authorship. Enable with:
6
+ # git config core.hooksPath .githooks
7
+ set -eu
8
+ root=$(git rev-parse --show-toplevel)
9
+ exec "$root/scripts/check-attribution.sh" --message-file "$1"
@@ -0,0 +1,9 @@
1
+ name: "omind CodeQL config"
2
+
3
+ # SAST targets the shipped package only. Test files contain deliberate edge-case
4
+ # patterns that generate noise; analyzing src/ keeps findings actionable.
5
+ paths:
6
+ - src
7
+
8
+ paths-ignore:
9
+ - tests
@@ -0,0 +1,21 @@
1
+ version: 2
2
+ updates:
3
+ # Python dependencies (pyproject.toml). omind's CI installs with pip.
4
+ - package-ecosystem: "pip"
5
+ directory: "/"
6
+ schedule:
7
+ interval: "weekly"
8
+ open-pull-requests-limit: 5
9
+ groups:
10
+ python-deps:
11
+ patterns: ["*"]
12
+
13
+ # Keep the SHA-pinned GitHub Actions current.
14
+ - package-ecosystem: "github-actions"
15
+ directory: "/"
16
+ schedule:
17
+ interval: "weekly"
18
+ open-pull-requests-limit: 5
19
+ groups:
20
+ github-actions:
21
+ patterns: ["*"]
@@ -0,0 +1,35 @@
1
+ name: CodeQL
2
+
3
+ # Semantic static analysis (SAST) for the Python source. Runs on pushes/PRs to
4
+ # main and weekly, so new code paths and newly-disclosed query packs are caught.
5
+ on:
6
+ push:
7
+ branches: [main]
8
+ pull_request:
9
+ branches: [main]
10
+ schedule:
11
+ - cron: "0 6 * * 1" # Mondays 06:00 UTC
12
+ workflow_dispatch:
13
+
14
+ permissions:
15
+ contents: read
16
+
17
+ jobs:
18
+ analyze:
19
+ name: Analyze (python)
20
+ runs-on: ubuntu-latest
21
+ permissions:
22
+ security-events: write
23
+ contents: read
24
+ steps:
25
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
26
+ - name: Initialize CodeQL
27
+ uses: github/codeql-action/init@9b3254085494b55a0f7c4c2b3d2d52cc712ce370 # v4.39.1
28
+ with:
29
+ languages: python
30
+ queries: security-and-quality
31
+ config-file: ./.github/codeql/codeql-config.yml
32
+ - name: Perform CodeQL analysis
33
+ uses: github/codeql-action/analyze@9b3254085494b55a0f7c4c2b3d2d52cc712ce370 # v4.39.1
34
+ with:
35
+ category: "/language:python"
@@ -0,0 +1,80 @@
1
+ name: publish
2
+ # Uploads omind to PyPI on every published GitHub release (#267).
3
+ #
4
+ # Auth: a PyPI API token stored as the `PYPI_API_TOKEN` secret of the `pypi`
5
+ # environment (Settings -> Environments -> pypi). Only the publish job runs in
6
+ # that environment, so only it can read the token. Rotate the token on pypi.org
7
+ # and re-set the secret; nothing else references it.
8
+ on:
9
+ release:
10
+ types: [published]
11
+ workflow_dispatch:
12
+ inputs:
13
+ dry_run:
14
+ description: Build and verify only; do not upload
15
+ type: boolean
16
+ default: true
17
+
18
+ # Least privilege: read-only everywhere; the token is scoped to the `pypi`
19
+ # environment, which only the publish job enters.
20
+ permissions:
21
+ contents: read
22
+
23
+ concurrency:
24
+ group: publish-${{ github.ref }}
25
+ cancel-in-progress: false
26
+
27
+ jobs:
28
+ build:
29
+ name: Build sdist + wheel
30
+ runs-on: ubuntu-latest
31
+ steps:
32
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
33
+ - uses: actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0 # v7.1.0
34
+ with:
35
+ python-version: '3.12'
36
+ - uses: astral-sh/setup-uv@07a047e608db84b3d8c06cd9a7c7dcc9c355c18e # v10.3.2
37
+ - name: A release tag must match the packaged version
38
+ if: github.event_name == 'release'
39
+ env:
40
+ TAG: ${{ github.event.release.tag_name }}
41
+ run: |
42
+ version="$(python - <<'PY'
43
+ import tomllib
44
+ print(tomllib.load(open("pyproject.toml", "rb"))["project"]["version"])
45
+ PY
46
+ )"
47
+ if [ "v$version" != "$TAG" ]; then
48
+ echo "::error::release tag $TAG does not match pyproject version $version"
49
+ exit 1
50
+ fi
51
+ # uv build: the same command test.yml's wheel job runs on every PR, so
52
+ # the build path that publishes is the one CI exercises.
53
+ - run: uv build
54
+ - name: Metadata renders on PyPI
55
+ run: uvx twine check --strict dist/*
56
+ - name: Hand the artifacts to the publish job
57
+ uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
58
+ with:
59
+ name: dist
60
+ path: dist/
61
+ if-no-files-found: error
62
+
63
+ publish:
64
+ name: Upload to PyPI
65
+ needs: build
66
+ if: github.event_name == 'release' || inputs.dry_run == false
67
+ runs-on: ubuntu-latest
68
+ environment:
69
+ name: pypi
70
+ url: https://pypi.org/project/omind/
71
+ steps:
72
+ - uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
73
+ with:
74
+ name: dist
75
+ path: dist/
76
+ - uses: pypa/gh-action-pypi-publish@7245906fb61fa33a13554f9d5fb856fe61758086 # v1.14.3
77
+ with:
78
+ password: ${{ secrets.PYPI_API_TOKEN }}
79
+ # Attestations need trusted publishing (OIDC); token uploads skip them.
80
+ attestations: false
@@ -0,0 +1,246 @@
1
+ name: ci
2
+ on:
3
+ pull_request:
4
+ push:
5
+ branches: [main]
6
+
7
+ # Least privilege: jobs only read the repo.
8
+ permissions:
9
+ contents: read
10
+
11
+ # Cancel superseded runs on the same ref.
12
+ concurrency:
13
+ group: ci-${{ github.workflow }}-${{ github.ref }}
14
+ cancel-in-progress: true
15
+
16
+ jobs:
17
+ test:
18
+ runs-on: ${{ matrix.os }}
19
+ strategy:
20
+ fail-fast: false
21
+ matrix:
22
+ os: [ubuntu-latest]
23
+ python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
24
+ # Windows and macOS are supported deploy platforms (filelock shim /
25
+ # .cmd-shim resolution on Windows; BSD userland, case-insensitive FS and
26
+ # the ~/.local/bin PATH behavior on macOS). Exercise the oldest and
27
+ # newest Python on each so platform-specific breakage can't ship green.
28
+ include:
29
+ - os: windows-latest
30
+ python-version: "3.10"
31
+ - os: windows-latest
32
+ python-version: "3.14"
33
+ - os: macos-latest
34
+ python-version: "3.10"
35
+ - os: macos-latest
36
+ python-version: "3.14"
37
+ steps:
38
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
39
+ - uses: actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0 # v7.1.0
40
+ with:
41
+ python-version: ${{ matrix.python-version }}
42
+ # setuptools too: the windows-latest Python 3.10 toolcache bundles a
43
+ # vulnerable 65.5.0 that pip-audit (rightly) flags.
44
+ - run: python -m pip install -U pip setuptools
45
+ - run: pip install -e .[dev]
46
+ - run: ruff check .
47
+ - run: mypy src
48
+ # filelock is not an omind dependency — pip-audit pulls it for its own
49
+ # cachecontrol filecache. Its fix (4.2.1) requires Python >=3.11, so the
50
+ # 3.10 matrix legs can never install a fixed version; ignore the six
51
+ # CVEs rather than pretend the 3.10 legs can be green. pip-audit 2.10
52
+ # has no package-level skip, hence the explicit IDs.
53
+ - run: >-
54
+ pip-audit
55
+ --ignore-vuln CVE-2026-112906 --ignore-vuln CVE-2026-112907
56
+ --ignore-vuln CVE-2026-112913 --ignore-vuln CVE-2026-112914
57
+ --ignore-vuln CVE-2026-112937 --ignore-vuln CVE-2026-112940
58
+ - run: pytest -v --cov=omind --cov-report=term-missing
59
+
60
+ wheel:
61
+ # CI otherwise only installs editable (`pip install -e`), so hatchling's
62
+ # wheel file-selection is never exercised — a change that drops the hook
63
+ # .sh/.js scripts or the web/static assets from the package would ship green
64
+ # and crash `importlib.resources` on installed nodes. Build the real wheel,
65
+ # install it non-editable, and assert the packaged data files are present.
66
+ name: Wheel build + install smoke test
67
+ runs-on: ${{ matrix.os }}
68
+ strategy:
69
+ fail-fast: false
70
+ matrix:
71
+ os: [ubuntu-latest, macos-latest]
72
+ steps:
73
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
74
+ - uses: actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0 # v7.1.0
75
+ with:
76
+ python-version: '3.12'
77
+ # Same build path as publish.yml, so every PR exercises what gets uploaded.
78
+ - uses: astral-sh/setup-uv@07a047e608db84b3d8c06cd9a7c7dcc9c355c18e # v10.3.2
79
+ - name: Build the wheel
80
+ run: uv build --wheel
81
+ - name: Install the built wheel (not editable)
82
+ run: pip install dist/*.whl
83
+ - name: Smoke test the CLI and the packaged data files
84
+ run: |
85
+ omind --version
86
+ python - <<'PY'
87
+ from importlib.resources import files
88
+
89
+ root = files("omind")
90
+
91
+ def res(*parts):
92
+ p = root
93
+ for part in parts:
94
+ p = p / part
95
+ return p
96
+
97
+ required = [
98
+ ("omi-guard.sh",),
99
+ ("omi-guard-hermes.sh",),
100
+ ("omi-gate-reset.sh",),
101
+ ("secret-output-guard.sh",),
102
+ ("git-fresh-base.sh",),
103
+ ("fleet-sudo.sh",),
104
+ ("omi-guard.opencode.js",),
105
+ ("_omi_enforce.py",),
106
+ ("web", "static", "app.js"),
107
+ ("web", "static", "graph.js"),
108
+ ]
109
+ missing = ["/".join(parts) for parts in required if not res(*parts).is_file()]
110
+ fonts = [f for f in res("web", "static", "vendor", "fonts").iterdir()]
111
+ assert not missing, f"wheel is missing packaged data files: {missing}"
112
+ assert fonts, "wheel is missing web/static/vendor/fonts"
113
+ print(f"OK: {len(required)} data files + {len(fonts)} fonts present in the wheel")
114
+ PY
115
+
116
+ upgrade:
117
+ # Every PR proves that people can still UPGRADE, against a real uv on a real
118
+ # filesystem, on every OS omind is installed on. The unit tests mock uv, and
119
+ # the failure this guards (#375) does not exist in a mock: `uv tool install
120
+ # --force` deletes the environment before it builds the new one, and on
121
+ # Windows cannot delete the python.exe that `omind self-update` runs from —
122
+ # 9.4.0 -> 9.7.5 left a machine with no omind at all.
123
+ #
124
+ # Path walked: install an OLD release the way a user did -> upgrade it to this
125
+ # checkout -> run this checkout's `omind self-update` -> re-run the installer
126
+ # over the result. The invariant after EVERY step: omind still starts.
127
+ name: Upgrade from ${{ matrix.from }} (${{ matrix.os }})
128
+ runs-on: ${{ matrix.os }}
129
+ strategy:
130
+ fail-fast: false
131
+ matrix:
132
+ os: [ubuntu-latest, macos-latest, windows-latest]
133
+ # A pinned old release (the one #375 started from) and whatever is the
134
+ # newest tag today, so the baseline moves forward with every release.
135
+ from: [v9.4.0, latest]
136
+ defaults:
137
+ run:
138
+ shell: bash
139
+ env:
140
+ # The heal re-provisions ~/.claude and needs the claude CLI; not under test.
141
+ OMIND_NO_AUTOHEAL: '1'
142
+ steps:
143
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
144
+ - uses: actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0 # v7.1.0
145
+ with:
146
+ python-version: '3.12'
147
+ - run: python -m pip install -U pip uv
148
+ - name: Install the old release with bootstrap.sh, on a clean machine
149
+ run: |
150
+ bin="$(uv tool dir --bin)"
151
+ echo "$bin" >> "$GITHUB_PATH"
152
+ # Git Bash splits PATH on ':', so C:\... must become /c/... for this step.
153
+ if command -v cygpath >/dev/null 2>&1; then bin="$(cygpath -u "$bin")"; fi
154
+ export PATH="$bin:$PATH"
155
+ ref=()
156
+ [ "${{ matrix.from }}" = "latest" ] || ref=(--ref "${{ matrix.from }}")
157
+ # Exits 1 only because the runner has no `claude` CLI to set up.
158
+ scripts/bootstrap.sh --no-setup "${ref[@]}" || true
159
+ omind --version
160
+ - name: Upgrade it to this checkout
161
+ run: |
162
+ uv tool install --force --from . omind
163
+ want="$(grep -m1 '^version = ' pyproject.toml | cut -d'"' -f2)"
164
+ omind --version | tee version.txt
165
+ grep -qF "$want" version.txt
166
+ - name: omind self-update, for real
167
+ run: |
168
+ set +e
169
+ omind self-update --force 2>&1 | tee update.log
170
+ code=${PIPESTATUS[0]}
171
+ set -e
172
+ if grep -q "could not reach GitHub" update.log; then
173
+ echo "::warning::GitHub API unreachable/rate-limited from this runner; self-update not exercised"
174
+ elif [ "$RUNNER_OS" = "Windows" ]; then
175
+ # In-place replacement cannot work on Windows: it must refuse, not try.
176
+ [ "$code" -eq 1 ] && grep -q "refusing to update" update.log
177
+ else
178
+ [ "$code" -eq 0 ] && grep -q "updated to" update.log
179
+ fi
180
+ - name: Whatever self-update decided, omind still starts
181
+ run: omind --version
182
+ - name: bootstrap.sh over an existing install leaves a working omind
183
+ run: |
184
+ scripts/bootstrap.sh --no-setup || true
185
+ omind --version
186
+
187
+ secrets:
188
+ name: Secret scan (gitleaks, full history)
189
+ runs-on: ubuntu-latest
190
+ steps:
191
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
192
+ with:
193
+ fetch-depth: 0 # gitleaks scans history
194
+ - name: gitleaks
195
+ run: |
196
+ docker run --rm -v "${{ github.workspace }}:/repo" \
197
+ --entrypoint sh ghcr.io/gitleaks/gitleaks:v8.30.1 \
198
+ -c "git config --global --add safe.directory /repo && \
199
+ gitleaks git --redact --verbose /repo"
200
+
201
+ attribution:
202
+ name: Commit attribution
203
+ runs-on: ubuntu-latest
204
+ if: github.event_name == 'pull_request'
205
+ steps:
206
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
207
+ with:
208
+ fetch-depth: 0 # needs the base branch to diff against
209
+ - name: Every commit declares its authorship
210
+ run: ./scripts/check-attribution.sh --range "origin/${{ github.base_ref }}..HEAD"
211
+
212
+ conformance:
213
+ name: MCP conformance (live stdio)
214
+ runs-on: ubuntu-latest
215
+ steps:
216
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
217
+ - uses: actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0 # v7.1.0
218
+ with:
219
+ python-version: '3.12'
220
+ - name: Conformance suite
221
+ # mcp-conformance is a private repo, so this job is a graceful no-op until
222
+ # MCP_CONFORMANCE_TOKEN (a PAT with read access to it) is set in the repo's
223
+ # Actions secrets. Then it boots `omind node` over stdio against a throwaway
224
+ # vault and asserts the baseline contracts (see conformance.toml).
225
+ env:
226
+ MCP_CONFORMANCE_TOKEN: ${{ secrets.MCP_CONFORMANCE_TOKEN }}
227
+ run: |
228
+ if [ -z "$MCP_CONFORMANCE_TOKEN" ]; then
229
+ echo "MCP_CONFORMANCE_TOKEN not set — skipping conformance suite."
230
+ exit 0
231
+ fi
232
+ python -m venv .venv
233
+ .venv/bin/pip install -U pip
234
+ .venv/bin/pip install -e .
235
+ # The token is set but may be expired or lack access to the private
236
+ # repo. Treat a failed clone/install as a skip, not a hard CI failure —
237
+ # this job is a graceful no-op until a working token is wired up, and
238
+ # an expired PAT shouldn't turn the whole build red.
239
+ if ! .venv/bin/pip install "git+https://x-access-token:${MCP_CONFORMANCE_TOKEN}@github.com/CryptoJones/mcp-conformance.git"; then
240
+ echo "::warning::Could not install mcp-conformance (token expired or no access?) — skipping conformance suite."
241
+ exit 0
242
+ fi
243
+ mkdir -p ./.conformance-vault/OMI
244
+ .venv/bin/mcp-conformance run -- -q
245
+
246
+ # Actions pinned by commit SHA; kept current by Dependabot (.github/dependabot.yml).
@@ -0,0 +1,22 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ *.egg-info/
4
+ *.egg
5
+ build/
6
+ dist/
7
+ .eggs/
8
+ .venv/
9
+ venv/
10
+ env/
11
+ .pytest_cache/
12
+ .mypy_cache/
13
+ .ruff_cache/
14
+ .coverage
15
+ htmlcov/
16
+ .vscode/
17
+ .idea/
18
+ *.swp
19
+ .DS_Store
20
+ Thumbs.db
21
+ .claude/
22
+ .aider*
@@ -0,0 +1,19 @@
1
+ # gitleaks config. Uses the default rule set; allowlists obvious test fixtures
2
+ # and the generated mesh node-id/backup-password placeholders so CI stays signal,
3
+ # not noise. omind has no committed credentials: backup passwords and node IDs
4
+ # are generated at runtime with `secrets.token_*` and written outside the repo.
5
+ title = "omind gitleaks"
6
+
7
+ [extend]
8
+ useDefault = true
9
+
10
+ [allowlist]
11
+ description = "Test/e2e fixtures and docs use obvious fake tokens/paths."
12
+ paths = [
13
+ '''tests/.*''',
14
+ '''docs/.*''',
15
+ # The e2e harness reads provider keys from the environment at runtime; it
16
+ # commits no secrets. gitleaks' generic-api-key rule false-positives on the
17
+ # high-entropy env-var NAME in runpod_api_key()'s docstring (e2e/providers.py).
18
+ '''e2e/.*''',
19
+ ]
@@ -0,0 +1,14 @@
1
+ when:
2
+ - event: push
3
+ - event: pull_request
4
+
5
+ steps:
6
+ test:
7
+ image: python:3.12-slim
8
+ commands:
9
+ - python -m pip install -U pip
10
+ - pip install -e .[dev]
11
+ - ruff check .
12
+ - mypy src
13
+ - pip-audit
14
+ - pytest -v
omind-10.3.4/AGENTS.md ADDED
@@ -0,0 +1,156 @@
1
+ # AGENTS.md — orientation for AI agents working on omind
2
+
3
+ Read this before changing code. It covers what a contributor doc can't: the
4
+ invariants that break *silently*, the current state of in-flight work, and the
5
+ dead ends someone already walked down.
6
+
7
+ For dev setup, the four quality gates, the module map, SemVer rules, and PR
8
+ conventions, see **[CONTRIBUTING.md](CONTRIBUTING.md)** — this file does not
9
+ repeat them.
10
+
11
+ ---
12
+
13
+ ## The one-paragraph version
14
+
15
+ omind gives AI agents durable memory as **plain Markdown notes** in an Obsidian
16
+ vault, replicated peer-to-peer over git, exposed to agents through a local MCP
17
+ server (`omind node`) and enforced by a hook-based guard. Roughly a third of the
18
+ repo is memory; the rest is agent enforcement (`guard.py`, `policy.py`,
19
+ `verify.py`), fleet provisioning (`provision.py`, `agents.py`), and mesh
20
+ replication (`mesh.py`, `merge.py`). Know which subsystem you are in.
21
+
22
+ ## Invariants — violate these and something breaks quietly
23
+
24
+ 1. **The Markdown files are the source of truth.** Indexes, caches, and vectors
25
+ are derived and disposable. Anything derived lives in the state dir
26
+ (`paths.state_dir()`), never in the vault: vault contents are committed and
27
+ mesh-synced, so a derived file there would replicate machine-specific junk
28
+ fleet-wide.
29
+ 2. **Retrieval fails open.** Every layer of search returns `None` on any problem
30
+ and the caller falls back to the older, dumber path. A missing model, a
31
+ corrupt index, a locked database, a missing FTS5 build — all degrade search;
32
+ none may break it. Test the failure branch, not just the happy one.
33
+ 3. **Multi-note writes go through `omind.txn`.** One note at a time is already
34
+ atomic (same-dir temp + `os.replace`). Two or more is not, and a crash
35
+ between them used to leave partial state with no way back. Any new operation
36
+ that writes several notes must journal its pre-images through
37
+ `txn.Transaction` under `store.write_lock()`, or it reintroduces the gap
38
+ `omind recover` exists to close. Recovery refuses to overwrite a note edited
39
+ after the crash — that edit is newer than the pre-image.
40
+ 4. **All note writes go through `OmiStore`** (`notes.upsert_note` for external
41
+ writers) — flock, atomic rename, Lamport `Rev:` stamping, soft delete.
42
+ Deletes archive (`Disabled: true`); only `omind mesh purge` truly removes.
43
+ 5. **`OmiStore.safe_name` guards every read and write.** Path traversal must stay
44
+ impossible; there are tests enforcing this. Don't route around them.
45
+ 6. **`store.py` stays framework-free.** No FastAPI, no MCP. The CLI and the web
46
+ app both build on it.
47
+ 7. **Credential notes are de-prioritised** in search and in the gate's
48
+ suggestions unless the query is itself about credentials
49
+ (`retrieve._CREDENTIAL_PENALTY`). The gate must never steer an agent into the
50
+ secrets notes. This is load-bearing, not decoration.
51
+ 8. **No MCP tool may return unbounded output.** Every list-shaped tool pages
52
+ (`limit`, `offset`, `total`, `has_more`) via `server._page`. `list-notes` once
53
+ returned ~90,800 tokens in a single result; `tests/test_server.py::
54
+ test_every_list_tool_is_bounded` exists so a new tool cannot regress that.
55
+ 9. **Reserved files are not memories.** `index.md` and `Memory Template.md` are
56
+ scaffolding; reading one does *not* clear the consult gate
57
+ (`paths.NON_CONSULT_FILENAMES` — an anti-dodge measure, issue #109).
58
+
59
+ ---
60
+
61
+ ## Handoff: the 2026-10-02 backlog sweep (shipped)
62
+
63
+ The 2026-08-27 handoff below is history too. Current state: **v10.2.11 on `main`**.
64
+ Trust **BACKLOG.md + CHANGELOG.md** (10.1.1–10.2.11) for detail.
65
+
66
+ The sweep closed #393 #392 #391 #394 #414 #402 #403 #406 #416 #377 #380 #417 #419
67
+ #420 #423 #425 via PRs #405, #407–#413, #415, #418, #421, #422, #424 and #426.
68
+ Every item from that sweep is closed.
69
+
70
+ Lessons for the next agent:
71
+
72
+ - `windows-latest` CI runners are real Windows. Tests must be platform-correct: use
73
+ `tmp_path` absolute paths, `.as_posix()` in command text, and pin `provision._windows`.
74
+ - PowerShell `-Command` turns a native exit 2 into 1 unless the command ends with
75
+ the null-guarded `exit $LASTEXITCODE`.
76
+ - Recall names must be stored filenames, never titles.
77
+ - Enforcement classifiers must bind markers to their own stage; repo-scoped rules
78
+ match only real command sites.
79
+ - Fail-open must never drop the seed hard rules.
80
+
81
+ ---
82
+
83
+ ## Handoff: the 2026-08-27 multi-agent review (shipped — history)
84
+
85
+ The 2026-07-24 retrieval handoff below is history: `feat/hybrid-retrieval-token-budgets`
86
+ landed long ago, and #167–#178 all shipped (see BACKLOG.md). Current state at this
87
+ writing: **v8.8.0 on `main`**, 1,000+ tests + ruff + mypy strict green. Trust
88
+ **BACKLOG.md + CHANGELOG.md** for what's open — not older handoffs.
89
+
90
+ ### What changed and why
91
+
92
+ A nine-slice multi-agent review (report:
93
+ [docs/reviews/2026-08-27-multi-agent-review.md](docs/reviews/2026-08-27-multi-agent-review.md))
94
+ found 35 issues; all are fixed in the working tree. The classes worth remembering:
95
+
96
+ - **Locking is total now, and the pattern is uniform.** Any read-modify-write of a
97
+ small state file (gate sentinels, re-close/off-topic counters, `loop_guard.json`,
98
+ `node.json`, `backup.json`, harness settings.json) goes through
99
+ `filelock.exclusive()` on a SIBLING `.lock` path — never on the data file itself,
100
+ because the data file is replaced atomically and a flock on a replaced inode
101
+ protects nothing. Apply this to any new state file.
102
+ - **Optimistic concurrency is the coordination story.** `upsert_note` captures the
103
+ version BEFORE reading existing fields; checkpoint/okf/consolidate pin versions;
104
+ `edit-note` without a token answers `concurrency: "unverified"` instead of
105
+ silently last-write-wins.
106
+ - **Deletion yields to newer edits.** Purge tombstones carry the purge-time Rev;
107
+ `_apply_tombstones` keeps and reports a note whose live Rev dominates it.
108
+ - **Merge LWW losses are visible in the vault** (`merge-lww` tag), not just daemon
109
+ stderr. If you touch `merge.py`, keep scalar losses tagged.
110
+ - **The index stores the encoder IDENTITY** (`embed.model_identity`: name +
111
+ embedding-space digest), not the model name — same name/different snapshot used
112
+ to mix vector spaces silently. Refresh also BACKFILLS chunks missing vectors.
113
+ - **Self-update pins the resolved commit SHA**, never the mutable tag, and records
114
+ the previous version for `omind self-update --rollback`.
115
+ - **Enforcement hardening:** `guard reset` is compliance-logged (`gate-reset`);
116
+ freshness recorded at PreToolUse is RETRACTED on PostToolUse failure; the
117
+ verifier prompt fences untrusted material and parses verdicts by token; Layer E
118
+ uses the strict `policy.opt_in_satisfied` matcher.
119
+
120
+ ### Things that will bite you (still true)
121
+
122
+ - Retrieval/enforcement fail OPEN — every new path must degrade, never raise into
123
+ the agent. `SearchIndex.search` now blanket-catches; keep it that way.
124
+ - Recency only re-ranks matches (`test_recency_only_reorders_matches...`).
125
+ - The index doesn't strip fences from `[[wikilinks]]`; lint.py does.
126
+ - `link_targets()` preserves case.
127
+ - Never mutate a cached `NoteSummary`; use `dataclasses.replace`.
128
+ - `mesh purge` requires `--yes` (or a TTY confirm) — keep it gated.
129
+ - `read-note` caps bodies (20k default / 65k hard) — keep it bounded (invariant 8).
130
+
131
+ ### Where to pick up
132
+
133
+ The feature roadmap (agent identity/attribution, a usefulness feedback loop,
134
+ sleep-time consolidation, write-time dedup, scoped writes) is Part 2 of the review
135
+ report — none of it is started.
136
+
137
+ ---
138
+
139
+ ## Working agreements
140
+
141
+ - **BACKLOG.md and the GitHub Issues tab are two views of one list.** File an
142
+ issue for every backlog line and link it both ways; check the box when it
143
+ ships. Both had drifted badly before 2026-07-24 (every "Open" item was already
144
+ closed upstream) — don't let that happen again.
145
+ - **GitHub is the only remote** (Codeberg is end-of-life).
146
+ - **Commit/push only when asked.** Branch off `main` (`feat/`, `fix/`, `docs/`,
147
+ `chore/`, `refactor/`), conventional-commit subjects.
148
+ - **Docs carry the footer** (`*Proudly Made in Nebraska. Go Big Red! 🌽
149
+ <https://xkcd.com/2347/>*`); the README carries the centred banner version.
150
+ - **Report honestly.** If a gate fails, say so with the output. If you skipped
151
+ part of the scope, say which part and why — see how #174 and #177 were left
152
+ open rather than half-done.
153
+
154
+ ---
155
+
156
+ *Proudly Made in Nebraska. Go Big Red! 🌽 <https://xkcd.com/2347/>*