268 lines
7.2 KiB
Markdown
268 lines
7.2 KiB
Markdown
# Agent Development Guide
|
|
|
|
## Development Environment
|
|
|
|
This project uses:
|
|
- **mise** (mise.jdx.dev) - tool version manager and task runner
|
|
- **hk** (hk.jdx.dev) - git hook manager
|
|
- **uv** - fast Python package installer
|
|
- **ruff** - linter and formatter
|
|
- **pytest** - test runner
|
|
|
|
### Setup
|
|
|
|
```bash
|
|
# Install dependencies
|
|
mise run install
|
|
|
|
# Or equivalently:
|
|
uv sync
|
|
```
|
|
|
|
### Available Commands
|
|
|
|
```bash
|
|
# Development
|
|
mise run test # Run tests
|
|
mise run test-v # Run tests verbose
|
|
mise run test-cov # Run tests with coverage report
|
|
mise run lint # Run ruff linter
|
|
mise run lint-fix # Run ruff with auto-fix
|
|
mise run format # Run ruff formatter
|
|
mise run ci # Full CI pipeline
|
|
|
|
# Runtime
|
|
mise run run # Interactive terminal mode (news)
|
|
mise run run-poetry # Interactive terminal mode (poetry)
|
|
mise run run-firehose # Dense headline mode
|
|
|
|
# Daemon mode (recommended for long-running)
|
|
mise run daemon # Start mainline in background
|
|
mise run daemon-stop # Stop daemon
|
|
mise run daemon-restart # Restart daemon
|
|
|
|
# Command & Control
|
|
mise run cmd # Interactive CLI
|
|
mise run cmd "/cmd" # Send single command
|
|
mise run cmd-stats # Watch performance stats
|
|
mise run topics-init # Initialize ntfy topics
|
|
|
|
# Environment
|
|
mise run install # Install dependencies
|
|
mise run sync # Sync dependencies
|
|
mise run sync-all # Sync with all extras
|
|
mise run clean # Clean cache files
|
|
mise run clobber # Aggressive cleanup (git clean -fdx + caches)
|
|
```
|
|
|
|
## Git Hooks
|
|
|
|
**At the start of every agent session**, verify hooks are installed:
|
|
|
|
```bash
|
|
ls -la .git/hooks/pre-commit
|
|
```
|
|
|
|
If hooks are not installed, install them with:
|
|
|
|
```bash
|
|
hk init --mise
|
|
mise run pre-commit
|
|
```
|
|
|
|
The project uses hk configured in `hk.pkl`:
|
|
- **pre-commit**: runs ruff-format and ruff (with auto-fix)
|
|
- **pre-push**: runs ruff check
|
|
|
|
## Workflow Rules
|
|
|
|
### Before Committing
|
|
|
|
1. **Always run the test suite** - never commit code that fails tests:
|
|
```bash
|
|
mise run test
|
|
```
|
|
|
|
2. **Always run the linter**:
|
|
```bash
|
|
mise run lint
|
|
```
|
|
|
|
3. **Fix any lint errors** before committing (or let the pre-commit hook handle it).
|
|
|
|
4. **Review your changes** using `git diff` to understand what will be committed.
|
|
|
|
### On Failing Tests
|
|
|
|
When tests fail, **determine whether it's an out-of-date test or a correctly failing test**:
|
|
|
|
- **Out-of-date test**: The test was written for old behavior that has legitimately changed. Update the test to match the new expected behavior.
|
|
|
|
- **Correctly failing test**: The test correctly identifies a broken contract. Fix the implementation, not the test.
|
|
|
|
**Never** modify a test to make it pass without understanding why it failed.
|
|
|
|
### Code Review
|
|
|
|
Before committing significant changes:
|
|
- Run `git diff` to review all changes
|
|
- Ensure new code follows existing patterns in the codebase
|
|
- Check that type hints are added for new functions
|
|
- Verify that tests exist for new functionality
|
|
|
|
## Testing
|
|
|
|
Tests live in `tests/` and follow the pattern `test_*.py`.
|
|
|
|
Run all tests:
|
|
```bash
|
|
mise run test
|
|
```
|
|
|
|
Run with coverage:
|
|
```bash
|
|
mise run test-cov
|
|
```
|
|
|
|
The project uses pytest with strict marker enforcement. Test configuration is in `pyproject.toml` under `[tool.pytest.ini_options]`.
|
|
|
|
## Architecture Notes
|
|
|
|
- **ntfy.py** and **mic.py** are standalone modules with zero internal dependencies
|
|
- **eventbus.py** provides thread-safe event publishing for decoupled communication
|
|
- **controller.py** coordinates ntfy/mic monitoring
|
|
- The render pipeline: fetch → render → effects → scroll → terminal output
|
|
- **display.py** provides swappable display backends (TerminalDisplay, NullDisplay)
|
|
|
|
## Operating Modes
|
|
|
|
Mainline can run in two modes:
|
|
|
|
### 1. Standalone Mode (Original)
|
|
Run directly as a terminal application with interactive pickers:
|
|
```bash
|
|
mise run run # news stream
|
|
mise run run-poetry # poetry mode
|
|
mise run run-firehose # dense headline mode
|
|
```
|
|
This runs the full interactive experience with font picker and effects picker at startup.
|
|
|
|
### 2. Daemon + Command Mode (Recommended for Long-Running)
|
|
|
|
The recommended approach for persistent displays:
|
|
|
|
```bash
|
|
# Start the daemon (headless rendering)
|
|
mise run daemon
|
|
|
|
# Send commands via ntfy
|
|
mise run cmd "/effects list"
|
|
mise run cmd "/effects noise off"
|
|
mise run cmd "/effects stats"
|
|
|
|
# Watch mode (continuous stats polling)
|
|
mise run cmd-stats
|
|
|
|
# Stop the daemon
|
|
mise run daemon-stop
|
|
```
|
|
|
|
#### How It Works
|
|
|
|
- **Daemon**: Runs `mainline.py` in the background, renders to terminal
|
|
- **C&C Topics**: Uses separate ntfy topics (like UART serial):
|
|
- `klubhaus_terminal_mainline_cc_cmd` - commands TO mainline
|
|
- `klubhaus_terminal_mainline_cc_resp` - responses FROM mainline
|
|
- **Topics are auto-warmed** on first daemon start
|
|
|
|
#### Available Commands
|
|
|
|
```
|
|
/effects list - List all effects and status
|
|
/effects <name> on - Enable an effect
|
|
/effects <name> off - Disable an effect
|
|
/effects <name> intensity 0.5 - Set effect intensity (0.0-1.0)
|
|
/effects reorder noise,fade,glitch,firehose - Reorder pipeline
|
|
/effects stats - Show performance statistics
|
|
```
|
|
|
|
## Effects Plugin System
|
|
|
|
The effects system is implemented as a plugin architecture in `engine/effects/`.
|
|
|
|
### Core Components
|
|
|
|
| Module | Purpose |
|
|
|--------|---------|
|
|
| `effects/types.py` | `EffectConfig`, `EffectContext` dataclasses and `EffectPlugin` protocol |
|
|
| `effects/registry.py` | Plugin discovery and management (`EffectRegistry`) |
|
|
| `effects/chain.py` | Ordered pipeline execution (`EffectChain`) |
|
|
| `effects_plugins/*.py` | Externalized effect plugins |
|
|
|
|
### Creating a New Effect
|
|
|
|
Create a file in `effects_plugins/` with a class ending in `Effect`:
|
|
|
|
```python
|
|
from engine.effects.types import EffectConfig, EffectContext
|
|
|
|
class MyEffect:
|
|
name = "myeffect"
|
|
config = EffectConfig(enabled=True, intensity=1.0)
|
|
|
|
def process(self, buf: list[str], ctx: EffectContext) -> list[str]:
|
|
# Process buffer and return modified buffer
|
|
return buf
|
|
|
|
def configure(self, config: EffectConfig) -> None:
|
|
self.config = config
|
|
```
|
|
|
|
### NTFY Commands
|
|
|
|
Send commands via `cmdline.py` or directly to the C&C topic:
|
|
|
|
```bash
|
|
# Using cmdline tool (recommended)
|
|
mise run cmd "/effects list"
|
|
mise run cmd "/effects noise on"
|
|
mise run cmd "/effects noise intensity 0.5"
|
|
mise run cmd "/effects reorder noise,glitch,fade,firehose"
|
|
|
|
# Or directly via curl
|
|
curl -d "/effects list" https://ntfy.sh/klubhaus_terminal_mainline_cc_cmd
|
|
```
|
|
|
|
The cmdline tool polls the response topic for the daemon's reply.
|
|
|
|
## Conventional Commits
|
|
|
|
Commit messages follow the [Conventional Commits](https://www.conventionalcommits.org/) specification:
|
|
|
|
```
|
|
<type>(<scope>): <description>
|
|
|
|
[optional body]
|
|
|
|
[optional footer(s)]
|
|
```
|
|
|
|
### Types
|
|
|
|
- `feat`: A new feature
|
|
- `fix`: A bug fix
|
|
- `docs`: Documentation only changes
|
|
- `style`: Changes that don't affect code meaning (formatting)
|
|
- `refactor`: Code change that neither fixes a bug nor adds a feature
|
|
- `test`: Adding or updating tests
|
|
- `chore`: Changes to build process, dependencies, etc.
|
|
|
|
### Examples
|
|
|
|
```
|
|
feat(effects): add plugin architecture for visual effects
|
|
fix(layers): resolve glitch effect not applying on empty buffer
|
|
docs(AGENTS.md): add effects plugin system documentation
|
|
test(effects): add tests for EffectChain pipeline ordering
|
|
```
|