Skip to content

feat(cli): add --headless-interactive flag for multi-turn stdin sessions#23367

Closed
GoBeromsu wants to merge 1 commit intogoogle-gemini:mainfrom
GoBeromsu:feat/headless-interactive
Closed

feat(cli): add --headless-interactive flag for multi-turn stdin sessions#23367
GoBeromsu wants to merge 1 commit intogoogle-gemini:mainfrom
GoBeromsu:feat/headless-interactive

Conversation

@GoBeromsu
Copy link
Copy Markdown

Summary

  • Add --headless-interactive CLI flag that enables headless interactive mode for programmatic consumers
  • Reads newline-delimited prompts from stdin, maintains conversation state across turns, outputs to stdout
  • No Ink UI required — works when stdin.isTTY === false

Context

Issue #13924 requests the ability to keep the CLI alive for multi-turn sessions when launched programmatically (e.g., from Java, Node.js, or backend services). Currently, isHeadlessMode() forces non-interactive mode when stdin is not a TTY, which reads all stdin as one prompt and exits.

I investigated existing solutions:

This PR offers a lightweight alternative: a plain-text stdin/stdout interface following the same pattern as nonInteractiveCli.ts. It's complementary to both ACP and the daemon approach — different interface for different use cases.

How to Validate

# Single prompt
echo "what is 2+2?" | gemini --headless-interactive

# Multi-turn session (second prompt references first)
node -e "
const { spawn } = require('child_process');
const child = spawn('npx', ['gemini', '--headless-interactive'], { stdio: ['pipe', 'pipe', 'inherit'] });
child.stdout.on('data', d => console.log(d.toString()));
child.stdin.write('My name is Alice.\n');
setTimeout(() => child.stdin.write('What is my name?\n'), 10000);
setTimeout(() => child.stdin.end(), 20000);
"

# With structured output
echo "hello" | gemini --headless-interactive --output-format stream-json

Changes

File Change
packages/cli/src/config/config.ts Add --headless-interactive flag, CliArgs field, mutual exclusivity checks
packages/cli/src/gemini.tsx Add routing branch after ACP, before interactive mode
packages/cli/src/headlessInteractiveCli.ts New readline-based headless REPL runner

Related Issues

Fixes #13924
Related: #15338, PR #20700

Pre-Merge Checklist

  • Updated relevant documentation and README (if needed)
  • Added/updated tests (if needed)
  • Noted breaking changes (if any)
  • Validated on required platforms/methods:
    • macOS
      • npm run

Add a new `--headless-interactive` flag that enables headless interactive
mode: reads newline-delimited prompts from stdin, maintains conversation
state across prompts, and outputs responses to stdout without the Ink UI.

This addresses the gap described in google-gemini#13924 where programmatic consumers
(Java, Node.js, backend services) cannot maintain multi-turn sessions
because `stdin.isTTY === false` forces non-interactive single-prompt mode.

While ACP mode (`--acp`) technically provides headless interactive
capabilities, it requires ndJSON protocol handshake and SDK dependency.
This flag offers a simpler plain-text stdin/stdout interface for shell
pipeline use cases.

Changes:
- Add `--headless-interactive` CLI flag with mutual exclusivity checks
- Add routing branch in main() between ACP and interactive mode
- Create `headlessInteractiveCli.ts` with readline-based REPL runner

Fixes google-gemini#13924
@gemini-cli gemini-cli Bot added priority/p2 Important but can be addressed in a future release. area/non-interactive Issues related to GitHub Actions, SDK, 3P Integrations, Shell Scripting, Command line automation help wanted We will accept PRs from all issues marked as "help wanted". Thanks for your support! labels Mar 21, 2026
@GoBeromsu
Copy link
Copy Markdown
Author

Closing draft — need to address review findings before resubmitting.

@GoBeromsu GoBeromsu closed this Mar 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/non-interactive Issues related to GitHub Actions, SDK, 3P Integrations, Shell Scripting, Command line automation help wanted We will accept PRs from all issues marked as "help wanted". Thanks for your support! priority/p2 Important but can be addressed in a future release.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Allow interactive mode to stay alive even when process.stdin.isTTY is false

1 participant