forgedev 1.1.0 → 1.1.3

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 (31) hide show
  1. package/README.md +79 -7
  2. package/bin/devforge.js +10 -1
  3. package/package.json +1 -1
  4. package/src/claude-configurator.js +1 -0
  5. package/src/cli.js +11 -0
  6. package/src/doctor-prompts.js +9 -2
  7. package/src/doctor.js +19 -0
  8. package/src/index.js +7 -0
  9. package/src/update-check.js +49 -0
  10. package/src/update.js +33 -0
  11. package/templates/auth/jwt-custom/backend/app/core/security.py.template +4 -1
  12. package/templates/backend/fastapi/backend/app/core/config.py.template +2 -2
  13. package/templates/claude-code/agents/build-error-resolver.md +2 -3
  14. package/templates/claude-code/agents/database-reviewer.md +1 -1
  15. package/templates/claude-code/agents/doc-updater.md +1 -1
  16. package/templates/claude-code/agents/loop-operator.md +1 -2
  17. package/templates/claude-code/agents/uat-validator.md +2 -1
  18. package/templates/claude-code/claude-md/base.md +2 -2
  19. package/templates/claude-code/commands/build-fix.md +1 -1
  20. package/templates/claude-code/commands/code-review.md +1 -2
  21. package/templates/claude-code/commands/full-audit.md +60 -0
  22. package/templates/claude-code/commands/workflows.md +1 -0
  23. package/templates/claude-code/hooks/scripts/autofix-polyglot.mjs +12 -4
  24. package/templates/claude-code/hooks/scripts/autofix-python.mjs +11 -3
  25. package/templates/claude-code/hooks/scripts/autofix-typescript.mjs +11 -3
  26. package/templates/claude-code/skills/ai-prompts/SKILL.md +1 -0
  27. package/templates/claude-code/skills/fastapi/SKILL.md +1 -1
  28. package/templates/claude-code/skills/git-workflow/SKILL.md +1 -1
  29. package/templates/claude-code/skills/playwright/SKILL.md +2 -2
  30. package/templates/claude-code/skills/security-api/SKILL.md +2 -2
  31. package/templates/database/sqlalchemy-postgres/.env.example +1 -0
package/README.md CHANGED
@@ -16,6 +16,9 @@ npx forgedev init
16
16
 
17
17
  # Diagnose and optimize existing project
18
18
  npx forgedev doctor
19
+
20
+ # Check for updates
21
+ npx forgedev update
19
22
  ```
20
23
 
21
24
  ## Four Modes, Four Audiences
@@ -174,14 +177,51 @@ Every project includes:
174
177
 
175
178
  With Claude Code infrastructure enabled (default):
176
179
 
177
- - **CLAUDE.md** tailored to your stack
178
- - **Hooks** — auto-lint on edit, quality gate on stop
179
- - **Skills** — framework-specific knowledge
180
- - **Agents** — 5-agent verification chain
181
- - **Commands** — workflows, status, next, done, verify-all, audit-spec, audit-wiring, audit-security, pre-pr, run-uat, generate-prd, generate-uat, optimize-claude-md
180
+ - **CLAUDE.md** tailored to your stack (with pitfalls and agents quick-reference)
181
+ - **Hooks** — cross-platform Node.js `.mjs` hooks (auto-lint on edit, quality gate, protected file guard)
182
+ - **17 Agents** — verification, development, review, and orchestration (see below)
183
+ - **20 Commands** — daily workflow, verification, release, development, session management
184
+ - **8 Skills** — framework-specific + universal knowledge
182
185
  - **UAT templates** — scenario packs and CSV checklists
183
186
  - **Prompt library** — the complete development prompt library
184
187
 
188
+ ## Agents (17)
189
+
190
+ Every scaffolded project gets these agents in `.claude/agents/`:
191
+
192
+ | Agent | Role | Access |
193
+ |-------|------|--------|
194
+ | `architect` | System design, data models, API contracts | Read-only |
195
+ | `build-error-resolver` | Fix build/lint/type errors with minimal changes | Write |
196
+ | `chief-of-staff` | Orchestrate multiple agents for complex tasks | Write |
197
+ | `code-quality-reviewer` | Code quality review | Read-only |
198
+ | `database-reviewer` | Query optimization, schema review, N+1 detection | Read-only |
199
+ | `doc-updater` | Keep docs in sync with code changes | Write |
200
+ | `docs-lookup` | Search framework docs for answers | Read-only |
201
+ | `e2e-runner` | Generate and run Playwright E2E tests | Write |
202
+ | `harness-optimizer` | Audit Claude Code setup, suggest optimizations | Read-only |
203
+ | `loop-operator` | Autonomous improvement loops with stop conditions | Write |
204
+ | `planner` | Create implementation plans before coding | Read-only |
205
+ | `production-readiness` | Production deployment readiness review | Read-only |
206
+ | `refactor-cleaner` | Dead code removal, duplicate elimination | Write |
207
+ | `security-reviewer` | Security audit | Read-only |
208
+ | `spec-validator` | Validate implementation matches specification | Read-only |
209
+ | `tdd-guide` | Enforce RED-GREEN-REFACTOR TDD cycle | Write |
210
+ | `uat-validator` | QA validation of UAT scenarios | Read-only |
211
+
212
+ ## Skills (8)
213
+
214
+ | Skill | Scope |
215
+ |-------|-------|
216
+ | `nextjs` | Next.js 15 App Router patterns |
217
+ | `fastapi` | FastAPI + SQLAlchemy 2.0 + Pydantic v2 |
218
+ | `playwright` | Playwright E2E testing |
219
+ | `security-web` | Web application security |
220
+ | `security-api` | API security |
221
+ | `ai-prompts` | AI/LLM integration patterns |
222
+ | `git-workflow` | Git branching, commits, PR workflow (universal) |
223
+ | `testing-patterns` | Test pyramid, AAA pattern, mocking (universal) |
224
+
185
225
  ## Development
186
226
 
187
227
  ```bash
@@ -190,6 +230,7 @@ npm test # run unit tests
190
230
  node bin/devforge.js test-output # manual smoke test (guided + developer)
191
231
  node bin/devforge.js init # test init mode (from any project dir)
192
232
  node bin/devforge.js doctor # test doctor mode (from any project dir)
233
+ node bin/devforge.js update # check for updates
193
234
  ```
194
235
 
195
236
  ## Project Structure
@@ -198,7 +239,7 @@ node bin/devforge.js doctor # test doctor mode (from any project dir)
198
239
  devforge/
199
240
  ├── bin/devforge.js # CLI entry point
200
241
  ├── src/
201
- │ ├── cli.js # Command router (new, init, doctor)
242
+ │ ├── cli.js # Command router (new, init, doctor, update)
202
243
  │ ├── index.js # New project orchestrator (guided + developer)
203
244
  │ ├── guided.js # Guided mode (description → stack)
204
245
  │ ├── prompts.js # Interactive prompts (Inquirer.js)
@@ -211,6 +252,8 @@ devforge/
211
252
  │ ├── doctor.js # Doctor mode orchestrator
212
253
  │ ├── doctor-checks.js # Diagnostic check functions
213
254
  │ ├── doctor-prompts.js # Fix prompt generators
255
+ │ ├── update-check.js # npm registry version check
256
+ │ ├── update.js # Update command handler
214
257
  │ └── utils.js # File ops, logging, colors
215
258
  ├── templates/ # Scaffold templates by category
216
259
  │ ├── base/ # Every project gets this
@@ -225,26 +268,55 @@ devforge/
225
268
  └── docs/ # Reference documentation
226
269
  ```
227
270
 
228
- ## Claude Code Commands
271
+ ## Claude Code Commands (20)
229
272
 
230
273
  After running `npx forgedev init`, these slash commands are available inside Claude Code:
231
274
 
275
+ **Daily Workflow:**
276
+
232
277
  | Command | What It Does |
233
278
  |---------|-------------|
234
279
  | `/workflows` | Lists all available workflows |
235
280
  | `/status` | Project dashboard — tests, branch, changes |
236
281
  | `/next` | Figures out your next task |
237
282
  | `/done` | Verifies task completion |
283
+
284
+ **Verification:**
285
+
286
+ | Command | What It Does |
287
+ |---------|-------------|
238
288
  | `/verify-all` | Runs lint, type check, tests, then launches reviewers |
289
+ | `/full-audit` | Runs every audit and review agent in a single pass |
239
290
  | `/audit-spec` | Validates implementation against a spec/PRD |
240
291
  | `/audit-wiring` | Finds dead or unwired features |
241
292
  | `/audit-security` | Runs a security audit |
293
+ | `/code-review` | Reviews uncommitted changes for security and quality |
294
+
295
+ **Release:**
296
+
297
+ | Command | What It Does |
298
+ |---------|-------------|
242
299
  | `/pre-pr` | Runs the complete pre-PR checklist |
243
300
  | `/run-uat` | Executes UAT scenarios |
301
+
302
+ **Development:**
303
+
304
+ | Command | What It Does |
305
+ |---------|-------------|
306
+ | `/plan` | Invoke planner agent for implementation planning |
307
+ | `/build-fix` | Incrementally fix build/lint/type errors |
308
+ | `/tdd` | Enforce test-driven development cycle |
244
309
  | `/generate-prd` | Generates a PRD with Mermaid diagrams |
245
310
  | `/generate-uat` | Generates UAT scenarios from codebase |
246
311
  | `/optimize-claude-md` | Proposes splitting an oversized CLAUDE.md |
247
312
 
313
+ **Session:**
314
+
315
+ | Command | What It Does |
316
+ |---------|-------------|
317
+ | `/save-session` | Save work context for later resumption |
318
+ | `/resume-session` | Load saved session and continue where you left off |
319
+
248
320
  ## Install
249
321
 
250
322
  ```bash
package/bin/devforge.js CHANGED
@@ -1,4 +1,13 @@
1
1
  #!/usr/bin/env node
2
2
  import { parseCommand } from '../src/cli.js';
3
3
 
4
- parseCommand(process.argv.slice(2));
4
+ try {
5
+ await parseCommand(process.argv.slice(2));
6
+ } catch (err) {
7
+ // Graceful exit on Ctrl+C / prompt cancellation
8
+ if (err?.name === 'ExitPromptError' || err?.code === 'ERR_USE_AFTER_CLOSE') {
9
+ console.log('');
10
+ process.exit(0);
11
+ }
12
+ throw err;
13
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "forgedev",
3
- "version": "1.1.0",
3
+ "version": "1.1.3",
4
4
  "description": "Universal, AI-first project scaffolding CLI with Claude Code infrastructure",
5
5
  "type": "module",
6
6
  "bin": {
@@ -260,6 +260,7 @@ function generateCommands(outputDir, config, vars) {
260
260
  'tdd.md',
261
261
  'save-session.md',
262
262
  'resume-session.md',
263
+ 'full-audit.md',
263
264
  ];
264
265
 
265
266
  for (const cmd of commands) {
package/src/cli.js CHANGED
@@ -46,6 +46,12 @@ export async function parseCommand(args) {
46
46
  return;
47
47
  }
48
48
 
49
+ if (command === 'update') {
50
+ const { runUpdate } = await import('./update.js');
51
+ await runUpdate();
52
+ return;
53
+ }
54
+
49
55
  // Shorthand: devforge my-app → devforge new my-app
50
56
  if (!command.startsWith('-')) {
51
57
  const targetDir = path.resolve(process.cwd(), command);
@@ -73,6 +79,7 @@ function showUsage() {
73
79
  devforge new <name> Create a new project
74
80
  devforge init Add dev guardrails to current project
75
81
  devforge doctor Diagnose and optimize current project
82
+ devforge update Check for newer version
76
83
  devforge <name> Shorthand for ${chalk.dim('devforge new <name>')}
77
84
 
78
85
  ${chalk.bold('Options:')}
@@ -105,6 +112,10 @@ function showHelp() {
105
112
  flaky tests, dead code, duplicate code, and more.
106
113
  Generates Claude Code prompts to fix each issue.
107
114
 
115
+ ${chalk.bold('devforge update')}
116
+ Check if a newer version of DevForge is available.
117
+ Shows upgrade instructions if an update exists.
118
+
108
119
  ${chalk.bold('Supported stacks (V1):')}
109
120
  - Next.js full-stack (TypeScript + Prisma + PostgreSQL)
110
121
  - FastAPI backend (Python + SQLAlchemy + PostgreSQL)
@@ -176,6 +176,15 @@ ${fileList}
176
176
 
177
177
  Extract all prompts into a dedicated prompts file (e.g., src/lib/prompts.ts or prompts/). This makes prompts easier to version, A/B test, and iterate on without changing application code.`;
178
178
  },
179
+
180
+ DEVFORGE_UPDATE: (issue) => {
181
+ return `A newer version of DevForge is available.
182
+
183
+ Run: npm install -g forgedev@latest
184
+ Then re-run: npx forgedev init
185
+
186
+ This will update your project's agents, commands, skills, and hooks to the latest version.`;
187
+ },
179
188
  };
180
189
 
181
190
  export function generatePrompt(issue) {
@@ -223,8 +232,6 @@ export function generateReport(issues, projectName) {
223
232
  const critical = issues.filter(i => i.severity === 'critical');
224
233
  const warnings = issues.filter(i => i.severity === 'warning');
225
234
  const info = issues.filter(i => i.severity === 'info');
226
- const healthy = []; // Could be populated by passing in good checks
227
-
228
235
  let report = `# DevForge Doctor Report — ${projectName}
229
236
  Generated: ${new Date().toISOString().split('T')[0]}
230
237
 
package/src/doctor.js CHANGED
@@ -29,6 +29,25 @@ export async function runDoctor(projectDir) {
29
29
  // Run all checks
30
30
  const issues = runAllChecks(projectDir, scan);
31
31
 
32
+ // Check for DevForge updates (5s timeout, won't crash on failure)
33
+ try {
34
+ const { checkForUpdate } = await import('./update-check.js');
35
+ const updateResult = await checkForUpdate();
36
+ if (updateResult?.updateAvailable) {
37
+ issues.push({
38
+ severity: 'info',
39
+ title: `DevForge update available: ${updateResult.current} → ${updateResult.latest}`,
40
+ impact: 'Newer version may include improved agents, commands, and bug fixes',
41
+ files: [],
42
+ autoFixable: false,
43
+ promptId: 'DEVFORGE_UPDATE',
44
+ effort: 'quick',
45
+ });
46
+ }
47
+ } catch {
48
+ // Silently ignore — network issues shouldn't block doctor
49
+ }
50
+
32
51
  if (issues.length === 0) {
33
52
  console.log(chalk.green(' ✓ Your project looks healthy! No issues found.'));
34
53
  console.log('');
package/src/index.js CHANGED
@@ -11,6 +11,13 @@ import { generateUAT } from './uat-generator.js';
11
11
 
12
12
  export async function runNew(projectName) {
13
13
  const safeName = toKebabCase(projectName);
14
+
15
+ // Prevent path traversal — project name must not escape cwd
16
+ if (/[\/\\]/.test(safeName) || safeName.includes('..')) {
17
+ log.error('Project name must not contain path separators or ".."');
18
+ process.exit(1);
19
+ }
20
+
14
21
  const outputDir = path.resolve(process.cwd(), safeName);
15
22
 
16
23
  if (fs.existsSync(outputDir)) {
@@ -0,0 +1,49 @@
1
+ import fs from 'node:fs';
2
+
3
+ const PACKAGE_NAME = 'forgedev';
4
+
5
+ /**
6
+ * Compare two semver strings (major.minor.patch).
7
+ * Returns 1 if a > b, -1 if a < b, 0 if equal.
8
+ */
9
+ export function compareVersions(a, b) {
10
+ const pa = a.split('.').map(Number);
11
+ const pb = b.split('.').map(Number);
12
+ for (let i = 0; i < 3; i++) {
13
+ if ((pa[i] || 0) > (pb[i] || 0)) return 1;
14
+ if ((pa[i] || 0) < (pb[i] || 0)) return -1;
15
+ }
16
+ return 0;
17
+ }
18
+
19
+ /**
20
+ * Check npm registry for a newer version of forgedev.
21
+ * Returns { current, latest, updateAvailable } or null on failure.
22
+ */
23
+ export async function checkForUpdate() {
24
+ const pkg = JSON.parse(
25
+ fs.readFileSync(new URL('../package.json', import.meta.url), 'utf-8')
26
+ );
27
+ const currentVersion = pkg.version;
28
+
29
+ try {
30
+ const response = await fetch(
31
+ `https://registry.npmjs.org/${PACKAGE_NAME}/latest`,
32
+ { signal: AbortSignal.timeout(5000) }
33
+ );
34
+ if (!response.ok) return null;
35
+ const data = await response.json();
36
+ const latestVersion = data.version;
37
+
38
+ // Validate version format before trusting registry response
39
+ if (!/^\d+\.\d+\.\d+/.test(latestVersion)) return null;
40
+
41
+ return {
42
+ current: currentVersion,
43
+ latest: latestVersion,
44
+ updateAvailable: compareVersions(latestVersion, currentVersion) > 0,
45
+ };
46
+ } catch {
47
+ return null;
48
+ }
49
+ }
package/src/update.js ADDED
@@ -0,0 +1,33 @@
1
+ import chalk from 'chalk';
2
+ import { log } from './utils.js';
3
+ import { checkForUpdate } from './update-check.js';
4
+
5
+ export async function runUpdate() {
6
+ console.log('');
7
+ console.log(chalk.bold.cyan(' DevForge') + chalk.dim(' — Checking for updates...'));
8
+ console.log('');
9
+
10
+ const result = await checkForUpdate();
11
+
12
+ if (result === null) {
13
+ log.warn(' Could not reach the npm registry. Check your internet connection.');
14
+ console.log('');
15
+ return;
16
+ }
17
+
18
+ if (!result.updateAvailable) {
19
+ log.success(` ✓ You're on the latest version (${result.current})`);
20
+ console.log('');
21
+ return;
22
+ }
23
+
24
+ log.warn(` Update available: ${result.current} → ${result.latest}`);
25
+ console.log('');
26
+ console.log(' To update:');
27
+ console.log(` ${chalk.bold('npm install -g forgedev@latest')} ${chalk.dim('(if installed globally)')}`);
28
+ console.log(` ${chalk.bold('npx forgedev@latest new my-app')} ${chalk.dim('(one-time use)')}`);
29
+ console.log('');
30
+ log.dim(' To update an existing project\'s Claude Code infrastructure:');
31
+ log.dim(' cd my-project && npx forgedev@latest init');
32
+ console.log('');
33
+ }
@@ -1,3 +1,4 @@
1
+ import os
1
2
  from datetime import datetime, timedelta, timezone
2
3
 
3
4
  from jose import JWTError, jwt
@@ -7,7 +8,9 @@ from app.core.config import settings
7
8
 
8
9
  pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
9
10
 
10
- SECRET_KEY = "change-me-in-production" # TODO: Move to settings/env
11
+ SECRET_KEY = os.environ.get("JWT_SECRET_KEY")
12
+ if not SECRET_KEY:
13
+ raise RuntimeError("JWT_SECRET_KEY environment variable is required. Set it in your .env file.")
11
14
  ALGORITHM = "HS256"
12
15
  ACCESS_TOKEN_EXPIRE_MINUTES = 30
13
16
 
@@ -6,8 +6,8 @@ class Settings(BaseSettings):
6
6
  app_name: str = "{{PROJECT_NAME_PASCAL}}"
7
7
  debug: bool = False
8
8
 
9
- # Database
10
- database_url: str = "postgresql+asyncpg://postgres:postgres@localhost:5432/{{PROJECT_NAME_SNAKE}}"
9
+ # Database — no default: must be set via .env or environment
10
+ database_url: str
11
11
 
12
12
  # CORS
13
13
  cors_origins: list[str] = ["http://localhost:3000"]
@@ -8,9 +8,8 @@ You are a build error resolution specialist. Your job is to fix build/type/lint
8
8
 
9
9
  1. **Collect errors** — Run `{{BUILD_COMMAND}}`, `{{LINT_COMMAND}}`, and `{{TYPE_CHECK_COMMAND}}` to capture all errors
10
10
  2. **Group by file** — Sort errors by file path, fix in dependency order (imports/types before logic)
11
- 3. **Fix one at a time** — Read the file, diagnose root cause, apply minimal edit, re-run build
12
- 4. **Verify** — After each fix, confirm the error is gone and no new errors were introduced
13
-
11
+ 3. **Fix one error at a time** — Read the file, diagnose root cause, apply minimal edit
12
+ 4. **Verify** — After each fix, re-run all three commands to confirm the error is gone and no new errors were introduced
14
13
  ## Common Fix Patterns
15
14
 
16
15
  | Error Type | Fix |
@@ -19,7 +19,7 @@ You are a database specialist. Your job is to review database code for performan
19
19
  - [ ] Transactions are short-lived (no long-running transactions)
20
20
 
21
21
  ### Schema Design
22
- - [ ] Primary keys use UUID or serial (not random values that fragment indexes)
22
+ - [ ] Primary keys use sequential identifiers (SERIAL, BIGSERIAL, UUIDv7) to avoid index fragmentation
23
23
  - [ ] Foreign keys have indexes
24
24
  - [ ] Timestamps use timezone-aware types (`timestamptz` not `timestamp`)
25
25
  - [ ] Nullable columns have explicit defaults or are intentionally nullable
@@ -6,7 +6,7 @@ You are a documentation specialist. Your job is to keep project documentation ac
6
6
 
7
7
  ## Workflow
8
8
 
9
- 1. **Detect changes** — Run `git diff --name-only HEAD~1` to see what changed
9
+ 1. **Detect changes** — Run `git diff --name-only HEAD~1` to see files changed in the last commit
10
10
  2. **Identify affected docs** — Map code changes to documentation that needs updating
11
11
  3. **Update docs** — Edit README, API docs, changelogs, and inline comments
12
12
  4. **Verify links** — Check that all referenced files and endpoints still exist
@@ -14,8 +14,7 @@ Execute iterative improvement loops safely: run a sequence of checks → fixes
14
14
  2. **Set stop conditions** — Define when to stop (all tests pass, zero lint errors, or max 5 iterations)
15
15
  3. **Execute iteration** — Fix one category of issues per iteration
16
16
  4. **Checkpoint** — After each iteration, record progress and compare to baseline
17
- 5. **Evaluate** — If progress stalled (same errors as last iteration), stop and report
18
- 6. **Report** — Show baseline vs final state with concrete numbers
17
+ 5. **Evaluate** — If no progress across 2 consecutive iterations, stop and report6. **Report** — Show baseline vs final state with concrete numbers
19
18
 
20
19
  ## Stop Conditions (halt the loop if any are true)
21
20
 
@@ -16,7 +16,8 @@ Read-only. Never modify code.
16
16
  a. Verify the feature exists in the codebase
17
17
  b. Check if there's a corresponding automated test
18
18
  c. If automated test exists, verify it covers the scenario's steps
19
- d. Flag gaps: scenarios without tests, tests without scenarios
19
+ d. Flag scenarios without automated tests
20
+ 3. Scan test files to identify orphaned tests (tests without corresponding UAT scenarios)
20
21
 
21
22
  ## Output: Traceability Matrix
22
23
 
@@ -14,7 +14,7 @@
14
14
  ## RULES
15
15
  - Never commit `.env` files or secrets
16
16
  - Never modify migration files directly — generate new migrations instead
17
- - All API responses use structured error format: `{ error: { code, message } }`
17
+ - All API responses use structured error format: `{ "error": { "code": "ERR_CODE", "message": "..." } }`
18
18
  - Never leak stack traces to clients
19
19
  - Health check endpoints must always be available
20
20
  - Write tests for new features before marking them complete
@@ -23,7 +23,7 @@
23
23
 
24
24
  ## Pitfalls
25
25
  - Never commit lock file merge conflicts — delete and regenerate
26
- - Never use `any` type — use `unknown` and narrow with type guards
26
+ - Never use loose types (`any` in TS, `Any` in Python) — use strict types and narrow explicitly
27
27
  - Never hardcode URLs, ports, or credentials — use environment variables
28
28
  - Never catch errors silently — always log or re-throw
29
29
  - Never push directly to main — always use feature branches
@@ -22,7 +22,7 @@ For each error:
22
22
  1. Read the file to see error context
23
23
  2. Diagnose the root cause (missing import, wrong type, syntax error)
24
24
  3. Apply the smallest possible fix
25
- 4. Re-run the build to verify the error is gone
25
+ 4. Re-run all three commands (build, lint, type check) to confirm the error is gone and no new errors were introduced
26
26
  5. Move to the next error
27
27
 
28
28
  ## Step 4: Guardrails
@@ -33,11 +33,10 @@ For each changed file, check:
33
33
  ## Step 3: Generate Report
34
34
 
35
35
  For each issue found:
36
- - **Severity**: CRITICAL, HIGH, MEDIUM, LOW
36
+ - **Severity**: CRITICAL, HIGH, MEDIUM
37
37
  - **File**: path and line number
38
38
  - **Issue**: what's wrong
39
39
  - **Fix**: how to fix it
40
-
41
40
  ## Step 4: Verdict
42
41
 
43
42
  - If CRITICAL issues found → block commit, list required fixes
@@ -0,0 +1,60 @@
1
+ Run every audit and review agent in a single pass. Use this when you want a comprehensive project health check.
2
+
3
+ ## Step 1: Build + Lint + Tests
4
+
5
+ 1. Run lint: `{{LINT_COMMAND}}`
6
+ 2. Run type check: `{{TYPE_CHECK_COMMAND}}`
7
+ 3. Run tests: `{{TEST_COMMAND}}`
8
+
9
+ If any step fails, report the failures but continue with the remaining audits.
10
+
11
+ ## Step 2: Code Review (changed files)
12
+
13
+ 1. Get changed files: `git diff --name-only HEAD`
14
+ 2. For each changed file, check for:
15
+ - Hardcoded credentials, API keys, tokens
16
+ - SQL injection, XSS, path traversal
17
+ - Functions > 50 lines, files > 800 lines
18
+ - Missing error handling, console.log left in
19
+ - Missing tests for new code
20
+
21
+ ## Step 3: Launch Review Agents
22
+
23
+ Run these agents in sequence on the full codebase:
24
+
25
+ 1. **code-quality-reviewer** — code patterns, duplication, naming
26
+ 2. **security-reviewer** — vulnerabilities, secrets, unsafe operations
27
+ 3. **production-readiness** — deployment readiness, error handling, health checks
28
+ 4. **database-reviewer** — query performance, N+1, schema issues (skip if no database)
29
+
30
+ ## Step 4: Structural Audits
31
+
32
+ 1. **Wiring audit** — verify all API endpoints are connected between frontend and backend
33
+ 2. **Spec audit** — if `docs/` contains a spec/PRD, validate implementation coverage
34
+
35
+ ## Step 5: Claude Code Setup
36
+
37
+ 1. **harness-optimizer** — check if .claude/ setup follows best practices
38
+
39
+ ## Step 6: Summary Report
40
+
41
+ Compile all findings into a single report grouped by severity:
42
+
43
+ ```
44
+ CRITICAL (must fix before merge):
45
+ - [list]
46
+
47
+ HIGH (fix soon):
48
+ - [list]
49
+
50
+ MEDIUM (improve when possible):
51
+ - [list]
52
+
53
+ LOW (nice to have):
54
+ - [list]
55
+
56
+ PASSED:
57
+ - [list of checks that found no issues]
58
+ ```
59
+
60
+ Include total counts: X critical, Y high, Z medium, W low.
@@ -15,6 +15,7 @@ Show the developer what workflows are available.
15
15
 
16
16
  ### Verification
17
17
  - `/verify-all` — Run lint, type check, tests, then launch all reviewers
18
+ - `/full-audit` — Run every audit and review agent in a single pass
18
19
  - `/audit-spec` — Validate implementation against a spec/PRD
19
20
  - `/audit-wiring` — Find dead or unwired features
20
21
  - `/audit-security` — Run a security audit
@@ -1,7 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
  // Auto-fix lint issues on saved TypeScript or Python files (polyglot)
3
3
 
4
- import { execSync } from 'node:child_process';
4
+ import { execFileSync } from 'node:child_process';
5
+ import { resolve } from 'node:path';
5
6
 
6
7
  let input = '';
7
8
  process.stdin.setEncoding('utf8');
@@ -11,19 +12,26 @@ process.stdin.on('end', () => {
11
12
  const data = JSON.parse(input);
12
13
  const filePath = data?.tool_input?.file_path || '';
13
14
 
14
- if (!filePath) {
15
+ if (!filePath || filePath.includes('..')) {
16
+ process.exit(0);
17
+ }
18
+
19
+ // Ensure path stays within the working directory
20
+ const resolved = resolve(filePath);
21
+ const cwd = resolve('.');
22
+ if (!resolved.startsWith(cwd)) {
15
23
  process.exit(0);
16
24
  }
17
25
 
18
26
  if (filePath.endsWith('.ts') || filePath.endsWith('.tsx')) {
19
27
  try {
20
- execSync(`npx eslint --fix "${filePath}"`, { stdio: 'pipe', cwd: 'frontend' });
28
+ execFileSync('npx', ['eslint', '--fix', filePath], { stdio: 'pipe', cwd: 'frontend' });
21
29
  } catch {
22
30
  // eslint may exit non-zero for unfixable issues — that's okay
23
31
  }
24
32
  } else if (filePath.endsWith('.py')) {
25
33
  try {
26
- execSync(`ruff check --fix "${filePath}"`, { stdio: 'pipe', cwd: 'backend' });
34
+ execFileSync('ruff', ['check', '--fix', filePath], { stdio: 'pipe', cwd: 'backend' });
27
35
  } catch {
28
36
  // ruff may exit non-zero for unfixable issues — that's okay
29
37
  }
@@ -1,7 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
  // Auto-fix lint issues on saved Python files
3
3
 
4
- import { execSync } from 'node:child_process';
4
+ import { execFileSync } from 'node:child_process';
5
+ import { resolve } from 'node:path';
5
6
 
6
7
  let input = '';
7
8
  process.stdin.setEncoding('utf8');
@@ -11,13 +12,20 @@ process.stdin.on('end', () => {
11
12
  const data = JSON.parse(input);
12
13
  const filePath = data?.tool_input?.file_path || '';
13
14
 
14
- if (!filePath) {
15
+ if (!filePath || filePath.includes('..')) {
16
+ process.exit(0);
17
+ }
18
+
19
+ // Ensure path stays within the working directory
20
+ const resolved = resolve(filePath);
21
+ const cwd = resolve('.');
22
+ if (!resolved.startsWith(cwd)) {
15
23
  process.exit(0);
16
24
  }
17
25
 
18
26
  if (filePath.endsWith('.py')) {
19
27
  try {
20
- execSync(`ruff check --fix "${filePath}"`, { stdio: 'pipe', cwd: 'backend' });
28
+ execFileSync('ruff', ['check', '--fix', filePath], { stdio: 'pipe', cwd: 'backend' });
21
29
  } catch {
22
30
  // ruff may exit non-zero for unfixable issues — that's okay
23
31
  }
@@ -1,7 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
  // Auto-fix lint issues on saved TypeScript files
3
3
 
4
- import { execSync } from 'node:child_process';
4
+ import { execFileSync } from 'node:child_process';
5
+ import { resolve } from 'node:path';
5
6
 
6
7
  let input = '';
7
8
  process.stdin.setEncoding('utf8');
@@ -11,13 +12,20 @@ process.stdin.on('end', () => {
11
12
  const data = JSON.parse(input);
12
13
  const filePath = data?.tool_input?.file_path || '';
13
14
 
14
- if (!filePath) {
15
+ if (!filePath || filePath.includes('..')) {
16
+ process.exit(0);
17
+ }
18
+
19
+ // Ensure path stays within the working directory
20
+ const resolved = resolve(filePath);
21
+ const cwd = resolve('.');
22
+ if (!resolved.startsWith(cwd)) {
15
23
  process.exit(0);
16
24
  }
17
25
 
18
26
  if (filePath.endsWith('.ts') || filePath.endsWith('.tsx')) {
19
27
  try {
20
- execSync(`npx eslint --fix "${filePath}"`, { stdio: 'pipe' });
28
+ execFileSync('npx', ['eslint', '--fix', filePath], { stdio: 'pipe' });
21
29
  } catch {
22
30
  // eslint may exit non-zero for unfixable issues — that's okay
23
31
  }
@@ -33,6 +33,7 @@ description: AI/LLM integration patterns and best practices
33
33
  ## Security
34
34
  - Never include user secrets in prompts
35
35
  - Sanitize user input before including in prompts
36
+ - Protect against prompt injection attacks (delimiter tokens, input validation, output filtering)
36
37
  - Validate and sanitize AI output before using
37
38
  - Don't trust AI output for security decisions
38
39
 
@@ -29,7 +29,7 @@ description: FastAPI + SQLAlchemy 2.0 + Pydantic v2 patterns
29
29
  - Raise `AppError` subclasses, never `HTTPException` with raw strings
30
30
  - Global exception handler catches unhandled errors
31
31
  - Never expose stack traces or internal details to clients
32
- - Use structured error format: `{ error: { code, message } }`
32
+ - Use structured error format: `{ "error": { "code": "ERR_CODE", "message": "Error description" } }`
33
33
 
34
34
  ## Testing
35
35
  - Use `httpx.AsyncClient` with `ASGITransport` for async tests
@@ -61,4 +61,4 @@ If rebase gets messy: `git rebase --abort` and start over.
61
61
  - Never commit `.env` files, credentials, or large binaries
62
62
  - Never rebase commits that have been pushed and shared
63
63
  - Never merge main into feature branches (rebase instead)
64
- - Always pull before pushing: `git pull --rebase origin main`
64
+ - Always pull before pushing: `git pull --rebase` (pulls current branch's upstream)
@@ -25,8 +25,8 @@ description: Playwright E2E testing patterns and best practices
25
25
 
26
26
  ## Common Patterns
27
27
  - Navigation: `await page.goto('/')` then assert page loaded
28
- - Form filling: `await page.fill('[name=email]', 'test@example.com')`
29
- - Clicking: `await page.click('button[type=submit]')` or `getByRole`
28
+ - Form filling: `await page.getByLabel('Email').fill('test@example.com')`
29
+ - Clicking: `await page.getByRole('button', { name: 'Submit' }).click()`
30
30
  - Waiting: prefer auto-waiting over explicit waits
31
31
  - Network: `page.waitForResponse()` for API-dependent tests
32
32
  - Authentication: use `storageState` for persistent auth across tests
@@ -16,7 +16,7 @@ description: API security best practices
16
16
  - Validate all input with Pydantic models
17
17
  - Set max lengths on string fields
18
18
  - Validate email formats, URLs, phone numbers
19
- - Reject unexpected fields (Pydantic does this by default)
19
+ - Reject unexpected fields (set `extra = "forbid"` in Pydantic model config)
20
20
  - Validate file uploads (size, type, extension)
21
21
 
22
22
  ## SQL Injection Prevention
@@ -38,7 +38,7 @@ description: API security best practices
38
38
  - Never expose stack traces to clients
39
39
  - Use generic error messages for auth failures
40
40
  - Log detailed errors server-side only
41
- - Return structured error responses: `{ error: { code, message } }`
41
+ - Return structured error responses: `{ "error": { "code": "ERR_CODE", "message": "Error description" } }`
42
42
 
43
43
  ## Secrets Management
44
44
  - Store secrets in environment variables, never in code
@@ -1 +1,2 @@
1
1
  DATABASE_URL="postgresql+asyncpg://postgres:postgres@localhost:5432/{{PROJECT_NAME_SNAKE}}"
2
+ JWT_SECRET_KEY="change-me-generate-a-random-secret"