Skip to content

feat: support Gemini and custom agent runtimes#37

Open
Ezopek wants to merge 8 commits into
bmad-code-org:mainfrom
Ezopek:feat/gemini-custom-agent-runtime
Open

feat: support Gemini and custom agent runtimes#37
Ezopek wants to merge 8 commits into
bmad-code-org:mainfrom
Ezopek:feat/gemini-custom-agent-runtime

Conversation

@Ezopek

@Ezopek Ezopek commented Jun 6, 2026

Copy link
Copy Markdown

Summary

Adds runtime dispatch support for Gemini and custom non-Codex child agents in the Python Story Automator tmux flow.

This PR makes per-task agentConfig safer and more explicit:

  • gemini now launches Gemini CLI instead of silently falling through to Claude.
  • unsupported agent names fail fast unless a custom command is configured.
  • custom non-Codex agents can be wired with environment variables:
    • STORY_AUTOMATOR_AGENT_<NAME>_COMMAND
    • legacy-compatible AI_COMMAND_<NAME>
    • optional STORY_AUTOMATOR_AGENT_<NAME>_PROCESS for liveness monitoring when the executable name differs from the agent alias.
  • legacy/tmux liveness checks are now agent-aware and descendant-aware, so wrapped agents are not missed.
  • docs/tests cover Claude, Codex, Gemini, and custom-agent dispatch behavior.

Fixes #33.

Motivation

agentConfig can express per-task agent choices, but the tmux runtime previously treated unknown/non-Codex agents like Claude in important paths. That made configurations such as review: gemini misleading and unsafe, because they could silently run under Claude.

The goal of this PR is to make child-agent dispatch explicit:

  • built-in Gemini support works at the runtime/dispatch layer;
  • custom agent commands are supported without source changes;
  • typos or unsupported agents fail loudly instead of falling back silently.

Implementation notes

Built-in command mapping now includes:

  • Claude: claude --dangerously-skip-permissions
  • Codex: existing isolated Codex execution path
  • Gemini: gemini --approval-mode yolo -p
    • with a model: gemini --approval-mode yolo --model <id> -p

Gemini uses --approval-mode yolo because BMAD child workflows need autonomous file edits and shell/test execution. The docs call out the safety boundary: this is only appropriate in trusted workspaces controlled by the operator.

Custom agents use STORY_AUTOMATOR_AGENT_<NAME>_COMMAND; liveness monitoring defaults to the configured command executable basename unless an explicit STORY_AUTOMATOR_AGENT_<NAME>_PROCESS override is provided.

Relationship to #34

This does not duplicate #34's native OpenCode dispatch work. This PR stays in the existing tmux child-session runtime and adds Gemini/custom non-Codex CLI selection there.

Validation

Final validation on the current branch:

env -u AI_AGENT PYTHONPATH=skills/bmad-story-automator/src python3 -m pytest tests/test_agent_config_model.py tests/test_tmux_runtime.py -q
# 83 passed, 14 subtests passed

env -u AI_AGENT PYTHONPATH=skills/bmad-story-automator/src python3 -m pytest -q
# 442 passed, 20 subtests passed

npm run test:smoke
# smoke ok

Additional manual validation:

  • all-role Gemini scratch test confirmed runtime dispatch starts Gemini for create, dev, auto, review, and retro roles;
  • bare headless gemini -p was verified to be insufficient for autonomous workflows, so built-in Gemini dispatch now uses --approval-mode yolo;
  • independent Codex review initially found dispatch/model-order/custom-process issues; those were fixed in follow-up commits, and a second fresh Codex review returned APPROVE.

CodeRabbit is green on the latest commit.

Summary by CodeRabbit

  • New Features
    • Added runtime support for Gemini and custom-configured agents alongside Claude/Codex, with improved agent selection via AI_AGENT or command inference.
    • Enhanced tmux process monitoring to be agent-aware (including better task labeling) and applied Gemini workspace trust in tmux sessions.
  • Documentation
    • Updated README and agent/monitoring guides to include Gemini and custom-agent configuration and CLI examples.
  • Bug Fixes
    • Improved failure handling for unsupported agent selections by reporting the error and exiting with code 1.
  • Tests
    • Expanded unit tests for Gemini/custom agent command rendering and process-ancestry detection.

@Ezopek Ezopek requested a review from bma-d as a code owner June 6, 2026 23:12
@coderabbitai

coderabbitai Bot commented Jun 6, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 9dc33bd0-5a19-485c-8cef-17540dfac453

📥 Commits

Reviewing files that changed from the base of the PR and between 1b33167 and de80f2a.

📒 Files selected for processing (4)
  • skills/bmad-story-automator/src/story_automator/commands/tmux.py
  • skills/bmad-story-automator/src/story_automator/core/tmux_runtime.py
  • tests/test_agent_config_model.py
  • tests/test_tmux_runtime.py
🚧 Files skipped from review as they are similar to previous changes (3)
  • tests/test_tmux_runtime.py
  • tests/test_agent_config_model.py
  • skills/bmad-story-automator/src/story_automator/core/tmux_runtime.py

Walkthrough

This PR adds Gemini and configurable custom child-agent support: docs updated, tmux command paths made agent-aware and fail-fast on unknown agents, core runtime now derives/normalizes agents and builds per-agent CLI (including Gemini), session detection generalized, process-ancestry checks added, and tests extended.

Changes

Multi-Agent Support: Gemini and Custom LLM Configuration

Layer / File(s) Summary
Documentation of Multi-Agent Support
README.md, docs/agents-and-monitoring.md, skills/bmad-story-automator/data/agent-fallback.md, skills/bmad-story-automator/data/tmux-commands.md
Updated README and docs to document `AI_AGENT=<claude
Adapter import update
skills/bmad-story-automator/src/story_automator/adapters/tmux.py
Replaced detect_codex_session import with detect_agent_session.
CLI Selection & Error Handling in Commands
skills/bmad-story-automator/src/story_automator/commands/tmux.py
Treat non-empty AI_AGENT as authoritative (normalized), infer agent from AI_COMMAND otherwise (with Gemini detection), catch and report ValueError from agent_cli() to stderr returning exit code 1.
Core Agent Type, CLI, Session & Process Monitoring
skills/bmad-story-automator/src/story_automator/core/tmux_runtime.py
Added agent_type() and enhanced agent_cli() with normalization and per-agent env overrides; added helpers custom_agent_command(), normalize_agent_name(), env_agent_name(), agent_process_pattern(); replaced detect_codex_session() with detect_agent_session(); updated legacy activity checks to use agent-aware descendant-process matching; added /proc/ps-backed ancestry helpers; set GEMINI_CLI_TRUST_WORKSPACE=true in spawns.
Test Coverage for Multi-Agent Behavior
tests/test_agent_config_model.py, tests/test_tmux_runtime.py
Extended tests for Gemini CLI generation (including model/-p ordering and quoting), custom command overrides (current and legacy env vars), process-pattern derivation for custom agents, raw agent selection inference/normalization, _build_cmd Gemini-specific paths, and pane-descendant ancestry detection helpers with cycle protection.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • bma-d

Poem

🐰 Hops and whiskers in the sand,
Multi-agents, oh so grand!
Gemini joined with Custom flair,
CLI commands floating through the air,
Codex, Claude, now side by side—
Automation's config opens wide!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 4.11% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: support Gemini and custom agent runtimes' clearly and concisely summarizes the main changes: adding Gemini support and custom agent runtime capabilities to the Story Automator.
Linked Issues check ✅ Passed The PR fully addresses issue #33's objectives: implementing built-in Gemini dispatch, supporting custom agent commands via environment configuration, and enabling per-task LLM selection without source code changes.
Out of Scope Changes check ✅ Passed All changes are directly related to supporting Gemini and custom agent runtimes: documentation updates, runtime dispatch logic, CLI selection, liveness checks, and comprehensive test coverage all align with the linked issue requirements.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@skills/bmad-story-automator/data/tmux-commands.md`:
- Line 193: Update the CLI table row in tmux-commands.md so the Codex entry
reflects the actual runtime command built by the automator: replace the stale
`codex exec --full-auto` string with the full command template that includes
explicit flags (e.g. `codex exec -s workspace-write --allow-policy
--allow-reasoning` or the project’s exact policy/reasoning flags), and ensure
the corresponding environment variable `STORY_AUTOMATOR_AGENT_<NAME>_COMMAND`
example matches that same full command template.

In `@skills/bmad-story-automator/src/story_automator/core/tmux_runtime.py`:
- Around line 914-917: The current liveness check uses pgrep -P <pane_pid> which
only finds immediate children and misses wrapped agents; update the logic that
sets agent_running in tmux_runtime.py to: run pgrep -f
agent_process_pattern(agent) (using the existing run_cmd) to get candidate PIDs,
then for each candidate call a new helper (e.g., _is_descendant(pid, pane_pid))
that walks parent PIDs (via /proc/<pid>/stat or ps -o ppid) to determine if
pane_pid is an ancestor; set agent_running true if any candidate is a
descendant. Keep references to detect_agent_session, tmux_display,
agent_process_pattern, run_cmd and replace the existing pgrep -P usage with this
descendant-aware check.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 5fd794dc-a27c-4f57-a763-199b971e073f

📥 Commits

Reviewing files that changed from the base of the PR and between f332173 and 64c56da.

📒 Files selected for processing (8)
  • README.md
  • docs/agents-and-monitoring.md
  • skills/bmad-story-automator/data/agent-fallback.md
  • skills/bmad-story-automator/data/tmux-commands.md
  • skills/bmad-story-automator/src/story_automator/adapters/tmux.py
  • skills/bmad-story-automator/src/story_automator/commands/tmux.py
  • skills/bmad-story-automator/src/story_automator/core/tmux_runtime.py
  • tests/test_agent_config_model.py

Comment thread skills/bmad-story-automator/data/tmux-commands.md Outdated
@Ezopek

Ezopek commented Jun 6, 2026

Copy link
Copy Markdown
Author

Follow-up after CodeRabbit's two actionable comments:

  • Addressed the stale Codex CLI docs in skills/bmad-story-automator/data/tmux-commands.md by replacing codex exec --full-auto with the actual command shape generated by the current build-cmd Codex path.
  • Addressed the process liveness concern by replacing the direct-child-only pgrep -P <pane_pid> check with descendant-aware detection:
    • collect candidate PIDs with pgrep -f <agent_process_pattern>;
    • confirm each candidate is under the tmux pane by walking parent PIDs via /proc/<pid>/stat with a ps fallback;
    • added focused coverage for grandchild detection, unrelated matching processes, no-match, invalid pane PID, and parent-cycle safety.

Validation after the follow-up commit 60ac970:

  • PYTHONPATH=skills/bmad-story-automator/src python3 -m pytest -q
    • 424 passed, 2 skipped, 20 subtests passed
  • npm run test:smoke
    • smoke ok
  • External Gemini review of the follow-up diff: APPROVE

CodeRabbit appears rate-limited on the latest pass, but the current PR check is green and both original inline review threads are addressed by the follow-up commit.

@Ezopek Ezopek marked this pull request as draft June 7, 2026 00:23
@Ezopek Ezopek marked this pull request as ready for review June 7, 2026 01:16

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
skills/bmad-story-automator/src/story_automator/core/tmux_runtime.py (1)

1013-1015: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Legacy heartbeat still only looks for Claude/Codex processes.

_legacy_heartbeat_check() is the path behind cmd_heartbeat_check() in legacy mode, but Lines 1013-1014 still hard-code "codex" vs "claude". Gemini/custom sessions will be reported as dead/completed even while session_status() can still see them via agent_process_pattern() and the new descendant-aware checks, so the two monitors can disagree on the same live session.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@skills/bmad-story-automator/src/story_automator/core/tmux_runtime.py` around
lines 1013 - 1015, The legacy heartbeat path (_legacy_heartbeat_check called by
cmd_heartbeat_check) currently hard-codes "codex"/"claude" when building the
`pattern` used by _find_agent_pid, which causes Gemini/custom sessions to be
missed; update the logic to derive the search pattern via the existing
agent_process_pattern(selected_agent) (or equivalent helper) instead of the
ternary, and pass that pattern into _find_agent_pid so legacy checks use the
same descendant-aware process pattern resolution as
session_status()/agent_process_pattern; ensure the code references
selected_agent, _find_agent_pid, and agent_process_pattern so the monitors
remain consistent.
skills/bmad-story-automator/src/story_automator/commands/tmux.py (1)

206-214: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Don't bypass the built-in Gemini launcher when only AI_COMMAND is set.

_raw_agent_selection() now infers "gemini" from AI_COMMAND, but this branch still emits the raw AI_COMMAND whenever AI_AGENT is unset. With AI_COMMAND=gemini, the generated command becomes gemini <prompt> and drops both --approval-mode yolo -p and any task-level --model, so the legacy env path still mis-dispatches Gemini instead of using the new built-in CLI shape.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@skills/bmad-story-automator/src/story_automator/commands/tmux.py` around
lines 206 - 214, The branch that sets cli = ai_command when AI_COMMAND is
present bypasses the built-in Gemini launcher; change it so that when AI_COMMAND
is set but the inferred agent is "gemini" (or agent == "gemini") you call
agent_cli(agent, model) instead of using the raw AI_COMMAND, otherwise fall back
to using ai_command; update the block handling ai_command/AI_AGENT to prefer
agent_cli for known agents (at minimum check agent == "gemini") and only emit
the raw ai_command for truly custom/unknown agents.
🧹 Nitpick comments (1)
tests/test_agent_config_model.py (1)

718-739: ⚡ Quick win

Add the AI_COMMAND-only Gemini regression case.

These tests cover AI_AGENT=gemini, but the broken branch is when AI_AGENT is empty and AI_COMMAND is the only signal. A case like AI_COMMAND=gemini plus --model gemini-2.5-pro would catch the current fallback to raw AI_COMMAND instead of agent_cli("gemini", model).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/test_agent_config_model.py` around lines 718 - 739, Add a test that
simulates the regression where AI_AGENT is empty but AI_COMMAND is set: in tests
referencing _build_cmd, patch the environment to set AI_COMMAND="gemini" (and
ensure AI_AGENT is not set or is empty) and call
_build_cmd(["review","9.1","--model","gemini-2.5-pro"]) capturing stdout; assert
the rendered command contains the expected "gemini --approval-mode yolo -p"
invocation and does not contain "claude --dangerously-skip-permissions" to
ensure the _raw_agent_selection path does not incorrectly bypass
agent_cli("gemini", model) and fall back to raw AI_COMMAND handling.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@skills/bmad-story-automator/src/story_automator/commands/tmux.py`:
- Around line 206-214: The branch that sets cli = ai_command when AI_COMMAND is
present bypasses the built-in Gemini launcher; change it so that when AI_COMMAND
is set but the inferred agent is "gemini" (or agent == "gemini") you call
agent_cli(agent, model) instead of using the raw AI_COMMAND, otherwise fall back
to using ai_command; update the block handling ai_command/AI_AGENT to prefer
agent_cli for known agents (at minimum check agent == "gemini") and only emit
the raw ai_command for truly custom/unknown agents.

In `@skills/bmad-story-automator/src/story_automator/core/tmux_runtime.py`:
- Around line 1013-1015: The legacy heartbeat path (_legacy_heartbeat_check
called by cmd_heartbeat_check) currently hard-codes "codex"/"claude" when
building the `pattern` used by _find_agent_pid, which causes Gemini/custom
sessions to be missed; update the logic to derive the search pattern via the
existing agent_process_pattern(selected_agent) (or equivalent helper) instead of
the ternary, and pass that pattern into _find_agent_pid so legacy checks use the
same descendant-aware process pattern resolution as
session_status()/agent_process_pattern; ensure the code references
selected_agent, _find_agent_pid, and agent_process_pattern so the monitors
remain consistent.

---

Nitpick comments:
In `@tests/test_agent_config_model.py`:
- Around line 718-739: Add a test that simulates the regression where AI_AGENT
is empty but AI_COMMAND is set: in tests referencing _build_cmd, patch the
environment to set AI_COMMAND="gemini" (and ensure AI_AGENT is not set or is
empty) and call _build_cmd(["review","9.1","--model","gemini-2.5-pro"])
capturing stdout; assert the rendered command contains the expected "gemini
--approval-mode yolo -p" invocation and does not contain "claude
--dangerously-skip-permissions" to ensure the _raw_agent_selection path does not
incorrectly bypass agent_cli("gemini", model) and fall back to raw AI_COMMAND
handling.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 9dcf2ab6-e5f0-4dd6-a4b4-afd8b4ac3456

📥 Commits

Reviewing files that changed from the base of the PR and between 64c56da and c939355.

📒 Files selected for processing (7)
  • docs/agents-and-monitoring.md
  • skills/bmad-story-automator/data/agent-fallback.md
  • skills/bmad-story-automator/data/tmux-commands.md
  • skills/bmad-story-automator/src/story_automator/commands/tmux.py
  • skills/bmad-story-automator/src/story_automator/core/tmux_runtime.py
  • tests/test_agent_config_model.py
  • tests/test_tmux_runtime.py
✅ Files skipped from review due to trivial changes (1)
  • docs/agents-and-monitoring.md
🚧 Files skipped from review as they are similar to previous changes (2)
  • skills/bmad-story-automator/data/tmux-commands.md
  • skills/bmad-story-automator/data/agent-fallback.md

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
skills/bmad-story-automator/src/story_automator/commands/tmux.py (1)

501-515: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Use exact executable matching in agent inference to avoid silent misrouting.

On Line 509/Line 511/Line 513, substring checks can misclassify custom wrappers (e.g., my-gemini-wrapper) as built-in agents. That can make _build_cmd ignore the raw AI_COMMAND path and dispatch the wrong CLI.

Proposed fix
 def _infer_agent_from_command(command: str) -> str:
     value = command.strip()
     if not value:
         return ""
     try:
-        executable = Path(shlex.split(value)[0]).name.lower()
+        executable = Path(shlex.split(value)[0]).name.lower()
+        token = Path(executable).stem.lower()  # handles .exe and similar suffixes
     except ValueError:
         return ""
-    if "codex" in executable:
+    if token in {"codex", "codex-cli"}:
         return "codex"
-    if "claude" in executable:
+    if token in {"claude"}:
         return "claude"
-    if "gemini" in executable:
+    if token in {"gemini", "gemini-cli"}:
         return "gemini"
     return ""
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@skills/bmad-story-automator/src/story_automator/commands/tmux.py` around
lines 501 - 515, _infer_agent_from_command currently uses substring checks on
the resolved executable name (variable executable), which can misclassify
wrappers like "my-gemini-wrapper"; change the logic to perform exact matching
against the known agent binary names (e.g., compare executable == "codex" or
executable == "codex.exe" and likewise for "claude" and "gemini") rather than
"in" substring checks so only true agent executables are detected; update the
checks in _infer_agent_from_command to normalize the name (lowercase) and
compare equality against the allowed set of agent names (and common platform
extensions like .exe) and otherwise return "".
🧹 Nitpick comments (1)
tests/test_agent_config_model.py (1)

677-689: ⚡ Quick win

Add a regression test for wrapper-name collisions in _infer_agent_from_command.

Current cases don’t guard against false positives like my-gemini-wrapper run, which should remain unknown ("") rather than infer built-in Gemini.

Suggested test addition
 class InferAgentFromCommandTests(unittest.TestCase):
@@
     def test_empty_and_unknown_return_empty(self) -> None:
         self.assertEqual(_infer_agent_from_command(""), "")
         self.assertEqual(_infer_agent_from_command("some-other-tool run"), "")
+        self.assertEqual(_infer_agent_from_command("my-gemini-wrapper run"), "")
+        self.assertEqual(_infer_agent_from_command("codextra run"), "")
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/test_agent_config_model.py` around lines 677 - 689, Add a regression
test to ensure _infer_agent_from_command does not falsely match wrapper names
that contain agent names as substrings (e.g., "my-gemini-wrapper run" should
return ""), by adding assertions to InferAgentFromCommandTests that verify
commands like "my-gemini-wrapper run" and similarly prefixed/suffixed variants
(e.g., "prefix-gemini", "gemini-wrapper") return an empty string; update or add
test cases in the class referencing the _infer_agent_from_command function to
cover these collision scenarios.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@skills/bmad-story-automator/src/story_automator/commands/tmux.py`:
- Around line 501-515: _infer_agent_from_command currently uses substring checks
on the resolved executable name (variable executable), which can misclassify
wrappers like "my-gemini-wrapper"; change the logic to perform exact matching
against the known agent binary names (e.g., compare executable == "codex" or
executable == "codex.exe" and likewise for "claude" and "gemini") rather than
"in" substring checks so only true agent executables are detected; update the
checks in _infer_agent_from_command to normalize the name (lowercase) and
compare equality against the allowed set of agent names (and common platform
extensions like .exe) and otherwise return "".

---

Nitpick comments:
In `@tests/test_agent_config_model.py`:
- Around line 677-689: Add a regression test to ensure _infer_agent_from_command
does not falsely match wrapper names that contain agent names as substrings
(e.g., "my-gemini-wrapper run" should return ""), by adding assertions to
InferAgentFromCommandTests that verify commands like "my-gemini-wrapper run" and
similarly prefixed/suffixed variants (e.g., "prefix-gemini", "gemini-wrapper")
return an empty string; update or add test cases in the class referencing the
_infer_agent_from_command function to cover these collision scenarios.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: df656f2a-7632-4fa1-9a7b-0d77ed2f62fe

📥 Commits

Reviewing files that changed from the base of the PR and between c939355 and 1b33167.

📒 Files selected for processing (4)
  • skills/bmad-story-automator/src/story_automator/commands/tmux.py
  • skills/bmad-story-automator/src/story_automator/core/tmux_runtime.py
  • tests/test_agent_config_model.py
  • tests/test_tmux_runtime.py
🚧 Files skipped from review as they are similar to previous changes (2)
  • tests/test_tmux_runtime.py
  • skills/bmad-story-automator/src/story_automator/core/tmux_runtime.py

@bma-d

bma-d commented Jun 17, 2026

Copy link
Copy Markdown
Collaborator

@augmentcode review

@augmentcode

augmentcode Bot commented Jun 17, 2026

Copy link
Copy Markdown
🤖 Augment PR Summary

Summary: This PR makes Story Automator tmux child-session dispatch explicit and safer by adding first-class Gemini support and enabling configurable custom non-Codex agent runtimes.

Changes:

  • Extended agent selection to recognize gemini and arbitrary custom agent names (fail-fast on unknown agents unless a custom command is configured).
  • Added built-in Gemini CLI mapping using gemini --approval-mode yolo -p (with correct model-flag ordering).
  • Added env-based custom agent configuration via STORY_AUTOMATOR_AGENT_<NAME>_COMMAND and optional ..._PROCESS for liveness monitoring.
  • Updated tmux wrapper command generation to surface unsupported agents as errors instead of silently falling back.
  • Improved legacy tmux liveness checks to be agent-aware and descendant-aware (handles wrapper/shell launched agents).
  • Propagated Gemini trust-workspace env var into spawned sessions.
  • Updated docs to cover Claude/Codex/Gemini/custom dispatch and monitoring.
  • Expanded unit tests to cover agent CLI mapping, selection inference, custom agents, and descendant PID ancestry detection.

Technical Notes: The liveness monitor now uses a process-pattern lookup per agent and validates candidate PIDs by walking parent PIDs up to the tmux pane PID to avoid missing wrapped child processes.

🤖 Was this summary useful? React with 👍 or 👎

@augmentcode augmentcode Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review completed. 2 suggestions posted.

Fix All in Augment

Comment augment review to trigger a new review at any time.

def agent_type() -> str:
value = os.environ.get("AI_AGENT", "").strip().lower()
if value in {"claude", "codex"}:
value = normalize_agent_name(os.environ.get("AI_AGENT", ""))

@augmentcode augmentcode Bot Jun 17, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

agent_type() now returns any non-empty AI_AGENT value verbatim, so AI_AGENT=auto/runtime (which _raw_agent_selection() preserves) will flow into tmux-wrapper agent-cli and fail because agent_cli() rejects those names. Consider resolving auto/runtime via runtime_provider() here to keep env-based selection behavior consistent across entry points.

Severity: medium

Fix This in Augment

🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in de80f2a.

agent_type() now treats auto and runtime as meta-selectors and resolves them through runtime_provider() instead of returning them as concrete agent names. Explicit built-in/custom agent names still pass through unchanged. Added regression coverage in AgentTypeResolutionTests for auto, runtime, empty, built-in, and custom agent values.

Validation:

  • env -u AI_AGENT PYTHONPATH=skills/bmad-story-automator/src python3 -m pytest tests/test_agent_config_model.py tests/test_tmux_runtime.py -q → 94 passed, 14 subtests passed
  • env -u AI_AGENT PYTHONPATH=skills/bmad-story-automator/src python3 -m pytest -q → 453 passed, 20 subtests passed
  • npm run test:smoke → smoke ok

f"unsupported agent {agent!r}; supported agents are claude, codex, gemini, "
f"or set STORY_AUTOMATOR_AGENT_{env_agent_name(agent)}_COMMAND"
)
if model:

@augmentcode augmentcode Bot Jun 17, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When custom_agent_command() is used, the later if model: appends --model ... to the end of the custom command, which can break CLIs where the prompt flag must be last (e.g. a custom Gemini command ending in -p). This can result in the model flag being swallowed/ignored and the session running with an unintended model.

Severity: medium

Fix This in Augment

🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in de80f2a.

For custom commands ending in a trailing -p, agent_cli() now injects --model <quoted model> before -p, preventing prompt flags from swallowing the model argument. Custom commands without trailing -p keep the previous append-at-end behavior, and Claude/Codex behavior is unchanged. Added regression tests for trailing -p, quoted model values, and the non--p append path.

Validation:

  • env -u AI_AGENT PYTHONPATH=skills/bmad-story-automator/src python3 -m pytest tests/test_agent_config_model.py tests/test_tmux_runtime.py -q → 94 passed, 14 subtests passed
  • env -u AI_AGENT PYTHONPATH=skills/bmad-story-automator/src python3 -m pytest -q → 453 passed, 20 subtests passed
  • npm run test:smoke → smoke ok

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Question: can it support custom llm

2 participants