flywheel-canon 0.2.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 (231) hide show
  1. flywheel_canon-0.2.0/CHANGELOG.md +42 -0
  2. flywheel_canon-0.2.0/LICENSE +110 -0
  3. flywheel_canon-0.2.0/MANIFEST.in +8 -0
  4. flywheel_canon-0.2.0/PKG-INFO +204 -0
  5. flywheel_canon-0.2.0/README.md +191 -0
  6. flywheel_canon-0.2.0/docs/art/canon-header.svg +1 -0
  7. flywheel_canon-0.2.0/docs/art/canon.art.json +234 -0
  8. flywheel_canon-0.2.0/docs/art/record-table.svg +17 -0
  9. flywheel_canon-0.2.0/docs/art/surface-lane.svg +19 -0
  10. flywheel_canon-0.2.0/docs/art/verdict-lane.svg +19 -0
  11. flywheel_canon-0.2.0/project-docs/F0-DECISIONS.md +63 -0
  12. flywheel_canon-0.2.0/project-docs/F0-DECLARED-DROPS.md +126 -0
  13. flywheel_canon-0.2.0/project-docs/F0-LAYERING.md +77 -0
  14. flywheel_canon-0.2.0/project-docs/F0-SCHEMA.md +92 -0
  15. flywheel_canon-0.2.0/project-docs/F0-SECTION-OWNERSHIP.md +65 -0
  16. flywheel_canon-0.2.0/project-docs/F1-BACKENDS.md +170 -0
  17. flywheel_canon-0.2.0/project-docs/F1-DECISIONS.md +93 -0
  18. flywheel_canon-0.2.0/project-docs/M4-CANON-CHECK.md +112 -0
  19. flywheel_canon-0.2.0/project-docs/M4-DECISIONS.md +539 -0
  20. flywheel_canon-0.2.0/project-docs/M4-EXPANDED-SCOPE-PROPOSAL-20260831.md +1067 -0
  21. flywheel_canon-0.2.0/project-docs/M4-TRANSPORT.md +192 -0
  22. flywheel_canon-0.2.0/project-docs/M4-VAULT-READER.md +215 -0
  23. flywheel_canon-0.2.0/project-docs/M4-VERSIONS.md +276 -0
  24. flywheel_canon-0.2.0/project-docs/MCP-DECISIONS.md +102 -0
  25. flywheel_canon-0.2.0/project-docs/R0-DECISIONS.md +117 -0
  26. flywheel_canon-0.2.0/project-docs/R1-DECISIONS.md +131 -0
  27. flywheel_canon-0.2.0/project-docs/R2-DECISIONS.md +285 -0
  28. flywheel_canon-0.2.0/project-docs/V2-DECISIONS.md +121 -0
  29. flywheel_canon-0.2.0/project-docs/V3-DECISIONS.md +169 -0
  30. flywheel_canon-0.2.0/project-docs/V4-DECISIONS.md +378 -0
  31. flywheel_canon-0.2.0/pyproject.toml +28 -0
  32. flywheel_canon-0.2.0/setup.cfg +4 -0
  33. flywheel_canon-0.2.0/src/canon/__init__.py +188 -0
  34. flywheel_canon-0.2.0/src/canon/__main__.py +9 -0
  35. flywheel_canon-0.2.0/src/canon/adapter.py +275 -0
  36. flywheel_canon-0.2.0/src/canon/atom.py +299 -0
  37. flywheel_canon-0.2.0/src/canon/backends/__init__.py +67 -0
  38. flywheel_canon-0.2.0/src/canon/backends/base.py +160 -0
  39. flywheel_canon-0.2.0/src/canon/backends/files.py +67 -0
  40. flywheel_canon-0.2.0/src/canon/backends/flywheel.py +77 -0
  41. flywheel_canon-0.2.0/src/canon/backends/mneme.py +177 -0
  42. flywheel_canon-0.2.0/src/canon/backends/sqlite.py +107 -0
  43. flywheel_canon-0.2.0/src/canon/blocks.py +102 -0
  44. flywheel_canon-0.2.0/src/canon/bootstrap.py +136 -0
  45. flywheel_canon-0.2.0/src/canon/bootstrap_report.py +145 -0
  46. flywheel_canon-0.2.0/src/canon/bootstrap_runtime.py +227 -0
  47. flywheel_canon-0.2.0/src/canon/bootstrap_runtime_cache.py +263 -0
  48. flywheel_canon-0.2.0/src/canon/bootstrap_runtime_error.py +10 -0
  49. flywheel_canon-0.2.0/src/canon/bootstrap_runtime_inputs.py +171 -0
  50. flywheel_canon-0.2.0/src/canon/bootstrap_sources.py +298 -0
  51. flywheel_canon-0.2.0/src/canon/bootstrap_state_root.py +193 -0
  52. flywheel_canon-0.2.0/src/canon/bootstrap_validation.py +248 -0
  53. flywheel_canon-0.2.0/src/canon/bootstrap_witness_store.py +274 -0
  54. flywheel_canon-0.2.0/src/canon/bootstrap_witness_store_posix.py +148 -0
  55. flywheel_canon-0.2.0/src/canon/canon_check.py +140 -0
  56. flywheel_canon-0.2.0/src/canon/canonical_json.py +62 -0
  57. flywheel_canon-0.2.0/src/canon/canonmd.py +287 -0
  58. flywheel_canon-0.2.0/src/canon/canonpack.py +298 -0
  59. flywheel_canon-0.2.0/src/canon/capsule.py +46 -0
  60. flywheel_canon-0.2.0/src/canon/capsule_build.py +130 -0
  61. flywheel_canon-0.2.0/src/canon/capsule_rules.py +106 -0
  62. flywheel_canon-0.2.0/src/canon/capsule_types.py +279 -0
  63. flywheel_canon-0.2.0/src/canon/capsule_validation.py +238 -0
  64. flywheel_canon-0.2.0/src/canon/cli.py +216 -0
  65. flywheel_canon-0.2.0/src/canon/cli_artifacts.py +226 -0
  66. flywheel_canon-0.2.0/src/canon/cli_compile.py +295 -0
  67. flywheel_canon-0.2.0/src/canon/cli_export.py +275 -0
  68. flywheel_canon-0.2.0/src/canon/cli_export_support.py +62 -0
  69. flywheel_canon-0.2.0/src/canon/cli_format.py +247 -0
  70. flywheel_canon-0.2.0/src/canon/cli_init.py +270 -0
  71. flywheel_canon-0.2.0/src/canon/cli_parser.py +170 -0
  72. flywheel_canon-0.2.0/src/canon/cli_publish.py +300 -0
  73. flywheel_canon-0.2.0/src/canon/cli_rescue.py +297 -0
  74. flywheel_canon-0.2.0/src/canon/client_capture.py +225 -0
  75. flywheel_canon-0.2.0/src/canon/client_capture_payload.py +161 -0
  76. flywheel_canon-0.2.0/src/canon/concurrency.py +58 -0
  77. flywheel_canon-0.2.0/src/canon/concurrency_capability.py +84 -0
  78. flywheel_canon-0.2.0/src/canon/concurrency_errors.py +7 -0
  79. flywheel_canon-0.2.0/src/canon/concurrency_lock.py +212 -0
  80. flywheel_canon-0.2.0/src/canon/concurrency_lock_backend.py +192 -0
  81. flywheel_canon-0.2.0/src/canon/concurrency_posix.py +70 -0
  82. flywheel_canon-0.2.0/src/canon/concurrency_windows.py +123 -0
  83. flywheel_canon-0.2.0/src/canon/concurrency_windows_api.py +273 -0
  84. flywheel_canon-0.2.0/src/canon/context_mcp.py +145 -0
  85. flywheel_canon-0.2.0/src/canon/context_query.py +197 -0
  86. flywheel_canon-0.2.0/src/canon/context_records.py +90 -0
  87. flywheel_canon-0.2.0/src/canon/context_related.py +111 -0
  88. flywheel_canon-0.2.0/src/canon/context_store.py +234 -0
  89. flywheel_canon-0.2.0/src/canon/doctor.py +224 -0
  90. flywheel_canon-0.2.0/src/canon/drift.py +134 -0
  91. flywheel_canon-0.2.0/src/canon/exit_codes.py +50 -0
  92. flywheel_canon-0.2.0/src/canon/export_output.py +87 -0
  93. flywheel_canon-0.2.0/src/canon/fidelity.py +235 -0
  94. flywheel_canon-0.2.0/src/canon/frontmatter.py +127 -0
  95. flywheel_canon-0.2.0/src/canon/import_policy.py +298 -0
  96. flywheel_canon-0.2.0/src/canon/import_review.py +247 -0
  97. flywheel_canon-0.2.0/src/canon/import_review_safety.py +147 -0
  98. flywheel_canon-0.2.0/src/canon/layering.py +123 -0
  99. flywheel_canon-0.2.0/src/canon/local_mcp.py +252 -0
  100. flywheel_canon-0.2.0/src/canon/omission.py +131 -0
  101. flywheel_canon-0.2.0/src/canon/path_policy.py +249 -0
  102. flywheel_canon-0.2.0/src/canon/persona_thesis.py +189 -0
  103. flywheel_canon-0.2.0/src/canon/readiness.py +298 -0
  104. flywheel_canon-0.2.0/src/canon/reconcile.py +269 -0
  105. flywheel_canon-0.2.0/src/canon/reconcile_gate.py +107 -0
  106. flywheel_canon-0.2.0/src/canon/reconcile_run.py +172 -0
  107. flywheel_canon-0.2.0/src/canon/region.py +151 -0
  108. flywheel_canon-0.2.0/src/canon/registry.py +183 -0
  109. flywheel_canon-0.2.0/src/canon/replay.py +103 -0
  110. flywheel_canon-0.2.0/src/canon/rescue.py +81 -0
  111. flywheel_canon-0.2.0/src/canon/rescue_artifacts.py +117 -0
  112. flywheel_canon-0.2.0/src/canon/rescue_output.py +122 -0
  113. flywheel_canon-0.2.0/src/canon/retention.py +272 -0
  114. flywheel_canon-0.2.0/src/canon/retention_receipts.py +110 -0
  115. flywheel_canon-0.2.0/src/canon/retention_safety.py +62 -0
  116. flywheel_canon-0.2.0/src/canon/schema.py +214 -0
  117. flywheel_canon-0.2.0/src/canon/secret_quarantine.py +256 -0
  118. flywheel_canon-0.2.0/src/canon/source_safe_read.py +300 -0
  119. flywheel_canon-0.2.0/src/canon/source_state.py +119 -0
  120. flywheel_canon-0.2.0/src/canon/source_state_cache.py +300 -0
  121. flywheel_canon-0.2.0/src/canon/surface.py +54 -0
  122. flywheel_canon-0.2.0/src/canon/textblock.py +252 -0
  123. flywheel_canon-0.2.0/src/canon/textutil.py +36 -0
  124. flywheel_canon-0.2.0/src/canon/transform.py +168 -0
  125. flywheel_canon-0.2.0/src/canon/transport/__init__.py +56 -0
  126. flywheel_canon-0.2.0/src/canon/transport/base.py +300 -0
  127. flywheel_canon-0.2.0/src/canon/transport/capabilities.py +67 -0
  128. flywheel_canon-0.2.0/src/canon/undo.py +81 -0
  129. flywheel_canon-0.2.0/src/canon/undo_io.py +279 -0
  130. flywheel_canon-0.2.0/src/canon/undo_posix.py +113 -0
  131. flywheel_canon-0.2.0/src/canon/undo_posix_core.py +184 -0
  132. flywheel_canon-0.2.0/src/canon/undo_posix_files.py +218 -0
  133. flywheel_canon-0.2.0/src/canon/undo_receipts.py +210 -0
  134. flywheel_canon-0.2.0/src/canon/validator.py +191 -0
  135. flywheel_canon-0.2.0/src/canon/vault.py +296 -0
  136. flywheel_canon-0.2.0/src/canon/vault_fidelity.py +147 -0
  137. flywheel_canon-0.2.0/src/canon/vault_mirror.py +300 -0
  138. flywheel_canon-0.2.0/src/canon/vault_read_fidelity.py +153 -0
  139. flywheel_canon-0.2.0/src/canon/vault_reader.py +299 -0
  140. flywheel_canon-0.2.0/src/canon/versions.py +306 -0
  141. flywheel_canon-0.2.0/src/canon/versions_migrate.py +133 -0
  142. flywheel_canon-0.2.0/src/canon/witness.py +297 -0
  143. flywheel_canon-0.2.0/src/canon/writing_gate.py +95 -0
  144. flywheel_canon-0.2.0/src/flywheel_canon.egg-info/PKG-INFO +204 -0
  145. flywheel_canon-0.2.0/src/flywheel_canon.egg-info/SOURCES.txt +229 -0
  146. flywheel_canon-0.2.0/src/flywheel_canon.egg-info/dependency_links.txt +1 -0
  147. flywheel_canon-0.2.0/src/flywheel_canon.egg-info/entry_points.txt +2 -0
  148. flywheel_canon-0.2.0/src/flywheel_canon.egg-info/requires.txt +3 -0
  149. flywheel_canon-0.2.0/src/flywheel_canon.egg-info/top_level.txt +1 -0
  150. flywheel_canon-0.2.0/tests/fixtures/bootstrap/atoms.jsonl +4 -0
  151. flywheel_canon-0.2.0/tests/fixtures/bootstrap/readiness_fail_missing_goal.json +22 -0
  152. flywheel_canon-0.2.0/tests/fixtures/bootstrap/readiness_pass.json +22 -0
  153. flywheel_canon-0.2.0/tests/fixtures/bootstrap/records.jsonl +1 -0
  154. flywheel_canon-0.2.0/tests/fixtures/bootstrap/secret_atoms.jsonl +1 -0
  155. flywheel_canon-0.2.0/tests/fixtures/foundation/CANON.expected.md +70 -0
  156. flywheel_canon-0.2.0/tests/fixtures/foundation/adapter_a2a_artifact_guided.json +1 -0
  157. flywheel_canon-0.2.0/tests/fixtures/foundation/adapter_codex_cli_native_advisory.json +1 -0
  158. flywheel_canon-0.2.0/tests/fixtures/foundation/adapter_mcp_readonly_guided.json +1 -0
  159. flywheel_canon-0.2.0/tests/fixtures/foundation/atom_active_goal.json +1 -0
  160. flywheel_canon-0.2.0/tests/fixtures/foundation/atom_conflict.json +1 -0
  161. flywheel_canon-0.2.0/tests/fixtures/foundation/atom_constraint.json +1 -0
  162. flywheel_canon-0.2.0/tests/fixtures/foundation/atom_frontier_state.json +1 -0
  163. flywheel_canon-0.2.0/tests/fixtures/foundation/atom_permission.json +1 -0
  164. flywheel_canon-0.2.0/tests/fixtures/foundation/atom_prohibition.json +1 -0
  165. flywheel_canon-0.2.0/tests/fixtures/foundation/atom_unknown.json +1 -0
  166. flywheel_canon-0.2.0/tests/fixtures/foundation/bootstrap_witness_pass.json +1 -0
  167. flywheel_canon-0.2.0/tests/fixtures/foundation/capsule_handoff_full.json +1 -0
  168. flywheel_canon-0.2.0/tests/fixtures/foundation/capsule_minimal_needle.json +1 -0
  169. flywheel_canon-0.2.0/tests/fixtures/foundation/omission_budget_noncritical.json +1 -0
  170. flywheel_canon-0.2.0/tests/fixtures/foundation/readiness_probe.json +1 -0
  171. flywheel_canon-0.2.0/tests/fixtures/foundation/transform_summary.json +1 -0
  172. flywheel_canon-0.2.0/tests/fixtures/layering_expected.json +12 -0
  173. flywheel_canon-0.2.0/tests/fixtures/layering_pool.json +56 -0
  174. flywheel_canon-0.2.0/tests/fixtures/records/adr_decision.json +29 -0
  175. flywheel_canon-0.2.0/tests/fixtures/records/episodic_memory.json +26 -0
  176. flywheel_canon-0.2.0/tests/fixtures/records/personality_block.json +23 -0
  177. flywheel_canon-0.2.0/tests/fixtures/records/research_artifact_ref.json +22 -0
  178. flywheel_canon-0.2.0/tests/fixtures/records/synthesized_persona_l3.json +26 -0
  179. flywheel_canon-0.2.0/tests/test_backend_base.py +140 -0
  180. flywheel_canon-0.2.0/tests/test_blocks.py +181 -0
  181. flywheel_canon-0.2.0/tests/test_canon_check.py +247 -0
  182. flywheel_canon-0.2.0/tests/test_client_capture.py +413 -0
  183. flywheel_canon-0.2.0/tests/test_concurrency.py +1045 -0
  184. flywheel_canon-0.2.0/tests/test_context_identifier_query.py +210 -0
  185. flywheel_canon-0.2.0/tests/test_context_mcp.py +268 -0
  186. flywheel_canon-0.2.0/tests/test_context_related_events.py +207 -0
  187. flywheel_canon-0.2.0/tests/test_context_store.py +276 -0
  188. flywheel_canon-0.2.0/tests/test_context_store_identity.py +227 -0
  189. flywheel_canon-0.2.0/tests/test_declared_drops.py +91 -0
  190. flywheel_canon-0.2.0/tests/test_doctor_cli.py +471 -0
  191. flywheel_canon-0.2.0/tests/test_drift.py +227 -0
  192. flywheel_canon-0.2.0/tests/test_export_rescue_cli.py +797 -0
  193. flywheel_canon-0.2.0/tests/test_fidelity.py +264 -0
  194. flywheel_canon-0.2.0/tests/test_files_backend.py +79 -0
  195. flywheel_canon-0.2.0/tests/test_flywheel_backend.py +90 -0
  196. flywheel_canon-0.2.0/tests/test_frontmatter.py +134 -0
  197. flywheel_canon-0.2.0/tests/test_import_policy.py +401 -0
  198. flywheel_canon-0.2.0/tests/test_import_review.py +441 -0
  199. flywheel_canon-0.2.0/tests/test_layering.py +157 -0
  200. flywheel_canon-0.2.0/tests/test_local_mcp.py +236 -0
  201. flywheel_canon-0.2.0/tests/test_mcp_check.py +76 -0
  202. flywheel_canon-0.2.0/tests/test_mneme_backend.py +207 -0
  203. flywheel_canon-0.2.0/tests/test_orchestration.py +220 -0
  204. flywheel_canon-0.2.0/tests/test_persona_thesis.py +307 -0
  205. flywheel_canon-0.2.0/tests/test_reconcile.py +636 -0
  206. flywheel_canon-0.2.0/tests/test_reconcile_gate.py +149 -0
  207. flywheel_canon-0.2.0/tests/test_reconcile_run.py +445 -0
  208. flywheel_canon-0.2.0/tests/test_region.py +172 -0
  209. flywheel_canon-0.2.0/tests/test_registry.py +159 -0
  210. flywheel_canon-0.2.0/tests/test_replay.py +194 -0
  211. flywheel_canon-0.2.0/tests/test_repo_art.py +282 -0
  212. flywheel_canon-0.2.0/tests/test_retention.py +461 -0
  213. flywheel_canon-0.2.0/tests/test_schema_roundtrip.py +111 -0
  214. flywheel_canon-0.2.0/tests/test_selective_continuity_cli.py +306 -0
  215. flywheel_canon-0.2.0/tests/test_soul.py +142 -0
  216. flywheel_canon-0.2.0/tests/test_source_safe_read.py +95 -0
  217. flywheel_canon-0.2.0/tests/test_sqlite_backend.py +93 -0
  218. flywheel_canon-0.2.0/tests/test_surface.py +153 -0
  219. flywheel_canon-0.2.0/tests/test_textblock.py +334 -0
  220. flywheel_canon-0.2.0/tests/test_textutil.py +161 -0
  221. flywheel_canon-0.2.0/tests/test_transport_base.py +292 -0
  222. flywheel_canon-0.2.0/tests/test_transport_conformance.py +216 -0
  223. flywheel_canon-0.2.0/tests/test_validator.py +164 -0
  224. flywheel_canon-0.2.0/tests/test_vault.py +321 -0
  225. flywheel_canon-0.2.0/tests/test_vault_fidelity.py +92 -0
  226. flywheel_canon-0.2.0/tests/test_vault_mirror.py +408 -0
  227. flywheel_canon-0.2.0/tests/test_vault_reader.py +409 -0
  228. flywheel_canon-0.2.0/tests/test_vault_reader_fidelity.py +106 -0
  229. flywheel_canon-0.2.0/tests/test_versions.py +383 -0
  230. flywheel_canon-0.2.0/tests/test_versions_migrate.py +211 -0
  231. flywheel_canon-0.2.0/tests/test_writing_gate.py +134 -0
@@ -0,0 +1,42 @@
1
+ # Changelog
2
+
3
+ ## 0.2.0 - 2026-09-22
4
+
5
+ - Publishes to PyPI as `flywheel-canon`. The bare name `canon` belongs to an
6
+ unrelated project, so the distribution carries the prefix while the console
7
+ script stays `canon`.
8
+ - Adds an OIDC trusted-publishing release workflow with tag/version, artifact
9
+ digest, clean-venv entry-point resolution, and sdist-rebuild gates.
10
+ - Adds run-lock concurrency control, and fixes POSIX run-lock descriptor release.
11
+ - Adds doctor diagnostics, retention planning, replay checks, rescue handoff, and
12
+ an import review policy.
13
+ - Hardens Canon source reads.
14
+
15
+ ## 0.1.0 — 2026-09-07
16
+
17
+ First GitHub release for Canon.
18
+
19
+ - Keeps the existing read-only MCP surface: `canon.status`, `canon.doctor`,
20
+ `canon.blocks`, `canon.render`, `canon.validate`, and `canon.check`.
21
+ - Adds provider-neutral continuity preview and export from explicit
22
+ `records.jsonl` and `atoms.jsonl` inputs.
23
+ - Exports Canon Markdown, capsule JSON, readiness JSON, or a three-file bundle
24
+ containing `CANON.md`, `canon.capsule.json`, and `readiness-probe.json`.
25
+ - Records source-state hashes, artifact hashes, target tier, omissions, and
26
+ does-not-prove limits in the generated capsule outputs.
27
+ - Uses confined bundle publication or fails closed. On Windows, the final bundle
28
+ directory rename is parent-handle-relative and leaf-only.
29
+
30
+ Limits:
31
+
32
+ - Canon does not import ChatGPT web conversations, Codex task databases, Claude
33
+ web history, Claude Code sessions, provider auth caches, or credentials.
34
+ - The `codex-cli` and `claude-code` targets are native-advisory. App and web
35
+ targets remain guided until their hosts provide stronger startup evidence.
36
+ - Bundle export proves the command's publication boundary, not immutability
37
+ after the command returns.
38
+ - New bundle creation currently requires the supported Windows native backend.
39
+ Linux and macOS refuse new bundle creation without writing. Preview and stdout
40
+ exports remain available there.
41
+ - Release downloads are distributed through GitHub. No PyPI publication claim
42
+ is made.
@@ -0,0 +1,110 @@
1
+ # Functional Source License, Version 1.1, MIT Future License
2
+
3
+ ## Abbreviation
4
+
5
+ FSL-1.1-MIT
6
+
7
+ ## Notice
8
+
9
+ Copyright 2026 Zain Dana Harper
10
+
11
+ ## Terms and Conditions
12
+
13
+ ### Licensor ("We")
14
+
15
+ The party offering the Software under these Terms and Conditions.
16
+
17
+ ### The Software
18
+
19
+ The "Software" is each version of the software that we make available under
20
+ these Terms and Conditions, as indicated by our inclusion of these Terms and
21
+ Conditions with the Software.
22
+
23
+ ### License Grant
24
+
25
+ Subject to your compliance with this License Grant and the Patents,
26
+ Redistribution and Trademark clauses below, we hereby grant you the right to
27
+ use, copy, modify, create derivative works, publicly perform, publicly display
28
+ and redistribute the Software for any Permitted Purpose identified below.
29
+
30
+ ### Permitted Purpose
31
+
32
+ A Permitted Purpose is any purpose other than a Competing Use. A Competing Use
33
+ means making the Software available to others in a commercial product or
34
+ service that:
35
+
36
+ 1. substitutes for the Software;
37
+
38
+ 2. substitutes for any other product or service we offer using the Software
39
+ that exists as of the date we make the Software available; or
40
+
41
+ 3. offers the same or substantially similar functionality as the Software.
42
+
43
+ Permitted Purposes specifically include using the Software:
44
+
45
+ 1. for your internal use and access;
46
+
47
+ 2. for non-commercial education;
48
+
49
+ 3. for non-commercial research; and
50
+
51
+ 4. in connection with professional services that you provide to a licensee
52
+ using the Software in accordance with these Terms and Conditions.
53
+
54
+ ### Patents
55
+
56
+ To the extent your use for a Permitted Purpose would necessarily infringe our
57
+ patents, the license grant above includes a license under our patents. If you
58
+ make a claim against any party that the Software infringes or contributes to
59
+ the infringement of any patent, then your patent license to the Software ends
60
+ immediately.
61
+
62
+ ### Redistribution
63
+
64
+ The Terms and Conditions apply to all copies, modifications and derivatives of
65
+ the Software.
66
+
67
+ If you redistribute any copies, modifications or derivatives of the Software,
68
+ you must include a copy of or a link to these Terms and Conditions and not
69
+ remove any copyright notices provided in or with the Software.
70
+
71
+ ### Disclaimer
72
+
73
+ THE SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTIES OF ANY KIND, EXPRESS OR
74
+ IMPLIED, INCLUDING WITHOUT LIMITATION WARRANTIES OF FITNESS FOR A PARTICULAR
75
+ PURPOSE, MERCHANTABILITY, TITLE OR NON-INFRINGEMENT.
76
+
77
+ IN NO EVENT WILL WE HAVE ANY LIABILITY TO YOU ARISING OUT OF OR RELATED TO THE
78
+ SOFTWARE, INCLUDING INDIRECT, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES,
79
+ EVEN IF WE HAVE BEEN INFORMED OF THEIR POSSIBILITY IN ADVANCE.
80
+
81
+ ### Trademarks
82
+
83
+ Except for displaying the License Details and identifying us as the origin of
84
+ the Software, you have no right under these Terms and Conditions to use our
85
+ trademarks, trade names, service marks or product names.
86
+
87
+ ## Grant of Future License
88
+
89
+ We hereby irrevocably grant you an additional license to use the Software under
90
+ the MIT license that is effective on the second anniversary of the date we make
91
+ the Software available. On or after that date, you may use the Software under
92
+ the MIT license, in which case the following will apply:
93
+
94
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
95
+ this software and associated documentation files (the "Software"), to deal in
96
+ the Software without restriction, including without limitation the rights to
97
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
98
+ of the Software, and to permit persons to whom the Software is furnished to do
99
+ so, subject to the following conditions:
100
+
101
+ The above copyright notice and this permission notice shall be included in all
102
+ copies or substantial portions of the Software.
103
+
104
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
105
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
106
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
107
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
108
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
109
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
110
+ SOFTWARE.
@@ -0,0 +1,8 @@
1
+ include CHANGELOG.md
2
+ recursive-include docs/art *.json *.svg
3
+ # Ship format specifications and implementation decisions, not historical audits.
4
+ include project-docs/F*.md
5
+ include project-docs/R*.md
6
+ include project-docs/V*.md
7
+ include project-docs/M*.md
8
+ recursive-include tests/fixtures *
@@ -0,0 +1,204 @@
1
+ Metadata-Version: 2.4
2
+ Name: flywheel-canon
3
+ Version: 0.2.0
4
+ Summary: A provider-neutral memory-bank, personality container, and continuity capsule CLI.
5
+ Author: HarperZ9
6
+ License-Expression: LicenseRef-FSL-1.1-MIT
7
+ Requires-Python: >=3.11
8
+ Description-Content-Type: text/markdown
9
+ License-File: LICENSE
10
+ Provides-Extra: dev
11
+ Requires-Dist: pytest>=8; extra == "dev"
12
+ Dynamic: license-file
13
+
14
+ # canon
15
+
16
+ One record for your memory bank and your personality, shared across every model
17
+ and every tool.
18
+
19
+ ![canon: one memory record, rendered into every tool's own file. Own one region of the file. Leave every byte outside it alone.](docs/art/canon-header.svg)
20
+
21
+ You keep the same working relationship whether you open Claude Code, Claude CLI,
22
+ ChatGPT, Codex, or a web surface: the same authored voice, the same accumulated
23
+ memory, the same decisions. Today that lives in a dozen files with a dozen
24
+ shapes (`CLAUDE.md`, `AGENTS.md`, `SOUL.md`, `GEMINI.md`) plus per-tool memory
25
+ stores that do not talk to each other. canon gives all of them one typed record
26
+ to draw from and write back to, and renders each tool's file from that record.
27
+
28
+ ## What it does
29
+
30
+ - **One envelope, five kinds.** An authored personality block, a raw or extracted
31
+ memory, a synthesized persona, a decision record, and a reference to an
32
+ external research artifact all share one record shape with a provenance
33
+ receipt on every entry.
34
+ - **Two scopes that layer.** A `global` block is your default everywhere; a
35
+ `workspace` block with the same id overrides it where that workspace applies.
36
+ A render resolves the effective set for its target, current entries only.
37
+ - **Deterministic by construction.** Ordering uses a clock-free ordinal, so a
38
+ rebuild from the same records is byte-identical. The wall clock is kept only
39
+ as a non-authoritative convenience.
40
+ - **An assembly, not a rewrite.** canon aims at proven engines rather than
41
+ replacing them: a memory fact-engine, an authored-block store, and a
42
+ cross-provider transport. It adds the one record they share and the renderer
43
+ that projects each surface.
44
+
45
+ ## How one record becomes the file each tool reads
46
+
47
+ ![Eight stages taking one record to the file a tool reads: record, validate, layer, resolve, render, region, allow-list, write. Every entry is one envelope in one of five kinds: an authored personality block, an episodic memory, a synthesized persona, a decision record, and a reference to an external research artifact. The validator checks every field and refuses a record it cannot vouch for. A workspace block overrides a global block carrying the same id, and the resolve step keeps current entries only, ordered by a clock-free ordinal so a rebuild is byte-identical. The block set is rendered to text and spliced into the span between the canon begin and end markers, and every byte outside that span is preserved. The write allow-list holds four surfaces: a global and a workspace file for Claude Code, an AGENTS.md for Codex, and a workspace SOUL.md for Hermes. A path outside that list is refused, and so is a file with no canon region. Three outcomes: written inside the markers canon owns, a surface that drifted and needs a human, and a file canon declines to write at all.](docs/art/surface-lane.svg)
48
+
49
+ canon writes four paths and no others, and inside those four it rewrites only
50
+ the span between its own markers. A file with no canon region is left alone.
51
+
52
+ ## How a rendered file is checked back against the record
53
+
54
+ ![Eight stages checking a rendered file back against its record: read, extract, ingest, canonical, compare, drops, legs, verdict. The file is read as it sits on disk and the region between the canon markers is extracted byte exactly. The region text is ingested back into records, each reduced to one canonical form so the comparison is against a single shape rather than a formatting accident. The rendered form and the ingested form are compared field by field. Every field that failed to survive is classified against the losses that storage adapter declared in advance, and a loss nobody declared is a refusal. The aggregate check folds four legs: surface drift, the vault round-trip, the vault read symmetry, and the persona assessment. A leg whose seam is not wired reports nothing and does not affect the result. The verdict is one exit code, zero when every wired leg passed and one otherwise, and all four gate functions in the codebase share that signature so a build keys on them the same way. Three outcomes: the record survives the file, a declared drop that was named in advance, and a refusal that returns a nonzero code.](docs/art/verdict-lane.svg)
55
+
56
+ A round-trip that loses a field passes only when the adapter declared that loss
57
+ in advance. Anything else fails the gate rather than logging a warning.
58
+
59
+ ## What canon carries
60
+
61
+ ![A table of twelve rows: what canon carries, how many of it there are, and where each number is read from. Five record kinds share one envelope. Two scopes layer, workspace over global. Four surfaces sit on the write allow-list: a global and a workspace file for Claude Code, an AGENTS.md for Codex, and a workspace SOUL.md for Hermes. Four storage adapters implement the backend protocol, and five capability tokens describe what each one can carry. Sixteen schema pins name the seams that carry a version. The aggregate check folds four legs, and four gate functions share the same zero or one exit code. 111 source modules hold 19,731 lines, and 53 test files hold 1061 tests. Two surfaces named in the roadmap are absent from the catalog, a global SOUL.md and a GEMINI.md, so canon does not render them.](docs/art/record-table.svg)
62
+
63
+ Every count is asserted against the module that defines it in
64
+ `tests/test_repo_art.py`.
65
+
66
+ ## Status
67
+
68
+ F0 is the record of record: the canonical schema, its validator, and the
69
+ per-scope layering. F1 adds the storage seam: a `MemoryBackend` protocol with
70
+ capability tokens and four adapters, among them a zero-drop SQLite reference and
71
+ injected-handle adapters for a memory fact-engine and an authored-block store.
72
+ R0 adds the block round-trip gate: a byte-exact region boundary inside a managed
73
+ file, a record-to-text renderer and its inverse, and a go/no-go verdict that
74
+ proves a block set round-trips to its canonical form with every dropped field
75
+ declared.
76
+
77
+ R1 renders your files from the record. It resolves the block set for a file's
78
+ scope and rewrites only the region canon owns, every byte outside it preserved.
79
+ It writes only a fixed allow-list of files, and only a file you have opted in
80
+ with a canon region. Where a tool reads both a global and a workspace file, the
81
+ workspace file carries just your workspace blocks, so a shared block is never
82
+ duplicated; where a tool reads one file, that file carries the full resolved set.
83
+
84
+ R2 mirrors your whole record set into an Obsidian vault. Each record becomes one
85
+ markdown note you can read, search, and link, and a MEMORY.md index lists them
86
+ all. The full record rides inside every note, so a rebuild is exact and editing a
87
+ note's prose never rewrites the record behind it. canon writes only inside its own
88
+ vault, never touches a file it did not write, and when you drop a record it
89
+ reports the note left behind rather than deleting it. R2 also adds SOUL.md to the
90
+ rendered surfaces.
91
+
92
+ V2 through V4 add the checks and the decision on top of them. A drift check
93
+ re-derives every managed surface and compares only the region canon owns, so
94
+ your own prose outside the markers is never flagged. A persona check reports
95
+ whether the memories behind a synthesized persona still resolve. V4 separates a
96
+ mechanical fast-forward from a conflict, writes the fast-forwards, and raises a
97
+ durable gate for anything a human should adjudicate.
98
+
99
+ A harness reaches all of this over MCP. `canon mcp` serves six read-only tools:
100
+ identity, a readiness diagnostic, the authored record set, the render for a
101
+ scope, the validator, and the aggregate check. Nothing on that server writes a
102
+ file. Reconcile stays a library call, because rewriting your instruction files
103
+ and raising a gate is an action with a person behind it.
104
+
105
+ The CLI can also compile a provider-neutral continuity capsule from two explicit
106
+ inputs: `records.jsonl` and `atoms.jsonl`. Preview reports artifact names,
107
+ target tier, readiness probe data, and source-state hashes without writing.
108
+ Export writes the same capsule as Canon Markdown, capsule JSON, readiness JSON,
109
+ or a three-file bundle. The capsule records omitted state as typed atoms or
110
+ transform omissions and says what the export does not prove, including host
111
+ enforcement. It does not import provider auth, private databases, ChatGPT web
112
+ state, or Claude web state.
113
+
114
+ Installing a region into a fresh file, the first migrator on the version seam,
115
+ and the global SOUL.md and GEMINI.md surfaces are later phases. Everything
116
+ shipped is proven by a full test suite and aims at the one envelope.
117
+
118
+ ## Run it
119
+
120
+ Canon 0.1.0 is prepared as a GitHub release candidate. Install from a reviewed
121
+ GitHub release asset after publication, or from a local wheel during review:
122
+
123
+ ```bash
124
+ python -m pip install canon-0.1.0-py3-none-any.whl
125
+ ```
126
+
127
+ No PyPI package ownership or publication is claimed here.
128
+
129
+ Serve the record set to a harness:
130
+
131
+ ```bash
132
+ canon mcp
133
+ ```
134
+
135
+ Ask canon what it believes, with no transport in the way:
136
+
137
+ ```bash
138
+ canon check
139
+ canon blocks
140
+ ```
141
+
142
+ `canon check` exits non-zero when a wired leg fails or the block pool is not the
143
+ authored set, so a build can key on it. Point it at your records with
144
+ `CANON_BLOCKS_DIR`, and at your files with `CANON_HOME` and `CANON_WORKSPACE`.
145
+
146
+ Preview and export a continuity capsule from explicit local inputs:
147
+
148
+ ```bash
149
+ canon --json preview --workspace . --records records.jsonl --atoms atoms.jsonl --target codex-cli
150
+ canon export --workspace . --records records.jsonl --atoms atoms.jsonl --target codex-cli --format canon-md
151
+ canon export --workspace . --records records.jsonl --atoms atoms.jsonl --target codex-cli --format capsule-json
152
+ canon --json export --workspace . --records records.jsonl --atoms atoms.jsonl --target codex-cli --format bundle --out bundle
153
+ ```
154
+
155
+ The `codex-cli` and `claude-code` targets are native-advisory surfaces. App and
156
+ web targets remain guided until their hosts provide stronger startup evidence.
157
+ Preview and stdout exports work across supported Python platforms. Creating a
158
+ new bundle currently requires Windows with the confined native writer. On Linux
159
+ and macOS, new bundle creation returns `unsafe_path` without writing; use stdout
160
+ export there. The Windows final directory rename is parent-handle-relative and
161
+ leaf-only. This bounds publication, not immutability after the command returns.
162
+
163
+ Run the suite:
164
+
165
+ ```bash
166
+ python -m pytest
167
+ ```
168
+
169
+ No runtime dependencies. Python 3.11 or newer.
170
+
171
+ ## Layout
172
+
173
+ ```
174
+ src/canon/
175
+ schema.py, validator.py, layering.py the record, its rules, per-scope resolve
176
+ backends/ the storage seam and four adapters
177
+ region.py, textblock.py, fidelity.py the byte boundary, the text codec, the gate
178
+ surface.py, registry.py the render composition, the write allow-list
179
+ frontmatter.py, vault.py the note frontmatter codec, the one-record note
180
+ vault_mirror.py, vault_fidelity.py the whole-vault mirror and its round-trip gate
181
+ drift.py, writing_gate.py the surface drift check, the injected prose gate
182
+ persona_thesis.py, canon_check.py the persona basis adapter, the aggregate check
183
+ reconcile*.py the fast-forward decision and its durable gate
184
+ blocks.py, local_mcp.py, cli.py the authored-block loader, the MCP door, the CLI
185
+ capsule*.py, atom.py, adapter.py the continuity capsule, atom and target contract
186
+ cli_compile.py, cli_export.py preview, stdout export and bundle export
187
+ cli_artifacts.py, cli_publish.py source hashes and confined artifact publishing
188
+ tests/ round-trip, validator, layering, backend,
189
+ fidelity, surface, orchestration, vault,
190
+ drift, reconcile, continuity, and artwork proofs
191
+ docs/art/ the drawings above and the spec they render from
192
+ project-docs/ the F0, F1, R0, R1, R2, V2, V3, V4, MCP decisions
193
+ ```
194
+
195
+ See `project-docs/` for the schema reference, the layering derivation, the
196
+ section-ownership contract, the declared drops each storage backend must
197
+ announce, and the decisions behind the round-trip, vault, drift and reconcile
198
+ gates.
199
+
200
+ ## License
201
+
202
+ FSL-1.1-MIT. Functional Source License, source-available now for any purpose
203
+ other than a competing product, and it converts to the MIT license two years
204
+ after each version is released. See `LICENSE`.
@@ -0,0 +1,191 @@
1
+ # canon
2
+
3
+ One record for your memory bank and your personality, shared across every model
4
+ and every tool.
5
+
6
+ ![canon: one memory record, rendered into every tool's own file. Own one region of the file. Leave every byte outside it alone.](docs/art/canon-header.svg)
7
+
8
+ You keep the same working relationship whether you open Claude Code, Claude CLI,
9
+ ChatGPT, Codex, or a web surface: the same authored voice, the same accumulated
10
+ memory, the same decisions. Today that lives in a dozen files with a dozen
11
+ shapes (`CLAUDE.md`, `AGENTS.md`, `SOUL.md`, `GEMINI.md`) plus per-tool memory
12
+ stores that do not talk to each other. canon gives all of them one typed record
13
+ to draw from and write back to, and renders each tool's file from that record.
14
+
15
+ ## What it does
16
+
17
+ - **One envelope, five kinds.** An authored personality block, a raw or extracted
18
+ memory, a synthesized persona, a decision record, and a reference to an
19
+ external research artifact all share one record shape with a provenance
20
+ receipt on every entry.
21
+ - **Two scopes that layer.** A `global` block is your default everywhere; a
22
+ `workspace` block with the same id overrides it where that workspace applies.
23
+ A render resolves the effective set for its target, current entries only.
24
+ - **Deterministic by construction.** Ordering uses a clock-free ordinal, so a
25
+ rebuild from the same records is byte-identical. The wall clock is kept only
26
+ as a non-authoritative convenience.
27
+ - **An assembly, not a rewrite.** canon aims at proven engines rather than
28
+ replacing them: a memory fact-engine, an authored-block store, and a
29
+ cross-provider transport. It adds the one record they share and the renderer
30
+ that projects each surface.
31
+
32
+ ## How one record becomes the file each tool reads
33
+
34
+ ![Eight stages taking one record to the file a tool reads: record, validate, layer, resolve, render, region, allow-list, write. Every entry is one envelope in one of five kinds: an authored personality block, an episodic memory, a synthesized persona, a decision record, and a reference to an external research artifact. The validator checks every field and refuses a record it cannot vouch for. A workspace block overrides a global block carrying the same id, and the resolve step keeps current entries only, ordered by a clock-free ordinal so a rebuild is byte-identical. The block set is rendered to text and spliced into the span between the canon begin and end markers, and every byte outside that span is preserved. The write allow-list holds four surfaces: a global and a workspace file for Claude Code, an AGENTS.md for Codex, and a workspace SOUL.md for Hermes. A path outside that list is refused, and so is a file with no canon region. Three outcomes: written inside the markers canon owns, a surface that drifted and needs a human, and a file canon declines to write at all.](docs/art/surface-lane.svg)
35
+
36
+ canon writes four paths and no others, and inside those four it rewrites only
37
+ the span between its own markers. A file with no canon region is left alone.
38
+
39
+ ## How a rendered file is checked back against the record
40
+
41
+ ![Eight stages checking a rendered file back against its record: read, extract, ingest, canonical, compare, drops, legs, verdict. The file is read as it sits on disk and the region between the canon markers is extracted byte exactly. The region text is ingested back into records, each reduced to one canonical form so the comparison is against a single shape rather than a formatting accident. The rendered form and the ingested form are compared field by field. Every field that failed to survive is classified against the losses that storage adapter declared in advance, and a loss nobody declared is a refusal. The aggregate check folds four legs: surface drift, the vault round-trip, the vault read symmetry, and the persona assessment. A leg whose seam is not wired reports nothing and does not affect the result. The verdict is one exit code, zero when every wired leg passed and one otherwise, and all four gate functions in the codebase share that signature so a build keys on them the same way. Three outcomes: the record survives the file, a declared drop that was named in advance, and a refusal that returns a nonzero code.](docs/art/verdict-lane.svg)
42
+
43
+ A round-trip that loses a field passes only when the adapter declared that loss
44
+ in advance. Anything else fails the gate rather than logging a warning.
45
+
46
+ ## What canon carries
47
+
48
+ ![A table of twelve rows: what canon carries, how many of it there are, and where each number is read from. Five record kinds share one envelope. Two scopes layer, workspace over global. Four surfaces sit on the write allow-list: a global and a workspace file for Claude Code, an AGENTS.md for Codex, and a workspace SOUL.md for Hermes. Four storage adapters implement the backend protocol, and five capability tokens describe what each one can carry. Sixteen schema pins name the seams that carry a version. The aggregate check folds four legs, and four gate functions share the same zero or one exit code. 111 source modules hold 19,731 lines, and 53 test files hold 1061 tests. Two surfaces named in the roadmap are absent from the catalog, a global SOUL.md and a GEMINI.md, so canon does not render them.](docs/art/record-table.svg)
49
+
50
+ Every count is asserted against the module that defines it in
51
+ `tests/test_repo_art.py`.
52
+
53
+ ## Status
54
+
55
+ F0 is the record of record: the canonical schema, its validator, and the
56
+ per-scope layering. F1 adds the storage seam: a `MemoryBackend` protocol with
57
+ capability tokens and four adapters, among them a zero-drop SQLite reference and
58
+ injected-handle adapters for a memory fact-engine and an authored-block store.
59
+ R0 adds the block round-trip gate: a byte-exact region boundary inside a managed
60
+ file, a record-to-text renderer and its inverse, and a go/no-go verdict that
61
+ proves a block set round-trips to its canonical form with every dropped field
62
+ declared.
63
+
64
+ R1 renders your files from the record. It resolves the block set for a file's
65
+ scope and rewrites only the region canon owns, every byte outside it preserved.
66
+ It writes only a fixed allow-list of files, and only a file you have opted in
67
+ with a canon region. Where a tool reads both a global and a workspace file, the
68
+ workspace file carries just your workspace blocks, so a shared block is never
69
+ duplicated; where a tool reads one file, that file carries the full resolved set.
70
+
71
+ R2 mirrors your whole record set into an Obsidian vault. Each record becomes one
72
+ markdown note you can read, search, and link, and a MEMORY.md index lists them
73
+ all. The full record rides inside every note, so a rebuild is exact and editing a
74
+ note's prose never rewrites the record behind it. canon writes only inside its own
75
+ vault, never touches a file it did not write, and when you drop a record it
76
+ reports the note left behind rather than deleting it. R2 also adds SOUL.md to the
77
+ rendered surfaces.
78
+
79
+ V2 through V4 add the checks and the decision on top of them. A drift check
80
+ re-derives every managed surface and compares only the region canon owns, so
81
+ your own prose outside the markers is never flagged. A persona check reports
82
+ whether the memories behind a synthesized persona still resolve. V4 separates a
83
+ mechanical fast-forward from a conflict, writes the fast-forwards, and raises a
84
+ durable gate for anything a human should adjudicate.
85
+
86
+ A harness reaches all of this over MCP. `canon mcp` serves six read-only tools:
87
+ identity, a readiness diagnostic, the authored record set, the render for a
88
+ scope, the validator, and the aggregate check. Nothing on that server writes a
89
+ file. Reconcile stays a library call, because rewriting your instruction files
90
+ and raising a gate is an action with a person behind it.
91
+
92
+ The CLI can also compile a provider-neutral continuity capsule from two explicit
93
+ inputs: `records.jsonl` and `atoms.jsonl`. Preview reports artifact names,
94
+ target tier, readiness probe data, and source-state hashes without writing.
95
+ Export writes the same capsule as Canon Markdown, capsule JSON, readiness JSON,
96
+ or a three-file bundle. The capsule records omitted state as typed atoms or
97
+ transform omissions and says what the export does not prove, including host
98
+ enforcement. It does not import provider auth, private databases, ChatGPT web
99
+ state, or Claude web state.
100
+
101
+ Installing a region into a fresh file, the first migrator on the version seam,
102
+ and the global SOUL.md and GEMINI.md surfaces are later phases. Everything
103
+ shipped is proven by a full test suite and aims at the one envelope.
104
+
105
+ ## Run it
106
+
107
+ Canon 0.1.0 is prepared as a GitHub release candidate. Install from a reviewed
108
+ GitHub release asset after publication, or from a local wheel during review:
109
+
110
+ ```bash
111
+ python -m pip install canon-0.1.0-py3-none-any.whl
112
+ ```
113
+
114
+ No PyPI package ownership or publication is claimed here.
115
+
116
+ Serve the record set to a harness:
117
+
118
+ ```bash
119
+ canon mcp
120
+ ```
121
+
122
+ Ask canon what it believes, with no transport in the way:
123
+
124
+ ```bash
125
+ canon check
126
+ canon blocks
127
+ ```
128
+
129
+ `canon check` exits non-zero when a wired leg fails or the block pool is not the
130
+ authored set, so a build can key on it. Point it at your records with
131
+ `CANON_BLOCKS_DIR`, and at your files with `CANON_HOME` and `CANON_WORKSPACE`.
132
+
133
+ Preview and export a continuity capsule from explicit local inputs:
134
+
135
+ ```bash
136
+ canon --json preview --workspace . --records records.jsonl --atoms atoms.jsonl --target codex-cli
137
+ canon export --workspace . --records records.jsonl --atoms atoms.jsonl --target codex-cli --format canon-md
138
+ canon export --workspace . --records records.jsonl --atoms atoms.jsonl --target codex-cli --format capsule-json
139
+ canon --json export --workspace . --records records.jsonl --atoms atoms.jsonl --target codex-cli --format bundle --out bundle
140
+ ```
141
+
142
+ The `codex-cli` and `claude-code` targets are native-advisory surfaces. App and
143
+ web targets remain guided until their hosts provide stronger startup evidence.
144
+ Preview and stdout exports work across supported Python platforms. Creating a
145
+ new bundle currently requires Windows with the confined native writer. On Linux
146
+ and macOS, new bundle creation returns `unsafe_path` without writing; use stdout
147
+ export there. The Windows final directory rename is parent-handle-relative and
148
+ leaf-only. This bounds publication, not immutability after the command returns.
149
+
150
+ Run the suite:
151
+
152
+ ```bash
153
+ python -m pytest
154
+ ```
155
+
156
+ No runtime dependencies. Python 3.11 or newer.
157
+
158
+ ## Layout
159
+
160
+ ```
161
+ src/canon/
162
+ schema.py, validator.py, layering.py the record, its rules, per-scope resolve
163
+ backends/ the storage seam and four adapters
164
+ region.py, textblock.py, fidelity.py the byte boundary, the text codec, the gate
165
+ surface.py, registry.py the render composition, the write allow-list
166
+ frontmatter.py, vault.py the note frontmatter codec, the one-record note
167
+ vault_mirror.py, vault_fidelity.py the whole-vault mirror and its round-trip gate
168
+ drift.py, writing_gate.py the surface drift check, the injected prose gate
169
+ persona_thesis.py, canon_check.py the persona basis adapter, the aggregate check
170
+ reconcile*.py the fast-forward decision and its durable gate
171
+ blocks.py, local_mcp.py, cli.py the authored-block loader, the MCP door, the CLI
172
+ capsule*.py, atom.py, adapter.py the continuity capsule, atom and target contract
173
+ cli_compile.py, cli_export.py preview, stdout export and bundle export
174
+ cli_artifacts.py, cli_publish.py source hashes and confined artifact publishing
175
+ tests/ round-trip, validator, layering, backend,
176
+ fidelity, surface, orchestration, vault,
177
+ drift, reconcile, continuity, and artwork proofs
178
+ docs/art/ the drawings above and the spec they render from
179
+ project-docs/ the F0, F1, R0, R1, R2, V2, V3, V4, MCP decisions
180
+ ```
181
+
182
+ See `project-docs/` for the schema reference, the layering derivation, the
183
+ section-ownership contract, the declared drops each storage backend must
184
+ announce, and the decisions behind the round-trip, vault, drift and reconcile
185
+ gates.
186
+
187
+ ## License
188
+
189
+ FSL-1.1-MIT. Functional Source License, source-available now for any purpose
190
+ other than a competing product, and it converts to the MIT license two years
191
+ after each version is released. See `LICENSE`.