armarium 0.1.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 (216) hide show
  1. armarium-0.1.0/.gitignore +10 -0
  2. armarium-0.1.0/AGENTS.md +17 -0
  3. armarium-0.1.0/CHANGELOG.md +15 -0
  4. armarium-0.1.0/LICENSE +21 -0
  5. armarium-0.1.0/PKG-INFO +98 -0
  6. armarium-0.1.0/README.md +73 -0
  7. armarium-0.1.0/docs/add.md +170 -0
  8. armarium-0.1.0/docs/campaign.md +46 -0
  9. armarium-0.1.0/docs/init.md +22 -0
  10. armarium-0.1.0/docs/record.md +73 -0
  11. armarium-0.1.0/docs/releases.md +20 -0
  12. armarium-0.1.0/docs/schemas.md +52 -0
  13. armarium-0.1.0/docs/type.md +245 -0
  14. armarium-0.1.0/docs/validate.md +103 -0
  15. armarium-0.1.0/docs/vault.md +86 -0
  16. armarium-0.1.0/pyproject.toml +66 -0
  17. armarium-0.1.0/ruff.toml +4 -0
  18. armarium-0.1.0/src/armarium/__init__.py +1 -0
  19. armarium-0.1.0/src/armarium/add.py +304 -0
  20. armarium-0.1.0/src/armarium/cli.py +232 -0
  21. armarium-0.1.0/src/armarium/clue.py +97 -0
  22. armarium-0.1.0/src/armarium/content.py +126 -0
  23. armarium-0.1.0/src/armarium/index.py +195 -0
  24. armarium-0.1.0/src/armarium/init.py +79 -0
  25. armarium-0.1.0/src/armarium/lib.py +518 -0
  26. armarium-0.1.0/src/armarium/logging.py +40 -0
  27. armarium-0.1.0/src/armarium/note.py +46 -0
  28. armarium-0.1.0/src/armarium/parse.py +599 -0
  29. armarium-0.1.0/src/armarium/player.py +45 -0
  30. armarium-0.1.0/src/armarium/schemas.py +178 -0
  31. armarium-0.1.0/src/armarium/session.py +52 -0
  32. armarium-0.1.0/src/armarium/transcript.py +83 -0
  33. armarium-0.1.0/src/armarium/validate.py +1359 -0
  34. armarium-0.1.0/tests/schemas/.gitignore +1 -0
  35. armarium-0.1.0/tests/schemas/__init__.py +1 -0
  36. armarium-0.1.0/tests/schemas/fixtures/clue.json +228 -0
  37. armarium-0.1.0/tests/schemas/fixtures/content.json +165 -0
  38. armarium-0.1.0/tests/schemas/fixtures/note.json +28 -0
  39. armarium-0.1.0/tests/schemas/fixtures/player.json +72 -0
  40. armarium-0.1.0/tests/schemas/fixtures/reference.json +28 -0
  41. armarium-0.1.0/tests/schemas/fixtures/session.json +405 -0
  42. armarium-0.1.0/tests/schemas/fixtures/status.json +102 -0
  43. armarium-0.1.0/tests/schemas/fixtures/transcript.json +65 -0
  44. armarium-0.1.0/tests/schemas/fixtures/type.json +181 -0
  45. armarium-0.1.0/tests/schemas/requirements.txt +3 -0
  46. armarium-0.1.0/tests/schemas/test_schemas.py +283 -0
  47. armarium-0.1.0/tests/schemas/test_views.py +145 -0
  48. armarium-0.1.0/tests/test_add.py +463 -0
  49. armarium-0.1.0/tests/test_cli.py +1190 -0
  50. armarium-0.1.0/tests/test_clue.py +352 -0
  51. armarium-0.1.0/tests/test_content.py +385 -0
  52. armarium-0.1.0/tests/test_diagnostics.py +60 -0
  53. armarium-0.1.0/tests/test_docs.py +187 -0
  54. armarium-0.1.0/tests/test_index.py +258 -0
  55. armarium-0.1.0/tests/test_init.py +196 -0
  56. armarium-0.1.0/tests/test_lib.py +672 -0
  57. armarium-0.1.0/tests/test_logging.py +68 -0
  58. armarium-0.1.0/tests/test_note.py +343 -0
  59. armarium-0.1.0/tests/test_parse.py +842 -0
  60. armarium-0.1.0/tests/test_player.py +332 -0
  61. armarium-0.1.0/tests/test_pyproject.py +956 -0
  62. armarium-0.1.0/tests/test_schemas.py +491 -0
  63. armarium-0.1.0/tests/test_session.py +242 -0
  64. armarium-0.1.0/tests/test_transcript.py +358 -0
  65. armarium-0.1.0/tests/test_validate.py +3081 -0
  66. armarium-0.1.0/tests/test_vaults.py +56 -0
  67. armarium-0.1.0/vaults/example/.gitignore +8 -0
  68. armarium-0.1.0/vaults/example/.obsidian/app.json +3 -0
  69. armarium-0.1.0/vaults/example/.obsidian/appearance.json +5 -0
  70. armarium-0.1.0/vaults/example/.obsidian/snippets/armarium-prose.css +27 -0
  71. armarium-0.1.0/vaults/example/.scratch/.gitkeep +0 -0
  72. armarium-0.1.0/vaults/example/assets/harbor-pass.txt +7 -0
  73. armarium-0.1.0/vaults/example/campaigns/campaign_1/clues/C-1-0001.md +11 -0
  74. armarium-0.1.0/vaults/example/campaigns/campaign_1/clues/C-1-0002.md +11 -0
  75. armarium-0.1.0/vaults/example/campaigns/campaign_1/clues/C-1-0003.md +11 -0
  76. armarium-0.1.0/vaults/example/campaigns/campaign_1/clues/C-1-0004.md +11 -0
  77. armarium-0.1.0/vaults/example/campaigns/campaign_1/content/Blue Signal Flare.md +21 -0
  78. armarium-0.1.0/vaults/example/campaigns/campaign_1/content/Brass Harbor Seal.md +23 -0
  79. armarium-0.1.0/vaults/example/campaigns/campaign_1/content/Esme Calder.md +23 -0
  80. armarium-0.1.0/vaults/example/campaigns/campaign_1/content/Glass Petrel Crew.md +23 -0
  81. armarium-0.1.0/vaults/example/campaigns/campaign_1/content/Glass Petrel.md +28 -0
  82. armarium-0.1.0/vaults/example/campaigns/campaign_1/content/Quay Nine.md +23 -0
  83. armarium-0.1.0/vaults/example/campaigns/campaign_1/content/Shoal Chart.md +22 -0
  84. armarium-0.1.0/vaults/example/campaigns/campaign_1/content/Talia Venn.md +29 -0
  85. armarium-0.1.0/vaults/example/campaigns/campaign_1/notes/Prep for the hearing.md +14 -0
  86. armarium-0.1.0/vaults/example/campaigns/campaign_1/reference/Campaign.md +13 -0
  87. armarium-0.1.0/vaults/example/campaigns/campaign_1/reference/indexes/Clues.md +21 -0
  88. armarium-0.1.0/vaults/example/campaigns/campaign_1/reference/players/Ellis.md +4 -0
  89. armarium-0.1.0/vaults/example/campaigns/campaign_1/reference/players/Rowan.md +4 -0
  90. armarium-0.1.0/vaults/example/campaigns/campaign_1/sessions/S-1-001.md +73 -0
  91. armarium-0.1.0/vaults/example/campaigns/campaign_1/sessions/S-1-002.md +74 -0
  92. armarium-0.1.0/vaults/example/campaigns/campaign_1/sessions/S-1-003.md +68 -0
  93. armarium-0.1.0/vaults/example/campaigns/campaign_1/sessions/transcripts/S-1-001 Transcript.md +29 -0
  94. armarium-0.1.0/vaults/example/campaigns/campaign_1/sessions/transcripts/S-1-002 Transcript.md +23 -0
  95. armarium-0.1.0/vaults/example/campaigns/campaign_2/clues/C-2-0001.md +12 -0
  96. armarium-0.1.0/vaults/example/campaigns/campaign_2/clues/C-2-0002.md +12 -0
  97. armarium-0.1.0/vaults/example/campaigns/campaign_2/clues/C-2-0003.md +12 -0
  98. armarium-0.1.0/vaults/example/campaigns/campaign_2/clues/C-2-0004.md +12 -0
  99. armarium-0.1.0/vaults/example/campaigns/campaign_2/content/Bram Kest.md +31 -0
  100. armarium-0.1.0/vaults/example/campaigns/campaign_2/content/Copper Finch.md +26 -0
  101. armarium-0.1.0/vaults/example/campaigns/campaign_2/content/Darian Holt.md +31 -0
  102. armarium-0.1.0/vaults/example/campaigns/campaign_2/content/Oren Vale.md +25 -0
  103. armarium-0.1.0/vaults/example/campaigns/campaign_2/content/Silas Rook.md +25 -0
  104. armarium-0.1.0/vaults/example/campaigns/campaign_2/content/Tern Salvage Company.md +26 -0
  105. armarium-0.1.0/vaults/example/campaigns/campaign_2/content/Tern.md +23 -0
  106. armarium-0.1.0/vaults/example/campaigns/campaign_2/notes/Storm timing.md +13 -0
  107. armarium-0.1.0/vaults/example/campaigns/campaign_2/reference/Campaign.md +15 -0
  108. armarium-0.1.0/vaults/example/campaigns/campaign_2/reference/indexes/Clues.md +21 -0
  109. armarium-0.1.0/vaults/example/campaigns/campaign_2/reference/players/Martin.md +6 -0
  110. armarium-0.1.0/vaults/example/campaigns/campaign_2/reference/players/Peter.md +6 -0
  111. armarium-0.1.0/vaults/example/campaigns/campaign_2/sessions/S-2-001.md +94 -0
  112. armarium-0.1.0/vaults/example/campaigns/campaign_2/sessions/S-2-002.md +77 -0
  113. armarium-0.1.0/vaults/example/campaigns/campaign_2/sessions/transcripts/S-2-001 Transcript.md +24 -0
  114. armarium-0.1.0/vaults/example/content/Captain Mara Vey.md +23 -0
  115. armarium-0.1.0/vaults/example/content/Free Pilots Assembly.md +26 -0
  116. armarium-0.1.0/vaults/example/content/Orlan Countinghouse.md +28 -0
  117. armarium-0.1.0/vaults/example/content/Port Briselle.md +27 -0
  118. armarium-0.1.0/vaults/example/content/The Bell Accord.md +22 -0
  119. armarium-0.1.0/vaults/example/content/The Crownless Coast.md +28 -0
  120. armarium-0.1.0/vaults/example/content/The Red Teeth.md +27 -0
  121. armarium-0.1.0/vaults/example/content/Wake-lark.md +22 -0
  122. armarium-0.1.0/vaults/example/notes/Coast design notes.md +13 -0
  123. armarium-0.1.0/vaults/example/reference/.gitkeep +0 -0
  124. armarium-0.1.0/vaults/example/reference/schemas/clue.schema.json +142 -0
  125. armarium-0.1.0/vaults/example/reference/schemas/content.schema.json +360 -0
  126. armarium-0.1.0/vaults/example/reference/schemas/note.schema.json +28 -0
  127. armarium-0.1.0/vaults/example/reference/schemas/player.schema.json +42 -0
  128. armarium-0.1.0/vaults/example/reference/schemas/reference.schema.json +28 -0
  129. armarium-0.1.0/vaults/example/reference/schemas/session.schema.json +143 -0
  130. armarium-0.1.0/vaults/example/reference/schemas/status.schema.json +34 -0
  131. armarium-0.1.0/vaults/example/reference/schemas/transcript.schema.json +41 -0
  132. armarium-0.1.0/vaults/example/reference/schemas/type.schema.json +50 -0
  133. armarium-0.1.0/vaults/example/reference/statuses/Abandoned.md +5 -0
  134. armarium-0.1.0/vaults/example/reference/statuses/Dormant.md +5 -0
  135. armarium-0.1.0/vaults/example/reference/statuses/Hinted.md +5 -0
  136. armarium-0.1.0/vaults/example/reference/statuses/Pending.md +5 -0
  137. armarium-0.1.0/vaults/example/reference/statuses/Revealed.md +5 -0
  138. armarium-0.1.0/vaults/example/reference/statuses/Superseded.md +5 -0
  139. armarium-0.1.0/vaults/example/reference/templates/Campaign.md +4 -0
  140. armarium-0.1.0/vaults/example/reference/templates/Clue.md +10 -0
  141. armarium-0.1.0/vaults/example/reference/templates/Clues.md +21 -0
  142. armarium-0.1.0/vaults/example/reference/templates/Content.md +15 -0
  143. armarium-0.1.0/vaults/example/reference/templates/Note.md +3 -0
  144. armarium-0.1.0/vaults/example/reference/templates/Player.md +4 -0
  145. armarium-0.1.0/vaults/example/reference/templates/Session.md +46 -0
  146. armarium-0.1.0/vaults/example/reference/templates/Transcript.md +7 -0
  147. armarium-0.1.0/vaults/example/reference/types/Clue.md +32 -0
  148. armarium-0.1.0/vaults/example/reference/types/Content.md +66 -0
  149. armarium-0.1.0/vaults/example/reference/types/Note.md +18 -0
  150. armarium-0.1.0/vaults/example/reference/types/Player.md +16 -0
  151. armarium-0.1.0/vaults/example/reference/types/Reference.md +15 -0
  152. armarium-0.1.0/vaults/example/reference/types/Session.md +38 -0
  153. armarium-0.1.0/vaults/example/reference/types/Status.md +26 -0
  154. armarium-0.1.0/vaults/example/reference/types/Transcript.md +41 -0
  155. armarium-0.1.0/vaults/example/reference/types/Type.md +29 -0
  156. armarium-0.1.0/vaults/example/reference/views/clue-index.base +33 -0
  157. armarium-0.1.0/vaults/example/reference/views/clue-sessions.base +23 -0
  158. armarium-0.1.0/vaults/example/reference/views/content-clues.base +23 -0
  159. armarium-0.1.0/vaults/example/reference/views/prepared-clues.base +22 -0
  160. armarium-0.1.0/vaults/example/reference/views/prepared-locations.base +23 -0
  161. armarium-0.1.0/vaults/example/reference/views/prepared-npcs.base +23 -0
  162. armarium-0.1.0/vaults/starter/.gitignore +8 -0
  163. armarium-0.1.0/vaults/starter/.obsidian/app.json +3 -0
  164. armarium-0.1.0/vaults/starter/.obsidian/appearance.json +5 -0
  165. armarium-0.1.0/vaults/starter/.obsidian/snippets/armarium-prose.css +27 -0
  166. armarium-0.1.0/vaults/starter/.scratch/.gitkeep +0 -0
  167. armarium-0.1.0/vaults/starter/assets/.gitkeep +0 -0
  168. armarium-0.1.0/vaults/starter/campaigns/campaign_1/clues/.gitkeep +0 -0
  169. armarium-0.1.0/vaults/starter/campaigns/campaign_1/content/.gitkeep +0 -0
  170. armarium-0.1.0/vaults/starter/campaigns/campaign_1/notes/.gitkeep +0 -0
  171. armarium-0.1.0/vaults/starter/campaigns/campaign_1/reference/Campaign.md +4 -0
  172. armarium-0.1.0/vaults/starter/campaigns/campaign_1/reference/indexes/Clues.md +21 -0
  173. armarium-0.1.0/vaults/starter/campaigns/campaign_1/reference/players/.gitkeep +0 -0
  174. armarium-0.1.0/vaults/starter/campaigns/campaign_1/sessions/.gitkeep +0 -0
  175. armarium-0.1.0/vaults/starter/campaigns/campaign_1/sessions/transcripts/.gitkeep +0 -0
  176. armarium-0.1.0/vaults/starter/content/.gitkeep +0 -0
  177. armarium-0.1.0/vaults/starter/notes/.gitkeep +0 -0
  178. armarium-0.1.0/vaults/starter/reference/.gitkeep +0 -0
  179. armarium-0.1.0/vaults/starter/reference/schemas/clue.schema.json +142 -0
  180. armarium-0.1.0/vaults/starter/reference/schemas/content.schema.json +360 -0
  181. armarium-0.1.0/vaults/starter/reference/schemas/note.schema.json +28 -0
  182. armarium-0.1.0/vaults/starter/reference/schemas/player.schema.json +42 -0
  183. armarium-0.1.0/vaults/starter/reference/schemas/reference.schema.json +28 -0
  184. armarium-0.1.0/vaults/starter/reference/schemas/session.schema.json +143 -0
  185. armarium-0.1.0/vaults/starter/reference/schemas/status.schema.json +34 -0
  186. armarium-0.1.0/vaults/starter/reference/schemas/transcript.schema.json +41 -0
  187. armarium-0.1.0/vaults/starter/reference/schemas/type.schema.json +50 -0
  188. armarium-0.1.0/vaults/starter/reference/statuses/Abandoned.md +5 -0
  189. armarium-0.1.0/vaults/starter/reference/statuses/Dormant.md +5 -0
  190. armarium-0.1.0/vaults/starter/reference/statuses/Hinted.md +5 -0
  191. armarium-0.1.0/vaults/starter/reference/statuses/Pending.md +5 -0
  192. armarium-0.1.0/vaults/starter/reference/statuses/Revealed.md +5 -0
  193. armarium-0.1.0/vaults/starter/reference/statuses/Superseded.md +5 -0
  194. armarium-0.1.0/vaults/starter/reference/templates/Campaign.md +4 -0
  195. armarium-0.1.0/vaults/starter/reference/templates/Clue.md +10 -0
  196. armarium-0.1.0/vaults/starter/reference/templates/Clues.md +21 -0
  197. armarium-0.1.0/vaults/starter/reference/templates/Content.md +15 -0
  198. armarium-0.1.0/vaults/starter/reference/templates/Note.md +3 -0
  199. armarium-0.1.0/vaults/starter/reference/templates/Player.md +4 -0
  200. armarium-0.1.0/vaults/starter/reference/templates/Session.md +46 -0
  201. armarium-0.1.0/vaults/starter/reference/templates/Transcript.md +7 -0
  202. armarium-0.1.0/vaults/starter/reference/types/Clue.md +32 -0
  203. armarium-0.1.0/vaults/starter/reference/types/Content.md +66 -0
  204. armarium-0.1.0/vaults/starter/reference/types/Note.md +18 -0
  205. armarium-0.1.0/vaults/starter/reference/types/Player.md +16 -0
  206. armarium-0.1.0/vaults/starter/reference/types/Reference.md +15 -0
  207. armarium-0.1.0/vaults/starter/reference/types/Session.md +38 -0
  208. armarium-0.1.0/vaults/starter/reference/types/Status.md +26 -0
  209. armarium-0.1.0/vaults/starter/reference/types/Transcript.md +41 -0
  210. armarium-0.1.0/vaults/starter/reference/types/Type.md +29 -0
  211. armarium-0.1.0/vaults/starter/reference/views/clue-index.base +33 -0
  212. armarium-0.1.0/vaults/starter/reference/views/clue-sessions.base +23 -0
  213. armarium-0.1.0/vaults/starter/reference/views/content-clues.base +23 -0
  214. armarium-0.1.0/vaults/starter/reference/views/prepared-clues.base +22 -0
  215. armarium-0.1.0/vaults/starter/reference/views/prepared-locations.base +23 -0
  216. armarium-0.1.0/vaults/starter/reference/views/prepared-npcs.base +23 -0
@@ -0,0 +1,10 @@
1
+ .scratch/
2
+ .DS_Store
3
+
4
+ .venv/
5
+ __pycache__/
6
+ .pytest_cache/
7
+ .mypy_cache/
8
+ .ruff_cache/
9
+ dist/
10
+ *.egg-info/
@@ -0,0 +1,17 @@
1
+ # Repository workflow
2
+
3
+ - Never commit or push directly to `main`.
4
+ - Make all changes, including planning and documentation, on a working branch
5
+ and submit them through a pull request.
6
+ - The user reviews and merges pull requests; do not merge them on the user's behalf
7
+ without explicit instruction.
8
+
9
+ # Testing conventions
10
+
11
+ - Tests for a source module `X.py` belong in `test_X.py`.
12
+ - Cover every class, function, and method with dedicated tests, including private
13
+ helpers and properties.
14
+ - Organize tests into classes named for the class, function, or method under test
15
+ (for example, `TestParseWikilink` or `TestResultFailed`).
16
+ - Minimize redundant test code aggressively with `pytest.mark.parametrize`; share
17
+ a test body when cases exercise the same behavior with different inputs.
@@ -0,0 +1,15 @@
1
+ # Changelog
2
+
3
+ ## Unreleased
4
+
5
+ ## 0.1.0 (2026-09-30)
6
+
7
+ - Add `armarium init` for creating standalone vaults.
8
+ - Add `armarium add` subcommands for campaigns, Content, Clues, Sessions, Players,
9
+ Notes, and Transcripts, using vault-local templates and conventions.
10
+ - Add `armarium validate` for records, directories, and vaults, with checks for
11
+ schemas, Markdown structure, wikilinks, and relationships between records.
12
+ - Add shared setting content and campaign-specific records, with Obsidian Bases
13
+ views for clues and session preparation.
14
+ - Add a starter vault and a two-campaign example vault.
15
+ - Add the MIT license and changelog-driven release automation.
armarium-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 William J. Bradshaw
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,98 @@
1
+ Metadata-Version: 2.5
2
+ Name: armarium
3
+ Version: 0.1.0
4
+ Summary: Create and validate Armarium Markdown vaults
5
+ Project-URL: Homepage, https://github.com/willbradshaw/armarium
6
+ Project-URL: Repository, https://github.com/willbradshaw/armarium
7
+ Project-URL: Issues, https://github.com/willbradshaw/armarium/issues
8
+ Project-URL: Changelog, https://github.com/willbradshaw/armarium/blob/main/CHANGELOG.md
9
+ Author: Will Bradshaw
10
+ License-Expression: MIT
11
+ License-File: LICENSE
12
+ Requires-Python: >=3.14
13
+ Requires-Dist: jsonschema[format]<5,>=4.23
14
+ Requires-Dist: markdown-it-py<4,>=3
15
+ Requires-Dist: pyyaml<7,>=6
16
+ Requires-Dist: referencing<1,>=0.35
17
+ Provides-Extra: dev
18
+ Requires-Dist: build<2,>=1; extra == 'dev'
19
+ Requires-Dist: mypy; extra == 'dev'
20
+ Requires-Dist: pytest>=8; extra == 'dev'
21
+ Requires-Dist: ruff==0.16.8; extra == 'dev'
22
+ Requires-Dist: types-jsonschema; extra == 'dev'
23
+ Requires-Dist: types-pyyaml; extra == 'dev'
24
+ Description-Content-Type: text/markdown
25
+
26
+ # Armarium
27
+
28
+ A system-general starter for tabletop roleplaying knowledge bases in Obsidian.
29
+
30
+ See [vaults/example](vaults/example) for a fleshed-out toy vault that follows and
31
+ demonstrates this repository's conventions.
32
+
33
+ ## Create a vault
34
+
35
+ With Python 3.14+ and [uv](https://docs.astral.sh/uv/guides/tools/), install
36
+ Armarium from this checkout and create a vault:
37
+
38
+ ```sh
39
+ uv tool install .
40
+ armarium init ../my-vault
41
+ ```
42
+
43
+ If `armarium` is not on your PATH, run `uv tool update-shell` and restart your
44
+ terminal. To reinstall after updating this checkout, use
45
+ `uv tool install --reinstall-package armarium .`.
46
+
47
+ Open the new folder in Obsidian and edit
48
+ `campaigns/campaign_1/reference/Campaign.md`. See [Creating a vault](docs/init.md)
49
+ for details.
50
+
51
+ Add campaigns and records with `armarium add`; see
52
+ [Adding to a vault](docs/add.md).
53
+
54
+ Requires Obsidian **1.13.7+** with **Bases** and
55
+ [Frontmatter Markdown Links](https://github.com/mnaoumov/obsidian-frontmatter-markdown-links)
56
+ enabled.
57
+
58
+ ## Layout
59
+
60
+ | Folder | Purpose |
61
+ | --- | --- |
62
+ | `content/` | Shared setting content. |
63
+ | `campaigns/campaign_1/` | Campaign content, clues, sessions, and reference material. |
64
+ | `reference/` | Templates, type descriptions, schemas, statuses, and shared reference material. |
65
+ | `assets/` | Maps, images, and handouts. |
66
+
67
+ Use [`armarium add`](docs/add.md#adding-a-record) or copy a file from
68
+ `reference/templates/` to create a record. [Records](docs/record.md)
69
+ describes what every record shares and [Types](docs/type.md) the fields, body
70
+ and rules of each type.
71
+
72
+ The starter is preconfigured for a single campaign. The example includes two
73
+ campaigns sharing setting Content, with independent campaign state and combined
74
+ Clue and appearance lists. [Vault layout](docs/vault.md) states the full required
75
+ skeleton and where each record type lives.
76
+
77
+ `.obsidian/` holds the settings the records rely on and is part of the vault;
78
+ only Obsidian's workspace files are ignored. `.scratch/` is ignored working
79
+ space; `.gitkeep` files preserve empty directories in Git. The copied vault can
80
+ be its own Git repository.
81
+
82
+ For schema integration and testing, see [Schema development](docs/schemas.md).
83
+
84
+ Planned work is tracked in the [issues](https://github.com/willbradshaw/armarium/issues).
85
+
86
+ MIT licensed. See the [changelog](CHANGELOG.md) and [release process](docs/releases.md).
87
+
88
+ ## Validate records
89
+
90
+ Validate a record or a whole vault:
91
+
92
+ ```sh
93
+ armarium validate path/to/record.md
94
+ armarium validate ../my-vault
95
+ ```
96
+
97
+ See [Validation](docs/validate.md) for the command's options, what is checked
98
+ and how findings are reported.
@@ -0,0 +1,73 @@
1
+ # Armarium
2
+
3
+ A system-general starter for tabletop roleplaying knowledge bases in Obsidian.
4
+
5
+ See [vaults/example](vaults/example) for a fleshed-out toy vault that follows and
6
+ demonstrates this repository's conventions.
7
+
8
+ ## Create a vault
9
+
10
+ With Python 3.14+ and [uv](https://docs.astral.sh/uv/guides/tools/), install
11
+ Armarium from this checkout and create a vault:
12
+
13
+ ```sh
14
+ uv tool install .
15
+ armarium init ../my-vault
16
+ ```
17
+
18
+ If `armarium` is not on your PATH, run `uv tool update-shell` and restart your
19
+ terminal. To reinstall after updating this checkout, use
20
+ `uv tool install --reinstall-package armarium .`.
21
+
22
+ Open the new folder in Obsidian and edit
23
+ `campaigns/campaign_1/reference/Campaign.md`. See [Creating a vault](docs/init.md)
24
+ for details.
25
+
26
+ Add campaigns and records with `armarium add`; see
27
+ [Adding to a vault](docs/add.md).
28
+
29
+ Requires Obsidian **1.13.7+** with **Bases** and
30
+ [Frontmatter Markdown Links](https://github.com/mnaoumov/obsidian-frontmatter-markdown-links)
31
+ enabled.
32
+
33
+ ## Layout
34
+
35
+ | Folder | Purpose |
36
+ | --- | --- |
37
+ | `content/` | Shared setting content. |
38
+ | `campaigns/campaign_1/` | Campaign content, clues, sessions, and reference material. |
39
+ | `reference/` | Templates, type descriptions, schemas, statuses, and shared reference material. |
40
+ | `assets/` | Maps, images, and handouts. |
41
+
42
+ Use [`armarium add`](docs/add.md#adding-a-record) or copy a file from
43
+ `reference/templates/` to create a record. [Records](docs/record.md)
44
+ describes what every record shares and [Types](docs/type.md) the fields, body
45
+ and rules of each type.
46
+
47
+ The starter is preconfigured for a single campaign. The example includes two
48
+ campaigns sharing setting Content, with independent campaign state and combined
49
+ Clue and appearance lists. [Vault layout](docs/vault.md) states the full required
50
+ skeleton and where each record type lives.
51
+
52
+ `.obsidian/` holds the settings the records rely on and is part of the vault;
53
+ only Obsidian's workspace files are ignored. `.scratch/` is ignored working
54
+ space; `.gitkeep` files preserve empty directories in Git. The copied vault can
55
+ be its own Git repository.
56
+
57
+ For schema integration and testing, see [Schema development](docs/schemas.md).
58
+
59
+ Planned work is tracked in the [issues](https://github.com/willbradshaw/armarium/issues).
60
+
61
+ MIT licensed. See the [changelog](CHANGELOG.md) and [release process](docs/releases.md).
62
+
63
+ ## Validate records
64
+
65
+ Validate a record or a whole vault:
66
+
67
+ ```sh
68
+ armarium validate path/to/record.md
69
+ armarium validate ../my-vault
70
+ ```
71
+
72
+ See [Validation](docs/validate.md) for the command's options, what is checked
73
+ and how findings are reported.
@@ -0,0 +1,170 @@
1
+ # Adding to a vault
2
+
3
+ `armarium add` creates [campaigns](#adding-a-campaign) and [records](#adding-a-record)
4
+ in an existing [vault](vault.md) using its local templates and conventions, then
5
+ [validates the result](#templates-and-validation). For example:
6
+
7
+ ```sh
8
+ armarium add campaign --vault ../my-vault
9
+ armarium add content "Port Briselle" --subtype Location --vault ../my-vault
10
+ armarium add session --campaign 1 --vault ../my-vault
11
+ ```
12
+
13
+ For a new vault, start with [`armarium init`](init.md).
14
+
15
+ ## Shared behavior
16
+
17
+ All commands share rules for [vault selection](#choosing-a-vault-and-destination),
18
+ [campaign selection](#choosing-a-campaign) and [templates and
19
+ validation](#templates-and-validation).
20
+
21
+ ### Choosing a vault and destination
22
+
23
+ Pass `--vault PATH` to select a vault's root directory, using an absolute path or a path
24
+ relative to your current directory. Omit it to discover the vault from your current
25
+ directory when running anywhere inside it.
26
+
27
+ Records go in the selected vault's [declared directory](vault.md#where-records-live) for
28
+ their type and [campaign scope](#choosing-a-campaign), rather than directly in the
29
+ current directory. Existing records and campaigns are never overwritten.
30
+
31
+ ### Choosing a campaign
32
+
33
+ While inside a [campaign directory](campaign.md#directory) or any descendants, new
34
+ records created with `armarium add` are added to that campaign. Use `--campaign N` to
35
+ select another existing campaign. Selecting a different vault does not inherit the
36
+ current campaign.
37
+
38
+ Outside a campaign directory, [Content](#content) and [Notes](#notes) default to shared
39
+ scope; [Players](#players), [Sessions](#sessions) and [Clues](#clues) require
40
+ `--campaign`. [Transcripts](#transcripts) always take their campaign from the selected
41
+ Session. [`add campaign`](#adding-a-campaign) creates a new campaign.
42
+
43
+ ### Templates and validation
44
+
45
+ Initial values come from the vault's local [templates](record.md#anatomy), and validation
46
+ uses its [schemas](record.md#types-statuses-and-schemas). Edit a template to change
47
+ defaults, or edit the new record afterward.
48
+
49
+ A new [record](record.md) must pass [schema, link and contextual
50
+ checks](validate.md#checks). Failed writes, interruptions and record-validation failures
51
+ remove the new record. Each command then [validates the whole vault](validate.md#scope);
52
+ failure exits with status 1 and retains the valid new record for inspection. Campaign
53
+ creation removes partial campaigns on write failure, but retains them on validation
54
+ failure.
55
+
56
+ ## Adding a campaign
57
+
58
+ Add a [campaign](campaign.md):
59
+
60
+ ```sh
61
+ armarium add campaign --vault ../my-vault
62
+ ```
63
+
64
+ The new number is one greater than the largest existing campaign number; `--number N`
65
+ chooses an unused positive number explicitly.
66
+
67
+ Campaign and Clues templates supply the initial records. Their `campaign_1` and `C-1-`
68
+ clue ID placeholders are updated to the new number; other text is preserved. Players,
69
+ sessions and content are not copied from existing campaigns.
70
+
71
+ ## Adding a record
72
+
73
+ [Content](#content), [Players](#players) and [Notes](#notes) take a name, which becomes
74
+ the filename. Names may contain spaces; omit `.md`.
75
+
76
+ [Sessions](#sessions) and [Clues](#clues) use numbered filenames. By default, the number
77
+ is one greater than the largest existing number of that type in the campaign, including
78
+ archives. Use `--number N` to choose an unused number within the type's range.
79
+
80
+ [References to existing records](record.md#links) must resolve uniquely; use
81
+ vault-relative paths when names are ambiguous.
82
+
83
+ ### Content
84
+
85
+ ```sh
86
+ armarium add content "Port Briselle" --subtype Location --vault ../my-vault
87
+ armarium add content "Mira" --subtype PC --campaign 1 --player Alex --vault ../my-vault
88
+ ```
89
+
90
+ Use `--subtype NPC|PC|Location|Faction|Object|Lore` to select the [Content
91
+ subtype](type.md#content). Required nullable subtype fields start empty unless set in
92
+ the template. PCs need an existing [Player](#players), supplied with `--player` or in
93
+ the template.
94
+
95
+ Shared records start without [campaign state](campaign.md#state). Campaign-specific
96
+ records get a `campaign_N` block, where `N` is the selected campaign number; Objects
97
+ also get `held_by` in that block.
98
+
99
+ ### Sessions
100
+
101
+ ```sh
102
+ armarium add session --campaign 1 --vault ../my-vault
103
+ ```
104
+
105
+ Creates a [Session](type.md#session), `S-N-NNN.md`, with the campaign link and session
106
+ number filled in. Session numbers range from 1 to 999.
107
+
108
+ ### Players
109
+
110
+ ```sh
111
+ armarium add player "Alex" --campaign 1 --vault ../my-vault
112
+ ```
113
+
114
+ The standard template creates an unassigned [Player](type.md#player) with `plays: []`.
115
+ Configured links must target shared or same-campaign PCs. Use [add content](#content) to
116
+ create a PC linked to the new Player; creating a Player does not change PCs or
117
+ backlinks.
118
+
119
+ ### Notes
120
+
121
+ ```sh
122
+ armarium add note "Working ideas" --vault ../my-vault
123
+ armarium add note "Session prep" --campaign 1 --vault ../my-vault
124
+ ```
125
+
126
+ Copies the local [Note](type.md#note) template, including its metadata and body. An
127
+ empty body is valid.
128
+
129
+ ### Clues
130
+
131
+ ```sh
132
+ armarium add clue --campaign 1 --vault ../my-vault --text 'The gate is locked from within.'
133
+ ```
134
+
135
+ Creates a [Clue](type.md#clue), `C-N-NNNN.md`. Clue numbers range from 1 to 9999.
136
+
137
+ Supply nonblank `--text`, or omit it to use nonblank text from the local template.
138
+ `armarium add clue --vault ../my-vault --help` shows the discovered default text, or
139
+ indicates that `--text` is required when the template text is blank.
140
+
141
+ Text goes in [frontmatter](record.md#anatomy). Its [wikilinks](record.md#links) must
142
+ target shared or same-campaign [Content](#content). `subjects` is derived from those
143
+ targets without duplicates, or `[]` for unlinked text. Template status, session fields
144
+ and the Sessions section/Base embed are preserved.
145
+
146
+ ### Transcripts
147
+
148
+ ```sh
149
+ armarium add transcript S-1-001 --body-file recorded-speech.md --vault ../my-vault
150
+ ```
151
+
152
+ Select an existing [Session](#sessions) by name or vault-relative path. Its campaign and
153
+ identity determine the [Transcript](type.md#transcript) destination, `S-N-NNN
154
+ Transcript.md`. No Session is selected automatically.
155
+
156
+ `--body-file` is required and reads UTF-8 Markdown without frontmatter:
157
+
158
+ ```markdown
159
+ ## Arrival
160
+
161
+ - [GM] The door opens.
162
+ - [Player] Who is there?
163
+ ```
164
+
165
+ Follow the [Transcript body format](type.md#body-7): titled level-two sections, each
166
+ containing one bullet list of attributed, single-paragraph utterances. The supplied body
167
+ replaces the template's instructional sample. The command imports already-formatted text
168
+ without transcribing audio, editing speech or changing the source file or Session. Body
169
+ grammar and the local schema are checked before creating the file; link and contextual
170
+ checks follow.
@@ -0,0 +1,46 @@
1
+ # Campaigns
2
+
3
+ Each [vault](vault.md) holds one or more **campaigns**, each in its own directory
4
+ `campaigns/campaign_N/` (with `N` a positive integer). Each campaign describes a series of TTRPG [sessions](type.md#session) in the vault's setting, along with their shared context and metadata.
5
+
6
+ ## Directory
7
+
8
+ ```text
9
+ campaigns/campaign_N/
10
+ clues/ Clue records, C-N-NNNN.md
11
+ content/ Content records specific to this campaign
12
+ notes/ Note records specific to this campaign
13
+ reference/
14
+ Campaign.md the campaign overview, a Reference record
15
+ indexes/
16
+ Clues.md the clue index, a Reference record
17
+ players/ Player records
18
+ sessions/ Session records, S-N-NNN.md
19
+ transcripts/ Transcript records, S-N-NNN Transcript.md
20
+ ```
21
+
22
+ The starter vault ships `campaign_1`. Use [`armarium add campaign`](add.md#adding-a-campaign)
23
+ to add another.
24
+
25
+ ## State
26
+
27
+ [Content](type.md#content) records carry `campaign_N` blocks in their frontmatter describing their campaign-related state:
28
+
29
+ ```yaml
30
+ campaign_1:
31
+ first_session: "[[S-1-001]]"
32
+ last_session: "[[S-1-002]]"
33
+ campaign_2:
34
+ first_session:
35
+ last_session:
36
+ ```
37
+
38
+ A block's `first_session` and `last_session` are both null until the record
39
+ first appears in that campaign, and then both link to the earliest and latest
40
+ Session of that campaign in the record's Appearances. `N` must be an existing
41
+ campaign, and a record under `campaigns/campaign_N/content` may carry only that
42
+ campaign's block; shared Content may carry a block for any campaign.
43
+
44
+ A Content record with the Object subtype has an additional field in its campaign blocks: `held_by`. This is null before the object enters play; then a link to a Content entry denoting the PC, NPC or Faction holding the object, or a list thereof for shared possession; then `GONE` if the object has left play.
45
+
46
+ In addition to the `campaign_N` blocks, a Content entry must also describe its subject's appearances in each campaign in its Appearances section; see [Content](type.md#content) for more details.
@@ -0,0 +1,22 @@
1
+ # Creating a vault
2
+
3
+ ```sh
4
+ armarium init ../my-vault
5
+ ```
6
+
7
+ `armarium init PATH` initializes a new vault in a fresh directory by copying the
8
+ [starter vault](../vaults/starter/). `PATH` must be a nonexistent directory;
9
+ existing files and directories (even empty ones) are refused, as are symbolic
10
+ links. Missing parent directories are automatically created. If copying fails or
11
+ is interrupted, the partially created vault is removed safely. After copying
12
+ completes, the new vault undergoes validation before success is reported.
13
+
14
+ Use `armarium init --force PATH` to replace an existing directory and **all its
15
+ contents** with the starter vault. Files and symbolic links are still refused.
16
+ The replacement is copied before the old directory is removed, so a copy failure
17
+ leaves the existing directory intact.
18
+
19
+ `init` does not initialize Git or install Obsidian plugins. After completion,
20
+ open the new vault in Obsidian and enable the plugins listed in
21
+ [the README](../README.md) before editing. After initialization, the vault can be
22
+ moved or placed in its own Git repository.
@@ -0,0 +1,73 @@
1
+ # Records
2
+
3
+ Every Markdown file in a [vault](vault.md) is a record: YAML frontmatter that
4
+ declares its type, followed by a Markdown body. What every record shares is
5
+ below; each type's fields, body and rules are documented in [Types](type.md).
6
+
7
+ ## Anatomy
8
+
9
+ ```markdown
10
+ ---
11
+ type: "[[types/Content]]"
12
+ subtype: NPC
13
+ summary: Harbour pilot who witnesses petitions.
14
+ aliases: [Mara]
15
+ campaign_1:
16
+ first_session: "[[S-1-001]]"
17
+ last_session: "[[S-1-002]]"
18
+ ---
19
+ ## Notes
20
+ Mara holds a seat for the eastern approaches. ^seat
21
+ ```
22
+
23
+ **Frontmatter** is a YAML mapping between the opening and closing `---` lines.
24
+ Keys must be unique strings and values representable in JSON, so dates are
25
+ written as `YYYY-MM-DD` strings. A record without frontmatter has no type and
26
+ is invalid. Fields beyond a type's schema are allowed on every type.
27
+
28
+ **`type`** is the one field every record must have: a canonical
29
+ [wikilink](#links) to the record's Type record, `[[types/Content]]` or
30
+ `[[Content]]`, with no alias or anchor. The last path segment names the type,
31
+ and `reference/types/Content.md` must exist.
32
+
33
+ **The body** is everything after the closing `---`: CommonMark with tables,
34
+ as Obsidian renders it. Headings divide it into sections, nested by level; a
35
+ paragraph or list item may end in an Obsidian block id (`^seat`). Each type
36
+ fixes which headings its body must have; the rest is free Markdown.
37
+
38
+ **Templates** in `reference/templates/` are starting points, not records:
39
+ their placeholder values need not follow the rules. Copy one to start a record.
40
+
41
+ ## Links
42
+
43
+ Records link to each other with Obsidian
44
+ [internal links](https://help.obsidian.md/links): `[[Quay Nine]]`,
45
+ `[[Quay Nine|the quay]]`, `[[S-1-002#Events]]`, `[[The Bell Accord#^hearing]]`,
46
+ `![[…]]` to embed. Armarium adds these rules:
47
+
48
+ - Every link must resolve to exactly one file. A target matches any trailing
49
+ part of a file's path, case-insensitively and with `.md` optional, so the
50
+ shortest spelling that is unique is enough; when two files share a name,
51
+ spell enough of the path to tell them apart.
52
+ - A heading or block anchor must exist in the linked record. Anchors on files
53
+ that are not records (`![[reference/views/clue-index.base#Active]]`) are
54
+ not validated.
55
+ - In frontmatter a link must be **canonical**: quoted, `"[[target]]"`, with no
56
+ alias or anchor. A frontmatter field may not name the same file twice.
57
+ - Inside a Markdown table, a `|` within a link is written `\|` to avoid
58
+ splitting the link between cells.
59
+
60
+ ## Types, statuses and schemas
61
+
62
+ The type system lives in `reference/`:
63
+
64
+ - A **Type** record in `reference/types/` defines a type: its name is the
65
+ filename, and its `directories` field says
66
+ [where its records live](vault.md#where-records-live).
67
+ - A **schema**, `reference/schemas/<type>.schema.json`, describes each record
68
+ of the type as `{frontmatter, body}` in JSON Schema draft 2020-12: the
69
+ frontmatter as parsed, the body as one string. Every Type has a schema and
70
+ every schema a Type.
71
+ - A **Status** record in `reference/statuses/` defines a lifecycle state for
72
+ one type, named in `applies_to`. A record's `status` must be a Status whose
73
+ `applies_to` is the record's type. The six shipped statuses apply to Clues.
@@ -0,0 +1,20 @@
1
+ # Releases
2
+
3
+ Every PR updates [CHANGELOG.md](../CHANGELOG.md), normally under `Unreleased`.
4
+
5
+ To prepare a release, update `version` in [pyproject.toml](../pyproject.toml),
6
+ rename the `Unreleased` heading to `VERSION (YYYY-MM-DD)`, and add a fresh
7
+ `Unreleased` heading above it. Merge the PR to create a draft GitHub release
8
+ whose text comes from that version's changelog section. The draft targets the
9
+ commit that triggered the workflow. The `draft-release` workflow can also be
10
+ run manually to retry draft creation.
11
+
12
+ Changes to `pyproject.toml` or `CHANGELOG.md` trigger the workflow. It skips
13
+ draft creation unless the changelog has a versioned heading matching the package
14
+ version, and skips versions that already have a GitHub release. PR titles do
15
+ not affect release creation.
16
+
17
+ Review and publish the draft on GitHub. The `publish` workflow checks out the
18
+ release tag, checks that it matches the package version, runs lint, type checks,
19
+ tests and vault validation, then builds and publishes to PyPI. Tags use the
20
+ package version without a `v` prefix, for example `0.1.0`.
@@ -0,0 +1,52 @@
1
+ # Schema development
2
+
3
+ For contributors changing and testing schemas. Record authoring rules
4
+ live in the vault's `reference/types/` Type records.
5
+
6
+ ## Input and schema selection
7
+
8
+ Draft 2020-12 schemas validate `{frontmatter, body}`: parsed frontmatter and the
9
+ Markdown body. Dates are represented as ISO date strings; Session `date` accepts
10
+ `YYYY-MM-DD` or null. Custom frontmatter fields are allowed.
11
+
12
+ Each supported `type` has a schema in the vault's `reference/schemas/` directory:
13
+
14
+ | `type` | Schema |
15
+ | --- | --- |
16
+ | `[[types/Content]]` | `content.schema.json` |
17
+ | `[[types/Clue]]` | `clue.schema.json` |
18
+ | `[[types/Note]]` | `note.schema.json` |
19
+ | `[[types/Session]]` | `session.schema.json` |
20
+ | `[[types/Player]]` | `player.schema.json` |
21
+ | `[[types/Transcript]]` | `transcript.schema.json` |
22
+ | `[[Reference]]` | `reference.schema.json` |
23
+ | `[[Type]]` | `type.schema.json` |
24
+ | `[[Status]]` | `status.schema.json` |
25
+
26
+ Schemas apply to typed records; unfinished templates are a separate category.
27
+ References are local. The tests enable URI and date format assertions.
28
+
29
+ ## Limits
30
+
31
+ Body regexes check basic structure. Duplicate headings and matching fenced text
32
+ can satisfy Content/Session heading checks; Transcript checks only one heading
33
+ and attributed entry. Clue requires Sessions plus one Base embed, but cannot establish that
34
+ it executes or that the embedded Base exists. Content’s Active Clues and each
35
+ Session preparation view section also require exactly one Base embed; other
36
+ sections retain their free Markdown content. Link existence, target kinds, campaign and
37
+ filename identity, chronology, reciprocal relationships and history consistency
38
+ require vault-aware validation.
39
+
40
+ ## Tests
41
+
42
+ From the repository root, without installing Armarium:
43
+
44
+ ```sh
45
+ python3 -m venv /tmp/armarium-schema-venv
46
+ /tmp/armarium-schema-venv/bin/pip install -r tests/schemas/requirements.txt
47
+ /tmp/armarium-schema-venv/bin/python -m pytest tests/schemas -q
48
+ ```
49
+
50
+ Tests cover meta-schemas, offline references, parsed JSON fixtures, committed
51
+ Markdown records and identical schema/type-reference copies in both vaults.
52
+ The PyYAML fixture loader is test support, not a production parser.