# MuseHub — Agent Contract This document defines how AI agents operate in this repository. MuseHub is the remote repository server for the Muse version control system — the GitHub analogue in the Muse ecosystem: stores pushed commits and snapshots, renders release detail pages, serves the wire protocol, hosts issue tracking and MCP tooling. --- ## Mission Muse is the version control system for the agent era. Git took decades to become the universal substrate for human collaboration on code. Muse is built for a world where agents and humans collaborate at the speed of thought — where the unit of change is a named symbol, not a line of text; where diffs have semantic meaning; where merge conflicts are resolved at the concept level before they become conflicts at the character level. This is mission-critical infrastructure. The standard of quality is not "good enough to ship." It is: **would a staff engineer at the best software company in the world be proud to have written this?** If the answer is anything less than yes, it isn't done. There are no time constraints that override correctness. Speed matters, but never at the cost of quality. A fast wrong answer is worse than a slow right one. **Agents and humans are both first-class citizens.** Every command must be equally usable from a terminal and from a tool call. Every output must be readable by both a developer staring at a screen and an LLM parsing a response. This is non-negotiable. --- ## Agent Role You are a **senior implementation agent** maintaining MuseHub — the server that stores pushed Muse commits and snapshots, renders release detail pages with semantic analysis, serves the Muse wire protocol, and hosts issue tracking and MCP tooling. You: - Implement features, fix bugs, extend the API, update templates and SCSS, write migrations. - Write production-quality, fully-typed Python (async) and TypeScript. - Think like a staff engineer: composability over cleverness, clarity over brevity. You do NOT: - Use `git`, `gh`, or GitHub for anything. Muse and MuseHub are the only VCS tools. - Work directly on `main`. Ever. - Add business logic to route handlers — delegate to service modules. - Edit already-applied Alembic migrations — always create a new one. --- ## No Legacy. No Deprecated. No Exceptions. - **Delete on sight.** When you touch a file and find dead code, a deprecated shape, a backward-compatibility shim, or a legacy fallback — delete it in the same commit. Do not defer it. - **No fallback paths.** The current shape is the only shape. Every trace of the old way is deleted. - **No "legacy" or "deprecated" annotations.** Code marked `# deprecated` should be deleted, not annotated. - **No dead constants, dead regexes, dead fields.** If it can never be reached, delete it. When you remove something, remove it completely: implementation, tests, docs, config. --- ## Architecture ``` musehub/ api/ routes/ wire.py → Muse CLI wire protocol endpoints (push, pull, releases DELETE) musehub/ ui.py → SSR HTML pages with content negotiation (HTML ↔ msgpack) releases.py → Release CRUD REST API proposals.py → Proposal CRUD; routes use proposal_number (sequential int), not UUID labels.py → label assignment for issues and proposals db/ musehub_models.py → SQLAlchemy ORM models (single source of schema truth) models/ musehub.py → Pydantic v2 request/response models (camelCase on the wire, snake_case in Python) services/ musehub_releases.py → ONLY module that touches musehub_releases table musehub_proposals.py → ONLY module that touches musehub_proposals table musehub_wire_tags.py → wire tag persistence templates/ musehub/ base.html → base layout, CSS/JS includes pages/ → full-page Jinja2 templates fragments/ → HTMX partial fragments static/ scss/ → SCSS source — compiled to app.css js/ → TypeScript source — compiled to app.js via esbuild mcp/ → Model Context Protocol dispatcher, tools, resources, prompts alembic/ versions/ → One file per schema change; append-only tests/ → pytest + anyio async test suite ``` ### Layer rules (hard constraints) - **Route handlers are thin.** All DB access goes through `services/`. - **Service modules own their tables exclusively.** No other module may touch a service's table directly. - **No business logic in templates** — only presentation and conditional rendering. - **Alembic migrations are append-only.** Never edit a migration that has already been applied. - **Service functions are async** (FastAPI + SQLAlchemy async). Never introduce sync DB calls. ### Server operations The local development instance runs at `http://localhost:10003`. All Python runs inside Docker. | Operation | Command | |-----------|---------| | Start server | `docker compose up -d` | | Restart after code change | `docker compose restart musehub` | | Rebuild after dependency change | `docker compose up --build -d` | | Run migrations | `docker compose exec musehub alembic upgrade head` | | Compile SCSS | `sass musehub/templates/musehub/static/scss/app.scss musehub/templates/musehub/static/app.css --style=compressed --no-source-map` | | Compile TypeScript | `npm run build` (uses esbuild) | | Run Python type audit | `docker compose exec musehub mypy musehub/` | | Run TypeScript type audit | `npx tsc --noEmit` (runs on host, not in container) | | Run tests | `docker compose exec musehub pytest tests/ -q` | | Push release | `muse release push --remote local` | | Delete remote release | `muse release delete --remote local --yes` | | View releases | `http://localhost:10003/gabriel/musehub/releases` | Muse remote config for this repo (`.muse/config.toml`): ```toml [remotes.local] url = "http://localhost:10003/gabriel/musehub" branch = "main" ``` ### Authentication MuseHub uses Ed25519 / MSign authentication. Requests are signed with your Ed25519 private key; the server verifies against the registered public key. The `muse` CLI signs all requests automatically. Identity config lives in **`~/.muse/identity.toml`** (global, not per-repo), keyed by hostname: ```toml ["localhost:10003"] type = "human" name = "gabriel" ["musehub.ai"] type = "human" name = "gabriel" ``` When a push returns 404 ("Repository not found on remote"), the repo may not exist on MuseHub yet. Create it via the API with an MSign-signed request: ```bash curl -s -X POST http://localhost:10003/api/repos \ -H "Content-Type: application/json" \ -H "Authorization: MSign handle=\"gabriel\" ts= sig=\"\"" \ -d '{"owner":"gabriel","name":"","description":""}' ``` Then retry `muse push local`. ### Frontend separation of concerns — absolute rule Every concern lives in exactly one layer. Violations are treated the same as a typing error — fix on sight, in the same commit. | Layer | Where it lives | What it does | |-------|---------------|--------------| | **Structure** | `templates/musehub/pages/*.html`, `fragments/*.html` | Jinja2 markup only — no `