formwork-kit 0.1.0__py3-none-any.whl
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.
- formwork_cli/__init__.py +326 -0
- formwork_cli/kit/COSTS.md +111 -0
- formwork_cli/kit/adapters/claude-code/README.md +53 -0
- formwork_cli/kit/adapters/claude-code/settings.json +46 -0
- formwork_cli/kit/adapters/codex/README.md +43 -0
- formwork_cli/kit/adapters/cursor/README.md +45 -0
- formwork_cli/kit/adapters/gemini-cli/README.md +47 -0
- formwork_cli/kit/build +410 -0
- formwork_cli/kit/check/checks/config-shape +123 -0
- formwork_cli/kit/check/checks/decision-ids +159 -0
- formwork_cli/kit/check/checks/doc-links +133 -0
- formwork_cli/kit/check/checks/generated-current +74 -0
- formwork_cli/kit/check/checks/guard-wired +139 -0
- formwork_cli/kit/check/checks/kit-integrity +199 -0
- formwork_cli/kit/check/checks/predictions-first +127 -0
- formwork_cli/kit/check/checks/role-shape +172 -0
- formwork_cli/kit/check/checks/rule-labels +135 -0
- formwork_cli/kit/check/fixtures/config-shape/must-fail/documents-a-section-that-does-not-exist/.formwork.toml +5 -0
- formwork_cli/kit/check/fixtures/config-shape/must-fail/documents-a-section-that-does-not-exist/formwork/guide.md +13 -0
- formwork_cli/kit/check/fixtures/config-shape/must-fail/rules-as-a-switchboard/.formwork.toml +8 -0
- formwork_cli/kit/check/fixtures/config-shape/must-pass/layers-kept-apart/.formwork.toml +5 -0
- formwork_cli/kit/check/fixtures/decision-ids/must-fail/a-placeholder-shipped/docs/decisions/0003-still-pending.md +7 -0
- formwork_cli/kit/check/fixtures/decision-ids/must-fail/superseded-by-nothing/docs/decisions/0002-old.md +6 -0
- formwork_cli/kit/check/fixtures/decision-ids/must-fail/two-decisions-one-number/docs/decisions/0007-first.md +6 -0
- formwork_cli/kit/check/fixtures/decision-ids/must-fail/two-decisions-one-number/docs/decisions/0007-second.md +6 -0
- formwork_cli/kit/check/fixtures/decision-ids/must-pass/clean-numbering/docs/decisions/0001-the-first.md +6 -0
- formwork_cli/kit/check/fixtures/decision-ids/must-pass/clean-numbering/docs/decisions/0002-the-second.md +6 -0
- formwork_cli/kit/check/fixtures/decision-ids/must-pass/clean-numbering/docs/decisions/0003-the-third.md +6 -0
- formwork_cli/kit/check/fixtures/decision-ids/must-pass/nothing-recorded-yet/docs/decisions/README.md +3 -0
- formwork_cli/kit/check/fixtures/doc-links/must-fail/never-written/index.md +7 -0
- formwork_cli/kit/check/fixtures/doc-links/must-fail/renamed-file/architecture-notes.md +3 -0
- formwork_cli/kit/check/fixtures/doc-links/must-fail/renamed-file/guide.md +8 -0
- formwork_cli/kit/check/fixtures/doc-links/must-pass/links-resolve/architecture-notes.md +1 -0
- formwork_cli/kit/check/fixtures/doc-links/must-pass/links-resolve/guide.md +5 -0
- formwork_cli/kit/check/fixtures/generated-current/must-fail/a-generated-file-was-edited/.claude/agents/sample.md +22 -0
- formwork_cli/kit/check/fixtures/generated-current/must-fail/a-generated-file-was-edited/.codex/agents/sample.toml +22 -0
- formwork_cli/kit/check/fixtures/generated-current/must-fail/a-generated-file-was-edited/.formwork.toml +1 -0
- formwork_cli/kit/check/fixtures/generated-current/must-fail/a-generated-file-was-edited/.gemini/agents/sample.md +23 -0
- formwork_cli/kit/check/fixtures/generated-current/must-fail/a-generated-file-was-edited/formwork/build +349 -0
- formwork_cli/kit/check/fixtures/generated-current/must-fail/a-generated-file-was-edited/formwork/roles/method/sample.md +18 -0
- formwork_cli/kit/check/fixtures/generated-current/must-pass/generated-and-current/.claude/agents/sample.md +20 -0
- formwork_cli/kit/check/fixtures/generated-current/must-pass/generated-and-current/.codex/agents/sample.toml +22 -0
- formwork_cli/kit/check/fixtures/generated-current/must-pass/generated-and-current/.formwork.toml +1 -0
- formwork_cli/kit/check/fixtures/generated-current/must-pass/generated-and-current/.gemini/agents/sample.md +23 -0
- formwork_cli/kit/check/fixtures/generated-current/must-pass/generated-and-current/formwork/build +349 -0
- formwork_cli/kit/check/fixtures/generated-current/must-pass/generated-and-current/formwork/roles/method/sample.md +18 -0
- formwork_cli/kit/check/fixtures/generated-current/must-pass/nothing-is-generated-here/README.md +3 -0
- formwork_cli/kit/check/fixtures/guard-wired/must-fail/declared-but-no-file/.formwork.toml +1 -0
- formwork_cli/kit/check/fixtures/guard-wired/must-fail/file-but-not-wired/.claude/settings.json +1 -0
- formwork_cli/kit/check/fixtures/guard-wired/must-fail/file-but-not-wired/.formwork.toml +1 -0
- formwork_cli/kit/check/fixtures/guard-wired/must-pass/declared-and-wired/.claude/settings.json +1 -0
- formwork_cli/kit/check/fixtures/guard-wired/must-pass/declared-and-wired/.formwork.toml +1 -0
- formwork_cli/kit/check/fixtures/guard-wired/must-pass/nothing-declared/README.md +1 -0
- formwork_cli/kit/check/fixtures/kit-integrity/must-fail/a-check-went-missing/formwork/check/checks/still-here +2 -0
- formwork_cli/kit/check/fixtures/kit-integrity/must-fail/a-check-went-missing/state/fingerprints.txt +2 -0
- formwork_cli/kit/check/fixtures/kit-integrity/must-fail/a-guard-was-altered/formwork/guard/git-boundary +3 -0
- formwork_cli/kit/check/fixtures/kit-integrity/must-fail/a-guard-was-altered/state/fingerprints.txt +1 -0
- formwork_cli/kit/check/fixtures/kit-integrity/must-pass/everything-matches/formwork/guard/git-boundary +2 -0
- formwork_cli/kit/check/fixtures/kit-integrity/must-pass/everything-matches/state/fingerprints.txt +1 -0
- formwork_cli/kit/check/fixtures/predictions-first/must-fail/argued-with-no-predictions/docs/rounds/0004-the-storage-question/architect.md +3 -0
- formwork_cli/kit/check/fixtures/predictions-first/must-fail/argued-with-no-predictions/docs/rounds/0004-the-storage-question/researcher.md +3 -0
- formwork_cli/kit/check/fixtures/predictions-first/must-fail/argued-with-no-predictions/docs/rounds/0004-the-storage-question/round.md +4 -0
- formwork_cli/kit/check/fixtures/predictions-first/must-pass/a-round-that-has-not-argued-yet/docs/rounds/0006-not-started/round.md +3 -0
- formwork_cli/kit/check/fixtures/predictions-first/must-pass/no-rounds-at-all/docs/README.md +3 -0
- formwork_cli/kit/check/fixtures/predictions-first/must-pass/predictions-on-record/docs/rounds/0005-the-shape-of-a-brief/architect.md +3 -0
- formwork_cli/kit/check/fixtures/predictions-first/must-pass/predictions-on-record/docs/rounds/0005-the-shape-of-a-brief/predictions.md +4 -0
- formwork_cli/kit/check/fixtures/predictions-first/must-pass/predictions-on-record/docs/rounds/0005-the-shape-of-a-brief/researcher.md +3 -0
- formwork_cli/kit/check/fixtures/role-shape/must-fail/claims-a-grant-binds-everywhere/formwork/roles/README.md +6 -0
- formwork_cli/kit/check/fixtures/role-shape/must-fail/claims-a-grant-binds-everywhere/formwork/roles/complete.md +18 -0
- formwork_cli/kit/check/fixtures/role-shape/must-fail/missing-a-section/formwork/roles/vague.md +16 -0
- formwork_cli/kit/check/fixtures/role-shape/must-fail/spawn-without-being-lead/formwork/roles/eager.md +18 -0
- formwork_cli/kit/check/fixtures/role-shape/must-fail/two-roles-one-job/formwork/roles/first.md +18 -0
- formwork_cli/kit/check/fixtures/role-shape/must-fail/two-roles-one-job/formwork/roles/second.md +18 -0
- formwork_cli/kit/check/fixtures/role-shape/must-pass/well-formed/formwork/roles/complete.md +18 -0
- formwork_cli/kit/check/fixtures/rule-labels/must-fail/claims-enforcement-that-does-not-exist/formwork/rules/core.md +9 -0
- formwork_cli/kit/check/fixtures/rule-labels/must-fail/no-catches/formwork/rules/core.md +9 -0
- formwork_cli/kit/check/fixtures/rule-labels/must-fail/unlabelled/formwork/rules/core.md +7 -0
- formwork_cli/kit/check/fixtures/rule-labels/must-pass/well-formed/formwork/rules/core.md +10 -0
- formwork_cli/kit/check/run +340 -0
- formwork_cli/kit/check/test_gate.py +222 -0
- formwork_cli/kit/first-run.md +204 -0
- formwork_cli/kit/fw +121 -0
- formwork_cli/kit/glossary.md +160 -0
- formwork_cli/kit/guard/git-boundary +627 -0
- formwork_cli/kit/guard/protected-files +748 -0
- formwork_cli/kit/guard/quality-gate +260 -0
- formwork_cli/kit/guard/test_boundary.py +273 -0
- formwork_cli/kit/guard/test_protection.py +254 -0
- formwork_cli/kit/guard/test_quality_gate.py +156 -0
- formwork_cli/kit/install +395 -0
- formwork_cli/kit/limits.md +141 -0
- formwork_cli/kit/loop.md +82 -0
- formwork_cli/kit/roles/HOW-TO-ADD-A-ROLE.md +105 -0
- formwork_cli/kit/roles/TEMPLATE.md +26 -0
- formwork_cli/kit/roles/method/architect.md +269 -0
- formwork_cli/kit/roles/method/challenger.md +243 -0
- formwork_cli/kit/roles/method/lead.md +280 -0
- formwork_cli/kit/roles/method/record-keeper.md +206 -0
- formwork_cli/kit/roles/method/researcher.md +246 -0
- formwork_cli/kit/roles/method/reviewer.md +207 -0
- formwork_cli/kit/roles/packs/accessibility.md +236 -0
- formwork_cli/kit/roles/packs/ai.md +248 -0
- formwork_cli/kit/roles/packs/analyst.md +233 -0
- formwork_cli/kit/roles/packs/backend.md +425 -0
- formwork_cli/kit/roles/packs/brainstormer.md +190 -0
- formwork_cli/kit/roles/packs/data.md +212 -0
- formwork_cli/kit/roles/packs/devops.md +203 -0
- formwork_cli/kit/roles/packs/frontend.md +224 -0
- formwork_cli/kit/roles/packs/integrations.md +215 -0
- formwork_cli/kit/roles/packs/legal.md +251 -0
- formwork_cli/kit/roles/packs/marketing.md +206 -0
- formwork_cli/kit/roles/packs/mobile.md +202 -0
- formwork_cli/kit/roles/packs/performance.md +192 -0
- formwork_cli/kit/roles/packs/product.md +217 -0
- formwork_cli/kit/roles/packs/security.md +267 -0
- formwork_cli/kit/roles/packs/sre.md +203 -0
- formwork_cli/kit/roles/packs/tester.md +246 -0
- formwork_cli/kit/roles/packs/user-researcher.md +218 -0
- formwork_cli/kit/roles/packs/ux.md +205 -0
- formwork_cli/kit/roles/packs/visual.md +199 -0
- formwork_cli/kit/roles/packs/writer.md +198 -0
- formwork_cli/kit/round.md +131 -0
- formwork_cli/kit/rules/core.md +195 -0
- formwork_cli/kit/rules/full.md +493 -0
- formwork_cli/kit/templates/brief.md +68 -0
- formwork_cli/kit/templates/decision.md +93 -0
- formwork_cli/kit/templates/predictions.md +54 -0
- formwork_cli/kit/templates/report.md +52 -0
- formwork_cli/kit/templates/round.md +77 -0
- formwork_cli/kit/test_install.py +165 -0
- formwork_cli/kit/troubleshooting.md +247 -0
- formwork_cli/kit-page/FORMWORK.md +182 -0
- formwork_kit-0.1.0.dist-info/METADATA +308 -0
- formwork_kit-0.1.0.dist-info/RECORD +137 -0
- formwork_kit-0.1.0.dist-info/WHEEL +4 -0
- formwork_kit-0.1.0.dist-info/entry_points.txt +2 -0
- formwork_kit-0.1.0.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
# Your first fifteen minutes
|
|
2
|
+
|
|
3
|
+
Seven short steps, on your own project. No tutorial, no sample repository.
|
|
4
|
+
|
|
5
|
+
**Nothing here restructures your work.** The install adds files and touches
|
|
6
|
+
nothing else. It does not need a clean working tree.
|
|
7
|
+
|
|
8
|
+
**The fifteen minutes is a target, not a measurement.** The machine's share is
|
|
9
|
+
about a second. Your share is step 4, which is real work on your own project,
|
|
10
|
+
and nobody can time that for you.
|
|
11
|
+
|
|
12
|
+
> [!TIP]
|
|
13
|
+
> **`command not found: formwork`?** Everything here also works as
|
|
14
|
+
> `formwork/fw check`, `formwork/fw record` and so on, from the top of your
|
|
15
|
+
> project. To get the short command: `pipx install formwork-kit`.
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## 0. Get the kit into your project
|
|
20
|
+
|
|
21
|
+
```
|
|
22
|
+
formwork init
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
That puts `formwork/` and `FORMWORK.md` here. Without the command, copy those
|
|
26
|
+
two in by hand from the source repository. Nothing else in it is needed.
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## 1. Install
|
|
31
|
+
|
|
32
|
+
```
|
|
33
|
+
formwork install
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
It works out which agent you use, writes `.formwork.toml`, wires the guards
|
|
37
|
+
into that agent's hooks, and generates your role files.
|
|
38
|
+
|
|
39
|
+
**It adds and never removes.** Existing hook settings are kept, the kit's are
|
|
40
|
+
added alongside, and a copy of your original is saved first.
|
|
41
|
+
|
|
42
|
+
**It also writes one file outside your project**, in `~/.formwork/`: a
|
|
43
|
+
fingerprint of everything that enforces a rule. Keeping it outside means a
|
|
44
|
+
change to a guard cannot be hidden by changing the record next to it. It is
|
|
45
|
+
also why a clone on another machine needs installing again.
|
|
46
|
+
|
|
47
|
+
`formwork install --dry-run` shows what it would do. `--runtime cursor` says
|
|
48
|
+
which agent when it cannot tell.
|
|
49
|
+
|
|
50
|
+
**Read the exit code.** `0` finished. `1` got as far as it could and prints a
|
|
51
|
+
`NOT FINISHED` list. `2` could not run.
|
|
52
|
+
|
|
53
|
+
**On Claude Code the gate is green straight away.** On the other three it
|
|
54
|
+
writes your config and roles but cannot wire the hooks, because the kit ships
|
|
55
|
+
no wiring file for them. Your gate stays red until you write that file
|
|
56
|
+
yourself, using your agent's page in `formwork/adapters/`. Red is correct
|
|
57
|
+
there: nothing is guarding yet.
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
## 2. Watch it refuse
|
|
62
|
+
|
|
63
|
+
Ask your agent to commit something.
|
|
64
|
+
|
|
65
|
+
```
|
|
66
|
+
you: commit this for me
|
|
67
|
+
agent: (tries)
|
|
68
|
+
REFUSED by the version-control boundary: git commit changes
|
|
69
|
+
the repository.
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
The command never ran.
|
|
73
|
+
|
|
74
|
+
Now ask it for `git status`. That works, as it always did.
|
|
75
|
+
|
|
76
|
+
**Nothing was explained to you. You watched it happen.** That is the whole
|
|
77
|
+
teaching method here: the rules catch things in front of you rather than being
|
|
78
|
+
argued for.
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
## 3. Watch a check go red
|
|
83
|
+
|
|
84
|
+
```
|
|
85
|
+
formwork check
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Green. Now:
|
|
89
|
+
|
|
90
|
+
```
|
|
91
|
+
formwork demo
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Each check runs against an input built to break it, and you watch each one
|
|
95
|
+
refuse.
|
|
96
|
+
|
|
97
|
+
**A check nobody has seen fail is not evidence of anything.** Every check ships
|
|
98
|
+
an input it must reject and one it must accept, so it has to tell them apart
|
|
99
|
+
rather than simply be capable of complaining. If one ever stops rejecting its
|
|
100
|
+
broken input, the gate goes red for that reason alone.
|
|
101
|
+
|
|
102
|
+
---
|
|
103
|
+
|
|
104
|
+
## 4. Do one real thing
|
|
105
|
+
|
|
106
|
+
Pick something small and genuinely yours. A rename. A typo. A comment.
|
|
107
|
+
|
|
108
|
+
Write a one-line brief:
|
|
109
|
+
|
|
110
|
+
```
|
|
111
|
+
Rename `foo` to `bar` in the parser. Nothing else.
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
That is a complete brief: a goal, a scope, and a fence.
|
|
115
|
+
|
|
116
|
+
Let the agent do it. Then read what comes back:
|
|
117
|
+
|
|
118
|
+
```
|
|
119
|
+
Renamed foo -> bar in parser.py and its two tests.
|
|
120
|
+
Gate green.
|
|
121
|
+
Nothing staged.
|
|
122
|
+
Nothing unasked, nothing skipped, brief was accurate.
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
Four lines, answering the three questions that matter: what was done beyond the
|
|
126
|
+
request, what was skipped, and whether the brief was right.
|
|
127
|
+
|
|
128
|
+
> [!IMPORTANT]
|
|
129
|
+
> **Then it stops.** It does not start the next thing. That is the loop, and
|
|
130
|
+
> `STOP` is the part worth keeping if you keep nothing else.
|
|
131
|
+
|
|
132
|
+
---
|
|
133
|
+
|
|
134
|
+
## 5. Now read the page
|
|
135
|
+
|
|
136
|
+
[`FORMWORK.md`](../FORMWORK.md). One page, **after** doing the work rather than
|
|
137
|
+
before.
|
|
138
|
+
|
|
139
|
+
Everything on it now refers to something you have already seen.
|
|
140
|
+
|
|
141
|
+
---
|
|
142
|
+
|
|
143
|
+
## 6. What to read when you need it
|
|
144
|
+
|
|
145
|
+
Nothing else is required today. These are the pages for when the situation
|
|
146
|
+
arrives:
|
|
147
|
+
|
|
148
|
+
| | |
|
|
149
|
+
|---|---|
|
|
150
|
+
| [`loop.md`](loop.md) | the working loop in full: brief, work, check, report, stop |
|
|
151
|
+
| [`round.md`](round.md) | how to run a round, and when one is worth the money |
|
|
152
|
+
| [`templates/`](templates/) | the brief, the report, the decision record, the round |
|
|
153
|
+
| [`roles/HOW-TO-ADD-A-ROLE.md`](roles/HOW-TO-ADD-A-ROLE.md) | adding your own |
|
|
154
|
+
| [`COSTS.md`](COSTS.md) | what this costs, and the number nobody has |
|
|
155
|
+
| [`limits.md`](limits.md) | what the guards cannot do. Read before trusting them |
|
|
156
|
+
| [`glossary.md`](glossary.md) | any word here you did not recognise |
|
|
157
|
+
| [`troubleshooting.md`](troubleshooting.md) | when something goes wrong |
|
|
158
|
+
|
|
159
|
+
---
|
|
160
|
+
|
|
161
|
+
## What you have not been told
|
|
162
|
+
|
|
163
|
+
Forty-six rules exist, in [`rules/`](rules/). Thirteen you meet daily,
|
|
164
|
+
thirty-three for particular situations. You have seen three of them, by
|
|
165
|
+
watching them catch something.
|
|
166
|
+
|
|
167
|
+
Reading them now would be reading a list. You would agree with all of them and
|
|
168
|
+
remember none.
|
|
169
|
+
|
|
170
|
+
## Some of it will look like fussiness
|
|
171
|
+
|
|
172
|
+
It will. Several of these rules came from failures you have not had.
|
|
173
|
+
|
|
174
|
+
Each one says what it catches. **If you never hit that, delete it** from
|
|
175
|
+
`formwork/rules/core.md`, so that losing a rule is a line in your version
|
|
176
|
+
control with your name on it. There is no switch for this in `.formwork.toml`
|
|
177
|
+
on purpose. What that file tunes is how hard the guards bite: `block`, `warn`
|
|
178
|
+
or `off`.
|
|
179
|
+
|
|
180
|
+
A rule followed without understanding gets dropped quietly later anyway.
|
|
181
|
+
|
|
182
|
+
## If your agent cannot block
|
|
183
|
+
|
|
184
|
+
**Only Claude Code has been watched refusing a real command.** The other three
|
|
185
|
+
document a way and nobody has tried it. Their adapter pages say so in one word:
|
|
186
|
+
untested.
|
|
187
|
+
|
|
188
|
+
If yours is one of those three:
|
|
189
|
+
|
|
190
|
+
**Step 2 may do nothing.** Ask for the commit anyway. If it is refused, you
|
|
191
|
+
have established something nobody had established before, and it is worth
|
|
192
|
+
saying so. If it goes through, you now know that on day one rather than on a
|
|
193
|
+
bad day.
|
|
194
|
+
|
|
195
|
+
**Steps 3 and 4 work either way.** `formwork demo` is a program you run
|
|
196
|
+
yourself. The loop, the brief and the stop are things the agent does because
|
|
197
|
+
the rules say so.
|
|
198
|
+
|
|
199
|
+
> [!WARNING]
|
|
200
|
+
> **The checks are yours whatever you run. None of the three guards is, until
|
|
201
|
+
> the hooks are wired.**
|
|
202
|
+
|
|
203
|
+
A rule an agent follows most of the time is worth having. It is not the same as
|
|
204
|
+
one it cannot break, and this kit will not blur the two.
|
formwork_cli/kit/fw
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""One command for everything in this kit.
|
|
3
|
+
|
|
4
|
+
formwork/fw what you can do
|
|
5
|
+
formwork/fw install set this project up
|
|
6
|
+
formwork/fw check run every check
|
|
7
|
+
formwork/fw demo watch every check refuse a broken input
|
|
8
|
+
formwork/fw roles rebuild the role files after editing one
|
|
9
|
+
formwork/fw record write down what the kit looks like now
|
|
10
|
+
formwork/fw test run every test
|
|
11
|
+
|
|
12
|
+
WHY THIS EXISTS
|
|
13
|
+
---------------
|
|
14
|
+
Before this, you had to remember `formwork/install --runtime claude-code` and
|
|
15
|
+
`formwork/check/run` and `formwork/build`. Three paths and a flag, for five
|
|
16
|
+
things you do every day.
|
|
17
|
+
|
|
18
|
+
A Makefile at your project root would have been the obvious answer. It is also
|
|
19
|
+
a file name your project may already be using, and overwriting somebody's build
|
|
20
|
+
to save them typing is exactly what this kit exists to prevent.
|
|
21
|
+
|
|
22
|
+
So: one file, inside the kit's own folder, where nothing can collide.
|
|
23
|
+
|
|
24
|
+
Exit status is whatever the program underneath returned, so this can be used in
|
|
25
|
+
a script the same way as the programs it calls.
|
|
26
|
+
"""
|
|
27
|
+
import os
|
|
28
|
+
import subprocess
|
|
29
|
+
import sys
|
|
30
|
+
|
|
31
|
+
HERE = os.path.dirname(os.path.abspath(__file__))
|
|
32
|
+
|
|
33
|
+
COMMANDS = [
|
|
34
|
+
("install", "set this project up. Add --runtime <name> to pick your agent"),
|
|
35
|
+
("check", "run every check on this project"),
|
|
36
|
+
("demo", "watch every check refuse a broken input"),
|
|
37
|
+
("roles", "rebuild the role files after editing one"),
|
|
38
|
+
("record", "write down what the kit looks like now, after you changed it"),
|
|
39
|
+
("test", "run every test in the kit"),
|
|
40
|
+
]
|
|
41
|
+
|
|
42
|
+
TESTS = [
|
|
43
|
+
os.path.join("guard", "test_boundary.py"),
|
|
44
|
+
os.path.join("guard", "test_protection.py"),
|
|
45
|
+
os.path.join("guard", "test_quality_gate.py"),
|
|
46
|
+
os.path.join("check", "test_gate.py"),
|
|
47
|
+
"test_install.py",
|
|
48
|
+
]
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
PROJECT = os.path.dirname(HERE)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def run(path, args):
|
|
55
|
+
full = os.path.join(HERE, path)
|
|
56
|
+
if not os.path.isfile(full):
|
|
57
|
+
print("ERROR: %s is missing from this kit" % path, file=sys.stderr)
|
|
58
|
+
return 2
|
|
59
|
+
try:
|
|
60
|
+
# From the project, always. Run from a subfolder without this and
|
|
61
|
+
# `install` wrote a second configuration into that subfolder and
|
|
62
|
+
# called it a success.
|
|
63
|
+
return subprocess.run([full] + args, cwd=PROJECT).returncode
|
|
64
|
+
except OSError as e:
|
|
65
|
+
print("ERROR: could not run %s: %s" % (path, e), file=sys.stderr)
|
|
66
|
+
return 2
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def run_tests():
|
|
70
|
+
failed = []
|
|
71
|
+
for t in TESTS:
|
|
72
|
+
full = os.path.join(HERE, t)
|
|
73
|
+
if not os.path.isfile(full):
|
|
74
|
+
continue
|
|
75
|
+
print("\n%s" % t, flush=True)
|
|
76
|
+
if subprocess.run([sys.executable, full], cwd=PROJECT).returncode != 0:
|
|
77
|
+
failed.append(t)
|
|
78
|
+
print("")
|
|
79
|
+
if failed:
|
|
80
|
+
print("FAILED: %s" % ", ".join(failed), file=sys.stderr)
|
|
81
|
+
return 1
|
|
82
|
+
print("every test passed")
|
|
83
|
+
return 0
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def usage():
|
|
87
|
+
print("formwork/fw <command>")
|
|
88
|
+
print("")
|
|
89
|
+
for name, what in COMMANDS:
|
|
90
|
+
print(" %-9s %s" % (name, what))
|
|
91
|
+
print("")
|
|
92
|
+
print("Nothing here is hidden. Each one runs a program in this folder that")
|
|
93
|
+
print("you can also run directly.")
|
|
94
|
+
return 0
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def main(argv):
|
|
98
|
+
if len(argv) < 2 or argv[1] in ("help", "-h", "--help"):
|
|
99
|
+
return usage()
|
|
100
|
+
cmd, rest = argv[1], argv[2:]
|
|
101
|
+
if cmd == "install":
|
|
102
|
+
return run("install", rest)
|
|
103
|
+
if cmd == "check":
|
|
104
|
+
return run(os.path.join("check", "run"), rest)
|
|
105
|
+
if cmd == "demo":
|
|
106
|
+
return run(os.path.join("check", "run"), ["--demo-fail"] + rest)
|
|
107
|
+
if cmd == "roles":
|
|
108
|
+
return run("build", rest)
|
|
109
|
+
if cmd == "test":
|
|
110
|
+
return run_tests()
|
|
111
|
+
if cmd == "record":
|
|
112
|
+
return run(os.path.join("check", "checks", "kit-integrity"),
|
|
113
|
+
["--record", os.path.dirname(HERE)] + rest)
|
|
114
|
+
print("ERROR: no such command: %s" % cmd, file=sys.stderr)
|
|
115
|
+
print("", file=sys.stderr)
|
|
116
|
+
usage()
|
|
117
|
+
return 2
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
if __name__ == "__main__":
|
|
121
|
+
sys.exit(main(sys.argv))
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
# Words this kit uses
|
|
2
|
+
|
|
3
|
+
Plain meanings, collected so you never have to go looking.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## The main ones
|
|
8
|
+
|
|
9
|
+
**Agent**
|
|
10
|
+
A program that does work for you using an AI model. You tell it what you want
|
|
11
|
+
in plain words. It reads files, writes files and runs commands. Claude Code,
|
|
12
|
+
Codex, Cursor and Gemini CLI are agents.
|
|
13
|
+
|
|
14
|
+
**Runtime**
|
|
15
|
+
The particular agent tool you use. This kit supports four of them. You tell it
|
|
16
|
+
which one you have in `.formwork.toml`.
|
|
17
|
+
|
|
18
|
+
**Role**
|
|
19
|
+
A job description for an agent. One file. It says what that job owns, what it
|
|
20
|
+
does not own, when it should stop, and what bad work from it would look like.
|
|
21
|
+
This kit ships twenty seven.
|
|
22
|
+
|
|
23
|
+
**Guard**
|
|
24
|
+
A small program that refuses. Two of the three stop a command before it runs.
|
|
25
|
+
The third stops a turn from ending while the gate is red. Not a warning.
|
|
26
|
+
|
|
27
|
+
**Check**
|
|
28
|
+
A small program that reads your project and says green or red. Checks look at
|
|
29
|
+
what is there. Guards stop what is about to happen.
|
|
30
|
+
|
|
31
|
+
**The gate**, also called **the aggregate**
|
|
32
|
+
All nine checks, run together, with one answer at the end. Green or red.
|
|
33
|
+
|
|
34
|
+
You will see the word aggregate in a refusal: *the aggregate is red, so this
|
|
35
|
+
turn cannot conclude*. It means the same thing.
|
|
36
|
+
|
|
37
|
+
**Adapter**
|
|
38
|
+
The instructions for wiring the guards into one particular agent. One folder
|
|
39
|
+
per agent, in `formwork/adapters/`.
|
|
40
|
+
|
|
41
|
+
**Frontmatter**
|
|
42
|
+
The block at the very top of a role file, between two lines of three dashes.
|
|
43
|
+
It holds the name, the pack, the owns slug and the tools. A role without it
|
|
44
|
+
does not load.
|
|
45
|
+
|
|
46
|
+
**Slug**
|
|
47
|
+
A short name with no spaces, used as an identifier. `owns: what-runs-on-a-
|
|
48
|
+
server` is a slug. Two roles may not use the same one.
|
|
49
|
+
|
|
50
|
+
**Turn**
|
|
51
|
+
One exchange. You ask for something, the agent works, the agent replies. The
|
|
52
|
+
gate runs at the end of every turn where something changed.
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
## Words about the work
|
|
57
|
+
|
|
58
|
+
**Brief**
|
|
59
|
+
What you want, written down before any work starts. Six short headings. The
|
|
60
|
+
template is in `formwork/templates/brief.md`.
|
|
61
|
+
|
|
62
|
+
**Report**
|
|
63
|
+
What came back. What was done, what was skipped, what the agent thinks you
|
|
64
|
+
should know. The template is in `formwork/templates/report.md`.
|
|
65
|
+
|
|
66
|
+
**Round**
|
|
67
|
+
Several agents looking at the same question at once, arguing, and one document
|
|
68
|
+
coming out. Expensive. Only worth it for a decision you cannot easily undo. See
|
|
69
|
+
`formwork/round.md`.
|
|
70
|
+
|
|
71
|
+
**Predictions**
|
|
72
|
+
What the challenger expects to go wrong, written before anybody proposes anything.
|
|
73
|
+
Written after the fact it is not a prediction, it is agreement.
|
|
74
|
+
|
|
75
|
+
**Decision record**
|
|
76
|
+
One page saying what was decided, why, and what follows from it. Numbered.
|
|
77
|
+
Never edited afterwards. If it changes later, a new one replaces it and both
|
|
78
|
+
are kept.
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
## Words about the guards
|
|
83
|
+
|
|
84
|
+
**Blocked** or **refused**
|
|
85
|
+
The command did not run. You will see the word REFUSED and a reason.
|
|
86
|
+
|
|
87
|
+
**The version-control boundary**
|
|
88
|
+
The rule that your agent never commits, pushes or merges. You do that. It is
|
|
89
|
+
enforced by a guard, not by asking nicely.
|
|
90
|
+
|
|
91
|
+
**Self-protection**
|
|
92
|
+
The rule that your agent cannot quietly change the kit's own files. The guards,
|
|
93
|
+
the checks and the settings.
|
|
94
|
+
|
|
95
|
+
**Strength**
|
|
96
|
+
How hard a guard bites. Three settings: `block` refuses, `warn` lets it through
|
|
97
|
+
and tells you, `off` does nothing. Set in `.formwork.toml`.
|
|
98
|
+
|
|
99
|
+
**Refusal budget**
|
|
100
|
+
The turn-end gate refuses a red gate three times in one session, then steps
|
|
101
|
+
aside and says so loudly. Without this, a genuinely stuck turn would be stuck
|
|
102
|
+
for ever.
|
|
103
|
+
|
|
104
|
+
**Fingerprint**
|
|
105
|
+
A short code worked out from the exact contents of a file. Change one character
|
|
106
|
+
and the code changes. The kit keeps one for each file that enforces something,
|
|
107
|
+
outside your project, so a change to a guard cannot be hidden.
|
|
108
|
+
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
## Words about the checks
|
|
112
|
+
|
|
113
|
+
**Fixture**
|
|
114
|
+
A small fake project used to test a check. Every check ships two kinds: one it
|
|
115
|
+
must reject, and one it must accept.
|
|
116
|
+
|
|
117
|
+
**Must-fail** and **must-pass**
|
|
118
|
+
Those two kinds. A check has to tell them apart. Being able to complain is not
|
|
119
|
+
enough.
|
|
120
|
+
|
|
121
|
+
**Green** and **red**
|
|
122
|
+
Green means every check passed. Red means at least one found something and
|
|
123
|
+
named it.
|
|
124
|
+
|
|
125
|
+
**Cannot run**
|
|
126
|
+
A third answer, and the most important one. The check could not do its job.
|
|
127
|
+
This is never treated as a pass.
|
|
128
|
+
|
|
129
|
+
---
|
|
130
|
+
|
|
131
|
+
## Words you will see in role files
|
|
132
|
+
|
|
133
|
+
**Owns**
|
|
134
|
+
The one thing that job is responsible for. No two roles own the same thing.
|
|
135
|
+
|
|
136
|
+
**Does not own**
|
|
137
|
+
What to hand to somebody else, and who.
|
|
138
|
+
|
|
139
|
+
**Stops when**
|
|
140
|
+
The moment that job should stop and ask you instead of guessing.
|
|
141
|
+
|
|
142
|
+
**Tools**
|
|
143
|
+
Which abilities a role may use: reading, writing, running commands, searching
|
|
144
|
+
the web, starting other agents. Only the lead may start other agents.
|
|
145
|
+
|
|
146
|
+
**Pack**
|
|
147
|
+
A group of related roles. The software pack, the design pack, and so on. All
|
|
148
|
+
roles are available today. There is no switch yet, and the kit says so.
|
|
149
|
+
|
|
150
|
+
---
|
|
151
|
+
|
|
152
|
+
## Two phrases worth knowing
|
|
153
|
+
|
|
154
|
+
**NOT ESTABLISHED**
|
|
155
|
+
Nobody has measured this or checked it. It is not a guess dressed up as a fact.
|
|
156
|
+
Where you see this, treat the thing as unknown.
|
|
157
|
+
|
|
158
|
+
**Catches**
|
|
159
|
+
Every rule has a line saying what it catches. If a rule cannot say what goes
|
|
160
|
+
wrong without it, it is an opinion, not a rule.
|