Claude-skill-registry headless-terminal

This skill provides guidance for implementing headless terminal interfaces that programmatically control interactive shell sessions. Use this skill when tasks involve creating terminal emulators, implementing pseudo-terminal (PTY) wrappers, building programmatic shell interfaces, or any scenario requiring automated interaction with command-line programs.

install
source · Clone the upstream repo
git clone https://github.com/majiayu000/claude-skill-registry
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/headless-terminal" ~/.claude/skills/majiayu000-claude-skill-registry-headless-terminal && rm -rf "$T"
manifest: skills/data/headless-terminal/SKILL.md
source content

Headless Terminal

Overview

This skill guides the implementation of headless terminal interfaces—programmatic abstractions that spawn and control interactive shell sessions without a visible terminal window. These implementations enable automated interaction with command-line programs, handling of interactive prompts, and capture of terminal output.

When to Apply This Skill

Apply this skill when:

  • Implementing a class or module that wraps shell/terminal functionality
  • Building programmatic interfaces to interactive CLI programs
  • Creating test harnesses for terminal-based applications
  • Automating interactions with programs that expect TTY input
  • Implementing BaseTerminal or similar abstract interfaces

Implementation Approach

Step 1: Interface Discovery

Before implementing, locate and understand any base interface or abstract class that defines the contract:

  1. Search for abstract base classes or interface definitions (e.g.,
    BaseTerminal
    ,
    TerminalInterface
    )
  2. Identify all required methods and their signatures
  3. Note any expected behaviors documented in docstrings or comments
  4. Check for existing implementations that can serve as reference

Step 2: Library Selection

Choose an appropriate library for PTY interaction. Common options include:

LibraryProsConsBest For
pexpect
Simple API, handles expect patterns, cross-platformHigher-level abstractionMost use cases
pty
+
subprocess
Standard library, fine-grained controlMore complex setupCustom requirements
tmux
/
screen
Session persistence, multiplexingExternal dependencyLong-running sessions

Document the reasoning for the chosen library explicitly.

Step 3: Core Implementation

Implement these essential components:

  1. Shell Spawning: Start an interactive shell with appropriate flags

    • Consider using
      -i
      flag for bash to source startup files
    • Set appropriate terminal dimensions (rows, columns)
    • Configure echo behavior explicitly
  2. Input Methods: Implement keystroke and command sending

    • Handle special characters (Ctrl+C as
      \x03
      , Ctrl+D as
      \x04
      , Ctrl+Z as
      \x1a
      )
    • Consider line endings (
      \n
      vs
      \r\n
      )
    • Implement both raw keystroke and full command methods
  3. Output Reading: Capture terminal output reliably

    • Handle non-blocking reads
    • Manage output buffering
    • Consider timeout behavior
  4. Resource Management: Ensure proper cleanup

    • Implement context manager protocol (
      __enter__
      ,
      __exit__
      )
    • Close file descriptors and terminate processes
    • Prevent zombie processes

Step 4: Verification Strategy

Critical: Always verify implementations are complete and correct.

  1. Post-Write Verification: After writing any file, read it back to confirm:

    • All methods are complete (not truncated mid-definition)
    • All imports are present
    • Syntax is valid
  2. Incremental Testing: Test each component before integration:

    • Shell spawning works
    • Commands execute and return output
    • Special keystrokes are handled
    • Cleanup occurs properly
  3. Assertion Quality: Avoid weak assertions that always pass:

    # BAD - always passes
    assert "expected" in output or True
    
    # GOOD - actually verifies behavior
    assert "expected" in output, f"Expected 'expected' in output, got: {output}"
    
  4. Edge Case Testing: Explicitly test:

    • Empty output handling
    • Long-running commands
    • Commands that produce no output
    • Error conditions (invalid commands)
    • Resource cleanup after errors

Common Pitfalls

Truncated Implementations

Problem: Code gets cut off mid-method, especially in longer files.

Prevention:

  • After writing, use Read tool to verify the complete file
  • Check that all method definitions have complete bodies
  • Verify closing brackets/parentheses match opening ones

Weak Test Assertions

Problem: Tests that cannot fail provide false confidence.

Prevention:

  • Every assertion should be capable of failing
  • Include the actual value in assertion messages
  • Test both positive and negative cases

Missing Error Handling

Problem: Implementations fail silently on edge cases.

Prevention:

  • Test what happens when shell dies unexpectedly
  • Handle timeout scenarios explicitly
  • Verify behavior after close() is called

Resource Leaks

Problem: Zombie processes or unclosed file descriptors.

Prevention:

  • Always implement context manager protocol
  • Test that cleanup occurs even after exceptions
  • Verify no processes remain after test completion:
    import subprocess
    # After cleanup, verify no orphaned processes
    result = subprocess.run(['pgrep', '-f', 'pattern'], capture_output=True)
    assert result.returncode != 0, "Found orphaned processes"
    

Race Conditions

Problem: Timing-dependent behavior causes flaky tests.

Prevention:

  • Avoid arbitrary
    time.sleep()
    calls; use expect patterns when possible
  • Document why specific delays are necessary
  • Use output patterns rather than fixed waits:
    # BAD - arbitrary delay
    time.sleep(0.1)
    
    # GOOD - wait for specific pattern
    terminal.expect(r'\$\s*$', timeout=5)  # Wait for prompt
    

Incomplete Signal Support

Problem: Only testing Ctrl+C while ignoring other signals.

Prevention:

  • Test Ctrl+C (
    \x03
    ) for interrupt
  • Test Ctrl+D (
    \x04
    ) for EOF
  • Test Ctrl+Z (
    \x1a
    ) for suspend
  • Document which signals are supported

Verification Checklist

Before declaring implementation complete:

  • All interface methods are implemented with complete bodies
  • File has been read back to verify no truncation
  • Tests use meaningful assertions that can fail
  • Context manager properly cleans up resources
  • Error conditions are tested
  • Special keystrokes (Ctrl+C, Ctrl+D, Ctrl+Z) are verified
  • No zombie processes remain after cleanup
  • Timeout behavior is documented and tested
  • Encoding handling is explicit

References

For detailed technical documentation on PTY handling and common implementation patterns, see

references/pty_implementation.md
.