vibe-forge 0.3.12 → 0.8.1

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 (85) hide show
  1. package/.claude/commands/clear-attention.md +63 -63
  2. package/.claude/commands/compact-context.md +52 -0
  3. package/.claude/commands/configure-vcs.md +102 -0
  4. package/.claude/commands/forge.md +218 -171
  5. package/.claude/commands/need-help.md +77 -77
  6. package/.claude/commands/update-status.md +64 -64
  7. package/.claude/commands/worker-loop.md +106 -106
  8. package/.claude/hooks/worker-loop.js +217 -0
  9. package/.claude/scripts/setup-worker-loop.sh +45 -45
  10. package/.claude/settings.json +89 -0
  11. package/LICENSE +21 -21
  12. package/README.md +253 -230
  13. package/agents/aegis/personality.md +303 -269
  14. package/agents/anvil/personality.md +278 -211
  15. package/agents/architect/personality.md +260 -0
  16. package/agents/crucible/personality.md +362 -285
  17. package/agents/crucible-x/personality.md +210 -0
  18. package/agents/ember/personality.md +293 -245
  19. package/agents/flux/personality.md +248 -0
  20. package/agents/furnace/personality.md +342 -262
  21. package/agents/herald/personality.md +249 -247
  22. package/agents/loki/personality.md +108 -0
  23. package/agents/oracle/personality.md +284 -0
  24. package/agents/pixel/personality.md +140 -0
  25. package/agents/planning-hub/personality.md +473 -251
  26. package/agents/scribe/personality.md +253 -231
  27. package/agents/slag/personality.md +268 -0
  28. package/agents/temper/personality.md +270 -0
  29. package/bin/cli.js +372 -325
  30. package/bin/dashboard/api/agents.js +333 -0
  31. package/bin/dashboard/api/dispatch.js +507 -0
  32. package/bin/dashboard/api/tasks.js +416 -0
  33. package/bin/dashboard/public/assets/index-BpHfsx1r.js +2 -0
  34. package/bin/dashboard/public/assets/index-QODv4Zn9.css +1 -0
  35. package/bin/dashboard/public/index.html +14 -0
  36. package/bin/dashboard/server.js +645 -0
  37. package/bin/forge-daemon.sh +477 -775
  38. package/bin/forge-setup.sh +661 -532
  39. package/bin/forge-spawn.sh +164 -159
  40. package/bin/forge.cmd +83 -83
  41. package/bin/forge.sh +566 -393
  42. package/bin/lib/agents.sh +177 -177
  43. package/bin/lib/check-aliases.js +50 -0
  44. package/bin/lib/colors.sh +44 -44
  45. package/bin/lib/config.sh +347 -271
  46. package/bin/lib/constants.sh +241 -171
  47. package/bin/lib/daemon/budgets.sh +107 -0
  48. package/bin/lib/daemon/dependencies.sh +146 -0
  49. package/bin/lib/daemon/display.sh +128 -0
  50. package/bin/lib/daemon/notifications.sh +273 -0
  51. package/bin/lib/daemon/routing.sh +93 -0
  52. package/bin/lib/daemon/state.sh +163 -0
  53. package/bin/lib/daemon/sync.sh +103 -0
  54. package/bin/lib/database.sh +357 -224
  55. package/bin/lib/frontmatter.js +106 -0
  56. package/bin/lib/heimdall-setup.js +113 -0
  57. package/bin/lib/heimdall.js +265 -0
  58. package/bin/lib/json.sh +264 -0
  59. package/bin/lib/terminal.js +452 -0
  60. package/bin/lib/util.sh +126 -0
  61. package/bin/lib/vcs.js +349 -0
  62. package/config/agent-manifest.yaml +237 -230
  63. package/config/agents.json +207 -85
  64. package/config/task-template.md +159 -87
  65. package/config/task-types.yaml +111 -106
  66. package/config/templates/handoff-template.md +40 -0
  67. package/context/agent-overrides/README.md +41 -0
  68. package/context/architecture.md +42 -0
  69. package/context/modern-conventions.md +129 -129
  70. package/context/project-context-template.md +122 -122
  71. package/docs/agents.md +473 -0
  72. package/docs/architecture.md +194 -0
  73. package/docs/commands.md +451 -0
  74. package/docs/security.md +195 -144
  75. package/package.json +77 -48
  76. package/.claude/hooks/worker-loop.sh +0 -141
  77. package/.claude/settings.local.json +0 -29
  78. package/agents/forge-master/capabilities.md +0 -144
  79. package/agents/forge-master/context-template.md +0 -128
  80. package/agents/forge-master/personality.md +0 -138
  81. package/agents/sentinel/personality.md +0 -194
  82. package/context/forge-state.yaml +0 -19
  83. package/docs/TODO.md +0 -176
  84. package/docs/npm-publishing.md +0 -95
  85. package/tasks/review/task-001.md +0 -78
package/docs/security.md CHANGED
@@ -1,144 +1,195 @@
1
- # Vibe Forge Security Documentation
2
-
3
- This document explains security considerations and intentional design decisions in Vibe Forge.
4
-
5
- ## The `--dangerously-skip-permissions` Flag
6
-
7
- ### What It Does
8
-
9
- When starting agents, Vibe Forge uses Claude Code's `--dangerously-skip-permissions` flag:
10
-
11
- ```bash
12
- claude --dangerously-skip-permissions --system-prompt "$system_prompt" "startup"
13
- ```
14
-
15
- This flag disables Claude Code's permission prompts for file operations, command execution, and other actions that would normally require user confirmation.
16
-
17
- ### Why We Use It
18
-
19
- Vibe Forge is designed for **terminal-native vibe coding** - a workflow where you launch multiple AI agents that work autonomously on your codebase. The typical workflow involves:
20
-
21
- 1. Starting a Planning Hub that coordinates work
22
- 2. Spawning worker agents (frontend, backend, testing, etc.) in separate terminals
23
- 3. Agents working autonomously on assigned tasks
24
- 4. Human review at defined checkpoints
25
-
26
- With permission prompts enabled, each agent would constantly interrupt for confirmation, breaking the autonomous workflow that makes Vibe Forge effective.
27
-
28
- ### Security Mitigations
29
-
30
- We implement several security measures to offset the risks:
31
-
32
- #### 1. Agent Whitelist Validation
33
-
34
- All agent names go through strict whitelist validation before execution:
35
-
36
- ```bash
37
- # bin/lib/constants.sh
38
- VALID_AGENTS=("anvil" "furnace" "crucible" ...)
39
-
40
- # bin/lib/agents.sh
41
- resolve_agent() {
42
- local canonical="${AGENT_ALIASES[$normalized]:-}"
43
- if [[ -n "$canonical" ]]; then
44
- echo "$canonical"
45
- return 0
46
- fi
47
- return 1 # Reject unknown agents
48
- }
49
- ```
50
-
51
- This prevents command injection through agent names.
52
-
53
- #### 2. Path Traversal Protection
54
-
55
- Personality file paths are validated to ensure they remain within the expected directory:
56
-
57
- ```bash
58
- get_agent_personality_path() {
59
- local real_path=$(cd "$(dirname "$personality_path")" && pwd)/$(basename "$personality_path")
60
- local agents_dir=$(cd "$forge_root/agents" && pwd)
61
-
62
- if [[ "$real_path" != "$agents_dir"/* ]]; then
63
- echo "Security error: Path traversal detected" >&2
64
- return 1
65
- fi
66
- }
67
- ```
68
-
69
- #### 3. Safe JSON Parsing
70
-
71
- We use Node.js for JSON parsing instead of `grep`/`cut` which could be vulnerable to injection:
72
-
73
- ```bash
74
- json_get_string() {
75
- node -e "
76
- const fs = require('fs');
77
- const data = JSON.parse(fs.readFileSync('$file', 'utf8'));
78
- if (data['$key'] !== undefined) console.log(String(data['$key']));
79
- "
80
- }
81
- ```
82
-
83
- #### 4. Daemon Security
84
-
85
- The background daemon includes multiple protections:
86
-
87
- - **Symlink protection**: Skips symlinks to prevent symlink attacks
88
- - **Path validation**: Verifies destinations are within FORGE_ROOT
89
- - **Atomic operations**: Uses temp files + move for safe writes
90
- - **Lock files**: Prevents multiple daemon instances
91
- - **Log rotation**: Bounded log growth prevents disk exhaustion
92
-
93
- ### Risks to Be Aware Of
94
-
95
- Even with mitigations, understand these risks:
96
-
97
- 1. **AI agents can modify any file** in your project without confirmation
98
- 2. **AI agents can execute any command** without confirmation
99
- 3. **Malicious prompts** could potentially be injected if context files are compromised
100
- 4. **Network access** is unrestricted - agents could make API calls
101
-
102
- ### Recommendations
103
-
104
- 1. **Use in development environments only** - Don't run on production systems
105
- 2. **Use with version control** - Git makes it easy to review and revert changes
106
- 3. **Review at checkpoints** - Check agent work during task transitions
107
- 4. **Understand the personality files** - They define agent behavior
108
- 5. **Keep project context secure** - Don't include secrets in context files
109
- 6. **Run in isolated environments** - Consider containers for sensitive projects
110
-
111
- ### Alternative: Manual Approval Mode
112
-
113
- If you prefer permission prompts, you can modify the agent startup in `bin/forge.sh`:
114
-
115
- ```bash
116
- # Change this:
117
- claude --dangerously-skip-permissions --system-prompt "$system_prompt" "startup"
118
-
119
- # To this (removes the flag):
120
- claude --system-prompt "$system_prompt" "startup"
121
- ```
122
-
123
- Note: This will significantly impact the autonomous workflow.
124
-
125
- ## Reporting Security Issues
126
-
127
- If you discover a security vulnerability in Vibe Forge:
128
-
129
- 1. **Do not open a public issue**
130
- 2. Email security concerns to the maintainers
131
- 3. Include steps to reproduce
132
- 4. Allow time for a fix before public disclosure
133
-
134
- ## Security Checklist for Contributors
135
-
136
- When contributing to Vibe Forge:
137
-
138
- - [ ] Never pass user input directly to shell commands
139
- - [ ] Always validate agent names against the whitelist
140
- - [ ] Use safe JSON parsing (Node.js, not grep/cut)
141
- - [ ] Validate file paths don't traverse outside expected directories
142
- - [ ] Use atomic file operations where race conditions are possible
143
- - [ ] Add tests for security-sensitive functions
144
- - [ ] Document any new security considerations
1
+ # Vibe Forge Security Documentation
2
+
3
+ This document explains security considerations and intentional design decisions in Vibe Forge.
4
+
5
+ ## Agent Permission Model
6
+
7
+ ### How It Works
8
+
9
+ Vibe Forge agents run with **allowlist-based permissions** defined in `.claude/settings.json`. This replaces the previous `--dangerously-skip-permissions` approach with a defense-in-depth model:
10
+
11
+ 1. **Allowlist** (`.claude/settings.json`) - Pre-approves safe operations (file reads, writes, git, npm, etc.)
12
+ 2. **Heimdall** (pre-tool hook) - Intercepts and gates forge-specific policy (branch protection, etc.)
13
+ 3. **Claude Code native prompts** - Anything not in the allowlist still requires user approval
14
+
15
+ ```
16
+ Agent wants to run a command
17
+ |
18
+ v
19
+ ┌─────────────────┐
20
+ │ Allowlist check │──── Not allowed ──> User prompted
21
+ └────────┬────────┘
22
+ Allowed
23
+ v
24
+ ┌─────────────────┐
25
+ │ Heimdall hook │──── Policy violation ──> Blocked
26
+ └────────┬────────┘
27
+ │ Pass
28
+ v
29
+ Executed
30
+ ```
31
+
32
+ ### What Agents Can Do Without Prompting
33
+
34
+ The allowlist covers normal development operations:
35
+ - Read, write, and edit files
36
+ - Search with glob/grep
37
+ - Run git commands (status, diff, add, commit, push, branch, etc.)
38
+ - Run GitHub CLI (PRs, runs, workflows)
39
+ - Run npm (test, install, audit, build)
40
+ - Run node/npx scripts
41
+ - File operations (ls, cp, mv, mkdir, find)
42
+ - SQLite operations
43
+
44
+ ### What Still Requires Approval
45
+
46
+ Anything not in the allowlist prompts the user:
47
+ - Installing system packages (apt, brew, etc.)
48
+ - Running unfamiliar binaries
49
+ - Network operations (curl, wget) unless via node
50
+ - Destructive operations not covered by git (rm -rf, etc.)
51
+
52
+ ### Heimdall Policy Layer
53
+
54
+ Heimdall is a pre-tool hook that enforces forge-specific rules on top of the allowlist:
55
+ - Blocks direct pushes to main/master
56
+ - Enforces branch naming conventions
57
+ - Gates security-sensitive operations
58
+
59
+ Heimdall runs on every Bash tool call regardless of allowlist status.
60
+
61
+ ### Why Not --dangerously-skip-permissions?
62
+
63
+ The `--dsp` flag disables ALL permission checks. The allowlist approach is better because:
64
+ - Only known-safe operations are pre-approved
65
+ - Unknown commands still prompt for approval
66
+ - Heimdall policies still enforce forge rules
67
+ - The security posture is auditable (read `.claude/settings.json`)
68
+
69
+ Users who prefer the fully autonomous workflow can still use `--dsp` in their own terminals.
70
+
71
+ ### Trust Boundary: Shared Allowlist
72
+
73
+ All forge agents share a single allowlist defined in `.claude/settings.json`. There are no per-agent permission boundaries. This means:
74
+
75
+ - **Anvil** (frontend) has the same file-write permissions as **Aegis** (security)
76
+ - A compromised or confused agent personality cannot be contained by permissions alone
77
+ - Heimdall policies provide some per-agent gating (e.g. branch protection) but do not restrict filesystem scope
78
+
79
+ This is an accepted architectural trade-off. Per-agent permission boundaries would require separate `settings.json` files per agent and a launcher that selects the correct one, which adds complexity without proportional security benefit in a single-developer, local-only workflow.
80
+
81
+ **Mitigations:**
82
+ - Version control (git) makes all file changes reviewable and revertible
83
+ - Heimdall enforces structural policies (no direct push to main, naming conventions)
84
+ - Sentinel code review catches inappropriate changes before merge
85
+ - The dashboard provides visibility into what each agent is doing
86
+
87
+ **Future consideration:** If Vibe Forge supports multi-developer or remote execution (T3-4), per-agent permission boundaries should be revisited.
88
+
89
+ ## Dashboard Security
90
+
91
+ ### Session Token Authentication
92
+
93
+ The dashboard server generates a cryptographic session token at startup:
94
+ - Written to `.forge/dashboard.token` with mode 0600
95
+ - All API endpoints require `X-Forge-Token` header
96
+ - WebSocket connections require `?token=` query parameter
97
+ - Token is cleaned up on server shutdown
98
+ - `/api/health` is exempt (monitoring probes)
99
+
100
+ ### Same-Origin Protection
101
+
102
+ The dashboard serves no CORS headers. Browsers enforce same-origin policy, meaning:
103
+ - Only the dashboard UI (served from the same origin) can call the API
104
+ - Cross-origin requests from malicious websites are blocked
105
+ - The `/api/token` bootstrap endpoint is protected by same-origin policy
106
+
107
+ ### Why This Matters
108
+
109
+ Without these protections, any website you visit could dispatch tasks to your forge agents via cross-origin API calls. Combined with agent permissions, this would allow arbitrary code execution. The session token + same-origin combination eliminates this attack vector.
110
+
111
+ ## Additional Security Measures
112
+
113
+ ### Agent Whitelist Validation
114
+
115
+ All agent names go through strict whitelist validation before execution:
116
+
117
+ ```bash
118
+ resolve_agent() {
119
+ local canonical="${AGENT_ALIASES[$normalized]:-}"
120
+ if [[ -n "$canonical" ]]; then
121
+ echo "$canonical"
122
+ return 0
123
+ fi
124
+ return 1 # Reject unknown agents
125
+ }
126
+ ```
127
+
128
+ ### Path Traversal Protection
129
+
130
+ Personality file paths are validated to remain within expected directories:
131
+
132
+ ```bash
133
+ get_agent_personality_path() {
134
+ local real_path=$(cd "$(dirname "$personality_path")" && pwd)/$(basename "$personality_path")
135
+ local agents_dir=$(cd "$forge_root/agents" && pwd)
136
+ if [[ "$real_path" != "$agents_dir"/* ]]; then
137
+ echo "Security error: Path traversal detected" >&2
138
+ return 1
139
+ fi
140
+ }
141
+ ```
142
+
143
+ ### Daemon Security
144
+
145
+ The background daemon includes:
146
+ - **Symlink protection**: Skips symlinks to prevent symlink attacks
147
+ - **Path validation**: Verifies destinations within FORGE_ROOT
148
+ - **Atomic operations**: Temp files + move for safe writes
149
+ - **Lock files**: Prevents multiple daemon instances
150
+ - **SQL escaping**: All database inputs go through `db_escape()`
151
+ - **Input sanitization**: Frontmatter extraction strips shell metacharacters
152
+
153
+ ### Alias Collision Detection
154
+
155
+ Agent alias collisions are checked at three levels:
156
+ - Pre-commit hook (local development)
157
+ - CI lint job (GitHub Actions)
158
+ - `forge init` (project setup)
159
+
160
+ ## Risks to Be Aware Of
161
+
162
+ 1. **Allowlisted operations execute without confirmation** - agents can modify files, run tests, and push code
163
+ 2. **Prompt injection** - crafted task files or context could influence agent behavior
164
+ 3. **Heimdall is not exhaustive** - it enforces known policies, not all possible risks
165
+ 4. **Local network exposure** - the dashboard binds to localhost only; changing this has security implications
166
+
167
+ ## Recommendations
168
+
169
+ 1. **Use in development environments only**
170
+ 2. **Use with version control** - git makes it easy to review and revert
171
+ 3. **Review at checkpoints** - check agent work during task transitions
172
+ 4. **Keep project context secure** - don't include secrets in context files
173
+ 5. **Audit the allowlist** - review `.claude/settings.json` for your comfort level
174
+ 6. **Run in isolated environments** - consider containers for sensitive projects
175
+
176
+ ## Reporting Security Issues
177
+
178
+ If you discover a security vulnerability in Vibe Forge:
179
+
180
+ 1. **Do not open a public issue**
181
+ 2. Email security concerns to the maintainers
182
+ 3. Include steps to reproduce
183
+ 4. Allow time for a fix before public disclosure
184
+
185
+ ## Security Checklist for Contributors
186
+
187
+ When contributing to Vibe Forge:
188
+
189
+ - [ ] Never pass user input directly to shell commands
190
+ - [ ] Always validate agent names against the whitelist
191
+ - [ ] Use safe JSON parsing (Node.js, not grep/cut)
192
+ - [ ] Validate file paths don't traverse outside expected directories
193
+ - [ ] Use atomic file operations where race conditions are possible
194
+ - [ ] Add tests for security-sensitive functions
195
+ - [ ] Document any new security considerations
package/package.json CHANGED
@@ -1,48 +1,77 @@
1
- {
2
- "name": "vibe-forge",
3
- "version": "0.3.12",
4
- "description": "Multi-agent development orchestration system for terminal-native vibe coding",
5
- "keywords": [
6
- "vibe-coding",
7
- "claude",
8
- "ai",
9
- "agents",
10
- "multi-agent",
11
- "development",
12
- "orchestration",
13
- "terminal",
14
- "cli"
15
- ],
16
- "author": "SpasticPalate",
17
- "license": "MIT",
18
- "repository": {
19
- "type": "git",
20
- "url": "git+https://github.com/SpasticPalate/vibe-forge.git"
21
- },
22
- "homepage": "https://github.com/SpasticPalate/vibe-forge#readme",
23
- "bugs": {
24
- "url": "https://github.com/SpasticPalate/vibe-forge/issues"
25
- },
26
- "bin": {
27
- "vibe-forge": "bin/cli.js"
28
- },
29
- "files": [
30
- "bin/",
31
- "agents/",
32
- "config/",
33
- "context/",
34
- "tasks/",
35
- ".claude/",
36
- "docs/"
37
- ],
38
- "scripts": {
39
- "test": "jest tests/js/",
40
- "test:js": "jest tests/js/"
41
- },
42
- "devDependencies": {
43
- "jest": "^30.0.0"
44
- },
45
- "engines": {
46
- "node": ">=16.0.0"
47
- }
48
- }
1
+ {
2
+ "name": "vibe-forge",
3
+ "version": "0.8.1",
4
+ "description": "Multi-agent development orchestration system for terminal-native vibe coding",
5
+ "keywords": [
6
+ "vibe-coding",
7
+ "claude",
8
+ "ai",
9
+ "agents",
10
+ "multi-agent",
11
+ "development",
12
+ "orchestration",
13
+ "terminal",
14
+ "cli"
15
+ ],
16
+ "author": "sugar-crash-studios",
17
+ "license": "MIT",
18
+ "repository": {
19
+ "type": "git",
20
+ "url": "git+https://github.com/sugar-crash-studios/vibe-forge.git"
21
+ },
22
+ "homepage": "https://github.com/sugar-crash-studios/vibe-forge#readme",
23
+ "bugs": {
24
+ "url": "https://github.com/sugar-crash-studios/vibe-forge/issues"
25
+ },
26
+ "publishConfig": {
27
+ "access": "public"
28
+ },
29
+ "bin": {
30
+ "vibe-forge": "bin/cli.js"
31
+ },
32
+ "files": [
33
+ "bin/cli.js",
34
+ "bin/lib/",
35
+ "bin/forge.cmd",
36
+ "bin/forge.sh",
37
+ "bin/forge-daemon.sh",
38
+ "bin/forge-setup.sh",
39
+ "bin/forge-spawn.sh",
40
+ "bin/dashboard/server.js",
41
+ "bin/dashboard/api/",
42
+ "bin/dashboard/public/",
43
+ "agents/",
44
+ "config/",
45
+ "context/project-context-template.md",
46
+ "context/architecture.md",
47
+ "context/modern-conventions.md",
48
+ "context/agent-overrides/README.md",
49
+ ".claude/commands/",
50
+ ".claude/hooks/",
51
+ ".claude/scripts/",
52
+ ".claude/settings.json",
53
+ "docs/security.md",
54
+ "docs/architecture.md",
55
+ "docs/agents.md",
56
+ "docs/commands.md"
57
+ ],
58
+ "scripts": {
59
+ "prepare": "husky",
60
+ "test": "node --no-warnings node_modules/jest/bin/jest.js tests/unit/",
61
+ "test:unit": "node --no-warnings node_modules/jest/bin/jest.js tests/unit/",
62
+ "test:integration": "node --no-warnings node_modules/jest/bin/jest.js tests/integration/",
63
+ "test:all": "node --no-warnings node_modules/jest/bin/jest.js tests/"
64
+ },
65
+ "devDependencies": {
66
+ "husky": "^9.1.7",
67
+ "jest": "^30.0.0",
68
+ "ws": "^8.18.0"
69
+ },
70
+ "engines": {
71
+ "node": ">=16.0.0"
72
+ },
73
+ "dependencies": {
74
+ "js-yaml": "^4.1.1",
75
+ "msedge-tts": "^2.0.4"
76
+ }
77
+ }
@@ -1,141 +0,0 @@
1
- #!/usr/bin/env bash
2
- #
3
- # Vibe Forge Worker Loop - Stop Hook
4
- #
5
- # Implements the Ralph Loop technique for Vibe Forge workers.
6
- # When a worker tries to exit, this hook checks if there are pending tasks
7
- # and feeds the worker prompt back to continue working.
8
- #
9
- # Based on the Ralph Loop plugin by Anthropic.
10
- #
11
- # Activation modes:
12
- # 1. Config-based: worker_loop_enabled=true in .forge/config.json
13
- # 2. Runtime: State file created by /worker-loop command
14
- #
15
-
16
- set -euo pipefail
17
-
18
- # State file location (runtime toggle)
19
- STATE_FILE="${CLAUDE_LOCAL_DIR:-$HOME/.claude}/forge-worker-loop.json"
20
- FORGE_ROOT="${FORGE_ROOT:-$(pwd)}"
21
-
22
- # Check for runtime state file first (takes precedence)
23
- LOOP_ACTIVE=false
24
- WORKER_AGENT=""
25
- MAX_IDLE_CHECKS=10
26
- IDLE_COUNT=0
27
- POLL_INTERVAL=5
28
-
29
- if [[ -f "$STATE_FILE" ]]; then
30
- LOOP_ACTIVE=true
31
- WORKER_AGENT=$(jq -r '.agent // ""' "$STATE_FILE" 2>/dev/null || echo "")
32
- MAX_IDLE_CHECKS=$(jq -r '.max_idle_checks // 10' "$STATE_FILE" 2>/dev/null || echo "10")
33
- IDLE_COUNT=$(jq -r '.idle_count // 0' "$STATE_FILE" 2>/dev/null || echo "0")
34
- POLL_INTERVAL=$(jq -r '.poll_interval // 5' "$STATE_FILE" 2>/dev/null || echo "5")
35
- fi
36
-
37
- # If no runtime state, check config-based setting
38
- if [[ "$LOOP_ACTIVE" == "false" ]]; then
39
- CONFIG_FILE="$FORGE_ROOT/.forge/config.json"
40
- if [[ -f "$CONFIG_FILE" ]]; then
41
- CONFIG_ENABLED=$(jq -r '.worker_loop_enabled // false' "$CONFIG_FILE" 2>/dev/null || echo "false")
42
- if [[ "$CONFIG_ENABLED" == "true" ]]; then
43
- LOOP_ACTIVE=true
44
- # For config-based, use "any" to match any worker
45
- WORKER_AGENT="any"
46
- fi
47
- fi
48
- fi
49
-
50
- # Check if worker loop is active
51
- if [[ "$LOOP_ACTIVE" == "false" ]]; then
52
- # No active loop, allow exit
53
- echo '{"decision": "allow"}'
54
- exit 0
55
- fi
56
-
57
- if [[ -z "$WORKER_AGENT" ]]; then
58
- # Invalid state, clean up and allow exit
59
- rm -f "$STATE_FILE" 2>/dev/null || true
60
- echo '{"decision": "allow"}'
61
- exit 0
62
- fi
63
-
64
- # Check for pending tasks (assigned to specific worker or any worker)
65
- TASKS_DIR="$FORGE_ROOT/tasks"
66
- PENDING_COUNT=0
67
- NEEDS_CHANGES_COUNT=0
68
-
69
- if [[ -d "$TASKS_DIR/pending" ]]; then
70
- if [[ "$WORKER_AGENT" == "any" ]]; then
71
- # Config mode: count all pending tasks
72
- PENDING_COUNT=$(find "$TASKS_DIR/pending" -name "*.md" 2>/dev/null | wc -l || echo "0")
73
- else
74
- # Runtime mode: count only tasks assigned to specific worker
75
- PENDING_COUNT=$(grep -l "assigned_to:.*$WORKER_AGENT" "$TASKS_DIR/pending/"*.md 2>/dev/null | wc -l || echo "0")
76
- fi
77
- fi
78
-
79
- if [[ -d "$TASKS_DIR/needs-changes" ]]; then
80
- if [[ "$WORKER_AGENT" == "any" ]]; then
81
- # Config mode: count all needs-changes tasks
82
- NEEDS_CHANGES_COUNT=$(find "$TASKS_DIR/needs-changes" -name "*.md" 2>/dev/null | wc -l || echo "0")
83
- else
84
- # Runtime mode: count only tasks assigned to specific worker
85
- NEEDS_CHANGES_COUNT=$(grep -l "assigned_to:.*$WORKER_AGENT" "$TASKS_DIR/needs-changes/"*.md 2>/dev/null | wc -l || echo "0")
86
- fi
87
- fi
88
-
89
- TOTAL_TASKS=$((PENDING_COUNT + NEEDS_CHANGES_COUNT))
90
-
91
- if [[ "$TOTAL_TASKS" -gt 0 ]]; then
92
- # Tasks found! Reset idle counter and continue
93
- if [[ -f "$STATE_FILE" ]]; then
94
- jq --argjson idle 0 '.idle_count = $idle' "$STATE_FILE" > "$STATE_FILE.tmp" && mv "$STATE_FILE.tmp" "$STATE_FILE"
95
- fi
96
-
97
- # Block exit and feed prompt to continue working
98
- cat << EOF
99
- {
100
- "decision": "block",
101
- "message": "[Forge Loop] Found $TOTAL_TASKS pending task(s). Continuing work...",
102
- "prompt": "Check tasks/pending/ and tasks/needs-changes/ for tasks assigned to you and begin working on them immediately."
103
- }
104
- EOF
105
- exit 0
106
- fi
107
-
108
- # No tasks - increment idle counter (only for runtime mode with state file)
109
- if [[ -f "$STATE_FILE" ]]; then
110
- IDLE_COUNT=$((IDLE_COUNT + 1))
111
- jq --argjson idle "$IDLE_COUNT" '.idle_count = $idle' "$STATE_FILE" > "$STATE_FILE.tmp" && mv "$STATE_FILE.tmp" "$STATE_FILE"
112
-
113
- if [[ "$IDLE_COUNT" -ge "$MAX_IDLE_CHECKS" ]]; then
114
- # Max idle checks reached, clean up and allow exit
115
- rm -f "$STATE_FILE"
116
- cat << EOF
117
- {
118
- "decision": "allow",
119
- "message": "[Forge Loop] No tasks found after $MAX_IDLE_CHECKS checks. Exiting."
120
- }
121
- EOF
122
- exit 0
123
- fi
124
-
125
- # Still within idle limit - wait and check again
126
- cat << EOF
127
- {
128
- "decision": "block",
129
- "message": "[Forge Loop] No tasks available. Idle check $IDLE_COUNT/$MAX_IDLE_CHECKS. Waiting...",
130
- "prompt": "No tasks currently assigned to you. Wait briefly, then check tasks/pending/ and tasks/needs-changes/ again for new work. If still no tasks, announce you are idle and ready."
131
- }
132
- EOF
133
- else
134
- # Config-based mode - no idle tracking, just allow exit when no tasks
135
- cat << EOF
136
- {
137
- "decision": "allow",
138
- "message": "[Forge Loop] No pending tasks. Worker exiting."
139
- }
140
- EOF
141
- fi
@@ -1,29 +0,0 @@
1
- {
2
- "permissions": {
3
- "allow": [
4
- "Bash(ls:*)",
5
- "Bash(git pull:*)",
6
- "Bash(npm view:*)",
7
- "Bash(gh run list:*)",
8
- "Bash(gh run view:*)",
9
- "Bash(gh secret list:*)",
10
- "Bash(git add:*)",
11
- "Bash(git commit:*)",
12
- "Bash(gh workflow run:*)",
13
- "Bash(gh repo view:*)"
14
- ]
15
- },
16
- "hooks": {
17
- "Stop": [
18
- {
19
- "matcher": "",
20
- "hooks": [
21
- {
22
- "type": "command",
23
- "command": ".claude/hooks/worker-loop.sh"
24
- }
25
- ]
26
- }
27
- ]
28
- }
29
- }