gabriel / musehub public
AGENTS.md markdown
257 lines 8.9 KB
0bfb4569 add agent rules: Muse-only VCS, no Git/GitHub gabriel 9h ago
1 # MuseHub — Agent Contract
2
3 This document defines how AI agents operate in the MuseHub repository. MuseHub is the remote repository server for the Muse version control system — the GitHub analogue in the Muse ecosystem.
4
5 ---
6
7 ## Agent Role
8
9 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.
10
11 You:
12 - Implement features, fix bugs, extend the API, update templates and SCSS, write migrations.
13 - Write production-quality, fully-typed Python and Jinja2.
14 - Think like a staff engineer: composability over cleverness, clarity over brevity.
15
16 You do NOT:
17 - Use `git`, `gh`, or GitHub for anything. Muse and MuseHub are the only VCS tools.
18 - Work directly on `main`. Ever.
19 - Add business logic to route handlers — delegate to service modules.
20 - Edit already-applied Alembic migrations — always create a new one.
21
22 ---
23
24 ## No legacy. No deprecated. No exceptions.
25
26 - **Delete on sight.** Dead code, deprecated shapes, backward-compatibility shims — delete in the same commit.
27 - **No fallback paths.** The current shape is the only shape.
28 - **No "legacy" or "deprecated" annotations.** If it's marked deprecated, delete it.
29 - **No dead constants, dead regexes, dead fields.**
30
31 When you remove something, remove it completely: implementation, tests, docs, config.
32
33 ---
34
35 ## Architecture
36
37 ```
38 musehub/
39 api/
40 routes/
41 wire.py → Muse CLI wire protocol endpoints (push, pull, releases DELETE)
42 musehub/
43 ui.py → SSR HTML pages with content negotiation (HTML ↔ msgpack)
44 releases.py → Release CRUD REST API
45 db/
46 musehub_models.py → SQLAlchemy ORM models (single source of schema truth)
47 models/
48 musehub.py → Pydantic v2 request/response models
49 (camelCase on the wire, snake_case in Python)
50 services/
51 musehub_releases.py → ONLY module that touches musehub_releases table
52 musehub_wire_tags.py → wire tag persistence
53 templates/
54 musehub/
55 base.html → base layout, CSS/JS includes
56 pages/ → full-page Jinja2 templates
57 fragments/ → HTMX partial fragments (SSE, release rows, etc.)
58 static/
59 scss/ → SCSS source — compiled to app.css
60 mcp/ → Model Context Protocol dispatcher, tools, resources, prompts
61 alembic/
62 versions/ → One file per schema change; append-only
63 tests/ → pytest + anyio async test suite
64 ```
65
66 ### Layer rules (hard constraints)
67
68 - **Route handlers are thin.** All DB access goes through `services/`.
69 - **`musehub_releases.py` owns the releases table.** No other module may touch it directly.
70 - **No business logic in templates** — only presentation and conditional rendering.
71 - **Alembic migrations are append-only.** Never edit a migration that has already been applied.
72 - **Service functions are async** (FastAPI + SQLAlchemy async). Never introduce sync DB calls.
73
74 ---
75
76 ## Version Control — Muse Only
77
78 **Git and GitHub are not used.** All branching, committing, merging, and releasing happen through Muse. Never run `git`, `gh`, or reference GitHub.
79
80 ### The mental model
81
82 Git tracks line changes in files. Muse tracks **named things** — functions, classes, sections — across time. `muse diff` shows `InvoiceService.charge()` was modified; `muse merge --dry-run` identifies symbol conflicts before a conflict marker is written; `muse commit` is a typed event that proposes MAJOR/MINOR/PATCH based on structural changes.
83
84 ### Starting work
85
86 ```
87 muse status # where am I, what's dirty
88 muse branch feat/my-thing # create branch
89 muse checkout feat/my-thing # switch to it
90 ```
91
92 ### While working
93
94 ```
95 muse status # constantly
96 muse diff # symbol-level diff
97 muse code add . # stage
98 muse commit -m "..." # typed commit
99 ```
100
101 ### Before merging
102
103 ```
104 muse fetch local
105 muse status
106 muse merge --dry-run main # confirm no symbol conflicts, check semver impact
107 ```
108
109 ### Merging
110
111 ```
112 muse checkout main
113 muse merge feat/my-thing
114 ```
115
116 ### Releasing
117
118 ```
119 muse release add <tag> # create local release at HEAD
120 muse release push <tag> --remote local # push to MuseHub local instance
121 ```
122
123 ### Branch discipline — absolute rule
124
125 **`main` is not for direct work. Every task lives on a branch.**
126
127 Full lifecycle:
128 1. `muse status` — clean before branching.
129 2. `muse branch feat/<desc>` then `muse checkout feat/<desc>`.
130 3. Do the work. Commit on the branch.
131 4. **Verify** before merging — in this exact order:
132 ```
133 mypy musehub/ # zero errors
134 pytest tests/ -v # all green
135 ```
136 5. `muse merge --dry-run main` — confirm clean.
137 6. `muse checkout main && muse merge feat/<desc>`.
138 7. `muse release add <tag> && muse release push <tag> --remote local`.
139
140 ### Enforcement protocol
141
142 | Checkpoint | Command | Expected |
143 |-----------|---------|----------|
144 | Before branching | `muse status` | clean working tree |
145 | Before merging | `mypy` + `pytest` | all pass |
146 | After merge | `muse status` | clean |
147
148 ---
149
150 ## MuseHub Server
151
152 The local development instance runs at `http://localhost:10003`. Start it with Docker Compose.
153
154 | Operation | Command |
155 |-----------|---------|
156 | Start | `docker compose up -d` |
157 | View releases | `http://localhost:10003/gabriel/musehub/releases` |
158 | Push release | `muse release push <tag> --remote local` |
159 | Delete remote release | `muse release delete <tag> --remote local --yes` |
160 | Run migrations | `docker compose exec musehub alembic upgrade head` |
161 | Build SCSS | build script in `tools/` |
162
163 Muse remote config for this repo (`.muse/config.toml`):
164 ```toml
165 [remotes.local]
166 url = "http://localhost:10003/gabriel/musehub"
167 branch = "main"
168 ```
169
170 ---
171
172 ## Code Standards
173
174 - **Type hints everywhere — 100% coverage.**
175 - **Modern syntax:** `list[X]`, `dict[K, V]`, `X | None`.
176 - **`logging.getLogger(__name__)`** — never `print()`.
177 - **Docstrings** on public modules, classes, and functions.
178 - **Sparse logs.** Emoji prefixes: ❌ error, ⚠️ warning, ✅ success.
179
180 ---
181
182 ## Typing — Zero-Tolerance Rules
183
184 | What | Why banned | Use instead |
185 |------|------------|-------------|
186 | `Any` | Collapses type safety | `TypedDict`, `Protocol`, specific union |
187 | `object` | Effectively `Any` | The actual type |
188 | `list` (bare) | Tells nothing about contents | `list[X]` |
189 | `dict` (bare) | Same | `dict[K, V]` |
190 | `cast(T, x)` | Masks a broken return type | Fix the callee |
191 | `# type: ignore` | A lie in the source | Fix the root cause |
192 | `Optional[X]` | Legacy syntax | `X \| None` |
193 | `List[X]`, `Dict[K,V]` | Legacy imports | `list[X]`, `dict[K, V]` |
194
195 ---
196
197 ## Testing Standards
198
199 | Level | Scope | Required when |
200 |-------|-------|---------------|
201 | **Unit** | Single service function, mocked DB | Always — every public service function |
202 | **Integration** | Route handler + service + real test DB | Every new endpoint |
203 | **Regression** | Reproduces a bug | Every bug fix |
204 | **SSR** | Full HTML page render via async test client | Every template change |
205
206 **Test efficiency — mandatory protocol:**
207 1. Run the full suite **once** to find all failures.
208 2. Fix every failure found.
209 3. Re-run **only the files that were failing** to confirm the fix.
210 4. Run the full suite only as the final pre-merge gate.
211
212 ---
213
214 ## Verification Checklist
215
216 Run before merging to `main`:
217
218 - [ ] On a feature branch — never on `main`
219 - [ ] `mypy musehub/` — zero errors
220 - [ ] `pytest tests/ -v` — all green
221 - [ ] No `Any`, bare collections, `cast()`, `# type: ignore`, `Optional[X]`, `List`/`Dict`
222 - [ ] No dead code, no music-domain elements in generic pages
223 - [ ] New DB columns have a new Alembic migration
224 - [ ] SCSS compiled to `app.css`
225 - [ ] Affected docs updated in the same commit
226 - [ ] No secrets, no `print()`, no orphaned imports
227
228 ---
229
230 ## Scope of Authority
231
232 ### Decide yourself
233 - Bug fixes with regression tests.
234 - New Alembic migrations for schema additions.
235 - Template and SCSS updates.
236 - New service functions and API endpoints within existing patterns.
237 - Test additions and improvements.
238
239 ### Ask the user first
240 - New top-level database tables.
241 - Changes to the Muse wire protocol shape.
242 - New Docker services or infrastructure dependencies.
243 - Architecture changes (new layers, new storage backends).
244
245 ---
246
247 ## Anti-Patterns (never do these)
248
249 - Using `git`, `gh`, or GitHub for anything. Muse and MuseHub only.
250 - Working directly on `main`.
251 - Business logic in route handlers — put it in services.
252 - Editing an already-applied Alembic migration.
253 - `Any`, bare collections, `cast()`, `# type: ignore` — absolute bans.
254 - `Optional[X]`, `List[X]`, `Dict[K,V]` — use modern syntax.
255 - Music-domain-specific UI (audio players, MIDI buttons) in generic release or repo pages.
256 - `print()` for diagnostics — use `logging`.
257 - Syncing schema changes without a migration.