hamilton-core 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.
- hamilton_core-0.1.0/LICENSE +21 -0
- hamilton_core-0.1.0/PKG-INFO +402 -0
- hamilton_core-0.1.0/README.md +357 -0
- hamilton_core-0.1.0/hamilton_core/__init__.py +3 -0
- hamilton_core-0.1.0/hamilton_core/__main__.py +6 -0
- hamilton_core-0.1.0/hamilton_core/check.py +613 -0
- hamilton_core-0.1.0/hamilton_core/cli.py +75 -0
- hamilton_core-0.1.0/hamilton_core/guard.py +76 -0
- hamilton_core-0.1.0/hamilton_core/init.py +83 -0
- hamilton_core-0.1.0/hamilton_core/launch.py +198 -0
- hamilton_core-0.1.0/hamilton_core/model.py +202 -0
- hamilton_core-0.1.0/hamilton_core/show.py +138 -0
- hamilton_core-0.1.0/hamilton_core/status.py +141 -0
- hamilton_core-0.1.0/hamilton_core/templates/AGENTS.md +24 -0
- hamilton_core-0.1.0/hamilton_core/templates/CLAUDE.md +2 -0
- hamilton_core-0.1.0/hamilton_core/templates/claude/settings.json +16 -0
- hamilton_core-0.1.0/hamilton_core/templates/hamilton/config +26 -0
- hamilton_core-0.1.0/hamilton_core/templates/hamilton/phase +1 -0
- hamilton_core-0.1.0/hamilton_core/templates/prompts/hamilton.md +559 -0
- hamilton_core-0.1.0/hamilton_core/templates/spec/actors.md +11 -0
- hamilton_core-0.1.0/hamilton_core/templates/spec/requirements.md +45 -0
- hamilton_core-0.1.0/hamilton_core/templates/spec/vision.md +21 -0
- hamilton_core-0.1.0/hamilton_core/tree.py +70 -0
- hamilton_core-0.1.0/hamilton_core/upgrade.py +114 -0
- hamilton_core-0.1.0/hamilton_core.egg-info/PKG-INFO +402 -0
- hamilton_core-0.1.0/hamilton_core.egg-info/SOURCES.txt +41 -0
- hamilton_core-0.1.0/hamilton_core.egg-info/dependency_links.txt +1 -0
- hamilton_core-0.1.0/hamilton_core.egg-info/entry_points.txt +2 -0
- hamilton_core-0.1.0/hamilton_core.egg-info/requires.txt +3 -0
- hamilton_core-0.1.0/hamilton_core.egg-info/top_level.txt +1 -0
- hamilton_core-0.1.0/pyproject.toml +51 -0
- hamilton_core-0.1.0/setup.cfg +4 -0
- hamilton_core-0.1.0/tests/test_check.py +311 -0
- hamilton_core-0.1.0/tests/test_guard.py +249 -0
- hamilton_core-0.1.0/tests/test_init.py +159 -0
- hamilton_core-0.1.0/tests/test_launch.py +162 -0
- hamilton_core-0.1.0/tests/test_model.py +110 -0
- hamilton_core-0.1.0/tests/test_normalize.py +55 -0
- hamilton_core-0.1.0/tests/test_show.py +184 -0
- hamilton_core-0.1.0/tests/test_status.py +96 -0
- hamilton_core-0.1.0/tests/test_tree.py +109 -0
- hamilton_core-0.1.0/tests/test_upgrade.py +173 -0
- hamilton_core-0.1.0/tests/test_warnings.py +140 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 D5 Software GmbH
|
|
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.
|
|
@@ -0,0 +1,402 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: hamilton-core
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Specification-gated development with enforced verification
|
|
5
|
+
Author-email: Sebastian Greshake <sebastian.greshake@d5software.de>
|
|
6
|
+
License: MIT License
|
|
7
|
+
|
|
8
|
+
Copyright (c) 2026 D5 Software GmbH
|
|
9
|
+
|
|
10
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
11
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
12
|
+
in the Software without restriction, including without limitation the rights
|
|
13
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
14
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
15
|
+
furnished to do so, subject to the following conditions:
|
|
16
|
+
|
|
17
|
+
The above copyright notice and this permission notice shall be included in all
|
|
18
|
+
copies or substantial portions of the Software.
|
|
19
|
+
|
|
20
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
21
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
22
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
23
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
24
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
25
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
26
|
+
SOFTWARE.
|
|
27
|
+
|
|
28
|
+
Project-URL: Homepage, https://github.com/hamilton-toolkit/core
|
|
29
|
+
Project-URL: Repository, https://github.com/hamilton-toolkit/core
|
|
30
|
+
Project-URL: Issues, https://github.com/hamilton-toolkit/core/issues
|
|
31
|
+
Classifier: Development Status :: 3 - Alpha
|
|
32
|
+
Classifier: Environment :: Console
|
|
33
|
+
Classifier: Intended Audience :: Developers
|
|
34
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
35
|
+
Classifier: Programming Language :: Python :: 3
|
|
36
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
37
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
38
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
39
|
+
Requires-Python: >=3.11
|
|
40
|
+
Description-Content-Type: text/markdown
|
|
41
|
+
License-File: LICENSE
|
|
42
|
+
Provides-Extra: test
|
|
43
|
+
Requires-Dist: pytest; extra == "test"
|
|
44
|
+
Dynamic: license-file
|
|
45
|
+
|
|
46
|
+
# Hamilton
|
|
47
|
+
|
|
48
|
+
> Forget vibe coding, start engineering.
|
|
49
|
+
|
|
50
|
+
Hamilton is a small framework for building software **with** an AI agent
|
|
51
|
+
without taking its word for when the work is done. You write down what the
|
|
52
|
+
software must do — as specific, testable acceptance criteria — *before* it is
|
|
53
|
+
built. The agent then implements it and writes the tests. One command,
|
|
54
|
+
`hamilton check`, verifies that every criterion has a test that names it, that
|
|
55
|
+
the suite passes, and that no criterion has been quietly reworded since it last
|
|
56
|
+
passed. Specification, code and tests live in one repository and land in one
|
|
57
|
+
review.
|
|
58
|
+
|
|
59
|
+
## Why
|
|
60
|
+
|
|
61
|
+
Vibe coding optimises for the first working version and leaves you to discover
|
|
62
|
+
later what it actually does. That is fine until the software matters, and then
|
|
63
|
+
the missing half of the work — *deciding what it should do, and proving it
|
|
64
|
+
does* — is the expensive half.
|
|
65
|
+
|
|
66
|
+
Hamilton borrows the discipline of the **V-model** from systems engineering:
|
|
67
|
+
verification intent is fixed *before* implementation, by someone not yet
|
|
68
|
+
anchored by the code, and every requirement is paired with the criteria that
|
|
69
|
+
say when it is met. It is deliberately a scale-appropriate slice — one engineer
|
|
70
|
+
to a small team, not a defence contractor — but the core move is the same: the
|
|
71
|
+
target is written down first, and "done" is checked against it rather than
|
|
72
|
+
asserted by whoever (or whatever) wrote the code.
|
|
73
|
+
|
|
74
|
+
It is named after **Margaret Hamilton**, who ran software engineering for the
|
|
75
|
+
Apollo flight computer and coined the term "software engineering" to make the
|
|
76
|
+
point that it deserved to be taken as seriously as any other kind.
|
|
77
|
+
|
|
78
|
+
### The loop
|
|
79
|
+
|
|
80
|
+
1. **You specify.** In `spec/` you write the vision, the actors, and a tree of
|
|
81
|
+
requirements. Each requirement is one sentence and carries acceptance
|
|
82
|
+
criteria — observable conditions and their expected outcomes.
|
|
83
|
+
2. **The agent implements.** It writes the code and the tests. Each test
|
|
84
|
+
carries a one-line comment naming the single criterion it covers —
|
|
85
|
+
`@covers R-0001/AC1`.
|
|
86
|
+
3. **`hamilton check` verifies.** It runs your suite and stays red until every
|
|
87
|
+
criterion has a passing tagged test. Reword a criterion and it goes red
|
|
88
|
+
again until the test and code are reconciled with the new wording.
|
|
89
|
+
|
|
90
|
+
The acceptance criteria are yours. The rigorous tests that bind to them are the
|
|
91
|
+
agent's. `hamilton check` is what keeps the two honest.
|
|
92
|
+
|
|
93
|
+
## The two phases
|
|
94
|
+
|
|
95
|
+
Work happens in one of two phases, and the point of each is what it stops you
|
|
96
|
+
(or the agent) from doing.
|
|
97
|
+
|
|
98
|
+
**Spec phase** — you decide what the software should do. The agent can edit
|
|
99
|
+
`spec/` and nothing else. It cannot start writing code against a target you
|
|
100
|
+
have not finished setting.
|
|
101
|
+
|
|
102
|
+
**Build phase** — the agent writes the code and the tests. It cannot edit
|
|
103
|
+
`spec/`, `.claude/`, or `AGENTS.md`, and of `.hamilton/` only `config` — and
|
|
104
|
+
there only `test_command` / `test_paths`, because picking the test framework
|
|
105
|
+
and layout is a build-time call. It cannot quietly change a requirement to
|
|
106
|
+
match what it built, or rewrite its own rules.
|
|
107
|
+
|
|
108
|
+
You start a session in a phase with **`hamilton design`** (spec) or
|
|
109
|
+
**`hamilton build`** (build). Each writes the phase to `.hamilton/phase`,
|
|
110
|
+
prints a status banner, then runs your agent as a child process holding the
|
|
111
|
+
terminal, with a one-line kickoff so the session starts working straight away.
|
|
112
|
+
The phase is fixed for that whole session: it exports `HAMILTON_SESSION`, and
|
|
113
|
+
`design` / `build` refuse to run when that is already set, so an agent can't
|
|
114
|
+
relaunch itself into the other phase. A `PreToolUse` hook blocks edits to
|
|
115
|
+
read-only paths during the session as fast feedback.
|
|
116
|
+
|
|
117
|
+
None of this is unbypassable — unset the variable, edit the phase file by hand,
|
|
118
|
+
or run the agent directly and you are outside it. It stops drift, not a
|
|
119
|
+
determined operator. `hamilton check` run in CI, which ignores the phase
|
|
120
|
+
entirely, is the gate that enforces the outcome for real.
|
|
121
|
+
|
|
122
|
+
## Quick start
|
|
123
|
+
|
|
124
|
+
### 1. Check out the framework
|
|
125
|
+
|
|
126
|
+
Get this repository onto your machine (`git clone`, or you may already have it)
|
|
127
|
+
and `cd` into it. This checkout *is* the distribution — `hamilton-core` is not
|
|
128
|
+
published anywhere.
|
|
129
|
+
|
|
130
|
+
Requires Python 3.11+. There are no dependencies — standard library only.
|
|
131
|
+
|
|
132
|
+
Run its own test suite before you trust a checkout, especially one you have
|
|
133
|
+
been editing:
|
|
134
|
+
|
|
135
|
+
```
|
|
136
|
+
$ python -m pytest -q # expects 194 passing
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### 2. Link it into a separate test project
|
|
140
|
+
|
|
141
|
+
`hamilton-core` is not on PyPI (the name `hamilton` there belongs to an
|
|
142
|
+
unrelated project), so you install it from the checkout. To exercise it on a
|
|
143
|
+
real project, install it from your working copy into that project's virtualenv
|
|
144
|
+
— exactly what a published release would look like, just pointed at a local
|
|
145
|
+
path.
|
|
146
|
+
|
|
147
|
+
```
|
|
148
|
+
$ cd /path/to/your-test-project
|
|
149
|
+
$ python -m venv .venv
|
|
150
|
+
$ . .venv/bin/activate
|
|
151
|
+
|
|
152
|
+
# editable install: your edits to the framework take effect with no reinstall
|
|
153
|
+
$ pip install -e /path/to/hamilton
|
|
154
|
+
|
|
155
|
+
# — or — a fixed snapshot, exactly like installing a published release
|
|
156
|
+
$ pip install /path/to/hamilton
|
|
157
|
+
|
|
158
|
+
# the test project needs its own test runner in the same venv
|
|
159
|
+
$ pip install pytest
|
|
160
|
+
|
|
161
|
+
$ hamilton --help
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
`hamilton` is now on the venv's `PATH`. Keep the venv activated so that a
|
|
165
|
+
`test_command` of `python -m pytest -q` in `.hamilton/config` resolves to this
|
|
166
|
+
venv's pytest.
|
|
167
|
+
|
|
168
|
+
### 3. Scaffold the project
|
|
169
|
+
|
|
170
|
+
```
|
|
171
|
+
$ cd /path/to/your-test-project
|
|
172
|
+
$ git init -q
|
|
173
|
+
$ hamilton init
|
|
174
|
+
hamilton init: scaffolded /path/to/your-test-project
|
|
175
|
+
|
|
176
|
+
Run `hamilton design` to write the specification with an AI agent's help.
|
|
177
|
+
Prefer to write it by hand? Start from the files in spec/ -- each explains
|
|
178
|
+
what it should contain.
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
`init` writes `spec/` (`vision.md`, `actors.md`, `requirements.md` — each with
|
|
182
|
+
a fenced example to replace), `.hamilton/` (`phase`, `config`), `AGENTS.md`
|
|
183
|
+
with `CLAUDE.md` pointing at it, and `.claude/` (the phase-guard hook settings
|
|
184
|
+
and the `hamilton` skill). `AGENTS.md` and `.claude/` belong to the framework
|
|
185
|
+
and stay as written.
|
|
186
|
+
|
|
187
|
+
If your coding agent is not `claude`, set `agent_command` in `.hamilton/config`
|
|
188
|
+
before the next step.
|
|
189
|
+
|
|
190
|
+
### 4. Specify, build, check
|
|
191
|
+
|
|
192
|
+
```
|
|
193
|
+
$ hamilton design # spec phase: draft the vision and the requirements with the agent
|
|
194
|
+
$ hamilton build # build phase: the agent writes code + tagged tests, gets the gate green
|
|
195
|
+
$ hamilton check # the verification gate — run it yourself, and in CI
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
`hamilton check` exits `0` when every criterion has a passing tagged test and
|
|
199
|
+
nothing is stale; `1` on any finding; `2` if it cannot run at all. Wire the
|
|
200
|
+
same command into your pipeline — that CI run, outside the agent, is the real
|
|
201
|
+
gate.
|
|
202
|
+
|
|
203
|
+
### Following along without an agent
|
|
204
|
+
|
|
205
|
+
Every step `hamilton design` / `hamilton build` drive can be done by hand to
|
|
206
|
+
see the mechanism:
|
|
207
|
+
|
|
208
|
+
```
|
|
209
|
+
$ printf spec > .hamilton/phase # (what `hamilton design` does)
|
|
210
|
+
# ... edit spec/requirements.md and spec/actors.md ...
|
|
211
|
+
$ printf build > .hamilton/phase # (what `hamilton build` does)
|
|
212
|
+
# ... write the implementation and tests/ with @covers tags ...
|
|
213
|
+
$ hamilton check
|
|
214
|
+
hamilton check: running test_command: python -m pytest -q
|
|
215
|
+
2 passed in 0.01s
|
|
216
|
+
hamilton check: 1 requirement(s), 2 acceptance criteria
|
|
217
|
+
hamilton check: ok
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
A green run writes `.hamilton/verified` — the hash of each criterion's text at
|
|
221
|
+
that passing run. Commit it; that is what a later `stale` finding compares
|
|
222
|
+
against.
|
|
223
|
+
|
|
224
|
+
### Starting from an existing codebase
|
|
225
|
+
|
|
226
|
+
If the code already exists, run `hamilton reverse` instead of `hamilton design`
|
|
227
|
+
for the first spec session:
|
|
228
|
+
|
|
229
|
+
```
|
|
230
|
+
$ hamilton init
|
|
231
|
+
$ hamilton reverse # spec phase: the agent surveys the code and its git
|
|
232
|
+
# history, confirms with you what the system is and who
|
|
233
|
+
# its actors are, then derives the requirement tree
|
|
234
|
+
# module by module — you ratify each piece
|
|
235
|
+
$ hamilton check # red on `uncovered` — expected; the derived spec has
|
|
236
|
+
# no tests bound to it yet
|
|
237
|
+
$ hamilton build # the agent binds your existing tests to the derived
|
|
238
|
+
# criteria (and writes AC-level tests where the unit
|
|
239
|
+
# tests are too fine-grained), then gets the gate green
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
The derived spec is deliberately **thinner than the code** — it records intent
|
|
243
|
+
and the load-bearing decisions and leaves the rest to the implementing agent, so
|
|
244
|
+
`hamilton check` still runs against the same one-tree model as a greenfield
|
|
245
|
+
project. `hamilton reverse` refuses once `spec/requirements.md` has real
|
|
246
|
+
requirements; extend an existing spec with `hamilton design`.
|
|
247
|
+
|
|
248
|
+
## Commands
|
|
249
|
+
|
|
250
|
+
| Command | Phase | What it does |
|
|
251
|
+
|---|---|---|
|
|
252
|
+
| `hamilton init [path]` | — | Scaffold a project: `spec/`, `.hamilton/`, `AGENTS.md` / `CLAUDE.md`, `.claude/`. Refuses if `.hamilton/` already exists. |
|
|
253
|
+
| `hamilton design` | sets **spec** | Write the phase, print the status banner, launch the agent scoped to spec phase with a kickoff to draft the vision / requirements through the review protocol. |
|
|
254
|
+
| `hamilton build` | sets **build** | Write the phase, print the banner, launch the agent scoped to build phase with a kickoff to propagate the latest spec change and get `hamilton check` green. |
|
|
255
|
+
| `hamilton reverse` | sets **spec** | Brownfield: like `hamilton design`, but the kickoff has the agent derive a first spec from the existing code and its git history, module by module. Refuses if `spec/requirements.md` already has requirements. |
|
|
256
|
+
| `hamilton check [--json]` | ignores phase | The verification gate: run `test_command`, check every AC has a passing `@covers` test under `test_paths`, flag reworded criteria as `stale`, validate the requirement tree. Writes `.hamilton/verified` on a clean run. This is the gate — run it in CI. |
|
|
257
|
+
| `hamilton status` | read-only | Print the project snapshot the launcher shows as its banner: phase, requirement and coverage counts, and the last three `spec/` changes. |
|
|
258
|
+
| `hamilton tree [--json]` | read-only | Print the whole requirement tree with a dotted path computed at render time, an `i` / `!` marker for whether each interior node carries an `Interface:` yet, and a per-requirement coverage mark. |
|
|
259
|
+
| `hamilton show <ID> [--json]` | read-only | Print one entity in full and what refers to it. `R-nnnn`: path by title, statement, criteria with coverage status and the file holding each `@covers` tag, `Interface:` / `Actor:`, child requirements. `A-nnnn`: description and the requirements that name it. |
|
|
260
|
+
| `hamilton upgrade [path]` | — | Bring the framework-managed files up to date after installing a newer Hamilton — `AGENTS.md`, `CLAUDE.md`, the `.claude/` tree. Prints a diff, then overwrites. Never touches `spec/`, `.hamilton/phase`, `.hamilton/config`, `.hamilton/verified`. |
|
|
261
|
+
| `hamilton guard` | — | Internal: the `PreToolUse` hook backend that blocks read-only-path edits during a session. Not run by hand. |
|
|
262
|
+
|
|
263
|
+
`hamilton tree`, `hamilton show` and `hamilton status` write nothing and never
|
|
264
|
+
touch the gate. All three, plus `hamilton check`, take `--json` for tooling.
|
|
265
|
+
|
|
266
|
+
### When `hamilton check` fails
|
|
267
|
+
|
|
268
|
+
| Rule | What it means / what to do |
|
|
269
|
+
|---|---|
|
|
270
|
+
| `no-test-command` | `.hamilton/config` has no `test_command` (or a blank one). Set it — e.g. `test_command=python -m pytest -q`. |
|
|
271
|
+
| `tests-failed` | `test_command` ran and did not exit 0. Run it yourself to see why, and fix the code or the test. |
|
|
272
|
+
| `uncovered` | An acceptance criterion has no `@covers R-nnnn/ACn` tag in any file under `test_paths`. Add the tag to the test that checks that criterion. |
|
|
273
|
+
| `orphan-tag` | A `@covers` tag names a requirement or criterion that `spec/requirements.md` does not declare. Fix the tag, or add the criterion (in spec phase). |
|
|
274
|
+
| `orphan-requirement` | A requirement with no `Parent:` does not name an `Actor:`. Add the `Actor:`, or give it a `Parent:`. |
|
|
275
|
+
| `dangling-ref` | A `Parent:` or `Actor:` value names an entity that isn't declared. Fix the reference, or add the entity. |
|
|
276
|
+
| `cyclic-parent` | Following `Parent:` links from some requirement loops back on itself. Re-point one `Parent:`. |
|
|
277
|
+
| `stale` | A criterion was reworded since the last green check. Re-read it, confirm the tagged test still fits, and run `hamilton check` again — it clears once the run is otherwise clean. |
|
|
278
|
+
| `malformed` | A requirement is missing its `Statement`, has no criteria, repeats an id, or has a line that doesn't parse — or the file has no real requirements at all. The message names the line. |
|
|
279
|
+
|
|
280
|
+
It also prints **advisory warnings** — never fail the run, never change the
|
|
281
|
+
exit code: `long-statement` (a `Statement:` over 20 words — it is several
|
|
282
|
+
requirements welded together), `long-description` (an actor `Description:` over
|
|
283
|
+
one sentence), `no-interface` (an interior requirement with no `Interface:`
|
|
284
|
+
line yet). And a **notice** if `.hamilton/config` sets `mutation_command`: that
|
|
285
|
+
key is reserved for future mutation testing and is not implemented — unset it.
|
|
286
|
+
|
|
287
|
+
## The spec files
|
|
288
|
+
|
|
289
|
+
`hamilton init` writes three files under `spec/`. Each opens with a fenced
|
|
290
|
+
example that `hamilton check` ignores; you replace it with your own content
|
|
291
|
+
below the fence. `spec/` is writable in spec phase, read-only in build.
|
|
292
|
+
|
|
293
|
+
### `spec/vision.md`
|
|
294
|
+
|
|
295
|
+
Prose, not a model — `hamilton check` never reads it. Three sections:
|
|
296
|
+
**Purpose** (one or two sentences on what the software is for and for whom),
|
|
297
|
+
**Users** (who uses it and what they need), **Non-goals** (plausible features
|
|
298
|
+
that are deliberately out of scope, each with why). The non-goals are the
|
|
299
|
+
load-bearing part: they are what lets a reviewer, and a future agent, tell a
|
|
300
|
+
requested change from an unrequested feature. On a brand-new project
|
|
301
|
+
`hamilton design` offers to draft this with you first.
|
|
302
|
+
|
|
303
|
+
### `spec/actors.md`
|
|
304
|
+
|
|
305
|
+
A flat list of the external entities that interact with the system — they
|
|
306
|
+
define its boundary. One `## A-nnnn` block each, with a `Name:` and a
|
|
307
|
+
one-sentence `Description:`.
|
|
308
|
+
|
|
309
|
+
```markdown
|
|
310
|
+
## A-0001
|
|
311
|
+
Name: CLI user
|
|
312
|
+
Description: Runs the initials tool from the command line.
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
### `spec/requirements.md`
|
|
316
|
+
|
|
317
|
+
The whole model: one `Parent:` tree.
|
|
318
|
+
|
|
319
|
+
- A requirement with **no `Parent:`** is a **root** — a system-level goal — and
|
|
320
|
+
must name the `Actor:` whose goal it is. Ratify the root layer first;
|
|
321
|
+
specification is top-down.
|
|
322
|
+
- A requirement **with children** is a subsystem boundary and carries an
|
|
323
|
+
`Interface:` line — one sentence naming what crosses that boundary. The
|
|
324
|
+
interior of the tree *is* the architecture.
|
|
325
|
+
- A **leaf** needs neither: just a `Statement:` and criteria.
|
|
326
|
+
|
|
327
|
+
Every requirement is a `## R-nnnn Short title` block with a one-sentence
|
|
328
|
+
`Statement:` (under 20 words, one behaviour — detail belongs in the criteria)
|
|
329
|
+
and at least one `- ACn:` line, written as `<observable condition> -> <expected
|
|
330
|
+
outcome>` where that shape fits.
|
|
331
|
+
|
|
332
|
+
```markdown
|
|
333
|
+
## R-0001 Initials of a name
|
|
334
|
+
Actor: A-0001
|
|
335
|
+
Statement: initials(name) returns the capitalised first letter of each whitespace-separated word.
|
|
336
|
+
Criteria:
|
|
337
|
+
- AC1: "ada lovelace" -> "AL"
|
|
338
|
+
- AC2: runs of whitespace between words count as one separator
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
A test that covers one of its criteria:
|
|
342
|
+
|
|
343
|
+
```python
|
|
344
|
+
def test_two_words(): # @covers R-0001/AC1
|
|
345
|
+
assert initials("ada lovelace") == "AL"
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
A shared field rule — a format, an enum, a validation rule — goes once in a
|
|
349
|
+
`## Domain vocabulary` section at the top of the file and is referenced by name
|
|
350
|
+
from the criteria that need it, never restated inside a `Statement:`.
|
|
351
|
+
|
|
352
|
+
## What this does not do
|
|
353
|
+
|
|
354
|
+
It runs your tests and checks that each criterion has one — it does **not**
|
|
355
|
+
check that your tests are any good. A test that asserts nothing, or the wrong
|
|
356
|
+
thing, passes the gate as long as it runs. `hamilton check` proves your
|
|
357
|
+
criteria are written down, tied to tests, and passing; it does not prove those
|
|
358
|
+
tests would catch a regression.
|
|
359
|
+
|
|
360
|
+
Related limits, stated plainly:
|
|
361
|
+
|
|
362
|
+
- **`stale` clears by re-running.** It proves the suite was re-executed against
|
|
363
|
+
the reworded criterion, not that a person reconciled the test with it.
|
|
364
|
+
- **The phase hook is defeatable from a shell.** It covers file-editing tools
|
|
365
|
+
only, so it stops drift inside a cooperating session, not deliberate
|
|
366
|
+
circumvention. CI — `hamilton check` run outside the agent — is the real gate.
|
|
367
|
+
- **Only requirements and criteria can *fail* the gate.** `spec/actors.md` is
|
|
368
|
+
read for the view commands, for `dangling-ref` on an `Actor:` link, and for
|
|
369
|
+
`long-description` warnings, but nothing in it turns a build red by itself.
|
|
370
|
+
- **IDs are hand-written.** A repeated `R-nnnn` is caught by `hamilton check`
|
|
371
|
+
(`malformed`), not prevented as you type.
|
|
372
|
+
- **The Claude Code hook and skill are one supported agent, not the only one.**
|
|
373
|
+
The launcher works with any `agent_command`; the per-edit `PreToolUse` hook
|
|
374
|
+
ships for Claude Code only.
|
|
375
|
+
|
|
376
|
+
## Upgrading the scaffold
|
|
377
|
+
|
|
378
|
+
After installing a newer Hamilton, `hamilton upgrade` brings the
|
|
379
|
+
framework-managed files up to date — `AGENTS.md`, `CLAUDE.md` (a pointer at
|
|
380
|
+
it), and the `.claude/` tree (the phase-guard hook settings and the `hamilton`
|
|
381
|
+
skill). It never touches your own work: `spec/` (including `spec/vision.md`),
|
|
382
|
+
`.hamilton/phase`, `.hamilton/config`, `.hamilton/verified`.
|
|
383
|
+
|
|
384
|
+
```
|
|
385
|
+
$ hamilton upgrade
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
It prints a diff of everything it changes, then overwrites those files with the
|
|
389
|
+
current templates, recreates any you deleted, and deletes any it has since
|
|
390
|
+
retired. They belong to the framework, so it does not ask before replacing them
|
|
391
|
+
— keep local changes out of them.
|
|
392
|
+
|
|
393
|
+
**A project created before the launcher** has no `agent_command` line in
|
|
394
|
+
`.hamilton/config` (that file is yours, so `upgrade` won't add it). Add
|
|
395
|
+
`agent_command=claude` — or whatever starts your agent — by hand, or the first
|
|
396
|
+
`hamilton design` / `hamilton build` stops with "agent_command is not set".
|
|
397
|
+
|
|
398
|
+
## The rationale
|
|
399
|
+
|
|
400
|
+
The design rationale is in `docs/` — `concept.md` (the V-model / MBSE slice)
|
|
401
|
+
and `data-model.md` (the spec format in full). You do not need either to use
|
|
402
|
+
the tool.
|