flo-pm 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 (70) hide show
  1. flo_pm-0.1.0/.gitignore +6 -0
  2. flo_pm-0.1.0/PKG-INFO +173 -0
  3. flo_pm-0.1.0/README.md +162 -0
  4. flo_pm-0.1.0/examples/kettle/.context/README.md +184 -0
  5. flo_pm-0.1.0/examples/kettle/.context/TEMPLATE.md +45 -0
  6. flo_pm-0.1.0/examples/kettle/.context/favicon.svg +14 -0
  7. flo_pm-0.1.0/examples/kettle/.context/loyalty.md +37 -0
  8. flo_pm-0.1.0/examples/kettle/.context/menu.md +42 -0
  9. flo_pm-0.1.0/examples/kettle/.context/ordering.md +70 -0
  10. flo_pm-0.1.0/examples/kettle/.context/payments.md +58 -0
  11. flo_pm-0.1.0/examples/kettle/.context/pos/README.md +35 -0
  12. flo_pm-0.1.0/examples/kettle/.context/pos/opening-hours.md +32 -0
  13. flo_pm-0.1.0/examples/kettle/.context/pos/till-sync.md +38 -0
  14. flo_pm-0.1.0/examples/kettle/.issues/KET-01-menu-data-model.md +28 -0
  15. flo_pm-0.1.0/examples/kettle/.issues/KET-02-basket-and-checkout.md +28 -0
  16. flo_pm-0.1.0/examples/kettle/.issues/KET-03-pickup-slot-picker.md +28 -0
  17. flo_pm-0.1.0/examples/kettle/.issues/KET-04-shop-opening-hours.md +27 -0
  18. flo_pm-0.1.0/examples/kettle/.issues/KET-05-card-payments.md +32 -0
  19. flo_pm-0.1.0/examples/kettle/.issues/KET-06-refunds-on-cancel.md +29 -0
  20. flo_pm-0.1.0/examples/kettle/.issues/KET-07-order-confirmation-messages.md +23 -0
  21. flo_pm-0.1.0/examples/kettle/.issues/KET-08-orders-to-shop-tills.md +31 -0
  22. flo_pm-0.1.0/examples/kettle/.issues/KET-09-allergen-labels.md +28 -0
  23. flo_pm-0.1.0/examples/kettle/.issues/KET-10-deploy-pipeline.md +24 -0
  24. flo_pm-0.1.0/examples/kettle/.issues/KET-11-monitoring-and-alerts.md +27 -0
  25. flo_pm-0.1.0/examples/kettle/.issues/KET-12-loyalty-points.md +27 -0
  26. flo_pm-0.1.0/examples/kettle/.issues/KET-13-customer-accounts.md +24 -0
  27. flo_pm-0.1.0/examples/kettle/.issues/KET-14-checkout-screen-reader-pass.md +23 -0
  28. flo_pm-0.1.0/examples/kettle/.issues/KET-15-courier-delivery.md +21 -0
  29. flo_pm-0.1.0/examples/kettle/.issues/KET-16-gift-cards.md +25 -0
  30. flo_pm-0.1.0/examples/kettle/.issues/KET-17-daily-sales-export.md +21 -0
  31. flo_pm-0.1.0/examples/kettle/.issues/KET-18-price-list-sign-off.md +23 -0
  32. flo_pm-0.1.0/examples/kettle/.issues/NEXT-ID +1 -0
  33. flo_pm-0.1.0/examples/kettle/.issues/README.md +204 -0
  34. flo_pm-0.1.0/examples/kettle/.issues/TEMPLATE.md +37 -0
  35. flo_pm-0.1.0/examples/kettle/.issues/favicon.svg +12 -0
  36. flo_pm-0.1.0/examples/kettle/flo-theme.css +64 -0
  37. flo_pm-0.1.0/examples/kettle/flo.toml +358 -0
  38. flo_pm-0.1.0/pyproject.toml +36 -0
  39. flo_pm-0.1.0/src/flo/__init__.py +3 -0
  40. flo_pm-0.1.0/src/flo/backlog.py +4954 -0
  41. flo_pm-0.1.0/src/flo/burnup.py +2318 -0
  42. flo_pm-0.1.0/src/flo/cli.py +100 -0
  43. flo_pm-0.1.0/src/flo/config.py +290 -0
  44. flo_pm-0.1.0/src/flo/context.py +3147 -0
  45. flo_pm-0.1.0/src/flo/delivery.py +1147 -0
  46. flo_pm-0.1.0/src/flo/epics.py +829 -0
  47. flo_pm-0.1.0/src/flo/ids.py +34 -0
  48. flo_pm-0.1.0/src/flo/init.py +161 -0
  49. flo_pm-0.1.0/src/flo/menu.py +141 -0
  50. flo_pm-0.1.0/src/flo/migrate.py +61 -0
  51. flo_pm-0.1.0/src/flo/roadmap.py +1298 -0
  52. flo_pm-0.1.0/src/flo/site.py +352 -0
  53. flo_pm-0.1.0/src/flo/templates/context/README.md +184 -0
  54. flo_pm-0.1.0/src/flo/templates/context/TEMPLATE.md +45 -0
  55. flo_pm-0.1.0/src/flo/templates/context/favicon.svg +14 -0
  56. flo_pm-0.1.0/src/flo/templates/delivery.toml +29 -0
  57. flo_pm-0.1.0/src/flo/templates/epics.toml +19 -0
  58. flo_pm-0.1.0/src/flo/templates/flo.toml +32 -0
  59. flo_pm-0.1.0/src/flo/templates/issues/README.md +204 -0
  60. flo_pm-0.1.0/src/flo/templates/issues/TEMPLATE.md +37 -0
  61. flo_pm-0.1.0/src/flo/templates/issues/favicon.svg +12 -0
  62. flo_pm-0.1.0/src/flo/templates/labels-reports.toml +27 -0
  63. flo_pm-0.1.0/src/flo/templates/labels.toml +83 -0
  64. flo_pm-0.1.0/src/flo/templates/roadmap.toml +49 -0
  65. flo_pm-0.1.0/src/flo/templates/workpackages.toml +35 -0
  66. flo_pm-0.1.0/src/flo/theme.py +53 -0
  67. flo_pm-0.1.0/src/flo/vendor/mermaid.min.js +2314 -0
  68. flo_pm-0.1.0/src/flo/workpackages.py +728 -0
  69. flo_pm-0.1.0/tests/test_kettle.py +259 -0
  70. flo_pm-0.1.0/wheelhouse/.gitignore +1 -0
@@ -0,0 +1,6 @@
1
+ .DS_Store
2
+ __pycache__/
3
+ *.pyc
4
+ .venv/
5
+ dist/
6
+ *.egg-info/
flo_pm-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,173 @@
1
+ Metadata-Version: 2.5
2
+ Name: flo-pm
3
+ Version: 0.1.0
4
+ Summary: Static sites and reports from a repo's .issues/ and .context/ markdown
5
+ Project-URL: Repository, https://github.com/BramEsposito/flo-pm
6
+ Project-URL: Issues, https://github.com/BramEsposito/flo-pm/issues
7
+ Requires-Python: >=3.11
8
+ Requires-Dist: markdown>=3.5
9
+ Requires-Dist: pyyaml>=6.0
10
+ Description-Content-Type: text/markdown
11
+
12
+ # flo
13
+
14
+ Static sites and reports from a repository's own markdown: an issue backlog
15
+ in `.issues/`, the project's design context in `.context/`, and release
16
+ reports read off both. No server and no database: the issue files live next
17
+ to the code they are about, and every page works straight from `file://`.
18
+
19
+ | Command | Builds | From |
20
+ |---|---|---|
21
+ | `flo issues` | a filterable issues site, one page per issue | `.issues/*.md`, `[labels]` |
22
+ | `flo context` | a site of the project's scope files, checked for broken deep links | `.context/**/*.md` |
23
+ | `flo burnup` | a burnup chart: scope against closed, per release | the issues |
24
+ | `flo roadmap` | when each release can ship, theme by theme, at the planned pace | the issues + `[roadmap]` |
25
+ | `flo workpackages` | the open work grouped into packages, and each one's progress | the issues + `[workpackages]` |
26
+ | `flo epics` | every issue ever filed grouped by the part of the product it belongs to, with each epic's points left, pace and history | the issues + `[epics]` |
27
+ | `flo delivery` | what stands between a release and shipping, with code checks | the issues + `[delivery]` |
28
+ | `flo build` | all of the above that the project has inputs for | |
29
+ | `flo init` | sets a project up for all of it | |
30
+ | `flo migrate` | folds an older project's `labels.toml`, `roadmap.toml`, … into `flo.toml` | |
31
+
32
+ `examples/kettle/` is a complete project to look at: a pickup-ordering app
33
+ for a fictional bakery chain, with eighteen issues, a context directory and
34
+ every report configured. `cd examples/kettle && flo build` and open
35
+ `dist/issues-site/index.html`.
36
+
37
+ ## Install
38
+
39
+ Globally, as a command available in every project:
40
+
41
+ ```sh
42
+ uv tool install flo-pm # or: pipx install flo-pm
43
+ ```
44
+
45
+ Or per project, pinned with the rest of the dev tooling:
46
+
47
+ ```sh
48
+ uv add --dev flo-pm # then: uv run flo build
49
+ ```
50
+
51
+ The package is `flo-pm` on PyPI (`flo` there is an unrelated project);
52
+ either way the command is `flo`, and it reads the `flo.toml` of whatever
53
+ project you run it in. Python 3.11+.
54
+
55
+ ## Start a project
56
+
57
+ ```sh
58
+ flo init --name Kettle --prefix KET --reports
59
+ flo build
60
+ ```
61
+
62
+ `init` writes `flo.toml` — flo's settings and the `[labels]` every issue is
63
+ checked against — an issues directory and a context directory, each with a
64
+ README that explains its conventions, a `TEMPLATE.md` to copy and an icon, and
65
+ a starter issue and scope file. `--reports` adds the `[roadmap]`,
66
+ `[workpackages]` and `[delivery]` blocks. It only ever adds — files, and
67
+ blocks to an existing `flo.toml` — so it is safe to run in a project that
68
+ already has some of them.
69
+
70
+ Both directories are [Open Knowledge Format](https://github.com/GoogleCloudPlatform/knowledge-catalog/blob/main/okf/SPEC.md)
71
+ bundles as they stand: every markdown file `init` writes carries a `type`
72
+ (`Issue`, `Context`, `Guide`), the one key OKF requires, and the sites warn
73
+ about a file without one. `index.md` and `log.md`, the names OKF reserves,
74
+ are never read as issues or scopes.
75
+
76
+ The conventions are the substance: **one markdown file per issue, which never
77
+ moves; `status` is the only thing that says where it stands; one context file
78
+ per scope, split into AS IS and TO BE, with no history in it.** The two READMEs
79
+ `init` writes spell them out, and the sites warn when a file breaks them.
80
+
81
+ ## `flo.toml`
82
+
83
+ Everything flo needs to know about a project, in one file with one clearly
84
+ marked block per concern: flo's own settings, then the project's data — the
85
+ label vocabulary and the plans the reports are drawn from. Found by walking up
86
+ from the working directory, so `flo` works from anywhere in the project. Paths
87
+ are relative to the file.
88
+
89
+ ```toml
90
+ # ══ flo — where things are, what issues are called, how the sites look ══════
91
+ [project]
92
+ name = "Kettle" # shown on every page (default: the directory name)
93
+ id_prefix = "KET" # issues are KET-1, KET-2, … (default: ISS)
94
+
95
+ [paths]
96
+ issues = ".issues"
97
+ context = ".context"
98
+ out = "dist" # each site is a directory under it
99
+
100
+ [urls] # where a dev server serves each site, if one does
101
+ issues = "/issues/" # (defaults: /issues/, /context/, /burnup/, …)
102
+
103
+ [theme]
104
+ css = "flo-theme.css" # inlined at the end of every page's <head>
105
+ fonts = "https://fonts.googleapis.com/css2?family=…"
106
+
107
+ [menu] # the strip of links across the pages, in order
108
+ tools = ["issues", "context", "burnup", "roadmap", "workpackages", "epics", "delivery"]
109
+ home = { label = "Home", url = "/" }
110
+
111
+ # ══ labels — the vocabulary every issue is checked against ══════════════════
112
+ [labels.issue] # which frontmatter keys every issue must answer
113
+ [labels.status] # one section per label field, with its allowed values
114
+ [labels.assignee]
115
+ [labels.tags] # … and any field of your own: version, points, theme
116
+
117
+ # ══ roadmap — the plan `flo roadmap` lays the releases out by ═══════════════
118
+ [roadmap.plan] # start, pace, baseline
119
+ [[roadmap.release]] # each release, its reserve…
120
+ [[roadmap.release.theme]] # …and the themes it is scheduled in
121
+
122
+ # ══ workpackages — what each package of work is ═════════════════════════════
123
+ [workpackages] # the releases in scope, the baseline
124
+ [[workpackages.kind]]
125
+ [[workpackages.package]]
126
+ # ══ epics — what each epic is ════════════════════════════════════════════════
127
+ [[epics.epic]] # key, name, blurb; an issue's `epic` names one
128
+
129
+ # ══ delivery — the recommended path the delivery report follows ═════════════
130
+ [delivery.review] # the review date and the release it was for
131
+ [[delivery.lane]] # the order to clear the work in
132
+ ```
133
+
134
+ `examples/kettle/flo.toml` is a complete one, every block filled in. A project
135
+ without a `[roadmap]` simply has no roadmap — `flo build` skips it — and the
136
+ same goes for the other two report blocks.
137
+
138
+ Older projects kept the data blocks as files of their own in the issues
139
+ directory (`labels.toml`, `roadmap.toml`, `workpackages.toml`, `epics.toml`,
140
+ `delivery-review.toml`). flo still reads those, with a note, and `flo migrate`
141
+ folds them into `flo.toml` — comments and all — checking that each block reads
142
+ back as its file did before deleting the file.
143
+
144
+ Every command's flags default to these values, and still override them: `flo
145
+ roadmap --as-of 2026-11-01`, `flo issues --watch`. `flo <command> --help`
146
+ lists them.
147
+
148
+ ## Theming
149
+
150
+ Every page ships flo's neutral theme — system fonts, a palette declared as
151
+ custom properties on `:root`, redefined for dark mode. A project's `[theme]
152
+ css` comes after it, so redefining a property wins. Define dark-mode values
153
+ with the pages' own selectors (`@media (prefers-color-scheme: dark) {
154
+ :root:not([data-theme="light"]) { … } }` and `:root[data-theme="dark"]`);
155
+ they are more specific than a bare `:root`. `examples/kettle/flo-theme.css`
156
+ covers the tokens each page reads.
157
+
158
+ ## Development
159
+
160
+ ```sh
161
+ uv venv && uv pip install -e . pytest
162
+ .venv/bin/python -m pytest
163
+ ```
164
+
165
+ CI runs the tests on every push and pull request
166
+ (`.github/workflows/ci.yml`). A version tag publishes to PyPI: bump `version`
167
+ in `pyproject.toml`, commit, then `git tag v<version> && git push origin
168
+ v<version>` (`.github/workflows/publish.yml`, through PyPI trusted
169
+ publishing — no token is stored).
170
+
171
+ The test suite builds the Kettle example and a freshly initialised project,
172
+ and fails on any build warning — so a change to a generator, a template or the
173
+ example is checked end to end.
flo_pm-0.1.0/README.md ADDED
@@ -0,0 +1,162 @@
1
+ # flo
2
+
3
+ Static sites and reports from a repository's own markdown: an issue backlog
4
+ in `.issues/`, the project's design context in `.context/`, and release
5
+ reports read off both. No server and no database: the issue files live next
6
+ to the code they are about, and every page works straight from `file://`.
7
+
8
+ | Command | Builds | From |
9
+ |---|---|---|
10
+ | `flo issues` | a filterable issues site, one page per issue | `.issues/*.md`, `[labels]` |
11
+ | `flo context` | a site of the project's scope files, checked for broken deep links | `.context/**/*.md` |
12
+ | `flo burnup` | a burnup chart: scope against closed, per release | the issues |
13
+ | `flo roadmap` | when each release can ship, theme by theme, at the planned pace | the issues + `[roadmap]` |
14
+ | `flo workpackages` | the open work grouped into packages, and each one's progress | the issues + `[workpackages]` |
15
+ | `flo epics` | every issue ever filed grouped by the part of the product it belongs to, with each epic's points left, pace and history | the issues + `[epics]` |
16
+ | `flo delivery` | what stands between a release and shipping, with code checks | the issues + `[delivery]` |
17
+ | `flo build` | all of the above that the project has inputs for | |
18
+ | `flo init` | sets a project up for all of it | |
19
+ | `flo migrate` | folds an older project's `labels.toml`, `roadmap.toml`, … into `flo.toml` | |
20
+
21
+ `examples/kettle/` is a complete project to look at: a pickup-ordering app
22
+ for a fictional bakery chain, with eighteen issues, a context directory and
23
+ every report configured. `cd examples/kettle && flo build` and open
24
+ `dist/issues-site/index.html`.
25
+
26
+ ## Install
27
+
28
+ Globally, as a command available in every project:
29
+
30
+ ```sh
31
+ uv tool install flo-pm # or: pipx install flo-pm
32
+ ```
33
+
34
+ Or per project, pinned with the rest of the dev tooling:
35
+
36
+ ```sh
37
+ uv add --dev flo-pm # then: uv run flo build
38
+ ```
39
+
40
+ The package is `flo-pm` on PyPI (`flo` there is an unrelated project);
41
+ either way the command is `flo`, and it reads the `flo.toml` of whatever
42
+ project you run it in. Python 3.11+.
43
+
44
+ ## Start a project
45
+
46
+ ```sh
47
+ flo init --name Kettle --prefix KET --reports
48
+ flo build
49
+ ```
50
+
51
+ `init` writes `flo.toml` — flo's settings and the `[labels]` every issue is
52
+ checked against — an issues directory and a context directory, each with a
53
+ README that explains its conventions, a `TEMPLATE.md` to copy and an icon, and
54
+ a starter issue and scope file. `--reports` adds the `[roadmap]`,
55
+ `[workpackages]` and `[delivery]` blocks. It only ever adds — files, and
56
+ blocks to an existing `flo.toml` — so it is safe to run in a project that
57
+ already has some of them.
58
+
59
+ Both directories are [Open Knowledge Format](https://github.com/GoogleCloudPlatform/knowledge-catalog/blob/main/okf/SPEC.md)
60
+ bundles as they stand: every markdown file `init` writes carries a `type`
61
+ (`Issue`, `Context`, `Guide`), the one key OKF requires, and the sites warn
62
+ about a file without one. `index.md` and `log.md`, the names OKF reserves,
63
+ are never read as issues or scopes.
64
+
65
+ The conventions are the substance: **one markdown file per issue, which never
66
+ moves; `status` is the only thing that says where it stands; one context file
67
+ per scope, split into AS IS and TO BE, with no history in it.** The two READMEs
68
+ `init` writes spell them out, and the sites warn when a file breaks them.
69
+
70
+ ## `flo.toml`
71
+
72
+ Everything flo needs to know about a project, in one file with one clearly
73
+ marked block per concern: flo's own settings, then the project's data — the
74
+ label vocabulary and the plans the reports are drawn from. Found by walking up
75
+ from the working directory, so `flo` works from anywhere in the project. Paths
76
+ are relative to the file.
77
+
78
+ ```toml
79
+ # ══ flo — where things are, what issues are called, how the sites look ══════
80
+ [project]
81
+ name = "Kettle" # shown on every page (default: the directory name)
82
+ id_prefix = "KET" # issues are KET-1, KET-2, … (default: ISS)
83
+
84
+ [paths]
85
+ issues = ".issues"
86
+ context = ".context"
87
+ out = "dist" # each site is a directory under it
88
+
89
+ [urls] # where a dev server serves each site, if one does
90
+ issues = "/issues/" # (defaults: /issues/, /context/, /burnup/, …)
91
+
92
+ [theme]
93
+ css = "flo-theme.css" # inlined at the end of every page's <head>
94
+ fonts = "https://fonts.googleapis.com/css2?family=…"
95
+
96
+ [menu] # the strip of links across the pages, in order
97
+ tools = ["issues", "context", "burnup", "roadmap", "workpackages", "epics", "delivery"]
98
+ home = { label = "Home", url = "/" }
99
+
100
+ # ══ labels — the vocabulary every issue is checked against ══════════════════
101
+ [labels.issue] # which frontmatter keys every issue must answer
102
+ [labels.status] # one section per label field, with its allowed values
103
+ [labels.assignee]
104
+ [labels.tags] # … and any field of your own: version, points, theme
105
+
106
+ # ══ roadmap — the plan `flo roadmap` lays the releases out by ═══════════════
107
+ [roadmap.plan] # start, pace, baseline
108
+ [[roadmap.release]] # each release, its reserve…
109
+ [[roadmap.release.theme]] # …and the themes it is scheduled in
110
+
111
+ # ══ workpackages — what each package of work is ═════════════════════════════
112
+ [workpackages] # the releases in scope, the baseline
113
+ [[workpackages.kind]]
114
+ [[workpackages.package]]
115
+ # ══ epics — what each epic is ════════════════════════════════════════════════
116
+ [[epics.epic]] # key, name, blurb; an issue's `epic` names one
117
+
118
+ # ══ delivery — the recommended path the delivery report follows ═════════════
119
+ [delivery.review] # the review date and the release it was for
120
+ [[delivery.lane]] # the order to clear the work in
121
+ ```
122
+
123
+ `examples/kettle/flo.toml` is a complete one, every block filled in. A project
124
+ without a `[roadmap]` simply has no roadmap — `flo build` skips it — and the
125
+ same goes for the other two report blocks.
126
+
127
+ Older projects kept the data blocks as files of their own in the issues
128
+ directory (`labels.toml`, `roadmap.toml`, `workpackages.toml`, `epics.toml`,
129
+ `delivery-review.toml`). flo still reads those, with a note, and `flo migrate`
130
+ folds them into `flo.toml` — comments and all — checking that each block reads
131
+ back as its file did before deleting the file.
132
+
133
+ Every command's flags default to these values, and still override them: `flo
134
+ roadmap --as-of 2026-11-01`, `flo issues --watch`. `flo <command> --help`
135
+ lists them.
136
+
137
+ ## Theming
138
+
139
+ Every page ships flo's neutral theme — system fonts, a palette declared as
140
+ custom properties on `:root`, redefined for dark mode. A project's `[theme]
141
+ css` comes after it, so redefining a property wins. Define dark-mode values
142
+ with the pages' own selectors (`@media (prefers-color-scheme: dark) {
143
+ :root:not([data-theme="light"]) { … } }` and `:root[data-theme="dark"]`);
144
+ they are more specific than a bare `:root`. `examples/kettle/flo-theme.css`
145
+ covers the tokens each page reads.
146
+
147
+ ## Development
148
+
149
+ ```sh
150
+ uv venv && uv pip install -e . pytest
151
+ .venv/bin/python -m pytest
152
+ ```
153
+
154
+ CI runs the tests on every push and pull request
155
+ (`.github/workflows/ci.yml`). A version tag publishes to PyPI: bump `version`
156
+ in `pyproject.toml`, commit, then `git tag v<version> && git push origin
157
+ v<version>` (`.github/workflows/publish.yml`, through PyPI trusted
158
+ publishing — no token is stored).
159
+
160
+ The test suite builds the Kettle example and a freshly initialised project,
161
+ and fails on any build warning — so a change to a generator, a template or the
162
+ example is checked end to end.
@@ -0,0 +1,184 @@
1
+ ---
2
+ type: Guide
3
+ title: Context conventions
4
+ ---
5
+
6
+ # Context
7
+
8
+ This directory records **Kettle's context**: standing, formalized facts,
9
+ designs and decisions. `.issues/` tracks work that still needs doing;
10
+ `.context/` tracks what the project *is* and what it is *meant to become*,
11
+ so neither has to be reconstructed from scattered conversations every time
12
+ it's relevant.
13
+
14
+ Three rules govern everything below:
15
+
16
+ 1. **One file per scope.** Every scope gets a context file, and the
17
+ information for that scope is recorded **in that file only** — never
18
+ duplicated into a second file, an issue, or an agent's instructions file.
19
+ 2. **Every file splits into AS IS and TO BE.** What exists today, and what is
20
+ designed but not built yet.
21
+ 3. **No history.** Git log is the history.
22
+
23
+ ---
24
+
25
+ ## 1. One file per scope, referenced by deep link
26
+
27
+ Each scope is written down **once**, in its own file. Anything elsewhere that
28
+ needs that information — another context file, an issue, a README, a code
29
+ comment, a commit message — **links to it instead of restating it**.
30
+
31
+ - Link with a **deep link to the heading**, not just the file, so the reader
32
+ lands on the fact rather than on a 600-line document:
33
+ - from inside `.context/` — `[refunds](payments.md#refunds)`
34
+ - from anywhere else in the repo —
35
+ `[refunds](.context/payments.md#refunds)`
36
+ - Anchors are the GitHub slug of the heading text: lowercased, spaces to `-`,
37
+ punctuation dropped (`### Refunds (v2, current)` → `#refunds-v2-current`).
38
+ Keep headings stable-ish; when you rename one, fix the links that pointed at
39
+ it (`grep -rn 'payments.md#old-anchor' --include='*.md' .`).
40
+ - If you catch yourself re-explaining something that lives in another scope's
41
+ file: delete the explanation, link to it. A summarizing sentence plus a deep
42
+ link is fine; a second copy of the facts is not — two copies drift, and then
43
+ neither is trustworthy.
44
+ - If a fact doesn't fit any existing scope, that's the signal to create a new
45
+ scope file, not to park it in the nearest one.
46
+
47
+ ## 2. AS IS and TO BE
48
+
49
+ Every scope file has exactly these two top-level sections, in this order:
50
+
51
+ ```
52
+ # <Scope title>
53
+
54
+ intro: what this file is the source of truth for
55
+
56
+ ## AS IS ← the current design: what is built and running today
57
+ ### <sub-topic>
58
+ ### <sub-topic>
59
+
60
+ ## TO BE ← the designed-but-not-yet-built target state
61
+ ### <sub-topic>
62
+ ### <sub-topic>
63
+
64
+ ## See also
65
+ ```
66
+
67
+ - **AS IS** — the design as it actually exists in the code right now. Cite
68
+ code as evidence: `src/orders/checkout.py:120-180`, `Basket.total`.
69
+ - **TO BE** — functionality that is *designed* but not built. Each entry says
70
+ what the target state is and links the issue that will build it
71
+ (`[[KET-40]]`). A TO BE entry with no issue behind it is a design
72
+ note, not a plan — say so (`**Issue:** none filed`).
73
+ - Keep the boundary sharp. Never let a TO BE design read as if it were live,
74
+ and mark status explicitly per sub-topic: **decided** / **confirmed** /
75
+ **to be decided**. Something that's built but behind a debug flag is AS IS —
76
+ and says so.
77
+ - When a TO BE item ships, **move it into AS IS and rewrite it in the present
78
+ tense**. Don't leave the old TO BE text behind as a record of what was
79
+ planned — that's history (rule 3).
80
+ - Either section may be empty: write `_Nothing designed beyond AS IS._` or
81
+ `_Not built yet._` rather than dropping the heading, so its absence never
82
+ has to be interpreted.
83
+ - **One exception: a catalog** — a file whose body is a list of like entries
84
+ (rules, an inventory of feature flags) may carry a **status per entry**
85
+ instead of the two blocks, since that is the same distinction at a finer
86
+ grain. It must say the word "catalog" in its first paragraph — that's how
87
+ the site recognises one — and every not-yet-implemented entry still links
88
+ its issue.
89
+
90
+ ### Formatting within a section
91
+
92
+ Use the full toolbox — these files are read to answer a question fast, not
93
+ front to back:
94
+
95
+ - **Headings and subheadings** (`###`, `####`) per sub-topic — they're also
96
+ the deep-link targets other files point at.
97
+ - **Bulleted lists** for facts, constraints and caveats.
98
+ - **Numbered lists** for anything with an order: a flow, a sequence of steps,
99
+ a release procedure, ranked options.
100
+ - **Tables** for inventories: settings keys, endpoints, environment variables.
101
+ - **Diagrams** for anything with shape — a request flow, a state machine. ASCII
102
+ box drawings in a fenced block, or a fenced `mermaid` block; put the diagram
103
+ before the prose that explains it.
104
+
105
+ ## 3. No history
106
+
107
+ These files describe the **current** state of the world, not how it got there.
108
+
109
+ - **Don't** write changelogs, "previously we…", "Update: X removed", dated
110
+ decision logs, or "kept for anyone revisiting" option write-ups.
111
+ - **Do** just state what is true now. When a fact changes, **overwrite** it
112
+ and bump `updated`.
113
+ - To consult how a fact got to be the way it is, use git: `git log -p --
114
+ .context/<scope>.md`, or `git log -S '<phrase>' -- .context/`.
115
+ - Two things that look like history and are not, so keep them:
116
+ - a *constraint* that happens to be dated — "the production schema is
117
+ deployed, so a stored field can't be renamed";
118
+ - **provenance** — "decided by Ada, 2026-09-25" against a rule or a
119
+ decision. That says who to ask whether it still holds, which is a present
120
+ fact about the rule, not a record of a change to it.
121
+
122
+ A dated checklist or a session log is not a scope file; the work in one
123
+ belongs in `.issues/`, and the narrative in git.
124
+
125
+ ## Where a scope file goes
126
+
127
+ `.context/` is **flat** until it isn't: every scope file sits directly in
128
+ this directory while there are a dozen of them, because a directory tree would
129
+ only add places to look.
130
+
131
+ When the directory grows a cluster of three or more scopes about one subject,
132
+ group them in a subdirectory whose `README.md` is **the group's own scope
133
+ file**: AS IS / TO BE for what is true of the group as a whole, plus an index
134
+ of the children. Two files don't need a directory.
135
+
136
+ The cross-cutting axis is `area` (see **Frontmatter fields**), not the
137
+ directory — the site filters on it.
138
+
139
+ ## Filename
140
+
141
+ `<scope>.md`, a short lowercase slug with `-`, one file per scope (e.g.
142
+ `payments.md`, `store-hours.md`). No numbering — scopes aren't a sequence, so
143
+ files are found and referenced by name.
144
+
145
+ ## Creating a new scope file
146
+
147
+ Copy `TEMPLATE.md` to `<scope>.md` and fill it in.
148
+
149
+ ## This directory is also a site
150
+
151
+ `flo context` renders this directory into a site and **checks the rules above
152
+ while it does** — a deep link whose `#anchor` names no heading, a reference to
153
+ a scope file or issue that doesn't exist, a missing `title`/`area`/`updated`, a
154
+ file with neither section, a TO BE entry with no issue behind it. Those all
155
+ render as perfectly ordinary pages, which is why they are worth a build
156
+ warning, so read the output after editing.
157
+
158
+ ```sh
159
+ flo context # → the context site, under the output dir in flo.toml
160
+ flo context --watch # rebuild on every edit
161
+ ```
162
+
163
+ ## Frontmatter fields
164
+
165
+ - **type** — `Context`, always: the [Open Knowledge Format](https://github.com/GoogleCloudPlatform/knowledge-catalog/blob/main/okf/SPEC.md)
166
+ concept kind, the one key OKF requires of every markdown file. With it this
167
+ directory is an OKF bundle as it stands; `index.md` and `log.md` are the
168
+ names OKF reserves, and the site never reads either as a scope
169
+ - **title** — short scope title
170
+ - **area** — one subsystem tag, from the same vocabulary as the `tags` in
171
+ `[labels.tags]` in `flo.toml`. Need a new one? Add it there first.
172
+ - **updated** — date of the last real change (YYYY-MM-DD); bump it whenever a
173
+ fact or decision in the file changes, not on cosmetic edits
174
+
175
+ ## Cross-linking with `.issues/`
176
+
177
+ - Every TO BE sub-topic links the issue that will build it, as
178
+ `[[KET-NN]]` or `` `.issues/KET-NN-slug.md` `` — the site
179
+ turns both into links.
180
+ - Every issue that depends on a recorded fact deep-links into the AS IS
181
+ section holding it rather than restating it.
182
+ - `.issues/` is authoritative for *status of work*; `.context/` is
183
+ authoritative for *design*. If they disagree about whether something is
184
+ built, the issue file wins and this directory is stale — fix it.
@@ -0,0 +1,45 @@
1
+ ---
2
+ type: Context
3
+ title: Short scope title
4
+ area:
5
+ updated: YYYY-MM-DD
6
+ ---
7
+
8
+ # <Scope title>
9
+
10
+ One or two sentences: what this file is the source of truth for. Deep-link to
11
+ other scope files instead of repeating what they already record
12
+ (`[refunds](payments.md#refunds)`).
13
+
14
+ ## AS IS
15
+
16
+ What is built and running today. Delete nothing into history — overwrite.
17
+
18
+ ### <Sub-topic>
19
+
20
+ - **Status:** confirmed / decided
21
+ - The fact itself, with evidence (`path/to/file.py:123`).
22
+
23
+ ### <Sub-topic with shape>
24
+
25
+ ```
26
+ A ──▶ B ──▶ C diagram first, prose after
27
+ ```
28
+
29
+ 1. Ordered step
30
+ 2. Ordered step
31
+
32
+ ## TO BE
33
+
34
+ Designed, not built yet. `_Not built yet._` if there's nothing.
35
+
36
+ ### <Sub-topic>
37
+
38
+ - **Status:** decided / to be decided
39
+ - **Issue:** `.issues/KET-XX`
40
+ - The target state, in the future tense, and what it replaces in AS IS.
41
+
42
+ ## See also
43
+
44
+ - `.issues/KET-XX` — related open work
45
+ - Other scope files this one deep-links into
@@ -0,0 +1,14 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
2
+ <!-- Stacked layers: one scope per file, and the directory is the stack.
3
+ Deliberately not the issues site's icon (three list rows) — the two
4
+ sites are read side by side, and a tab strip is where they are told
5
+ apart. Themed both ways: the browser's chrome follows the OS, not the
6
+ page, so a single fill would be invisible on one of the two. -->
7
+ <style>
8
+ path { fill: #15171a }
9
+ @media (prefers-color-scheme: dark) { path { fill: #e7e9ec } }
10
+ </style>
11
+ <path d="M8 1 15 4.3 8 7.6 1 4.3Z"/>
12
+ <path d="M1 7.7 8 11 15 7.7 13.2 6.8 8 9.3 2.8 6.8Z"/>
13
+ <path d="M1 11.1 8 14.4 15 11.1 13.2 10.2 8 12.7 2.8 10.2Z"/>
14
+ </svg>
@@ -0,0 +1,37 @@
1
+ ---
2
+ type: Context
3
+ title: Loyalty — points for regulars
4
+ area: loyalty
5
+ updated: 2026-09-29
6
+ ---
7
+
8
+ # Loyalty
9
+
10
+ The loyalty scheme Crumb & Co wants for v1.1: why regulars would order through
11
+ Kettle rather than a marketplace.
12
+
13
+ ## AS IS
14
+
15
+ _Not built yet._
16
+
17
+ ## TO BE
18
+
19
+ ### Earning and spending points
20
+
21
+ - **Status:** to be decided
22
+ - **Issue:** [[KET-12]]
23
+ - One point per euro spent on a `paid` order, credited when the order is
24
+ `collected` (see [order states](ordering.md#order-states)).
25
+ - 100 points buy a free coffee. Whether points expire is waiting on
26
+ Crumb & Co — decided by Sam once they answer.
27
+
28
+ ### Accounts
29
+
30
+ - **Status:** decided
31
+ - **Issue:** [[KET-13]]
32
+ - Points need an account: email and a magic link, no passwords. An order
33
+ placed without an account earns nothing.
34
+
35
+ ## See also
36
+
37
+ - [[KET-12]], [[KET-13]] — the v1.1 work
@@ -0,0 +1,42 @@
1
+ ---
2
+ type: Context
3
+ title: Menu — products, allergens and prices
4
+ area: menu
5
+ updated: 2026-09-25
6
+ ---
7
+
8
+ # Menu
9
+
10
+ What Kettle sells, what is in it and what it costs. The menu is Crumb & Co's;
11
+ Kettle only shows it.
12
+
13
+ ## AS IS
14
+
15
+ ### Products and allergens
16
+
17
+ - **Status:** confirmed
18
+ - A product belongs to one category and carries a list of the fourteen EU
19
+ allergens as data (`src/menu/models.py:10-52`), never as free text.
20
+ - Every product page lists its allergens as text and as labelled icons.
21
+ - Which shops sell a product is a list on the product: the station shops
22
+ carry a shorter menu.
23
+
24
+ ### Prices
25
+
26
+ - **Status:** confirmed
27
+ - One online price per product, the same in every shop.
28
+ - An order keeps the prices it was placed at; a price change never touches an
29
+ order that already exists.
30
+
31
+ ## TO BE
32
+
33
+ ### Signed-off price list
34
+
35
+ - **Status:** decided
36
+ - **Issue:** [[KET-18]]
37
+ - Online prices go live only once Crumb & Co has signed off the list. Some
38
+ products are 5% above the shop price, to cover the payment fees.
39
+
40
+ ## See also
41
+
42
+ - [ordering](ordering.md#basket-and-checkout) — how prices are fixed on an order