infinity-harness 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. package/CHANGELOG.md +114 -0
  2. package/LICENSE +21 -0
  3. package/README.md +266 -0
  4. package/extensions/infinity-harness/index.ts +870 -0
  5. package/harness/docs/ARCHITECTURE.md +159 -0
  6. package/harness/docs/CONSTRAINTS.md +19 -0
  7. package/harness/docs/DECISIONS.md +107 -0
  8. package/harness/docs/DOMAIN.md +13 -0
  9. package/harness/docs/agents/evaluator.md +14 -0
  10. package/harness/docs/agents/generator.md +13 -0
  11. package/harness/docs/agents/planner.md +13 -0
  12. package/harness/docs/agents/simplifier.md +13 -0
  13. package/harness/docs/api-patterns.md +23 -0
  14. package/harness/docs/phases/build.md +47 -0
  15. package/harness/docs/phases/define.md +58 -0
  16. package/harness/docs/phases/plan.md +50 -0
  17. package/harness/docs/phases/review.md +47 -0
  18. package/harness/docs/phases/ship.md +43 -0
  19. package/harness/docs/phases/simplify.md +45 -0
  20. package/harness/docs/phases/verify.md +46 -0
  21. package/harness/model-router.json +28 -0
  22. package/harness/skills/README.md +60 -0
  23. package/harness/skills/auth-security.md +56 -0
  24. package/harness/skills/building-mcp-servers.md +70 -0
  25. package/harness/skills/building-tools.md +60 -0
  26. package/harness/skills/capability-acquisition.md +72 -0
  27. package/harness/skills/cli-design.md +55 -0
  28. package/harness/skills/code-review.md +57 -0
  29. package/harness/skills/codebase-design.md +70 -0
  30. package/harness/skills/concurrency-async.md +61 -0
  31. package/harness/skills/config-and-secrets.md +52 -0
  32. package/harness/skills/context-hygiene.md +51 -0
  33. package/harness/skills/databases.md +63 -0
  34. package/harness/skills/diagnosing-bugs.md +84 -0
  35. package/harness/skills/domain-modeling.md +65 -0
  36. package/harness/skills/error-handling-logging.md +56 -0
  37. package/harness/skills/frontend-ui.md +56 -0
  38. package/harness/skills/grilling.md +48 -0
  39. package/harness/skills/http-apis.md +60 -0
  40. package/harness/skills/performance.md +53 -0
  41. package/harness/skills/pi-todo-adapted.md +41 -0
  42. package/harness/skills/planning-tasks.md +86 -0
  43. package/harness/skills/prototype.md +39 -0
  44. package/harness/skills/research.md +32 -0
  45. package/harness/skills/resolving-merge-conflicts.md +30 -0
  46. package/harness/skills/scope-discipline.md +49 -0
  47. package/harness/skills/self-review.md +45 -0
  48. package/harness/skills/stuck-protocol.md +51 -0
  49. package/harness/skills/tdd.md +80 -0
  50. package/harness/skills/testing-infra.md +57 -0
  51. package/harness/skills/writing-skills.md +60 -0
  52. package/package.json +61 -0
  53. package/src/core/brief.ts +242 -0
  54. package/src/core/config.ts +265 -0
  55. package/src/core/exec.ts +130 -0
  56. package/src/core/featureList.ts +286 -0
  57. package/src/core/fsx.ts +119 -0
  58. package/src/core/gates.ts +444 -0
  59. package/src/core/lock.ts +192 -0
  60. package/src/core/paths.ts +95 -0
  61. package/src/core/phases.ts +143 -0
  62. package/src/core/settings.ts +445 -0
  63. package/src/core/types.ts +245 -0
  64. package/src/goalLoop.ts +628 -0
  65. package/src/goalSpec.ts +679 -0
  66. package/src/goalState.ts +338 -0
  67. package/src/loop.ts +355 -0
  68. package/src/modelRouter.ts +184 -0
  69. package/src/remote.ts +244 -0
  70. package/src/replan.ts +300 -0
  71. package/src/review.ts +53 -0
  72. package/src/rework.ts +274 -0
  73. package/src/taskList.ts +355 -0
  74. package/src/ui/config.ts +286 -0
  75. package/src/ui/dashboard.ts +1066 -0
  76. package/src/ui/theme.ts +317 -0
  77. package/src/ui/widget.ts +370 -0
  78. package/src/unstuck.ts +214 -0
  79. package/src/worker.ts +351 -0
  80. package/types/proper-lockfile.d.ts +19 -0
@@ -0,0 +1,61 @@
1
+ ---
2
+ name: concurrency-async
3
+ description: Concurrency and async correctness — races, idempotency, queues, cancellation, locking
4
+ tags: [concurrency, async, race, parallel, queue, lock, mutex, retry, idempotent, worker, thread, promise, deadlock, atomic]
5
+ when: task involves parallel work, background jobs, shared state, or retried operations
6
+ phases: [plan, build, verify]
7
+ provenance: { origin: built-in }
8
+ ---
9
+
10
+ # Concurrency & Async
11
+
12
+ ## Rules
13
+
14
+ - **Name the shared state.** Before writing concurrent code, list what is
15
+ read/written by more than one flow. No list = you haven't designed yet.
16
+ Prefer eliminating sharing (message passing, ownership) over locking it.
17
+ - **Check-then-act is a race.** `if (!exists) create()` fails under
18
+ concurrency every time. Push atomicity down: unique constraints +
19
+ upsert, atomic compare-and-swap, `INSERT ... ON CONFLICT` — let the
20
+ storage layer arbitrate.
21
+ - **Everything retried must be idempotent.** Queues deliver at-least-once;
22
+ networks retry; users double-click. Design handlers so processing twice
23
+ = processing once (idempotency keys, natural dedup, upserts).
24
+ - **Every await is a suspension point.** State can change across it —
25
+ re-validate assumptions after resuming; don't cache a check made before
26
+ an await and act on it after.
27
+ - **Bound everything:** every queue has a max depth + backpressure
28
+ behavior; every parallel map has a concurrency limit; every wait has a
29
+ timeout. Unbounded = OOM or thundering herd, only later.
30
+ - **Cancellation propagates.** Long operations accept a signal
31
+ (AbortSignal / context) and pass it to their children; on cancel, clean
32
+ up partial work.
33
+ - **One lock order.** If you must hold two locks, EVERY path acquires them
34
+ in the same documented order — that single rule prevents most deadlocks.
35
+
36
+ ## Anti-patterns
37
+
38
+ - **Fire-and-forget promises** — unawaited async work whose failures
39
+ vanish → await it, or hand it to a supervised job runner that logs +
40
+ retries.
41
+ - **Sleep-based coordination** — "wait 500ms so X finishes first" →
42
+ synchronize on the event itself; timing assumptions break under load.
43
+ - **Global mutable singletons as coordination** → explicit passing or a
44
+ real store with atomic ops.
45
+ - **Distributed transactions by hope** — two systems updated without an
46
+ outbox/saga → write locally + outbox table, deliver async, reconcile.
47
+
48
+ ## Testing concurrency
49
+
50
+ Force interleavings — don't hope: run the racy pair with a barrier so both
51
+ start together; loop 100×; inject delays at suspension points. A race you
52
+ can't provoke deliberately is a race you'll meet in production
53
+ (`diagnosing-bugs.md` § non-deterministic bugs).
54
+
55
+ ## Checklist
56
+
57
+ - [ ] Shared state enumerated; each entry owned, locked, or made atomic
58
+ - [ ] All retried paths provably idempotent (test: run handler twice)
59
+ - [ ] Queues/parallelism/waits all bounded with explicit numbers
60
+ - [ ] Cancellation reaches children; partial work cleaned up
61
+ - [ ] At least one test forces the race window
@@ -0,0 +1,52 @@
1
+ ---
2
+ name: config-and-secrets
3
+ description: Configuration discipline — env-driven config, validation at boot, secret hygiene, environments
4
+ tags: [config, configuration, environment, env, secret, settings, deploy, dotenv, variable]
5
+ when: task adds configuration, environment handling, or deployment settings
6
+ phases: [build, ship]
7
+ provenance: { origin: built-in }
8
+ ---
9
+
10
+ # Configuration & Secrets
11
+
12
+ ## Rules
13
+
14
+ - **Config comes from the environment; code ships identical everywhere.**
15
+ Anything that differs between dev/staging/prod (URLs, credentials,
16
+ flags, limits) is env config — never an `if (env === "prod")` branch
17
+ buried in logic.
18
+ - **One config module, validated at boot.** Read `process.env`/equivalent
19
+ in exactly one place; parse, type-check, and apply defaults there; crash
20
+ at startup with a message naming every missing/invalid variable. A
21
+ missing variable discovered at 3am mid-request is a design failure.
22
+ - **Everything has a sane dev default EXCEPT secrets.** A fresh clone runs
23
+ with `.env.example` copied to `.env`. Secrets have NO defaults —
24
+ absence must fail loudly, never fall back to a shared "dev secret".
25
+ - **Secrets:** environment or secrets manager only. `.env` gitignored;
26
+ `.env.example` committed with dummy values documenting every variable.
27
+ Rotate on any suspicion of exposure; a secret that hit git history IS
28
+ exposed (rewriting history doesn't un-leak it — rotate).
29
+ - **Name for grep:** consistent prefix (`APP_DB_URL`, `APP_REDIS_URL`).
30
+ Booleans parse explicitly ("true"/"1"); everything else arrives as a
31
+ string — convert deliberately.
32
+ - **Feature flags are config too:** defined in the config module, defaulted
33
+ off, deleted after full rollout — a flag older than a quarter is debt.
34
+
35
+ ## Anti-patterns
36
+
37
+ - **`process.env.X` scattered through the codebase** → impossible to know
38
+ what the app needs; centralize.
39
+ - **Config objects passed 8 layers deep** → modules accept the 2 values
40
+ they need (see `codebase-design.md`), not the world.
41
+ - **"Just for testing" hardcoded credentials** → tests read the same
42
+ config module, pointed at test resources.
43
+ - **Committing the real .env "temporarily"** → it's in history forever;
44
+ rotate everything it contained.
45
+
46
+ ## Checklist
47
+
48
+ - [ ] Fresh clone + `.env.example` → app boots (or fails naming exactly what's missing)
49
+ - [ ] Single config module; grep finds no stray env reads
50
+ - [ ] No secret has a default; all documented in .env.example
51
+ - [ ] git history greps clean of credentials
52
+ - [ ] Env-specific behavior expressed as config values, not env-name branches
@@ -0,0 +1,51 @@
1
+ ---
2
+ name: context-hygiene
3
+ description: Externalize state before it decays — write discoveries down, re-read instead of remember
4
+ tags: [meta, context, memory, handoff, session, notes, playbook]
5
+ when: any long session, and always before ending one
6
+ phases: []
7
+ provenance: { origin: built-in, notes: frontier-playbook }
8
+ ---
9
+
10
+ # Context Hygiene
11
+
12
+ Your working memory decays and your session will end — possibly mid-task.
13
+ Everything that matters must live in files, not in your head. The next
14
+ session (you, another agent, a human) starts from what was WRITTEN.
15
+
16
+ ## Rules
17
+
18
+ - **Externalize at the moment of discovery**, not "later":
19
+ - Surprise, gotcha, non-obvious behavior → `harness/lessons-decisions.md "..."`
20
+ - Design choice with a why → `infinity-harness decision "..."`
21
+ - Resolved terminology → `harness/docs/DOMAIN.md`
22
+ - Verified fact about an API/tool → `docs/research/` (with frontmatter)
23
+ - **Re-read instead of remember.** Before acting on something you learned
24
+ a while ago (a file's shape, a config value), read it again — it may
25
+ have changed, and your memory of it degrades silently.
26
+ - **Carry one slice.** Work on the current task only; when adjacent
27
+ problems surface, write them down (learn / feature-list backlog) and
28
+ return to the slice. Holding five threads drops four.
29
+ - **Commit = checkpoint your understanding.** Commit after every validated
30
+ step with a message that says WHY, not just what. Uncommitted work +
31
+ ended session = archaeology for the next one.
32
+ - **Before exiting — the clock-out ritual:**
33
+ 1. Record any un-captured discoveries (`learn`) and choices (`decision`)
34
+ 2. Commit (`git commit -am "session: <state + what's next>"`)
35
+ 3. The harness writes `session-handoff.md` at boundaries — make sure
36
+ what YOU know that it doesn't is in progress notes or lessons
37
+
38
+ ## Anti-patterns
39
+
40
+ - **"I'll remember"** — across an iteration boundary, you won't exist.
41
+ Write it down.
42
+ - **Giant uncommitted diffs** spanning multiple concerns — impossible to
43
+ hand off, painful to bisect. Commit per validated slice.
44
+ - **Notes in chat/scratch only** — anything not in the repo doesn't exist
45
+ for the next session.
46
+
47
+ ## Checklist (end of any session)
48
+
49
+ - [ ] Lessons/decisions recorded for everything non-obvious found
50
+ - [ ] Working tree committed with a why-message
51
+ - [ ] A stranger could resume from handoff + progress + lessons alone
@@ -0,0 +1,63 @@
1
+ ---
2
+ name: databases
3
+ description: Relational database craft — schema design, migrations, transactions, indexing, query safety
4
+ tags: [database, db, sql, postgres, postgresql, mysql, sqlite, schema, migration, transaction, index, query, orm, persistence, storage]
5
+ when: task touches persistent data, schemas, queries, or migrations
6
+ phases: [plan, build, verify]
7
+ provenance: { origin: built-in }
8
+ ---
9
+
10
+ # Databases
11
+
12
+ ## Rules
13
+
14
+ - **Schema first, code second.** Write the DDL (tables, types, constraints)
15
+ before the access code. Constraints in the database (`NOT NULL`, `UNIQUE`,
16
+ `FOREIGN KEY`, `CHECK`) beat validation in code — code has bugs; the
17
+ constraint never sleeps.
18
+ - **Every schema change is a migration file** — forward-only, numbered,
19
+ committed, and runnable from scratch (`migrate` on an empty DB must
20
+ produce the current schema). Never edit an applied migration; add a new one.
21
+ - **Transactions around invariants.** Any multi-statement change that must
22
+ hold together goes in one transaction. Name the invariant in a comment.
23
+ - **Parameterized queries only.** String-built SQL is an injection —
24
+ no exceptions, including "internal" tooling.
25
+ - **Index what you filter/join/sort on** — but only with evidence: add the
26
+ index when a real query needs it (EXPLAIN shows a scan), not
27
+ speculatively. Every index taxes writes.
28
+ - **IDs:** prefer surrogate keys (bigint identity or UUIDv7); natural keys
29
+ get UNIQUE constraints instead.
30
+ - **Timestamps:** store UTC (`timestamptz` in Postgres), convert at the edge.
31
+ - **Money/decimals:** exact types (`NUMERIC`), never floats.
32
+
33
+ ## The N+1 rule
34
+
35
+ If you query in a loop, you have an N+1. Fix with a join, an `IN` batch,
36
+ or a dataloader — before it ships, not after the incident. Tell: page
37
+ loads trigger a query count proportional to row count.
38
+
39
+ ## Migration safety (live systems)
40
+
41
+ Expand → migrate → contract: add the new column/table (nullable or
42
+ defaulted) → backfill + dual-write → switch reads → drop the old thing in
43
+ a LATER migration once nothing references it. Never rename or drop in the
44
+ same deploy that changes code.
45
+
46
+ ## Anti-patterns
47
+
48
+ - **SELECT \*** in application code → name the columns; schema drift breaks
49
+ you silently otherwise.
50
+ - **Soft-delete everywhere by default** → only where restore/audit is a real
51
+ requirement; otherwise it poisons every query with `WHERE deleted_at IS NULL`.
52
+ - **Business logic in triggers** → invisible control flow; keep triggers to
53
+ bookkeeping (updated_at) if used at all.
54
+ - **Testing against mocks of the DB** → test against a real (local/ephemeral)
55
+ database; SQLite-in-memory only when production is SQLite.
56
+
57
+ ## Checklist
58
+
59
+ - [ ] Schema has constraints for every invariant you rely on
60
+ - [ ] Migrations replay clean on an empty database
61
+ - [ ] No string-concatenated SQL anywhere
62
+ - [ ] Hot queries EXPLAINed; indexes justified by a real plan
63
+ - [ ] Tests hit a real database engine matching production
@@ -0,0 +1,84 @@
1
+ ---
2
+ name: diagnosing-bugs
3
+ description: Feedback-loop-first debugging discipline for hard bugs and regressions
4
+ tags: [debug, debugging, bug, error, failure, crash, flaky, slow, performance, regression, bisect]
5
+ when: something is broken, throwing, failing intermittently, or slow
6
+ phases: [verify, build]
7
+ provenance: { origin: "mattpocock/skills", license: MIT, adapted: true }
8
+ ---
9
+
10
+ # Diagnosing Bugs
11
+
12
+ > Adapted from [mattpocock/skills](https://github.com/mattpocock/skills) (MIT © Matt Pocock).
13
+ > Use during: VERIFY, or any time something is broken, throwing, failing, or slow.
14
+
15
+ A discipline for hard bugs. Follow the phases in order; skip one only when
16
+ you can explicitly justify it.
17
+
18
+ ## Phase 1 — Build a feedback loop
19
+
20
+ **This is the skill.** Everything else is mechanical. You need a **tight**
21
+ pass/fail signal that goes red on *this* bug. Without one, no amount of
22
+ staring at code will save you. Spend disproportionate effort here.
23
+
24
+ Ways to construct one, roughly in order:
25
+
26
+ 1. **Failing test** at whatever seam reaches the bug — unit, integration, e2e.
27
+ 2. **CLI/HTTP invocation** with a fixture input, diffing output against a known-good result.
28
+ 3. **Replay a captured trace** — save a real payload/event log, replay it through the code path in isolation.
29
+ 4. **Throwaway harness** — a minimal subset of the system (one module, mocked externals) that exercises the bug path with a single call.
30
+ 5. **Bisection harness** — if the bug appeared between two known states, automate "boot at state X, check" so `git bisect run` can do the work.
31
+ 6. **Differential loop** — run the same input through old vs new version and diff outputs.
32
+
33
+ Once you have *a* loop, **tighten** it: faster (seconds, not minutes),
34
+ sharper (assert the exact symptom, not "didn't crash"), deterministic (pin
35
+ time, seed RNG, isolate filesystem). For flaky bugs, raise the reproduction
36
+ rate — loop the trigger 100×, add stress, narrow timing — until it's
37
+ debuggable.
38
+
39
+ **Completion criterion:** you can name ONE command you have already run that
40
+ is red-capable (asserts the user's exact symptom), deterministic, fast, and
41
+ runnable unattended. If you catch yourself reading code to build a theory
42
+ before this command exists — stop. That's the exact failure this skill
43
+ prevents.
44
+
45
+ ## Phase 2 — Reproduce + minimise
46
+
47
+ Run the loop. Watch it go red. Confirm it produces the failure mode that was
48
+ *reported* — not a different failure nearby. Then shrink the repro to the
49
+ smallest scenario that still goes red: cut inputs, callers, config, one at a
50
+ time, re-running after each cut. Done when every remaining element is
51
+ load-bearing.
52
+
53
+ ## Phase 3 — Hypothesise
54
+
55
+ Generate **3–5 ranked hypotheses** before testing any. Each must be
56
+ falsifiable: "If X is the cause, then changing Y will make the bug
57
+ disappear." If you can't state the prediction, it's a vibe — discard it.
58
+ Record the ranked list (in the task notes or `harness/lessons-decisions.md`).
59
+
60
+ ## Phase 4 — Instrument
61
+
62
+ Each probe maps to one prediction. Change one variable at a time. Prefer a
63
+ debugger/REPL breakpoint over logs; targeted logs over log-everything. Tag
64
+ every debug log with a unique prefix (e.g. `[DEBUG-a4f2]`) so cleanup is a
65
+ single grep. For performance bugs: measure a baseline first, then bisect —
66
+ logs are usually the wrong tool.
67
+
68
+ ## Phase 5 — Fix + regression test
69
+
70
+ Write the regression test **before the fix** — at a seam that exercises the
71
+ real bug pattern. If no correct seam exists, that is itself a finding:
72
+ record it as a lesson. Then: watch the test fail → apply the fix → watch it
73
+ pass → re-run the Phase 1 loop against the original scenario.
74
+
75
+ ## Phase 6 — Cleanup + post-mortem
76
+
77
+ - [ ] Original repro no longer reproduces
78
+ - [ ] Regression test passes (or absence of seam documented)
79
+ - [ ] All `[DEBUG-...]` instrumentation removed (grep the prefix)
80
+ - [ ] Throwaway harnesses deleted
81
+ - [ ] Record the confirmed hypothesis: `harness/lessons-decisions.md "bug X was caused by Y"`
82
+
83
+ Then ask: what would have prevented this bug? If the answer is architectural
84
+ (no test seam, tangled callers), record it: `infinity-harness decision "..."`.
@@ -0,0 +1,65 @@
1
+ ---
2
+ name: domain-modeling
3
+ description: Pin down domain terminology — glossary discipline and decision records
4
+ tags: [domain, glossary, terminology, naming, model, ubiquitous, language, adr, decision]
5
+ when: defining specs, resolving fuzzy or conflicting terms, recording decisions
6
+ phases: [define, plan]
7
+ provenance: { origin: "mattpocock/skills", license: MIT, adapted: true }
8
+ ---
9
+
10
+ # Domain Modeling
11
+
12
+ > Adapted from [mattpocock/skills](https://github.com/mattpocock/skills) (MIT © Matt Pocock).
13
+ > Use during: DEFINE (before writing the spec), and whenever terminology gets fuzzy.
14
+
15
+ Actively build and sharpen the project's domain model as you design.
16
+ The glossary lives in `harness/docs/DOMAIN.md`; decisions live in
17
+ `harness/docs/DECISIONS.md`. Create `DOMAIN.md` the moment the first term
18
+ is resolved — not before, and not "later".
19
+
20
+ ## The habits
21
+
22
+ ### Sharpen fuzzy language
23
+ When a vague or overloaded term appears ("account", "job", "sync"), propose
24
+ a precise canonical term. "You're saying 'account' — do you mean the
25
+ Customer or the User? Those are different things." One concept, one name,
26
+ everywhere: spec, code, tests, docs.
27
+
28
+ ### Challenge against the glossary
29
+ When new text conflicts with an existing definition in `DOMAIN.md`, call it
30
+ out immediately and resolve which meaning wins. Never let two meanings
31
+ coexist silently.
32
+
33
+ ### Stress-test with concrete scenarios
34
+ When domain relationships are being defined, invent specific scenarios that
35
+ probe the edges. "A customer cancels half an order that already partially
36
+ shipped — what happens to the invoice?" Force the boundaries between
37
+ concepts to be precise.
38
+
39
+ ### Cross-reference with code
40
+ When someone states how something works, check whether the code agrees. If
41
+ the code cancels entire Orders but the spec says partial cancellation is
42
+ possible — surface the contradiction now, not in BUILD.
43
+
44
+ ### Update DOMAIN.md inline
45
+ When a term is resolved, write it down right there. Don't batch. Format:
46
+
47
+ ```markdown
48
+ ## Terms
49
+
50
+ ### Order
51
+ A customer's confirmed request to purchase. Created at checkout; immutable
52
+ once `shipped`. NOT the same as a Cart (pre-checkout, mutable).
53
+ ```
54
+
55
+ `DOMAIN.md` is a glossary and nothing else — no implementation details, no
56
+ scratch notes, no specs.
57
+
58
+ ### Record decisions sparingly
59
+ Record a decision (`infinity-harness decision "..."`) only when all three hold:
60
+
61
+ 1. **Hard to reverse** — changing your mind later costs something real
62
+ 2. **Surprising without context** — a future reader would ask "why?"
63
+ 3. **A real trade-off** — genuine alternatives existed and you picked one
64
+
65
+ If any is missing, skip it. Noise buries signal.
@@ -0,0 +1,56 @@
1
+ ---
2
+ name: error-handling-logging
3
+ description: Error taxonomy, fail-loud handling, structured logging that debugs itself
4
+ tags: [error, exception, logging, log, observability, retry, crash, handling, monitoring, trace]
5
+ when: task defines error paths, adds logging, or hardens failure behavior
6
+ phases: [build, verify]
7
+ provenance: { origin: built-in }
8
+ ---
9
+
10
+ # Error Handling & Logging
11
+
12
+ ## Rules
13
+
14
+ - **Two kinds of errors, two behaviors.** *Expected/operational* (bad
15
+ input, not-found, downstream timeout): handle at the boundary, map to
16
+ the API error shape, keep serving. *Unexpected/programmer* (undefined is
17
+ not a function, invariant broken): crash loud — log, alert, restart.
18
+ Catching-and-continuing a programmer error corrupts state downstream.
19
+ - **Catch where you can act.** A catch block must do one of: recover
20
+ meaningfully, translate to the caller's vocabulary (wrapping the cause),
21
+ or add context and rethrow. `catch (e) {}` and log-and-swallow are how
22
+ systems lie about being healthy.
23
+ - **Preserve the chain.** When wrapping, keep the original (`cause`), the
24
+ stack, and add what you know: which operation, which IDs, which inputs.
25
+ "Database error" tells nothing; "saving order 123: unique violation on
26
+ idempotency_key" tells everything.
27
+ - **Structured logs (JSON), one event per line:** timestamp, level, event
28
+ name, and the IDs someone will grep for at 3am (request_id, user_id,
29
+ order_id). A log line you can't query is decoration.
30
+ - **Correlate:** generate/propagate a request_id at the edge; include it
31
+ in every log line and error response. One incident = one grep.
32
+ - **Levels mean things:** ERROR = a human should look (alertable);
33
+ WARN = degraded but coping; INFO = state changes worth an audit trail;
34
+ DEBUG = off in production. If ERROR fires routinely, it's WARN or a bug.
35
+ - **Never log secrets** — tokens, passwords, full card/PII. Scrub
36
+ centrally at the logger, not at each call site.
37
+
38
+ ## Anti-patterns
39
+
40
+ - **Stringly errors** (`throw "failed"`) → typed/coded errors the caller
41
+ can switch on; strings can't be handled, only displayed.
42
+ - **Retry without classification** — retrying a 400 forever, or not
43
+ retrying a timeout → retry only transient errors, bounded + backoff
44
+ (see `concurrency-async.md` for idempotency).
45
+ - **The 500-catch-all that hides the cause** → boundary handler logs the
46
+ full chained error with request_id, returns the safe shape.
47
+ - **printf debugging left behind** → tagged temp logs (`[DEBUG-x]`) and a
48
+ cleanup grep before validate (the anti-placeholder gate will catch you).
49
+
50
+ ## Checklist
51
+
52
+ - [ ] Every catch: recovers, translates, or rethrows with context — no swallows
53
+ - [ ] Error responses use the API error shape; internals never leak
54
+ - [ ] Logs structured; request_id flows edge→depths
55
+ - [ ] ERROR level = actionable only; alert noise is a bug
56
+ - [ ] Grep confirms: no secrets in logs, no leftover debug prints
@@ -0,0 +1,56 @@
1
+ ---
2
+ name: frontend-ui
3
+ description: Frontend craft — state discipline, componentization, accessibility, loading/error states
4
+ tags: [frontend, ui, component, react, vue, svelte, state, form, accessibility, a11y, css, browser, render]
5
+ when: task builds or changes user interface
6
+ phases: [plan, build]
7
+ provenance: { origin: built-in }
8
+ ---
9
+
10
+ # Frontend / UI
11
+
12
+ ## Rules
13
+
14
+ - **State has one owner.** Every piece of state lives in exactly one place;
15
+ everything else derives from it. Duplicated state = guaranteed
16
+ desync bug. Derive, don't copy.
17
+ - **Server state ≠ UI state.** Data fetched from an API (cacheable,
18
+ refetchable, shared) is a different animal from local UI state (open
19
+ modal, input draft). Use the ecosystem's query layer for server state;
20
+ keep UI state local to the component that owns it.
21
+ - **Every async view renders three states:** loading, error (with a retry
22
+ affordance), and empty ("no results" is not a blank screen). Design them
23
+ first — they're most of what users see on bad networks.
24
+ - **Forms:** controlled state or a form library — not DOM scraping.
25
+ Validate on submit + inline after first blur; disable the submit button
26
+ while in flight (double-submit is a data bug, not a UX nit).
27
+ - **Accessibility is baseline, not polish:** semantic elements first
28
+ (`button`, `label`+input, `nav`); every interactive element keyboard
29
+ reachable with visible focus; images get alt; color is never the only
30
+ signal. If a div has onClick, it's a button — make it one.
31
+ - **Componentize by responsibility, not by size.** A component that takes
32
+ 12 props wants to be two. Container (data) vs presentational (markup)
33
+ split keeps both testable.
34
+ - **Test behavior through the user's eyes:** render, interact (click/type),
35
+ assert visible outcome. Don't assert internal state or mock child
36
+ components — that's the implementation-coupled trap (`tdd.md`).
37
+
38
+ ## Anti-patterns
39
+
40
+ - **useEffect as event handler** — effects synchronize with external
41
+ systems; user actions belong in handlers. Effect-chains that set state
42
+ which triggers effects = rewrite the data flow.
43
+ - **Prop drilling 4+ levels** → lift to context/store — but only genuinely
44
+ shared state; context is not a junk drawer.
45
+ - **Pixel-perfect absolute positioning** → flexbox/grid; the content WILL
46
+ change length and language.
47
+ - **Swallowed promise rejections in handlers** → every await in a handler
48
+ has a catch that surfaces to the user.
49
+
50
+ ## Checklist
51
+
52
+ - [ ] Loading / error / empty rendered for every async view
53
+ - [ ] Keyboard-only walkthrough works; focus visible
54
+ - [ ] No state duplicated across components (grep for copied fetch results)
55
+ - [ ] Forms: double-submit blocked, validation inline, errors named
56
+ - [ ] Interaction tests assert what the USER sees
@@ -0,0 +1,48 @@
1
+ ---
2
+ name: grilling
3
+ description: Stress-test a spec or plan with relentless one-at-a-time questions before committing
4
+ tags: [grill, spec, requirements, questions, stress, interview, scope, clarify]
5
+ when: before proposing the sprint contract, or when a plan feels underspecified
6
+ phases: [define]
7
+ provenance: { origin: "mattpocock/skills", license: MIT, adapted: true }
8
+ ---
9
+
10
+ # Grilling — Stress-Test the Spec
11
+
12
+ > Adapted from [mattpocock/skills](https://github.com/mattpocock/skills) (MIT © Matt Pocock).
13
+ > Use during: DEFINE (before the sprint contract is agreed).
14
+
15
+ A spec that hasn't been grilled is a guess. Before proposing the sprint
16
+ contract, interrogate the plan until it stops changing.
17
+
18
+ ## With a human available (copilot mode)
19
+
20
+ Interview the human relentlessly about every aspect of the spec until you
21
+ reach shared understanding. Walk down each branch of the decision tree,
22
+ resolving dependencies between decisions one by one.
23
+
24
+ - Ask questions **one at a time** — wait for each answer before continuing.
25
+ Multiple questions at once are bewildering.
26
+ - For each question, provide your **recommended answer**.
27
+ - If a *fact* can be found by exploring the environment (filesystem, code,
28
+ docs), look it up rather than asking. The *decisions* are the human's —
29
+ put each one to them.
30
+ - Do not propose the contract until the human confirms shared understanding.
31
+
32
+ ## Without a human (autopilot mode) — self-grill
33
+
34
+ Ask the questions anyway, and answer each with your best recommendation.
35
+ Write the question + answer pairs into `specs/prd.md` under
36
+ "## Resolved Questions" so a human can audit them later. Standard probes:
37
+
38
+ - Who uses this, and what do they do the moment it works?
39
+ - What is explicitly OUT of scope this sprint?
40
+ - What's the smallest end-to-end slice that proves the concept?
41
+ - What breaks first under bad input / no network / concurrent use?
42
+ - How will we KNOW it works — what command or check proves it?
43
+ - What existing code/library already does part of this?
44
+ - What's the most likely way this plan fails, and what's the fallback?
45
+
46
+ Any question you cannot answer confidently becomes an exclusion in the
47
+ sprint contract or a research task (`harness/skills/research.md`) — never
48
+ a silent assumption.
@@ -0,0 +1,60 @@
1
+ ---
2
+ name: http-apis
3
+ description: HTTP/REST API design — resources, status codes, errors, versioning, pagination, idempotency
4
+ tags: [api, http, rest, endpoint, route, json, status, error, versioning, pagination, webhook, request, response]
5
+ when: task designs or implements HTTP endpoints or consumes external APIs
6
+ phases: [plan, build]
7
+ provenance: { origin: built-in }
8
+ ---
9
+
10
+ # HTTP APIs
11
+
12
+ ## Rules
13
+
14
+ - **Resources, not verbs.** `POST /orders`, `GET /orders/:id` — the verb is
15
+ the method. RPC-ish actions get a sub-resource: `POST /orders/:id/cancel`.
16
+ - **Status codes carry meaning:** 200 ok · 201 created (+ `Location`) ·
17
+ 204 no body · 400 client sent garbage · 401 unauthenticated ·
18
+ 403 unauthorized · 404 absent (also for "exists but not yours") ·
19
+ 409 conflict · 422 validation · 429 throttled · 5xx = OUR bug, never the
20
+ client's. Don't return 200 with `{"error": ...}`.
21
+ - **One error shape everywhere:**
22
+
23
+ ```json
24
+ { "error": { "code": "ORDER_NOT_CANCELLABLE", "message": "Order already shipped", "details": [] } }
25
+ ```
26
+
27
+ `code` is machine-stable (clients switch on it); `message` is for humans
28
+ and may change.
29
+ - **Validate at the edge.** Reject unknown fields, wrong types, and
30
+ out-of-range values with 400/422 naming the field. Never let bad input
31
+ deep into the system.
32
+ - **Mutations are idempotent or idempotency-keyed.** PUT/DELETE naturally;
33
+ POST that charges/creates accepts an `Idempotency-Key` header and
34
+ dedupes retries — networks WILL retry.
35
+ - **Paginate every list** from day one (cursor > offset for anything that
36
+ grows). Return `next_cursor`; cap page size.
37
+ - **Version in the path** (`/v1/`) and only break within a version never.
38
+ Additive changes (new optional fields) don't need a bump.
39
+ - **Timeouts + retries on everything you CALL:** explicit connect/read
40
+ timeouts, retry only idempotent calls, exponential backoff + jitter,
41
+ honor `Retry-After`.
42
+
43
+ ## Anti-patterns
44
+
45
+ - **Chatty endpoints** — client needs 5 calls to render one screen → add a
46
+ composed read endpoint; don't make the client an orchestrator.
47
+ - **Tunneling through POST /doThing** with a type field → separate routes;
48
+ observability and auth depend on it.
49
+ - **Leaking internals** — DB column names, stack traces, ORM errors in
50
+ responses → map to the error shape at the boundary.
51
+ - **Webhooks without verification** — sign payloads (HMAC), verify
52
+ signature + timestamp, respond 2xx fast and process async.
53
+
54
+ ## Checklist
55
+
56
+ - [ ] Every endpoint: documented method+path, request/response example, error codes
57
+ - [ ] Error shape uniform; codes machine-stable
58
+ - [ ] Lists paginated; mutations idempotent or keyed
59
+ - [ ] Outbound calls have timeouts, bounded retries, backoff
60
+ - [ ] Contract exercised by an integration test hitting real routes
@@ -0,0 +1,53 @@
1
+ ---
2
+ name: performance
3
+ description: Performance work — measure first, fix the biggest cost, cache with invalidation, verify
4
+ tags: [performance, slow, latency, profiling, optimize, cache, memory, benchmark, throughput, speed]
5
+ when: something is slow, memory-hungry, or a task sets performance targets
6
+ phases: [verify, build]
7
+ provenance: { origin: built-in }
8
+ ---
9
+
10
+ # Performance
11
+
12
+ ## Rules
13
+
14
+ - **Measure before touching anything.** Reproduce the slowness with a
15
+ number (timing harness, profiler, EXPLAIN, flamegraph) and save the
16
+ baseline. Optimizing without a measurement is guessing — most guesses
17
+ about "the slow part" are wrong.
18
+ - **Fix costs in order of size.** The profile ranks them. The top item is
19
+ usually I/O shaped: N+1 queries, missing index, sync call in a loop,
20
+ chatty API — algorithmic elegance rarely matters before those are gone.
21
+ - **Set a target before optimizing** ("p95 < 300ms", "fits in 512MB").
22
+ Without a target, optimization never ends; with one, you stop on hit.
23
+ - **Do less work first:** don't compute what nobody reads, paginate,
24
+ filter at the source (DB, not app), batch round-trips, stream instead of
25
+ buffering whole payloads.
26
+ - **Cache only with an invalidation story.** Every cache states: key,
27
+ TTL/eviction, and what makes it stale. A cache without invalidation is a
28
+ correctness bug on a delay. Prefer short TTLs you can reason about.
29
+ - **Verify with the same harness** that produced the baseline; keep the
30
+ before/after numbers in the commit message. No number = no optimization
31
+ happened.
32
+ - **Concurrency ≠ speed.** Parallelizing CPU-bound work on one core, or
33
+ hammering a saturated DB harder, makes it slower. Know which resource is
34
+ the bottleneck first.
35
+
36
+ ## Anti-patterns
37
+
38
+ - **Micro-optimizing the cold path** — shaving the loop while every call
39
+ does a network round-trip → profile decides, not intuition.
40
+ - **Speculative caching layers** — Redis before there's a measured need →
41
+ measure, then cache the specific hot read.
42
+ - **Load testing at 1×** — perf verified only at dev-scale → test at
43
+ expected load ± spike; N+1s hide at N=3.
44
+ - **"It's the language/framework"** — usually it's your query pattern.
45
+ Prove the platform is the ceiling before replatforming.
46
+
47
+ ## Checklist
48
+
49
+ - [ ] Baseline measured and saved before any change
50
+ - [ ] Target stated; work stops when hit
51
+ - [ ] Top profile item addressed first (linked evidence)
52
+ - [ ] Every cache has key/TTL/invalidation written down
53
+ - [ ] After-numbers from the same harness, in the commit