forgedock 1.0.16 → 1.0.17

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 (71) hide show
  1. package/README.md +21 -3
  2. package/bin/forgedock.mjs +1992 -540
  3. package/bin/github-app-manifest.json.license +2 -0
  4. package/bin/hooks/session-start.mjs +4 -5
  5. package/bin/registry.mjs +20 -0
  6. package/bin/tui.mjs +172 -96
  7. package/commands/adopt.md +433 -0
  8. package/commands/analytics.md +2 -0
  9. package/commands/audit-agents.md +2 -0
  10. package/commands/audit.md +2 -0
  11. package/commands/changelog.md +354 -0
  12. package/commands/cleanup.md +2 -0
  13. package/commands/compat-audit.md +330 -0
  14. package/commands/deploy-info.md +6 -5
  15. package/commands/diagnose.md +483 -0
  16. package/commands/explain.md +349 -0
  17. package/commands/forge-stats.md +2 -0
  18. package/commands/forgedock-init.md +2 -0
  19. package/commands/geo-audit.md +2 -0
  20. package/commands/incident-response.md +2 -0
  21. package/commands/issue.md +2 -0
  22. package/commands/milestone.md +2 -0
  23. package/commands/optimize.md +411 -0
  24. package/commands/orchestrate.md +118 -0
  25. package/commands/pipeline-health.md +60 -1
  26. package/commands/qa-sweep.md +2 -0
  27. package/commands/quality-gate.md +37 -0
  28. package/commands/replay.md +263 -0
  29. package/commands/resume.md +264 -0
  30. package/commands/review-pr-agents.md +5 -1
  31. package/commands/review-pr-staging.md +2 -0
  32. package/commands/review-pr.md +85 -3
  33. package/commands/rollback.md +2 -0
  34. package/commands/scope.md +280 -0
  35. package/commands/security-audit.md +2 -0
  36. package/commands/status.md +262 -0
  37. package/commands/sync-ecosystem.md +2 -0
  38. package/commands/validate.md +2 -0
  39. package/commands/work-on/build/architect.md +128 -18
  40. package/commands/work-on/build/context.md +130 -17
  41. package/commands/work-on/build/implement.md +2 -0
  42. package/commands/work-on/build/validate.md +2 -0
  43. package/commands/work-on/build.md +32 -7
  44. package/commands/work-on/close.md +85 -0
  45. package/commands/work-on/decompose.md +2 -0
  46. package/commands/work-on/investigate.md +30 -3
  47. package/commands/work-on/review.md +13 -1
  48. package/commands/work-on-monolithic.md +2 -0
  49. package/commands/work-on.md +624 -36
  50. package/docs/BRAND.md +51 -0
  51. package/docs/CONFIG.md +94 -0
  52. package/docs/articles/per-repo-adaptive-scripts-token-savings.md +174 -0
  53. package/docs/claude-breakpoints.json +47 -0
  54. package/docs/site/getting-started.md +21 -0
  55. package/package.json +3 -3
  56. package/scripts/classify-lane.sh +145 -0
  57. package/scripts/transition-label.sh +161 -0
  58. package/scripts/validate-pr-target.sh +30 -0
  59. package/templates/devdocs/README.md +72 -0
  60. package/templates/devdocs/agent/using-forgedock.md +3 -0
  61. package/templates/devdocs/agent/using-github.md +3 -0
  62. package/templates/devdocs/index.yaml +162 -0
  63. package/templates/devdocs/project/architecture.md +3 -0
  64. package/templates/devdocs/project/conventions.md +3 -0
  65. package/templates/devdocs/project/custom-instructions.md +3 -0
  66. package/templates/devdocs/project/glossary.md +3 -0
  67. package/templates/devdocs/project/stack.md +3 -0
  68. package/templates/devdocs/templates/commit-convention.md +3 -0
  69. package/templates/devdocs/templates/issue.md +3 -0
  70. package/templates/devdocs/templates/pull-request.md +3 -0
  71. package/templates/devdocs/templates/review-finding.md +3 -0
package/docs/BRAND.md ADDED
@@ -0,0 +1,51 @@
1
+ # ForgeDock Brand Handles
2
+
3
+ Status of reserved and blocked brand handles across platforms.
4
+
5
+ ## Domain
6
+
7
+ | Domain | Status |
8
+ |--------|--------|
9
+ | `forgedock.dev` | **Owned** — canonical marketing and App URL |
10
+
11
+ ## npm
12
+
13
+ | Package | Status |
14
+ |---------|--------|
15
+ | `forgedock` | **Owned** — published AGPL CLI at https://www.npmjs.com/package/forgedock |
16
+
17
+ No action needed. The package name was claimed on first publish.
18
+
19
+ ## GitHub Organization
20
+
21
+ | Slug | Status |
22
+ |------|--------|
23
+ | `forgedock` | **Blocked** — parked org created 2024-05-23, not administered by RapierCraft Studios |
24
+
25
+ The bare `forgedock` org slug cannot be used for the ForgeDock GitHub App name — GitHub
26
+ slugifies App display names and rejects collisions with existing user/org accounts.
27
+
28
+ **Recommended App slug**: `forgedock-ai` (or `forgedock-app`). The App ID in use during
29
+ development is **3978349** (registered under RapierCraftStudios with `public: false`).
30
+ Update the display name and slug when the L2 central public App launches.
31
+
32
+ ## Social Handles
33
+
34
+ | Platform | Handle | Status |
35
+ |----------|--------|--------|
36
+ | X / Twitter | `@forgedock` | Check and reserve if available |
37
+ | Bluesky | `forgedock.bsky.social` | Check and reserve if available |
38
+ | LinkedIn | `forgedock` company page | Check and reserve if available |
39
+ | Product Hunt | `forgedock` | Reserve at launch |
40
+
41
+ Social handle registration is an operational task. Reserve handles before public launch
42
+ (L1 milestone) to prevent squatting. The public App launch (L2) is gated on L1 completion.
43
+
44
+ ## Summary
45
+
46
+ | Platform | Action |
47
+ |----------|--------|
48
+ | Domain | Done |
49
+ | npm | Done |
50
+ | GitHub org slug | Blocked — use variant for App slug |
51
+ | Social handles | Reserve before L1 public launch |
package/docs/CONFIG.md CHANGED
@@ -41,6 +41,7 @@ The default (`npx forgedock init` with no flags) remains the zero-question autop
41
41
  | [`devdocs`](#devdocs-optional) | No | Devdocs knowledge tree path |
42
42
  | [`verification`](#verification-optional) | No | Health-check patterns |
43
43
  | [`billing`](#billing-optional) | No | Enable financial integrity audit phase |
44
+ | [`adaptive_scripts`](#adaptive_scripts-optional) | No | Per-repo script override configuration |
44
45
 
45
46
  ---
46
47
 
@@ -330,14 +331,38 @@ Run `npx forgedock docs init` to scaffold the tree from ForgeDock's seed templat
330
331
  ```yaml
331
332
  devdocs:
332
333
  path: "devdocs"
334
+ # index_path: "devdocs/index.yaml" # optional; defaults to {path}/index.yaml
333
335
  ```
334
336
 
335
337
  | Field | Type | Required | Description |
336
338
  |-------|------|----------|-------------|
337
339
  | `path` | string (relative path) | No | Path to the devdocs tree, relative to project root. Default: `devdocs`. |
340
+ | `index_path` | string (relative or absolute path) | No | Path to the selective loading index file. Default: `{path}/index.yaml`. When the index file exists at this path, agents read it first (~400 tokens) and load only docs whose domain matches the current issue's labels. When absent, agents fall back to loading all docs with `applies_to: work-on` (backward compatible). Scaffold the index with `npx forgedock docs init`. |
338
341
 
339
342
  **Commands that use this section**: `docs init`, `work-on/build/context` (Phase C-1), `work-on/build/architect` (Phase A0)
340
343
 
344
+ ### Selective Loading (index.yaml)
345
+
346
+ When `devdocs/index.yaml` exists, agents use **domain-filtered selective loading** instead of reading all applicable devdocs:
347
+
348
+ 1. Read `index.yaml` (~400 tokens)
349
+ 2. Extract issue labels (e.g. `billing`, `infra`, `auth`)
350
+ 3. Load only docs in matching domains + all `always_load` entries
351
+ 4. When no labels match any domain key: load only `always_load` entries
352
+
353
+ **Domain matching**: GitHub issue labels map directly to domain keys in `index.yaml`. For example, a label `billing` matches `domains.billing`. Prefixes like `workflow:`, `priority:`, and `review-finding` are stripped before matching.
354
+
355
+ **`always_load` entries** are loaded for every task regardless of domain. Use for `project/custom-instructions.md` and other files every agent must read.
356
+
357
+ **Token savings**: A typical task loads 1-3 docs (~1,500-3,000 tokens) instead of all docs (~8,000-12,000 tokens). The index itself costs ~400 tokens — break-even at 1 file avoided.
358
+
359
+ **Backward compatibility**: If `index.yaml` is absent, behavior is unchanged — all docs with `applies_to: work-on` are loaded. No migration required for existing devdocs trees.
360
+
361
+ Scaffold the index with:
362
+ ```bash
363
+ npx forgedock docs init
364
+ ```
365
+
341
366
  ### Migration from `review.context`
342
367
 
343
368
  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`:
@@ -431,6 +456,75 @@ billing:
431
456
 
432
457
  ---
433
458
 
459
+ ## `adaptive_scripts` (OPTIONAL)
460
+
461
+ Per-repo script override configuration. Controls whether ForgeDock looks for project-specific scripts in `.forgedock/scripts/` before falling back to universal scripts.
462
+
463
+ ```yaml
464
+ adaptive_scripts:
465
+ enabled: true
466
+ directory: ".forgedock/scripts"
467
+ commit: false
468
+ ```
469
+
470
+ | Field | Type | Required | Default | Description |
471
+ |-------|------|----------|---------|-------------|
472
+ | `enabled` | boolean | No | `true` | When `true`, pipeline agents check `.forgedock/scripts/` for a per-repo script before using the universal one. Set to `false` to disable per-repo overrides entirely and always use universal scripts. |
473
+ | `directory` | string (relative path) | No | `".forgedock/scripts"` | Directory where per-repo adaptive scripts live, relative to the project root. Scaffolded by `npx forgedock init`. |
474
+ | `commit` | boolean | No | `false` | When `false`, `.forgedock/scripts/` is `.gitignore`d — scripts are local-only and not shared with the team. Set to `true` (and remove the `.gitignore` entry) to commit per-repo scripts to version control. |
475
+
476
+ **Commands that use this section**: `work-on` (Phase 0B script resolution), any pipeline command that calls a deterministic script
477
+
478
+ ### Script Precedence
479
+
480
+ ForgeDock resolves which script handles each operation using a strict 4-level hierarchy (highest to lowest authority):
481
+
482
+ ```
483
+ 1. forge.yaml → learned: (machine-captured corrections) ← highest
484
+ 2. .forgedock/scripts/{operation}.sh (per-repo adaptive)
485
+ 3. scripts/{operation}.sh (universal, ships with npm)
486
+ 4. Prose instructions in command specs (fallback) ← lowest
487
+ ```
488
+
489
+ ### Override Semantics
490
+
491
+ - **Per-repo scripts completely replace** the universal script for that operation — there is no partial inheritance or merging.
492
+ - **Per-repo scripts may call universal scripts** via the `$FORGEDOCK_SCRIPTS/{operation}.sh` path. Every universal script exports `FORGEDOCK_SCRIPTS` (absolute path to the universal scripts directory) and `FORGEDOCK_HOME` (absolute path to the ForgeDock installation root) so that per-repo scripts can delegate back to them.
493
+ - **No circular dependencies**: per-repo scripts may call universal scripts but must NOT call other per-repo scripts. One level of delegation only.
494
+ - **`forge.yaml → learned:`** overrides take precedence over everything. They represent explicit user corrections captured by the pipeline.
495
+
496
+ ### Example: per-repo script that delegates to universal
497
+
498
+ ```bash
499
+ #!/usr/bin/env bash
500
+ # .forgedock/scripts/classify-lane.sh
501
+ # Override: this repo uses 'develop' instead of 'staging' for the fast lane.
502
+
503
+ set -euo pipefail
504
+
505
+ # Delegate to universal classify-lane.sh to get the standard result
506
+ UNIVERSAL_RESULT=$(bash "$FORGEDOCK_SCRIPTS/classify-lane.sh" "$@")
507
+
508
+ # Override only the fast-lane output for this project
509
+ if [ "$UNIVERSAL_RESULT" = "staging" ]; then
510
+ echo "develop"
511
+ else
512
+ echo "$UNIVERSAL_RESULT"
513
+ fi
514
+ ```
515
+
516
+ ### Logging
517
+
518
+ When a pipeline agent resolves a script tier, it logs the result in the FORGE annotation:
519
+
520
+ ```
521
+ Script tier: adaptive (.forgedock/scripts/classify-lane.sh)
522
+ Script tier: universal (scripts/classify-lane.sh)
523
+ Script tier: prose (no script found — using spec instructions)
524
+ ```
525
+
526
+ ---
527
+
434
528
  ## Label Bootstrap
435
529
 
436
530
  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.
@@ -0,0 +1,174 @@
1
+ ---
2
+ title: "Per-Repo Adaptive Scripts: Measured Token Savings vs Per-Session Rediscovery"
3
+ description: "Every AI coding session rediscovers the same project-specific patterns — branch names, test commands, commit style. We measured the cost and quantified how per-repo adaptive scripts eliminate it."
4
+ tags: ["ai", "performance", "tokens", "productivity", "opensource"]
5
+ cover_image:
6
+ canonical_url: https://github.com/RapierCraftStudios/ForgeDock
7
+ published: false
8
+ ---
9
+
10
+ <!-- Generated by ForgeDock pipeline — Issue #673 -->
11
+
12
+ AI coding agents are expensive to run. Every session starts from scratch, re-reading files, running commands, and re-learning the same project-specific patterns that have not changed since last week. This article measures how much that costs, and what per-repo adaptive scripts do about it.
13
+
14
+ ---
15
+
16
+ ## The Problem: Per-Session Rediscovery
17
+
18
+ Every time a ForgeDock agent starts working on an issue, it must answer the same questions about the project:
19
+
20
+ - What is the PR base branch? (staging? milestone/something? main?)
21
+ - How do I run the tests? (pnpm test? pytest? npm run test:unit?)
22
+ - What commit format does this project use? (conventional commits? what scope?)
23
+ - Where do the tests live? (tests/? __tests__/? spec/?)
24
+ - What workflow labels exist on this repo?
25
+
26
+ None of these change between sessions. The codebase does not reorganize its test directory overnight. The commit convention does not shift on a Tuesday. But the agent re-discovers all of them from scratch on every run — reading files, executing commands, inferring patterns.
27
+
28
+ We measured this cost across five representative completed issues.
29
+
30
+ ---
31
+
32
+ ## Methodology
33
+
34
+ We analyzed five pipeline sessions from the ForgeDock dogfooding repository (issues #674, #669, #671, #679, #676). For each session, we identified every tool call that was a "rediscovery call" — a call whose purpose was to learn something about the project that was already true in the previous session.
35
+
36
+ Token counts were estimated at 1 token per 4 characters (conservative; actual tokenization may differ by model and content type). We counted command invocation + output, not context window overhead.
37
+
38
+ ---
39
+
40
+ ## Baseline: Per-Session Rediscovery Cost
41
+
42
+ | Operation | Mechanism (baseline) | Token estimate |
43
+ |-----------|---------------------|----------------|
44
+ | forge.yaml full read | Read 111-line, 4,228-byte file | ~1,050 |
45
+ | Branch name determination | `gh issue view` + LLM milestone-to-slug inference | ~350 |
46
+ | Commit style detection | `git log --oneline -5` + LLM pattern inference | ~200 |
47
+ | Test command discovery | Read package.json/pyproject.toml + grep test scripts | ~400 |
48
+ | Test location discovery | `ls tests/`, `ls __tests__/`, parse package.json | ~250 |
49
+ | Label scheme discovery | `gh label list` or inferred from pipeline comments | ~300 |
50
+ | **Total per session** | | **~2,550 tokens** |
51
+
52
+ These numbers are per-session. On a repository with active development (10-30 issues/month), this rediscovery tax runs 25,500–76,500 tokens/month on patterns that have not changed.
53
+
54
+ The branch name example is instructive. Before `classify-lane.sh` was introduced in #669, agents would:
55
+
56
+ 1. Call `gh issue view NUMBER --json milestone` (~200 tokens output)
57
+ 2. Extract the milestone title string
58
+ 3. LLM-infer the slug transformation (`Deterministic Pipeline v2` → `milestone/deterministic-pipeline-v2`)
59
+ 4. Sometimes get it wrong and hallucinate `milestone/project-agnostic` (the bug that motivated #639)
60
+
61
+ After `classify-lane.sh`: one deterministic script execution with a 6-token output. No LLM inference in the critical path.
62
+
63
+ ---
64
+
65
+ ## Target: Per-Repo Adaptive Script Overhead
66
+
67
+ After `/optimize` generates `.forgedock/scripts/` entries from `forge.yaml → learned:`, the same operations become:
68
+
69
+ | Script | Size | Execution cost |
70
+ |--------|------|----------------|
71
+ | `branch-targets.sh` | 23 lines, ~470 bytes | ~170 tokens |
72
+ | `run-tests.sh` | 10 lines, ~200 bytes | ~80 tokens |
73
+ | `format-commit.sh` | 15 lines, ~300 bytes | ~100 tokens |
74
+ | `forge.yaml` learned section (4 targeted yq reads) | subset of 4,228-byte file | ~100 tokens |
75
+ | **Total per session** | | **~450 tokens** |
76
+
77
+ The key insight: a script call costs roughly the script size (to read) plus the output size (to receive). A 23-line branch-targets.sh costs ~118 tokens to read and produces 1 line of output. The equivalent LLM-based rediscovery costs ~350 tokens and occasionally hallucinates.
78
+
79
+ ---
80
+
81
+ ## Savings Calculation
82
+
83
+ ```
84
+ savings_per_session = 2,550 - 450 = 2,100 tokens
85
+
86
+ range:
87
+ low = 1,200 tokens (simple fast-lane issues, no test discovery needed)
88
+ high = 3,500 tokens (complex multi-file issues with full pattern rediscovery)
89
+ ```
90
+
91
+ At claude-sonnet-4-5 pricing ($3.00 per million input tokens):
92
+
93
+ ```
94
+ 2,100 tokens/session × $3.00 / 1,000,000 = $0.0063/session
95
+ ```
96
+
97
+ At observed ForgeDock dogfooding pace (5–15 issues/day, averaging ~10):
98
+
99
+ ```
100
+ 300 sessions/month × $0.0063 = $1.89/month per repo
101
+ ```
102
+
103
+ For teams running ForgeDock at production scale across multiple repositories, these savings compound. A team with 5 active repos at 300 sessions/month each saves ~$9.45/month from adaptive scripts alone. The cost of running `/optimize` once per repo to generate the scripts: effectively zero (a single session that generates ~5 scripts).
104
+
105
+ **Payback period: 1 session.**
106
+
107
+ ---
108
+
109
+ ## Comparison with DevDocs
110
+
111
+ Per-repo scripts and devdocs solve different problems:
112
+
113
+ | Pattern type | Script approach | DevDocs approach | Winner |
114
+ |-------------|----------------|-----------------|--------|
115
+ | Branch target | `branch-targets.sh` — 23 lines, 1 execution call | 1 line in architecture.md | **DevDocs** (simpler for static values already documented) |
116
+ | Test commands | `run-tests.sh` — executable, deterministic output | Section in devdocs, LLM parses prose | **Scripts** (executable beats interpreted) |
117
+ | Commit format | `format-commit.sh` — outputs exact string | Convention in devdocs, LLM infers | **Scripts** (deterministic output vs interpretation) |
118
+ | Architecture decisions | Cannot encode reasoning in scripts | `devdocs/project/architecture.md` | **DevDocs** (irreplaceable for reasoning context) |
119
+ | Debug runbooks | Script could wrap commands, but context matters | DevDocs with structured steps | **DevDocs** (context-dependent) |
120
+
121
+ The boundary rule: if the knowledge produces a **deterministic output** (a branch name, a command string, a file path), encode it as a script. If it requires **contextual interpretation** (design rationale, tradeoff analysis, conventions with exceptions), encode it in devdocs.
122
+
123
+ Per-repo scripts replace approximately 25–40% of devdocs content for projects with established operational patterns. This reduces per-session devdocs loading by an estimated 500–1,000 tokens, complementing the token savings from selective devdocs loading introduced in #675.
124
+
125
+ **Combined savings per session** (adaptive scripts + devdocs selective loading):
126
+
127
+ ```
128
+ Rediscovery elimination (adaptive scripts): ~2,100 tokens
129
+ Devdocs selective loading (#675): ~1,000 tokens
130
+ ────────────────────────────────────────────────────────
131
+ Total combined: ~3,100 tokens/session
132
+ ```
133
+
134
+ ---
135
+
136
+ ## What Gets Generated
137
+
138
+ Running `/optimize` on a ForgeDock repository after the `learned:` section is populated produces:
139
+
140
+ | Script | Trigger | What it replaces |
141
+ |--------|---------|-----------------|
142
+ | `branch-targets.sh` | `learned.branch_targets.staging` is set | gh issue milestone lookup + LLM slug inference |
143
+ | `run-tests.sh` | `learned.test_commands` is non-empty | package.json/pyproject.toml read + LLM test command inference |
144
+ | `format-commit.sh` | `learned.commit_style` is set + 3+ commits confirm pattern | git log --oneline + LLM conventional commit inference |
145
+ | `find-tests.sh` | `learned.test_locations` is non-empty | ls tests/, __tests__/ + LLM path inference |
146
+ | `label-map.sh` | `learned.label_map` is non-empty | gh label list + LLM label mapping |
147
+
148
+ Each script is generated at confidence >= 0.7 (two independent signals) or 1.0 (explicit `learned:` value). The confidence threshold ensures scripts are only generated when there is enough signal to trust the encoded knowledge.
149
+
150
+ ---
151
+
152
+ ## Limitations and Confidence Intervals
153
+
154
+ The estimates in this article carry these caveats:
155
+
156
+ 1. **Token counting method**: We use 1 token per 4 characters. Actual tokenization varies by model and content type (code tokenizes more densely than prose). Error: ±20%.
157
+
158
+ 2. **Baseline measurement**: We analyzed 5 issues from one repository (ForgeDock itself). A ForgeDock-type repository (markdown command specs, minimal code) may have lower rediscovery cost than a large application codebase with many test configurations. Application repos with complex test setups may see 4,000–6,000 tokens of rediscovery per session.
159
+
160
+ 3. **LLM hallucination cost not counted**: Our baseline counts only the token cost of rediscovery, not the token cost of correcting a hallucinated branch name or wrong test command. Including rework, the actual cost of rediscovery-induced errors is higher.
161
+
162
+ 4. **Model pricing changes**: The $3.00/M figure is current as of June 2026. Pricing trends downward over time; the absolute dollar savings will decrease, but the proportional savings (rediscovery as a fraction of session cost) remain constant.
163
+
164
+ ---
165
+
166
+ ## Prioritization Conclusion
167
+
168
+ This measurement was created to inform the prioritization decision for #667 (learned section) and #668 (/optimize command). Both are now merged.
169
+
170
+ The data confirms: **adaptive scripts are worth implementing.** The payback period is less than one session. The primary value is not dollar savings (which are modest for individual repos) but **reliability** — replacing LLM inference with deterministic script output eliminates a class of hallucination errors that were causing production-impacting bugs (see #639: agents hallucinating `milestone/project-agnostic` instead of `staging`).
171
+
172
+ Token savings are the measurable proxy for the deeper value: an agent that runs `branch-targets.sh` and gets `milestone/deterministic-pipeline-v2` in 6 tokens cannot hallucinate the branch name. An agent that reads a 350-token prose description and infers the branch name sometimes gets it wrong.
173
+
174
+ Scripts do not just save tokens. They eliminate a category of error.
@@ -0,0 +1,47 @@
1
+ {
2
+ "_comment": "claude-breakpoints.json — structured registry of known Claude Code version breakpoints. Each entry documents a version where Claude Code changed behavior that ForgeDock depends on, introduced a feature ForgeDock leverages, or broke a capability ForgeDock uses. Format is append-only and human-editable. Consumers: detectClaudeVersion() (issue #680), /compat-audit (issue #686), forgedock doctor (issue #682).",
3
+ "schema": {
4
+ "version": "Claude Code version string where the breakpoint was introduced (e.g. '2.1.157')",
5
+ "type": "Category of change: 'feature' | 'behavior_change' | 'compatibility' | 'deprecation'",
6
+ "description": "Human-readable description of what changed in Claude Code at this version",
7
+ "forgedock_impact": "How this change affects ForgeDock — what commands, scripts, or behaviors are affected",
8
+ "severity": "Impact level if a user is on this version or older: 'high' | 'medium' | 'low' | 'info'"
9
+ },
10
+ "breakpoints": [
11
+ {
12
+ "version": "2.1.157",
13
+ "type": "behavior_change",
14
+ "description": "EnterWorktree now unlocks worktrees automatically when the agent session finishes",
15
+ "forgedock_impact": "ForgeDock no longer needs --force on worktree cleanup commands. The cleanup phase in work-on.md can use standard git worktree remove without the force flag.",
16
+ "severity": "low"
17
+ },
18
+ {
19
+ "version": "2.1.157",
20
+ "type": "feature",
21
+ "description": "Plugins in .claude/skills are auto-loaded without requiring marketplace installation",
22
+ "forgedock_impact": "Symlink-based install (the original forgedock install method) remains valid but is no longer required for skill discovery. The stub file install pattern introduced in #619 is the preferred approach and works the same way.",
23
+ "severity": "info"
24
+ },
25
+ {
26
+ "version": "2.1.163",
27
+ "type": "compatibility",
28
+ "description": "requiredMinimumVersion and requiredMaximumVersion managed settings added for enterprise deployments",
29
+ "forgedock_impact": "ForgeDock's own version check (forgedock doctor, #682) is the OSS equivalent of this enterprise feature. No conflict — enterprise users with managed settings may have stricter version constraints than ForgeDock requires.",
30
+ "severity": "info"
31
+ },
32
+ {
33
+ "version": "2.1.172",
34
+ "type": "feature",
35
+ "description": "Sub-agents can spawn sub-agents up to 5 levels deep (increased nesting depth)",
36
+ "forgedock_impact": "ForgeDock's orchestrate.md uses multi-agent orchestration. The 5-level nesting limit is compatible with ForgeDock's orchestration patterns. No changes needed.",
37
+ "severity": "info"
38
+ },
39
+ {
40
+ "version": "2.1.154",
41
+ "type": "compatibility",
42
+ "description": "Native /workflows dynamic workflows introduced as a built-in Claude Code feature",
43
+ "forgedock_impact": "Parallel to ForgeDock's orchestrate.md. ForgeDock's approach adds GitHub persistence (FORGE: annotations, label-state machine, compaction resilience) that native /workflows lacks. Both can coexist — ForgeDock is the orchestration layer with state, not a replacement for native workflows.",
44
+ "severity": "info"
45
+ }
46
+ ]
47
+ }
@@ -17,6 +17,27 @@ This tutorial gets you from zero to your first autonomous pipeline run in under
17
17
  - [Claude Code](https://docs.anthropic.com/en/docs/claude-code) installed and authenticated
18
18
  - Git and GitHub CLI (`gh`) installed and authenticated (`gh auth login`)
19
19
  - Node.js 18 or higher
20
+ - [`yq`](https://github.com/mikefarah/yq) — YAML parser used by all pipeline commands to read `forge.yaml`
21
+
22
+ **Install `yq`:**
23
+
24
+ ```bash
25
+ # macOS
26
+ brew install yq
27
+
28
+ # Ubuntu / Debian
29
+ sudo apt-get install yq
30
+ # or: sudo snap install yq
31
+
32
+ # Windows
33
+ winget install mikefarah.yq
34
+ # or: choco install yq
35
+
36
+ # Any platform (via Go)
37
+ go install github.com/mikefarah/yq/v4@latest
38
+ ```
39
+
40
+ > **Note:** Without `yq`, pipeline commands that read `forge.yaml` (including `/work-on`, `/scope`, `/orchestrate`, and most others) will fall back to defaults or skip config-driven steps silently.
20
41
 
21
42
  ---
22
43
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "forgedock",
3
- "version": "1.0.16",
3
+ "version": "1.0.17",
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"
@@ -27,7 +27,7 @@
27
27
  "type": "git",
28
28
  "url": "git+https://github.com/RapierCraftStudios/ForgeDock.git"
29
29
  },
30
- "homepage": "https://github.com/RapierCraftStudios/ForgeDock",
30
+ "homepage": "https://forgedock.dev",
31
31
  "bugs": {
32
32
  "url": "https://github.com/RapierCraftStudios/ForgeDock/issues"
33
33
  },
@@ -52,7 +52,7 @@
52
52
  },
53
53
  "peerDependenciesMeta": {
54
54
  "@anthropic-ai/claude-code": {
55
- "optional": false
55
+ "optional": true
56
56
  }
57
57
  }
58
58
  }
@@ -0,0 +1,145 @@
1
+ #!/usr/bin/env bash
2
+ # classify-lane.sh — Deterministic lane routing from issue milestone
3
+ #
4
+ # Usage: classify-lane.sh <issue_number> [-R <owner/repo>]
5
+ # issue_number: GitHub issue number (required)
6
+ # -R <owner/repo>: GitHub repository (optional, defaults to current repo)
7
+ #
8
+ # Output: lane string written to stdout
9
+ # staging — issue has no milestone (fast lane)
10
+ # milestone/{slug} — issue has a milestone (feature lane, slug = lowercased, spaces→hyphens, git-invalid chars stripped)
11
+ #
12
+ # Exit codes: 0 = success, 1 = error (invalid issue, gh auth failure, branch missing, etc.)
13
+ #
14
+ # Branch existence validation:
15
+ # Both fast-lane (staging) and feature-lane (milestone/{slug}) outputs are validated
16
+ # against the remote via `git ls-remote`. If the target branch does not exist, the
17
+ # script exits 1 with a descriptive error. This prevents agents from creating PRs
18
+ # targeting phantom branches and catches misconfigured branches.staging values early.
19
+ # Fast-lane staging branch name is read from forge.yaml (branches.staging key),
20
+ # defaulting to "staging" when forge.yaml is absent or yq is unavailable.
21
+
22
+ set -euo pipefail
23
+
24
+ ISSUE_NUMBER="${1:-}"
25
+ GH_REPO_ARGS=()
26
+
27
+ # Parse arguments: issue number + optional -R flag
28
+ if [ -z "$ISSUE_NUMBER" ]; then
29
+ echo "ERROR: issue number is required" >&2
30
+ echo "Usage: classify-lane.sh <issue_number> [-R <owner/repo>]" >&2
31
+ exit 1
32
+ fi
33
+
34
+ shift
35
+ while [ $# -gt 0 ]; do
36
+ case "$1" in
37
+ -R)
38
+ if [ $# -lt 2 ]; then
39
+ echo "ERROR: -R requires a value <owner/repo>" >&2
40
+ echo "Usage: classify-lane.sh <issue_number> [-R <owner/repo>]" >&2
41
+ exit 1
42
+ fi
43
+ if ! [[ "$2" =~ ^[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+$ ]]; then
44
+ echo "ERROR: -R value must be owner/repo format, got: $2" >&2
45
+ exit 1
46
+ fi
47
+ GH_REPO_ARGS=(-R "$2")
48
+ shift 2
49
+ ;;
50
+ *)
51
+ echo "ERROR: unknown argument: $1" >&2
52
+ exit 1
53
+ ;;
54
+ esac
55
+ done
56
+
57
+ # Validate issue number is numeric
58
+ if ! [[ "$ISSUE_NUMBER" =~ ^[0-9]+$ ]]; then
59
+ echo "ERROR: issue number must be numeric, got: $ISSUE_NUMBER" >&2
60
+ exit 1
61
+ fi
62
+
63
+ # Fetch milestone title from GitHub
64
+ # gh issue view exits non-zero if the issue does not exist or auth fails
65
+ GH_STDERR_TMP=$(mktemp)
66
+ MILESTONE_TITLE=$(gh issue view "$ISSUE_NUMBER" "${GH_REPO_ARGS[@]}" --json milestone --jq '.milestone.title // empty' 2>"$GH_STDERR_TMP") || {
67
+ echo "ERROR: failed to fetch issue #$ISSUE_NUMBER — check issue number and repo flag" >&2
68
+ cat "$GH_STDERR_TMP" >&2
69
+ rm -f "$GH_STDERR_TMP"
70
+ exit 1
71
+ }
72
+ rm -f "$GH_STDERR_TMP"
73
+
74
+ # Export universal script environment so per-repo scripts can call back into universal scripts.
75
+ # Per-repo scripts (.forgedock/scripts/{operation}.sh) source these to delegate to universal ones.
76
+ export FORGEDOCK_SCRIPTS
77
+ FORGEDOCK_SCRIPTS="$(cd "$(dirname "$0")" && pwd)"
78
+ export FORGEDOCK_HOME
79
+ FORGEDOCK_HOME="$(cd "$(dirname "$0")/.." && pwd)"
80
+
81
+ # Resolve staging branch name from forge.yaml (branches.staging), defaulting to "staging".
82
+ # Uses yq if available; falls back gracefully when forge.yaml is absent or yq is not installed.
83
+ STAGING_BRANCH=$(yq '.branches.staging // "staging"' forge.yaml 2>/dev/null || echo 'staging')
84
+ # yq returns literal "null" when the key exists but is null-valued — treat as default
85
+ [ "$STAGING_BRANCH" = "null" ] && STAGING_BRANCH="staging"
86
+ # Trim any surrounding whitespace or quotes that yq might emit
87
+ STAGING_BRANCH=$(echo "$STAGING_BRANCH" | tr -d '"' | xargs)
88
+ # Final safety net: if somehow empty, use default
89
+ [ -z "$STAGING_BRANCH" ] && STAGING_BRANCH="staging"
90
+
91
+ # Classify lane based on milestone presence
92
+ if [ -z "$MILESTONE_TITLE" ]; then
93
+ # Fast lane: validate staging branch exists on remote before returning it.
94
+ # This mirrors the feature-lane validation below and catches misconfigured
95
+ # branches.staging values early, with a descriptive error instead of an
96
+ # opaque failure in the subsequent git worktree add or gh pr create call.
97
+ if ! git ls-remote --exit-code origin "$STAGING_BRANCH" >/dev/null 2>&1; then
98
+ echo "ERROR: Fast-lane PR target branch '$STAGING_BRANCH' does not exist on remote 'origin'." >&2
99
+ echo " This branch is configured via forge.yaml → branches.staging (default: staging)." >&2
100
+ echo " Create the branch first, or update forge.yaml to point to an existing branch." >&2
101
+ echo " Run: git push origin HEAD:$STAGING_BRANCH (from the default branch)" >&2
102
+ exit 1
103
+ fi
104
+ echo "$STAGING_BRANCH"
105
+ else
106
+ # Slugify: lowercase, spaces → hyphens, strip git-invalid chars, collapse multiple hyphens,
107
+ # strip leading/trailing hyphens.
108
+ # `tr -cd 'a-z0-9-'` removes every character that is not a lowercase letter, digit, or hyphen —
109
+ # this covers all chars forbidden by git-check-ref-format (colons, brackets, parens, etc.).
110
+ # It runs after space→hyphen so that word boundaries become hyphens before the strip pass,
111
+ # and before the hyphen-collapse step so consecutive hyphens (produced by stripping special
112
+ # chars between words) are collapsed into a single hyphen.
113
+ SLUG=$(echo "$MILESTONE_TITLE" \
114
+ | tr '[:upper:]' '[:lower:]' \
115
+ | tr ' ' '-' \
116
+ | tr -cd 'a-z0-9-' \
117
+ | sed 's/--*/-/g' \
118
+ | sed 's/^-//;s/-$//')
119
+
120
+ # Guard: empty slug means the milestone title contained no ASCII letters, digits, or hyphens
121
+ # (e.g. purely Unicode/emoji titles like "🚀✨"). An empty slug would produce LANE="milestone/"
122
+ # which is an invalid branch reference — catch this early with an actionable error.
123
+ if [ -z "$SLUG" ]; then
124
+ echo "ERROR: Milestone title '$MILESTONE_TITLE' produced an empty slug after slugification." >&2
125
+ echo " Milestone titles must contain at least one ASCII letter, digit, or hyphen." >&2
126
+ echo " Rename the milestone to include an ASCII-safe name (e.g. add a short English suffix)." >&2
127
+ exit 1
128
+ fi
129
+
130
+ LANE="milestone/$SLUG"
131
+
132
+ # Validate that the computed milestone branch exists on the remote.
133
+ # A non-existent branch means either: (a) the milestone slug was hallucinated, or
134
+ # (b) the milestone branch has not been created yet. Either way, targeting it would
135
+ # strand the PR on a phantom branch — hard-fail so a human can investigate.
136
+ if ! git ls-remote --exit-code origin "$LANE" >/dev/null 2>&1; then
137
+ echo "ERROR: PR target branch '$LANE' does not exist on remote 'origin'." >&2
138
+ echo " Milestone: '$MILESTONE_TITLE' → slug: '$SLUG'" >&2
139
+ echo " Create the branch first, or check that the milestone title is correct." >&2
140
+ echo " Run: git push origin HEAD:$LANE (from the base branch)" >&2
141
+ exit 1
142
+ fi
143
+
144
+ echo "$LANE"
145
+ fi