noetrail 0.10.0a1__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 (223) hide show
  1. noetrail-0.10.0a1/.github/CODEOWNERS +33 -0
  2. noetrail-0.10.0a1/.github/ISSUE_TEMPLATE/bug_report.yml +96 -0
  3. noetrail-0.10.0a1/.github/ISSUE_TEMPLATE/config.yml +15 -0
  4. noetrail-0.10.0a1/.github/ISSUE_TEMPLATE/documentation.yml +75 -0
  5. noetrail-0.10.0a1/.github/ISSUE_TEMPLATE/feature_request.yml +77 -0
  6. noetrail-0.10.0a1/.github/PULL_REQUEST_TEMPLATE.md +47 -0
  7. noetrail-0.10.0a1/.github/dependabot.yml +19 -0
  8. noetrail-0.10.0a1/.github/workflows/ci.yml +153 -0
  9. noetrail-0.10.0a1/.github/workflows/codeql.yml +53 -0
  10. noetrail-0.10.0a1/.github/workflows/deploy-zeroclaw.yml +49 -0
  11. noetrail-0.10.0a1/.github/workflows/release.yml +172 -0
  12. noetrail-0.10.0a1/.gitignore +34 -0
  13. noetrail-0.10.0a1/.knowledge/SPEC.md +674 -0
  14. noetrail-0.10.0a1/.knowledge/config.yaml +25 -0
  15. noetrail-0.10.0a1/.knowledge/packs/books/book.md +5 -0
  16. noetrail-0.10.0a1/.knowledge/packs/books/pack.yaml +32 -0
  17. noetrail-0.10.0a1/.knowledge/packs/knowledge-core/pack.yaml +230 -0
  18. noetrail-0.10.0a1/.knowledge/relation-types.yaml +18 -0
  19. noetrail-0.10.0a1/.knowledge/schemas/entry.schema.json +294 -0
  20. noetrail-0.10.0a1/.knowledge/templates/bookmark.md +27 -0
  21. noetrail-0.10.0a1/.knowledge/templates/experience.md +17 -0
  22. noetrail-0.10.0a1/.knowledge/templates/imported-note.md +18 -0
  23. noetrail-0.10.0a1/.knowledge/templates/memory.md +17 -0
  24. noetrail-0.10.0a1/.knowledge/templates/place.md +17 -0
  25. noetrail-0.10.0a1/.knowledge/templates/product.md +17 -0
  26. noetrail-0.10.0a1/.knowledge/templates/recipe.md +27 -0
  27. noetrail-0.10.0a1/.knowledge/templates/thought.md +17 -0
  28. noetrail-0.10.0a1/AGENTS.md +124 -0
  29. noetrail-0.10.0a1/CHANGELOG.md +543 -0
  30. noetrail-0.10.0a1/CODE_OF_CONDUCT.md +137 -0
  31. noetrail-0.10.0a1/CONTRIBUTING.md +145 -0
  32. noetrail-0.10.0a1/LICENSE +201 -0
  33. noetrail-0.10.0a1/MANIFEST.in +58 -0
  34. noetrail-0.10.0a1/Makefile +67 -0
  35. noetrail-0.10.0a1/PKG-INFO +363 -0
  36. noetrail-0.10.0a1/README.md +334 -0
  37. noetrail-0.10.0a1/ROADMAP.md +84 -0
  38. noetrail-0.10.0a1/SECURITY.md +100 -0
  39. noetrail-0.10.0a1/SUPPORT.md +30 -0
  40. noetrail-0.10.0a1/demo/README.md +39 -0
  41. noetrail-0.10.0a1/demo/config/packs/travel/pack.yaml +26 -0
  42. noetrail-0.10.0a1/demo/data/imports/raw/markdown/reading-list.md +4 -0
  43. noetrail-0.10.0a1/demo/data/imports/work/.gitkeep +1 -0
  44. noetrail-0.10.0a1/demo/data/trash/.gitkeep +1 -0
  45. noetrail-0.10.0a1/demo/data/vault/.locks/.gitkeep +1 -0
  46. noetrail-0.10.0a1/demo/data/vault/custom/travel/destination/2026-01-01--azure-harbor--22222222.md +24 -0
  47. noetrail-0.10.0a1/demo/data/vault/notes/2026-01-01--welcome-to-noetrail--11111111.md +21 -0
  48. noetrail-0.10.0a1/demo/session.sh +70 -0
  49. noetrail-0.10.0a1/deploy/zeroclaw/AGENTS.md +161 -0
  50. noetrail-0.10.0a1/deploy/zeroclaw/Containerfile.bookmark-fetcher +23 -0
  51. noetrail-0.10.0a1/deploy/zeroclaw/bookmark-fetcher-deployment.example.yaml +77 -0
  52. noetrail-0.10.0a1/deploy/zeroclaw/bookmark-fetcher-network-policy.example.yaml +83 -0
  53. noetrail-0.10.0a1/deploy/zeroclaw/security-profiles.example.toml +250 -0
  54. noetrail-0.10.0a1/docs/adr/0001-core-and-schema-packs.md +254 -0
  55. noetrail-0.10.0a1/docs/adr/0002-noetrail-name-and-compatibility.md +65 -0
  56. noetrail-0.10.0a1/docs/adr/0003-in-process-reads.md +123 -0
  57. noetrail-0.10.0a1/docs/adr/0004-no-search-index.md +109 -0
  58. noetrail-0.10.0a1/docs/adr/0005-lexical-bm25-index.md +156 -0
  59. noetrail-0.10.0a1/docs/adr/0006-relation-level-valid-time.md +194 -0
  60. noetrail-0.10.0a1/docs/adr/0007-hybrid-retrieval-default.md +104 -0
  61. noetrail-0.10.0a1/docs/adr/0008-word-form-fallback.md +57 -0
  62. noetrail-0.10.0a1/docs/adr/README.md +24 -0
  63. noetrail-0.10.0a1/docs/ai-authorship.md +85 -0
  64. noetrail-0.10.0a1/docs/alpha-pilot.md +44 -0
  65. noetrail-0.10.0a1/docs/architecture.md +321 -0
  66. noetrail-0.10.0a1/docs/assets/demo.svg +77 -0
  67. noetrail-0.10.0a1/docs/assets/demo.txt +72 -0
  68. noetrail-0.10.0a1/docs/assets/noetrail-lockup.svg +12 -0
  69. noetrail-0.10.0a1/docs/assets/noetrail-logo.md +24 -0
  70. noetrail-0.10.0a1/docs/assets/noetrail-mark-currentcolor.svg +10 -0
  71. noetrail-0.10.0a1/docs/assets/noetrail-mark-small.svg +10 -0
  72. noetrail-0.10.0a1/docs/assets/noetrail-mark.svg +10 -0
  73. noetrail-0.10.0a1/docs/assets/valid-time-dark.svg +38 -0
  74. noetrail-0.10.0a1/docs/assets/valid-time-light.svg +38 -0
  75. noetrail-0.10.0a1/docs/backup-restore.md +100 -0
  76. noetrail-0.10.0a1/docs/embeddings.md +135 -0
  77. noetrail-0.10.0a1/docs/importing.md +201 -0
  78. noetrail-0.10.0a1/docs/installation.md +158 -0
  79. noetrail-0.10.0a1/docs/integrations/mcp-clients.md +189 -0
  80. noetrail-0.10.0a1/docs/integrations/zeroclaw-security.md +272 -0
  81. noetrail-0.10.0a1/docs/integrations/zeroclaw-setup.md +376 -0
  82. noetrail-0.10.0a1/docs/internal/decision-log.md +95 -0
  83. noetrail-0.10.0a1/docs/knowledge-maintenance.md +52 -0
  84. noetrail-0.10.0a1/docs/layout.md +111 -0
  85. noetrail-0.10.0a1/docs/limits.md +364 -0
  86. noetrail-0.10.0a1/docs/privacy.md +127 -0
  87. noetrail-0.10.0a1/docs/publication-readiness.md +106 -0
  88. noetrail-0.10.0a1/docs/quickstart.md +250 -0
  89. noetrail-0.10.0a1/docs/releases/0.10.0a1.md +98 -0
  90. noetrail-0.10.0a1/docs/releasing.md +239 -0
  91. noetrail-0.10.0a1/docs/retrieval-evaluation.md +112 -0
  92. noetrail-0.10.0a1/docs/saved-views.md +37 -0
  93. noetrail-0.10.0a1/docs/schema-packs.md +253 -0
  94. noetrail-0.10.0a1/docs/versioning.md +26 -0
  95. noetrail-0.10.0a1/pyproject.toml +168 -0
  96. noetrail-0.10.0a1/setup.cfg +4 -0
  97. noetrail-0.10.0a1/skills/capture-knowledge/SKILL.md +316 -0
  98. noetrail-0.10.0a1/skills/capture-knowledge/agents/openai.yaml +4 -0
  99. noetrail-0.10.0a1/skills/fetch-bookmark-metadata/SKILL.md +32 -0
  100. noetrail-0.10.0a1/skills/fetch-bookmark-metadata/agents/openai.yaml +4 -0
  101. noetrail-0.10.0a1/skills/import-knowledge/SKILL.md +86 -0
  102. noetrail-0.10.0a1/skills/import-knowledge/agents/openai.yaml +4 -0
  103. noetrail-0.10.0a1/skills/manage-trash/SKILL.md +93 -0
  104. noetrail-0.10.0a1/skills/manage-trash/agents/openai.yaml +4 -0
  105. noetrail-0.10.0a1/skills/review-knowledge/SKILL.md +94 -0
  106. noetrail-0.10.0a1/skills/review-knowledge/agents/openai.yaml +4 -0
  107. noetrail-0.10.0a1/skills/save-bookmark/SKILL.md +161 -0
  108. noetrail-0.10.0a1/skills/save-bookmark/agents/openai.yaml +4 -0
  109. noetrail-0.10.0a1/src/noetrail/__init__.py +7 -0
  110. noetrail-0.10.0a1/src/noetrail/attachments.py +320 -0
  111. noetrail-0.10.0a1/src/noetrail/basic_memory.py +129 -0
  112. noetrail-0.10.0a1/src/noetrail/body.py +222 -0
  113. noetrail-0.10.0a1/src/noetrail/bookmark_fetcher.py +1159 -0
  114. noetrail-0.10.0a1/src/noetrail/cli.py +1020 -0
  115. noetrail-0.10.0a1/src/noetrail/commands/__init__.py +7 -0
  116. noetrail-0.10.0a1/src/noetrail/commands/capture.py +538 -0
  117. noetrail-0.10.0a1/src/noetrail/commands/curate.py +295 -0
  118. noetrail-0.10.0a1/src/noetrail/commands/edit.py +899 -0
  119. noetrail-0.10.0a1/src/noetrail/commands/importer.py +334 -0
  120. noetrail-0.10.0a1/src/noetrail/commands/maintenance.py +785 -0
  121. noetrail-0.10.0a1/src/noetrail/commands/query.py +903 -0
  122. noetrail-0.10.0a1/src/noetrail/commands/quickstart.py +239 -0
  123. noetrail-0.10.0a1/src/noetrail/commands/review.py +440 -0
  124. noetrail-0.10.0a1/src/noetrail/commands/vault_import.py +984 -0
  125. noetrail-0.10.0a1/src/noetrail/commands/views.py +69 -0
  126. noetrail-0.10.0a1/src/noetrail/constants.py +356 -0
  127. noetrail-0.10.0a1/src/noetrail/deadline.py +34 -0
  128. noetrail-0.10.0a1/src/noetrail/entries.py +230 -0
  129. noetrail-0.10.0a1/src/noetrail/errors.py +107 -0
  130. noetrail-0.10.0a1/src/noetrail/evidence.py +96 -0
  131. noetrail-0.10.0a1/src/noetrail/frontmatter.py +716 -0
  132. noetrail-0.10.0a1/src/noetrail/index.py +1028 -0
  133. noetrail-0.10.0a1/src/noetrail/jsonrpc.py +92 -0
  134. noetrail-0.10.0a1/src/noetrail/layout.py +344 -0
  135. noetrail-0.10.0a1/src/noetrail/mcp.py +2665 -0
  136. noetrail-0.10.0a1/src/noetrail/mcp_protocol.py +99 -0
  137. noetrail-0.10.0a1/src/noetrail/migrations.py +359 -0
  138. noetrail-0.10.0a1/src/noetrail/normalize.py +121 -0
  139. noetrail-0.10.0a1/src/noetrail/obsidian.py +339 -0
  140. noetrail-0.10.0a1/src/noetrail/payloads.py +57 -0
  141. noetrail-0.10.0a1/src/noetrail/provenance.py +217 -0
  142. noetrail-0.10.0a1/src/noetrail/relations.py +129 -0
  143. noetrail-0.10.0a1/src/noetrail/schema.py +1143 -0
  144. noetrail-0.10.0a1/src/noetrail/search.py +366 -0
  145. noetrail-0.10.0a1/src/noetrail/store.py +263 -0
  146. noetrail-0.10.0a1/src/noetrail/temporal.py +469 -0
  147. noetrail-0.10.0a1/src/noetrail/validation.py +574 -0
  148. noetrail-0.10.0a1/src/noetrail/vectors.py +271 -0
  149. noetrail-0.10.0a1/src/noetrail/version.py +19 -0
  150. noetrail-0.10.0a1/src/noetrail/views.py +287 -0
  151. noetrail-0.10.0a1/src/noetrail.egg-info/PKG-INFO +363 -0
  152. noetrail-0.10.0a1/src/noetrail.egg-info/SOURCES.txt +221 -0
  153. noetrail-0.10.0a1/src/noetrail.egg-info/dependency_links.txt +1 -0
  154. noetrail-0.10.0a1/src/noetrail.egg-info/entry_points.txt +7 -0
  155. noetrail-0.10.0a1/src/noetrail.egg-info/top_level.txt +1 -0
  156. noetrail-0.10.0a1/tests/__init__.py +66 -0
  157. noetrail-0.10.0a1/tests/test_absent_type.py +125 -0
  158. noetrail-0.10.0a1/tests/test_backup_restore.py +72 -0
  159. noetrail-0.10.0a1/tests/test_body_headings.py +151 -0
  160. noetrail-0.10.0a1/tests/test_bookmark_fetch_mcp.py +316 -0
  161. noetrail-0.10.0a1/tests/test_bookmark_fetcher_addresses.py +219 -0
  162. noetrail-0.10.0a1/tests/test_bookmark_fetcher_redirects.py +535 -0
  163. noetrail-0.10.0a1/tests/test_builtin_schema.py +361 -0
  164. noetrail-0.10.0a1/tests/test_cli.py +2765 -0
  165. noetrail-0.10.0a1/tests/test_coverage_tool.py +178 -0
  166. noetrail-0.10.0a1/tests/test_curate.py +168 -0
  167. noetrail-0.10.0a1/tests/test_custom_types.py +350 -0
  168. noetrail-0.10.0a1/tests/test_demo.py +74 -0
  169. noetrail-0.10.0a1/tests/test_demo_recording.py +116 -0
  170. noetrail-0.10.0a1/tests/test_documentation.py +495 -0
  171. noetrail-0.10.0a1/tests/test_everyday_questions.py +50 -0
  172. noetrail-0.10.0a1/tests/test_foreign_formats.py +232 -0
  173. noetrail-0.10.0a1/tests/test_frontmatter.py +315 -0
  174. noetrail-0.10.0a1/tests/test_git_boundary.py +65 -0
  175. noetrail-0.10.0a1/tests/test_governance.py +281 -0
  176. noetrail-0.10.0a1/tests/test_history_check.py +141 -0
  177. noetrail-0.10.0a1/tests/test_hybrid_rank.py +174 -0
  178. noetrail-0.10.0a1/tests/test_in_process.py +226 -0
  179. noetrail-0.10.0a1/tests/test_initialization.py +148 -0
  180. noetrail-0.10.0a1/tests/test_jsonrpc.py +79 -0
  181. noetrail-0.10.0a1/tests/test_layout.py +507 -0
  182. noetrail-0.10.0a1/tests/test_locking.py +507 -0
  183. noetrail-0.10.0a1/tests/test_malformed_frontmatter.py +184 -0
  184. noetrail-0.10.0a1/tests/test_markdown_import.py +183 -0
  185. noetrail-0.10.0a1/tests/test_mcp.py +1800 -0
  186. noetrail-0.10.0a1/tests/test_migrations.py +230 -0
  187. noetrail-0.10.0a1/tests/test_packaging.py +548 -0
  188. noetrail-0.10.0a1/tests/test_provenance.py +478 -0
  189. noetrail-0.10.0a1/tests/test_quickstart.py +128 -0
  190. noetrail-0.10.0a1/tests/test_read_deadline.py +52 -0
  191. noetrail-0.10.0a1/tests/test_release_consistency.py +88 -0
  192. noetrail-0.10.0a1/tests/test_retrieval_quality.py +157 -0
  193. noetrail-0.10.0a1/tests/test_retype.py +223 -0
  194. noetrail-0.10.0a1/tests/test_schema.py +465 -0
  195. noetrail-0.10.0a1/tests/test_search_evidence.py +46 -0
  196. noetrail-0.10.0a1/tests/test_search_index.py +688 -0
  197. noetrail-0.10.0a1/tests/test_supply_chain.py +190 -0
  198. noetrail-0.10.0a1/tests/test_temporal.py +933 -0
  199. noetrail-0.10.0a1/tests/test_vault_import.py +625 -0
  200. noetrail-0.10.0a1/tests/test_vault_index.py +304 -0
  201. noetrail-0.10.0a1/tests/test_vector_rerank.py +337 -0
  202. noetrail-0.10.0a1/tests/test_views.py +494 -0
  203. noetrail-0.10.0a1/tests/test_word_forms.py +108 -0
  204. noetrail-0.10.0a1/tests/test_zeroclaw_candidate.py +94 -0
  205. noetrail-0.10.0a1/tools/bookmark_fetch_mcp.py +18 -0
  206. noetrail-0.10.0a1/tools/check_git_boundary.py +122 -0
  207. noetrail-0.10.0a1/tools/check_history.py +180 -0
  208. noetrail-0.10.0a1/tools/check_release_consistency.py +105 -0
  209. noetrail-0.10.0a1/tools/check_reproducible.py +249 -0
  210. noetrail-0.10.0a1/tools/check_secrets.py +102 -0
  211. noetrail-0.10.0a1/tools/coverage.py +526 -0
  212. noetrail-0.10.0a1/tools/generate_sbom.py +248 -0
  213. noetrail-0.10.0a1/tools/know.py +18 -0
  214. noetrail-0.10.0a1/tools/knowledge_mcp.py +18 -0
  215. noetrail-0.10.0a1/tools/measure_questions.py +131 -0
  216. noetrail-0.10.0a1/tools/measure_retrieval.py +209 -0
  217. noetrail-0.10.0a1/tools/measure_search.py +455 -0
  218. noetrail-0.10.0a1/tools/question_set.json +828 -0
  219. noetrail-0.10.0a1/tools/release_acceptance.py +332 -0
  220. noetrail-0.10.0a1/tools/render_terminal_svg.py +280 -0
  221. noetrail-0.10.0a1/tools/retrieval_set.json +359 -0
  222. noetrail-0.10.0a1/tools/word_form_set.json +40 -0
  223. noetrail-0.10.0a1/tools/zeroclaw_candidate.py +40 -0
@@ -0,0 +1,33 @@
1
+ # Review ownership. Noetrail has one maintainer, so a single catch-all rule
2
+ # would be enough; the paths below are listed separately because they are the
3
+ # ones where an unreviewed change is expensive, and because this file should
4
+ # still say something useful when there is more than one owner.
5
+ #
6
+ # CODEOWNERS only requests reviews. Requiring them is a branch-protection
7
+ # setting on `main`, which is configured in the repository settings, not here.
8
+
9
+ * @patsch1
10
+
11
+ # On-disk format, migrations, and the code that decides what a path may be.
12
+ /src/noetrail/migrations.py @patsch1
13
+ /src/noetrail/layout.py @patsch1
14
+ /src/noetrail/schema.py @patsch1
15
+ /.knowledge/ @patsch1
16
+
17
+ # Agent-facing boundaries: the MCP surface and the isolated fetcher.
18
+ /src/noetrail/mcp.py @patsch1
19
+ /src/noetrail/mcp_protocol.py @patsch1
20
+ /src/noetrail/bookmark_fetcher.py @patsch1
21
+
22
+ # Supply chain and publication: workflows, packaging metadata, and the
23
+ # scripts a release is checked with.
24
+ /.github/ @patsch1
25
+ /pyproject.toml @patsch1
26
+ /MANIFEST.in @patsch1
27
+ /tools/ @patsch1
28
+
29
+ # Governance and security promises.
30
+ /SECURITY.md @patsch1
31
+ /CODE_OF_CONDUCT.md @patsch1
32
+ /CONTRIBUTING.md @patsch1
33
+ /LICENSE @patsch1
@@ -0,0 +1,96 @@
1
+ name: Bug report
2
+ description: Something behaves differently than documented, or fails.
3
+ title: "bug: "
4
+ labels: ["bug"]
5
+ body:
6
+ - type: markdown
7
+ attributes:
8
+ value: |
9
+ SUPPORT.md asks for the environment and a `noetrail doctor` report with
10
+ every issue. This form requires it, because a bug report without it
11
+ usually costs one round trip before anything can be looked at.
12
+
13
+ Use synthetic data. Never paste a real vault entry, export,
14
+ attachment, URL with personal content, token, or infrastructure
15
+ detail. Redact absolute paths that contain names.
16
+ - type: checkboxes
17
+ id: preflight
18
+ attributes:
19
+ label: Before reporting
20
+ options:
21
+ - label: I searched the existing open and closed issues.
22
+ required: true
23
+ - label: I can reproduce this with synthetic data in a temporary vault, or I explain below why not.
24
+ required: true
25
+ - label: This report contains no personal vault content, credentials, or private infrastructure details.
26
+ required: true
27
+ - label: This is not a security vulnerability. Those go to the private channel in SECURITY.md.
28
+ required: true
29
+ - type: input
30
+ id: version
31
+ attributes:
32
+ label: Noetrail version
33
+ description: Output of `noetrail --version`.
34
+ placeholder: "noetrail 0.10.0a1"
35
+ validations:
36
+ required: true
37
+ - type: input
38
+ id: python
39
+ attributes:
40
+ label: Python version
41
+ description: Output of `python3 -V`.
42
+ placeholder: "Python 3.13.2"
43
+ validations:
44
+ required: true
45
+ - type: input
46
+ id: os
47
+ attributes:
48
+ label: Operating system
49
+ description: Name and version, plus the filesystem if the vault is not on local storage.
50
+ placeholder: "Debian 13, ext4"
51
+ validations:
52
+ required: true
53
+ - type: dropdown
54
+ id: surface
55
+ attributes:
56
+ label: Command surface
57
+ options:
58
+ - CLI
59
+ - Noetrail MCP
60
+ - bookmark fetcher
61
+ - both CLI and MCP
62
+ validations:
63
+ required: true
64
+ - type: textarea
65
+ id: doctor
66
+ attributes:
67
+ label: "`noetrail doctor` output"
68
+ description: Run `noetrail doctor` against the affected instance and paste the JSON report unchanged, except for paths you need to redact.
69
+ render: json
70
+ validations:
71
+ required: true
72
+ - type: textarea
73
+ id: reproduction
74
+ attributes:
75
+ label: Steps to reproduce
76
+ description: The exact commands, in order, starting from a state a reader can create.
77
+ placeholder: |
78
+ 1. noetrail --data-root "$T/data" --config-root "$T/config" init
79
+ 2. noetrail ... capture --type thought --title "synthetic" --text "synthetic"
80
+ 3. noetrail ... search synthetic
81
+ validations:
82
+ required: true
83
+ - type: textarea
84
+ id: expected
85
+ attributes:
86
+ label: Expected and actual result
87
+ description: What you expected, what happened, and the sanitized error or exit code.
88
+ validations:
89
+ required: true
90
+ - type: textarea
91
+ id: context
92
+ attributes:
93
+ label: Anything else
94
+ description: Schema packs in use, vault size, MCP client, container deployment. Optional.
95
+ validations:
96
+ required: false
@@ -0,0 +1,15 @@
1
+ # Blank issues are disabled on purpose: the three forms exist so that a report
2
+ # arrives with the version, the interpreter, the operating system, and a
3
+ # `noetrail doctor` report already in it, which SUPPORT.md asks for and a free
4
+ # text box does not enforce.
5
+ blank_issues_enabled: false
6
+ contact_links:
7
+ - name: Question or idea
8
+ url: https://github.com/patsch1/noetrail/discussions
9
+ about: Usage questions, agent setups, and open-ended ideas belong in Discussions, not in the issue tracker.
10
+ - name: Report a security vulnerability
11
+ url: https://github.com/patsch1/noetrail/security/advisories/new
12
+ about: Never file a vulnerability as a public issue. Use the private advisory form; SECURITY.md states the response times.
13
+ - name: Support and what to include
14
+ url: https://github.com/patsch1/noetrail/blob/main/SUPPORT.md
15
+ about: What this project does and does not support, and how to sanitize a report before sending it.
@@ -0,0 +1,75 @@
1
+ name: Documentation problem
2
+ description: A documented step is wrong, missing, unclear, or out of date.
3
+ title: "docs: "
4
+ labels: ["documentation"]
5
+ body:
6
+ - type: markdown
7
+ attributes:
8
+ value: |
9
+ The shell blocks in `README.md` and `docs/quickstart.md` are executed
10
+ by the test suite, so a failing block there is a real defect. Blocks in
11
+ other documents are not, and a report is the only way they get fixed.
12
+
13
+ Redact absolute paths that contain personal names.
14
+ - type: checkboxes
15
+ id: preflight
16
+ attributes:
17
+ label: Before reporting
18
+ options:
19
+ - label: I searched the existing open and closed issues.
20
+ required: true
21
+ - label: This report contains no personal vault content or credentials.
22
+ required: true
23
+ - type: input
24
+ id: document
25
+ attributes:
26
+ label: Document
27
+ description: Repository path, and the heading or line if you have it.
28
+ placeholder: "docs/quickstart.md, section 'Import Markdown'"
29
+ validations:
30
+ required: true
31
+ - type: input
32
+ id: version
33
+ attributes:
34
+ label: Noetrail version
35
+ description: Output of `noetrail --version`. Documentation is versioned with the program.
36
+ placeholder: "noetrail 0.10.0a1"
37
+ validations:
38
+ required: true
39
+ - type: input
40
+ id: python
41
+ attributes:
42
+ label: Python version
43
+ description: Output of `python3 -V`.
44
+ placeholder: "Python 3.13.2"
45
+ validations:
46
+ required: true
47
+ - type: input
48
+ id: os
49
+ attributes:
50
+ label: Operating system
51
+ placeholder: "Ubuntu 24.04"
52
+ validations:
53
+ required: true
54
+ - type: textarea
55
+ id: doctor
56
+ attributes:
57
+ label: "`noetrail doctor` output"
58
+ description: Most documentation problems are really a mismatch between the documented layout and the actual one. This report shows which it is.
59
+ render: json
60
+ validations:
61
+ required: true
62
+ - type: textarea
63
+ id: problem
64
+ attributes:
65
+ label: What is wrong
66
+ description: Quote the documented text, then say what actually happens or what is missing. Include the command and its sanitized output if a documented step failed.
67
+ validations:
68
+ required: true
69
+ - type: textarea
70
+ id: suggestion
71
+ attributes:
72
+ label: Suggested wording
73
+ description: Optional. A concrete replacement is usually faster than a discussion.
74
+ validations:
75
+ required: false
@@ -0,0 +1,77 @@
1
+ name: Feature request
2
+ description: Propose a bounded change in behavior.
3
+ title: "feature: "
4
+ labels: ["enhancement"]
5
+ body:
6
+ - type: markdown
7
+ attributes:
8
+ value: |
9
+ Noetrail is a one-person project before `1.0`. A proposal that names
10
+ the problem, the smallest change that solves it, and what it would
11
+ cost has a much better chance than a list of wishes.
12
+
13
+ ROADMAP.md lists what is planned and what is deliberately out of
14
+ scope. Please check it first.
15
+ - type: checkboxes
16
+ id: preflight
17
+ attributes:
18
+ label: Before proposing
19
+ options:
20
+ - label: I searched the existing open and closed issues.
21
+ required: true
22
+ - label: I read ROADMAP.md and this is not already listed as a non-goal.
23
+ required: true
24
+ - label: This request contains no personal vault content or credentials.
25
+ required: true
26
+ - type: input
27
+ id: version
28
+ attributes:
29
+ label: Noetrail version
30
+ description: Output of `noetrail --version`, so the proposal is read against the right behavior.
31
+ placeholder: "noetrail 0.10.0a1"
32
+ validations:
33
+ required: true
34
+ - type: input
35
+ id: python
36
+ attributes:
37
+ label: Python version
38
+ description: Output of `python3 -V`.
39
+ placeholder: "Python 3.13.2"
40
+ validations:
41
+ required: true
42
+ - type: input
43
+ id: os
44
+ attributes:
45
+ label: Operating system
46
+ placeholder: "macOS 15.3"
47
+ validations:
48
+ required: true
49
+ - type: textarea
50
+ id: doctor
51
+ attributes:
52
+ label: "`noetrail doctor` output"
53
+ description: The report from the instance the proposal is about. It shows the schema version, the loaded packs, and the layout the request has to fit.
54
+ render: json
55
+ validations:
56
+ required: true
57
+ - type: textarea
58
+ id: problem
59
+ attributes:
60
+ label: Problem
61
+ description: What you are trying to do today, and where the current commands or MCP tools stop you. Describe the situation, not the solution.
62
+ validations:
63
+ required: true
64
+ - type: textarea
65
+ id: proposal
66
+ attributes:
67
+ label: Proposed change
68
+ description: The smallest change that would solve it. Name the affected surface — CLI, MCP, schema packs, on-disk format, documentation.
69
+ validations:
70
+ required: true
71
+ - type: textarea
72
+ id: alternatives
73
+ attributes:
74
+ label: Alternatives and impact
75
+ description: What you considered instead, and what this would cost — a data-format change, a migration, a new dependency, a wider agent permission. Say so if you do not know.
76
+ validations:
77
+ required: true
@@ -0,0 +1,47 @@
1
+ <!--
2
+ The four sections below are the four things CONTRIBUTING.md asks a pull
3
+ request to describe. Keep one coherent change per pull request.
4
+ Delete a section only if you replace it with a sentence saying why it does not
5
+ apply.
6
+ -->
7
+
8
+ ## Summary
9
+
10
+ <!-- What changes, and why. One paragraph. -->
11
+
12
+ ## User-visible behavior and compatibility
13
+
14
+ <!--
15
+ Which command, MCP tool, output field, or file layout changes, and what an
16
+ existing installation notices. Write "none" if nothing user-visible changes.
17
+ -->
18
+
19
+ ## Security and privacy boundaries
20
+
21
+ <!--
22
+ Which boundary this touches: the Git/private-data separation, the narrow MCP
23
+ surface, the isolated bookmark fetcher, attachment ingestion, purge, secrets.
24
+ Write "none affected" if it touches none of them.
25
+ -->
26
+
27
+ ## Tests run
28
+
29
+ <!--
30
+ Paste the commands you ran and their result. `make check` covers all six
31
+ gates; name the individual gates if you ran them separately.
32
+ -->
33
+
34
+ ## Migration, rollback, and documentation
35
+
36
+ <!--
37
+ On-disk format changes need an ordered, deterministic, dry-run migration and a
38
+ rollback path. Name the documents you updated, or say why none needed it.
39
+ -->
40
+
41
+ ---
42
+
43
+ - [ ] `make check` passes locally (lint, types, tests, coverage, secrets, boundary).
44
+ - [ ] Tests and fixtures use synthetic data only — no real vault, export, attachment, URL, or credential.
45
+ - [ ] Documentation, `CHANGELOG.md`, and any affected `docs/` page are updated.
46
+ - [ ] No generated wheels, private runtime directories, or copied logs are included.
47
+ - [ ] I am submitting this under the [Apache License 2.0](../LICENSE), per section 5 of that license.
@@ -0,0 +1,19 @@
1
+ version: 2
2
+
3
+ updates:
4
+ # The workflows pin actions to a commit SHA, which is safe but frozen:
5
+ # without this, a pinned action would keep running its original code
6
+ # indefinitely, security fixes included. Dependabot rewrites the SHA and the
7
+ # trailing version comment together.
8
+ - package-ecosystem: "github-actions"
9
+ directory: "/"
10
+ schedule:
11
+ interval: "weekly"
12
+ commit-message:
13
+ prefix: "ci"
14
+ labels:
15
+ - "dependencies"
16
+ - "github-actions"
17
+
18
+ # There is deliberately no "pip" entry: the runtime has no third-party
19
+ # dependencies, and the two CI-only tools are pinned in the workflows.
@@ -0,0 +1,153 @@
1
+ name: CI
2
+
3
+ # An unfiltered `push` plus `pull_request` ran every job twice for any branch
4
+ # that had an open pull request. Pushes are now limited to the branch and the
5
+ # tags that are worth a run on their own; everything else arrives via the
6
+ # pull-request event.
7
+ on:
8
+ push:
9
+ branches: [main]
10
+ tags:
11
+ - "v[0-9]+.[0-9]+.[0-9]+"
12
+ - "v[0-9]+.[0-9]+.[0-9]+a[0-9]+"
13
+ - "v[0-9]+.[0-9]+.[0-9]+b[0-9]+"
14
+ - "v[0-9]+.[0-9]+.[0-9]+rc[0-9]+"
15
+ pull_request:
16
+
17
+ # Only the newest commit of a ref is interesting; superseded runs are cancelled
18
+ # instead of competing for runners.
19
+ concurrency:
20
+ group: ci-${{ github.ref }}
21
+ cancel-in-progress: true
22
+
23
+ permissions:
24
+ contents: read
25
+
26
+ # Third-party actions are pinned to a commit SHA. A mutable major tag can be
27
+ # repointed at new code without any change in this repository, so the version
28
+ # in the trailing comment is documentation only.
29
+ jobs:
30
+ lint:
31
+ name: Lint
32
+ runs-on: ubuntu-latest
33
+ timeout-minutes: 10
34
+
35
+ steps:
36
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
37
+ - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
38
+ with:
39
+ python-version: "3.13"
40
+ - name: Install linter
41
+ run: python -m pip install ruff==0.14.0
42
+ - name: Check style and common defects
43
+ run: python -m ruff check .
44
+
45
+ typecheck:
46
+ name: Type check
47
+ runs-on: ubuntu-latest
48
+ timeout-minutes: 10
49
+
50
+ steps:
51
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
52
+ - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
53
+ with:
54
+ # The lowest supported interpreter: mypy resolves version-conditional
55
+ # standard-library stubs against the running Python, so checking on
56
+ # 3.13 would not see what 3.11 users get.
57
+ python-version: "3.11"
58
+ - name: Install type checker
59
+ run: python -m pip install mypy==1.20.2
60
+ # Scope, strictness and per-module overrides live in pyproject.toml.
61
+ - name: Check types
62
+ run: python -m mypy
63
+
64
+ test:
65
+ name: Python ${{ matrix.python-version }} on ${{ matrix.os }}
66
+ runs-on: ${{ matrix.os }}
67
+ timeout-minutes: 15
68
+ strategy:
69
+ fail-fast: false
70
+ matrix:
71
+ os: [ubuntu-latest]
72
+ python-version: ["3.11", "3.12", "3.13", "3.14"]
73
+ # One macOS job, not a second full matrix. Its purpose is the platform,
74
+ # not the interpreter: `/var` is a symlink there and `/tmp` on Linux is
75
+ # not, which is a difference the suite has already been wrong about.
76
+ # A macOS runner also bills at ten times a Linux one on a private
77
+ # repository, so the coverage is bought at one job, on the version the
78
+ # other gates use.
79
+ include:
80
+ - os: macos-latest
81
+ python-version: "3.13"
82
+
83
+ steps:
84
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
85
+ - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
86
+ with:
87
+ python-version: ${{ matrix.python-version }}
88
+ - name: Run synthetic tests
89
+ run: python -m unittest discover -s tests -t . -v
90
+ - name: Check repository for secrets
91
+ run: python tools/check_secrets.py
92
+ - name: Check Git and private-data boundary
93
+ run: python tools/check_git_boundary.py
94
+ - name: Build wheel
95
+ run: python -m pip wheel . --wheel-dir "${RUNNER_TEMP}/wheel"
96
+
97
+ coverage:
98
+ name: Coverage
99
+ runs-on: ubuntu-latest
100
+ timeout-minutes: 20
101
+
102
+ steps:
103
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
104
+ - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
105
+ with:
106
+ python-version: "3.13"
107
+ # `tools/coverage.py` is dependency-free and traces the child processes
108
+ # the suite starts, which is most of it. Thresholds live in that file and
109
+ # a shortfall fails this job.
110
+ - name: Measure statement coverage
111
+ run: python tools/coverage.py --json "${RUNNER_TEMP}/coverage.json"
112
+
113
+ sdist:
114
+ name: Source-distribution acceptance
115
+ runs-on: ubuntu-latest
116
+ timeout-minutes: 20
117
+
118
+ steps:
119
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
120
+ - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
121
+ with:
122
+ python-version: "3.13"
123
+ - name: Install build frontend
124
+ run: python -m pip install build==1.5.1
125
+ - name: Build source distribution
126
+ run: python -m build --sdist --outdir dist
127
+ # The sdist is the artifact a distribution packager rebuilds and tests
128
+ # from. Running the suite inside the unpacked archive is the only check
129
+ # that catches a file MANIFEST.in forgot -- `tests/__init__.py` was
130
+ # missing once, and nothing outside this job noticed.
131
+ - name: Run the suite from the unpacked source distribution
132
+ run: |
133
+ mkdir -p "${RUNNER_TEMP}/sdist"
134
+ tar xzf dist/noetrail-*.tar.gz -C "${RUNNER_TEMP}/sdist"
135
+ cd "${RUNNER_TEMP}/sdist"/noetrail-*/
136
+ python -m unittest discover -s tests -t . -v
137
+
138
+ installed-wheel:
139
+ name: Installed-wheel acceptance
140
+ runs-on: ubuntu-latest
141
+ timeout-minutes: 20
142
+
143
+ steps:
144
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
145
+ - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
146
+ with:
147
+ python-version: "3.13"
148
+ - name: Build wheel
149
+ run: python -m pip wheel . --no-deps --wheel-dir dist
150
+ - name: Install and exercise the wheel
151
+ run: |
152
+ python tools/release_acceptance.py \
153
+ --wheel "$(find dist -name 'noetrail-*.whl' -print -quit)"
@@ -0,0 +1,53 @@
1
+ name: CodeQL
2
+
3
+ # Static analysis on the Python sources. Runs on the same events as CI plus a
4
+ # weekly schedule, because CodeQL queries are updated independently of this
5
+ # repository and a finding can appear without any commit here.
6
+ on:
7
+ push:
8
+ branches: [main]
9
+ pull_request:
10
+ branches: [main]
11
+ schedule:
12
+ - cron: "17 5 * * 1"
13
+
14
+ concurrency:
15
+ group: codeql-${{ github.ref }}
16
+ cancel-in-progress: true
17
+
18
+ permissions:
19
+ contents: read
20
+
21
+ # Third-party actions are pinned to a commit SHA. A mutable major tag can be
22
+ # repointed at new code without any change in this repository, so the version
23
+ # in the trailing comment is documentation only.
24
+ jobs:
25
+ analyze:
26
+ name: Analyze Python
27
+ runs-on: ubuntu-latest
28
+ timeout-minutes: 20
29
+ # Code scanning needs GitHub Advanced Security on a private repository; on
30
+ # a personal plan CodeQL is only free for public ones. Without it the job
31
+ # fails during init with a permissions error rather than a finding, which
32
+ # is noise on every pull request and would block a required check for a
33
+ # reason that has nothing to do with the code. Skipping while private
34
+ # keeps the workflow honest: it starts analysing by itself the moment the
35
+ # repository is published, with no change here.
36
+ if: github.event.repository.private == false
37
+ permissions:
38
+ # Writing the results into the repository's code-scanning view is the
39
+ # only extra permission this job needs.
40
+ security-events: write
41
+
42
+ steps:
43
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
44
+ - name: Initialize CodeQL
45
+ uses: github/codeql-action/init@2892aa5e19bbd11bc0cff5427e3b750a04d9e3c2 # v4.38.2
46
+ with:
47
+ languages: python
48
+ build-mode: none
49
+ queries: security-and-quality
50
+ - name: Perform CodeQL analysis
51
+ uses: github/codeql-action/analyze@2892aa5e19bbd11bc0cff5427e3b750a04d9e3c2 # v4.38.2
52
+ with:
53
+ category: "/language:python"
@@ -0,0 +1,49 @@
1
+ name: Publish ZeroClaw candidate
2
+
3
+ on:
4
+ workflow_run:
5
+ workflows: [CI]
6
+ types: [completed]
7
+ branches: [main]
8
+
9
+ permissions:
10
+ contents: read
11
+
12
+ concurrency:
13
+ group: zeroclaw-candidate
14
+ cancel-in-progress: false
15
+
16
+ jobs:
17
+ candidate:
18
+ if: >-
19
+ github.event.workflow_run.conclusion == 'success' &&
20
+ github.event.workflow_run.event == 'push' &&
21
+ github.event.workflow_run.head_branch == 'main' &&
22
+ github.event.workflow_run.head_repository.full_name == github.repository
23
+ runs-on: ubuntu-latest
24
+ timeout-minutes: 5
25
+ permissions:
26
+ contents: write
27
+ steps:
28
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
29
+ with:
30
+ ref: ${{ github.event.workflow_run.head_sha }}
31
+ fetch-depth: 1
32
+ - name: Publish the tested main commit
33
+ env:
34
+ CANDIDATE_SHA: ${{ github.event.workflow_run.head_sha }}
35
+ run: |
36
+ set -euo pipefail
37
+ git fetch origin main
38
+ if [ "$(git rev-parse origin/main)" != "$CANDIDATE_SHA" ]; then
39
+ echo "A newer main commit exists; skip this candidate."
40
+ exit 0
41
+ fi
42
+ python3 tools/zeroclaw_candidate.py "$CANDIDATE_SHA" deploy/zeroclaw/candidate
43
+ git config user.name github-actions\[bot\]
44
+ git config user.email 41898282+github-actions\[bot\]@users.noreply.github.com
45
+ git add deploy/zeroclaw/candidate
46
+ git commit -m "ci: publish candidate $CANDIDATE_SHA"
47
+ # Only this generated branch is replaced; main remains PR-protected.
48
+ # Concurrency serializes publishers, and the main check rejects stale CI.
49
+ git push --force origin HEAD:refs/heads/deploy/test