This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Solo for Laravel is a developer tool package that runs multiple development commands simultaneously in a tabbed terminal interface. It enables developers to consolidate all local development processes (Vite, logs, queues, tests, etc.) into a single php artisan solo command.
Key Characteristics:
- Laravel package (requires Laravel 10-12, PHP 8.2+)
- Unix-only (requires ext-pcntl and ext-posix)
- Uses GNU Screen as an intermediary for PTY and ANSI handling
- Built on Laravel Prompts and Chewie for TUI rendering
- Configuration-driven command setup via
config/solo.php
# Run all tests
./vendor/bin/phpunit
# Run specific test suite
./vendor/bin/phpunit --testsuite=unit
./vendor/bin/phpunit --testsuite=integration
# Run single test file
./vendor/bin/phpunit tests/Unit/AnsiAwareTest.php
# Run single test method
./vendor/bin/phpunit --filter testMethodName
# Run the demo (requires testbench)
composer dev
# or: ./vendor/bin/testbench solo
# Install dependencies
composer installSince this is a Laravel package (not an application), it uses Orchestra Testbench for testing. Tests are in the tests/ directory with two suites:
tests/Unit/- Unit tests for individual componentstests/Integration/- Integration tests for full features
Solo uses a render loop pattern where the main Dashboard continuously:
- Collects output from all running processes (via process output callbacks)
- Renders the current state to the terminal
- Handles keyboard input
- Updates process states
- Repeats at ~40 FPS (25ms intervals)
php artisan solo
↓
Console\Commands\Solo
↓
Prompt\Dashboard (extends Laravel Prompt)
├── Manages Command[] array
├── Runs event loop (Loops trait from Chewie)
└── Handles keyboard input via KeyPressListener
↓
Commands\Command (implements Loopable)
├── ManagesProcess trait - process lifecycle
├── Screen (from soloterm/screen) - virtual terminal
└── onTick() - called each loop iteration
Manager (src/Manager.php)
- Singleton service registered in SoloServiceProvider
- Loads commands from config
- Manages themes and hotkeys
- Central configuration point
Dashboard (src/Prompt/Dashboard.php)
- Main TUI controller extending Laravel Prompt
- Owns the event loop via Chewie's Loops trait
- Manages tab switching and keyboard routing
- Coordinates rendering and input handling
- Handles terminal resize events (SIGWINCH)
Command (src/Commands/Command.php)
- Base class for all runnable commands
- Implements Loopable interface (onTick method)
- Uses ManagesProcess trait for process lifecycle
- Maintains a virtual Screen for output buffering
- Supports two modes: MODE_PASSIVE (read-only) and MODE_INTERACTIVE (input forwarded)
- Can be created from strings, custom classes, or via Command::from() static constructor
ManagesProcess (src/Commands/Concerns/ManagesProcess.php)
- Critical trait handling subprocess lifecycle
- Wraps user commands in GNU Screen for PTY emulation
- Manages incremental output collection without blocking
- Handles graceful shutdown (SIGTERM) and force kill (SIGKILL)
- Uses ProcessTracker to kill child processes on exit
Hotkeys & KeyHandler
Hotkeys\DefaultHotkeys.phpandHotkeys\VimHotkeys.phpdefine keybindingsHotkeys\KeyHandler.phpis an enum mapping actions to closures- Hotkeys are dynamically bound based on current tab and command state
- Each Command can define custom hotkeys() method for command-specific keys
Solo wraps user commands in GNU Screen to solve PTY and ANSI rendering challenges:
bash -c 'export LC_ALL=en_US.UTF-8 && stty cols 120 rows 40 && screen -U -q sh -c "printf MARKER; user-command; sleep 0.25; printf MARKER"'This provides:
- Proper PTY allocation for interactive programs
- ANSI code handling via Screen's terminal emulation
- Output markers to filter Screen's own output
- Small delay before exit to capture all output
Commands write output to a soloterm/screen Screen object, which is a virtual terminal buffer that:
- Handles ANSI codes (colors, cursor movement, etc.)
- Wraps lines to terminal width
- Maintains a buffer of printable output
- Supports querying (for responsive applications)
Recent optimization uses DiffRenderer (src/Support/DiffRenderer.php) to:
- Compare previous and current screen states
- Generate minimal ANSI sequences to update only changed cells
- Reduce terminal I/O for performance
config/solo.phpdefines commands array- Manager->loadCommands() reads config
- Manager->addCommand() converts strings/objects to Command instances
- Dashboard constructor calls ->setDimensions() and ->autostart() on each
- Commands marked ->lazy() skip autostart
Commands can be marked as "lazy" to prevent automatic startup:
'Queue' => Command::from('php artisan queue:work')->lazy()User must manually start them with 's' key.
Solo requires GNU Screen >= 5.0.0. The solo command checks version on startup and logs warnings if outdated.
- Autostart: Command starts when Dashboard initializes
- Running: Process is active, output being collected
- Stopping: Stop initiated, waiting for graceful shutdown (5 second timeout)
- Stopped: Process exited
- Force Killing: Timeout exceeded, sending SIGKILL
When quitting Solo (q or Ctrl+C):
- Dashboard->quit() calls ->stop() on all commands
- Commands send SIGTERM to child processes (excluding Screen wrapper)
- Loop continues for up to 3 seconds waiting for processes to die
- ProcessTracker cleans up any remaining children
- Monitor command (separate process) ensures cleanup even if Solo crashes
Commands marked ->interactive() can enter MODE_INTERACTIVE:
- Press 'i' to enter (if command supports it)
- All keyboard input forwarded directly to process
- Only Ctrl+X exits interactive mode
- Process keeps running after exiting interactive mode
- Theme interface defines colors and styling
- Ships with LightTheme and DarkTheme
- Renderer class (extends Laravel Prompts Renderer) generates the frame
- Frame includes: tabs, process status, output pane, hotkeys
Manager uses HasEvents trait for internal events:
- Event::ActivateTab - programmatically switch tabs
- Events dispatched via Solo facade
soloterm/screen- Virtual terminal implementationsoloterm/grapheme- Grapheme cluster handling for Unicodesoloterm/dumps- Dump server integrationjoetannenbaum/chewie- TUI loop and rendering primitiveslaravel/prompts- Base prompt system
- Unit tests focus on isolated components (ANSI parsing, wrapping, byte handling)
- Integration tests test full command behavior
- Tests use Orchestra Testbench to simulate Laravel environment
- Many tests verify complex ANSI code handling and multibyte character support