Skip to content

[Medium] Stdin Piping Support #23

@marklicata

Description

@marklicata

Summary

Enable piping content to Amplifier CLI via stdin, allowing integration with shell pipelines and scripting workflows.

Current State

Amplifier CLI requires prompts via:

  • Interactive mode (typing)
  • -p flag for non-interactive prompts
  • --resume for continuing sessions

Cannot currently:

  • Pipe content from other commands
  • Read prompts from files via stdin
  • Chain with other CLI tools

Proposed Implementation

1. Basic Stdin Piping

# Pipe file content as context
cat src/main.py | amplifier run -p "review this code"

# Pipe command output
git diff | amplifier run -p "write a commit message for these changes"

# Pipe multiple files
find . -name "*.py" -exec cat {} \; | amplifier run -p "summarize this codebase"

# Pipe from file
amplifier run -p "explain this" < README.md

2. Detection Logic

import sys
import select

def has_stdin_content() -> bool:
    """Check if there's content available on stdin."""
    if sys.stdin.isatty():
        return False
    # On Unix, use select to check for data
    if hasattr(select, 'select'):
        ready, _, _ = select.select([sys.stdin], [], [], 0)
        return bool(ready)
    # On Windows, just try to check if stdin has data
    return not sys.stdin.isatty()

def read_stdin() -> str:
    """Read all content from stdin."""
    return sys.stdin.read()

3. Stdin Content Handling

When stdin has content, prepend it to the prompt:

cat file.py | amplifier run -p "review this"

Becomes internally:

<stdin_content>
[contents of file.py]
</stdin_content>

review this

4. Stdin-Only Mode

Allow prompt to come entirely from stdin:

echo "What is Python?" | amplifier run

# Or from a file
amplifier run < prompt.txt

5. Explicit Stdin Flag

For clarity, add --stdin flag:

# Explicit: read stdin as content
cat file.py | amplifier run --stdin -p "review this"

# Read prompt from stdin (no -p)
echo "explain python decorators" | amplifier run --stdin

6. Combining with Other Flags

# Pipe content + prompt + output format
git diff | amplifier run -p "write commit message" --output-format json

# Pipe content + continue session
cat error.log | amplifier run -p "debug this" --resume abc123

# Pipe content + specific model
cat large_file.py | amplifier run -p "summarize" --model claude-sonnet

7. Output Piping

Already partially exists, but ensure clean output for piping:

# Pipe output to file
amplifier run -p "generate a README" > README.md

# Pipe to clipboard (macOS)
amplifier run -p "write a commit message" | pbcopy

# Chain with other tools
amplifier run -p "list files to refactor as JSON" | jq '.files[]'

8. Implementation

# In commands/run.py

@click.command()
@click.option('-p', '--prompt', help='Prompt to send')
@click.option('--stdin', is_flag=True, help='Read from stdin')
@click.pass_context
def run(ctx, prompt: str | None, stdin: bool):
    """Run a prompt."""
    
    stdin_content = None
    
    # Check for stdin content
    if stdin or has_stdin_content():
        stdin_content = read_stdin()
    
    # Build final prompt
    if stdin_content and prompt:
        # Stdin as context, prompt as instruction
        final_prompt = f"<stdin_content>\n{stdin_content}\n</stdin_content>\n\n{prompt}"
    elif stdin_content:
        # Stdin is the entire prompt
        final_prompt = stdin_content
    elif prompt:
        # Just the prompt flag
        final_prompt = prompt
    else:
        # No input - error or interactive mode
        if sys.stdin.isatty():
            # Launch interactive mode
            return start_interactive(ctx)
        else:
            raise click.UsageError("No prompt provided. Use -p or pipe content.")
    
    # Run the prompt
    result = run_prompt(final_prompt, ctx.obj)
    
    # Output (clean for piping)
    if not sys.stdout.isatty():
        # Piping - clean output only
        click.echo(result.content)
    else:
        # Terminal - rich formatting
        display_result(result)

9. Special Stdin Modes

# Read stdin as file path list
find . -name "*.py" | amplifier run --stdin-files -p "review these files"
# Reads each line as a file path, loads content

# Read stdin as JSON
echo '{"files": ["a.py", "b.py"]}' | amplifier run --stdin-json -p "process this"
# Parses JSON and makes it available as context

10. Configuration

# In amplifier.yaml
stdin:
  enabled: true
  max_size_kb: 1000          # Limit stdin size
  timeout_seconds: 5          # Wait max 5s for stdin
  format: "auto"              # auto | text | json | files

11. CLI Help Update

amplifier run --help

Usage: amplifier run [OPTIONS]

  Run a prompt or start interactive mode.

Options:
  -p, --prompt TEXT      Prompt to send to the AI
  --stdin                Read additional content from stdin
  --stdin-files          Treat stdin lines as file paths to read
  --stdin-json           Parse stdin as JSON context
  -o, --output PATH      Write output to file
  --output-format TEXT   Output format: text, json, markdown
  --resume TEXT          Resume session by ID
  --model TEXT           Model to use
  --help                 Show this message and exit

Examples:
  # Basic prompt
  amplifier run -p "explain Python"
  
  # Pipe file as context
  cat main.py | amplifier run -p "review this code"
  
  # Pipe git diff
  git diff | amplifier run -p "write commit message"
  
  # Output to file
  amplifier run -p "generate README" > README.md

Acceptance Criteria

  • cat file | amplifier run -p "prompt" works
  • Stdin content prepended to prompt with clear delimiter
  • --stdin flag explicitly requests stdin reading
  • Works with --resume for session continuation
  • Works with --output-format for structured output
  • Clean output when stdout is piped (no Rich formatting)
  • Timeout for stdin reading (don't hang forever)
  • Size limit for stdin content
  • Error message when no prompt and no stdin
  • Documentation with examples
  • Unit tests for stdin detection
  • Integration tests for piping workflows

Related

  • Depends on: None
  • Enhances: Scripting, automation, shell integration

Estimated Effort

Low - 3-5 days

Files to Create/Modify

  • src/amplifier_app_cli/commands/run.py (stdin handling)
  • src/amplifier_app_cli/lib/stdin.py (new - stdin utilities)
  • src/amplifier_app_cli/ui/output.py (clean output for piping)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions