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.
- ostler-0.1.0/.gitignore +218 -0
- ostler-0.1.0/LICENSE +21 -0
- ostler-0.1.0/PKG-INFO +253 -0
- ostler-0.1.0/README.md +227 -0
- ostler-0.1.0/SPEC.md +174 -0
- ostler-0.1.0/ostler/__init__.py +3 -0
- ostler-0.1.0/ostler/backlog.py +73 -0
- ostler-0.1.0/ostler/cli.py +307 -0
- ostler-0.1.0/ostler/crud.py +232 -0
- ostler-0.1.0/ostler/doctor.py +275 -0
- ostler-0.1.0/ostler/edit.py +154 -0
- ostler-0.1.0/ostler/freeze.py +116 -0
- ostler-0.1.0/ostler/ids.py +79 -0
- ostler-0.1.0/ostler/markdown.py +238 -0
- ostler-0.1.0/ostler/model.py +385 -0
- ostler-0.1.0/ostler/query.py +137 -0
- ostler-0.1.0/ostler/registry.py +118 -0
- ostler-0.1.0/ostler/schema/epic.schema.json +14 -0
- ostler-0.1.0/ostler/schema/feature.schema.json +16 -0
- ostler-0.1.0/ostler/schema/ids.schema.json +30 -0
- ostler-0.1.0/ostler/schema/knowledge-record.schema.json +36 -0
- ostler-0.1.0/ostler/schema/story.schema.json +14 -0
- ostler-0.1.0/ostler/schemas.py +27 -0
- ostler-0.1.0/ostler/scripts/__init__.py +0 -0
- ostler-0.1.0/ostler/scripts/okf_migrate.py +327 -0
- ostler-0.1.0/ostler/select.py +59 -0
- ostler-0.1.0/ostler/todo.py +81 -0
- ostler-0.1.0/ostler/trace.py +79 -0
- ostler-0.1.0/pyproject.toml +48 -0
ostler-0.1.0/.gitignore
ADDED
|
@@ -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).
|