.cursorrules
sha256:009b5a222314f47640a58d75ce5a1f428f1624cf0b51384dfcdfbdfab3cc42a4
feat: migration idempotency, file attribution DAG walk, mpa…
Sonnet 4.6
minor
⚠ breaking
51 days ago
| 1 | # Workspace — Shared Agent Configuration |
| 2 | |
| 3 | This file contains shared rules for all repositories in this workspace. |
| 4 | Each member repository may have its own ``.muse/agent.md`` with repo-specific |
| 5 | additions. |
| 6 | |
| 7 | Managed by `muse agent-config` — regenerate adapters with `muse agent-config sync`. |
| 8 | |
| 9 | --- |
| 10 | |
| 11 | ## Workspace Members |
| 12 | |
| 13 | | Repo | Path | Branch | |
| 14 | |------|------|--------| |
| 15 | | **muse** | `muse` | `dev` | |
| 16 | | **musehub** | `musehub` | `dev` | |
| 17 | | **agentception** | `agentception` | `dev` | |
| 18 | | **contracts** | `contracts` | `dev` | |
| 19 | | **Stori** | `Stori` | `dev` | |
| 20 | | **maestro** | `maestro` | `dev` | |
| 21 | | **muse-zsh** | `muse-zsh` | `dev` | |
| 22 | |
| 23 | --- |
| 24 | |
| 25 | ## Version Control |
| 26 | |
| 27 | This workspace uses **Muse** for version control — not git, not GitHub. |
| 28 | |
| 29 | - Never run `git`, `gh`, or any git subcommand. |
| 30 | - Never reference GitHub, GitHub Actions, or GitHub URLs. |
| 31 | - Use `muse -C ~/path/to/repo <command>` when CWD differs from the target repo. |
| 32 | |
| 33 | If you find a `git` or `gh` call anywhere — delete it in the same commit. |
| 34 | |
| 35 | --- |
| 36 | |
| 37 | ## Commit Convention — Agent-First |
| 38 | |
| 39 | This workspace is **agent-first**: agents do the work, humans provision agents. |
| 40 | Every commit made by an agent must carry full provenance. Human commits (direct |
| 41 | manual changes without an agent) are the exception, not the norm. |
| 42 | |
| 43 | ### Agent commit — always use this |
| 44 | |
| 45 | ```bash |
| 46 | muse commit -m "feat: ..." \ |
| 47 | --agent-id claude-code \ |
| 48 | --model-id claude-sonnet-4-6 \ |
| 49 | --sign |
| 50 | ``` |
| 51 | |
| 52 | - `--agent-id` — identifies the agent type (`claude-code`, `codex`, `agentception/worker`, …) |
| 53 | - `--model-id` — the specific model that produced the change (`claude-sonnet-4-6`, …) |
| 54 | - `--sign` — embeds Ed25519 public key + signature; traces back to gabriel's root mnemonic in `~/.muse/identity.toml` |
| 55 | |
| 56 | Use the model you are actually running. For Claude Code the current model is `claude-sonnet-4-6`. |
| 57 | |
| 58 | ### Human commit — manual actions only |
| 59 | |
| 60 | ```bash |
| 61 | muse commit -m "chore: manual config change" |
| 62 | ``` |
| 63 | |
| 64 | No provenance flags. Their absence is itself a signal that a human acted directly. |
| 65 | |
| 66 | ### Provenance chain |
| 67 | |
| 68 | ``` |
| 69 | ~/.muse/identity.toml ← root mnemonic (HD wallet seed, gabriel's root identity) |
| 70 | ↓ HD derivation |
| 71 | Ed25519 key pair ← signer_public_key embedded in every --sign commit |
| 72 | ↓ signs |
| 73 | CommitRecord ← agent_id + model_id + signature stored per-commit |
| 74 | ↓ content-addressed |
| 75 | sha256:<commit_id> ← tamper-evident, auditable forever |
| 76 | ``` |
| 77 | |
| 78 | Agents spawned by agentception receive a derived key via `MUSE_AGENT_KEY` env var — |
| 79 | their commits sign with that key, which itself traces back to gabriel's root identity. |
| 80 | |
| 81 | --- |
| 82 | |
| 83 | ## Branch Flow |
| 84 | |
| 85 | Always work on a feature branch — never commit directly to `main` or `dev`. |
| 86 | |
| 87 | ```bash |
| 88 | muse -C ~/path/to/repo checkout dev |
| 89 | muse -C ~/path/to/repo checkout -b task/my-thing |
| 90 | |
| 91 | muse rm <file> # delete from disk + stage deletion (mirrors git rm) |
| 92 | muse code add . # stage additions + modifications + already-deleted files |
| 93 | muse commit -m "feat: ..." --agent-id claude-code --model-id claude-sonnet-4-6 --sign |
| 94 | |
| 95 | muse -C ~/path/to/repo checkout dev |
| 96 | muse -C ~/path/to/repo merge task/my-thing |
| 97 | muse -C ~/path/to/repo branch -d task/my-thing |
| 98 | muse -C ~/path/to/repo push local dev |
| 99 | ``` |
| 100 | |
| 101 | --- |
| 102 | |
| 103 | ## Code Intelligence |
| 104 | |
| 105 | | Task | Command | |
| 106 | |------|---------| |
| 107 | | Find symbol declaration | `muse code grep "Name" --json` | |
| 108 | | Read one symbol | `muse code cat "file.py::Symbol" --json` | |
| 109 | | File structure | `muse code symbols --file file.py --json` | |
| 110 | | Blast radius | `muse code impact "file.py::Symbol" --json` | |
| 111 | | Dependencies | `muse code deps "file.py" --json` | |
| 112 | | Tests for changed code | `muse code test --json` | |
| 113 | |
| 114 | --- |
| 115 | |
| 116 | ## Testing Rules |
| 117 | |
| 118 | **Never run the full test suite.** It is slow and gabriel runs it when he's ready. |
| 119 | |
| 120 | 1. **Start with `muse code test --json`** — runs only tests relevant to changed files. |
| 121 | 2. **Run one file at a time** when fixing a specific failure: |
| 122 | ```bash |
| 123 | python3 -m pytest tests/test_foo.py -q --tb=short |
| 124 | ``` |
| 125 | 3. **Run one test by name** to verify a fix: |
| 126 | ```bash |
| 127 | python3 -m pytest tests/test_foo.py::test_bar -q --tb=short |
| 128 | ``` |
| 129 | |
| 130 | ### Forbidden |
| 131 | |
| 132 | - `python3 -m pytest tests/` — runs everything, never do this |
| 133 | - `python3 -m pytest` with no path — same as above |
| 134 | - `pytest -x tests/` or any whole-suite invocation |
| 135 | - Looping retries on the same command after a failure — diagnose first |
| 136 | |
| 137 | # musehub — Agent Configuration |
| 138 | |
| 139 | This repository is a member of a workspace. |
| 140 | Shared workspace rules live in the parent ``.muse/agent.md``. |
| 141 | This file contains only musehub-specific additions. |
| 142 | |
| 143 | Managed by `muse agent-config` — regenerate adapters with `muse agent-config sync`. |
| 144 | |
| 145 | --- |
| 146 | |
| 147 | ## Proposal Titles |
| 148 | |
| 149 | Proposal titles must be plain English — not branch-name style. |
| 150 | |
| 151 | The branch (`feat/auth-v2`, `task/proposal-models-v2`) already encodes the type prefix. |
| 152 | The title is what a human reads in the list; it should describe the change, not echo the branch. |
| 153 | |
| 154 | | Branch | Bad title | Good title | |
| 155 | |--------|-----------|------------| |
| 156 | | `feat/auth-v2` | `feat: auth v2` | `Ed25519 key rotation and MSign auth v2` | |
| 157 | | `task/proposal-models-v2` | `feat: proposal models v2` | `Proposal type badges, 7-state tabs, and ghost object integrity fix` | |
| 158 | | `fix/wire-timeout` | `fix: wire timeout` | `Increase push stream timeout to prevent drops on large repos` | |
| 159 | |
| 160 | Rule: if the title could be mistaken for a branch name or a commit message subject line, rewrite it. |
| 161 | |
| 162 | --- |
| 163 | |
| 164 | ## Localhost Container — ALWAYS Restart After Code Changes |
| 165 | |
| 166 | The localhost container (`musehub`) runs uvicorn **without** `--reload`. Code changes to the live-mounted volume are **not picked up until the container restarts**. This is non-negotiable: |
| 167 | |
| 168 | ```bash |
| 169 | docker restart musehub && sleep 5 && curl -sk https://localhost:1337/healthz |
| 170 | ``` |
| 171 | |
| 172 | **Do this immediately after every edit to musehub Python source.** No exceptions. Every cycle spent debugging "why aren't my logs showing up" is wasted because the container is running stale code. |
| 173 | |
| 174 | --- |
| 175 | |
| 176 | ## Repo-Specific Notes |
| 177 | |
| 178 | ### Staging Deploy |
| 179 | |
| 180 | ```bash |
| 181 | bash deploy/push.sh staging # build, push to ECR, blue-green deploy |
| 182 | bash deploy/push.sh prod # same for prod |
| 183 | bash deploy/push.sh staging prod # staging then prod |
| 184 | ``` |
| 185 | |
| 186 | ### Recovering a Down Staging Instance |
| 187 | |
| 188 | If staging returns 502 or the webserver is down: |
| 189 | |
| 190 | 1. **Restart the container** — containers use `--restart unless-stopped` so a reboot brings them back, but a manual `docker stop` does not: |
| 191 | ```bash |
| 192 | sudo docker start musehub-blue # or musehub-green, whichever is active |
| 193 | ``` |
| 194 | |
| 195 | 2. **Switch the active slot** — the ONLY correct way to change which slot nginx points to: |
| 196 | ```bash |
| 197 | sudo musehub-set-slot blue # blue = port 1337 |
| 198 | sudo musehub-set-slot green # green = port 1338 |
| 199 | ``` |
| 200 | This script lives at `/usr/local/bin/musehub-set-slot` on the instance. It is the only sanctioned way to write `/etc/nginx/musehub-active-port`. **Never write to that file directly** — it must contain a full nginx upstream directive (`server 127.0.0.1:1337;`), not a bare port number. Writing a bare port breaks nginx config parsing and causes 502s. |
| 201 | |
| 202 | 3. **Check current state**: |
| 203 | ```bash |
| 204 | cat /opt/musehub/.active-slot # which slot is active (blue or green) |
| 205 | cat /etc/nginx/musehub-active-port # what nginx is pointing at |
| 206 | sudo docker ps --format "{{.Names}} {{.Status}}" # container health |
| 207 | ``` |
| 208 | |
| 209 | 4. **If SSM commands are stuck as Pending** — reboot the instance. Containers with `--restart unless-stopped` come back automatically: |
| 210 | ```bash |
| 211 | aws ec2 reboot-instances --region us-east-1 --instance-ids i-07547cd20bee2dea5 |
| 212 | ``` |
| 213 | Then poll until SSM is back before sending new commands: |
| 214 | ```bash |
| 215 | aws ssm describe-instance-information --region us-east-1 \ |
| 216 | --filters "Key=InstanceIds,Values=i-07547cd20bee2dea5" \ |
| 217 | --query 'InstanceInformationList[0].PingStatus' --output text |
| 218 | ``` |
| 219 | |
| 220 | ### Instance IDs |
| 221 | |
| 222 | | Environment | Instance ID | |
| 223 | |-------------|-------------| |
| 224 | | staging | `i-07547cd20bee2dea5` | |
| 225 | | prod | `i-0855d6efe7fa1a49d` | |
File History
1 commit
sha256:009b5a222314f47640a58d75ce5a1f428f1624cf0b51384dfcdfbdfab3cc42a4
feat: migration idempotency, file attribution DAG walk, mpa…
Sonnet 4.6
minor
⚠
51 days ago