@samahlstrom/forge-cli 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (100) hide show
  1. package/README.md +175 -0
  2. package/bin/forge.js +2 -0
  3. package/dist/addons/index.d.ts +25 -0
  4. package/dist/addons/index.js +139 -0
  5. package/dist/addons/index.js.map +1 -0
  6. package/dist/commands/add.d.ts +1 -0
  7. package/dist/commands/add.js +61 -0
  8. package/dist/commands/add.js.map +1 -0
  9. package/dist/commands/doctor.d.ts +1 -0
  10. package/dist/commands/doctor.js +177 -0
  11. package/dist/commands/doctor.js.map +1 -0
  12. package/dist/commands/ingest.d.ts +24 -0
  13. package/dist/commands/ingest.js +316 -0
  14. package/dist/commands/ingest.js.map +1 -0
  15. package/dist/commands/init.d.ts +8 -0
  16. package/dist/commands/init.js +557 -0
  17. package/dist/commands/init.js.map +1 -0
  18. package/dist/commands/remove.d.ts +1 -0
  19. package/dist/commands/remove.js +42 -0
  20. package/dist/commands/remove.js.map +1 -0
  21. package/dist/commands/status.d.ts +1 -0
  22. package/dist/commands/status.js +48 -0
  23. package/dist/commands/status.js.map +1 -0
  24. package/dist/commands/upgrade.d.ts +5 -0
  25. package/dist/commands/upgrade.js +190 -0
  26. package/dist/commands/upgrade.js.map +1 -0
  27. package/dist/detect/features.d.ts +10 -0
  28. package/dist/detect/features.js +33 -0
  29. package/dist/detect/features.js.map +1 -0
  30. package/dist/detect/go.d.ts +3 -0
  31. package/dist/detect/go.js +38 -0
  32. package/dist/detect/go.js.map +1 -0
  33. package/dist/detect/index.d.ts +25 -0
  34. package/dist/detect/index.js +32 -0
  35. package/dist/detect/index.js.map +1 -0
  36. package/dist/detect/node.d.ts +3 -0
  37. package/dist/detect/node.js +99 -0
  38. package/dist/detect/node.js.map +1 -0
  39. package/dist/detect/python.d.ts +3 -0
  40. package/dist/detect/python.js +86 -0
  41. package/dist/detect/python.js.map +1 -0
  42. package/dist/index.d.ts +1 -0
  43. package/dist/index.js +51 -0
  44. package/dist/index.js.map +1 -0
  45. package/dist/render/engine.d.ts +8 -0
  46. package/dist/render/engine.js +71 -0
  47. package/dist/render/engine.js.map +1 -0
  48. package/dist/render/merge.d.ts +5 -0
  49. package/dist/render/merge.js +33 -0
  50. package/dist/render/merge.js.map +1 -0
  51. package/dist/utils/fs.d.ts +8 -0
  52. package/dist/utils/fs.js +42 -0
  53. package/dist/utils/fs.js.map +1 -0
  54. package/dist/utils/git.d.ts +3 -0
  55. package/dist/utils/git.js +31 -0
  56. package/dist/utils/git.js.map +1 -0
  57. package/dist/utils/hash.d.ts +8 -0
  58. package/dist/utils/hash.js +22 -0
  59. package/dist/utils/hash.js.map +1 -0
  60. package/dist/utils/yaml.d.ts +3 -0
  61. package/dist/utils/yaml.js +12 -0
  62. package/dist/utils/yaml.js.map +1 -0
  63. package/package.json +53 -0
  64. package/templates/addons/beads-dolt-backend/files/dolt-setup.sh +267 -0
  65. package/templates/addons/beads-dolt-backend/manifest.yaml +13 -0
  66. package/templates/addons/browser-testing/files/browser-smoke.sh +196 -0
  67. package/templates/addons/browser-testing/files/visual-qa.md +103 -0
  68. package/templates/addons/browser-testing/manifest.yaml +20 -0
  69. package/templates/addons/compliance-hipaa/files/hipaa-checks.sh +184 -0
  70. package/templates/addons/compliance-hipaa/files/hipaa-context.md +91 -0
  71. package/templates/addons/compliance-hipaa/manifest.yaml +15 -0
  72. package/templates/addons/compliance-soc2/files/soc2-checks.sh +232 -0
  73. package/templates/addons/compliance-soc2/files/soc2-context.md +147 -0
  74. package/templates/addons/compliance-soc2/manifest.yaml +15 -0
  75. package/templates/core/CLAUDE.md.hbs +70 -0
  76. package/templates/core/agents/architect.md.hbs +68 -0
  77. package/templates/core/agents/backend.md.hbs +27 -0
  78. package/templates/core/agents/frontend.md.hbs +25 -0
  79. package/templates/core/agents/quality.md.hbs +40 -0
  80. package/templates/core/agents/security.md.hbs +53 -0
  81. package/templates/core/context/project.md.hbs +60 -0
  82. package/templates/core/forge.yaml.hbs +69 -0
  83. package/templates/core/hooks/post-edit.sh.hbs +8 -0
  84. package/templates/core/hooks/pre-edit.sh.hbs +41 -0
  85. package/templates/core/hooks/session-start.sh.hbs +34 -0
  86. package/templates/core/pipeline/classify.sh.hbs +159 -0
  87. package/templates/core/pipeline/decompose.md.hbs +100 -0
  88. package/templates/core/pipeline/deliver.sh.hbs +171 -0
  89. package/templates/core/pipeline/execute.md.hbs +138 -0
  90. package/templates/core/pipeline/intake.sh.hbs +152 -0
  91. package/templates/core/pipeline/orchestrator.sh.hbs +361 -0
  92. package/templates/core/pipeline/verify.sh.hbs +160 -0
  93. package/templates/core/settings.json.hbs +55 -0
  94. package/templates/core/skill-creator.md.hbs +151 -0
  95. package/templates/core/skill-deliver.md.hbs +46 -0
  96. package/templates/core/skill-ingest.md.hbs +245 -0
  97. package/templates/presets/go/stack.md.hbs +133 -0
  98. package/templates/presets/python-fastapi/stack.md.hbs +101 -0
  99. package/templates/presets/react-next-ts/stack.md.hbs +77 -0
  100. package/templates/presets/sveltekit-ts/stack.md.hbs +116 -0
@@ -0,0 +1,70 @@
1
+ # CLAUDE.md — Agent Harness Instructions
2
+
3
+ > Generated by forge. These instructions apply to all AI agents working in this codebase.
4
+
5
+ ## Read First
6
+
7
+ - Read `forge.yaml` for project configuration
8
+ - Read `.forge/context/stack.md` for stack-specific conventions
9
+ - Read `.forge/context/project.md` for project-specific knowledge
10
+
11
+ ## Project
12
+
13
+ - **Name**: {{project.name}}
14
+ - **Stack preset**: {{project.preset}}
15
+ {{#if onboarding.description}}
16
+ - **Description**: {{onboarding.description}}
17
+ {{/if}}
18
+ {{#if onboarding.architecture}}
19
+ - **Architecture**: {{onboarding.architecture}}
20
+ {{/if}}
21
+
22
+ ## Workflow
23
+
24
+ All non-trivial work flows through the `/deliver` command:
25
+ 1. `/deliver "description"` — starts tracked work
26
+ 2. Pipeline: intake → classify → decompose → execute → verify → deliver
27
+ 3. Every edit is tracked via beads (`.forge/beads/`)
28
+ 4. Verification runs automatically before delivery
29
+
30
+ ## Spec Ingestion
31
+
32
+ For large specs, PRDs, or requirements documents:
33
+ 1. `/ingest <spec-id>` — parse a spec into epics, features, and atomic tasks
34
+ 2. Multi-pass analysis: extract → map domains → decompose → identify skills
35
+ 3. Review and refine the plan before writing any code
36
+ 4. Generate custom skills for repetitive patterns
37
+ 5. Execute phase-by-phase through `/deliver`
38
+
39
+ Specs are stored in `.forge/specs/`. Run `forge ingest <file>` to add a new spec.
40
+
41
+ ## Quality Gates
42
+
43
+ All code must pass before delivery:
44
+ - **Typecheck**: `{{commands.typecheck}}`
45
+ - **Lint**: `{{commands.lint}}`
46
+ - **Test**: `{{commands.test}}`
47
+
48
+ ## Anti-Patterns (Blockers)
49
+
50
+ Do NOT introduce these — verification will reject them:
51
+ - `TODO` / `FIXME` comments
52
+ - `console.log` / `debugger` statements
53
+ - Hardcoded secrets or API keys
54
+ - `any` type (TypeScript projects)
55
+
56
+ ## Agent Dispatch
57
+
58
+ Available agents for subtask assignment:
59
+ {{#each agents}}
60
+ - `{{this}}` — see `.forge/agents/{{this}}.md`
61
+ {{/each}}
62
+
63
+ ## Task Tracking (bd)
64
+
65
+ - Work is tracked via `bd` (steveyegge/beads) — a Dolt-backed issue tracker
66
+ - `bd ready` — see tasks with no open blockers
67
+ - `bd update <id> --claim` — atomically claim a task
68
+ - `bd close <id> --reason "..."` — mark work complete
69
+ - The pre-edit hook blocks file changes without an in-progress task
70
+ - Use `/deliver --quick` for lightweight changes with minimal ceremony
@@ -0,0 +1,68 @@
1
+ # Architect
2
+
3
+ > Analyzes work requests and produces subtask decompositions with dependency-ordered wave plans.
4
+
5
+ ## Role
6
+
7
+ You are the Architect agent. You analyze a work request and break it into atomic, testable subtasks that can be executed by specialist agents. You never write code — you plan.
8
+
9
+ ## Process
10
+
11
+ 1. **Understand the request**: Read the work description, risk tier, and project context.
12
+
13
+ 2. **Impact analysis**: Determine which files need to be modified or created. Consider:
14
+ - Data model changes
15
+ - Service/API changes
16
+ - UI component changes
17
+ - Route changes
18
+ - Test files needed
19
+
20
+ 3. **Subtask decomposition**: Break the work into subtasks where each:
21
+ - Is atomic (one agent, one concern)
22
+ - Is testable (has a clear verification)
23
+ - Is scoped to specific files
24
+ - Has an appropriate agent assignment
25
+
26
+ 4. **Wave planning**: Order subtasks into waves where:
27
+ - All subtasks in a wave can run in parallel
28
+ - No two subtasks in the same wave touch the same file
29
+ - Dependencies between waves are respected (wave 2 depends on wave 1)
30
+
31
+ 5. **Output the plan** as JSON matching the schema below.
32
+
33
+ ## Agent Roster
34
+
35
+ Available agents for assignment:
36
+ {{#each agents}}
37
+ - `{{this}}`
38
+ {{/each}}
39
+
40
+ ## Output Format
41
+
42
+ ```json
43
+ {
44
+ "subtasks": [
45
+ {
46
+ "id": "ST-1",
47
+ "title": "Short description of what to build",
48
+ "agent": "frontend|backend|quality|security",
49
+ "files": ["path/to/file.ts"],
50
+ "dependsOn": [],
51
+ "verification": "How to verify this subtask works"
52
+ }
53
+ ],
54
+ "waves": [
55
+ { "wave": 1, "subtasks": ["ST-1", "ST-2"] },
56
+ { "wave": 2, "subtasks": ["ST-3"] }
57
+ ]
58
+ }
59
+ ```
60
+
61
+ ## Constraints
62
+
63
+ - Maximum {{pipeline.max_subtasks}} subtasks per decomposition (default 15)
64
+ - Maximum {{pipeline.max_waves}} waves (default 5)
65
+ - No circular dependencies
66
+ - No file conflicts within a wave (two subtasks in the same wave cannot touch the same file)
67
+ - Every file modification must be assigned to exactly one subtask
68
+ - If the scope exceeds limits, break into smaller work requests
@@ -0,0 +1,27 @@
1
+ # Backend
2
+
3
+ > Builds API routes, server logic, services, and data access patterns.
4
+
5
+ ## Role
6
+
7
+ You are the Backend agent. You build server-side code including API endpoints, services, data access, and server utilities. You follow the conventions in `context/stack.md` strictly.
8
+
9
+ ## Process
10
+
11
+ 1. **Read the subtask**: Understand what server logic needs to be built or modified.
12
+ 2. **Read context**: Load `.forge/context/stack.md` for framework-specific patterns.
13
+ 3. **Check existing patterns**: Look at similar routes/services in the codebase.
14
+ 4. **Implement**: Write the route/service following stack conventions.
15
+ 5. **Verify**: Run `{{commands.typecheck}}` and confirm no type errors.
16
+
17
+ ## Constraints
18
+
19
+ - Follow all patterns in `context/stack.md` — routing, data access, error handling
20
+ - Validate all input on every endpoint
21
+ - Check authentication on protected routes
22
+ - Return proper HTTP status codes
23
+ - Never hardcode secrets — use environment variables or secret management
24
+ - Never expose internal error details in responses
25
+ - Never use `any` type
26
+ - Never import client-only code in server modules
27
+ - Use parameterized queries — never interpolate user input into queries
@@ -0,0 +1,25 @@
1
+ # Frontend
2
+
3
+ > Builds UI components, pages, and client-side logic using stack-specific patterns.
4
+
5
+ ## Role
6
+
7
+ You are the Frontend agent. You build user interface components, pages, layouts, and client-side interactions. You follow the conventions in `context/stack.md` strictly.
8
+
9
+ ## Process
10
+
11
+ 1. **Read the subtask**: Understand what UI needs to be built or modified.
12
+ 2. **Read context**: Load `.forge/context/stack.md` for framework-specific patterns.
13
+ 3. **Check existing patterns**: Look at similar components in the codebase for conventions.
14
+ 4. **Implement**: Write the component/page following stack conventions.
15
+ 5. **Verify**: Run `{{commands.typecheck}}` and confirm no type errors.
16
+
17
+ ## Constraints
18
+
19
+ - Follow all patterns in `context/stack.md` — framework-specific syntax, styling, component structure
20
+ - Add `data-testid` attributes on all interactive elements
21
+ - Use the project's styling system (Tailwind, CSS modules, etc.) — no inline styles
22
+ - Ensure accessibility: semantic HTML, aria labels, keyboard navigation
23
+ - Never import server-only code in client components
24
+ - Never fetch data in low-level components (atoms, molecules) — data flows down from pages/layouts
25
+ - Never use `any` type
@@ -0,0 +1,40 @@
1
+ # Quality
2
+
3
+ > Writes tests, verifies coverage, and validates that code meets quality standards.
4
+
5
+ ## Role
6
+
7
+ You are the Quality agent. You write tests for code produced by other agents and verify that the codebase meets quality standards.
8
+
9
+ ## Process
10
+
11
+ 1. **Read the subtask**: Understand what code was written and what needs testing.
12
+ 2. **Read the code under test**: Understand the implementation, inputs, outputs, edge cases.
13
+ 3. **Write tests**: Create test files that cover:
14
+ - Happy path (expected behavior)
15
+ - Error cases (invalid input, missing data)
16
+ - Edge cases (empty arrays, null values, boundary conditions)
17
+ - Integration points (does it work with dependencies?)
18
+ 4. **Run tests**: Execute `{{commands.test}}` and verify all pass.
19
+ 5. **Check coverage**: Ensure new code has adequate test coverage.
20
+
21
+ ## Test Structure
22
+
23
+ ```
24
+ describe('ModuleName', () => {
25
+ describe('functionName', () => {
26
+ it('returns expected result for valid input', () => {});
27
+ it('throws when input is invalid', () => {});
28
+ it('handles edge case correctly', () => {});
29
+ });
30
+ });
31
+ ```
32
+
33
+ ## Constraints
34
+
35
+ - Tests must pass (`{{commands.test}}` exits 0)
36
+ - No snapshot tests (brittle)
37
+ - No mocking internal modules (test real behavior)
38
+ - Descriptive test names that explain the scenario
39
+ - Each test should be independent (no shared mutable state)
40
+ - Add `data-testid` attributes when testing UI components
@@ -0,0 +1,53 @@
1
+ # Security
2
+
3
+ > Reviews code for security vulnerabilities and ensures safe coding practices.
4
+
5
+ ## Role
6
+
7
+ You are the Security agent. You review code for security issues, validate that security best practices are followed, and flag any concerns before code reaches production.
8
+
9
+ ## Process
10
+
11
+ 1. **Review the code changes**: Read all modified files in the subtask.
12
+ 2. **Check for vulnerabilities**: Scan for common security issues:
13
+ - Hardcoded secrets, API keys, or tokens
14
+ - SQL injection / NoSQL injection
15
+ - XSS (cross-site scripting)
16
+ - CSRF (cross-site request forgery)
17
+ - Unvalidated user input
18
+ - Missing authentication checks on protected endpoints
19
+ - Missing authorization checks (user can only access their own data)
20
+ - Insecure direct object references
21
+ - eval() or dynamic code execution
22
+ - Disabled security controls (eslint-disable, @ts-ignore for security rules)
23
+ 3. **Validate patterns**:
24
+ - Secrets come from environment or secret manager, never hardcoded
25
+ - All endpoints validate input
26
+ - Auth checks on every protected route
27
+ - Error messages don't leak internal details
28
+ - Sensitive data is not logged
29
+ 4. **Output findings**: List any issues found with severity and fix recommendations.
30
+
31
+ ## Output Format
32
+
33
+ ```json
34
+ {
35
+ "status": "pass|fail",
36
+ "findings": [
37
+ {
38
+ "severity": "critical|high|medium|low",
39
+ "file": "path/to/file.ts",
40
+ "line": 42,
41
+ "issue": "Description of the security issue",
42
+ "fix": "How to fix it"
43
+ }
44
+ ]
45
+ }
46
+ ```
47
+
48
+ ## Constraints
49
+
50
+ - Any `critical` or `high` finding fails the review
51
+ - Never approve code with hardcoded secrets
52
+ - Never approve code with missing auth on protected endpoints
53
+ - When in doubt, escalate to T3 (flag for human review)
@@ -0,0 +1,60 @@
1
+ # Project Context — {{project.name}}
2
+
3
+ > Project-specific knowledge for agents. This file is yours — forge will never overwrite it on upgrade.
4
+
5
+ ## Overview
6
+
7
+ {{#if onboarding.description}}
8
+ {{onboarding.description}}
9
+ {{else}}
10
+ <!-- Describe what you're building -->
11
+ {{/if}}
12
+
13
+ ## Project Type
14
+
15
+ {{#if onboarding.projectType}}
16
+ **Type**: {{onboarding.projectType}}
17
+ {{/if}}
18
+
19
+ ## Architecture
20
+
21
+ {{#if onboarding.architecture}}
22
+ **Style**: {{onboarding.architecture}}
23
+ {{else}}
24
+ <!-- Describe your architecture style (monolith, client-server, microservices, etc.) -->
25
+ {{/if}}
26
+
27
+ {{#if has_modules}}
28
+ ## Key Modules
29
+
30
+ {{#each onboarding.modules}}
31
+ - **{{this}}**
32
+ {{/each}}
33
+ {{else}}
34
+ ## Key Modules
35
+
36
+ <!-- List your main features or modules -->
37
+ {{/if}}
38
+
39
+ ## Key Conventions
40
+
41
+ <!-- Anything specific to YOUR project not covered by the stack context -->
42
+ <!-- Example: "All API responses use our standard envelope: { data, error, meta }" -->
43
+
44
+ ## Sensitive Paths
45
+
46
+ {{#if has_sensitive}}
47
+ {{onboarding.sensitivePaths}}
48
+ {{else}}
49
+ <!-- Paths that need extra care — auth, payments, PII, etc. -->
50
+ <!-- These will auto-escalate to T3 risk tier during classification -->
51
+ {{/if}}
52
+
53
+ ## Domain Knowledge
54
+
55
+ {{#if has_domain_rules}}
56
+ {{onboarding.domainRules}}
57
+ {{else}}
58
+ <!-- Business logic that agents need to understand -->
59
+ <!-- Example: "Users have one of three roles: patient, provider, admin." -->
60
+ {{/if}}
@@ -0,0 +1,69 @@
1
+ # forge.yaml — Agent harness configuration
2
+ # Generated by: forge init v0.1.0
3
+
4
+ version: 1
5
+
6
+ project:
7
+ name: "{{project.name}}"
8
+ preset: "{{project.preset}}"
9
+
10
+ # Verification commands — what the pipeline calls
11
+ commands:
12
+ typecheck: "{{commands.typecheck}}"
13
+ lint: "{{commands.lint}}"
14
+ test: "{{commands.test}}"
15
+ {{#if has_format}}
16
+ format: "{{commands.format}}"
17
+ {{/if}}
18
+ dev: "{{commands.dev}}"
19
+
20
+ # Which agents are available for dispatch
21
+ agents:
22
+ {{#each agents}}
23
+ - {{this}}
24
+ {{/each}}
25
+
26
+ # What verification checks run and how
27
+ verification:
28
+ typecheck: true
29
+ lint: true
30
+ test: true
31
+ coverage:
32
+ enabled: false
33
+ threshold: 70
34
+ security:
35
+ enabled: false
36
+ command: "semgrep --config=auto"
37
+ anti_patterns:
38
+ enabled: true
39
+ blockers:
40
+ - "TODO"
41
+ - "FIXME"
42
+ - "console.log"
43
+ - "debugger"
44
+ browser:
45
+ enabled: false
46
+
47
+ # Pipeline behavior
48
+ pipeline:
49
+ max_retries: 3
50
+ max_subtasks: 15
51
+ max_waves: 5
52
+ auto_pr: {{auto_pr}}
53
+
54
+ # Task tracking via bd (steveyegge/beads)
55
+ tracking:
56
+ backend: bd
57
+ enforce_tracking: true
58
+
59
+ # Risk classification
60
+ risk:
61
+ t3_paths: []
62
+ t3_keywords:
63
+ - "authentication"
64
+ - "encryption"
65
+ - "PII"
66
+ - "payment"
67
+
68
+ # Installed addons
69
+ addons: []
@@ -0,0 +1,8 @@
1
+ #!/bin/bash
2
+ # .forge/hooks/post-edit.sh — PostToolUse hook for Edit|Write
3
+ # Lightweight hook — bd handles tracking via its own git hooks
4
+
5
+ # No-op: bd tracks work through its git integration (bd setup claude)
6
+ # and its own commit hooks. No need to manually update task state here.
7
+
8
+ exit 0
@@ -0,0 +1,41 @@
1
+ #!/bin/bash
2
+ # .forge/hooks/pre-edit.sh — PreToolUse hook for Edit|Write
3
+ # Blocks file edits without an active (in-progress) bd task
4
+
5
+ INPUT=$(cat)
6
+ FILE_PATH=$(echo "$INPUT" | jq -r '.file_path // .path // empty' 2>/dev/null)
7
+
8
+ # If we can't determine the file path, allow (fail open)
9
+ if [ -z "$FILE_PATH" ]; then
10
+ exit 0
11
+ fi
12
+
13
+ # Allow harness files, docs, and config — these don't need tracking
14
+ case "$FILE_PATH" in
15
+ *.md|*.yaml|*.yml|*.txt|*.gitignore|*.env*) exit 0 ;;
16
+ .forge/*|.claude/*|.beads/*|forge.yaml|CLAUDE.md) exit 0 ;;
17
+ package.json|package-lock.json|tsconfig.json) exit 0 ;;
18
+ pyproject.toml|requirements.txt|go.mod|go.sum) exit 0 ;;
19
+ Cargo.toml|Cargo.lock) exit 0 ;;
20
+ esac
21
+
22
+ # Check if bd is available
23
+ if ! command -v bd &>/dev/null; then
24
+ exit 0
25
+ fi
26
+
27
+ # Check if tracking is enforced
28
+ ENFORCE=$(grep -oP 'enforce_tracking:\s*\K\w+' forge.yaml 2>/dev/null || echo "true")
29
+ if [ "$ENFORCE" != "true" ]; then
30
+ exit 0
31
+ fi
32
+
33
+ # Check for in-progress tasks
34
+ IN_PROGRESS=$(bd list --status in_progress --json 2>/dev/null)
35
+ if [ -z "$IN_PROGRESS" ] || [ "$IN_PROGRESS" = "[]" ]; then
36
+ echo '{"decision":"block","reason":"No active task. Run /deliver to start tracked work, or use /deliver --quick for a lightweight change."}'
37
+ exit 0
38
+ fi
39
+
40
+ # Allow the edit
41
+ exit 0
@@ -0,0 +1,34 @@
1
+ #!/bin/bash
2
+ # .forge/hooks/session-start.sh — SessionStart hook
3
+ # Verifies bd (beads) is available and shows active work
4
+
5
+ # Check that bd is available
6
+ if ! command -v bd &>/dev/null; then
7
+ echo "[forge] Warning: bd (beads) is not installed. Work tracking requires bd."
8
+ echo "[forge] Install with: brew install beads"
9
+ exit 0
10
+ fi
11
+
12
+ # Check that forge.yaml exists
13
+ if [ ! -f "forge.yaml" ]; then
14
+ exit 0
15
+ fi
16
+
17
+ # Check that beads is initialized
18
+ if [ ! -d ".beads" ]; then
19
+ echo "[forge] Beads not initialized. Initializing..."
20
+ bd init --quiet 2>/dev/null
21
+ fi
22
+
23
+ # Show ready tasks
24
+ READY=$(bd ready --json 2>/dev/null)
25
+ if [ -n "$READY" ] && [ "$READY" != "[]" ]; then
26
+ COUNT=$(echo "$READY" | jq 'length' 2>/dev/null)
27
+ echo "[forge] ${COUNT} task(s) ready to work on:"
28
+ echo "$READY" | jq -r '.[] | " \(.id) [P\(.priority)] \(.title)"' 2>/dev/null
29
+ echo "[forge] Claim one with: bd update <id> --claim"
30
+ else
31
+ echo "[forge] No tasks ready. Start work with: /deliver \"description\""
32
+ fi
33
+
34
+ exit 0
@@ -0,0 +1,159 @@
1
+ #!/usr/bin/env bash
2
+ # forge pipeline — classify: risk tier assignment
3
+ # Generated by: forge init
4
+ set -euo pipefail
5
+
6
+ FORGE_DIR=".forge"
7
+ CONFIG_FILE="${FORGE_DIR}/forge.yaml"
8
+
9
+ DESCRIPTION="${1:-}"
10
+
11
+ if [[ -z "$DESCRIPTION" ]]; then
12
+ echo '{"error":"No description provided"}' >&2
13
+ exit 1
14
+ fi
15
+
16
+ DESC_LOWER=$(echo "$DESCRIPTION" | tr '[:upper:]' '[:lower:]')
17
+
18
+ # --- Default risk patterns ---
19
+
20
+ # T3: Critical — auth, encryption, PII, payment, security
21
+ T3_PATTERNS=(
22
+ "auth" "authentication" "authorization" "login" "logout" "session"
23
+ "password" "credential" "secret" "token" "jwt" "oauth"
24
+ "encrypt" "decrypt" "hash" "salt" "certificate" "ssl" "tls"
25
+ "pii" "personal data" "gdpr" "hipaa" "phi" "ssn" "social security"
26
+ "payment" "stripe" "billing" "credit card" "charge" "subscription"
27
+ "security" "vulnerability" "xss" "csrf" "injection" "sanitiz"
28
+ "permission" "rbac" "role" "access control" "privilege"
29
+ )
30
+
31
+ # T2: Moderate — business logic, API, services, state, DB
32
+ T2_PATTERNS=(
33
+ "api" "endpoint" "route" "handler" "controller" "middleware"
34
+ "database" "migration" "schema" "query" "sql" "table" "column" "index"
35
+ "service" "repository" "model" "entity" "domain"
36
+ "state" "store" "reducer" "action" "dispatch" "context"
37
+ "business logic" "workflow" "validation" "transform"
38
+ "integration" "webhook" "event" "queue" "job" "worker"
39
+ "cache" "redis" "session" "cookie"
40
+ "server" "backend" "ssr" "hooks.server"
41
+ )
42
+
43
+ # T1: Low — UI, docs, styling, tests, config
44
+ T1_PATTERNS=(
45
+ "style" "css" "tailwind" "color" "font" "spacing" "margin" "padding"
46
+ "ui" "component" "layout" "responsive" "mobile" "desktop"
47
+ "doc" "readme" "comment" "changelog" "documentation"
48
+ "test" "spec" "vitest" "jest" "playwright" "e2e" "unit test"
49
+ "config" "eslint" "prettier" "tsconfig" "vite.config" "package.json"
50
+ "typo" "rename" "reformat" "lint" "cleanup"
51
+ )
52
+
53
+ # --- Read custom risk paths/keywords from forge.yaml ---
54
+
55
+ read_risk_keywords() {
56
+ local tier="$1"
57
+ local file="$CONFIG_FILE"
58
+ if [[ ! -f "$file" ]]; then
59
+ return
60
+ fi
61
+ # Extract keywords under risk.<tier>.keywords as a simple list
62
+ sed -n "/^risk:/,/^[^ ]/p" "$file" | \
63
+ sed -n "/${tier}:/,/^ [^ ]/p" | \
64
+ sed -n '/keywords:/,/^ [^ ]/p' | \
65
+ grep '^ *- ' | sed 's/^ *- *//' | tr '[:upper:]' '[:lower:]'
66
+ }
67
+
68
+ read_risk_paths() {
69
+ local tier="$1"
70
+ local file="$CONFIG_FILE"
71
+ if [[ ! -f "$file" ]]; then
72
+ return
73
+ fi
74
+ sed -n "/^risk:/,/^[^ ]/p" "$file" | \
75
+ sed -n "/${tier}:/,/^ [^ ]/p" | \
76
+ sed -n '/paths:/,/^ [^ ]/p' | \
77
+ grep '^ *- ' | sed 's/^ *- *//' | tr '[:upper:]' '[:lower:]'
78
+ }
79
+
80
+ # --- Classification ---
81
+
82
+ match_count() {
83
+ local count=0
84
+ for pattern in "$@"; do
85
+ if echo "$DESC_LOWER" | grep -qF "$pattern"; then
86
+ count=$((count + 1))
87
+ fi
88
+ done
89
+ echo "$count"
90
+ }
91
+
92
+ t3_hits=$(match_count "${T3_PATTERNS[@]}")
93
+ t2_hits=$(match_count "${T2_PATTERNS[@]}")
94
+ t1_hits=$(match_count "${T1_PATTERNS[@]}")
95
+
96
+ # Check custom keywords from config
97
+ while IFS= read -r kw; do
98
+ [[ -z "$kw" ]] && continue
99
+ if echo "$DESC_LOWER" | grep -qF "$kw"; then
100
+ t3_hits=$((t3_hits + 2)) # custom keywords weighted higher
101
+ fi
102
+ done < <(read_risk_keywords "t3")
103
+
104
+ while IFS= read -r kw; do
105
+ [[ -z "$kw" ]] && continue
106
+ if echo "$DESC_LOWER" | grep -qF "$kw"; then
107
+ t2_hits=$((t2_hits + 2))
108
+ fi
109
+ done < <(read_risk_keywords "t2")
110
+
111
+ while IFS= read -r kw; do
112
+ [[ -z "$kw" ]] && continue
113
+ if echo "$DESC_LOWER" | grep -qF "$kw"; then
114
+ t1_hits=$((t1_hits + 2))
115
+ fi
116
+ done < <(read_risk_keywords "t1")
117
+
118
+ # Check custom paths from config
119
+ while IFS= read -r p; do
120
+ [[ -z "$p" ]] && continue
121
+ if echo "$DESC_LOWER" | grep -qF "$p"; then
122
+ t3_hits=$((t3_hits + 3))
123
+ fi
124
+ done < <(read_risk_paths "t3")
125
+
126
+ while IFS= read -r p; do
127
+ [[ -z "$p" ]] && continue
128
+ if echo "$DESC_LOWER" | grep -qF "$p"; then
129
+ t2_hits=$((t2_hits + 3))
130
+ fi
131
+ done < <(read_risk_paths "t2")
132
+
133
+ # Determine tier — T3 wins over T2 wins over T1
134
+ TIER="T1"
135
+ REASON="Default: no high-risk patterns detected"
136
+
137
+ if [[ $t3_hits -gt 0 ]]; then
138
+ TIER="T3"
139
+ REASON="Matched ${t3_hits} critical-risk pattern(s): auth, encryption, PII, payment, or security-related"
140
+ elif [[ $t2_hits -gt 0 ]]; then
141
+ TIER="T2"
142
+ REASON="Matched ${t2_hits} moderate-risk pattern(s): business logic, API, database, or state management"
143
+ elif [[ $t1_hits -gt 0 ]]; then
144
+ TIER="T1"
145
+ REASON="Matched ${t1_hits} low-risk pattern(s): UI, docs, styling, tests, or config"
146
+ fi
147
+
148
+ # T3 always wins if any T3 match, regardless of other hits
149
+ if [[ $t3_hits -gt 0 ]]; then
150
+ TIER="T3"
151
+ fi
152
+
153
+ jq -n \
154
+ --arg tier "$TIER" \
155
+ --arg reason "$REASON" \
156
+ --argjson t3_hits "$t3_hits" \
157
+ --argjson t2_hits "$t2_hits" \
158
+ --argjson t1_hits "$t1_hits" \
159
+ '{tier:$tier, reason:$reason, hits:{t3:$t3_hits, t2:$t2_hits, t1:$t1_hits}}'