Thanks for your interest in contributing. This document covers the process for contributing to Homerun and how to get your development environment set up.
- Fork the repository
- Clone your fork:
git clone https://github.com/your-username/homerun.git cd homerun - Set up your development environment:
./scripts/infra/setup.sh ./scripts/infra/run.sh
- Create a feature branch:
git checkout -b your-feature-name
- Python 3.10+
- Node.js 18+
cd backend
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt
pip install ruff pytest # dev tools
uvicorn main:app --reload --port 8000cd frontend
npm install
npm run devcd backend
pytest tests/
pytest tests/ -v # verbose output- Linter/Formatter: Ruff — enforced in CI
- Run before committing:
ruff check backend/ ruff format backend/
- Follow existing code patterns and conventions
- Use type hints for function signatures
- Use async/await for all I/O operations
- Type checking:
tsc --noEmit— enforced in CI - Run before committing:
cd frontend npx tsc --noEmit - Use TypeScript strict mode
- Define types for API responses in
services/api.ts
Strategies are stored in the database (strategies table), not as Python
files in this repo. The .py files under backend/services/strategies/
are system (built-in) strategies that ship with the platform and are
seeded into the DB at migration time — end users never edit them
directly.
- Open the Strategies screen in the UI and click New Strategy.
- Start from
GET /strategies/template(the form prefills it). The endpoint also returns curated examples — including a multi-timeframe Compound Movement example demonstratingStrategySDK.MultiWindow,on_timeframe_close(), andStrategySDK.PersistentState. - Extend
BaseStrategyfromservices.strategies.baseand implementdetect()(ordetect_async()for I/O-bound work). Optionally overrideevaluate()andshould_exit(). - Save. The backend AST-validates the source (no
os/subprocess/eval/ arbitrary imports) and persists it into thestrategiestable.StrategyLoadercompiles and hot-reloads it without a restart. GET /strategies/docsis the live, machine-readable reference forBaseStrategy, theStrategySDKsurface, hooks, and config schema.
API equivalents (CLI / scripting): POST /strategies/validate for a
pre-flight check, POST /strategies to create, PUT /strategies/{id}
to edit, POST /strategies/{id}/reload to force a hot-reload.
- Add a new file in
backend/services/strategies/extendingBaseStrategy. - Register a seed entry in
backend/services/opportunity_strategy_catalog.py(SYSTEM_OPPORTUNITY_STRATEGY_SEEDS) — slug, source_key, import path, config schema. The catalog converts seeds intoStrategyrows on migration. - Add tests in
backend/tests/.
System strategies are loaded the same way as user strategies (through
the strategies table); the only difference is that system rows have
is_system=True and are seeded from this repo at migration time.
- Create or update a route file in
backend/api/ - Register the router in
backend/main.py - Add TypeScript types in
frontend/src/services/api.tsif consumed by the frontend
- Create the component in
frontend/src/components/ - Follow existing patterns (React Query for data fetching, TailwindCSS for styling)
- Wire it into
App.tsxor the relevant parent component
- Ensure your code passes CI:
ruff check backend/(no lint errors)ruff format --check backend/(properly formatted)npx tsc --noEmitinfrontend/(no type errors)npm run buildinfrontend/(builds successfully)
- Write a clear PR description explaining what changed and why
- Keep PRs focused — one feature or fix per PR
- Update the README if your change affects setup, configuration, or public APIs
Open an issue with:
- Steps to reproduce
- Expected behavior
- Actual behavior
- Python/Node versions and OS
Open an issue with:
- The problem you're trying to solve
- Your proposed solution
- Any alternatives you've considered
Open a discussion or issue — happy to help.