stylefix 0.7.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.
- stylefix-0.7.0/.gitignore +8 -0
- stylefix-0.7.0/LICENSE +21 -0
- stylefix-0.7.0/PKG-INFO +290 -0
- stylefix-0.7.0/README.md +269 -0
- stylefix-0.7.0/examples/sample.md +29 -0
- stylefix-0.7.0/man/stylefix.1 +361 -0
- stylefix-0.7.0/pyproject.toml +49 -0
- stylefix-0.7.0/scripts/eval_adjudicator.py +135 -0
- stylefix-0.7.0/stylefix/__init__.py +3 -0
- stylefix-0.7.0/stylefix/abbreviations.py +200 -0
- stylefix-0.7.0/stylefix/accept.txt +94 -0
- stylefix-0.7.0/stylefix/adjudicate.py +27 -0
- stylefix-0.7.0/stylefix/apply.py +3 -0
- stylefix-0.7.0/stylefix/candidates.py +105 -0
- stylefix-0.7.0/stylefix/changelog.py +66 -0
- stylefix-0.7.0/stylefix/cli.py +415 -0
- stylefix-0.7.0/stylefix/context.py +4 -0
- stylefix-0.7.0/stylefix/conventions.py +172 -0
- stylefix-0.7.0/stylefix/dict/README-varcon.txt +582 -0
- stylefix-0.7.0/stylefix/dict/varcon.txt.gz +0 -0
- stylefix-0.7.0/stylefix/dictionary.py +3 -0
- stylefix-0.7.0/stylefix/llm.py +4 -0
- stylefix-0.7.0/stylefix/patterns.py +217 -0
- stylefix-0.7.0/stylefix/report.py +65 -0
- stylefix-0.7.0/stylefix/spellcheck.py +68 -0
- stylefix-0.7.0/stylefix/styleguides.py +153 -0
- stylefix-0.7.0/stylefix/styleitems.py +221 -0
- stylefix-0.7.0/stylefix/styles/AP/Numbers.yml +9 -0
- stylefix-0.7.0/stylefix/styles/AP/Toward.yml +13 -0
- stylefix-0.7.0/stylefix/styles/APA/Numbers.yml +9 -0
- stylefix-0.7.0/stylefix/styles/Chicago/Numbers.yml +9 -0
- stylefix-0.7.0/stylefix/styles/Chicago/Toward.yml +13 -0
- stylefix-0.7.0/stylefix/styles/GPO/Numbers.yml +9 -0
- stylefix-0.7.0/stylefix/styles/GPO/Toward.yml +13 -0
- stylefix-0.7.0/stylefix/styles/Guardian/Numbers.yml +9 -0
- stylefix-0.7.0/stylefix/styles/Guardian/Towards.yml +10 -0
- stylefix-0.7.0/stylefix/styles/Oxford/Numbers.yml +9 -0
- stylefix-0.7.0/stylefix/styles/Oxford/Towards.yml +10 -0
- stylefix-0.7.0/stylefix/styles/ToUK/Ambiguous.yml +7 -0
- stylefix-0.7.0/stylefix/styles/ToUK/Ise1.yml +1509 -0
- stylefix-0.7.0/stylefix/styles/ToUK/Ise2.yml +1509 -0
- stylefix-0.7.0/stylefix/styles/ToUK/Ise3.yml +1509 -0
- stylefix-0.7.0/stylefix/styles/ToUK/Ise4.yml +1094 -0
- stylefix-0.7.0/stylefix/styles/ToUK/Oxford1.yml +1509 -0
- stylefix-0.7.0/stylefix/styles/ToUK/Oxford2.yml +1509 -0
- stylefix-0.7.0/stylefix/styles/ToUK/Oxford3.yml +1509 -0
- stylefix-0.7.0/stylefix/styles/ToUK/Oxford4.yml +1108 -0
- stylefix-0.7.0/stylefix/styles/ToUK/PatEr.yml +8 -0
- stylefix-0.7.0/stylefix/styles/ToUK/PatIse.yml +8 -0
- stylefix-0.7.0/stylefix/styles/ToUK/PatIze.yml +8 -0
- stylefix-0.7.0/stylefix/styles/ToUK/PatOr.yml +8 -0
- stylefix-0.7.0/stylefix/styles/ToUK/Variants1.yml +1509 -0
- stylefix-0.7.0/stylefix/styles/ToUK/Variants2.yml +1509 -0
- stylefix-0.7.0/stylefix/styles/ToUK/Variants3.yml +1317 -0
- stylefix-0.7.0/stylefix/styles/ToUS/Ambiguous.yml +7 -0
- stylefix-0.7.0/stylefix/styles/ToUS/PatIse.yml +8 -0
- stylefix-0.7.0/stylefix/styles/ToUS/PatLl.yml +8 -0
- stylefix-0.7.0/stylefix/styles/ToUS/PatOur.yml +8 -0
- stylefix-0.7.0/stylefix/styles/ToUS/PatRe.yml +8 -0
- stylefix-0.7.0/stylefix/styles/ToUS/Variants1.yml +1509 -0
- stylefix-0.7.0/stylefix/styles/ToUS/Variants2.yml +1509 -0
- stylefix-0.7.0/stylefix/styles/ToUS/Variants3.yml +1509 -0
- stylefix-0.7.0/stylefix/styles/ToUS/Variants4.yml +1509 -0
- stylefix-0.7.0/stylefix/styles/ToUS/Variants5.yml +1509 -0
- stylefix-0.7.0/stylefix/styles/ToUS/Variants6.yml +1509 -0
- stylefix-0.7.0/stylefix/styles/ToUS/Variants7.yml +697 -0
- stylefix-0.7.0/stylefix/vale_runner.py +113 -0
- stylefix-0.7.0/stylefix/varcon.py +170 -0
- stylefix-0.7.0/stylefix/wordlist.py +145 -0
- stylefix-0.7.0/tests/conftest.py +16 -0
- stylefix-0.7.0/tests/legacy_table.py +210 -0
- stylefix-0.7.0/tests/test_abbreviations.py +63 -0
- stylefix-0.7.0/tests/test_adjudicate.py +68 -0
- stylefix-0.7.0/tests/test_apply.py +42 -0
- stylefix-0.7.0/tests/test_changelog.py +36 -0
- stylefix-0.7.0/tests/test_context.py +39 -0
- stylefix-0.7.0/tests/test_conventions.py +56 -0
- stylefix-0.7.0/tests/test_docs.py +58 -0
- stylefix-0.7.0/tests/test_e2e.py +157 -0
- stylefix-0.7.0/tests/test_endpoint_cli.py +91 -0
- stylefix-0.7.0/tests/test_patterns.py +106 -0
- stylefix-0.7.0/tests/test_spellcheck.py +29 -0
- stylefix-0.7.0/tests/test_styleguides.py +37 -0
- stylefix-0.7.0/tests/test_styleitems.py +119 -0
- stylefix-0.7.0/tests/test_wordlist.py +67 -0
stylefix-0.7.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Andrew Brož
|
|
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.
|
stylefix-0.7.0/PKG-INFO
ADDED
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: stylefix
|
|
3
|
+
Version: 0.7.0
|
|
4
|
+
Summary: Regularize a Markdown file to US or UK English and a style guide, using Vale plus a language model for the ambiguous cases.
|
|
5
|
+
Project-URL: Homepage, https://github.com/AndrewBroz/stylefix
|
|
6
|
+
Project-URL: Issues, https://github.com/AndrewBroz/stylefix/issues
|
|
7
|
+
Author: Andrew Brož
|
|
8
|
+
License-Expression: MIT AND LicenseRef-VarCon
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
License-File: stylefix/dict/README-varcon.txt
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Environment :: Console
|
|
13
|
+
Classifier: Intended Audience :: End Users/Desktop
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Topic :: Text Processing :: Markup :: Markdown
|
|
17
|
+
Requires-Python: >=3.11
|
|
18
|
+
Requires-Dist: adjudicate<0.4,>=0.3
|
|
19
|
+
Requires-Dist: spylls>=0.1.7
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
|
|
22
|
+
# stylefix
|
|
23
|
+
|
|
24
|
+
Regularize a Markdown file to **US or UK English** and a **style guide**
|
|
25
|
+
(Chicago, Oxford, AP, GPO, APA or Guardian), fully automatically, and locally unless you point it at a hosted model.
|
|
26
|
+
|
|
27
|
+
```
|
|
28
|
+
stylefix draft.md --target us # -> draft.us.md + draft.us.md.report.md
|
|
29
|
+
stylefix draft.md --target uk --oxford-ize # UK with Oxford -ize spellings
|
|
30
|
+
stylefix draft.md --target us --dry-run # print a diff, write nothing
|
|
31
|
+
stylefix draft.md --target us --changes # list every change as it is made
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
[Vale](https://vale.sh) decides what to change; a small Python wrapper applies
|
|
35
|
+
the changes. The few words that need judgement (UK *licence*/*license*,
|
|
36
|
+
*programme*/*program*, *cheque*/*check*, ...) are put to a language model as a
|
|
37
|
+
multiple-choice question with the surrounding sentence. The model never
|
|
38
|
+
rewrites prose: it picks one of the options you supply, or KEEP.
|
|
39
|
+
|
|
40
|
+
## Install
|
|
41
|
+
|
|
42
|
+
```
|
|
43
|
+
uv tool install stylefix # or: pipx install stylefix
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
stylefix also needs [Vale](https://vale.sh/docs/install) on your PATH:
|
|
47
|
+
`brew install vale` on macOS, `choco install vale` on Windows, or a release
|
|
48
|
+
binary from GitHub on Linux. Python 3.11+.
|
|
49
|
+
|
|
50
|
+
`stylefix --help` gives the full option reference with examples. The man
|
|
51
|
+
page is in the repository at `man/stylefix.1` (`man ./man/stylefix.1`).
|
|
52
|
+
|
|
53
|
+
## How it works
|
|
54
|
+
|
|
55
|
+
Every candidate word lands in one of three tiers:
|
|
56
|
+
|
|
57
|
+
| tier | mechanism | what happens |
|
|
58
|
+
|---|---|---|
|
|
59
|
+
| deterministic | **suffix patterns** confirmed against dictionaries, plus a curated table for the irregular families | applied, case preserved |
|
|
60
|
+
| adjudicated | words with a sense split (licence/license, programme/program), pattern hits whose rewrite is in no dictionary (coinages, names), any hit that is capitalised mid-sentence or inside a quotation, and the style guide's serial-comma and numeral rules | a language model chooses between the candidates and KEEP |
|
|
61
|
+
| review | spellings that look like the other variety but could not be converted; serial-comma and numeral hits when no model is configured | listed in the report and the `--changes` log |
|
|
62
|
+
|
|
63
|
+
**Two data sources, both from the SCOWL project: VarCon, shipped in
|
|
64
|
+
`stylefix/dict/`, and the Hunspell dictionaries that come with adjudicate.**
|
|
65
|
+
|
|
66
|
+
- **VarCon** (Variant Conversion Info) is the curated table: about 15,000
|
|
67
|
+
spellings mapped to their preferred American, British and Oxford forms,
|
|
68
|
+
with sense annotations. It is the source of the Vale substitution rules,
|
|
69
|
+
regenerated by `python -m stylefix.wordlist`. Where VarCon says a spelling
|
|
70
|
+
is *also* a word of its own in the target ("check | verify" alongside
|
|
71
|
+
"check / cheque | bank"; licence as noun, license as verb), the word is
|
|
72
|
+
not converted but adjudicated, and VarCon's glosses become the rule of
|
|
73
|
+
thumb the model reads: "British: 'check' for verify; 'cheque' for bank."
|
|
74
|
+
- **Hunspell dictionaries** (en_US, en_GB, read with the pure-Python
|
|
75
|
+
`spylls`) confirm the pattern tier. English keeps coining -ize verbs, so
|
|
76
|
+
the -ise/-ize, -yse/-yze, -our/-or, -re/-er and -ll-/-l- endings are
|
|
77
|
+
handled as patterns: a hit is rewritten and looked up. A rewrite that is
|
|
78
|
+
a real word is applied ("securitise" becomes "securitize" without anyone
|
|
79
|
+
listing it); one in no dictionary goes to the model ("platformise"); a
|
|
80
|
+
word already valid in the target is left alone ("advertise", "glamour").
|
|
81
|
+
|
|
82
|
+
Patterns take what they can prove; the table carries everything else
|
|
83
|
+
(closed families like -ogue and ae/oe, vocabulary like aluminium/aluminum,
|
|
84
|
+
and inflections the patterns don't cover). On the same word the table
|
|
85
|
+
wins.
|
|
86
|
+
|
|
87
|
+
**UK variants.** The default UK target writes -ise. `--oxford-ize` uses
|
|
88
|
+
VarCon's Oxford column and flips the -ise/-ize pattern, keeping -yse and
|
|
89
|
+
every other British form.
|
|
90
|
+
|
|
91
|
+
## Style guides
|
|
92
|
+
|
|
93
|
+
`--style` chooses the mechanical conventions; spelling always follows
|
|
94
|
+
`--target`. `stylefix --list-styles` prints this table.
|
|
95
|
+
|
|
96
|
+
| guide | for | dash | serial comma | numerals from | toward | punctuation in quotes | abbreviations |
|
|
97
|
+
|---|---|---|---|---|---|---|---|
|
|
98
|
+
| `chicago` (US default) | Chicago Manual of Style | unspaced em | required | 101 | toward | inside | US, UK; PhD; 10 a.m.; vs.; e.g. |
|
|
99
|
+
| `gpo` | US Government Publishing Office Style Manual, the federal standard | unspaced em | required | 10 | toward | inside | U.S., U.K.; Ph.D.; 10 a.m.; vs.; e.g. |
|
|
100
|
+
| `ap` | Associated Press, journalism | spaced em | omitted in a simple series | 10 | toward | inside | U.S., U.K.; Ph.D.; 10 a.m.; vs.; e.g. |
|
|
101
|
+
| `apa` | APA 7th, academic and policy research | unspaced em | required | 10 | no rule | inside | U.S.; PhD; 10 a.m.; vs.; e.g. |
|
|
102
|
+
| `oxford` (UK default) | New Hart's Rules | spaced en | required | 101 | towards | logical (unchanged) | US, UK; PhD; 10 a.m.; vs; e.g. |
|
|
103
|
+
| `guardian` | Guardian/Observer, UK journalism | spaced en | omitted unless needed | 10 | towards | logical (unchanged) | US, UK; PhD; 10am; v; eg, ie, etc |
|
|
104
|
+
| `none` | no guide | unchanged | no rule | no rule | no rule | unchanged | unchanged |
|
|
105
|
+
|
|
106
|
+
**Abbreviations** follow the guides' general rules, not a word list.
|
|
107
|
+
Chicago's rule (10.4), shared by Oxford and the Guardian, is that an
|
|
108
|
+
abbreviation in full capitals takes no periods, two letters or more: US,
|
|
109
|
+
UK, EU, NATO, PhD, DC. It is applied to every period-group of capitals.
|
|
110
|
+
The hazard is personal initials ("J.K. Rowling" keeps its periods), which
|
|
111
|
+
look identical; so a group followed by a capitalised word is adjudicated,
|
|
112
|
+
with the readings shown as they would print, and the sentence-end case
|
|
113
|
+
("in the U.S. The ...") is handled the same way. AP's rule is the reverse
|
|
114
|
+
for "most two-letter abbreviations" (U.S., U.N., U.K., B.A., B.C.), with
|
|
115
|
+
named exceptions (EU, GI, ID) and none in longer ones (FBI, NATO); since AP
|
|
116
|
+
writes AI, IT and TV without periods, the rule is applied by category:
|
|
117
|
+
countries, places, degrees and eras. GPO follows AP's forms; APA keeps
|
|
118
|
+
"U.S." but writes degrees without periods (PhD, MA). Clock times, vs., and
|
|
119
|
+
e.g., i.e., etc. take each guide's form.
|
|
120
|
+
|
|
121
|
+
**The noun rule.** GPO and APA use "U.S." only as an adjective ("U.S.
|
|
122
|
+
policy") and write the noun out ("the United States"). Because that is a
|
|
123
|
+
part-of-speech question, it is a warning by default under those guides
|
|
124
|
+
(each likely noun use is listed for review) and an enforcement on request:
|
|
125
|
+
`--abbreviation-nouns enforce` puts every "the U.S." to the model, which
|
|
126
|
+
chooses "United States", the adjective form, or KEEP. `off` silences it.
|
|
127
|
+
|
|
128
|
+
Dashes, toward/towards and punctuation placement are applied outright.
|
|
129
|
+
Serial commas and numerals need judgement (is "attacks, intentional and
|
|
130
|
+
unintentional" a list of three? is "10" a count or a percentage?), so each
|
|
131
|
+
hit becomes an adjudication item: the model sees the sentence and the
|
|
132
|
+
guide's rule of thumb and chooses between one concrete edit ("ten",
|
|
133
|
+
"a, b, and c") and KEEP. With no model configured they are listed for
|
|
134
|
+
review instead. A guide from the other variety (`--target uk --style
|
|
135
|
+
chicago`) is allowed and noted on stderr.
|
|
136
|
+
|
|
137
|
+
Guides are a few parameters each in `stylefix/styleguides.py`; the Vale
|
|
138
|
+
rules are generated from them.
|
|
139
|
+
|
|
140
|
+
After the word-level edits, a punctuation pass handles what a regex rule
|
|
141
|
+
cannot: curly quotes, primary double (US) or single (UK) quotes with correct
|
|
142
|
+
nesting, apostrophes, parenthetical dashes (Chicago em dash / Oxford spaced en
|
|
143
|
+
dash), en dashes in number ranges, and date order (September 4, 2026 /
|
|
144
|
+
4 September 2026). Chicago also moves commas and periods inside closing
|
|
145
|
+
quotes. Front matter, fenced code, inline code, link targets and URLs are
|
|
146
|
+
never touched.
|
|
147
|
+
|
|
148
|
+
The report next to the output lists every deterministic swap, every model
|
|
149
|
+
decision with its confidence and reason, and every alert left for a human.
|
|
150
|
+
|
|
151
|
+
## The model
|
|
152
|
+
|
|
153
|
+
The quickest way to set one up is
|
|
154
|
+
|
|
155
|
+
```
|
|
156
|
+
stylefix --setup
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
which asks where your model is (local Ollama, a hosted API, or your own
|
|
160
|
+
server), tests it, and saves the answer where both stylefix and proofix
|
|
161
|
+
find it. `stylefix --check-endpoint` shows what stylefix will use, where
|
|
162
|
+
each setting came from, and whether the endpoint answers.
|
|
163
|
+
|
|
164
|
+
Any OpenAI-compatible `/v1/chat/completions` endpoint works: Ollama, vLLM,
|
|
165
|
+
LiteLLM, llama.cpp's server, or a hosted API. stylefix takes its settings
|
|
166
|
+
from, highest first: `--url`/`--model`/`--timeout`; `STYLEFIX_LLM_URL`,
|
|
167
|
+
`STYLEFIX_LLM_MODEL`, `STYLEFIX_LLM_KEY`; `~/.config/stylefix/config.toml`;
|
|
168
|
+
`ADJUDICATE_LLM_*`; and `~/.config/adjudicate/config.toml`, which proofix
|
|
169
|
+
reads too. A `--url` or `STYLEFIX_LLM_URL` drops keys set in lower layers;
|
|
170
|
+
set `STYLEFIX_LLM_KEY` (or `api_key_env` in the same config file) alongside
|
|
171
|
+
it. With nothing configured, `--llm auto` (the default) uses a local
|
|
172
|
+
Ollama if one is running with a model pulled, and otherwise runs as
|
|
173
|
+
`--llm none`: ambiguous words are left alone and listed in the report,
|
|
174
|
+
while capitalised deterministic swaps are applied anyway.
|
|
175
|
+
|
|
176
|
+
**Ollama**: nothing to configure; the first installed model is used.
|
|
177
|
+
`--model` picks another.
|
|
178
|
+
|
|
179
|
+
**A hosted API**:
|
|
180
|
+
|
|
181
|
+
```toml
|
|
182
|
+
# ~/.config/adjudicate/config.toml
|
|
183
|
+
[llm]
|
|
184
|
+
url = "https://api.openai.com/v1"
|
|
185
|
+
model = "gpt-4.1-mini"
|
|
186
|
+
api_key_env = "OPENAI_API_KEY" # the key stays in your environment
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
**Self-hosted vLLM or LiteLLM with a reasoning model**:
|
|
190
|
+
|
|
191
|
+
```toml
|
|
192
|
+
[llm]
|
|
193
|
+
url = "http://gpu-box:8000/v1"
|
|
194
|
+
model = "qwen3"
|
|
195
|
+
thinking_switch = true # send enable_thinking: false, which vLLM honours
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
Leave `model` out and the server's first listed model is used. A key the
|
|
199
|
+
file or environment names but that is unset, an unknown key, or a wrong
|
|
200
|
+
type stops the run with the file and key named. The full table is
|
|
201
|
+
documented in [adjudicate](https://github.com/AndrewBroz/adjudicate#choosing-the-model-endpoint).
|
|
202
|
+
|
|
203
|
+
Requests go out in batches of `--batch-size` items (20), `--parallel` (4) at a
|
|
204
|
+
time, so a serving stack with continuous batching (vLLM) answers a document's
|
|
205
|
+
worth of questions in a couple of round-trips. Decisions are cached in
|
|
206
|
+
`.stylefix/cache.json` keyed on target, word and sentence; re-runs are
|
|
207
|
+
instant and reproducible, and you can edit a cached choice to override it.
|
|
208
|
+
Answers below `--min-confidence` (0.7), invalid answers, and transport errors
|
|
209
|
+
all fall through to the report rather than being applied.
|
|
210
|
+
|
|
211
|
+
### Choosing a model
|
|
212
|
+
|
|
213
|
+
The question the model answers is narrow (pick one of two or three options,
|
|
214
|
+
given a sentence), so any current instruct model handles it; what differs is
|
|
215
|
+
speed. `scripts/eval_adjudicator.py` scores an endpoint on 48 gold cases
|
|
216
|
+
(noun/verb splits, sense splits, proper nouns, quotations) and reports latency:
|
|
217
|
+
|
|
218
|
+
```
|
|
219
|
+
uv run python scripts/eval_adjudicator.py [--url URL --model NAME] [--think] [--parallel 8] [--repeat 4]
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
One measurement, on a DGX Spark serving Qwen3.8-27B (NVFP4) through vLLM:
|
|
223
|
+
|
|
224
|
+
| mode | accuracy | per item |
|
|
225
|
+
|---|---|---|
|
|
226
|
+
| thinking off, `--parallel 1` | 47/48 | ~1.0 s |
|
|
227
|
+
| thinking off, `--parallel 8` | 47/48 | ~0.33 s |
|
|
228
|
+
| `--think`, batch 8, `--parallel 4` | 48/48 | ~3.2 s |
|
|
229
|
+
|
|
230
|
+
The one miss without thinking is a capitalised common noun ("Colour theory")
|
|
231
|
+
kept as if it were a title, which is the conservative failure. Thinking buys
|
|
232
|
+
the last case at four to ten times the latency; use `--think` with
|
|
233
|
+
`--batch-size 8 --timeout 600` for a final pass on an important document,
|
|
234
|
+
and the default for everyday runs. Throughput scales with `--parallel`
|
|
235
|
+
because vLLM batches concurrent requests, so a mixture-of-experts model with
|
|
236
|
+
few active parameters (e.g. Gemma-4-26B-A4B) will be faster still on large
|
|
237
|
+
batches without changing accuracy noticeably.
|
|
238
|
+
|
|
239
|
+
## Exceptions
|
|
240
|
+
|
|
241
|
+
Words to leave alone come from four places, all optional and all combined:
|
|
242
|
+
|
|
243
|
+
1. A built-in list (`stylefix/accept.txt`) of technical and policy terms
|
|
244
|
+
and acronyms (cybersecurity, sandboxing, LLM, NIST). A test ensures
|
|
245
|
+
nothing on it is a word the conversion tables know.
|
|
246
|
+
2. `~/.config/stylefix/accept.txt`, your personal list.
|
|
247
|
+
3. `.stylefix/accept.txt` in the working directory, the project's list.
|
|
248
|
+
4. `--accept FILE` for a one-off.
|
|
249
|
+
|
|
250
|
+
One term per line, `#` comments allowed, case-insensitive. They become a
|
|
251
|
+
Vale vocabulary and are skipped by every rule. `--no-default-accept` uses
|
|
252
|
+
only the `--accept` file.
|
|
253
|
+
|
|
254
|
+
## Extending
|
|
255
|
+
|
|
256
|
+
- **Suffix families** live in `stylefix/patterns.py`: the regexes, the
|
|
257
|
+
never-lists, and the decision logic. The conversion table comes from
|
|
258
|
+
`stylefix/dict/varcon.txt.gz` through `stylefix/varcon.py`; local fixes
|
|
259
|
+
go in the override dicts in `stylefix/wordlist.py`. After editing any of
|
|
260
|
+
these, run `python -m stylefix.wordlist` to regenerate the Vale rules (a
|
|
261
|
+
test fails if they drift). Tests check that the patterns never contradict
|
|
262
|
+
VarCon and that the old hand tables are still fully covered.
|
|
263
|
+
- **Ambiguous words** live in `stylefix/candidates.py` and the matching
|
|
264
|
+
`Ambiguous.yml` token regex.
|
|
265
|
+
- **Style rules** are plain Vale YAML under `stylefix/styles/<Guide>`, generated
|
|
266
|
+
from `stylefix/styleguides.py`; any substitution rule with `action: replace` is
|
|
267
|
+
applied automatically, anything else goes to the report.
|
|
268
|
+
|
|
269
|
+
## Limitations
|
|
270
|
+
|
|
271
|
+
- The UK direction does not move punctuation outside quotation marks: whether
|
|
272
|
+
a comma belongs to the quote is not knowable mechanically.
|
|
273
|
+
- Numeral and serial-comma detection is heuristic, so no hit is applied
|
|
274
|
+
mechanically: each goes to the model, which chooses the edit or KEEP, or to
|
|
275
|
+
the report when no model is available (`--llm none`, or no endpoint reachable).
|
|
276
|
+
- `.docx` files: convert with pandoc first
|
|
277
|
+
(`pandoc in.docx -t gfm -o in.md`), fix, convert back.
|
|
278
|
+
|
|
279
|
+
## License
|
|
280
|
+
|
|
281
|
+
MIT (see `LICENSE`). `stylefix/dict/varcon.txt.gz` is VarCon, under the
|
|
282
|
+
notice in `stylefix/dict/README-varcon.txt`. The spelling dictionaries come
|
|
283
|
+
with [adjudicate](https://github.com/AndrewBroz/adjudicate).
|
|
284
|
+
|
|
285
|
+
## Development
|
|
286
|
+
|
|
287
|
+
```
|
|
288
|
+
uv sync
|
|
289
|
+
uv run pytest
|
|
290
|
+
```
|
stylefix-0.7.0/README.md
ADDED
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
# stylefix
|
|
2
|
+
|
|
3
|
+
Regularize a Markdown file to **US or UK English** and a **style guide**
|
|
4
|
+
(Chicago, Oxford, AP, GPO, APA or Guardian), fully automatically, and locally unless you point it at a hosted model.
|
|
5
|
+
|
|
6
|
+
```
|
|
7
|
+
stylefix draft.md --target us # -> draft.us.md + draft.us.md.report.md
|
|
8
|
+
stylefix draft.md --target uk --oxford-ize # UK with Oxford -ize spellings
|
|
9
|
+
stylefix draft.md --target us --dry-run # print a diff, write nothing
|
|
10
|
+
stylefix draft.md --target us --changes # list every change as it is made
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
[Vale](https://vale.sh) decides what to change; a small Python wrapper applies
|
|
14
|
+
the changes. The few words that need judgement (UK *licence*/*license*,
|
|
15
|
+
*programme*/*program*, *cheque*/*check*, ...) are put to a language model as a
|
|
16
|
+
multiple-choice question with the surrounding sentence. The model never
|
|
17
|
+
rewrites prose: it picks one of the options you supply, or KEEP.
|
|
18
|
+
|
|
19
|
+
## Install
|
|
20
|
+
|
|
21
|
+
```
|
|
22
|
+
uv tool install stylefix # or: pipx install stylefix
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
stylefix also needs [Vale](https://vale.sh/docs/install) on your PATH:
|
|
26
|
+
`brew install vale` on macOS, `choco install vale` on Windows, or a release
|
|
27
|
+
binary from GitHub on Linux. Python 3.11+.
|
|
28
|
+
|
|
29
|
+
`stylefix --help` gives the full option reference with examples. The man
|
|
30
|
+
page is in the repository at `man/stylefix.1` (`man ./man/stylefix.1`).
|
|
31
|
+
|
|
32
|
+
## How it works
|
|
33
|
+
|
|
34
|
+
Every candidate word lands in one of three tiers:
|
|
35
|
+
|
|
36
|
+
| tier | mechanism | what happens |
|
|
37
|
+
|---|---|---|
|
|
38
|
+
| deterministic | **suffix patterns** confirmed against dictionaries, plus a curated table for the irregular families | applied, case preserved |
|
|
39
|
+
| adjudicated | words with a sense split (licence/license, programme/program), pattern hits whose rewrite is in no dictionary (coinages, names), any hit that is capitalised mid-sentence or inside a quotation, and the style guide's serial-comma and numeral rules | a language model chooses between the candidates and KEEP |
|
|
40
|
+
| review | spellings that look like the other variety but could not be converted; serial-comma and numeral hits when no model is configured | listed in the report and the `--changes` log |
|
|
41
|
+
|
|
42
|
+
**Two data sources, both from the SCOWL project: VarCon, shipped in
|
|
43
|
+
`stylefix/dict/`, and the Hunspell dictionaries that come with adjudicate.**
|
|
44
|
+
|
|
45
|
+
- **VarCon** (Variant Conversion Info) is the curated table: about 15,000
|
|
46
|
+
spellings mapped to their preferred American, British and Oxford forms,
|
|
47
|
+
with sense annotations. It is the source of the Vale substitution rules,
|
|
48
|
+
regenerated by `python -m stylefix.wordlist`. Where VarCon says a spelling
|
|
49
|
+
is *also* a word of its own in the target ("check | verify" alongside
|
|
50
|
+
"check / cheque | bank"; licence as noun, license as verb), the word is
|
|
51
|
+
not converted but adjudicated, and VarCon's glosses become the rule of
|
|
52
|
+
thumb the model reads: "British: 'check' for verify; 'cheque' for bank."
|
|
53
|
+
- **Hunspell dictionaries** (en_US, en_GB, read with the pure-Python
|
|
54
|
+
`spylls`) confirm the pattern tier. English keeps coining -ize verbs, so
|
|
55
|
+
the -ise/-ize, -yse/-yze, -our/-or, -re/-er and -ll-/-l- endings are
|
|
56
|
+
handled as patterns: a hit is rewritten and looked up. A rewrite that is
|
|
57
|
+
a real word is applied ("securitise" becomes "securitize" without anyone
|
|
58
|
+
listing it); one in no dictionary goes to the model ("platformise"); a
|
|
59
|
+
word already valid in the target is left alone ("advertise", "glamour").
|
|
60
|
+
|
|
61
|
+
Patterns take what they can prove; the table carries everything else
|
|
62
|
+
(closed families like -ogue and ae/oe, vocabulary like aluminium/aluminum,
|
|
63
|
+
and inflections the patterns don't cover). On the same word the table
|
|
64
|
+
wins.
|
|
65
|
+
|
|
66
|
+
**UK variants.** The default UK target writes -ise. `--oxford-ize` uses
|
|
67
|
+
VarCon's Oxford column and flips the -ise/-ize pattern, keeping -yse and
|
|
68
|
+
every other British form.
|
|
69
|
+
|
|
70
|
+
## Style guides
|
|
71
|
+
|
|
72
|
+
`--style` chooses the mechanical conventions; spelling always follows
|
|
73
|
+
`--target`. `stylefix --list-styles` prints this table.
|
|
74
|
+
|
|
75
|
+
| guide | for | dash | serial comma | numerals from | toward | punctuation in quotes | abbreviations |
|
|
76
|
+
|---|---|---|---|---|---|---|---|
|
|
77
|
+
| `chicago` (US default) | Chicago Manual of Style | unspaced em | required | 101 | toward | inside | US, UK; PhD; 10 a.m.; vs.; e.g. |
|
|
78
|
+
| `gpo` | US Government Publishing Office Style Manual, the federal standard | unspaced em | required | 10 | toward | inside | U.S., U.K.; Ph.D.; 10 a.m.; vs.; e.g. |
|
|
79
|
+
| `ap` | Associated Press, journalism | spaced em | omitted in a simple series | 10 | toward | inside | U.S., U.K.; Ph.D.; 10 a.m.; vs.; e.g. |
|
|
80
|
+
| `apa` | APA 7th, academic and policy research | unspaced em | required | 10 | no rule | inside | U.S.; PhD; 10 a.m.; vs.; e.g. |
|
|
81
|
+
| `oxford` (UK default) | New Hart's Rules | spaced en | required | 101 | towards | logical (unchanged) | US, UK; PhD; 10 a.m.; vs; e.g. |
|
|
82
|
+
| `guardian` | Guardian/Observer, UK journalism | spaced en | omitted unless needed | 10 | towards | logical (unchanged) | US, UK; PhD; 10am; v; eg, ie, etc |
|
|
83
|
+
| `none` | no guide | unchanged | no rule | no rule | no rule | unchanged | unchanged |
|
|
84
|
+
|
|
85
|
+
**Abbreviations** follow the guides' general rules, not a word list.
|
|
86
|
+
Chicago's rule (10.4), shared by Oxford and the Guardian, is that an
|
|
87
|
+
abbreviation in full capitals takes no periods, two letters or more: US,
|
|
88
|
+
UK, EU, NATO, PhD, DC. It is applied to every period-group of capitals.
|
|
89
|
+
The hazard is personal initials ("J.K. Rowling" keeps its periods), which
|
|
90
|
+
look identical; so a group followed by a capitalised word is adjudicated,
|
|
91
|
+
with the readings shown as they would print, and the sentence-end case
|
|
92
|
+
("in the U.S. The ...") is handled the same way. AP's rule is the reverse
|
|
93
|
+
for "most two-letter abbreviations" (U.S., U.N., U.K., B.A., B.C.), with
|
|
94
|
+
named exceptions (EU, GI, ID) and none in longer ones (FBI, NATO); since AP
|
|
95
|
+
writes AI, IT and TV without periods, the rule is applied by category:
|
|
96
|
+
countries, places, degrees and eras. GPO follows AP's forms; APA keeps
|
|
97
|
+
"U.S." but writes degrees without periods (PhD, MA). Clock times, vs., and
|
|
98
|
+
e.g., i.e., etc. take each guide's form.
|
|
99
|
+
|
|
100
|
+
**The noun rule.** GPO and APA use "U.S." only as an adjective ("U.S.
|
|
101
|
+
policy") and write the noun out ("the United States"). Because that is a
|
|
102
|
+
part-of-speech question, it is a warning by default under those guides
|
|
103
|
+
(each likely noun use is listed for review) and an enforcement on request:
|
|
104
|
+
`--abbreviation-nouns enforce` puts every "the U.S." to the model, which
|
|
105
|
+
chooses "United States", the adjective form, or KEEP. `off` silences it.
|
|
106
|
+
|
|
107
|
+
Dashes, toward/towards and punctuation placement are applied outright.
|
|
108
|
+
Serial commas and numerals need judgement (is "attacks, intentional and
|
|
109
|
+
unintentional" a list of three? is "10" a count or a percentage?), so each
|
|
110
|
+
hit becomes an adjudication item: the model sees the sentence and the
|
|
111
|
+
guide's rule of thumb and chooses between one concrete edit ("ten",
|
|
112
|
+
"a, b, and c") and KEEP. With no model configured they are listed for
|
|
113
|
+
review instead. A guide from the other variety (`--target uk --style
|
|
114
|
+
chicago`) is allowed and noted on stderr.
|
|
115
|
+
|
|
116
|
+
Guides are a few parameters each in `stylefix/styleguides.py`; the Vale
|
|
117
|
+
rules are generated from them.
|
|
118
|
+
|
|
119
|
+
After the word-level edits, a punctuation pass handles what a regex rule
|
|
120
|
+
cannot: curly quotes, primary double (US) or single (UK) quotes with correct
|
|
121
|
+
nesting, apostrophes, parenthetical dashes (Chicago em dash / Oxford spaced en
|
|
122
|
+
dash), en dashes in number ranges, and date order (September 4, 2026 /
|
|
123
|
+
4 September 2026). Chicago also moves commas and periods inside closing
|
|
124
|
+
quotes. Front matter, fenced code, inline code, link targets and URLs are
|
|
125
|
+
never touched.
|
|
126
|
+
|
|
127
|
+
The report next to the output lists every deterministic swap, every model
|
|
128
|
+
decision with its confidence and reason, and every alert left for a human.
|
|
129
|
+
|
|
130
|
+
## The model
|
|
131
|
+
|
|
132
|
+
The quickest way to set one up is
|
|
133
|
+
|
|
134
|
+
```
|
|
135
|
+
stylefix --setup
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
which asks where your model is (local Ollama, a hosted API, or your own
|
|
139
|
+
server), tests it, and saves the answer where both stylefix and proofix
|
|
140
|
+
find it. `stylefix --check-endpoint` shows what stylefix will use, where
|
|
141
|
+
each setting came from, and whether the endpoint answers.
|
|
142
|
+
|
|
143
|
+
Any OpenAI-compatible `/v1/chat/completions` endpoint works: Ollama, vLLM,
|
|
144
|
+
LiteLLM, llama.cpp's server, or a hosted API. stylefix takes its settings
|
|
145
|
+
from, highest first: `--url`/`--model`/`--timeout`; `STYLEFIX_LLM_URL`,
|
|
146
|
+
`STYLEFIX_LLM_MODEL`, `STYLEFIX_LLM_KEY`; `~/.config/stylefix/config.toml`;
|
|
147
|
+
`ADJUDICATE_LLM_*`; and `~/.config/adjudicate/config.toml`, which proofix
|
|
148
|
+
reads too. A `--url` or `STYLEFIX_LLM_URL` drops keys set in lower layers;
|
|
149
|
+
set `STYLEFIX_LLM_KEY` (or `api_key_env` in the same config file) alongside
|
|
150
|
+
it. With nothing configured, `--llm auto` (the default) uses a local
|
|
151
|
+
Ollama if one is running with a model pulled, and otherwise runs as
|
|
152
|
+
`--llm none`: ambiguous words are left alone and listed in the report,
|
|
153
|
+
while capitalised deterministic swaps are applied anyway.
|
|
154
|
+
|
|
155
|
+
**Ollama**: nothing to configure; the first installed model is used.
|
|
156
|
+
`--model` picks another.
|
|
157
|
+
|
|
158
|
+
**A hosted API**:
|
|
159
|
+
|
|
160
|
+
```toml
|
|
161
|
+
# ~/.config/adjudicate/config.toml
|
|
162
|
+
[llm]
|
|
163
|
+
url = "https://api.openai.com/v1"
|
|
164
|
+
model = "gpt-4.1-mini"
|
|
165
|
+
api_key_env = "OPENAI_API_KEY" # the key stays in your environment
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
**Self-hosted vLLM or LiteLLM with a reasoning model**:
|
|
169
|
+
|
|
170
|
+
```toml
|
|
171
|
+
[llm]
|
|
172
|
+
url = "http://gpu-box:8000/v1"
|
|
173
|
+
model = "qwen3"
|
|
174
|
+
thinking_switch = true # send enable_thinking: false, which vLLM honours
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
Leave `model` out and the server's first listed model is used. A key the
|
|
178
|
+
file or environment names but that is unset, an unknown key, or a wrong
|
|
179
|
+
type stops the run with the file and key named. The full table is
|
|
180
|
+
documented in [adjudicate](https://github.com/AndrewBroz/adjudicate#choosing-the-model-endpoint).
|
|
181
|
+
|
|
182
|
+
Requests go out in batches of `--batch-size` items (20), `--parallel` (4) at a
|
|
183
|
+
time, so a serving stack with continuous batching (vLLM) answers a document's
|
|
184
|
+
worth of questions in a couple of round-trips. Decisions are cached in
|
|
185
|
+
`.stylefix/cache.json` keyed on target, word and sentence; re-runs are
|
|
186
|
+
instant and reproducible, and you can edit a cached choice to override it.
|
|
187
|
+
Answers below `--min-confidence` (0.7), invalid answers, and transport errors
|
|
188
|
+
all fall through to the report rather than being applied.
|
|
189
|
+
|
|
190
|
+
### Choosing a model
|
|
191
|
+
|
|
192
|
+
The question the model answers is narrow (pick one of two or three options,
|
|
193
|
+
given a sentence), so any current instruct model handles it; what differs is
|
|
194
|
+
speed. `scripts/eval_adjudicator.py` scores an endpoint on 48 gold cases
|
|
195
|
+
(noun/verb splits, sense splits, proper nouns, quotations) and reports latency:
|
|
196
|
+
|
|
197
|
+
```
|
|
198
|
+
uv run python scripts/eval_adjudicator.py [--url URL --model NAME] [--think] [--parallel 8] [--repeat 4]
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
One measurement, on a DGX Spark serving Qwen3.8-27B (NVFP4) through vLLM:
|
|
202
|
+
|
|
203
|
+
| mode | accuracy | per item |
|
|
204
|
+
|---|---|---|
|
|
205
|
+
| thinking off, `--parallel 1` | 47/48 | ~1.0 s |
|
|
206
|
+
| thinking off, `--parallel 8` | 47/48 | ~0.33 s |
|
|
207
|
+
| `--think`, batch 8, `--parallel 4` | 48/48 | ~3.2 s |
|
|
208
|
+
|
|
209
|
+
The one miss without thinking is a capitalised common noun ("Colour theory")
|
|
210
|
+
kept as if it were a title, which is the conservative failure. Thinking buys
|
|
211
|
+
the last case at four to ten times the latency; use `--think` with
|
|
212
|
+
`--batch-size 8 --timeout 600` for a final pass on an important document,
|
|
213
|
+
and the default for everyday runs. Throughput scales with `--parallel`
|
|
214
|
+
because vLLM batches concurrent requests, so a mixture-of-experts model with
|
|
215
|
+
few active parameters (e.g. Gemma-4-26B-A4B) will be faster still on large
|
|
216
|
+
batches without changing accuracy noticeably.
|
|
217
|
+
|
|
218
|
+
## Exceptions
|
|
219
|
+
|
|
220
|
+
Words to leave alone come from four places, all optional and all combined:
|
|
221
|
+
|
|
222
|
+
1. A built-in list (`stylefix/accept.txt`) of technical and policy terms
|
|
223
|
+
and acronyms (cybersecurity, sandboxing, LLM, NIST). A test ensures
|
|
224
|
+
nothing on it is a word the conversion tables know.
|
|
225
|
+
2. `~/.config/stylefix/accept.txt`, your personal list.
|
|
226
|
+
3. `.stylefix/accept.txt` in the working directory, the project's list.
|
|
227
|
+
4. `--accept FILE` for a one-off.
|
|
228
|
+
|
|
229
|
+
One term per line, `#` comments allowed, case-insensitive. They become a
|
|
230
|
+
Vale vocabulary and are skipped by every rule. `--no-default-accept` uses
|
|
231
|
+
only the `--accept` file.
|
|
232
|
+
|
|
233
|
+
## Extending
|
|
234
|
+
|
|
235
|
+
- **Suffix families** live in `stylefix/patterns.py`: the regexes, the
|
|
236
|
+
never-lists, and the decision logic. The conversion table comes from
|
|
237
|
+
`stylefix/dict/varcon.txt.gz` through `stylefix/varcon.py`; local fixes
|
|
238
|
+
go in the override dicts in `stylefix/wordlist.py`. After editing any of
|
|
239
|
+
these, run `python -m stylefix.wordlist` to regenerate the Vale rules (a
|
|
240
|
+
test fails if they drift). Tests check that the patterns never contradict
|
|
241
|
+
VarCon and that the old hand tables are still fully covered.
|
|
242
|
+
- **Ambiguous words** live in `stylefix/candidates.py` and the matching
|
|
243
|
+
`Ambiguous.yml` token regex.
|
|
244
|
+
- **Style rules** are plain Vale YAML under `stylefix/styles/<Guide>`, generated
|
|
245
|
+
from `stylefix/styleguides.py`; any substitution rule with `action: replace` is
|
|
246
|
+
applied automatically, anything else goes to the report.
|
|
247
|
+
|
|
248
|
+
## Limitations
|
|
249
|
+
|
|
250
|
+
- The UK direction does not move punctuation outside quotation marks: whether
|
|
251
|
+
a comma belongs to the quote is not knowable mechanically.
|
|
252
|
+
- Numeral and serial-comma detection is heuristic, so no hit is applied
|
|
253
|
+
mechanically: each goes to the model, which chooses the edit or KEEP, or to
|
|
254
|
+
the report when no model is available (`--llm none`, or no endpoint reachable).
|
|
255
|
+
- `.docx` files: convert with pandoc first
|
|
256
|
+
(`pandoc in.docx -t gfm -o in.md`), fix, convert back.
|
|
257
|
+
|
|
258
|
+
## License
|
|
259
|
+
|
|
260
|
+
MIT (see `LICENSE`). `stylefix/dict/varcon.txt.gz` is VarCon, under the
|
|
261
|
+
notice in `stylefix/dict/README-varcon.txt`. The spelling dictionaries come
|
|
262
|
+
with [adjudicate](https://github.com/AndrewBroz/adjudicate).
|
|
263
|
+
|
|
264
|
+
## Development
|
|
265
|
+
|
|
266
|
+
```
|
|
267
|
+
uv sync
|
|
268
|
+
uv run pytest
|
|
269
|
+
```
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Colour Management Programme
|
|
3
|
+
author: The Centre for Analysis
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Colour management programme
|
|
7
|
+
|
|
8
|
+
The Centre for Digital Behaviour organises its work around a simple licence
|
|
9
|
+
model. Members practise what they preach: every programme is analysed, every
|
|
10
|
+
storey of the building is catalogued, and "colour" is spelt the British way --
|
|
11
|
+
whilst our American colleagues favour 'color'.
|
|
12
|
+
|
|
13
|
+
## Practical details
|
|
14
|
+
|
|
15
|
+
- The licence fee is 10 pounds and the practice runs 3-5 sessions a week.
|
|
16
|
+
- Please send your cheque to the Labour Party office by 4 September 2026.
|
|
17
|
+
- The theatre programme lists the metre readings, the tyre pressures, and the
|
|
18
|
+
disc brakes we've organised for the aluminium trailer.
|
|
19
|
+
- As the Defence Ministry's report put it, "the colour scheme was unauthorised".
|
|
20
|
+
|
|
21
|
+
The program crashed after the check cleared, and the story about the storey
|
|
22
|
+
made us tire of the whole thing. It's the Joneses' problem now, towards the end
|
|
23
|
+
of the '90s.
|
|
24
|
+
|
|
25
|
+
```python
|
|
26
|
+
colour = "unchanged in code" # organise nothing here
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
See `colour_utils.organise()` and [the colour guide](https://example.org/colour).
|