forgedock 1.0.0 → 1.0.2

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 (42) hide show
  1. package/README.md +19 -2
  2. package/bin/forgedock.mjs +286 -10
  3. package/commands/analytics.md +129 -52
  4. package/commands/audit-agents.md +29 -5
  5. package/commands/audit.md +55 -17
  6. package/commands/autopilot.md +11 -6
  7. package/commands/cleanup.md +44 -24
  8. package/commands/deploy-info.md +7 -3
  9. package/commands/forge-stats.md +13 -4
  10. package/commands/forgedock-init.md +534 -0
  11. package/commands/geo-audit.md +114 -26
  12. package/commands/incident-response.md +4 -1
  13. package/commands/issue.md +26 -25
  14. package/commands/milestone.md +80 -59
  15. package/commands/orchestrate.md +38 -21
  16. package/commands/pipeline-health.md +26 -15
  17. package/commands/qa-sweep.md +68 -5
  18. package/commands/quality-gate.md +18 -0
  19. package/commands/review-pr-agents.md +58 -90
  20. package/commands/review-pr.md +58 -16
  21. package/commands/rollback.md +8 -5
  22. package/commands/security-audit.md +68 -12
  23. package/commands/sync-ecosystem.md +196 -156
  24. package/commands/validate.md +1 -1
  25. package/commands/work-on/build/architect.md +2 -2
  26. package/commands/work-on/build/context.md +2 -2
  27. package/commands/work-on/build/implement.md +3 -3
  28. package/commands/work-on/build/validate.md +3 -3
  29. package/commands/work-on/build.md +6 -6
  30. package/commands/work-on/close.md +59 -30
  31. package/commands/work-on/decompose.md +6 -6
  32. package/commands/work-on/investigate.md +16 -20
  33. package/commands/work-on/review.md +4 -4
  34. package/commands/work-on-monolithic.md +15 -16
  35. package/commands/work-on.md +45 -33
  36. package/docs/CODEX.md +1 -1
  37. package/docs/CONFIG.md +398 -0
  38. package/docs/WORKFLOW.md +115 -72
  39. package/package.json +2 -2
  40. package/scripts/verify-host-headers.sh +14 -9
  41. package/scripts/verify-route-registration.sh +10 -10
  42. package/commands/failure-recon.md +0 -375
@@ -25,17 +25,35 @@ You are the top-level orchestrator. Your job is to take a batch of issues, plan
25
25
 
26
26
  ---
27
27
 
28
+ ## Config Resolution
29
+
30
+ Read `forge.yaml` at the project root to resolve all project-specific variables before running any commands:
31
+
32
+ ```bash
33
+ # Parse forge.yaml for project context
34
+ GH_REPO=$(yq '.project.owner + "/" + .project.repo' forge.yaml)
35
+ GH_FLAG="-R $GH_REPO"
36
+ REPO_PATH=$(yq '.paths.root' forge.yaml)
37
+ PROJECT_NAME=$(yq '.project.name' forge.yaml)
38
+ STAGING_BRANCH=$(yq '.branches.staging' forge.yaml)
39
+ # Build satellite repo map from repos.satellites list
40
+ # Each satellite: { prefix, repo, staging_branch }
41
+ ```
42
+
43
+ All `{GH_REPO}`, `{GH_FLAG}`, `{REPO_PATH}`, `{PROJECT_NAME}`, and `{STAGING_BRANCH}` references below are populated from `forge.yaml`.
44
+
45
+ ---
46
+
28
47
  ## Multi-Repo Support
29
48
 
30
- This orchestrator supports issues across the AlterLab ecosystem. See `/work-on` → "Multi-Repo Support" for the full project registry and context variables.
49
+ This orchestrator supports issues across multiple repositories. See `/work-on` → "Multi-Repo Support" and `forge.yaml → repos` for the full project registry and context variables.
31
50
 
32
51
  ### Cross-Repo Issue References
33
52
 
34
- Issues can be prefixed with a project shorthand:
35
- - `#123` or `123` → AlterLab (default: `RapierCraft/AlterLab`)
36
- - `mcp:5` → MCP Server (`RapierCraft/alterlab-mcp-server`)
37
- - `n8n:12` → n8n Node (`RapierCraft/n8n-nodes-alterlab`)
38
- - `all-repos` → Scan all ecosystem repos for open issues (combine and prioritize)
53
+ Issues can be prefixed with a project shorthand derived from `forge.yaml → repos.satellites`:
54
+ - `#123` or `123` → default repo (`{GH_REPO}`)
55
+ - `{satellite_prefix}:5` → satellite repo (e.g., `mcp:5`, `n8n:12`) — prefixes and repos come from `forge.yaml → repos.satellites`
56
+ - `all-repos` → Scan all configured repos for open issues (combine and prioritize)
39
57
 
40
58
  When spawning sub-agents, pass the project prefix so `/work-on` resolves to the correct repo.
41
59
 
@@ -63,20 +81,20 @@ Parse `$ARGUMENTS` to determine which issues to work on:
63
81
  For each resolved repo, use the appropriate `-R` flag:
64
82
 
65
83
  ```bash
66
- # AlterLab (default — no flag needed):
67
- gh issue list --milestone "{TITLE}" --state open --limit 500 --json number,title,labels,milestone --jq '.[] | {number, title, labels: [.labels[].name], milestone: .milestone.title}'
84
+ # Default repo (no flag needed if using GH_FLAG="" for the default):
85
+ gh issue list {GH_FLAG} --milestone "{TITLE}" --state open --limit 500 --json number,title,labels,milestone --jq '.[] | {number, title, labels: [.labels[].name], milestone: .milestone.title}'
68
86
 
69
- # Satellite repos — always include -R flag:
70
- gh issue list -R RapierCraft/alterlab-mcp-server --milestone "{TITLE}" --state open --limit 500 --json number,title,labels,milestone
71
- gh issue list -R RapierCraft/n8n-nodes-alterlab --milestone "{TITLE}" --state open --limit 500 --json number,title,labels,milestone
87
+ # Satellite repos — always include -R flag with the satellite repo from forge.yaml:
88
+ # For each satellite in forge.yaml → repos.satellites:
89
+ gh issue list -R {SATELLITE_REPO} --milestone "{TITLE}" --state open --limit 500 --json number,title,labels,milestone
72
90
 
73
91
  # For specific numbers with repo prefix:
74
- gh issue view 5 -R RapierCraft/alterlab-mcp-server --json number,title,labels,state,milestone,body
92
+ gh issue view {NUMBER} -R {SATELLITE_REPO} --json number,title,labels,state,milestone,body
75
93
 
76
- # For "all-repos" — fetch from all and combine:
77
- gh issue list --state open --limit {N} --json number,title,labels,milestone
78
- gh issue list -R RapierCraft/alterlab-mcp-server --state open --limit 500 --json number,title,labels,milestone
79
- gh issue list -R RapierCraft/n8n-nodes-alterlab --state open --limit 500 --json number,title,labels,milestone
94
+ # For "all-repos" — fetch from all configured repos and combine:
95
+ gh issue list {GH_FLAG} --state open --limit {N} --json number,title,labels,milestone
96
+ # For each satellite in forge.yaml → repos.satellites:
97
+ gh issue list -R {SATELLITE_REPO} --state open --limit 500 --json number,title,labels,milestone
80
98
  # Combine, sort by priority, take top N
81
99
  ```
82
100
 
@@ -526,7 +544,7 @@ Agent(
526
544
  model="sonnet",
527
545
  description="Work on {PROJECT_PREFIX}#{NUMBER}",
528
546
  run_in_background=true,
529
- prompt="You are working on GitHub issue #{NUMBER} for the AlterLab ecosystem.
547
+ prompt="You are working on GitHub issue #{NUMBER} for the {PROJECT_NAME} project.
530
548
 
531
549
  **Project**: {PROJECT_NAME}
532
550
  **Repository**: {GH_REPO}
@@ -540,11 +558,10 @@ Agent(
540
558
 
541
559
  **IMPORTANT RULES**:
542
560
  - **MANDATORY**: You MUST use the Skill tool to invoke 'work-on' with args '{PROJECT_PREFIX}{NUMBER}'. Do NOT implement manually — /work-on handles the full pipeline including label state machine (workflow:investigating → workflow:building → workflow:in-review → workflow:merged), investigation reports, PR creation, and cleanup.
543
- - For AlterLab issues: `Skill(skill='work-on', args='{NUMBER}')`
544
- - For MCP issues: `Skill(skill='work-on', args='mcp:{NUMBER}')`
545
- - For n8n issues: `Skill(skill='work-on', args='n8n:{NUMBER}')`
561
+ - For default repo issues: `Skill(skill='work-on', args='{NUMBER}')`
562
+ - For satellite repo issues: `Skill(skill='work-on', args='{SATELLITE_PREFIX}:{NUMBER}')` (prefix from forge.yaml → repos.satellites)
546
563
  - NEVER bypass /work-on with manual git/gh commands — the label updates and structured comments are critical for tracking
547
- - NEVER target `main` for AlterLab PRs. Use `staging` for fast-lane issues, or `milestone/{slug}` for milestone issues.
564
+ - NEVER target `main` for PRs targeting the default repo. Use `{STAGING_BRANCH}` for fast-lane issues, or `milestone/{slug}` for milestone issues.
548
565
  - Satellite repos (MCP, n8n) have no staging branch — fast-lane PRs go to `main` for those.
549
566
  - If the issue is INVALID after investigation, close it with a comment explaining why
550
567
  - If you hit merge conflicts or blockers, post a comment on the issue and STOP — do not force anything
@@ -9,7 +9,18 @@ argument-hint: [project repo slug or "all"]
9
9
 
10
10
  You are the Forge pipeline's self-awareness layer. Your job is to measure how well the pipeline is performing, correlate performance with recent prompt changes, identify weak spots, and propose concrete improvements.
11
11
 
12
- **FORGE_HOME**: `~/projects/forge`
12
+ ## Config
13
+
14
+ Read project identity from `forge.yaml` before running any phase:
15
+
16
+ ```bash
17
+ FORGE_REPO=$(yq e '.project.owner + "/" + .project.repo' forge.yaml)
18
+ FORGE_HOME=$(yq e '.paths.root' forge.yaml)
19
+ echo "Forge repo: $FORGE_REPO"
20
+ echo "Forge home: $FORGE_HOME"
21
+ ```
22
+
23
+ **FORGE_HOME**: `$FORGE_HOME` (set from `forge.yaml` → `paths.root`)
13
24
  **This command is READ-ONLY on the target project.** It creates issues in the Forge repo only.
14
25
 
15
26
  ---
@@ -32,7 +43,7 @@ echo "Target project: $REPO"
32
43
 
33
44
  ```bash
34
45
  # Last pipeline-health run (if any) — from Forge git log
35
- LAST_RUN=$(cd ~/projects/forge && git log --all --oneline --grep="pipeline-health: $REPO" --format="%aI" -1 2>/dev/null || echo "")
46
+ LAST_RUN=$(cd "$FORGE_HOME" && git log --all --oneline --grep="pipeline-health: $REPO" --format="%aI" -1 2>/dev/null || echo "")
36
47
  if [ -z "$LAST_RUN" ]; then
37
48
  # First run — analyze last 30 days
38
49
  SINCE=$(date -d "30 days ago" +%Y-%m-%dT%H:%M:%SZ 2>/dev/null || date -v-30d +%Y-%m-%dT%H:%M:%SZ)
@@ -49,7 +60,7 @@ Fetch the most recent `health-report` issue for the same repo and parse its metr
49
60
 
50
61
  ```bash
51
62
  # Find the most recent health-report issue for this repo
52
- PRIOR_REPORT=$(gh issue list -R RapierCraftStudios/forge \
63
+ PRIOR_REPORT=$(gh issue list -R $FORGE_REPO \
53
64
  --state all --label "health-report" --limit 10 \
54
65
  --json number,title,body \
55
66
  --jq "[.[] | select(.title | contains(\"$REPO\"))] | sort_by(.number) | last")
@@ -154,7 +165,7 @@ Run ALL of these in parallel (note: Phase 2I fetches trajectory comments per iss
154
165
  ### 2A: Forge changelog (what changed in the pipeline itself)
155
166
 
156
167
  ```bash
157
- cd ~/projects/forge
168
+ cd "$FORGE_HOME"
158
169
  git log --oneline --since="$SINCE" -- commands/ docs/
159
170
  ```
160
171
 
@@ -366,7 +377,7 @@ echo "Investigation invalidation rate: $INVALID_ISSUES / $TOTAL_INVESTIGATED"
366
377
 
367
378
  # 2. ISSUE_SPEC audit findings
368
379
  # Count of /audit findings classified as ISSUE_SPEC in the window
369
- ISSUE_SPEC_COUNT=$(gh issue list -R RapierCraftStudios/forge --state all --label "audit-finding" --limit 200 \
380
+ ISSUE_SPEC_COUNT=$(gh issue list -R $FORGE_REPO --state all --label "audit-finding" --limit 200 \
370
381
  --json number,title,body,createdAt \
371
382
  --jq "[.[] | select(.createdAt > \"$SINCE\" and (.body | contains(\"ISSUE_SPEC\")))] | length")
372
383
 
@@ -416,13 +427,13 @@ echo "Issue structure compliance: $STRUCTURED_ISSUES / $TOTAL_ISSUES"
416
427
  ```bash
417
428
  # Persisted audit-agents summaries are posted to a designated Forge tracking issue
418
429
  # tagged with label "orchestration-metrics". Find it:
419
- TRACKING_ISSUE=$(gh issue list -R RapierCraftStudios/forge \
430
+ TRACKING_ISSUE=$(gh issue list -R $FORGE_REPO \
420
431
  --state open --label "orchestration-metrics" --limit 1 \
421
432
  --json number --jq '.[0].number' 2>/dev/null)
422
433
 
423
434
  if [ -n "$TRACKING_ISSUE" ]; then
424
435
  # Fetch all FORGE:AUDIT-AGENTS comments posted since $SINCE
425
- AUDIT_COMMENTS=$(gh api repos/RapierCraftStudios/forge/issues/$TRACKING_ISSUE/comments \
436
+ AUDIT_COMMENTS=$(gh api repos/$FORGE_REPO/issues/$TRACKING_ISSUE/comments \
426
437
  --jq "[.[] | select(.body | contains(\"FORGE:AUDIT-AGENTS\")) | select(.created_at > \"$SINCE\")]")
427
438
  echo "Found $(echo "$AUDIT_COMMENTS" | jq 'length') persisted audit-agents summaries in window"
428
439
  else
@@ -530,7 +541,7 @@ fi
530
541
 
531
542
  ```bash
532
543
  # All audit-finding issues created in the window
533
- AUDIT_FINDINGS=$(gh issue list -R RapierCraftStudios/forge --state all --label "audit-finding" \
544
+ AUDIT_FINDINGS=$(gh issue list -R $FORGE_REPO --state all --label "audit-finding" \
534
545
  --limit 200 --json number,title,body,createdAt \
535
546
  --jq "[.[] | select(.createdAt > \"$SINCE\")]")
536
547
 
@@ -573,7 +584,7 @@ echo "$AUDIT_FINDINGS" | jq -r \
573
584
  # Severity breakdown (P1 vs P2 vs P3 from labels)
574
585
  echo ""
575
586
  echo "Severity breakdown:"
576
- gh issue list -R RapierCraftStudios/forge --state all --label "audit-finding" \
587
+ gh issue list -R $FORGE_REPO --state all --label "audit-finding" \
577
588
  --limit 200 --json number,createdAt,labels \
578
589
  --jq "[.[] | select(.createdAt > \"$SINCE\")] | group_by(.labels | map(.name) | map(select(startswith(\"P\"))) | .[0]) | map({severity: .[0].labels | map(.name) | map(select(startswith(\"P\"))) | .[0], count: length})"
579
590
  ```
@@ -598,9 +609,9 @@ This phase locates conversation JSONL files for pipeline command sessions (work-
598
609
  # Convert a Claude Code project path to its ~/.claude/projects/ directory name
599
610
  # Rule: both '/' and '.' are replaced with '-'
600
611
  # Examples:
601
- # /home/user/projects/forge -> -home-user-projects-forge
602
- # /home/user/projects/ScraperAPI/.claude/worktrees/fix-branch
603
- # -> -home-user-projects-ScraperAPI--claude-worktrees-fix-branch
612
+ # /home/user/projects/myproject -> -home-user-projects-myproject
613
+ # /home/user/projects/myproject/.claude/worktrees/fix-branch
614
+ # -> -home-user-projects-myproject--claude-worktrees-fix-branch
604
615
  # (note: .claude -> --claude because '.' becomes '-' and surrounding '/' also become '-')
605
616
  _session_project_dir() {
606
617
  echo "$1" | sed 's|[/.]|-|g'
@@ -2035,7 +2046,7 @@ For each of the top 3 defect categories:
2035
2046
  Create a detailed health report as a GitHub issue in the Forge repo:
2036
2047
 
2037
2048
  ```bash
2038
- gh issue create -R RapierCraftStudios/forge \
2049
+ gh issue create -R $FORGE_REPO \
2039
2050
  --title "Pipeline Health: $REPO — $(date +%Y-%m-%d) — Score: [SCORE]/100" \
2040
2051
  --label "health-report" \
2041
2052
  --body "$(cat <<'EOF'
@@ -2264,7 +2275,7 @@ For each improvement proposal, create a trackable issue using the `/issue` struc
2264
2275
  - Metric < 10% below target → `P3`
2265
2276
 
2266
2277
  ```bash
2267
- gh issue create -R RapierCraftStudios/forge \
2278
+ gh issue create -R $FORGE_REPO \
2268
2279
  --title "fix([command]): [description]" \
2269
2280
  --label "[bug|enhancement|feature],[P1|P2|P3]" \
2270
2281
  --body "## Problem
@@ -2338,6 +2349,6 @@ Pipeline health signals:
2338
2349
 
2339
2350
  Top defect categories: [CAT1] ([N]), [CAT2] ([N]), [CAT3] ([N])
2340
2351
 
2341
- Proposed improvements: [N] issues created in RapierCraftStudios/forge
2352
+ Proposed improvements: [N] issues created in $FORGE_REPO
2342
2353
  Health report: [ISSUE_URL]
2343
2354
  ```
@@ -95,9 +95,72 @@ Depth-first, workflow-driven:
95
95
 
96
96
  ## Phase 0: Setup & Auth
97
97
 
98
- 1. Verify services: `curl -s -o /dev/null -w "%{http_code}" http://localhost:3000` and `:8000/api/v1/health`
99
- 2. If down: `cd /home/mrdubey/projects/ScraperAPI/alterlab && docker compose up -d --build web api`
100
- 3. Login via Playwright: navigate `/auth/login`, fill `claude@alterlab.dev` / `ClaudeCode2026!`, submit
98
+ **Load config from forge.yaml** before running any checks:
99
+
100
+ ```bash
101
+ QA_CONFIG=$(python3 - <<'PYEOF'
102
+ import yaml, sys, os
103
+
104
+ config_path = os.environ.get('FORGE_CONFIG', 'forge.yaml')
105
+ try:
106
+ cfg = yaml.safe_load(open(config_path))
107
+ except FileNotFoundError:
108
+ print('ERROR: forge.yaml not found. Run `cp forge.yaml.example forge.yaml` and configure your project.')
109
+ sys.exit(1)
110
+
111
+ paths = cfg.get('paths', {})
112
+ root = paths.get('root', '')
113
+ if not root:
114
+ print('ERROR: forge.yaml missing paths.root — qa-sweep needs the project root to discover pages and start services.')
115
+ sys.exit(1)
116
+
117
+ svc = cfg.get('services', {})
118
+ app_url = svc.get('app_url', 'http://localhost:3000')
119
+ api_url = svc.get('api_url', 'http://localhost:8000')
120
+
121
+ # Read QA credentials from credentials file (graceful: empty string if not set)
122
+ creds = paths.get('credentials', {})
123
+ creds_file = creds.get('file', '') if isinstance(creds, dict) else ''
124
+ qa_user = ''
125
+ qa_pass = ''
126
+ if creds_file:
127
+ try:
128
+ creds_data = yaml.safe_load(open(creds_file))
129
+ qa_section = creds_data.get('qa', {})
130
+ qa_user = qa_section.get('username', '')
131
+ qa_pass = qa_section.get('password', '')
132
+ except (FileNotFoundError, AttributeError):
133
+ pass # Credentials file optional — will surface as empty QA_USER/QA_PASS
134
+
135
+ print(root)
136
+ print(app_url)
137
+ print(api_url)
138
+ print(qa_user)
139
+ print(qa_pass)
140
+ PYEOF
141
+ )
142
+
143
+ if echo "$QA_CONFIG" | grep -q '^ERROR:'; then
144
+ echo "$QA_CONFIG"
145
+ exit 1
146
+ fi
147
+
148
+ PROJECT_ROOT=$(echo "$QA_CONFIG" | sed -n '1p')
149
+ APP_URL=$(echo "$QA_CONFIG" | sed -n '2p')
150
+ API_URL=$(echo "$QA_CONFIG" | sed -n '3p')
151
+ QA_USER=$(echo "$QA_CONFIG" | sed -n '4p')
152
+ QA_PASS=$(echo "$QA_CONFIG" | sed -n '5p')
153
+
154
+ if [ -z "$QA_USER" ] || [ -z "$QA_PASS" ]; then
155
+ echo "WARNING: QA credentials not configured in credentials file."
156
+ echo "Add qa.username and qa.password to the credentials file at paths.credentials.file in forge.yaml."
157
+ echo "Proceeding — login step will require manual credential entry."
158
+ fi
159
+ ```
160
+
161
+ 1. Verify services: `curl -s -o /dev/null -w "%{http_code}" $APP_URL` and `$API_URL/api/v1/health`
162
+ 2. If down: `cd $PROJECT_ROOT && docker compose up -d --build web api`
163
+ 3. Login via Playwright: navigate `/auth/login`, fill `$QA_USER` / `$QA_PASS`, submit
101
164
  4. Capture baseline data from dashboard/sidebar: balance (exact number + format), user info, plan/tier, notification counts, nav items
102
165
 
103
166
  ---
@@ -107,7 +170,7 @@ Depth-first, workflow-driven:
107
170
  **Dynamic discovery from filesystem** (NOT hardcoded):
108
171
 
109
172
  ```bash
110
- cd /home/mrdubey/projects/ScraperAPI/alterlab/web/src/app
173
+ cd $PROJECT_ROOT/web/src/app
111
174
  find . -name "page.tsx" -o -name "page.js" | sort
112
175
  ```
113
176
 
@@ -229,7 +292,7 @@ Next steps: `/orchestrate` on P0/P1 issues before deploy.
229
292
  ## Safety Rules
230
293
 
231
294
  1. NEVER modify production data — only read/interact. CAN create+delete test data.
232
- 2. Test user only: `claude@alterlab.dev` / `ClaudeCode2026!`
295
+ 2. Test user only: `$QA_USER` (configured in credentials file via forge.yaml)
233
296
  3. Handle dialogs gracefully (accept/dismiss, don't leave hanging)
234
297
  4. Snapshot before interactions
235
298
  5. Check console after EVERY interaction
@@ -330,6 +330,24 @@ For shell scripts that make HTTP requests to internal services:
330
330
  2. Check that auth tokens are included if the endpoint requires them
331
331
  3. Verify the URL path actually exists
332
332
 
333
+ Before running host-header checks on shell scripts, read project-specific internal service patterns from `forge.yaml` and export them so `verify-host-headers.sh` can append them to its generic defaults:
334
+
335
+ ```bash
336
+ # Read project-specific internal service patterns from forge.yaml (if present)
337
+ FORGE_INTERNAL_PATTERNS=""
338
+ if [ -f "{WORKTREE_PATH}/forge.yaml" ]; then
339
+ # Extract internal_service_patterns list (one pattern per line) and join with |
340
+ FORGE_INTERNAL_PATTERNS=$(grep -A 999 'internal_service_patterns:' "{WORKTREE_PATH}/forge.yaml" \
341
+ | grep -E '^\s*-\s+' \
342
+ | sed 's/^\s*-\s*//' \
343
+ | tr -d '"'"'" \
344
+ | paste -sd '|' -)
345
+ fi
346
+ export FORGE_INTERNAL_PATTERNS
347
+ ```
348
+
349
+ The script `verify-host-headers.sh` checks for the `FORGE_INTERNAL_PATTERNS` env var and appends any project-specific patterns to its generic defaults (localhost, 127.0.0.1, api-, worker-, 172.x.x.x, IP env vars) when the var is set.
350
+
333
351
  ### 2G.5: Hardcoded localhost in DB connection functions (shell scripts)
334
352
 
335
353
  **Triggered when**: changed `*.sh` files contain DB connection patterns (`PGPASSWORD`, `createdb`, `psql`, `pg_dump`, `pg_restore`).
@@ -157,12 +157,13 @@ Append this block at the very end of your comment (after the `---` footer line,
157
157
 
158
158
  **Prompt template:**
159
159
  ```
160
- You are performing a security and code quality scan on PR #[PR_NUMBER] for AlterLab (web scraping DaaS platform).
160
+ You are performing a security and code quality scan on PR #[PR_NUMBER] for [PROJECT_NAME].
161
161
 
162
162
  ## Context
163
163
  - PR title: [TITLE]
164
164
  - Services touched: [SERVICES]
165
165
  - Files changed: [FILE_LIST]
166
+ [PROJECT_CONTEXT]
166
167
 
167
168
  ## Your Mission
168
169
  Scan ALL changed code for security vulnerabilities and code quality issues. This is the baseline review that runs on every PR.
@@ -538,34 +539,24 @@ EOF
538
539
 
539
540
  **Prompt template:**
540
541
  ```
541
- You are auditing PR #[PR_NUMBER] for authentication and authorization correctness in AlterLab.
542
+ You are auditing PR #[PR_NUMBER] for authentication and authorization correctness in [PROJECT_NAME].
542
543
 
543
544
  ## CRITICAL PROJECT CONVENTIONS — You MUST enforce these:
544
545
 
545
- ### Auth Dependency Rules
546
- AlterLab has TWO auth dependencies. Using the wrong one is a security bug:
547
-
548
- | Route Type | Auth Dependency | How It Works | Example Routes |
549
- |-----------|----------------|-------------|----------------|
550
- | **Dashboard routes** (browser sessions) | `SessionUser` | JWT from httpOnly cookie, set by NextAuth | `/api/dashboard/*`, `/api/billing/*`, `/api/keys/*`, `/api/users/*` |
551
- | **Public API routes** (SDK/external) | `CurrentUser` | API key from `X-API-Key` header | `/api/v1/scrape`, `/api/v1/jobs/*` |
552
- | **Admin routes** | `CurrentUser` + `is_admin` check | API key with admin flag | `/api/v1/admin/*` |
553
-
554
- **VIOLATION**: Using `CurrentUser` on a dashboard route exposes API key auth to browser sessions.
555
- **VIOLATION**: Using `SessionUser` on a public API route breaks SDK authentication.
546
+ [DOMAIN_CONTEXT]
556
547
 
557
548
  ### How to Check
558
549
  ```bash
559
550
  # Find auth patterns in changed files
560
- grep -rn "CurrentUser\|SessionUser\|Depends(get_current" [CHANGED_FILES]
551
+ grep -rn "auth\|Depends\|get_current\|verify_token\|require_auth" [CHANGED_FILES]
561
552
 
562
553
  # Cross-reference with route path to determine if correct
563
- grep -rn "@router\.(get\|post\|put\|delete)" [CHANGED_FILES]
554
+ grep -rn "@router\.(get\|post\|put\|delete)\|app\.(get\|post\|put\|delete)" [CHANGED_FILES]
564
555
  ```
565
556
 
566
557
  ### What to Verify
567
558
  1. Every new endpoint has an auth dependency (no unauthenticated endpoints without justification)
568
- 2. The CORRECT auth dependency is used based on route type (see table above)
559
+ 2. The CORRECT auth dependency is used based on route type (refer to project conventions in [DOMAIN_CONTEXT] above — if absent, derive from surrounding code patterns)
569
560
  3. Multi-tenancy: resource access checks `user_id` ownership BEFORE returning data
570
561
  4. Rate limiting is applied to public-facing endpoints
571
562
  5. No IDOR vulnerabilities (different error codes for 404 vs 403 leak existence)
@@ -675,30 +666,15 @@ EOF
675
666
 
676
667
  **Prompt template:**
677
668
  ```
678
- You are auditing PR #[PR_NUMBER] for billing integrity in AlterLab.
669
+ You are auditing PR #[PR_NUMBER] for billing integrity in [PROJECT_NAME].
679
670
 
680
- CRITICAL: Users pay per scrape. Any billing bug = revenue loss or user overcharging.
671
+ CRITICAL: Any billing bug = revenue loss or user overcharging.
681
672
 
682
673
  ## Project Billing Architecture
683
674
 
684
- The billing flow spans two services:
685
- ```
686
- API (pre-scrape):
687
- 1. Check user balance (services/api/app/core/credits.py or billing/)
688
- 2. Pre-debit estimated cost based on requested tier
689
- 3. Queue job to Redis
690
-
691
- Worker (post-scrape):
692
- 4. Execute scrape, determine actual tier used
693
- 5. Reconcile: refund difference if actual tier < estimated tier
694
- 6. Record final billing in job result
695
- ```
675
+ [DOMAIN_CONTEXT]
696
676
 
697
- ## Key Files to Cross-Reference
698
- - Pricing: `services/api/app/core/pricing.py` (TIER_COSTS)
699
- - Credits: `services/api/app/core/credits.py` or `billing/`
700
- - Reconciliation: `services/worker/worker/queues.py` (search for "reconcil")
701
- - Tier determination: `services/worker/worker/unified_consumer.py`
677
+ If no billing context is configured above, derive the billing flow from the changed files: trace credit check → debit → execution → reconciliation paths.
702
678
 
703
679
  ## What to Verify
704
680
  1. **Trace the full flow**: credit check → pre-debit → execution → reconciliation
@@ -781,7 +757,7 @@ EOF
781
757
 
782
758
  **Prompt template:**
783
759
  ```
784
- You are auditing PR #[PR_NUMBER] for concurrency bugs and race conditions in AlterLab.
760
+ You are auditing PR #[PR_NUMBER] for concurrency bugs and race conditions in [PROJECT_NAME].
785
761
 
786
762
  CRITICAL: This is a billing system. Double-spend = revenue loss.
787
763
 
@@ -915,19 +891,13 @@ EOF
915
891
 
916
892
  **Prompt template:**
917
893
  ```
918
- You are auditing PR #[PR_NUMBER] for scraper logic correctness in AlterLab.
894
+ You are auditing PR #[PR_NUMBER] for domain-specific logic correctness in [PROJECT_NAME].
919
895
 
920
- ## Tier System
921
- AlterLab uses tiered scraping with escalation:
922
- T1 (curl/httpx) → T2 (HTTP with headers) → T3 (stealth proxy) → T3.5 (light JS) → T4 (full browser/Playwright)
896
+ ## Project Domain Architecture
923
897
 
924
- Each tier has different costs. Tier selection affects billing.
898
+ [DOMAIN_CONTEXT]
925
899
 
926
- ## Key Architecture
927
- - **Tier escalation**: `services/worker/worker/unified_consumer.py` — `_parallel_tier_race()`, `get_optimal_starting_tier()`
928
- - **Domain playbooks**: `services/worker/config/domain_playbooks.json` — domain-specific tier overrides
929
- - **Cortex intelligence**: `services/worker/worker/cortex_client.py` — learned headers/cookies/min_tier
930
- - **Content validation**: Determines if scrape succeeded or needs tier escalation
900
+ If no domain context is configured above, derive the architecture from the changed files: read the primary consumer/worker/handler files to understand the execution model.
931
901
 
932
902
  ## What to Verify
933
903
  1. **Tier selection**: Is the starting tier correct? Does escalation logic work?
@@ -1096,14 +1066,13 @@ EOF
1096
1066
 
1097
1067
  **Prompt template:**
1098
1068
  ```
1099
- You are auditing PR #[PR_NUMBER] for frontend quality in AlterLab (Next.js 15, App Router, React Server Components).
1069
+ You are auditing PR #[PR_NUMBER] for frontend quality in [PROJECT_NAME].
1100
1070
 
1101
1071
  ## Project Frontend Conventions
1102
- - **Default to Server Components** — only use 'use client' when needed (hooks, event handlers, browser APIs)
1103
- - **Data fetching**: SWR for client-side, server actions or API routes for mutations
1104
- - **Styling**: Tailwind CSS with oklch dark mode, shadcn/ui components
1105
- - **Forms**: Zod for validation schemas
1106
- - **Auth in frontend**: NextAuth sessions, not direct API key usage
1072
+
1073
+ [DOMAIN_CONTEXT]
1074
+
1075
+ If no frontend context is configured above, derive conventions from the changed files: check package.json for framework versions and look at existing patterns in surrounding components.
1107
1076
 
1108
1077
  ## What to Check
1109
1078
  1. **Server vs Client components**: Is 'use client' used appropriately? Could this be a Server Component instead?
@@ -1176,15 +1145,13 @@ EOF
1176
1145
 
1177
1146
  **Prompt template:**
1178
1147
  ```
1179
- You are auditing PR #[PR_NUMBER] for API design consistency in AlterLab.
1148
+ You are auditing PR #[PR_NUMBER] for API design consistency in [PROJECT_NAME].
1180
1149
 
1181
1150
  ## Project API Conventions
1182
- - **Router registration**: New routers must be registered in `services/api/app/main.py`
1183
- - **Schema validation**: All request/response models use Pydantic with type hints
1184
- - **Error format**: Consistent error response schema across all endpoints
1185
- - **Versioning**: Public API endpoints under `/api/v1/`, internal under `/api/`
1186
- - **Auth**: Every endpoint must have explicit auth dependency (see Auth Conventions)
1187
- - **Naming**: snake_case for Python, camelCase for JSON response fields (if using alias)
1151
+
1152
+ [DOMAIN_CONTEXT]
1153
+
1154
+ If no API context is configured above, derive conventions from the changed files: read the main router/application entrypoint to understand registration patterns, and check neighboring endpoints for error format and naming conventions.
1188
1155
 
1189
1156
  ## What to Check
1190
1157
  1. **Registration**: Is the new router registered in main.py?
@@ -1302,7 +1269,9 @@ EOF
1302
1269
 
1303
1270
  **Prompt template:**
1304
1271
  ```
1305
- You are auditing PR #[PR_NUMBER] for database changes in AlterLab (PostgreSQL).
1272
+ You are auditing PR #[PR_NUMBER] for database changes in [PROJECT_NAME].
1273
+
1274
+ [DOMAIN_CONTEXT]
1306
1275
 
1307
1276
  ## What to Check
1308
1277
  1. **SQL correctness** (CHECK FIRST — a query that errors at runtime breaks the whole page):
@@ -1393,14 +1362,13 @@ EOF
1393
1362
 
1394
1363
  **Prompt template:**
1395
1364
  ```
1396
- You are auditing PR #[PR_NUMBER] for infrastructure and deployment safety in AlterLab.
1365
+ You are auditing PR #[PR_NUMBER] for infrastructure and deployment safety in [PROJECT_NAME].
1397
1366
 
1398
1367
  ## Deployment Architecture
1399
- - **Blue-green deployment**: Both old and new versions run simultaneously during rollout
1400
- - **Traefik**: Reverse proxy, handles routing. Config at `traefik/dynamic/active.yml`
1401
- - **Docker Compose**: `docker-compose.yml` (dev), `docker-compose.prod.yml` (prod)
1402
- - **Services**: api-blue/green, web-blue/green, worker-blue/green, stripe-webhooks-blue/green, postgres, redis, traefik
1403
- - **CI/CD**: GitHub Actions deploys on merge to `main`
1368
+
1369
+ [DOMAIN_CONTEXT]
1370
+
1371
+ If no infra context is configured above, derive the deployment model from the changed files: read docker-compose files, GitHub Actions workflows, and entrypoint scripts to understand the deployment pipeline.
1404
1372
 
1405
1373
  ## What to Check
1406
1374
  1. **Downtime risk**: Will this change cause container restarts during deploy?
@@ -1516,27 +1484,21 @@ You are auditing PR #[PR_NUMBER] for infrastructure and deployment safety in Alt
1516
1484
  - Common siblings: `ci.yml` ↔ `deploy-production.yml` (share `test-api`, `test-web` jobs), `deploy-production.yml` ↔ `hotfix-deploy.yml` (share build/deploy logic)
1517
1485
  **This is the #1 cause of "CI passed but deploy failed" incidents.** Do not skip this check.
1518
1486
  10. **Deploy scope awareness** (ALWAYS run — checks whether ALL changed services will actually be deployed):
1519
- AlterLab has two separate deploy pipelines. The PR's CI/CD only covers one of them:
1520
- | Path prefix | Deploy mechanism | Auto-triggered? |
1521
- |-------------|-----------------|-----------------|
1522
- | `web/**`, `services/api/**` | `deploy-production.yml` | Yes (on merge to main) |
1523
- | `services/worker/**` | `deploy-production.yml` | Yes (on merge to main) |
1524
- | `services/session-ingest/**` | `deploy-e2e.yml` | **NO — manual trigger required** |
1525
- | `services/herald/**` | `deploy-e2e.yml` | **NO — manual trigger required** |
1526
- | `services/cortex/**` | `deploy-e2e.yml` | **NO — manual trigger required** |
1527
-
1528
- **Steps**:
1487
+ This project may have multiple deploy pipelines. Check which pipelines cover which services:
1488
+
1529
1489
  ```bash
1490
+ # List all GitHub Actions workflows
1491
+ ls .github/workflows/
1530
1492
  # List all paths changed in this PR
1531
1493
  gh pr diff [PR_NUMBER] --name-only
1532
1494
  ```
1533
- - For each changed path, determine which deploy mechanism covers it (use table above)
1534
- - If ALL changed paths are covered by `deploy-production.yml` → no action needed
1535
- - **If ANY changed path maps to `deploy-e2e.yml` (session-ingest, herald, cortex)**:
1536
- - Flag as CONFIRMED BLOCKING finding
1537
- - Verdict: `BLOCK — Deploy prerequisite: manually trigger deploy-e2e.yml for [service names] before or after this deploy`
1538
- - Rationale: These services run via PM2 on the E2E host and are NOT rebuilt by the Docker deploy pipeline. Deploying without them leaves a broken contract between the API/web layer and the E2E service layer (e.g., a new token header sent by web but not yet verified by session-ingest causes 401/500 errors).
1539
- E2E services run via PM2 on the E2E host and are not part of the Docker deploy pipeline. When the API/web layer deploys a new auth contract (new token type, new header requirement) without a corresponding E2E service deploy, the two layers operate on mismatched contracts — resulting in 401/500 errors until the E2E service is manually redeployed.
1495
+
1496
+ For each changed path: read the `.github/workflows/` directory to determine which workflow deploys it and whether it's auto-triggered or requires manual action. If any changed service path is NOT covered by an auto-triggered workflow on merge:
1497
+ - Flag as CONFIRMED BLOCKING finding
1498
+ - Verdict: `BLOCK — Deploy prerequisite: manually trigger [workflow] for [service names] before or after this deploy`
1499
+ - Rationale: Services not covered by the auto-deploy pipeline will not be updated on merge, leaving a broken contract between deployed and un-deployed layers.
1500
+
1501
+ If `[DOMAIN_CONTEXT]` above contains a deploy pipeline table, use it as the authoritative source for path → pipeline mapping.
1540
1502
  11. **Config field type/doc-comment consistency** (when the diff introduces new pydantic-settings fields):
1541
1503
  When a new env var is introduced as a pydantic-settings field with a collection type (`list[str]`, `List[str]`, `set[str]`, `Set[str]`), cross-reference the field's type annotation against the format hint documented in `.env.example`. **pydantic-settings v2 parses collection-type fields via `json.loads()` — they require JSON array format like `["a","b"]`, NOT comma-separated format like `a,b`**. A doc comment saying "comma-separated" on a `list[str]` field is a CONFIRMED HIGH finding — it guarantees a startup crash for anyone following the documented format.
1542
1504
  ```bash
@@ -1610,7 +1572,13 @@ You are auditing PR #[PR_NUMBER] for infrastructure and deployment safety in Alt
1610
1572
  The INFRA agent's secret delivery chain verification (env var present in ENV_MAPPING) does NOT verify whether the fallback value is safe. A config file can pass all delivery chain checks while still containing an active placeholder credential for any environment where the env var is absent. This check targets that gap. <!-- Added: forge#301 -->
1611
1573
 
1612
1574
  14. **Host-side database tool invocations in deploy scripts** (when `.github/workflows/*.yml`, `scripts/deploy*.sh`, or any deploy entrypoint script in the diff invokes `psql`, `createdb`, or `pg_dump` directly on the host):
1613
- Host-side `psql`, `createdb`, and `pg_dump` connect to PostgreSQL via the host's port binding (`localhost:5432` or `127.0.0.1:5432`). In SSH-based deploy contexts, the host-side port mapping to PostgreSQL's Docker container is unreliable — the listening address may differ from what the SSH session can reach, and the mapping is not guaranteed to be present at all in hardened host configurations. The migration system already uses `docker exec alterlab-postgres` for all database operations — deploy scripts must do the same.
1575
+ Host-side `psql`, `createdb`, and `pg_dump` connect to PostgreSQL via the host's port binding (`localhost:5432` or `127.0.0.1:5432`). In SSH-based deploy contexts, the host-side port mapping to PostgreSQL's Docker container is unreliable — the listening address may differ from what the SSH session can reach, and the mapping is not guaranteed to be present at all in hardened host configurations. The safe pattern is to use `docker exec <postgres-container>` for all database operations in deploy scripts.
1576
+
1577
+ To find the correct container name, grep the project's docker-compose files:
1578
+ ```bash
1579
+ grep -n "container_name" docker-compose*.yml | grep -i "postgres\|pg\|db"
1580
+ ```
1581
+ Use the container name found (referred to as `[DB_CONTAINER]` in examples below).
1614
1582
 
1615
1583
  **Scan for host-side database tool invocations:**
1616
1584
  ```bash
@@ -1623,13 +1591,13 @@ You are auditing PR #[PR_NUMBER] for infrastructure and deployment safety in Alt
1623
1591
  **For each match, classify:**
1624
1592
  - `psql`, `createdb`, `pg_dump`, or `pg_restore` called directly (not via `docker exec`): **CONFIRMED HIGH**
1625
1593
  - Rationale: Host-side port mappings to PostgreSQL's Docker container are unreliable in SSH deploy contexts. A deploy step that fails to connect leaves post-deploy database setup incomplete — silently if `continue-on-error: true` is set, or rolls back a successful deploy if not.
1626
- - The safe pattern used by the migration system: `docker exec alterlab-postgres psql -U $POSTGRES_USER -d $POSTGRES_DB -c "..."` or `docker exec alterlab-postgres createdb -U $POSTGRES_USER $DB_NAME`
1627
- - `psql`/`createdb`/`pg_dump` called inside `docker exec alterlab-postgres ...`: **OK** — this is the safe pattern.
1594
+ - The safe pattern: `docker exec [DB_CONTAINER] psql -U $POSTGRES_USER -d $POSTGRES_DB -c "..."` or `docker exec [DB_CONTAINER] createdb -U $POSTGRES_USER $DB_NAME`
1595
+ - `psql`/`createdb`/`pg_dump` called inside `docker exec [DB_CONTAINER] ...`: **OK** — this is the safe pattern.
1628
1596
 
1629
- **Recommended fix**: Replace host-side invocations with `docker exec alterlab-postgres` equivalents:
1630
- - `psql -h localhost -U $USER -d $DB -c "..."` → `docker exec alterlab-postgres psql -U $USER -d $DB -c "..."`
1631
- - `createdb -h localhost -U $USER $DB_NAME` → `docker exec alterlab-postgres createdb -U $USER $DB_NAME`
1632
- - `pg_dump -h localhost -U $USER $DB` → `docker exec alterlab-postgres pg_dump -U $USER $DB`
1597
+ **Recommended fix**: Replace host-side invocations with `docker exec [DB_CONTAINER]` equivalents:
1598
+ - `psql -h localhost -U $USER -d $DB -c "..."` → `docker exec [DB_CONTAINER] psql -U $USER -d $DB -c "..."`
1599
+ - `createdb -h localhost -U $USER $DB_NAME` → `docker exec [DB_CONTAINER] createdb -U $USER $DB_NAME`
1600
+ - `pg_dump -h localhost -U $USER $DB` → `docker exec [DB_CONTAINER] pg_dump -U $USER $DB`
1633
1601
 
1634
1602
  Host-side port bindings to Docker containers are unreliable in SSH deploy contexts. Deploy scripts that invoke database tools directly cannot depend on `localhost:5432` being reachable; the same operation via `docker exec` bypasses the host network entirely and always succeeds when the container is running. <!-- Added: forge#322 -->
1635
1603