Development Guide¶
This guide covers setting up Zorac for development, testing, and contributing.
Development Setup¶
Prerequisites¶
- Python 3.13+
uvpackage manager- Git
Quick Setup¶
# Clone the repository
git clone https://github.com/chris-colinsky/zorac.git
cd zorac
# Complete development setup (installs deps + pre-commit hooks)
make dev-setup
# Or manually:
uv sync --extra dev
cp .env.example .env
# Edit .env to set your vLLM server URL
Project Structure¶
zorac/
├── zorac/ # Main package
│ ├── __init__.py # Package exports
│ ├── __main__.py # Module entry point
│ ├── commands.py # Command registry
│ ├── config.py # Configuration management
│ ├── console.py # Rich console singleton
│ ├── llm.py # LLM operations
│ ├── main.py # Main event loop
│ ├── markdown_custom.py # Custom markdown renderer
│ ├── session.py # Session persistence
│ └── utils.py # Utility functions
├── tests/ # Test suite
│ ├── __init__.py
│ ├── test_commands.py # Command registry tests (NEW)
│ └── test_zorac.py # Comprehensive tests
├── requirements/ # Requirements documents (NEW)
│ └── help_feature.md # Help feature requirements
├── docs/ # Documentation
│ ├── INSTALLATION.md
│ ├── CONFIGURATION.md
│ ├── USAGE.md
│ ├── DEVELOPMENT.md # This file
│ ├── SERVER_SETUP.md # vLLM server guide
│ └── TEST_TRAINING.md # Multi-GPU training guide (NEW)
├── .github/workflows/ # CI/CD
│ └── release.yml # Release automation
├── pyproject.toml # Dependencies and metadata
├── uv.lock # Dependency lock file
├── .env.example # Configuration template
├── README.md # Project overview
├── CLAUDE.md # AI assistant guide
├── CHANGELOG.md # Version history
├── CONTRIBUTING.md # Contribution guidelines
├── Makefile # Development commands
└── LICENSE # MIT License
Running Tests¶
Basic Testing¶
# Run all tests
make test
# Run with coverage report (generates HTML report)
make test-coverage
# View coverage report
open htmlcov/index.html
Test Coverage¶
Current coverage: 42% with 34 passing tests
The test suite covers: - Token counting with various message types - Session management (save/load, error handling) - UI header rendering - Message summarization logic - Configuration validation - Command registry structure and validation - Help system (display and LLM awareness) - Integration workflows (save/load roundtrips, help feature)
Module coverage:
- zorac/commands.py: 100% coverage
- zorac/session.py: 100% coverage
- zorac/console.py: 100% coverage
- zorac/llm.py: 96% coverage
- zorac/markdown_custom.py: 45% coverage (UI rendering, mostly tested via integration)
Coverage targets: - Minimum 80% code coverage - All core functions tested - Edge cases and error paths covered
Code Quality¶
Linting¶
Formatting¶
Type Checking¶
All Checks¶
Pre-commit Hooks¶
Zorac uses pre-commit hooks for automated quality checks:
# Install pre-commit hooks
make pre-commit-install
# Run pre-commit on all files
make pre-commit
# Pre-commit will automatically run on git commit
Dependencies¶
Production Dependencies¶
- openai (>=2.8.1): Client library for vLLM's OpenAI-compatible API
- tiktoken (>=0.8.0): Token counting for accurate usage tracking
- python-dotenv (>=1.0.0): Environment variable management from .env files
- rich (>=14.2.0): Rich terminal formatting, markdown rendering, and live updates
- textual (>=1.0.0): Modern TUI framework for the full terminal user interface
Development Dependencies¶
- pytest (>=8.0.0): Testing framework
- pytest-cov (>=4.1.0): Coverage reporting for pytest
- pytest-mock (>=3.12.0): Mock fixtures for pytest
- ruff (>=0.8.0): Fast Python linter and formatter
- mypy (>=1.8.0): Static type checker
- pre-commit (>=3.6.0): Git hook management
Architecture Overview¶
Module Breakdown¶
zorac/commands.py - Command Registry (NEW)
- Centralized registry of all interactive commands
- COMMANDS: List of command definitions with descriptions
- get_help_text(): Generates formatted help for /help display
- get_system_prompt_commands(): Provides command info to LLM via system prompt
- Single source of truth for command documentation
- Enables LLM awareness of Zorac's capabilities
zorac/config.py - Configuration Management
- Three-tier priority: Environment Variables > Config File > Defaults
- Type-safe getters: get_int_setting(), get_float_setting(), get_bool_setting()
- Runtime configuration via /config command
- Persistent storage in ~/.zorac/config.json
zorac/console.py - Rich Console Singleton - Single Rich console instance for consistent formatting - Used across all modules for output
zorac/llm.py - LLM Operations
- summarize_old_messages(): Auto-summarization with status spinner
- Handles API calls to vLLM server
- Token limit management
zorac/markdown_custom.py - Custom Markdown Renderer
- LeftAlignedMarkdown: Custom markdown renderer with left-aligned headings
- Monkey-patches Rich's Heading.__rich_console__ to remove centered heading panels
- Provides cleaner, more readable terminal output
- Maintains Rich styling (bold, colored) while forcing left justification
zorac/main.py - Textual TUI application with chat log, stats bar, and input widgets
- get_initial_system_message(): Generates enhanced system prompt with command info
- Textual Input widget with SuggestFromList for slash command autocomplete
- Real-time streaming via Markdown.get_stream() with persistent stats bar
- Streaming and non-streaming response modes
- Session auto-save after each response
- Stats bar widget (Static#stats-bar) docked to bottom for always-visible metrics
zorac/session.py - Session Persistence
- save_session(): Saves conversation to JSON
- load_session(): Restores conversation from disk
- Error handling for invalid sessions
zorac/utils.py - Utility Functions
- count_tokens(): Uses tiktoken to count tokens in conversation
- print_header(): Displays formatted welcome header
- check_connection(): Verifies vLLM server connectivity
Adding Features¶
New Commands¶
When adding a new command, follow these steps to ensure consistency:
- Add to Command Registry (
zorac/commands.py):
{
"command": "/mycommand",
"description": "Short one-line description for /help",
"detailed": "Detailed explanation for the LLM system prompt. Describe what the command does and when to use it."
}
- Implement Command Handler in
zorac/main.py:
if user_input.lower() == "/mycommand":
# Your command logic here
console.print("[green]Command executed![/green]")
continue
-
Add Tests in
tests/test_commands.pyortests/test_zorac.py -
Update Documentation:
- Add to command list in
docs/USAGE.md - Update
CLAUDE.mdif architecture changes - Update
README.mdif user-facing
Why use the command registry?
- Single source of truth for all commands
- /help command automatically displays your new command
- LLM automatically knows about your command and can suggest it to users
- Ensures consistency across documentation
New Configuration Settings¶
- Add default to
DEFAULT_CONFIGinzorac/config.py - Load it in
main()using appropriate getter - Use it in your code
- Update documentation
Custom Token Limits¶
Modify via .env file or /config command:
UI Customization¶
Panel Formatting:
Modify panel styling in zorac/main.py:
console.print(Panel(
content,
box=box.ROUNDED,
style="cyan",
expand=True # Full width for left-aligned content
))
Custom Markdown Rendering:
Modify heading styles in zorac/markdown_custom.py:
def _left_aligned_heading_rich_console(self, console, options):
if self.tag == "h1":
yield Text(text.plain, style="bold #ffffff") # Customize H1 style
elif self.tag == "h2":
yield Text(text.plain, style="bold #cccccc") # Customize H2 style
Design Principles:
- Full-width output for assistant responses
- Left-align all content to match "Assistant:" label
- Use Markdown.get_stream() during streaming for real-time content updates
- Static#stats-bar displays real-time metrics during streaming
- Stats bar updates in real-time during streaming, persists after response
- Stats persist in bottom toolbar between interactions
Feature Requirements¶
The requirements/ directory contains detailed specifications for features. When adding significant new functionality:
- Create a requirements document:
requirements/feature_name.md - Include these sections:
- Overview and user stories
- Functional requirements
- Technical design
- Implementation plan
- Testing strategy
- Documentation updates
- Acceptance criteria
Example: See requirements/help_feature.md for a comprehensive example of a feature specification.
Benefits: - Clear specification before implementation - Easier code review - Better documentation - Prevents scope creep
Publishing Releases¶
Zorac is distributed via PyPI and Homebrew. Releases are automated via GitHub Actions.
Distribution Channels¶
- PyPI:
pip install zorac/pipx install zorac - Homebrew:
brew tap chris-colinsky/zorac && brew install zorac
Semantic Versioning¶
- MAJOR (X.0.0): Breaking changes, incompatible API changes
- MINOR (x.Y.0): New features, backward compatible
- PATCH (x.y.Z): Bug fixes, documentation updates only
Release Process¶
1. Prepare the Release¶
# Create a release branch from main
git checkout main
git pull origin main
git checkout -b release/vX.Y.Z
# Update version in pyproject.toml
# Update CHANGELOG.md with release notes
# Run all quality checks
make all-checks
# Commit changes
git add .
git commit -m "Prepare release vX.Y.Z"
git push origin release/vX.Y.Z
2. Create PR and Merge¶
# Create a pull request to main
gh pr create --base main --head release/vX.Y.Z --title "Release vX.Y.Z"
# After PR is approved and CI passes, merge via GitHub UI
3. Tag and Release¶
# Switch to main and pull the merged changes
git switch main
git pull
# Create and push an annotated tag
git tag -a vX.Y.Z -m "Release version X.Y.Z"
git push origin vX.Y.Z
# Clean up release branch
git branch -d release/vX.Y.Z
4. Automated Pipeline¶
When you push the tag, GitHub Actions automatically:
- Runs tests - Ensures all tests pass
- Builds package - Creates wheel and sdist
- Publishes to PyPI - Via Trusted Publisher (OIDC)
- Creates GitHub Release - With package artifacts
- Updates Homebrew formula - Automatically updates
chris-colinsky/homebrew-zoracwith the new version, URL, and SHA256
Monitor the release: - Visit: https://github.com/chris-colinsky/zorac/actions - Look for "Release" workflow - Verify PyPI publish and Homebrew update succeed
Note: The Homebrew update requires a HOMEBREW_TAP_TOKEN secret (a GitHub PAT with write access to chris-colinsky/homebrew-zorac).
5. Verify Release¶
- Check PyPI: https://pypi.org/project/zorac/
- Check GitHub Release: https://github.com/chris-colinsky/zorac/releases/tag/vX.Y.Z
- Test installation:
- Test Homebrew (after formula update):
Release Checklist¶
Before creating a release:
- [ ] All tests pass:
make test - [ ] Code is linted:
make lint - [ ] Type checking passes:
make type-check - [ ] Version updated in
pyproject.toml - [ ] CHANGELOG.md updated with release notes
- [ ] All PRs for this release are merged
- [ ] Documentation is up to date
After release:
- [ ] PyPI page shows correct version
- [ ]
pip install zoracworks - [ ] GitHub Release created with artifacts
- [ ] Homebrew formula updated (automatic)
Quick Reference¶
# Complete release workflow
git checkout main && git pull
git checkout -b release/vX.Y.Z
# Update pyproject.toml version and CHANGELOG.md
make all-checks
git add . && git commit -m "Prepare release vX.Y.Z"
git push origin release/vX.Y.Z
gh pr create --base main --head release/vX.Y.Z --title "Release vX.Y.Z"
# Merge PR via GitHub UI
git switch main && git pull
git tag -a vX.Y.Z -m "Release version X.Y.Z"
git push origin vX.Y.Z
git branch -d release/vX.Y.Z
# Homebrew formula updates automatically after PyPI publish
Hotfix Releases¶
For urgent bug fixes:
git checkout main && git pull
git checkout -b hotfix/vX.Y.Z
# Fix the bug, then follow the same release process
# Use PATCH version bump (e.g., 1.1.0 -> 1.1.1)
Manual Publishing (Emergency)¶
If automated publishing fails:
LLM Command Awareness¶
Zorac includes an innovative feature where the LLM assistant running inside the chat client is aware of Zorac's own commands and capabilities.
How It Works¶
- Command Registry (
zorac/commands.py): - Centralized list of all commands with detailed descriptions
-
Single source of truth for command information
-
Enhanced System Prompt (
zorac/main.py): get_initial_system_message()injects command information into the system prompt-
LLM receives command details at session start
-
Natural Language Queries:
- Users can ask: "How do I save my session?"
- LLM responds with relevant command information
- LLM suggests appropriate commands based on user needs
Token Overhead¶
The enhanced system prompt adds ~400-450 tokens to each session. This is acceptable because: - Default context limit is 12,000 tokens - Overhead is <4% of available context - Users benefit from having an assistant that knows how to use the tool
Testing Command Awareness¶
See tests/test_zorac.py::TestHelpFeatureIntegration for tests that verify:
- System message includes all commands
- Token overhead is reasonable
- Help text is properly formatted
AI-Friendly Documentation¶
This project includes CLAUDE.md, a comprehensive development guide designed to help AI coding assistants understand the project.
What it contains: - Detailed project structure and file purposes - Architecture overview and design decisions - Configuration documentation - Development workflows and commands - Dependencies and their usage
Why it's useful: AI-powered development tools can use this file to provide better suggestions and write code that matches project conventions.
Contribution Guidelines¶
See CONTRIBUTING.md for detailed contribution guidelines.
Quick Checklist¶
Before submitting a PR:
- [ ] All tests pass:
make test - [ ] Code is linted:
make lint - [ ] Code is formatted:
make format - [ ] Type checking passes:
make type-check - [ ] Documentation is updated (README, USAGE, CLAUDE.md as needed)
- [ ] New commands added to command registry (
zorac/commands.py) - [ ] Requirements document created for significant features (
requirements/) - [ ] CHANGELOG.md is updated
- [ ] Commit messages are clear and descriptive
Troubleshooting Development¶
Virtual Environment Issues¶
Test Failures¶
# Run tests with verbose output
uv run pytest -vv
# Run specific test
uv run pytest tests/test_zorac.py::TestCountTokens -vv
Import Errors¶
Command Registry Issues¶
If commands aren't showing up in /help or the LLM doesn't know about them:
# Verify command is in the registry
python -c "from zorac.commands import COMMANDS; print([c['command'] for c in COMMANDS])"
# Test help text generation
python -c "from zorac.commands import get_help_text; print(get_help_text())"
# Test system prompt generation
python -c "from zorac.commands import get_system_prompt_commands; print(get_system_prompt_commands())"
Resources¶
- vLLM Documentation - vLLM inference server
- Rich Documentation - Terminal UI library
- OpenAI API Reference - API compatibility
- tiktoken - Token counting library
- Textual - Modern TUI framework
Support¶
For questions or issues:
1. Check existing GitHub Issues
2. Review documentation in docs/ directory
3. Open a new issue with details
License¶
MIT License - see LICENSE for details.