# Contributing to Hearth Thanks for your interest! Hearth is alpha and welcoming early contributors. ## Quick orientation | Layer | Files | Tech | |---|---|---| | Frontend | `*.jsx`, `data.js`, `i18n.js`, `index.html`, `styles.css` | React 18, in-browser Babel (no bundler), CSS custom-props | | Backend | `server/api/main.py` | FastAPI + httpx, reads Prometheus + LiteLLM Postgres + direct backend `/metrics` | | Infra | `server/{docker-compose.yml,nginx,prometheus,alertmanager}` | Docker Compose, nginx (host net), Prometheus, Alertmanager | The frontend has **no build step** — files are served as-is and Babel transpiles in the browser. That's a feature for hackability; a build step is a future option (P3) but not a requirement. ## Before you start For **non-trivial changes** (new feature, refactor, breaking change): please open an issue first to discuss. For typo fixes, small bugs, dependency bumps — go straight to a PR. ## Workflow 1. **Fork** the repo, create a branch from `main`: `git checkout -b feat/your-thing` 2. **Code**. Match the surrounding style (it's not strict — pragmatic Apple-product-page aesthetic, light comments explaining *why*, not *what*) 3. **Test manually** — there's no test suite yet. Run the stack locally (`docker compose up` in `server/`), reload the browser, hit the affected endpoints 4. **Commit** following [Conventional Commits](https://www.conventionalcommits.org/): - `feat(api): add llamacpp adapter` - `fix(ui): nav burger active state X transform` - `docs(readme): clarify quickstart` - `chore(deps): bump httpx 0.27 → 0.28` - Sign off your commits: `git commit -s -m "..."` (DCO) 5. **Open a PR** against `main`. Fill out the template. Link any related issue. ## Code style - **Frontend JSX**: per-file scoped style objects (never name them just `styles`). Use `terminalStyles`, `heroStyles`, etc. — different files collide. - **Comments**: explain *why*, not *what*. Code should be self-evident. - **Honesty principle**: if a metric isn't available from a backend, show `—`, not a fake `0`. The contract is "every visible number is real or honestly absent". - **Don't break the data shape**: frontend reads `live.nodes[id]..{now, hist}` and `live.models[id]..{now, hist}`. Both mock and live writers must respect this. ## Adding a metrics-source adapter Until v0.2.0 introduces a formal plugin API, adapters live in `server/api/main.py` as `_scrape_` functions. Pattern: take a base URL, return a dict of normalized fields (`tps`, `ttft`, `tpot`, `kv`, `running`, `waiting`, `p50`, `p95`, `p99`, `resident`). Missing fields → `0` *and* the model's `metrics` label tells the frontend which fields the source actually exposes (so the UI can show `—`). See `_scrape_vllm` and `_scrape_llamacpp` as references. ## Adding a UI language `i18n.js` has dictionaries keyed by English. Add a new language object beside `zh-CN` / `zh-TW`. Use UI placement to test (the lang switcher is in the nav). ## Reporting issues Use the GitHub issue templates. Include: - Hearth version (commit SHA if not tagged) - Your topology (1 node? cluster? what GPUs? what backends?) - What you expected vs what you saw (screenshot if UI) - Steps to reproduce ## Code of Conduct We follow the [Contributor Covenant 2.1](CODE_OF_CONDUCT.md). Be respectful. Disagreements are fine; personal attacks are not. ## License By contributing, you agree your work is licensed under the [MIT License](LICENSE) of this project.