Skip to content
This repository was archived by the owner on Jul 13, 2026. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ Current caveat: the official registry sets `automator` to `default_channel: next

- This is an orchestrator, not a correctness guarantee. Bad planning artifacts still produce bad implementation runs.
- The npm installer writes the skill into every supported dependency skill root that is complete: `.agents/skills`, `.claude/skills`, and/or `.codex/skills`.
- Child sessions can use Claude or Codex depending on agent configuration.
- Child sessions can use Claude, Codex, Gemini, or a custom non-Codex agent command depending on agent configuration.
- Retrospectives inherit the configured primary agent by default, and can be overridden explicitly via `agentConfig`.
- The automator expects sprint planning to be complete before it starts.
- Review completion is gated by verification, not by child-session exit alone.
Expand Down Expand Up @@ -195,7 +195,7 @@ Host requirements:

- `python3` 3.11+
- `tmux`
- Claude Code or Codex runtime access
- Claude Code, Codex, Gemini CLI, or configured custom-agent runtime access
- macOS, Linux, or Windows via WSL

Target project requirements:
Expand All @@ -207,7 +207,7 @@ Target project requirements:
- `bmad-retrospective`
- optional `bmad-qa-generate-e2e-tests`

Claude-only, Codex-only, and mixed projects are all supported. The installer updates each supported root that already contains the required dependency `SKILL.md` files.
Claude-only, Codex-only, Gemini-assisted, custom-agent, and mixed projects are all supported. The installer updates each supported root that already contains the required dependency `SKILL.md` files.

Dependency skill internals such as `workflow.md` are optional. If the QA skill is missing, install still succeeds. Run Story Automator with `Skip Automate = true` unless the QA skill is installed.

Expand Down
25 changes: 20 additions & 5 deletions docs/agents-and-monitoring.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ This doc explains how Story Automator chooses child agents, builds child-session
There are two distinct agent layers:

- the orchestrator itself, which runs from a supported top-level agent session
- child sessions, which can run Claude or Codex depending on the agent plan
- child sessions, which can run Claude, Codex, Gemini, or configured custom non-Codex agent commands depending on the agent plan

Agent selection is driven by:

Expand Down Expand Up @@ -74,14 +74,29 @@ sequenceDiagram
Environment details:

- `STORY_AUTOMATOR_CHILD=true`
- `AI_AGENT=<claude|codex>`
- `AI_AGENT=<claude|codex|gemini|custom-name>`
- Codex child sessions use isolated `CODEX_HOME` under `/tmp`
- Gemini child sessions use `gemini --approval-mode yolo -p` by default so autonomous workflows can edit files and run tests. ⚠️ `yolo` auto-approves every tool call (file writes, shell, tests) without prompting, so only run it in a trusted workspace you control; do not point a yolo Gemini session at untrusted code or a workspace holding secrets
- custom non-Codex agents can be configured with `STORY_AUTOMATOR_AGENT_<NAME>_COMMAND`; set `STORY_AUTOMATOR_AGENT_<NAME>_PROCESS` only when the monitor should look for a different process name

## Claude vs Codex
## Agent CLI selection

Python Story Automator does support Codex child sessions.
Python Story Automator supports Claude, Codex, Gemini, and custom non-Codex child sessions at the runtime/dispatch layer. Unknown agent names fail fast unless a custom command is configured, so typos do not silently run under Claude.

That is a major difference from the older Go README guidance.
Runtime support means the wrapper launches the requested CLI and monitors the requested process. The agent still needs a local tool contract capable of the target workflow. For example, BMAD create/dev/auto/review steps require file reads/writes and often shell/test execution; a Gemini CLI setup without those tools may launch correctly but fail inside the workflow.

Built-in command mapping:

- `claude` → `claude --dangerously-skip-permissions`
- `codex` → `codex exec` / isolated Codex execution path
- `gemini` → `gemini --approval-mode yolo -p`

Custom command example:

```bash
export STORY_AUTOMATOR_AGENT_GLM_COMMAND='glm-cli --prompt'
export STORY_AUTOMATOR_AGENT_GLM_PROCESS='glm-cli' # optional; defaults to agent name
```

Important Codex-specific behavior:

Expand Down
10 changes: 7 additions & 3 deletions skills/bmad-story-automator/data/agent-fallback.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Agent Fallback Strategy (v3.0.0)

**Multi-Agent Support:** The orchestrator can use Claude or Codex as AI coding agents, with automatic fallback on failure.
**Multi-Agent Support:** The orchestrator can use Claude, Codex, Gemini, or configured custom non-Codex commands as AI coding agents, with automatic fallback on failure.

## Configuration

Expand Down Expand Up @@ -28,9 +28,13 @@ Agent selection is resolved via the deterministic agents file created in preflig
| Agent | CLI | Prompt Style | Timeout | Todo Tracking |
|-------|-----|--------------|---------|---------------|
| Claude | `claude --dangerously-skip-permissions` | Natural language skill prompt | 60min | ☒/☐ checkboxes |
| Codex | `codex exec --full-auto` | Natural language prompt | 90min (1.5x) | Not supported |
| Codex | isolated `codex exec -s workspace-write -c 'approval_policy="never"' -c 'model_reasoning_effort="high"' --disable plugins --disable sqlite --disable shell_snapshot` (under a temp `CODEX_HOME`) | Natural language prompt | 90min (1.5x) | Not supported |
| Gemini | `gemini --approval-mode yolo -p` (with model: `gemini --approval-mode yolo --model <id> -p`) | Natural language skill prompt | 60min | best-effort via generic monitor |
| Custom | `STORY_AUTOMATOR_AGENT_<NAME>_COMMAND` | Natural language skill prompt | 60min | best-effort via configured process pattern |

**CRITICAL:** Both Claude and Codex prompts must name the skill/workflow to execute and include the story ID.
**CRITICAL:** All child-agent prompts must name the skill/workflow to execute and include the story ID.

> ⚠️ **Gemini `--approval-mode yolo` safety:** `yolo` auto-approves every tool call (file edits, shell, test runs) with no prompt, so the child session can modify the workspace and run commands fully autonomously. Only use it for Gemini child sessions in a trusted workspace you control (the orchestrator runs in BMAD-managed repos with `GEMINI_CLI_TRUST_WORKSPACE=true`). Do not point a yolo Gemini session at untrusted code or a workspace holding secrets/credentials.

The `story-automator tmux-wrapper build-cmd` function automatically generates the correct prompt format based on `AI_AGENT` environment variable.

Expand Down
14 changes: 7 additions & 7 deletions skills/bmad-story-automator/data/tmux-commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -188,15 +188,15 @@ tmux capture-pane -t "SESSION" -p -S -100 # Raw capture (use sparingly)

**Agent Configuration (v1.3.0):**

| Variable | Claude | Codex |
|----------|--------|-------|
| CLI | `claude --dangerously-skip-permissions` | `codex exec --full-auto` |
| Prompt Style | Natural language skill prompt | Natural language skill prompt |
| Timeout Multiplier | 1x (60min) | 1.5x (90min) |
| Todo Tracking | ☒/☐ checkboxes | Not supported |
| Variable | Claude | Codex | Gemini | Custom non-Codex |
|----------|--------|-------|--------|------------------|
| CLI | `claude --dangerously-skip-permissions` | `codex exec -s workspace-write -c 'approval_policy="never"' -c 'model_reasoning_effort="high"' --disable plugins --disable sqlite --disable shell_snapshot` | `gemini --approval-mode yolo -p` | `STORY_AUTOMATOR_AGENT_<NAME>_COMMAND` |
| Prompt Style | Natural language skill prompt | Natural language skill prompt | Natural language skill prompt | Natural language skill prompt |
| Timeout Multiplier | 1x (60min) | 1.5x (90min) | 1x (60min) | 1x (60min) |
| Todo Tracking | ☒/☐ checkboxes | Not supported | best-effort generic monitor | best-effort generic monitor |

**Environment Variables:**
- `AI_AGENT` = `claude` or `codex` (used by story-automator tmux-wrapper and story-automator monitor-session)
- `AI_AGENT` = `claude`, `codex`, `gemini`, or a custom agent name (used by story-automator tmux-wrapper and story-automator monitor-session)
- `AI_COMMAND` = Full CLI (legacy, deprecated)

`{projectPath}` = project root
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from ..core.tmux_runtime import (
agent_cli,
agent_type,
detect_codex_session,
detect_agent_session,
estimate_wait,
extract_active_task,
generate_session_name,
Expand Down
39 changes: 29 additions & 10 deletions skills/bmad-story-automator/src/story_automator/commands/tmux.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,11 @@ def cmd_tmux_wrapper(args: list[str]) -> int:
idx += 2
continue
idx += 1
print(agent_cli(agent_type(), model))
try:
print(agent_cli(agent_type(), model))
except ValueError as exc:
print(str(exc), file=__import__("sys").stderr)
return 1
return 0
if action == "skill-prefix":
print(skill_prefix(agent_type()))
Expand Down Expand Up @@ -201,9 +205,16 @@ def _build_cmd(args: list[str]) -> int:
return 1
ai_command = os.environ.get("AI_COMMAND", "").strip()
if ai_command and not os.environ.get("AI_AGENT"):
cli = ai_command
if agent == "gemini":
cli = agent_cli(agent, model)
else:
cli = ai_command
elif agent != "codex":
cli = agent_cli(agent, model)
try:
cli = agent_cli(agent, model)
except ValueError as exc:
print(str(exc), file=__import__("sys").stderr)
return 1
else:
cli = "codex exec"
quoted_prompt = shlex.quote(prompt)
Expand Down Expand Up @@ -470,11 +481,16 @@ def _flag_value(args: list[str], idx: int, flag: str) -> str:

def _raw_agent_selection() -> str:
value = os.environ.get("AI_AGENT", "").strip().lower()
if not value:
inferred = _infer_agent_from_command(os.environ.get("AI_COMMAND", ""))
if inferred:
return inferred
return value if value in {"claude", "codex", "auto", "runtime"} else "auto"
if value:
# A non-empty AI_AGENT is authoritative: preserve the normalized name so
# agent_cli can use a configured custom command or fail fast on a typo.
# Collapsing unknown values to "auto" would silently break env-configured
# custom agents and violate the fail-fast contract.
return value
inferred = _infer_agent_from_command(os.environ.get("AI_COMMAND", ""))
if inferred:
return inferred
return "auto"


def _resolve_agent_selection(agent: str, project_root: str) -> str:
Expand All @@ -490,8 +506,11 @@ def _infer_agent_from_command(command: str) -> str:
executable = Path(shlex.split(value)[0]).name.lower()
except ValueError:
return ""
if "codex" in executable:
token = Path(executable).stem.lower()
if token in {"codex", "codex-cli"}:
return "codex"
if "claude" in executable:
if token == "claude":
return "claude"
if token in {"gemini", "gemini-cli"}:
return "gemini"
return ""
Loading