diff --git a/get-shit-done/bin/lib/config.cjs b/get-shit-done/bin/lib/config.cjs index 5f1ae3d38..fd1f11ae9 100644 --- a/get-shit-done/bin/lib/config.cjs +++ b/get-shit-done/bin/lib/config.cjs @@ -28,6 +28,7 @@ const VALID_CONFIG_KEYS = new Set([ 'workflow.subagent_timeout', 'hooks.context_warnings', 'project_code', 'phase_naming', + 'manager.flags.discuss', 'manager.flags.plan', 'manager.flags.execute', ]); /** diff --git a/get-shit-done/bin/lib/core.cjs b/get-shit-done/bin/lib/core.cjs index 81b8cd9b4..ed316146d 100644 --- a/get-shit-done/bin/lib/core.cjs +++ b/get-shit-done/bin/lib/core.cjs @@ -314,6 +314,7 @@ function loadConfig(cwd) { subagent_timeout: get('subagent_timeout', { section: 'workflow', field: 'subagent_timeout' }) ?? defaults.subagent_timeout, model_overrides: parsed.model_overrides || null, agent_skills: parsed.agent_skills || {}, + manager: parsed.manager || {}, }; } catch { return defaults; diff --git a/get-shit-done/bin/lib/init.cjs b/get-shit-done/bin/lib/init.cjs index dd126eb42..dc0f8e03c 100644 --- a/get-shit-done/bin/lib/init.cjs +++ b/get-shit-done/bin/lib/init.cjs @@ -1026,6 +1026,14 @@ function cmdInitManager(cwd, raw) { }); const completedCount = phases.filter(p => p.disk_status === 'complete').length; + + // Read manager flags from config (passthrough flags for each step) + const managerFlags = { + discuss: (config.manager && config.manager.flags && config.manager.flags.discuss) || '', + plan: (config.manager && config.manager.flags && config.manager.flags.plan) || '', + execute: (config.manager && config.manager.flags && config.manager.flags.execute) || '', + }; + const result = { milestone_version: milestone.version, milestone_name: milestone.name, @@ -1039,6 +1047,7 @@ function cmdInitManager(cwd, raw) { project_exists: pathExistsInternal(cwd, '.planning/PROJECT.md'), roadmap_exists: true, state_exists: true, + manager_flags: managerFlags, }; output(withProjectRoot(cwd, result), raw); diff --git a/get-shit-done/references/planning-config.md b/get-shit-done/references/planning-config.md index e598f6214..aba562b98 100644 --- a/get-shit-done/references/planning-config.md +++ b/get-shit-done/references/planning-config.md @@ -14,6 +14,13 @@ Configuration options for `.planning/` directory behavior. "phase_branch_template": "gsd/phase-{phase}-{slug}", "milestone_branch_template": "gsd/{milestone}-{slug}", "quick_branch_template": null +}, +"manager": { + "flags": { + "discuss": "", + "plan": "", + "execute": "" + } } ``` @@ -28,6 +35,9 @@ Configuration options for `.planning/` directory behavior. | `git.quick_branch_template` | `null` | Optional branch template for quick-task runs | | `workflow.use_worktrees` | `true` | Whether executor agents run in isolated git worktrees. Set to `false` to disable worktrees — agents execute sequentially on the main working tree instead. Recommended for solo developers or when worktree merges cause issues. | | `workflow.subagent_timeout` | `300000` | Timeout in milliseconds for parallel subagent tasks (e.g. codebase mapping). Increase for large codebases or slower models. Default: 300000 (5 minutes). | +| `manager.flags.discuss` | `""` | Flags passed to `/gsd:discuss-phase` when dispatched from manager (e.g. `"--auto --analyze"`) | +| `manager.flags.plan` | `""` | Flags passed to plan workflow when dispatched from manager | +| `manager.flags.execute` | `""` | Flags passed to execute workflow when dispatched from manager | diff --git a/get-shit-done/workflows/manager.md b/get-shit-done/workflows/manager.md index 4eba9624b..fc3c64ee0 100644 --- a/get-shit-done/workflows/manager.md +++ b/get-shit-done/workflows/manager.md @@ -23,7 +23,14 @@ INIT=$(node "$HOME/.claude/get-shit-done/bin/gsd-tools.cjs" init manager) if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi ``` -Parse JSON for: `milestone_version`, `milestone_name`, `phase_count`, `completed_count`, `in_progress_count`, `phases`, `recommended_actions`, `all_complete`, `waiting_signal`. +Parse JSON for: `milestone_version`, `milestone_name`, `phase_count`, `completed_count`, `in_progress_count`, `phases`, `recommended_actions`, `all_complete`, `waiting_signal`, `manager_flags`. + +`manager_flags` contains per-step passthrough flags from config: +- `manager_flags.discuss` — appended to `/gsd:discuss-phase` args (e.g. `"--auto --analyze"`) +- `manager_flags.plan` — appended to plan agent init command +- `manager_flags.execute` — appended to execute agent init command + +These are empty strings by default. Set via: `gsd-tools config-set manager.flags.discuss "--auto --analyze"` **If error:** Display the error message and exit. @@ -193,24 +200,24 @@ When the user selects a compound option: 2. **Then run the inline discuss:** ``` -Skill(skill="gsd:discuss-phase", args="{PHASE_NUM}") +Skill(skill="gsd:discuss-phase", args="{PHASE_NUM} {manager_flags.discuss}") ``` After discuss completes, loop back to dashboard step (background agents continue running). ### Discuss Phase N -Discussion is interactive — needs user input. Run inline: +Discussion is interactive — needs user input. Run inline with any configured flags: ``` -Skill(skill="gsd:discuss-phase", args="{PHASE_NUM}") +Skill(skill="gsd:discuss-phase", args="{PHASE_NUM} {manager_flags.discuss}") ``` After discuss completes, loop back to dashboard step. ### Plan Phase N -Planning runs autonomously. Spawn a background agent that delegates to the Skill pipeline: +Planning runs autonomously. Spawn a background agent that delegates to the Skill pipeline with any configured flags: ``` Task( @@ -221,9 +228,10 @@ Task( Working directory: {cwd} Phase: {N} — {phase_name} Goal: {goal} +Manager flags: {manager_flags.plan} -Run the plan-phase Skill: -Skill(skill=\"gsd:plan-phase\", args=\"{N} --auto\") +Run the plan-phase Skill with any configured manager flags: +Skill(skill=\"gsd:plan-phase\", args=\"{N} --auto {manager_flags.plan}\") This delegates to the full plan-phase pipeline including local patches, research, plan-checker, and all quality gates. @@ -241,7 +249,7 @@ Loop back to dashboard step. ### Execute Phase N -Execution runs autonomously. Spawn a background agent that delegates to the Skill pipeline: +Execution runs autonomously. Spawn a background agent that delegates to the Skill pipeline with any configured flags: ``` Task( @@ -252,9 +260,10 @@ Task( Working directory: {cwd} Phase: {N} — {phase_name} Goal: {goal} +Manager flags: {manager_flags.execute} -Run the execute-phase Skill: -Skill(skill=\"gsd:execute-phase\", args=\"{N}\") +Run the execute-phase Skill with any configured manager flags: +Skill(skill=\"gsd:execute-phase\", args=\"{N} {manager_flags.execute}\") This delegates to the full execute-phase pipeline including local patches, branching, wave-based execution, verification, and all quality gates. diff --git a/tests/init-manager.test.cjs b/tests/init-manager.test.cjs index c133093bd..08d685ddb 100644 --- a/tests/init-manager.test.cjs +++ b/tests/init-manager.test.cjs @@ -413,4 +413,44 @@ describe('init manager', () => { // macOS resolves /var → /private/var; normalize both sides assert.strictEqual(fs.realpathSync(output.project_root), fs.realpathSync(tmpDir)); }); + + test('output includes manager_flags defaults when not configured', () => { + writeState(tmpDir); + writeRoadmap(tmpDir, [{ number: '1', name: 'Test' }]); + + const result = runGsdTools('init manager', tmpDir); + const output = JSON.parse(result.output); + + assert.ok(output.manager_flags, 'should include manager_flags'); + assert.strictEqual(output.manager_flags.discuss, ''); + assert.strictEqual(output.manager_flags.plan, ''); + assert.strictEqual(output.manager_flags.execute, ''); + }); + + test('output includes manager_flags from config when set', () => { + writeState(tmpDir); + writeRoadmap(tmpDir, [{ number: '1', name: 'Test' }]); + + // Write config with manager flags + fs.writeFileSync( + path.join(tmpDir, '.planning', 'config.json'), + JSON.stringify({ + manager: { + flags: { + discuss: '--auto --analyze', + plan: '--skip-research', + execute: '--interactive', + } + } + }) + ); + + const result = runGsdTools('init manager', tmpDir); + const output = JSON.parse(result.output); + + assert.ok(output.manager_flags, 'should include manager_flags'); + assert.strictEqual(output.manager_flags.discuss, '--auto --analyze'); + assert.strictEqual(output.manager_flags.plan, '--skip-research'); + assert.strictEqual(output.manager_flags.execute, '--interactive'); + }); });