forgedock 1.0.5 → 1.0.7

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 +7 -1
  2. package/bin/forgedock.mjs +496 -364
  3. package/bin/labels.json +152 -0
  4. package/commands/audit-agents.md +4 -2
  5. package/commands/autopilot.md +19 -11
  6. package/commands/cleanup.md +27 -12
  7. package/commands/deploy-info.md +36 -17
  8. package/commands/incident-response.md +15 -10
  9. package/commands/issue.md +8 -6
  10. package/commands/milestone.md +97 -48
  11. package/commands/orchestrate.md +109 -65
  12. package/commands/pipeline-health.md +8 -1
  13. package/commands/qa-sweep.md +14 -3
  14. package/commands/review-pr-agents.md +1 -1
  15. package/commands/review-pr-staging.md +129 -23
  16. package/commands/review-pr.md +237 -90
  17. package/commands/rollback.md +26 -7
  18. package/commands/security-audit.md +27 -25
  19. package/commands/sync-ecosystem.md +2 -2
  20. package/commands/work-on/build/architect.md +154 -2
  21. package/commands/work-on/build/context.md +131 -3
  22. package/commands/work-on/build/validate.md +32 -13
  23. package/commands/work-on/decompose.md +2 -0
  24. package/commands/work-on-monolithic.md +9 -5
  25. package/commands/work-on.md +67 -23
  26. package/docs/CONFIG.md +117 -0
  27. package/package.json +2 -1
  28. package/scripts/verify-route-registration.sh +36 -15
  29. package/scripts/verify-sops-chain.sh +18 -0
  30. package/templates/devdocs/README.md +96 -0
  31. package/templates/devdocs/agent/using-forgedock.md +245 -0
  32. package/templates/devdocs/agent/using-github.md +325 -0
  33. package/templates/devdocs/project/architecture.md +122 -0
  34. package/templates/devdocs/project/conventions.md +158 -0
  35. package/templates/devdocs/project/custom-instructions.md +73 -0
  36. package/templates/devdocs/project/glossary.md +84 -0
  37. package/templates/devdocs/project/stack.md +80 -0
  38. package/templates/devdocs/templates/commit-convention.md +147 -0
  39. package/templates/devdocs/templates/issue.md +141 -0
  40. package/templates/devdocs/templates/pull-request.md +115 -0
  41. package/templates/devdocs/templates/review-finding.md +147 -0
  42. package/bin/github-app-manifest.json +0 -24
@@ -747,25 +747,50 @@ if iteration == max_iterations AND not PASS:
747
747
 
748
748
  ### 3H: Format and verify
749
749
 
750
+ All tool commands are read from `forge.yaml → verification.commands`. When a key is absent, the step logs `SKIPPED — not configured in verification.commands` and continues rather than silently passing.
751
+
750
752
  **Python**:
751
753
  ```bash
752
754
  cd {WORKTREE_PATH}
753
- black {PYTHON_FILES} && isort {PYTHON_FILES} && python -m py_compile {PYTHON_FILES}
755
+
756
+ PYTHON_FORMAT=$(awk '/^ commands:/{f=1;next} f && /^[^ \t]/{exit} f' forge.yaml 2>/dev/null | awk '/^ python:/{f=1;next} f && /^ [^ \t]/{exit} f' | grep 'format:' | head -1 | sed "s/.*format: *['\"]//;s/['\"].*//")
757
+ if [ -n "$PYTHON_FORMAT" ]; then
758
+ eval "$PYTHON_FORMAT" 2>&1
759
+ else
760
+ echo "SKIPPED — python.format not configured in verification.commands"
761
+ fi
762
+
763
+ # Compile check always runs (no config needed — catches syntax errors)
764
+ python -m py_compile {PYTHON_FILES}
754
765
  ```
755
766
  `py_compile` failures are BLOCKING.
756
767
 
757
- **TypeScript (primary repo — has tsconfig.json)**:
768
+ **TypeScript**:
758
769
  ```bash
759
770
  cd {WORKTREE_PATH}
760
- prettier --write {TS_FILES} && tsc --noEmit
761
- ```
762
- `tsc --noEmit` failures are BLOCKING.
763
771
 
764
- **TypeScript (satellite repos)**:
765
- ```bash
766
- cd {WORKTREE_PATH}
767
- npm run build && prettier --write {TS_FILES}
772
+ TS_FORMAT=$(awk '/^ commands:/{f=1;next} f && /^[^ \t]/{exit} f' forge.yaml 2>/dev/null | awk '/^ typescript:/{f=1;next} f && /^ [^ \t]/{exit} f' | grep 'format:' | head -1 | sed "s/.*format: *['\"]//;s/['\"].*//")
773
+ TS_TYPECHECK=$(awk '/^ commands:/{f=1;next} f && /^[^ \t]/{exit} f' forge.yaml 2>/dev/null | awk '/^ typescript:/{f=1;next} f && /^ [^ \t]/{exit} f' | grep 'typecheck:' | head -1 | sed "s/.*typecheck: *['\"]//;s/['\"].*//")
774
+ TS_BUILD=$(awk '/^ commands:/{f=1;next} f && /^[^ \t]/{exit} f' forge.yaml 2>/dev/null | awk '/^ typescript:/{f=1;next} f && /^ [^ \t]/{exit} f' | grep 'build:' | head -1 | sed "s/.*build: *['\"]//;s/['\"].*//")
775
+
776
+ if [ -n "$TS_FORMAT" ]; then
777
+ eval "$TS_FORMAT" 2>&1
778
+ else
779
+ echo "SKIPPED — typescript.format not configured in verification.commands"
780
+ fi
781
+
782
+ if [ -n "$TS_TYPECHECK" ]; then
783
+ eval "$TS_TYPECHECK" 2>&1
784
+ TS_EXIT=$?
785
+ elif [ -n "$TS_BUILD" ]; then
786
+ eval "$TS_BUILD" 2>&1 | tail -30
787
+ TS_EXIT=$?
788
+ else
789
+ echo "SKIPPED — typescript.typecheck and typescript.build not configured in verification.commands"
790
+ TS_EXIT=0
791
+ fi
768
792
  ```
793
+ Typecheck or build failures are BLOCKING.
769
794
 
770
795
  ### 3I: Frontend proxy wiring check (MANDATORY)
771
796
 
@@ -791,27 +816,44 @@ Advisory only — does not block build. Check for lambda/callable in connect_arg
791
816
 
792
817
  Skip if no new env vars introduced.
793
818
 
819
+ **Config variables used by this phase** (set in `forge.yaml`):
820
+ - `{deploy.secrets_backend}` — secrets delivery method (`sops`, `aws-sm`, `vault`, `ci-env`, `none`). When absent or not `sops`, SOPS-specific checks below are skipped with an explicit log message.
821
+ - `{verification.services[name].container}` — container name for post-deploy verification. Resolved by matching the service name; falls back to `{service}` (bare name) when not configured.
822
+
794
823
  For each new env var, verify present in ALL required locations:
795
824
 
796
825
  | Location | Required for |
797
826
  |----------|-------------|
798
827
  | `.env.example` | All new vars |
799
- | `infra/secrets/prod.enc.yaml` (SOPS) | Production secrets |
800
- | `infra/decrypt-secrets.sh` ENV_MAPPING | All vars in deploy chain |
801
- | `app/env_validation.py` | API service vars |
802
- | `docker-compose.prod.yml` | Vars needing explicit injection |
828
+ | Secrets backend (see `deploy.secrets_backend`) | Secret vars — skip if backend is `none` or unset |
829
+ | `app/env_validation.py` | API service vars (if project has one) |
830
+ | `docker-compose.prod.yml` | Vars needing explicit injection (if project uses Docker Compose) |
803
831
 
804
- Deploy chain: SOPS → `decrypt-secrets.sh` (ENV_MAPPING) → `.env.secrets` → `merge-env-secrets.sh` → `.env.production` → docker-compose `env_file`.
832
+ **Secrets backend check** *(trigger: `deploy.secrets_backend == "sops"`)*:
805
833
 
806
- **Operator-set var classification** *(trigger: new env var is NOT present in `infra/secrets/prod.enc.yaml`)*: <!-- Added: forge#380 -->
834
+ If the project uses SOPS, verify the new var is present in all SOPS chain locations:
835
+ - `infra/secrets/prod.enc.yaml` — SOPS-encrypted secret store
836
+ - `infra/decrypt-secrets.sh` ENV_MAPPING — maps SOPS key to env var name
837
+ - Deploy chain: SOPS → `decrypt-secrets.sh` (ENV_MAPPING) → `.env.secrets` → `merge-env-secrets.sh` → `.env.production` → docker-compose `env_file`
807
838
 
808
- Some env vars are operator-set (non-secret, not sourced from SOPS) — they must be manually added to `.env.production` on the production server. The SOPS deploy chain does not carry them. When a new env var has no entry in `prod.enc.yaml`, classify it as operator-set and add a **HARD BLOCKER** item to the Testing Checklist:
839
+ If `deploy.secrets_backend` is absent or not `sops`, skip these checks and log:
840
+ > `SKIP: SOPS chain check — deploy.secrets_backend is not "sops". Configure deploy.secrets_backend in forge.yaml to enable.`
841
+
842
+ **Operator-set var classification** *(trigger: new env var is NOT in the configured secrets backend)*: <!-- Added: forge#380 -->
843
+
844
+ Some env vars are operator-set (non-secret, not sourced from the secrets backend) — they must be manually added to the runtime environment on the production server. When a new env var has no entry in the secrets backend, classify it as operator-set and add a **HARD BLOCKER** item to the Testing Checklist.
845
+
846
+ Resolve the container name for the verification command:
847
+ 1. Look up the service in `forge.yaml → verification.services[]` by name — use the `container` field if present.
848
+ 2. If no matching entry, fall back to the bare service name: `{service}` (no suffix).
809
849
 
810
850
  ```
811
- - [ ] HARD BLOCKER: Add {VAR_NAME} to .env.production on the production server.
812
- This var is operator-set (not in SOPS) — it does NOT flow through the automated
813
- deploy chain. It must be added manually before or after deploy.
814
- Verify with: docker exec {service}-blue env | grep {VAR_NAME}
851
+ - [ ] HARD BLOCKER: Add {VAR_NAME} to the runtime environment on the production server.
852
+ This var is operator-set — it does NOT flow through the automated secrets chain.
853
+ It must be added manually before or after deploy.
854
+ Verify with: docker exec {CONTAINER_NAME} env | grep {VAR_NAME}
855
+ (CONTAINER_NAME resolved from verification.services[{service}].container in forge.yaml,
856
+ or bare service name if not configured)
815
857
  ```
816
858
 
817
859
  **`env_file` re-read warning** *(trigger: any new env var added to `.env.production` path)*:
@@ -822,11 +864,13 @@ Add this warning to the Testing Checklist whenever a new env var is introduced (
822
864
 
823
865
  **Post-deploy in-container verification** *(trigger: any new env var)*:
824
866
 
825
- Add the following to the Testing Checklist so the deployer can confirm delivery after deploy:
867
+ Add the following to the Testing Checklist so the deployer can confirm delivery after deploy.
868
+
869
+ Resolve `{CONTAINER_NAME}` from `forge.yaml → verification.services[{service}].container`; use `{service}` (bare) if the field is absent.
826
870
 
827
871
  ```bash
828
872
  # Verify env var reached the running container (run post-deploy)
829
- docker exec {service}-blue env | grep {VAR_NAME}
873
+ docker exec {CONTAINER_NAME} env | grep {VAR_NAME}
830
874
  # Expected: {VAR_NAME}={value}
831
875
  # If blank: container was not recreated — run: docker compose up --no-deps --force-recreate {service}
832
876
  ```
@@ -1100,4 +1144,4 @@ gh issue comment {NUMBER} {GH_FLAG} --body "<!-- FORGE:TRAJECTORY -->
1100
1144
  - PR creation fails: check if branch pushed, if PR already exists
1101
1145
  - Merge conflicts: report to user, do NOT auto-resolve
1102
1146
  - gh CLI fails: check `gh auth status`
1103
- - Label missing: `gh label create "{name}" --color {hex} -R {GH_REPO}`
1147
+ - Label missing: run `npx forgedock labels setup` (from the project directory, or pass `--repo owner/repo`) to idempotently bootstrap all ForgeDock-managed labels with canonical colors and descriptions. Alternatively: `gh label create "{name}" --color {hex} --description "Managed by ForgeDock." --force -R {GH_REPO}`
package/docs/CONFIG.md CHANGED
@@ -23,6 +23,7 @@ echo "forge.yaml" >> .gitignore # if your credentials path is sensitive
23
23
  | [`project_board`](#project_board-optional) | No | GitHub Projects v2 integration |
24
24
  | [`services`](#services-optional) | No | External service URLs and IDs |
25
25
  | [`review`](#review-optional) | No | Context injected into review agents |
26
+ | [`devdocs`](#devdocs-optional) | No | Devdocs knowledge tree path |
26
27
  | [`verification`](#verification-optional) | No | Health-check patterns |
27
28
  | [`billing`](#billing-optional) | No | Enable financial integrity audit phase |
28
29
 
@@ -305,6 +306,39 @@ review:
305
306
 
306
307
  ---
307
308
 
309
+ ## `devdocs` (OPTIONAL)
310
+
311
+ Path configuration for the devdocs knowledge tree. Pipeline agents (work-on, review-pr, etc.) read these files as **authoritative project knowledge** before acting.
312
+
313
+ Run `npx forgedock docs init` to scaffold the tree from ForgeDock's seed templates into the configured path.
314
+
315
+ ```yaml
316
+ devdocs:
317
+ path: "devdocs"
318
+ ```
319
+
320
+ | Field | Type | Required | Description |
321
+ |-------|------|----------|-------------|
322
+ | `path` | string (relative path) | No | Path to the devdocs tree, relative to project root. Default: `devdocs`. |
323
+
324
+ **Commands that use this section**: `docs init`, `work-on/build/context` (Phase C-1), `work-on/build/architect` (Phase A0)
325
+
326
+ ### Migration from `review.context`
327
+
328
+ If you previously stored project context in `forge.yaml → review.context`, move that content into the appropriate devdocs file after running `npx forgedock docs init`:
329
+
330
+ | `review.context` content | Target devdocs file |
331
+ |--------------------------|---------------------|
332
+ | Architecture decisions | `devdocs/project/architecture.md` |
333
+ | Tech stack details | `devdocs/project/stack.md` |
334
+ | Coding conventions | `devdocs/project/conventions.md` |
335
+ | Project terminology | `devdocs/project/glossary.md` |
336
+ | ForgeDock usage notes | `devdocs/agent/using-forgedock.md` |
337
+
338
+ Agents read devdocs files as binding source-of-truth, so they receive richer context than the single `review.context` string.
339
+
340
+ ---
341
+
308
342
  ## `verification` (OPTIONAL)
309
343
 
310
344
  Service health-check patterns for the quality gate and validate commands.
@@ -382,6 +416,47 @@ billing:
382
416
 
383
417
  ---
384
418
 
419
+ ## Label Bootstrap
420
+
421
+ ForgeDock manages a canonical set of GitHub labels for use across all pipeline commands. Labels cover workflow state, priority, review findings, audit findings, and category classification.
422
+
423
+ ### Bootstrap command
424
+
425
+ ```bash
426
+ # Create/update all ForgeDock-managed labels on the repo defined in forge.yaml:
427
+ npx forgedock labels setup
428
+
429
+ # Or target a specific repo explicitly:
430
+ npx forgedock labels setup --repo owner/repo
431
+ ```
432
+
433
+ Running this command is idempotent — it creates labels that don't exist and updates the color/description of labels that do. Safe to re-run at any time.
434
+
435
+ **When to run it**: Once after `npx forgedock install`, or whenever a pipeline command fails with "label not found". The command bootstraps every label the pipeline relies on.
436
+
437
+ ### Canonical label set
438
+
439
+ The full manifest lives in [`bin/labels.json`](../bin/labels.json) in the ForgeDock package. Each label has a fixed hex color and a description attributing it to ForgeDock.
440
+
441
+ | Family | Labels |
442
+ |--------|--------|
443
+ | Priority | `priority:P0` `priority:P1` `priority:P2` `priority:P3` |
444
+ | Workflow | `workflow:investigating` `workflow:ready-to-build` `workflow:building` `workflow:in-review` `workflow:merged` `workflow:decomposed` `workflow:invalid` |
445
+ | Pipeline | `needs-human` `review-finding` `needs-validation` `validated` `false-positive` `staging-review` `audit-finding` `orchestration-metrics` `health-report` |
446
+ | Category | `bug` `enhancement` `feature` `refactor` `dead-code` `improvement` `documentation` `qa` `security` `performance` |
447
+
448
+ ### Colors
449
+
450
+ Colors are grouped by semantic meaning:
451
+ - **Critical/error** (`#B60205`): `priority:P0`, `security`
452
+ - **High/warning-red** (`#D93F0B`): `priority:P1`, `review-finding`, `audit-finding`
453
+ - **Medium/yellow** (`#FBCA04`): `priority:P2`, `needs-validation`
454
+ - **Low/green** (`#C2E0C6`, `#0E8A16`): `priority:P3`, `workflow:merged`, `validated`
455
+ - **Blue pipeline** (`#1D76DB`, `#0075CA`, `#0052CC`): active workflow states
456
+ - **Neutral** (`#CCCCCC`, `#E4E669`): terminal/dismissal states
457
+
458
+ ---
459
+
385
460
  ## Config Reading Conventions
386
461
 
387
462
  ForgeDock commands use two accepted patterns for reading `forge.yaml`:
@@ -393,6 +468,48 @@ Do **not** mix the two patterns for the same block of variables (e.g., `yq` with
393
468
 
394
469
  ---
395
470
 
471
+ ## CLAUDE.md Integration
472
+
473
+ ForgeDock can inject a managed usage block into your project's `CLAUDE.md` so every Claude Code session opened in the repo automatically knows that ForgeDock drives development here and which commands to use.
474
+
475
+ ### How It Works
476
+
477
+ Running `npx forgedock init` or `npx forgedock integrate` writes a marker-bounded block into `CLAUDE.md`:
478
+
479
+ ```
480
+ <!-- BEGIN FORGEDOCK -->
481
+ ## ForgeDock — Autonomous Development Pipeline
482
+ ...command index and conventions...
483
+ <!-- END FORGEDOCK -->
484
+ ```
485
+
486
+ The block is **idempotent** — re-running replaces only the managed section and leaves all other `CLAUDE.md` content untouched. If `CLAUDE.md` does not exist, it is created.
487
+
488
+ If `AGENTS.md` already exists in the project root, the same block is mirrored into it.
489
+
490
+ ### Commands
491
+
492
+ | Command | Action |
493
+ |---------|--------|
494
+ | `npx forgedock init` | Generates `forge.yaml` **and** injects the CLAUDE.md block |
495
+ | `npx forgedock integrate` | Injects/refreshes the block without modifying `forge.yaml` |
496
+
497
+ ### Opting Out
498
+
499
+ To prevent ForgeDock from managing the block, remove the `<!-- BEGIN FORGEDOCK -->` / `<!-- END FORGEDOCK -->` markers from `CLAUDE.md`. Without the markers, subsequent runs will append a new block rather than replacing one — so if you want to opt out permanently, delete or omit the markers **and** do not run `integrate` again.
500
+
501
+ Alternatively, keep the markers but edit the content between them freely — ForgeDock will replace that section on the next run, so any manual edits inside the markers will be overwritten.
502
+
503
+ ### Re-generating
504
+
505
+ The command index inside the block is auto-generated from the `description:` frontmatter in each `commands/*.md` file. To refresh it after a ForgeDock update:
506
+
507
+ ```bash
508
+ npx forgedock integrate
509
+ ```
510
+
511
+ ---
512
+
396
513
  ## Complete Example
397
514
 
398
515
  See [`forge.yaml.example`](../forge.yaml.example) at the repository root for a fully annotated example covering all sections.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "forgedock",
3
- "version": "1.0.5",
3
+ "version": "1.0.7",
4
4
  "description": "GitHub as a knowledge graph for AI agents. Autonomous dev pipeline for Claude Code.",
5
5
  "bin": {
6
6
  "forgedock": "bin/forgedock.mjs"
@@ -36,6 +36,7 @@
36
36
  "commands/",
37
37
  "docs/",
38
38
  "scripts/",
39
+ "templates/",
39
40
  "LICENSE",
40
41
  "README.md"
41
42
  ],
@@ -5,6 +5,18 @@
5
5
  # changed_files_file: path to a file listing changed files (one per line)
6
6
  # repo_root: path to the repository root
7
7
  #
8
+ # Layout path overrides (env vars — override defaults for non-AlterLab layouts):
9
+ # FORGE_PAGES_ROOT Root of Next.js App Router pages dir (default: web/src/app)
10
+ # FORGE_API_ROUTERS_DIR Dir containing FastAPI router .py files (default: services/api/app/routers)
11
+ # FORGE_API_MAIN Path to API app entrypoint, relative to repo root (default: services/api/app/main.py)
12
+ # FORGE_API_MIDDLEWARE_DIR Dir containing API middleware .py files (default: services/api/app/middleware)
13
+ # FORGE_API_SERVICES_DIR Root of the backend API service dir (default: services/api)
14
+ # FORGE_WORKER_DIR Root of the background worker service dir (default: services/worker)
15
+ # FORGE_COMPONENTS_DIR Root of shared frontend component library (default: web/src/components)
16
+ #
17
+ # Set these from forge.yaml review.layout fields before invoking, e.g.:
18
+ # export FORGE_PAGES_ROOT=$(yq '.review.layout.pages // "web/src/app"' forge.yaml)
19
+ #
8
20
  # Output: Structured findings (one per line, prefixed with severity)
9
21
  # BLOCKING: <message> — must fix before merge
10
22
  # WARNING: <message> — likely issue, verify manually
@@ -23,12 +35,21 @@ else
23
35
  FILES=$(cat "$CHANGED_FILES")
24
36
  fi
25
37
 
38
+ # Layout path configuration — read from env vars, fall back to AlterLab defaults
39
+ FORGE_PAGES_ROOT="${FORGE_PAGES_ROOT:-web/src/app}"
40
+ FORGE_API_ROUTERS_DIR="${FORGE_API_ROUTERS_DIR:-services/api/app/routers}"
41
+ FORGE_API_MAIN="${FORGE_API_MAIN:-services/api/app/main.py}"
42
+ FORGE_API_MIDDLEWARE_DIR="${FORGE_API_MIDDLEWARE_DIR:-services/api/app/middleware}"
43
+ FORGE_API_SERVICES_DIR="${FORGE_API_SERVICES_DIR:-services/api}"
44
+ FORGE_WORKER_DIR="${FORGE_WORKER_DIR:-services/worker}"
45
+ FORGE_COMPONENTS_DIR="${FORGE_COMPONENTS_DIR:-web/src/components}"
46
+
26
47
  BLOCKING=0
27
48
  WARNINGS=0
28
49
 
29
50
  # --- Next.js Route Handler registration check ---
30
51
  while read -r f; do
31
- URL_PATH=$(echo "$f" | sed 's|^web/src/app||; s|/route\.ts$||; s|\[.*\]|*|g')
52
+ URL_PATH=$(echo "$f" | sed "s|^${FORGE_PAGES_ROOT}||; s|/route\\.ts\$||; s|\\[.*\\]|*|g")
32
53
  ROUTE_SEGMENT=$(echo "$URL_PATH" | sed 's|/api/v1/||; s|/.*||')
33
54
 
34
55
  # Check if next.config.js has a rewrite that might shadow this route
@@ -48,50 +69,50 @@ while read -r f; do
48
69
  WARNINGS=$((WARNINGS + 1))
49
70
  fi
50
71
  fi
51
- done < <(echo "$FILES" | grep -E "^web/src/app/api/.*route\.ts$") || true
72
+ done < <(echo "$FILES" | grep -E "^${FORGE_PAGES_ROOT}/api/.*route\\.ts$") || true
52
73
 
53
74
  # --- Python API Router registration check ---
54
75
  while read -r f; do
55
76
  ROUTER_NAME=$(basename "$f" .py)
56
- MAIN_PY="$REPO_ROOT/services/api/app/main.py"
77
+ MAIN_PY="$REPO_ROOT/${FORGE_API_MAIN}"
57
78
 
58
79
  if [ -f "$MAIN_PY" ]; then
59
80
  if grep -q "$ROUTER_NAME" "$MAIN_PY" 2>/dev/null; then
60
- echo "OK: API Router '$ROUTER_NAME' ($f) — registered in main.py"
81
+ echo "OK: API Router '$ROUTER_NAME' ($f) — registered in $(basename "$MAIN_PY")"
61
82
  else
62
- echo "BLOCKING: API Router '$ROUTER_NAME' ($f) — NOT found in main.py. Router will not be reachable."
83
+ echo "BLOCKING: API Router '$ROUTER_NAME' ($f) — NOT found in $(basename "$MAIN_PY"). Router will not be reachable."
63
84
  BLOCKING=$((BLOCKING + 1))
64
85
  fi
65
86
  else
66
- echo "WARNING: Cannot verify router registration — main.py not found at $MAIN_PY"
87
+ echo "WARNING: Cannot verify router registration — API main not found at $MAIN_PY"
67
88
  WARNINGS=$((WARNINGS + 1))
68
89
  fi
69
- done < <(echo "$FILES" | grep -E "^services/api/app/routers/.*\.py$") || true
90
+ done < <(echo "$FILES" | grep -E "^${FORGE_API_ROUTERS_DIR}/.*\\.py$") || true
70
91
 
71
92
  # --- Python Middleware registration check ---
72
93
  while read -r f; do
73
94
  MIDDLEWARE_NAME=$(basename "$f" .py)
74
- MAIN_PY="$REPO_ROOT/services/api/app/main.py"
95
+ MAIN_PY="$REPO_ROOT/${FORGE_API_MAIN}"
75
96
 
76
97
  if [ -f "$MAIN_PY" ]; then
77
98
  if grep -q "$MIDDLEWARE_NAME" "$MAIN_PY" 2>/dev/null; then
78
- echo "OK: Middleware '$MIDDLEWARE_NAME' ($f) — registered in main.py"
99
+ echo "OK: Middleware '$MIDDLEWARE_NAME' ($f) — registered in $(basename "$MAIN_PY")"
79
100
  else
80
- echo "WARNING: Middleware '$MIDDLEWARE_NAME' ($f) — not found in main.py. May not be active."
101
+ echo "WARNING: Middleware '$MIDDLEWARE_NAME' ($f) — not found in $(basename "$MAIN_PY"). May not be active."
81
102
  WARNINGS=$((WARNINGS + 1))
82
103
  fi
83
104
  fi
84
- done < <(echo "$FILES" | grep -E "^services/api/app/middleware/.*\.py$") || true
105
+ done < <(echo "$FILES" | grep -E "^${FORGE_API_MIDDLEWARE_DIR}/.*\\.py$") || true
85
106
 
86
107
  # --- Shared module import check ---
87
108
  while read -r f; do
88
109
  MODULE_NAME=$(basename "$f" .py)
89
110
 
90
- IMPORTERS=$(grep -rl "$MODULE_NAME" "$REPO_ROOT/services/api/" "$REPO_ROOT/services/worker/" 2>/dev/null | head -5)
111
+ IMPORTERS=$(grep -rl "$MODULE_NAME" "$REPO_ROOT/${FORGE_API_SERVICES_DIR}/" "$REPO_ROOT/${FORGE_WORKER_DIR}/" 2>/dev/null | head -5)
91
112
  if [ -n "$IMPORTERS" ]; then
92
113
  echo "OK: Shared module '$MODULE_NAME' ($f) — imported by services"
93
114
  else
94
- echo "WARNING: Shared module '$MODULE_NAME' ($f) — no imports found in services/api/ or services/worker/"
115
+ echo "WARNING: Shared module '$MODULE_NAME' ($f) — no imports found in ${FORGE_API_SERVICES_DIR}/ or ${FORGE_WORKER_DIR}/"
95
116
  WARNINGS=$((WARNINGS + 1))
96
117
  fi
97
118
  done < <(echo "$FILES" | grep -E "^shared/.*\.py$") || true
@@ -100,14 +121,14 @@ done < <(echo "$FILES" | grep -E "^shared/.*\.py$") || true
100
121
  while read -r f; do
101
122
  COMPONENT_NAME=$(basename "$f" .tsx)
102
123
 
103
- IMPORTERS=$(grep -rl "$COMPONENT_NAME" "$REPO_ROOT/web/src/app/" "$REPO_ROOT/web/src/components/" 2>/dev/null | grep -v "$f" | head -3)
124
+ IMPORTERS=$(grep -rl "$COMPONENT_NAME" "$REPO_ROOT/${FORGE_PAGES_ROOT}/" "$REPO_ROOT/${FORGE_COMPONENTS_DIR}/" 2>/dev/null | grep -v "$f" | head -3)
104
125
  if [ -n "$IMPORTERS" ]; then
105
126
  echo "OK: Component '$COMPONENT_NAME' ($f) — imported by other files"
106
127
  else
107
128
  echo "WARNING: Component '$COMPONENT_NAME' ($f) — no imports found. May be unused or new."
108
129
  WARNINGS=$((WARNINGS + 1))
109
130
  fi
110
- done < <(echo "$FILES" | grep -E "^web/src/components/.*\.tsx$") || true
131
+ done < <(echo "$FILES" | grep -E "^${FORGE_COMPONENTS_DIR}/.*\\.tsx$") || true
111
132
 
112
133
  # --- Exit code ---
113
134
  if [ "$BLOCKING" -gt 0 ]; then
@@ -24,6 +24,24 @@ DIFF_INPUT="${1:--}"
24
24
  CHANGED_FILES_INPUT="${2:--}"
25
25
  REPO_ROOT="${3:-.}"
26
26
 
27
+ # --- Secrets backend guard ---
28
+ # This script only applies when the project uses SOPS as its secrets backend.
29
+ # Read the configured backend from the FORGE_SECRETS_BACKEND env var (set by the
30
+ # calling pipeline) or fall back to parsing forge.yaml in the repo root.
31
+ #
32
+ # If the backend is not "sops" (or is unset), exit 0 with a skip message.
33
+ # This is a clean no-op — not a false-pass — so callers can distinguish
34
+ # "SOPS configured and passed" from "SOPS not in use on this project".
35
+ _SECRETS_BACKEND="${FORGE_SECRETS_BACKEND:-}"
36
+ if [ -z "$_SECRETS_BACKEND" ] && [ -f "$REPO_ROOT/forge.yaml" ]; then
37
+ _SECRETS_BACKEND=$(grep -E '^\s*secrets_backend:' "$REPO_ROOT/forge.yaml" \
38
+ | head -1 | sed 's/.*secrets_backend:[[:space:]]*//' | tr -d '"' | tr -d "'" | xargs)
39
+ fi
40
+ if [ "$_SECRETS_BACKEND" != "sops" ]; then
41
+ echo "SKIP: verify-sops-chain — secrets_backend is '${_SECRETS_BACKEND:-none}' (not sops). Configure deploy.secrets_backend: sops in forge.yaml to enable SOPS chain verification."
42
+ exit 0
43
+ fi
44
+
27
45
  if [ "$DIFF_INPUT" = "-" ]; then
28
46
  DIFF_CONTENT=$(cat)
29
47
  else
@@ -0,0 +1,96 @@
1
+ ---
2
+ authority: required
3
+ scope: project
4
+ applies_to: [work-on, review-pr, issue, orchestrate, quality-gate]
5
+ ---
6
+
7
+ # DevDocs — Authoritative Knowledge Base
8
+
9
+ This directory contains the authoritative knowledge base for your project. Pipeline agents (ForgeDock commands) read these files as **binding source-of-truth** before acting — not as suggestions.
10
+
11
+ ---
12
+
13
+ ## Purpose
14
+
15
+ DevDocs bridge the gap between what agents know by default and what your project requires. They answer:
16
+
17
+ - How do we use ForgeDock in this project? (`agent/using-forgedock.md`)
18
+ - How do we use GitHub in this project? (`agent/using-github.md`)
19
+ - What templates do we use? (`templates/`)
20
+ - What is this project's tech stack, architecture, and conventions? (`project/`)
21
+
22
+ ---
23
+
24
+ ## Directory Structure
25
+
26
+ ```
27
+ devdocs/
28
+ README.md ← you are here
29
+ agent/
30
+ using-forgedock.md ← ForgeDock pipeline how-to (all phases, lanes, commands)
31
+ using-github.md ← GitHub CLI, branch naming, labels, commit discipline
32
+ templates/
33
+ issue.md ← reusable issue body template
34
+ pull-request.md ← reusable PR body template
35
+ commit-convention.md ← conventional commit reference
36
+ review-finding.md ← review-finding issue template
37
+ project/
38
+ custom-instructions.md ← user binding directives (HIGHEST precedence)
39
+ stack.md ← tech stack description
40
+ architecture.md ← system and domain overview
41
+ conventions.md ← coding standards and patterns
42
+ glossary.md ← domain terms and definitions
43
+ ```
44
+
45
+ ---
46
+
47
+ ## Precedence Rules
48
+
49
+ When a conflict arises between different knowledge sources, agents follow this priority order:
50
+
51
+ | Priority | Source | Description |
52
+ |----------|--------|-------------|
53
+ | 1 (highest) | `project/custom-instructions.md` | Explicit user-authored directives. Always wins. |
54
+ | 2 | Other `project/*.md` files | Authoritative project context (stack, architecture, conventions) |
55
+ | 3 | `agent/*.md` files | Authoritative ForgeDock/GitHub usage instructions |
56
+ | 4 | `templates/*.md` files | Standard templates (lower authority than instructions) |
57
+ | 5 | Agent memory | Recalled knowledge from past sessions |
58
+ | 6 (lowest) | Agent defaults | Built-in behaviors when no other source applies |
59
+
60
+ **Rule**: When `custom-instructions.md` says X, agents do X — even if their training or memory says otherwise.
61
+
62
+ ---
63
+
64
+ ## Authority Levels
65
+
66
+ Each file declares an `authority` field in its frontmatter:
67
+
68
+ | Authority | Meaning |
69
+ |-----------|---------|
70
+ | `required` | Agent MUST read this file before acting in its domain |
71
+ | `recommended` | Agent SHOULD read this file; improves output quality |
72
+ | `reference` | Agent MAY consult this file; informational only |
73
+
74
+ ---
75
+
76
+ ## How Agents Use DevDocs
77
+
78
+ 1. **Before investigating**: Read `agent/using-forgedock.md` and `project/custom-instructions.md`
79
+ 2. **Before building**: Read `agent/using-github.md`, relevant `project/*.md`, applicable `templates/*.md`
80
+ 3. **Before reviewing**: Read `project/conventions.md`, `project/stack.md`
81
+ 4. **Always**: Treat `project/custom-instructions.md` as the final authority
82
+
83
+ ---
84
+
85
+ ## Regeneration
86
+
87
+ If this directory was scaffolded by `npx forgedock docs init`, re-running that command will add any new template files introduced in newer ForgeDock versions. It will **not** overwrite files you have edited (idempotent).
88
+
89
+ ---
90
+
91
+ ## Maintenance Notes
92
+
93
+ - Edit `project/*.md` files to reflect your project's actual stack, architecture, and conventions
94
+ - Edit `project/custom-instructions.md` to add binding directives for your project
95
+ - Do NOT edit `agent/*.md` unless you want to override ForgeDock's default behavior for this project
96
+ - `templates/*.md` files can be customized; changes affect what pipeline agents use as templates