@event4u/agent-config 2.10.0 → 2.12.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 (94) hide show
  1. package/.agent-src/commands/agents.md +1 -0
  2. package/.agent-src/commands/challenge-me.md +1 -0
  3. package/.agent-src/commands/chat-history.md +1 -0
  4. package/.agent-src/commands/context.md +1 -0
  5. package/.agent-src/commands/council.md +1 -0
  6. package/.agent-src/commands/feature.md +1 -0
  7. package/.agent-src/commands/fix.md +1 -0
  8. package/.agent-src/commands/grill-me.md +1 -0
  9. package/.agent-src/commands/judge.md +1 -0
  10. package/.agent-src/commands/memory.md +1 -0
  11. package/.agent-src/commands/module.md +1 -0
  12. package/.agent-src/commands/onboard.md +32 -4
  13. package/.agent-src/commands/optimize.md +1 -0
  14. package/.agent-src/commands/override.md +1 -0
  15. package/.agent-src/commands/roadmap.md +1 -0
  16. package/.agent-src/commands/tests.md +1 -0
  17. package/.agent-src/skills/canvas-design/SKILL.md +132 -0
  18. package/.agent-src/skills/canvas-design/evals/triggers.json +16 -0
  19. package/.agent-src/skills/doc-coauthoring/SKILL.md +129 -0
  20. package/.agent-src/skills/doc-coauthoring/evals/triggers.json +16 -0
  21. package/.agent-src/skills/nextjs-patterns/SKILL.md +203 -0
  22. package/.agent-src/skills/skill-writing/SKILL.md +101 -16
  23. package/.agent-src/skills/sql-writing/SKILL.md +1 -1
  24. package/.agent-src/skills/symfony-workflow/SKILL.md +173 -0
  25. package/.agent-src/templates/scripts/work_engine/hook_bootstrap.py +4 -0
  26. package/.agent-src/templates/scripts/work_engine/hooks/builtin/__init__.py +3 -0
  27. package/.agent-src/templates/scripts/work_engine/hooks/builtin/decision_gate.py +162 -0
  28. package/.agent-src/templates/scripts/work_engine/hooks/settings.py +24 -6
  29. package/.agent-src/templates/scripts/work_engine/scoring/decision_engine.py +351 -0
  30. package/.claude-plugin/marketplace.json +5 -1
  31. package/CHANGELOG.md +68 -0
  32. package/README.md +37 -8
  33. package/config/agent-settings.template.yml +66 -0
  34. package/docs/architecture.md +1 -1
  35. package/docs/contracts/STABILITY.md +16 -0
  36. package/docs/contracts/adr-chat-history-split.md +1 -0
  37. package/docs/contracts/adr-forecast-construction-shape.md +1 -0
  38. package/docs/contracts/adr-gtm-context-spine.md +1 -0
  39. package/docs/contracts/adr-level-6-productization.md +147 -0
  40. package/docs/contracts/adr-settings-sync-engine.md +1 -0
  41. package/docs/contracts/adr-wing4-context-spine.md +1 -0
  42. package/docs/contracts/agent-memory-contract.md +1 -0
  43. package/docs/contracts/agents-md-tech-stack.md +1 -0
  44. package/docs/contracts/audit-log-v1.md +1 -0
  45. package/docs/contracts/command-clusters.md +1 -0
  46. package/docs/contracts/command-surface-tiers.md +1 -0
  47. package/docs/contracts/context-paths.md +1 -0
  48. package/docs/contracts/cost-profile-defaults.md +105 -0
  49. package/docs/contracts/cross-wing-handoff.md +1 -0
  50. package/docs/contracts/decision-engine-gates.md +115 -0
  51. package/docs/contracts/decision-trace-v1.md +1 -0
  52. package/docs/contracts/file-ownership-matrix.md +1 -0
  53. package/docs/contracts/hook-architecture-v1.md +1 -0
  54. package/docs/contracts/implement-ticket-flow.md +1 -0
  55. package/docs/contracts/installed-tools-lockfile.md +1 -0
  56. package/docs/contracts/kernel-membership.md +1 -0
  57. package/docs/contracts/linear-ai-rules-inclusion.md +1 -0
  58. package/docs/contracts/linear-ai-three-layers.md +1 -0
  59. package/docs/contracts/linter-structural-model.md +1 -0
  60. package/docs/contracts/load-context-budget-model.md +1 -0
  61. package/docs/contracts/load-context-schema.md +1 -0
  62. package/docs/contracts/memory-visibility-v1.md +1 -0
  63. package/docs/contracts/one-off-script-lifecycle.md +1 -0
  64. package/docs/contracts/orchestration-dsl-v1.md +1 -0
  65. package/docs/contracts/package-self-orientation.md +1 -0
  66. package/docs/contracts/persona-schema.md +1 -0
  67. package/docs/contracts/release-trunk-sync.md +104 -0
  68. package/docs/contracts/roadmap-complexity-standard.md +1 -0
  69. package/docs/contracts/rule-classification.md +1 -0
  70. package/docs/contracts/rule-interactions.md +26 -0
  71. package/docs/contracts/rule-priority-hierarchy.md +1 -0
  72. package/docs/contracts/rule-router.md +1 -0
  73. package/docs/contracts/settings-sync-yaml-subset.md +1 -0
  74. package/docs/contracts/skill-domains.md +1 -0
  75. package/docs/contracts/tier-3-contrib-plugin.md +1 -0
  76. package/docs/contracts/ui-stack-extension.md +1 -0
  77. package/docs/contracts/ui-track-flow.md +1 -0
  78. package/docs/customization.md +1 -1
  79. package/docs/getting-started.md +3 -1
  80. package/docs/installation.md +8 -6
  81. package/package.json +1 -1
  82. package/scripts/ai_council/clients.py +17 -4
  83. package/scripts/ai_council/orchestrator.py +6 -2
  84. package/scripts/check_beta_review_markers.py +127 -0
  85. package/scripts/check_references.py +25 -0
  86. package/scripts/check_release_trunk_sync.py +152 -0
  87. package/scripts/council_cli.py +36 -5
  88. package/scripts/install.py +3 -3
  89. package/scripts/run_skill_evals.py +185 -0
  90. package/scripts/schemas/command.schema.json +5 -0
  91. package/scripts/schemas/skill.schema.json +4 -0
  92. package/scripts/skill_linter.py +82 -3
  93. package/scripts/smoke_quickstart.py +134 -0
  94. package/scripts/validate_decision_engine.py +124 -0
@@ -0,0 +1,203 @@
1
+ ---
2
+ name: nextjs-patterns
3
+ description: "Writes Next.js App Router code — Server Components, Server Actions, RSC boundaries, route handlers, caching, and streaming — matching framework conventions and project architecture."
4
+ source: package
5
+ domain: engineering
6
+ ---
7
+
8
+ # nextjs-patterns
9
+
10
+ ## Compatibility
11
+
12
+ - **Tested against:** Next.js `14.x` and `15.x` (App Router), React `18+` / `19+`.
13
+ - Pages Router is **out of scope**. On a Pages-Router project (no `app/`),
14
+ fall back to plain React skills; ask before introducing App Router.
15
+
16
+ ## When to use
17
+
18
+ Use this skill for Next.js-specific code generation and editing on the App Router:
19
+
20
+ - Server Components (RSC) and Client Components (`"use client"`)
21
+ - Server Actions (`"use server"`)
22
+ - Route Handlers (`app/api/**/route.ts`)
23
+ - Layouts, templates, loading / error / not-found boundaries
24
+ - Data fetching with `fetch` + cache directives
25
+ - `revalidatePath` / `revalidateTag` invalidation
26
+ - Streaming and `<Suspense>` boundaries
27
+ - Middleware (`middleware.ts`)
28
+ - Metadata API (static + dynamic)
29
+ - Route Groups, Parallel Routes, Intercepting Routes
30
+
31
+ ## When to use the analysis sibling
32
+
33
+ When the task is **understanding** how a Next.js app boots, where the
34
+ server/client boundary lives, what is cached vs streamed, or why a
35
+ hydration mismatch fires — defer to `project-analysis-nextjs` first,
36
+ then return here for the edit.
37
+
38
+ ## Procedure: write Next.js code
39
+
40
+ 1. **Confirm App Router** — `app/` directory exists; `next.config.{js,ts,mjs}` present.
41
+ 2. **Confirm version** — `package.json` major for `next`. 14.x vs 15.x differs in
42
+ default caching (15.x is uncached by default for `fetch`) and in `cookies()` /
43
+ `headers()` being async.
44
+ 3. **Inspect routing layout** — flat `app/` vs grouped (`app/(marketing)/`,
45
+ `app/(app)/`); identify shared layouts and parallel routes.
46
+ 4. **Inspect data layer** — Server Actions vs route handlers vs external API;
47
+ ORM (Prisma, Drizzle) or fetch-based.
48
+ 5. **Inspect styling** — Tailwind, CSS Modules, or styled engine; respect the
49
+ chosen stack, do not mix.
50
+ 6. **Check test conventions** — Vitest / Jest + RTL for components; Playwright
51
+ for E2E; route-handler tests via `node` runtime.
52
+
53
+ ## Server vs Client boundary
54
+
55
+ - **Server Components are the default.** Add `"use client"` only when a leaf
56
+ component needs state, effects, browser APIs, or event handlers.
57
+ - The `"use client"` boundary is **viral upward at the import graph**, but you
58
+ can keep a Server Component **rendered as a child** of a Client Component
59
+ by passing it as a prop / `children` — that pattern keeps server logic out
60
+ of the client bundle.
61
+ - Never put database access, secrets, or server-only modules inside a Client
62
+ Component or a file imported by one. Use `import "server-only"` at the top
63
+ of a server module to make leaks fail at build time.
64
+ - Symmetric guard: `import "client-only"` for code that must never run on the
65
+ server (e.g. browser-only SDKs).
66
+ - Props passed from Server → Client must be serializable. No functions, no
67
+ Dates with custom prototypes, no `Map` / `Set` — use plain JSON.
68
+
69
+ ## Server Actions
70
+
71
+ - Declare with `"use server"` at the top of the file or per-function.
72
+ - Server Actions are **server-only RPC**; never call them from `useEffect` for
73
+ pure data fetching — that is what Server Components are for.
74
+ - Always **validate input** (zod or equivalent) at the entry of the action —
75
+ the caller is the client; treat it as hostile.
76
+ - Always **re-authorize** inside the action; do not trust client-side guards.
77
+ - After a mutation: call `revalidatePath()` / `revalidateTag()` or `redirect()`.
78
+ - Return shape: a `{ ok: true, data }` / `{ ok: false, error }` discriminated
79
+ union — never throw across the action boundary for expected errors.
80
+ - Use `useActionState` (15.x) / `useFormState` (14.x) on the client for
81
+ progressive enhancement; the form must work without JS.
82
+
83
+ ## Route Handlers
84
+
85
+ - `app/api/**/route.ts` exports `GET`, `POST`, etc.
86
+ - Handlers run on the **node runtime by default**; opt into `edge` only when
87
+ the dependency set supports it.
88
+ - Read request body once: `await req.json()` or `await req.formData()`.
89
+ - Return `Response` / `NextResponse`. Use `NextResponse.json` for JSON +
90
+ consistent status codes.
91
+ - Authentication and rate limiting happen **inside** the handler or via
92
+ `middleware.ts`; do not assume any framework default.
93
+ - Cache behavior: route handlers are dynamic by default in 15.x. Add
94
+ `export const dynamic = 'force-static'` / `revalidate = N` explicitly.
95
+
96
+ ## Caching and revalidation (14.x vs 15.x)
97
+
98
+ - **14.x**: `fetch` is cached by default (force-cache); opt out with
99
+ `{ cache: 'no-store' }` or segment-level `export const dynamic = 'force-dynamic'`.
100
+ - **15.x**: `fetch` is **not cached by default**; opt in with
101
+ `{ cache: 'force-cache' }` or `{ next: { revalidate: N } }`.
102
+ - Use **tag-based revalidation** for shared invalidation surface:
103
+ `fetch(url, { next: { tags: ['posts'] } })` then `revalidateTag('posts')`.
104
+ - Use `revalidatePath('/blog/[slug]', 'page')` for targeted page invalidation.
105
+ - Never call `revalidate*` from a Client Component — wrap it in a Server Action.
106
+ - `unstable_cache` / `cache` (React) wrap pure server functions for memoization
107
+ within a request; respect the difference between request-scoped and
108
+ cross-request caching.
109
+
110
+ ## Data fetching patterns
111
+
112
+ - Prefer fetching in **the Server Component that uses the data**, not in a
113
+ layout, to allow per-route streaming.
114
+ - Parallel fetching: declare independent promises and `await` together —
115
+ avoid sequential `await` chains that block streaming.
116
+ - `<Suspense>` boundaries make slow data non-blocking; wrap each independent
117
+ data dependency in its own Suspense, not the whole page.
118
+ - `loading.tsx` is a default Suspense fallback for the segment; do not use it
119
+ as a global spinner.
120
+ - Avoid `useEffect` for initial data load in Client Components — fetch on the
121
+ server and pass props.
122
+
123
+ ## Layouts, templates, error and not-found
124
+
125
+ - `layout.tsx` is a **persistent** wrapper across navigations; do not put
126
+ per-page logic there.
127
+ - `template.tsx` re-renders on every navigation; use only when a layout
128
+ cannot.
129
+ - `loading.tsx`, `error.tsx`, `not-found.tsx` are **per-segment**; nest them
130
+ to localize fallbacks.
131
+ - `error.tsx` must be a Client Component (`"use client"`); accept `error` and
132
+ `reset` props.
133
+
134
+ ## Middleware
135
+
136
+ - `middleware.ts` at the project root runs on the **edge runtime** before a
137
+ request hits a route — use for auth redirects, locale negotiation, A/B.
138
+ - No database access from middleware; the edge runtime cannot run most node
139
+ drivers. Use a session cookie + lightweight verification.
140
+ - `matcher` config narrows which paths invoke it — never let middleware run
141
+ on every asset.
142
+
143
+ ## Metadata, performance, env
144
+
145
+ - Metadata: static `export const metadata`; dynamic `generateMetadata()`.
146
+ `generateStaticParams` for static dynamic-segment generation.
147
+ - `next/image`, `next/font`, `next/dynamic` for images, fonts, code-split
148
+ Client Components — never bare `<img>`, CSS `@import` Google Fonts, or
149
+ unguarded heavy imports.
150
+ - A single `"use client"` near the top of a tree pulls the subtree into the
151
+ client bundle — keep the boundary at the leaf.
152
+ - Env: server-only `DATABASE_URL` etc.; client-exposed must be prefixed
153
+ `NEXT_PUBLIC_*` and is NOT secret. Validate env at boot (zod) and import
154
+ the validated object — never `process.env` ad hoc.
155
+
156
+ ## Output format
157
+
158
+ 1. Next.js code following App Router conventions and the project's existing layout.
159
+ 2. All related files (page, layout, server action, route handler, schema, test) as needed.
160
+ 3. When a cache surface changes — point at the invalidation call (`revalidateTag` / `revalidatePath`).
161
+
162
+ ## Do NOT
163
+
164
+ - Do NOT add `"use client"` to a file that does not need it — it pulls the
165
+ subtree into the client bundle.
166
+ - Do NOT import server modules (db client, secrets) from a Client Component
167
+ file — even transitively. Guard with `import "server-only"`.
168
+ - Do NOT call Server Actions from `useEffect` to fetch data — fetch on the server.
169
+ - Do NOT throw across a Server Action boundary for expected errors — return a
170
+ result union.
171
+ - Do NOT trust client-side authorization in a Server Action or route handler —
172
+ re-check.
173
+ - Do NOT mutate without revalidating — stale UI is a class of bug, not a design.
174
+ - Do NOT mix Pages Router and App Router patterns in one feature — pick one.
175
+ - Do NOT assume 14.x caching defaults on 15.x; verify the major before reasoning about cache.
176
+
177
+ ## Gotcha
178
+
179
+ - **15.x async APIs**: `cookies()`, `headers()`, `params`, `searchParams` are
180
+ **async** in 15.x. Code that ran on 14.x will silently misbehave (Promise
181
+ rendered as an object) until awaited.
182
+ - **Hydration mismatch**: rendering `Date.now()`, `Math.random()`, or
183
+ locale-dependent strings without `suppressHydrationWarning` or a Client
184
+ boundary causes a hydration error.
185
+ - **`"use client"` is not opt-in for hooks**: it is required for any file
186
+ using `useState`, `useEffect`, `useRef`, or browser globals.
187
+ - **Server Actions and forms**: a Server Action used as a form action must
188
+ accept `FormData`. Mixing `FormData` and typed args breaks progressive
189
+ enhancement.
190
+ - **Cache lies during dev**: dev mode ignores most cache directives. Verify
191
+ caching behavior in a production build (`next build && next start`).
192
+ - **`revalidatePath` requires the route group syntax** for parallel/dynamic
193
+ segments — bare paths silently miss.
194
+ - **Edge runtime ≠ Node**: most npm packages with native deps or Node-only
195
+ APIs (`fs`, `crypto.createHash`) fail at the edge. Pin runtime per route.
196
+
197
+ ## Auto-trigger keywords
198
+
199
+ - Next.js / App Router · Server Component (RSC) · Client Component (`"use client"`)
200
+ - Server Action (`"use server"`) · Route Handler (`app/api`) · `middleware.ts`
201
+ - `revalidatePath` / `revalidateTag` / `unstable_cache`
202
+ - `next/image` / `next/font` / `next/dynamic`
203
+ - `layout.tsx` / `loading.tsx` / `error.tsx` / `not-found.tsx`
@@ -3,6 +3,7 @@ name: skill-writing
3
3
  description: "Use when deciding 'should this be a skill or a rule?', creating/improving/reviewing agent skills, SKILL.md frontmatter, or procedure sections — even without saying 'skill-writing'."
4
4
  source: project
5
5
  domain: process
6
+ meta_skill: true
6
7
  ---
7
8
 
8
9
  # skill-writing
@@ -62,22 +63,25 @@ Ask: **"Does the model need this to do its job correctly?"**
62
63
 
63
64
  ### Skills and commands share the `.claude/skills/` namespace
64
65
 
65
- Skills (`.agent-src.uncompressed/skills/{name}/SKILL.md`) AND commands
66
- (`.agent-src.uncompressed/commands/{name}.md`) both project into
67
- `.claude/skills/` (`scripts/compress.py` → `generate_claude_skills` +
68
- `generate_claude_commands`). Claude treats the directory as native
69
- skills.
70
-
71
- * Same-name collision: skill wins, command is skipped
72
- (`generate_claude_commands` honors this). Don't reuse a command's
73
- slug for a skill unless the command should retire.
74
- * Both compete on `description` for routing. A weak skill description
75
- is shadowed by a stronger same-domain command and vice versa.
76
- Trigger phrasing must be precise (§ 1b below).
77
- * Workflow has both "user types `/foo`" path AND "model picks this up
78
- from intent" path author the skill first, let the command delegate
79
- via `skills:` frontmatter. Two artifacts with the same trigger
80
- surface fight each other in the router.
66
+ Skills in `.agent-src.uncompressed/skills/{name}/SKILL.md` AND commands in
67
+ `.agent-src.uncompressed/commands/{name}.md` both project into
68
+ `.claude/skills/` (see `scripts/compress.py` →
69
+ `generate_claude_skills` + `generate_claude_commands`). Claude treats
70
+ the whole directory as native skills.
71
+
72
+ Implications for skill authors:
73
+
74
+ * If a same-name command already exists, the skill takes priority and
75
+ the command is skipped (`generate_claude_commands` honors this).
76
+ Don't reuse a command's slug for a skill unless the command should
77
+ retire.
78
+ * Both artifacts compete on `description` for routing. A weak skill
79
+ description is shadowed by a stronger same-domain command and vice
80
+ versa. Make trigger phrasing precise 1b below).
81
+ * When the workflow has both a "user types `/foo`" path AND a "model
82
+ picks this up from intent" path, author the skill first and let the
83
+ command delegate (`skills:` frontmatter). Two artifacts with the same
84
+ trigger surface fight each other in the router.
81
85
 
82
86
  ### When "Nothing" is the right answer
83
87
 
@@ -263,6 +267,87 @@ Example:
263
267
  * K7: Created with analysis (not blind, expected behavior defined)
264
268
  * Size: Within limits (see size-and-scope guideline)
265
269
 
270
+ ### 7. Run + iterate evals (quantitative loop)
271
+
272
+ Triggers (`evals/triggers.json`) check **routing**. A separate
273
+ `evals/evals.json` checks **behavior** — does the skill make the agent
274
+ produce a better answer than baseline? Add this layer for any skill
275
+ where the procedure has measurable output (commands, artifacts,
276
+ structured text). Skip for evergreen heuristics with no falsifiable
277
+ output (e.g. `direct-answers`, `language-and-tone`) unless the user
278
+ asks for it.
279
+
280
+ **Workspace layout** (all under `.gitignore`):
281
+
282
+ ```
283
+ .agent-src.uncompressed/skills/{name}/evals/
284
+ triggers.json # tracked — routing eval (§ 1c)
285
+ evals.json # tracked — behavior eval definitions
286
+ runs/ # gitignored — per-iteration outputs
287
+ {timestamp}-baseline/ # sub-agent run without the skill
288
+ {timestamp}-with-skill/ # sub-agent run with the skill
289
+ {timestamp}-benchmark.json
290
+ ```
291
+
292
+ **`evals.json` shape** — 3–10 scenarios, each with prompt + grading
293
+ rubric:
294
+
295
+ ```json
296
+ {
297
+ "skill": "{name}",
298
+ "scenarios": [
299
+ {
300
+ "id": "happy-path",
301
+ "prompt": "<full user-shaped task that exercises the skill>",
302
+ "assertions": [
303
+ {"kind": "contains", "value": "<expected substring in output>"},
304
+ {"kind": "file_exists", "path": "<artifact path the skill should create>"},
305
+ {"kind": "rubric", "criterion": "<one-line judgement, e.g. 'output includes a numbered procedure'>"}
306
+ ]
307
+ }
308
+ ]
309
+ }
310
+ ```
311
+
312
+ `contains` / `file_exists` grade deterministically. `rubric` items grade
313
+ via a fresh sub-agent reading the output against the criterion — keep
314
+ each criterion to one falsifiable sentence.
315
+
316
+ **Loop** (orchestrated by `scripts/run_skill_evals.py`):
317
+
318
+ 1. **Scaffold** — `python3 scripts/run_skill_evals.py scaffold {skill}`
319
+ creates `runs/{timestamp}-{baseline,with-skill}/` and seeds each
320
+ scenario's `meta.json`.
321
+ 2. **Baseline run** — spawn one sub-agent per scenario **without** the
322
+ skill loaded. Capture stdout + any artifacts into
323
+ `runs/{timestamp}-baseline/{scenario-id}/`.
324
+ 3. **With-skill run** — same scenarios, same sub-agent harness, **with**
325
+ the skill loaded. Capture into `runs/{timestamp}-with-skill/{scenario-id}/`.
326
+ 4. **Grade** — for each scenario, write a `grade.json` file with
327
+ per-assertion pass/fail. Deterministic assertions auto-grade;
328
+ rubric assertions need a grader sub-agent.
329
+ 5. **Aggregate** — `python3 scripts/run_skill_evals.py aggregate {skill}
330
+ --run {timestamp}` produces `runs/{timestamp}-benchmark.json` with
331
+ pass-rate, timing, token deltas baseline-vs-with-skill.
332
+ 6. **Report** — `python3 scripts/run_skill_evals.py report {skill}
333
+ --run {timestamp}` prints the diff. Iterate on the skill body
334
+ until `with-skill` outperforms `baseline` on every scenario.
335
+
336
+ The script ships with sub-agent spawning **stubbed** — the orchestration
337
+ layer is per-environment (Claude Code, Augment, council). Implement
338
+ the spawn function once for your environment, the rest of the loop
339
+ (aggregate / report / scaffold) works out of the box.
340
+
341
+ **Exit criterion** — every scenario passes with-skill, at least one
342
+ fails baseline (proves the skill earns its slot). Commit the
343
+ `evals.json` alongside the skill; never commit `runs/`.
344
+
345
+ Neighbors:
346
+ * `description-assist` — iterate on the trigger phrasing
347
+ * `skill-reviewer` — structural 7-Killers audit
348
+ * `lint-skills` — static checks (frontmatter, sections, size)
349
+ * `skill-improvement-pipeline` — production-learning capture
350
+
266
351
  ## Output format
267
352
 
268
353
  1. Complete SKILL.md file
@@ -17,7 +17,7 @@ Do NOT use when:
17
17
 
18
18
  ## Procedure: Write raw SQL
19
19
 
20
- 1. **Choose approach** — Use query builder when possible. Raw SQL only when query builder can't express the query.
20
+ 1. **Inspect call site & choose approach** — identify every dynamic value flowing into the query, then pick: query builder when possible. Raw SQL only when query builder can't express the query.
21
21
  2. **Parameterize** — Every variable must use `?` binding or named `:param`. Never interpolate PHP variables into SQL strings.
22
22
  3. **Use MariaDB syntax** — Not PostgreSQL or MSSQL. Check `php/sql.md` for MariaDB-specific patterns.
23
23
  4. **Verify** — Run EXPLAIN on complex queries. Check that no PHP interpolation (`"$var"`, `'{$var}'`) appears in SQL.
@@ -0,0 +1,173 @@
1
+ ---
2
+ name: symfony-workflow
3
+ description: "Writes Symfony code following framework conventions, container wiring, and modern best practices for controllers, services, bundles, Messenger, Doctrine, security, and console commands."
4
+ source: package
5
+ domain: engineering
6
+ ---
7
+
8
+ # symfony-workflow
9
+
10
+ ## When to use
11
+
12
+ Use this skill for all Symfony-specific code generation and editing tasks, especially when working with:
13
+
14
+ - Controllers (annotated / attribute-routed)
15
+ - Request listeners / event subscribers
16
+ - Services and Dependency Injection (`services.yaml`)
17
+ - Forms and validators
18
+ - Doctrine entities, repositories, and migrations
19
+ - Security: firewalls, voters, authenticators
20
+ - Messenger handlers and transports
21
+ - Console commands
22
+ - Bundles, compiler passes, and tagged services
23
+ - Twig templates and view logic
24
+
25
+ This skill extends the base `php-coder` skill and applies Symfony conventions on top of the project's general PHP rules.
26
+
27
+ ## When to use the analysis sibling
28
+
29
+ When the task is **understanding** how a Symfony app boots, wires its container, routes requests, or fails at runtime — defer to `project-analysis-symfony` first, then return here for the edit. This skill assumes the kernel/container layout is already known.
30
+
31
+ ## Procedure: write Symfony code
32
+
33
+ → **First apply the `php-coder` skill** for general PHP rules.
34
+
35
+ Then add these **Symfony-specific** checks:
36
+
37
+ 1. **Confirm Symfony** — `bin/console` exists, `composer.json` lists `symfony/framework-bundle`.
38
+ 2. **Confirm version** — `composer.lock` for the framework-bundle major. 5.x → 6.x → 7.x differs in attribute routing, voter signatures, and Messenger DSN shape.
39
+ 3. **Inspect app structure** — standard, modular (`src/Module/<Name>/`), or DDD-style. Do not enforce a layout the project does not use.
40
+ 4. **Check config layout** — `config/packages/<env>/`, `services.yaml` autowiring vs explicit bindings, `config/bundles.php`.
41
+ 5. **Check test conventions** — PHPUnit/Codeception; unit vs integration vs functional split.
42
+
43
+ ## Core Symfony principles
44
+
45
+ - Follow Symfony conventions unless the project explicitly does otherwise.
46
+ - Keep controllers thin — delegate to services.
47
+ - Rely on autowiring + autoconfigure unless the project has explicit bindings.
48
+ - Prefer attributes over annotations on 6.x+; keep annotations only if the codebase still uses them.
49
+ - Use service IDs by FQCN — `App\Service\Foo`, not custom string IDs.
50
+ - Services are private by default; do not flip `public: true` to make tests pass.
51
+ - Do not bypass the container with `new` on classes that have collaborators.
52
+
53
+ ## HTTP layer rules
54
+
55
+ - Controllers:
56
+ - extend `AbstractController` only when the project does
57
+ - accept `Request` or a DTO; delegate business logic; return a `Response` variant
58
+ - Use `#[Route]` attributes on 6.x+; YAML routes only where the project already does.
59
+ - Use `#[MapRequestPayload]` / `#[MapQueryString]` (7.x+) for request DTOs when the project uses them.
60
+ - Validate via Symfony Validator on the DTO, not inline in the controller.
61
+ - Use `ParamConverter` / argument resolvers for entities only when the project uses them.
62
+
63
+ ## Validation rules
64
+
65
+ - Symfony Validator with constraints on DTOs / entities.
66
+ - Prefer attribute constraints (`#[Assert\NotBlank]`, `#[Assert\Email]`) on 6.x+.
67
+ - Render errors from `ConstraintViolationListInterface` — never compose error arrays by hand.
68
+ - Validation is declarative; do not put domain validation in entity setters.
69
+
70
+ ## Service layer and DI rules
71
+
72
+ - One responsibility per service; constructor injection.
73
+ - Interfaces when there are multiple implementations or the boundary is mocked.
74
+ - Tagged services for collecting implementations — `#[AutoconfigureTag]` or YAML tags, never an injected array of FQCNs.
75
+ - Decorators via `#[AsDecorator]` (6.1+); respect priority.
76
+ - Compiler passes only when wiring cannot be expressed via attributes/YAML.
77
+ - Do not call `Container::get` in application code.
78
+
79
+ ## Routing rules
80
+
81
+ - Follow the existing organization — attributes on controllers, or YAML in `config/routes/`.
82
+ - Route names: `<resource>_<action>` (`user_show`, `invoice_list`).
83
+ - `#[IsGranted]`, `#[RateLimit]` at the route level, not inside the controller body.
84
+ - `requirements:` for path parameter constraints; do not validate in the controller.
85
+
86
+ ## Response rules
87
+
88
+ - Match the project's response style: Twig, `JsonResponse`, API Platform, or redirects with flash.
89
+ - For APIs: consistent status codes; `ConstraintViolationList` → `application/problem+json`; DTOs / serializer groups, not raw entities.
90
+ - Do not return entities directly unless the project consistently does that.
91
+
92
+ ## Messenger and async work
93
+
94
+ - Messenger for async/deferred work; one message class per intent.
95
+ - Handlers: `MessageHandlerInterface` (5.x) or `#[AsMessageHandler]` (6.x+).
96
+ - Route via `framework.messenger.routing` in `config/packages/messenger.yaml`.
97
+ - Configure `failure_transport` explicitly — without it, failed messages disappear.
98
+ - Pass IDs, not entities; the consumer re-fetches.
99
+
100
+ ## Events and subscribers
101
+
102
+ - `#[AsEventListener]` (6.1+) or `EventSubscriberInterface` — match the project's convention.
103
+ - Past-tense event names (`UserRegistered`, `OrderPaid`); one side-effect per subscriber.
104
+ - Respect priority on `kernel.request` / `kernel.response` — wrong priority is a frequent bug source.
105
+
106
+ ## Security, voters, authorization
107
+
108
+ - One firewall per surface in `config/packages/security.yaml` (main, API, admin).
109
+ - Voters for object-level permissions; never role checks in templates or controllers.
110
+ - `#[IsGranted]` on actions; `$this->isGranted()` only when the result drives downstream logic.
111
+ - Stateless APIs: token-based authenticator, not form-login.
112
+
113
+ ## Config and environment
114
+
115
+ - Read via `ParameterBagInterface` or `#[Autowire(param: ...)]` — never `$_ENV` directly.
116
+ - New env vars in `.env` (+ `.env.test`); production values in deployment config.
117
+ - Bundle config under `config/packages/<bundle>.yaml`; env overrides under `config/packages/<env>/`.
118
+
119
+ ## Doctrine and persistence
120
+
121
+ - Doctrine ORM unless the project uses DBAL/raw SQL by convention.
122
+ - Repositories for non-trivial queries; no inline QueryBuilder in controllers/services.
123
+ - N+1 awareness: fetch joins via `addSelect` or `EAGER` when always needed.
124
+ - Transactions via `EntityManager::wrapInTransaction()` for multi-write atomicity.
125
+ - Lifecycle hooks (`PreFlush`, `PostUpdate`) — no domain logic there unless the project already does.
126
+
127
+ ## Migrations
128
+
129
+ - Generate via `doctrine:migrations:diff`; review before commit.
130
+ - Reversible — implement `up()` and `down()`.
131
+ - One concern per migration; destructive prod changes split into expand → migrate → contract.
132
+
133
+ ## Twig
134
+
135
+ - Templates are dumb — presentation only; pre-computed view models from the controller/service.
136
+ - Reuse via `{% extends %}` / `{% include %}` / macros.
137
+ - Auto-escape on; `|raw` only when content is provably safe.
138
+
139
+ ## Bundles and compiler passes
140
+
141
+ - Bundles are for reusable, redistributable code — not "another folder".
142
+ - Compiler passes only when wiring cannot be expressed via attributes/YAML.
143
+
144
+ ## Console commands
145
+
146
+ - `#[AsCommand]` (6.x+); one command class per intent; constructor injection.
147
+ - Long-running: `--limit`, `--time-limit`, graceful `SIGTERM` shutdown.
148
+ - Output via `OutputInterface` — never `echo`.
149
+
150
+ ## Output format
151
+
152
+ 1. Symfony code following framework conventions and project architecture.
153
+ 2. All related files (controller, service, DTO, repository, test, config) as needed.
154
+ 3. Schema changes — migration file plus updated entity/mapping.
155
+
156
+ ## Do NOT
157
+
158
+ - Business logic in controllers, entities, listeners, or Twig.
159
+ - Bypass the container with `new` on classes with collaborators.
160
+ - `$_ENV` / `$_SERVER` direct access — go through the parameter bag.
161
+ - Return Doctrine entities from an API endpoint — use DTOs or serializer groups.
162
+ - Silently swallow Messenger failures — route to a failure transport.
163
+ - Flip services `public: true` to make tests pass — use the test container.
164
+ - Pass entities through Messenger — pass IDs.
165
+ - Mix attribute and YAML routing for the same controller surface.
166
+
167
+ ## Gotcha
168
+
169
+ - Autowiring fails silently when two implementations exist without explicit binding — read the error, don't just flip `public: true`.
170
+ - `#[IsGranted]` is a no-op if the controller is not a service (autoconfigure handles it by default).
171
+ - Messenger `failure_transport` is opt-in; without it, failures vanish.
172
+ - Compiled container changes need `cache:clear` in `prod` before debugging "config not applied".
173
+ - Symfony 7.x removed deprecated APIs — verify `composer.lock` before assuming 6.x patterns work.
@@ -23,6 +23,7 @@ from .hooks.builtin import (
23
23
  MemoryVisibilityHook,
24
24
  StateShapeValidationHook,
25
25
  TraceHook,
26
+ build_decision_gate_hook,
26
27
  )
27
28
  from .hooks.settings import HookSettings, load_hook_settings
28
29
 
@@ -58,6 +59,9 @@ def _build_hook_registry(args: argparse.Namespace) -> HookRegistry:
58
59
  DirectiveSetGuardHook().register(registry)
59
60
  if settings.decision_trace:
60
61
  DecisionTraceHook().register(registry)
62
+ gate_hook = build_decision_gate_hook(settings.decision_engine)
63
+ if gate_hook is not None:
64
+ gate_hook.register(registry)
61
65
  if settings.memory_visibility:
62
66
  MemoryVisibilityHook(
63
67
  cost_profile=settings.cost_profile,
@@ -13,6 +13,7 @@ from __future__ import annotations
13
13
 
14
14
  from .chat_history_append import ChatHistoryAppendHook
15
15
  from .chat_history_halt_append import ChatHistoryHaltAppendHook
16
+ from .decision_gate import DecisionGateHook, build_decision_gate_hook
16
17
  from .decision_trace import DecisionTraceHook
17
18
  from .directive_set_guard import DirectiveSetGuardHook
18
19
  from .halt_surface_audit import HaltSurfaceAuditHook
@@ -23,10 +24,12 @@ from .trace import TraceHook
23
24
  __all__ = [
24
25
  "ChatHistoryAppendHook",
25
26
  "ChatHistoryHaltAppendHook",
27
+ "DecisionGateHook",
26
28
  "DecisionTraceHook",
27
29
  "DirectiveSetGuardHook",
28
30
  "HaltSurfaceAuditHook",
29
31
  "MemoryVisibilityHook",
30
32
  "StateShapeValidationHook",
31
33
  "TraceHook",
34
+ "build_decision_gate_hook",
32
35
  ]