@holdpoint/cli 0.1.0-alpha.16 → 0.1.0-alpha.17
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.
- package/dist/index.js +880 -390
- package/dist/index.js.map +1 -1
- package/dist/templates/HOLDPOINT_PREREQUISITES.md +1 -0
- package/dist/templates/HOLDPOINT_REFERENCE.md +341 -0
- package/dist/templates/MASTER_PROMPT.md +25 -295
- package/dist/templates/default.yaml +239 -0
- package/package.json +16 -17
- package/dist/builder-ui/assets/index-3J1uDBNl.css +0 -1
- package/dist/builder-ui/assets/index-DezgTDRo.js +0 -457
- package/dist/builder-ui/assets/index-DezgTDRo.js.map +0 -1
- package/dist/builder-ui/favicon.svg +0 -10
- package/dist/builder-ui/index.html +0 -14
- package/dist/templates/_base.yaml +0 -57
- package/dist/templates/fullstack.yaml +0 -93
- package/dist/templates/go.yaml +0 -60
- package/dist/templates/nextjs.yaml +0 -76
- package/dist/templates/python.yaml +0 -60
- package/dist/templates/typescript.yaml +0 -52
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
Holdpoint installed repo-local adapters for one or more AI coding agents. Before relying on them locally, review these setup notes:
|
|
4
4
|
|
|
5
5
|
- **GitHub Copilot CLI** — Holdpoint's `.github/extensions/holdpoint/extension.mjs` uses the Copilot CLI **EXTENSIONS** feature. Today that feature is gated behind experimental mode. In Copilot CLI, run `/experimental on` so **EXTENSIONS** appears in the enabled feature set before using Holdpoint locally.
|
|
6
|
+
- **Cursor** — project-level hooks run in trusted workspaces. After opening the repo in Cursor, confirm the workspace is trusted and review Settings → Hooks if hooks do not fire.
|
|
6
7
|
- **OpenAI Codex** — project-level hooks require trust approval. Run `codex trust` in the Codex TUI or review the hook with `/hooks`.
|
|
7
8
|
- **General** — Holdpoint expects Node.js 18+ and a git repository so `holdpoint init`, `holdpoint update`, and `holdpoint check` can run normally.
|
|
8
9
|
|
|
@@ -0,0 +1,341 @@
|
|
|
1
|
+
# Holdpoint — Eval Checkpoints
|
|
2
|
+
|
|
3
|
+
This project uses [Holdpoint](https://github.com/holdpoint-dev/holdpoint) to enforce
|
|
4
|
+
eval checkpoints. Before marking any task done, all checks must pass.
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## The Rule
|
|
9
|
+
|
|
10
|
+
Before marking **any** task complete:
|
|
11
|
+
|
|
12
|
+
1. Run `holdpoint check` — all tasks must exit 0.
|
|
13
|
+
2. `holdpoint check` also prints every **prompt** check whose `when` matches the
|
|
14
|
+
files you changed. Read and act on each listed instruction before finishing.
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## The Suggest Loop
|
|
19
|
+
|
|
20
|
+
`checks.yaml` is not static — it grows alongside the project automatically.
|
|
21
|
+
|
|
22
|
+
**`holdpoint-suggest` is a deterministic check** in `checks.yaml` that fires whenever you change a structural file (`package.json`, `pyproject.toml`, `go.mod`, `Dockerfile`, `tsconfig.json`, `vitest.config.*`, etc.). When it fires, `holdpoint suggest` runs and **exits 1 if `checks.yaml` is out of sync** — blocking task completion until you apply the proposals.
|
|
23
|
+
|
|
24
|
+
When blocked by `holdpoint-suggest`, run:
|
|
25
|
+
|
|
26
|
+
```
|
|
27
|
+
holdpoint suggest --apply # scan, apply proposals, regenerate engine files
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Then commit:
|
|
31
|
+
|
|
32
|
+
```
|
|
33
|
+
git add checks.yaml .github/holdpoint/generated/
|
|
34
|
+
git commit -m "chore: suggest holdpoint checks"
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
`holdpoint suggest --apply` is idempotent — safe to re-run at any time. It only adds checks for tools/patterns detected in the project and wraps stale checks (whose `when:` pattern no longer matches any file) with `conditionId: file_exists` so they auto-skip instead of failing.
|
|
38
|
+
|
|
39
|
+
**What triggers evolution:**
|
|
40
|
+
|
|
41
|
+
- New dependency in `package.json` / `pyproject.toml` / `go.mod` / `Cargo.toml`
|
|
42
|
+
- New `Dockerfile`, `docker-compose.yml`, `*.tf`, `openapi.yaml`
|
|
43
|
+
- New test runner config (`vitest.config.*`, `jest.config.*`, `playwright.config.*`)
|
|
44
|
+
- New CI workflow in `.github/workflows/`
|
|
45
|
+
- New TypeScript setup (`tsconfig.json`)
|
|
46
|
+
|
|
47
|
+
**What does NOT trigger it:** `.ts` / `.py` / `.go` source files, docs, styles, tests — minor work proceeds without interruption.
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## Git workflow best practices
|
|
52
|
+
|
|
53
|
+
Prefer the least-disruptive git workflow that still satisfies the task:
|
|
54
|
+
|
|
55
|
+
- Use a branch + PR when the user requests it, when work targets protected
|
|
56
|
+
`main`, or when remote CI/review is part of the task.
|
|
57
|
+
- For small local fixes, commit directly on the current branch and do not open a
|
|
58
|
+
PR unless the user asks.
|
|
59
|
+
- If already on a feature branch, keep committing there instead of creating
|
|
60
|
+
another branch.
|
|
61
|
+
- After committing, decide whether to push: push when a PR, remote review, CI
|
|
62
|
+
run, or handoff needs it; otherwise leave the commit local and report the
|
|
63
|
+
branch/commit.
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
## checks.yaml — Full Reference
|
|
68
|
+
|
|
69
|
+
`checks.yaml` at the project root is the single source of truth. Edit it to add,
|
|
70
|
+
remove, or change checkpoints.
|
|
71
|
+
|
|
72
|
+
After every edit, regenerate the engine files and commit everything together:
|
|
73
|
+
|
|
74
|
+
```
|
|
75
|
+
holdpoint update
|
|
76
|
+
git add checks.yaml .github/holdpoint/generated/ .github/hooks/
|
|
77
|
+
git commit -m "chore: update holdpoint checks"
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### Top-level structure
|
|
81
|
+
|
|
82
|
+
```yaml
|
|
83
|
+
version: 1
|
|
84
|
+
|
|
85
|
+
context:
|
|
86
|
+
guides: # project notes shown when `holdpoint check` runs
|
|
87
|
+
setup: >
|
|
88
|
+
Use pnpm, not npm. Node 20+ required.
|
|
89
|
+
|
|
90
|
+
session_context_files:
|
|
91
|
+
- MASTER_PROMPT.md # injected into Copilot/Codex sessions when supported
|
|
92
|
+
|
|
93
|
+
conditions: # gate checks on file/env state
|
|
94
|
+
- id: dist-built
|
|
95
|
+
operator: file_exists
|
|
96
|
+
path: dist/index.js
|
|
97
|
+
|
|
98
|
+
checks: # list of all checks — each has on/when + cmd (task) or prompt
|
|
99
|
+
- ...
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
---
|
|
103
|
+
|
|
104
|
+
### Deterministic check
|
|
105
|
+
|
|
106
|
+
```yaml
|
|
107
|
+
- id: lint # unique slug, kebab-case
|
|
108
|
+
label: "ESLint — all packages" # human-readable label shown in output
|
|
109
|
+
# on: before_done # lifecycle hook (default; only value today)
|
|
110
|
+
# when: frontend # file filter — omit to run on every task
|
|
111
|
+
cmd: "pnpm turbo lint" # shell command; must exit 0 to pass
|
|
112
|
+
conditionId: dist-built # optional: skip if condition is not met
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### Prompt check
|
|
116
|
+
|
|
117
|
+
```yaml
|
|
118
|
+
- id: migration-review
|
|
119
|
+
label: "Review DB migration"
|
|
120
|
+
when: "^prisma/migrations/" # only fires when migration files change
|
|
121
|
+
prompt: >
|
|
122
|
+
Open the new migration file. Confirm it is backward-compatible
|
|
123
|
+
and does not drop or truncate data without a fallback.
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
---
|
|
127
|
+
|
|
128
|
+
### `on` — lifecycle hooks
|
|
129
|
+
|
|
130
|
+
`on` specifies _when in the agent lifecycle_ a check fires. Omit it to use the default.
|
|
131
|
+
|
|
132
|
+
| Value | Fires |
|
|
133
|
+
| ------------- | ---------------------------------- |
|
|
134
|
+
| `before_done` | Before the agent marks a task done |
|
|
135
|
+
|
|
136
|
+
---
|
|
137
|
+
|
|
138
|
+
### `when` — file filters
|
|
139
|
+
|
|
140
|
+
`when` is an optional file filter. If omitted the check runs on every task.
|
|
141
|
+
|
|
142
|
+
| Value | Fires when changed files match |
|
|
143
|
+
| ----------- | -------------------------------------------------------------------------------------------------- |
|
|
144
|
+
| _(absent)_ | Every task — no file filter applied |
|
|
145
|
+
| `frontend` | `**/*.tsx`, `**/*.jsx`, `**/*.css`, `**/*.scss`, `**/tailwind.config.*`, `apps/**` |
|
|
146
|
+
| `backend` | `**/api/**`, `**/server/**`, `**/routes/**`, `**/controllers/**`, `packages/*/src/**` |
|
|
147
|
+
| `socket` | `**/socket/**`, `**/ws/**`, `**/websocket/**` |
|
|
148
|
+
| `visual` | `**/*.stories.{ts,tsx}`, `**/__screenshots__/**`, `**/*.snap` |
|
|
149
|
+
| `python` | `**/*.py`, `**/*.pyi`, `**/requirements*.txt`, `**/pyproject.toml`, `**/setup.py`, `**/pytest.ini` |
|
|
150
|
+
| `go` | `**/*.go`, `**/go.mod`, `**/go.sum` |
|
|
151
|
+
| `rust` | `**/*.rs`, `**/Cargo.toml`, `**/Cargo.lock` |
|
|
152
|
+
| `java` | `**/*.java`, `**/*.kt`, `**/*.gradle`, `**/*.gradle.kts`, `**/pom.xml` |
|
|
153
|
+
| `ruby` | `**/*.rb`, `**/Gemfile`, `**/Gemfile.lock`, `**/Rakefile` |
|
|
154
|
+
| `database` | `**/*.sql`, `**/migrations/**`, `**/db/**`, `**/database/**`, `**/prisma/**`, `**/*.prisma` |
|
|
155
|
+
| `prisma` | `**/prisma/**`, `**/*.prisma` — focused subset of `database` for Prisma-specific checks |
|
|
156
|
+
| `testing` | `**/*.test.*`, `**/*.spec.*`, `**/__tests__/**`, `**/test/**`, `**/tests/**`, `**/spec/**` |
|
|
157
|
+
| `infra` | `**/Dockerfile*`, `**/docker-compose.*`, `**/*.tf`, `**/*.tfvars`, `**/k8s/**`, `**/kubernetes/**` |
|
|
158
|
+
| `ci` | `**/.github/workflows/**`, `**/.circleci/**`, `**/Jenkinsfile`, `**/.gitlab-ci.yml` |
|
|
159
|
+
| `docs` | `**/*.mdx`, `**/*.rst`, `**/docs/**`, `**/documentation/**` |
|
|
160
|
+
| `"^src/.*"` | Any JavaScript regex tested against each changed file path |
|
|
161
|
+
|
|
162
|
+
Regex example — fires only when files under `src/api/` change:
|
|
163
|
+
|
|
164
|
+
```yaml
|
|
165
|
+
when: "^src/api/" # new RegExp(when).test(filePath)
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
> **Note:** Named scopes use glob matching; plain strings are treated as JavaScript regexes.
|
|
169
|
+
|
|
170
|
+
---
|
|
171
|
+
|
|
172
|
+
### Conditions
|
|
173
|
+
|
|
174
|
+
Conditions let you skip a check when a prerequisite is not yet met (e.g. a build
|
|
175
|
+
artefact doesn't exist yet).
|
|
176
|
+
|
|
177
|
+
| Operator | What it checks |
|
|
178
|
+
| ----------------- | ------------------------------------------------- |
|
|
179
|
+
| `file_exists` | A file or directory exists at `path` |
|
|
180
|
+
| `file_contains` | The file at `path` contains the substring `value` |
|
|
181
|
+
| `env_var_set` | The environment variable named `value` is set |
|
|
182
|
+
| `shell_returns_0` | The shell command in `cmd` exits with code 0 |
|
|
183
|
+
|
|
184
|
+
```yaml
|
|
185
|
+
conditions:
|
|
186
|
+
- id: packages-built
|
|
187
|
+
operator: file_exists
|
|
188
|
+
path: packages/yaml-core/dist/index.js
|
|
189
|
+
|
|
190
|
+
checks:
|
|
191
|
+
- id: validate-templates
|
|
192
|
+
label: "Templates parse against schema"
|
|
193
|
+
conditionId: packages-built # skipped (◌) when dist is absent
|
|
194
|
+
cmd: "node dist/validate.js templates/"
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
---
|
|
198
|
+
|
|
199
|
+
### Context guides
|
|
200
|
+
|
|
201
|
+
`context.guides` is a freeform key → multiline-string map. Guides are printed
|
|
202
|
+
at the start of `holdpoint check` output as project-level reminders to whoever
|
|
203
|
+
(or whatever) is running the checks.
|
|
204
|
+
|
|
205
|
+
```yaml
|
|
206
|
+
context:
|
|
207
|
+
guides:
|
|
208
|
+
setup: >
|
|
209
|
+
This project requires Node 20 and pnpm 9+.
|
|
210
|
+
Run `pnpm install` from the repo root before any other command.
|
|
211
|
+
architecture: >
|
|
212
|
+
API routes live in src/api/. Models live in src/models/.
|
|
213
|
+
Client code must never import from server modules.
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
---
|
|
217
|
+
|
|
218
|
+
## Adding a New Check
|
|
219
|
+
|
|
220
|
+
1. Open `checks.yaml`.
|
|
221
|
+
2. Add your entry under `checks:`.
|
|
222
|
+
3. Run `holdpoint update`.
|
|
223
|
+
4. Commit `checks.yaml` and the generated files.
|
|
224
|
+
|
|
225
|
+
**Add a task check (runs a shell command automatically):**
|
|
226
|
+
|
|
227
|
+
```yaml
|
|
228
|
+
checks:
|
|
229
|
+
- id: vitest
|
|
230
|
+
label: "Vitest — unit tests"
|
|
231
|
+
cmd: "pnpm vitest run"
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
**Add a scoped task (fires only on matching file changes):**
|
|
235
|
+
|
|
236
|
+
```yaml
|
|
237
|
+
checks:
|
|
238
|
+
- id: openapi-sync
|
|
239
|
+
label: "OpenAPI types are up to date"
|
|
240
|
+
when: "^src/api/"
|
|
241
|
+
cmd: "pnpm generate:types && git diff --exit-code src/generated/"
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
**Add an agent prompt checkpoint:**
|
|
245
|
+
|
|
246
|
+
```yaml
|
|
247
|
+
checks:
|
|
248
|
+
- id: jsdoc
|
|
249
|
+
label: "JSDoc on changed public functions"
|
|
250
|
+
prompt: >
|
|
251
|
+
For every public function or export you modified, ensure there is an
|
|
252
|
+
accurate JSDoc comment: description, @param, and @returns.
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
**Enforce changelog and git commit on every task (recommended):**
|
|
256
|
+
|
|
257
|
+
```yaml
|
|
258
|
+
checks:
|
|
259
|
+
- id: changelog-update
|
|
260
|
+
label: "Add a CHANGELOG.md entry for this session"
|
|
261
|
+
prompt: >
|
|
262
|
+
Before committing, add an entry to CHANGELOG.md describing what was done.
|
|
263
|
+
Use Keep a Changelog format — add under ## [Unreleased] (create the file
|
|
264
|
+
and that section if absent). Group entries as Added, Changed, Fixed, or Removed.
|
|
265
|
+
Be concise but specific. The entry text will serve as the commit message.
|
|
266
|
+
|
|
267
|
+
- id: readme-sync
|
|
268
|
+
label: "Update README.md if user-facing changes were made"
|
|
269
|
+
prompt: >
|
|
270
|
+
If you added, changed, or removed user-facing functionality — CLI commands,
|
|
271
|
+
configuration options, public APIs, or significant new features — update
|
|
272
|
+
README.md to reflect those changes.
|
|
273
|
+
|
|
274
|
+
- id: git-workflow
|
|
275
|
+
label: "Use the right git workflow"
|
|
276
|
+
prompt: >
|
|
277
|
+
Choose the least-disruptive git workflow: use branch + PR for requested
|
|
278
|
+
feature branches or protected-main work; for small local fixes, commit on
|
|
279
|
+
the current branch without opening a PR unless asked; if already on a
|
|
280
|
+
feature branch, keep committing there instead of creating another branch.
|
|
281
|
+
Push only when a PR, remote review, CI run, or handoff needs it; otherwise
|
|
282
|
+
leave the commit local and report the branch/commit.
|
|
283
|
+
|
|
284
|
+
- id: git-commit
|
|
285
|
+
label: "Commit all changes before finishing"
|
|
286
|
+
cmd: 'git rev-parse --is-inside-work-tree >/dev/null 2>&1 || exit 0; [ -z "$(git status --porcelain)" ] && exit 0; git status --short; exit 1'
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
When the `git-commit` check fails (uncommitted changes remain), the agent will also see
|
|
290
|
+
the `changelog-update` and `readme-sync` prompt reminders inline — ensuring it updates
|
|
291
|
+
the changelog, syncs docs, _then_ commits before it can mark the task done.
|
|
292
|
+
|
|
293
|
+
---
|
|
294
|
+
|
|
295
|
+
## `session_context_files`
|
|
296
|
+
|
|
297
|
+
`session_context_files` is an optional list of project files that Holdpoint injects
|
|
298
|
+
as context at the start of every Copilot session. Use it for files the agent should
|
|
299
|
+
always read before starting work.
|
|
300
|
+
|
|
301
|
+
```yaml
|
|
302
|
+
session_context_files:
|
|
303
|
+
- MASTER_PROMPT.md
|
|
304
|
+
- AGENT_CONTEXT.md
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
Files are resolved relative to the repo root and must stay inside it (traversal
|
|
308
|
+
paths like `../../etc/passwd` are rejected). If a file doesn't exist it is silently
|
|
309
|
+
skipped.
|
|
310
|
+
|
|
311
|
+
---
|
|
312
|
+
|
|
313
|
+
## Commands
|
|
314
|
+
|
|
315
|
+
| Command | What it does |
|
|
316
|
+
| ----------------------------- | ------------------------------------------------------- |
|
|
317
|
+
| `holdpoint check` | Run checks against all files changed vs HEAD |
|
|
318
|
+
| `holdpoint check --staged` | Run checks against staged files only |
|
|
319
|
+
| `holdpoint suggest` | Scan project and show proposed additions to checks.yaml |
|
|
320
|
+
| `holdpoint suggest --apply` | Apply proposals and regenerate engine files |
|
|
321
|
+
| `holdpoint require-changeset` | Require `.changeset/*.md` for package changes |
|
|
322
|
+
| `holdpoint update` | Regenerate engine files from the current `checks.yaml` |
|
|
323
|
+
| `holdpoint validate` | Validate `checks.yaml` schema (no commands run) |
|
|
324
|
+
| `holdpoint builder` | Open the daemon-served visual builder UI |
|
|
325
|
+
|
|
326
|
+
---
|
|
327
|
+
|
|
328
|
+
## Generated files (do not edit directly)
|
|
329
|
+
|
|
330
|
+
| File | Agent |
|
|
331
|
+
| --------------------------------------------------- | ------- |
|
|
332
|
+
| `.github/holdpoint/generated/checks.immutable.json` | all |
|
|
333
|
+
| `.github/hooks/holdpoint.json` | Copilot |
|
|
334
|
+
| `.github/hooks/holdpoint-check.mjs` | Copilot |
|
|
335
|
+
| `.claude/settings.json` | Claude |
|
|
336
|
+
| `.cursor/hooks.json` | Cursor |
|
|
337
|
+
| `.cursor/holdpoint-hook.mjs` | Cursor |
|
|
338
|
+
| `.cursorrules` (Holdpoint section) | Cursor |
|
|
339
|
+
|
|
340
|
+
All generated files are overwritten by `holdpoint update`. Edit `checks.yaml`,
|
|
341
|
+
then run `update` — never edit the generated files directly.
|
|
@@ -1,309 +1,39 @@
|
|
|
1
1
|
# Holdpoint — Eval Checkpoints
|
|
2
2
|
|
|
3
|
-
This
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
---
|
|
3
|
+
This repo uses [Holdpoint](https://holdpoint.dev) to enforce eval
|
|
4
|
+
checkpoints. Before marking any task done, all checks must pass.
|
|
7
5
|
|
|
8
6
|
## The Rule
|
|
9
7
|
|
|
10
8
|
Before marking **any** task complete:
|
|
11
9
|
|
|
12
|
-
1. Run `holdpoint check` — all
|
|
13
|
-
2. `holdpoint check` also prints every **prompt** check whose `when`
|
|
14
|
-
files you changed. Read and act on each listed
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
`checks.yaml` is not static — it grows alongside the project automatically.
|
|
21
|
-
|
|
22
|
-
**`holdpoint-evolve` is a deterministic check** in `checks.yaml` that fires whenever you change a structural file (`package.json`, `pyproject.toml`, `go.mod`, `Dockerfile`, `tsconfig.json`, `vitest.config.*`, etc.). When it fires, `holdpoint evolve` runs and **exits 1 if `checks.yaml` is out of sync** — blocking task completion until you apply the proposals.
|
|
23
|
-
|
|
24
|
-
When blocked by `holdpoint-evolve`, run:
|
|
25
|
-
|
|
26
|
-
```
|
|
27
|
-
holdpoint evolve --apply # scan, apply proposals, regenerate engine files
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
Then commit:
|
|
31
|
-
|
|
32
|
-
```
|
|
33
|
-
git add checks.yaml .github/holdpoint/generated/
|
|
34
|
-
git commit -m "chore: evolve holdpoint checks"
|
|
35
|
-
```
|
|
36
|
-
|
|
37
|
-
`holdpoint evolve --apply` is idempotent — safe to re-run at any time. It only adds checks for tools/patterns detected in the project and wraps stale checks (whose `when:` pattern no longer matches any file) with `conditionId: file_exists` so they auto-skip instead of failing.
|
|
38
|
-
|
|
39
|
-
**What triggers evolution:**
|
|
40
|
-
|
|
41
|
-
- New dependency in `package.json` / `pyproject.toml` / `go.mod` / `Cargo.toml`
|
|
42
|
-
- New `Dockerfile`, `docker-compose.yml`, `*.tf`, `openapi.yaml`
|
|
43
|
-
- New test runner config (`vitest.config.*`, `jest.config.*`, `playwright.config.*`)
|
|
44
|
-
- New CI workflow in `.github/workflows/`
|
|
45
|
-
- New TypeScript setup (`tsconfig.json`)
|
|
46
|
-
|
|
47
|
-
**What does NOT trigger it:** `.ts` / `.py` / `.go` source files, docs, styles, tests — minor work proceeds without interruption.
|
|
48
|
-
|
|
49
|
-
---
|
|
50
|
-
|
|
51
|
-
## checks.yaml — Full Reference
|
|
52
|
-
|
|
53
|
-
`checks.yaml` at the project root is the single source of truth. Edit it to add,
|
|
54
|
-
remove, or change checkpoints.
|
|
55
|
-
|
|
56
|
-
After every edit, regenerate the engine files and commit everything together:
|
|
57
|
-
|
|
58
|
-
```
|
|
59
|
-
holdpoint update
|
|
60
|
-
git add checks.yaml .github/holdpoint/generated/ .github/hooks/
|
|
61
|
-
git commit -m "chore: update holdpoint checks"
|
|
62
|
-
```
|
|
63
|
-
|
|
64
|
-
### Top-level structure
|
|
65
|
-
|
|
66
|
-
```yaml
|
|
67
|
-
version: 1
|
|
68
|
-
|
|
69
|
-
context:
|
|
70
|
-
guides: # project notes shown when `holdpoint check` runs
|
|
71
|
-
setup: >
|
|
72
|
-
Use pnpm, not npm. Node 20+ required.
|
|
73
|
-
|
|
74
|
-
conditions: # gate checks on file/env state
|
|
75
|
-
- id: dist-built
|
|
76
|
-
operator: file_exists
|
|
77
|
-
path: dist/index.js
|
|
78
|
-
|
|
79
|
-
checks: # list of all checks — each has on/when + cmd (task) or prompt
|
|
80
|
-
- ...
|
|
81
|
-
```
|
|
82
|
-
|
|
83
|
-
---
|
|
84
|
-
|
|
85
|
-
### Deterministic check
|
|
86
|
-
|
|
87
|
-
```yaml
|
|
88
|
-
- id: lint # unique slug, kebab-case
|
|
89
|
-
label: "ESLint — all packages" # human-readable label shown in output
|
|
90
|
-
# on: before_done # lifecycle hook (default; only value today)
|
|
91
|
-
# when: frontend # file filter — omit to run on every task
|
|
92
|
-
cmd: "pnpm turbo lint" # shell command; must exit 0 to pass
|
|
93
|
-
conditionId: dist-built # optional: skip if condition is not met
|
|
94
|
-
```
|
|
95
|
-
|
|
96
|
-
### Prompt check
|
|
97
|
-
|
|
98
|
-
```yaml
|
|
99
|
-
- id: migration-review
|
|
100
|
-
label: "Review DB migration"
|
|
101
|
-
when: "^prisma/migrations/" # only fires when migration files change
|
|
102
|
-
prompt: >
|
|
103
|
-
Open the new migration file. Confirm it is backward-compatible
|
|
104
|
-
and does not drop or truncate data without a fallback.
|
|
105
|
-
```
|
|
106
|
-
|
|
107
|
-
---
|
|
108
|
-
|
|
109
|
-
### `on` — lifecycle hooks
|
|
110
|
-
|
|
111
|
-
`on` specifies _when in the agent lifecycle_ a check fires. Omit it to use the default.
|
|
112
|
-
|
|
113
|
-
| Value | Fires |
|
|
114
|
-
| ------------- | ---------------------------------- |
|
|
115
|
-
| `before_done` | Before the agent marks a task done |
|
|
116
|
-
|
|
117
|
-
---
|
|
118
|
-
|
|
119
|
-
### `when` — file filters
|
|
120
|
-
|
|
121
|
-
`when` is an optional file filter. If omitted the check runs on every task.
|
|
122
|
-
|
|
123
|
-
| Value | Fires when changed files match |
|
|
124
|
-
| ----------- | -------------------------------------------------------------------------------------------------- |
|
|
125
|
-
| _(absent)_ | Every task — no file filter applied |
|
|
126
|
-
| `frontend` | `**/*.tsx`, `**/*.jsx`, `**/*.css`, `**/*.scss`, `**/tailwind.config.*`, `apps/**` |
|
|
127
|
-
| `backend` | `**/api/**`, `**/server/**`, `**/routes/**`, `**/controllers/**`, `packages/*/src/**` |
|
|
128
|
-
| `socket` | `**/socket/**`, `**/ws/**`, `**/websocket/**` |
|
|
129
|
-
| `visual` | `**/*.stories.{ts,tsx}`, `**/__screenshots__/**`, `**/*.snap` |
|
|
130
|
-
| `python` | `**/*.py`, `**/*.pyi`, `**/requirements*.txt`, `**/pyproject.toml`, `**/setup.py`, `**/pytest.ini` |
|
|
131
|
-
| `go` | `**/*.go`, `**/go.mod`, `**/go.sum` |
|
|
132
|
-
| `rust` | `**/*.rs`, `**/Cargo.toml`, `**/Cargo.lock` |
|
|
133
|
-
| `java` | `**/*.java`, `**/*.kt`, `**/*.gradle`, `**/*.gradle.kts`, `**/pom.xml` |
|
|
134
|
-
| `ruby` | `**/*.rb`, `**/Gemfile`, `**/Gemfile.lock`, `**/Rakefile` |
|
|
135
|
-
| `database` | `**/*.sql`, `**/migrations/**`, `**/db/**`, `**/database/**`, `**/prisma/**`, `**/*.prisma` |
|
|
136
|
-
| `prisma` | `**/prisma/**`, `**/*.prisma` — focused subset of `database` for Prisma-specific checks |
|
|
137
|
-
| `testing` | `**/*.test.*`, `**/*.spec.*`, `**/__tests__/**`, `**/test/**`, `**/tests/**`, `**/spec/**` |
|
|
138
|
-
| `infra` | `**/Dockerfile*`, `**/docker-compose.*`, `**/*.tf`, `**/*.tfvars`, `**/k8s/**`, `**/kubernetes/**` |
|
|
139
|
-
| `ci` | `**/.github/workflows/**`, `**/.circleci/**`, `**/Jenkinsfile`, `**/.gitlab-ci.yml` |
|
|
140
|
-
| `docs` | `**/*.mdx`, `**/*.rst`, `**/docs/**`, `**/documentation/**` |
|
|
141
|
-
| `"^src/.*"` | Any JavaScript regex tested against each changed file path |
|
|
142
|
-
|
|
143
|
-
Regex example — fires only when files under `src/api/` change:
|
|
144
|
-
|
|
145
|
-
```yaml
|
|
146
|
-
when: "^src/api/" # new RegExp(when).test(filePath)
|
|
147
|
-
```
|
|
148
|
-
|
|
149
|
-
> **Note:** Named scopes use glob matching; plain strings are treated as JavaScript regexes.
|
|
150
|
-
|
|
151
|
-
---
|
|
152
|
-
|
|
153
|
-
### Conditions
|
|
154
|
-
|
|
155
|
-
Conditions let you skip a check when a prerequisite is not yet met (e.g. a build
|
|
156
|
-
artefact doesn't exist yet).
|
|
157
|
-
|
|
158
|
-
| Operator | What it checks |
|
|
159
|
-
| ----------------- | ------------------------------------------------- |
|
|
160
|
-
| `file_exists` | A file or directory exists at `path` |
|
|
161
|
-
| `file_contains` | The file at `path` contains the substring `value` |
|
|
162
|
-
| `env_var_set` | The environment variable named `value` is set |
|
|
163
|
-
| `shell_returns_0` | The shell command in `cmd` exits with code 0 |
|
|
164
|
-
|
|
165
|
-
```yaml
|
|
166
|
-
conditions:
|
|
167
|
-
- id: packages-built
|
|
168
|
-
operator: file_exists
|
|
169
|
-
path: packages/yaml-core/dist/index.js
|
|
170
|
-
|
|
171
|
-
checks:
|
|
172
|
-
- id: validate-templates
|
|
173
|
-
label: "Templates parse against schema"
|
|
174
|
-
conditionId: packages-built # skipped (◌) when dist is absent
|
|
175
|
-
cmd: "node dist/validate.js templates/"
|
|
176
|
-
```
|
|
177
|
-
|
|
178
|
-
---
|
|
179
|
-
|
|
180
|
-
### Context guides
|
|
181
|
-
|
|
182
|
-
`context.guides` is a freeform key → multiline-string map. Guides are printed
|
|
183
|
-
at the start of `holdpoint check` output as project-level reminders to whoever
|
|
184
|
-
(or whatever) is running the checks.
|
|
185
|
-
|
|
186
|
-
```yaml
|
|
187
|
-
context:
|
|
188
|
-
guides:
|
|
189
|
-
setup: >
|
|
190
|
-
This project requires Node 20 and pnpm 9+.
|
|
191
|
-
Run `pnpm install` from the repo root before any other command.
|
|
192
|
-
architecture: >
|
|
193
|
-
API routes live in src/api/. Models live in src/models/.
|
|
194
|
-
Client code must never import from server modules.
|
|
195
|
-
```
|
|
196
|
-
|
|
197
|
-
---
|
|
198
|
-
|
|
199
|
-
## Adding a New Check
|
|
200
|
-
|
|
201
|
-
1. Open `checks.yaml`.
|
|
202
|
-
2. Add your entry under `checks:`.
|
|
203
|
-
3. Run `holdpoint update`.
|
|
204
|
-
4. Commit `checks.yaml` and the generated files.
|
|
205
|
-
|
|
206
|
-
**Add a task check (runs a shell command automatically):**
|
|
207
|
-
|
|
208
|
-
```yaml
|
|
209
|
-
checks:
|
|
210
|
-
- id: vitest
|
|
211
|
-
label: "Vitest — unit tests"
|
|
212
|
-
cmd: "pnpm vitest run"
|
|
213
|
-
```
|
|
214
|
-
|
|
215
|
-
**Add a scoped task (fires only on matching file changes):**
|
|
216
|
-
|
|
217
|
-
```yaml
|
|
218
|
-
checks:
|
|
219
|
-
- id: openapi-sync
|
|
220
|
-
label: "OpenAPI types are up to date"
|
|
221
|
-
when: "^src/api/"
|
|
222
|
-
cmd: "pnpm generate:types && git diff --exit-code src/generated/"
|
|
223
|
-
```
|
|
224
|
-
|
|
225
|
-
**Add an agent prompt checkpoint:**
|
|
226
|
-
|
|
227
|
-
```yaml
|
|
228
|
-
checks:
|
|
229
|
-
- id: jsdoc
|
|
230
|
-
label: "JSDoc on changed public functions"
|
|
231
|
-
prompt: >
|
|
232
|
-
For every public function or export you modified, ensure there is an
|
|
233
|
-
accurate JSDoc comment: description, @param, and @returns.
|
|
234
|
-
```
|
|
235
|
-
|
|
236
|
-
**Enforce changelog and git commit on every task (recommended):**
|
|
237
|
-
|
|
238
|
-
```yaml
|
|
239
|
-
checks:
|
|
240
|
-
- id: changelog-update
|
|
241
|
-
label: "Add a CHANGELOG.md entry for this session"
|
|
242
|
-
prompt: >
|
|
243
|
-
Before committing, add an entry to CHANGELOG.md describing what was done.
|
|
244
|
-
Use Keep a Changelog format — add under ## [Unreleased] (create the file
|
|
245
|
-
and that section if absent). Group entries as Added, Changed, Fixed, or Removed.
|
|
246
|
-
Be concise but specific. The entry text will serve as the commit message.
|
|
247
|
-
|
|
248
|
-
- id: readme-sync
|
|
249
|
-
label: "Update README.md if user-facing changes were made"
|
|
250
|
-
prompt: >
|
|
251
|
-
If you added, changed, or removed user-facing functionality — CLI commands,
|
|
252
|
-
configuration options, public APIs, or significant new features — update
|
|
253
|
-
README.md to reflect those changes.
|
|
254
|
-
|
|
255
|
-
- id: git-commit
|
|
256
|
-
label: "Commit all changes before finishing"
|
|
257
|
-
cmd: 'git rev-parse --is-inside-work-tree >/dev/null 2>&1 || exit 0; [ -z "$(git status --porcelain)" ] && exit 0; git status --short; exit 1'
|
|
258
|
-
```
|
|
259
|
-
|
|
260
|
-
When the `git-commit` check fails (uncommitted changes remain), the agent will also see
|
|
261
|
-
the `changelog-update` and `readme-sync` prompt reminders inline — ensuring it updates
|
|
262
|
-
the changelog, syncs docs, _then_ commits before it can mark the task done.
|
|
263
|
-
|
|
264
|
-
---
|
|
265
|
-
|
|
266
|
-
## `session_context_files`
|
|
267
|
-
|
|
268
|
-
`session_context_files` is an optional list of project files that Holdpoint injects
|
|
269
|
-
as context at the start of every Copilot session. Use it for files the agent should
|
|
270
|
-
always read before starting work.
|
|
271
|
-
|
|
272
|
-
```yaml
|
|
273
|
-
session_context_files:
|
|
274
|
-
- MASTER_PROMPT.md
|
|
275
|
-
- AGENT_CONTEXT.md
|
|
276
|
-
```
|
|
277
|
-
|
|
278
|
-
Files are resolved relative to the repo root and must stay inside it (traversal
|
|
279
|
-
paths like `../../etc/passwd` are rejected). If a file doesn't exist it is silently
|
|
280
|
-
skipped.
|
|
10
|
+
1. Run `holdpoint check` — all checks must exit 0.
|
|
11
|
+
2. `holdpoint check` also prints every **prompt** check whose `when`
|
|
12
|
+
matches the files you changed. Read and act on each listed
|
|
13
|
+
instruction before finishing.
|
|
14
|
+
3. Never bypass via `git commit --no-verify` or by skipping a stop
|
|
15
|
+
hook. If a check is wrong, fix the check in `checks.yaml`, don't
|
|
16
|
+
route around it.
|
|
281
17
|
|
|
282
|
-
|
|
18
|
+
## The Suggest Loop
|
|
283
19
|
|
|
284
|
-
|
|
20
|
+
`checks.yaml` grows with the project. `holdpoint-suggest` is a check
|
|
21
|
+
that fires whenever structural files change (`package.json`,
|
|
22
|
+
`pyproject.toml`, `go.mod`, `Dockerfile`, `tsconfig.json`,
|
|
23
|
+
`vitest.config.*`, etc.). When it fires, `holdpoint suggest` runs and
|
|
24
|
+
**exits 1 if `checks.yaml` is out of sync** — blocking task completion
|
|
25
|
+
until you apply the proposals.
|
|
285
26
|
|
|
286
|
-
|
|
287
|
-
| -------------------------- | ------------------------------------------------------- |
|
|
288
|
-
| `holdpoint check` | Run checks against all files changed vs HEAD |
|
|
289
|
-
| `holdpoint check --staged` | Run checks against staged files only |
|
|
290
|
-
| `holdpoint evolve` | Scan project and show proposed additions to checks.yaml |
|
|
291
|
-
| `holdpoint evolve --apply` | Apply proposals and regenerate engine files |
|
|
292
|
-
| `holdpoint update` | Regenerate engine files from the current `checks.yaml` |
|
|
293
|
-
| `holdpoint validate` | Validate `checks.yaml` schema (no commands run) |
|
|
294
|
-
| `holdpoint builder` | Open the visual builder UI at localhost:4321 |
|
|
27
|
+
When blocked, run:
|
|
295
28
|
|
|
296
|
-
|
|
29
|
+
holdpoint suggest --apply
|
|
297
30
|
|
|
298
|
-
|
|
31
|
+
then commit the changes and continue.
|
|
299
32
|
|
|
300
|
-
|
|
301
|
-
| --------------------------------------------------- | ------- |
|
|
302
|
-
| `.github/holdpoint/generated/checks.immutable.json` | all |
|
|
303
|
-
| `.github/hooks/holdpoint.json` | Copilot |
|
|
304
|
-
| `.github/hooks/holdpoint-check.mjs` | Copilot |
|
|
305
|
-
| `.claude/settings.json` | Claude |
|
|
306
|
-
| `.cursorrules` (Holdpoint section) | Cursor |
|
|
33
|
+
## Going deeper
|
|
307
34
|
|
|
308
|
-
|
|
309
|
-
|
|
35
|
+
For the full reference — every built-in check, every `when:` scope,
|
|
36
|
+
per-engine details, troubleshooting — read
|
|
37
|
+
[`HOLDPOINT_REFERENCE.md`](./HOLDPOINT_REFERENCE.md). The file is on
|
|
38
|
+
disk; you can `cat` it when you need detail. It is intentionally not
|
|
39
|
+
auto-injected because it's reference, not directive.
|