| name | gemini-sub-agent |
| description | Launch Gemini CLI as a headless sub-agent in a tmux pane, monitor its stream-json JSONL output, and poll for completion. Use when delegating a well-defined task to a Gemini agent subprocess with live observability. Triggers include "run gemini agent", "delegate to gemini", "gemini sub-agent", or any request to run gemini headlessly and monitor it. |
Gemini Sub-Agent Skill
Launch gemini as a headless sub-agent in a tmux pane with live JSONL monitoring. Depends on the tmux skill for pane interaction.
When to use
- Delegating a scoped task to Gemini CLI running autonomously
- Parallel execution alongside other sub-agents (copilot-sub-agent, claude-sub-agent, pi-sub-agent)
- Tasks where Gemini's explicit exit codes (41–53) are useful for error handling in scripts
Output format
Gemini streams newline-delimited JSON via --output-format stream-json. Key event types:
init — startup, contains session_id, model
message with role: user — echoes the prompt
message with role: assistant, delta: true — streaming text chunks
result — final line, contains status, stats (tokens, duration_ms, tool_calls)
Completion signal: "type":"result" line in the stream.
{"type":"result","status":"success","stats":{"total_tokens":11386,"input_tokens":10774,"output_tokens":71,"cached":6250,"duration_ms":5815,"tool_calls":0}}
Exit codes (unique to Gemini — use these in scripts):
0 — success
41 — authentication error
42 — invalid input
44 — sandbox error
52 — configuration error
53 — turn limit exceeded
Non-interactive invocation
Lean / headless invocation
cat /tmp/task-prompt.md | gemini \
--yolo \
--output-format stream-json \
--model flash \
> /tmp/gemini-output.jsonl 2>&1
What each flag does:
| Flag | Why |
|---|
--yolo | Auto-approve all tool calls — required for headless |
--output-format stream-json | JSONL stream for monitoring; completion signalled by "type":"result" line |
--model flash | Use flash (fast) instead of auto or pro — significantly faster for agentic tasks |
Gemini's startup footprint is controlled by what's in ~/.gemini/settings.json and GEMINI.md. There is no flag to suppress MCP loading — configure allowed-mcp-server-names with an empty list if you need to exclude all MCP servers:
cat /tmp/task-prompt.md | gemini \
--yolo \
--output-format stream-json \
--model flash \
--allowed-mcp-server-names "" \
> /tmp/gemini-output.jsonl 2>&1
Gemini's baseline system prompt is ~10–11k tokens and is cached by default on warm runs. There are no flags to reduce this further — the lean knob is model selection (flash vs pro) and avoiding GEMINI.md bloat when injecting personas.
Other useful flags:
--model flash-lite — fastest/cheapest option
--temperature 0 — deterministic output for automation
--timeout <ms> — execution timeout in milliseconds
--include-directories /path — add workspace directories
Workflow
1. Write the task prompt to a file
cat > /tmp/task-prompt.md << 'EOF'
Your task description here.
EOF
2. Identify a free tmux pane
bash {SKILLS_DIR}/tmux-remote-control/scripts/tmux-list.sh
3. Launch gemini + monitor in the pane
TARGET="{session}:{window}.{pane}"
tmux send-keys -t "$TARGET" \
"cd /path/to/repo && cat /tmp/task-prompt.md | gemini --yolo --output-format stream-json > /tmp/gemini-output.jsonl 2>&1 &" Enter
sleep 3
tmux send-keys -t "$TARGET" \
"python3 {SKILLS_DIR}/gemini-sub-agent/scripts/monitor.py /tmp/gemini-output.jsonl" Enter
4. Poll for completion
python3 {SKILLS_DIR}/gemini-sub-agent/scripts/poll.py "$TARGET" --interval 30
5. Check exit code and verify
tmux send-keys -t "$TARGET" C-c
python3 -c "
import json
for line in open('/tmp/gemini-output.jsonl'):
d = json.loads(line.strip())
if d.get('type') == 'result':
print('Status:', d['status'])
print('Stats:', json.dumps(d['stats'], indent=2))
"
git log --oneline -5
Full copy-paste pattern
cat > /tmp/task-prompt.md << 'EOF'
Your task here.
EOF
TARGET="{session}:{window}.{pane}"
tmux send-keys -t "$TARGET" \
"cd /path/to/repo && cat /tmp/task-prompt.md | gemini --yolo --output-format stream-json --model flash > /tmp/gemini-output.jsonl 2>&1 &" Enter
sleep 3
tmux send-keys -t "$TARGET" \
"python3 {SKILLS_DIR}/gemini-sub-agent/scripts/monitor.py /tmp/gemini-output.jsonl" Enter
python3 {SKILLS_DIR}/gemini-sub-agent/scripts/poll.py "$TARGET" --interval 30
tmux send-keys -t "$TARGET" C-c
git log --oneline -5
Agent / persona injection
Gemini has no --system-prompt CLI flag. Persona injection works via GEMINI.md in the current working directory — Gemini automatically loads it as system context before any prompt.
cat {SKILLS_DIR}/bart-adversarial-reviewer/references/bart.md > /path/to/repo/GEMINI.md
cd /path/to/repo
cat /tmp/task.md | gemini --yolo --output-format stream-json > /tmp/gemini-output.jsonl 2>&1
rm /path/to/repo/GEMINI.md
The GEMINI.md file is a plain markdown system prompt — no frontmatter required. Gemini loads it from $CWD/GEMINI.md (also checks ~/.gemini/GEMINI.md as a user-level default).
For headless sub-agent use, write the persona before launching:
cat > /path/to/repo/GEMINI.md << 'EOF'
You are Bart Simpson, adversarial reviewer. Find bugs. Be snarky.
EOF
tmux send-keys -t "$TARGET" \
"cd /path/to/repo && cat /tmp/task-prompt.md | gemini --yolo --output-format stream-json > /tmp/gemini-output.jsonl 2>&1 &" Enter
Model selection
gemini "task" --model flash-lite --yolo
gemini "task" --model flash --yolo
gemini "task" --model pro --yolo
Script integration (using exit codes)
cat /tmp/task-prompt.md | gemini --yolo --output-format stream-json > /tmp/out.jsonl 2>&1
case $? in
0) echo "Success" ;;
41) echo "Auth error — check GEMINI_API_KEY" ; exit 1 ;;
42) echo "Invalid input" ; exit 1 ;;
52) echo "Config error" ; exit 1 ;;
53) echo "Turn limit exceeded" ; exit 1 ;;
*) echo "Unknown error $?" ; exit 1 ;;
esac
Troubleshooting
Prompt truncated by shell: Use cat /tmp/file | gemini ... (stdin pipe) for long prompts.
Stuck with no result line: Check if --yolo is set; without it, Gemini pauses for tool approval.
tool_calls: 0 but task needed tools: Gemini may need --approval-mode yolo explicitly if --yolo alone doesn't propagate.
Parse the result stats:
grep '"type":"result"' /tmp/gemini-output.jsonl | python3 -c "import json,sys; d=json.loads(sys.stdin.read()); print(json.dumps(d['stats'], indent=2))"