ostler 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.
@@ -0,0 +1,218 @@
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[codz]
4
+ *$py.class
5
+
6
+ # C extensions
7
+ *.so
8
+
9
+ # Distribution / packaging
10
+ .Python
11
+ build/
12
+ develop-eggs/
13
+ dist/
14
+ downloads/
15
+ eggs/
16
+ .eggs/
17
+ lib/
18
+ lib64/
19
+ parts/
20
+ sdist/
21
+ var/
22
+ wheels/
23
+ share/python-wheels/
24
+ *.egg-info/
25
+ .installed.cfg
26
+ *.egg
27
+ MANIFEST
28
+
29
+ # PyInstaller
30
+ # Usually these files are written by a python script from a template
31
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
32
+ *.manifest
33
+ *.spec
34
+
35
+ # Installer logs
36
+ pip-log.txt
37
+ pip-delete-this-directory.txt
38
+
39
+ # Unit test / coverage reports
40
+ htmlcov/
41
+ .tox/
42
+ .nox/
43
+ .coverage
44
+ .coverage.*
45
+ .cache
46
+ nosetests.xml
47
+ coverage.xml
48
+ *.cover
49
+ *.py.cover
50
+ .hypothesis/
51
+ .pytest_cache/
52
+ cover/
53
+
54
+ # Translations
55
+ *.mo
56
+ *.pot
57
+
58
+ # Django stuff:
59
+ *.log
60
+ local_settings.py
61
+ db.sqlite3
62
+ db.sqlite3-journal
63
+
64
+ # Flask stuff:
65
+ instance/
66
+ .webassets-cache
67
+
68
+ # Scrapy stuff:
69
+ .scrapy
70
+
71
+ # Sphinx documentation
72
+ docs/_build/
73
+
74
+ # PyBuilder
75
+ .pybuilder/
76
+ target/
77
+
78
+ # Jupyter Notebook
79
+ .ipynb_checkpoints
80
+
81
+ # IPython
82
+ profile_default/
83
+ ipython_config.py
84
+
85
+ # pyenv
86
+ # For a library or package, you might want to ignore these files since the code is
87
+ # intended to run in multiple environments; otherwise, check them in:
88
+ # .python-version
89
+
90
+ # pipenv
91
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
92
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
93
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
94
+ # install all needed dependencies.
95
+ # Pipfile.lock
96
+
97
+ # UV
98
+ # Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
99
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
100
+ # commonly ignored for libraries.
101
+ # uv.lock
102
+
103
+ # poetry
104
+ # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
105
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
106
+ # commonly ignored for libraries.
107
+ # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
108
+ # poetry.lock
109
+ # poetry.toml
110
+
111
+ # pdm
112
+ # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
113
+ # pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python.
114
+ # https://pdm-project.org/en/latest/usage/project/#working-with-version-control
115
+ # pdm.lock
116
+ # pdm.toml
117
+ .pdm-python
118
+ .pdm-build/
119
+
120
+ # pixi
121
+ # Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control.
122
+ # pixi.lock
123
+ # Pixi creates a virtual environment in the .pixi directory, just like venv module creates one
124
+ # in the .venv directory. It is recommended not to include this directory in version control.
125
+ .pixi
126
+
127
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
128
+ __pypackages__/
129
+
130
+ # Celery stuff
131
+ celerybeat-schedule
132
+ celerybeat.pid
133
+
134
+ # Redis
135
+ *.rdb
136
+ *.aof
137
+ *.pid
138
+
139
+ # RabbitMQ
140
+ mnesia/
141
+ rabbitmq/
142
+ rabbitmq-data/
143
+
144
+ # ActiveMQ
145
+ activemq-data/
146
+
147
+ # SageMath parsed files
148
+ *.sage.py
149
+
150
+ # Environments
151
+ .env
152
+ .envrc
153
+ .venv
154
+ env/
155
+ venv/
156
+ ENV/
157
+ env.bak/
158
+ venv.bak/
159
+
160
+ # Spyder project settings
161
+ .spyderproject
162
+ .spyproject
163
+
164
+ # Rope project settings
165
+ .ropeproject
166
+
167
+ # mkdocs documentation
168
+ /site
169
+
170
+ # mypy
171
+ .mypy_cache/
172
+ .dmypy.json
173
+ dmypy.json
174
+
175
+ # Pyre type checker
176
+ .pyre/
177
+
178
+ # pytype static type analyzer
179
+ .pytype/
180
+
181
+ # Cython debug symbols
182
+ cython_debug/
183
+
184
+ # PyCharm
185
+ # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
186
+ # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
187
+ # and can be added to the global gitignore or merged into this file. For a more nuclear
188
+ # option (not recommended) you can uncomment the following to ignore the entire idea folder.
189
+ # .idea/
190
+
191
+ # Abstra
192
+ # Abstra is an AI-powered process automation framework.
193
+ # Ignore directories containing user credentials, local state, and settings.
194
+ # Learn more at https://abstra.io/docs
195
+ .abstra/
196
+
197
+ # Visual Studio Code
198
+ # Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore
199
+ # that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
200
+ # and can be added to the global gitignore or merged into this file. However, if you prefer,
201
+ # you could uncomment the following to ignore the entire vscode folder
202
+ # .vscode/
203
+ # Temporary file for partial code execution
204
+ tempCodeRunnerFile.py
205
+
206
+ # Ruff stuff:
207
+ .ruff_cache/
208
+
209
+ # PyPI configuration file
210
+ .pypirc
211
+
212
+ # Marimo
213
+ marimo/_static/
214
+ marimo/_lsp/
215
+ __marimo__/
216
+
217
+ # Streamlit
218
+ .streamlit/secrets.toml
ostler-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Gabriel Côté
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.
ostler-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,253 @@
1
+ Metadata-Version: 2.4
2
+ Name: ostler
3
+ Version: 0.1.0
4
+ Summary: Define, validate, search and mutate a repository's markdown knowledge graph (OKF profile: epics, stories, seeds, knowledge, features).
5
+ Project-URL: Homepage, https://github.com/GabrielCpp/stablemate
6
+ Project-URL: Repository, https://github.com/GabrielCpp/stablemate
7
+ Project-URL: Issues, https://github.com/GabrielCpp/stablemate/issues
8
+ Author: Gabriel Côté
9
+ License-Expression: MIT
10
+ License-File: LICENSE
11
+ Keywords: agents,docs,epics,knowledge,stories,validation
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Classifier: Programming Language :: Python :: 3.13
17
+ Classifier: Topic :: Software Development :: Documentation
18
+ Classifier: Topic :: Utilities
19
+ Requires-Python: >=3.12
20
+ Requires-Dist: jsonschema>=4.0
21
+ Requires-Dist: markdown-it-py>=3.0
22
+ Requires-Dist: pyyaml>=6.0
23
+ Provides-Extra: dev
24
+ Requires-Dist: pytest>=8.0; extra == 'dev'
25
+ Description-Content-Type: text/markdown
26
+
27
+ # ostler
28
+
29
+ > Tend your documentation graph.
30
+
31
+ `ostler` is the single system-of-record for a repository's `docs/` knowledge graph. It **defines,
32
+ validates, searches and mutates** your planning docs — epics, stories, seeds, knowledge records and
33
+ features — as plain markdown **Concepts** (a strict profile of the
34
+ [Open Knowledge Format](https://github.com/GoogleCloudPlatform/knowledge-catalog/blob/main/okf/SPEC.md)).
35
+
36
+ Everything is markdown. An epic's seeds and its story dependency-DAG live inside its `epic.md`; there
37
+ is **no** `seed.json`, `dependencies.json`, `inventory.json` or `epics-todo.json`. Ostler owns id
38
+ allocation and is the one tool that reads and writes the graph — so structure stays consistent while
39
+ humans (or agents) author the prose.
40
+
41
+ It is a standalone, repo-agnostic CLI that operates relative to the **current working directory**:
42
+ roots default to `<cwd>/docs/{epics,knowledge,features,specs}` and the organization name to the repo
43
+ folder name. Point it at any repo with `-C/--chdir`.
44
+
45
+ ## Install
46
+
47
+ ```bash
48
+ pipx install ostler # recommended: isolated CLI on your PATH
49
+ # or
50
+ pip install ostler
51
+ ```
52
+
53
+ For development against a local checkout:
54
+
55
+ ```bash
56
+ pipx install --editable /path/to/stablemate/ostler --force
57
+ ```
58
+
59
+ The package installs one console entry point, `ostler`.
60
+
61
+ ## Quickstart
62
+
63
+ Ostler creates the *structure and ids*; you author the *content* into the skeletons it scaffolds.
64
+
65
+ ```bash
66
+ # 1. See if the graph is healthy
67
+ ostler doctor
68
+
69
+ # 2. Scaffold an epic (allocates an id, writes docs/epics/checkout-flow/epic.md)
70
+ ostler create epic checkout-flow --title "Checkout Flow at Parity"
71
+
72
+ # 3. Record a seed (a unit of intended work) in that epic's ## Seeds
73
+ ostler seed add checkout-flow address-step --status researched \
74
+ --surface checkout/address --summary "Collect & validate the shipping address"
75
+
76
+ # 4. Cut a story that covers the seed (adds it to the epic's ## Stories, scaffolds story.md)
77
+ ostler create story checkout-flow 01-address-step \
78
+ --title "Address step" --covers address-step
79
+
80
+ # 5. Ask what to work on next, then list the epic's stories as JSON
81
+ ostler next-story checkout-flow
82
+ ostler list --type story --epic checkout-flow --json
83
+ ```
84
+
85
+ Then open the scaffolded `epic.md` / `story.md` and write the narrative, acceptance criteria, and
86
+ prose — ostler keeps the seeds, edges, ids and queue coherent around it.
87
+
88
+ ## The hierarchy
89
+
90
+ A repository's knowledge lives under `docs/` as OKF **bundles** (directories of markdown Concepts).
91
+ A **Concept** is one `.md` file with a YAML **frontmatter** block (whose only hard requirement is a
92
+ non-empty `type`) and a markdown **body** using conventional headings.
93
+
94
+ **Identity is the path.** A Concept's id is its bundle-relative path without `.md`
95
+ (`docs/knowledge/profile/preference-summary.md` → `profile/preference-summary`). The reserved
96
+ filenames `index.md` (an ordered listing of a bundle) and `log.md` (history) are not Concepts.
97
+
98
+ ### Entity types
99
+
100
+ | `type` | Location (repo-relative) | Identity | Required frontmatter |
101
+ |---|---|---|---|
102
+ | `epic` | `docs/epics/<epic>/epic.md` | `<epic>` (dir name) | `type`, `id`, `title` |
103
+ | `story` | `docs/epics/<epic>/stories/<slug>/story.md` | `<slug>` | `type`, `slug`, `status` |
104
+ | `knowledge` | `docs/knowledge/<area>/<name>.md` | path (`surface` alias) | `type`, `surface` |
105
+ | `feature` | `docs/features/<area>/<slug>.md` *(or flat `docs/features/<slug>.md`)* | `<area>/<slug>` | `type`, `slug`, `title` |
106
+ | `spec.plan` / `spec.review` / `spec.qa` | `docs/specs/<slug>/*.md` | path | `type` |
107
+
108
+ `spec.*` Concepts are process artifacts: typed and conformance-checked, but ostler does not own their
109
+ internal schema. **Not Concepts** (managed markdown, left in place): `docs/backlog.md` (an intake list)
110
+ and `docs/epics/index.md` (the epics queue).
111
+
112
+ ### `epic.md` — single source of truth for an epic
113
+
114
+ An epic's `epic.md` carries the narrative **and** its seeds and story dependency-DAG. Ostler parses two
115
+ canonical sections back out of the markdown by exact heading:
116
+
117
+ ```markdown
118
+ ---
119
+ type: epic
120
+ id: pred-15
121
+ title: Account Credits "Aperçu" Billing Body at Legacy Parity
122
+ status: in-progress # optional: planned | in-progress | done
123
+ ---
124
+
125
+ Free narrative prose (any headings: ## Goal, ## Method, ## Acceptance, …).
126
+
127
+ ## Seeds
128
+
129
+ ### apercu-landing-body
130
+ - status: researched # backlog | researched | covered | resolved | dropped | deferred
131
+ - surface: account-billing/apercu-billing-body
132
+ - legacySurface: /{_locale}/employe/profile/edit (BuyCreditsAction)
133
+ - backing: GET /billing/customer → CustomerDetails
134
+
135
+ The first paragraph after the metadata bullets is the seed summary; further prose is free markdown.
136
+
137
+ ## Stories
138
+
139
+ ### 01-apercu-billing-body
140
+ - title: Account Credits "Aperçu" Billing Body at Legacy Parity
141
+ - id: pred-16
142
+ - covers: apercu-landing-body, apercu-subscription-change-plan-link
143
+ - depends on: (none)
144
+ - phase: 1
145
+ - effort: 8-10 hours
146
+ ```
147
+
148
+ - `## Seeds` → `### <seed-id>` per seed (omit the whole section for a seedless epic).
149
+ - `## Stories` → `### <slug>` per story, carrying the **edges**: `covers:` (seed ids) and
150
+ `depends on:` (sibling slugs). The detailed spec lives in the story's own `story.md`.
151
+
152
+ See [`SPEC.md`](SPEC.md) for the authoritative, formal definition of every field, status enum, and
153
+ conformance rule.
154
+
155
+ ## Command interface
156
+
157
+ All read commands accept `--json`. Mutating commands allocate ids as needed and write canonical
158
+ markdown in place.
159
+
160
+ **Global**
161
+
162
+ ```bash
163
+ ostler --version
164
+ ostler -C, --chdir DIR <command> … # operate as if run from DIR
165
+ ```
166
+
167
+ **Inspect**
168
+
169
+ ```bash
170
+ ostler doctor [--epic SLUG] [--json] [--no-schema] # conformance + referential integrity; non-zero on a break
171
+ ostler trace <id|slug|gap|surface|path> # walk the graph from any node
172
+ ```
173
+
174
+ **Retrieve**
175
+
176
+ ```bash
177
+ ostler list --type epic|story|knowledge|feature|spec|seed|gap [--epic E] [--status S] [--json]
178
+ ostler search <query> [--type T] [--owner O] [--tag G] [--json]
179
+ ostler query gaps-in-story|stories-covering-seed|surfaces-referenced-by-story <arg> [--json]
180
+ ostler next-epic [--json] # next queued epic with unfinished work
181
+ ostler next-story <epic> [--json] # next runnable story (deps satisfied, not done)
182
+ ```
183
+
184
+ **Mutate** (allocates ids, writes markdown)
185
+
186
+ ```bash
187
+ ostler create epic <name> --title T [--prefix P] [--json]
188
+ ostler create story <epic> <slug> --title T [--covers a,b] [--depends a,b] [--prefix P] [--json]
189
+ ostler create feature <slug> --title T [--area A] [--route R] [--prefix P] [--json]
190
+ ostler delete epic|story|feature <name>
191
+
192
+ ostler seed add <epic> <id> [--status S] [--summary …] [--surface …] \
193
+ [--legacy-surface …] [--backing …] [--prerequisites …] [--source-bullet …]
194
+ ostler seed remove <epic> <id>
195
+ ostler set-status <story> <status>
196
+
197
+ ostler backlog add <id> <text> [--section S] | ostler backlog prune <id> | ostler backlog list [--json]
198
+ ostler todo add <epic> [--front] | ostler todo prune <epic> | ostler todo reorder <e…> | ostler todo list [--json]
199
+ ```
200
+
201
+ `create … --json` returns `{"ok": true, "id": "<allocated-id>", "message": "…"}`.
202
+
203
+ **Repair / approve**
204
+
205
+ ```bash
206
+ ostler edit set-owner <gap> <story> [--write] # dry-run by default; --write applies
207
+ ostler edit relink <old-path> <new-path> [--write]
208
+ ostler edit rename <old-slug> <new-slug> [--write]
209
+ ostler freeze <ident> [--by WHO] [--note …] # pin an approved story/seed as immutable ground truth
210
+ ostler unfreeze <ident>
211
+ ```
212
+
213
+ ## The coverage model
214
+
215
+ ```
216
+ knowledge gaps[].owner -> story (epic.md ## Stories) -> covers: seed (epic.md ## Seeds)
217
+ ```
218
+
219
+ `ostler doctor` checks OKF conformance (every Concept has a non-empty `type`) plus the typed
220
+ referential-integrity contract:
221
+
222
+ - **cross-epic references** — an id/slug used inside epic E that only resolves in another epic;
223
+ - **orphan seeds** — an active seed no story covers;
224
+ - **dangling references** — a `[gap:…]` tag, knowledge path, or sibling slug that resolves to nothing;
225
+ - **stale owners** — a non-resolved gap whose `owner` is empty or points at a missing story;
226
+ - **frozen drift** — an approved (frozen) story/seed that changed or vanished.
227
+
228
+ It exits non-zero when any error-level finding is present, so it drops straight into CI or a pre-commit
229
+ hook. Warning-level findings (e.g. `story-covers-no-seed`, `ungrounded-surface`) are reported but do
230
+ not fail the check.
231
+
232
+ ## Id allocation
233
+
234
+ Ostler owns `.agents/ids.json` (`{prefix, counter, frozen}`). `create epic|story|feature` allocates the
235
+ next `<prefix>-<n>` id atomically, scaffolds the canonical markdown, and (for stories) inserts the
236
+ `### <slug>` block into the epic's `## Stories`. There is no external id allocator.
237
+
238
+ ## Profiles
239
+
240
+ `ostler` infers a profile from the tree: **`full`** when `docs/epics` exists (the epic/story/seed/
241
+ knowledge coverage graph), **`exploration`** otherwise (knowledge/docs only, no coverage graph).
242
+ Override any default in an optional `organization:` block in `ostler.yml` / `agents.yml` at the repo
243
+ root.
244
+
245
+ ## Versioning
246
+
247
+ The format is the OKF profile **v1.0**, versioned `<major>.<minor>`. Minor bumps add backward-compatible
248
+ fields; major bumps may change required frontmatter or the `epic.md` grammar. A repo may record
249
+ `okf_version` and `ostler_profile` in `docs/epics/index.md`.
250
+
251
+ ## License
252
+
253
+ See [`LICENSE`](LICENSE).