musehub — Agent Configuration
This repository is a member of a workspace.
Shared workspace rules live in the parent .muse/agent.md.
This file contains only musehub-specific additions.
Managed by muse agent-config — regenerate adapters with muse agent-config sync.
Proposal Titles
Proposal titles must be plain English — not branch-name style.
The branch (feat/auth-v2, task/proposal-models-v2) already encodes the type prefix.
The title is what a human reads in the list; it should describe the change, not echo the branch.
| Branch | Bad title | Good title |
|---|---|---|
feat/auth-v2 |
feat: auth v2 |
Ed25519 key rotation and MSign auth v2 |
task/proposal-models-v2 |
feat: proposal models v2 |
Proposal type badges, 7-state tabs, and ghost object integrity fix |
fix/wire-timeout |
fix: wire timeout |
Increase push stream timeout to prevent drops on large repos |
Rule: if the title could be mistaken for a branch name or a commit message subject line, rewrite it.
Localhost Containers — ALWAYS Restart BOTH After Code Changes
Two containers run this repo's Python code, and both run without hot-reload — code changes to the live-mounted volume are not picked up until each is restarted:
| Container | Compose service | Runs |
|---|---|---|
musehub |
musehub |
the API (uvicorn, no --reload) |
musehub_worker |
worker |
the background job processor (mpack.index, fetch.mpack.prebuild) |
musehub-runner (docker-in-docker sandbox) and musehub_postgres/musehub_minio
(datastores) do not run this repo's Python and never need restarting for a code
change.
A real incident that cost real time: musehub_worker was found running a
Docker image dated over a month old while musehub itself had been restarted
recently — because only musehub's restart was a documented habit. Every
job-side observation made during that window (prebuild behavior, cache
invariants, mpack consolidation) was silently wrong, and it took a deep,
multi-hour investigation to notice the container itself was stale rather than
the code. Restarting only musehub and assuming the worker is also fresh is a
trap — always restart both, together, every time:
docker restart musehub musehub_worker && sleep 5 && curl -sk https://localhost:1337/healthz
Verify freshness before trusting any test result
A restart alone does not guarantee correctness — confirm it actually worked:
# 1. Confirm both containers actually restarted (not just "Up", but recently)
docker ps --format "{{.Names}}\t{{.Status}}" | grep -E "^musehub(\s|_worker)"
# "Up X seconds" — if either shows days/weeks, the restart didn't take or targeted the wrong name
# 2. Confirm the API booted clean — look for these exact lines, not just "started"
docker logs musehub --tail 20 | grep -i "schema check passed\|Application startup failed"
# ✅ "schema check passed — ORM and DB are in sync (N tables)"
# ❌ "Application startup failed" — see schema-drift section below, do not proceed until fixed
# 3. Confirm the worker booted clean
docker logs musehub_worker --tail 20 | grep -i "worker started\|Application startup failed"
# ✅ "MuseHub worker started"
If you're mid-investigation and something doesn't match your mental model of current code — check container freshness FIRST, before re-reading source or building new theories. Compare image build time against your last relevant commit:
docker inspect musehub --format '{{.Image}}' | xargs docker image inspect --format '{{.Created}}'
docker inspect musehub_worker --format '{{.Image}}' | xargs docker image inspect --format '{{.Created}}'
If either predates a commit you're relying on, restart doesn't help — see "When you need a rebuild, not just a restart" below.
When you need a rebuild, not just a restart
Plain docker restart is enough for .py edits under the bind-mounted
musehub/ directory (see docker inspect musehub --format '{{range .Mounts}}...'
for the exact list — musehub/musehub, musehub/alembic, musehub/tests, etc.
are all live bind mounts). It is not enough when:
Dockerfilechangedrequirements*.txt/ dependency pins changeddocker-compose.yml/docker-compose.override.ymlchanged
In those cases, rebuild the image before restarting:
cd ~/ecosystem/musehub
docker compose build musehub worker
docker compose up -d musehub worker
Schema drift and missing migrations — two distinct failure modes
Both show up as Application startup failed in docker logs musehub, but need
different fixes. Read the actual error before acting — do not assume
alembic upgrade head fixes every schema error:
Mode 1 — DB behind the migrations that already exist. Error names a table/ column the ORM expects. Fix:
docker exec musehub sh -c "cd /app && alembic upgrade head"
Mode 2 — an ORM model was added with no migration ever generated for it.
alembic current already reports (head) — there is nothing to "catch up" on;
the migration simply doesn't exist. Confirm which mode you're in:
docker exec musehub sh -c "cd /app && alembic current"
docker exec musehub sh -c "cd /app && alembic heads"
# If current == heads and the app still fails on a missing table → Mode 2
Fix by generating the missing migration, then rename it to match this repo's
numbered convention (00NN_description.py, not the default timestamp/hex
name) before applying:
docker exec musehub sh -c "cd /app && alembic revision --autogenerate -m 'add <table>'"
# rename the generated file: alembic/versions/<timestamp>_<hex>_....py → 00NN_description.py
# edit revision/down_revision inside to '00NN'/'00NN-1' matching the new filename
docker exec musehub sh -c "cd /app && alembic upgrade head"
docker restart musehub musehub_worker
If the container already auto-applied the pre-rename autogenerated revision at startup (common — many app entrypoints run migrations before the schema check), re-stamp the DB to the renamed revision id instead of re-running upgrade:
docker exec musehub_postgres psql -U musehub -d musehub -c "UPDATE alembic_version SET version_num = '00NN';"
Repo-Specific Notes
Deploying MuseHub and publishing a new Muse CLI build
Full runbook: docs/deploy.md. Quick reference:
# Deploy MuseHub server (staging)
cd ~/ecosystem/musehub
bash deploy/push.sh staging
# Publish a new Muse CLI tarball (always AFTER deploying the server)
cd ~/ecosystem/musehub
bash deploy/publish_muse_release.sh
Standard release flow (both repos share the same version string):
- Bump
versioninmuse/pyproject.tomlANDmusehub/pyproject.toml, commit each ondev muse -C ~/ecosystem/muse push local dev && muse -C ~/ecosystem/muse push staging devbash deploy/push.sh staging— server must be at the new version before the tarball is publishedbash deploy/publish_muse_release.sh- Verify:
curl -fsSL https://staging.musehub.ai/install.sh | sh && muse --version
Recovering a Down Staging Instance
If staging returns 502 or the webserver is down:
Restart the container — containers use
--restart unless-stoppedso a reboot brings them back, but a manualdocker stopdoes not:sudo docker start musehub-blue # or musehub-green, whichever is activeSwitch the active slot — the ONLY correct way to change which slot nginx points to:
sudo musehub-set-slot blue # blue = port 1337 sudo musehub-set-slot green # green = port 1338This script lives at
/usr/local/bin/musehub-set-sloton 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.Check current state:
cat /opt/musehub/.active-slot # which slot is active (blue or green) cat /etc/nginx/musehub-active-port # what nginx is pointing at sudo docker ps --format "{{.Names}} {{.Status}}" # container healthIf SSM commands are stuck as Pending — reboot the instance. Containers with
--restart unless-stoppedcome back automatically:aws ec2 reboot-instances --region us-east-1 --instance-ids i-07547cd20bee2dea5Then poll until SSM is back before sending new commands:
aws ssm describe-instance-information --region us-east-1 \ --filters "Key=InstanceIds,Values=i-07547cd20bee2dea5" \ --query 'InstanceInformationList[0].PingStatus' --output text
Instance IDs
| Environment | Instance ID |
|---|---|
| staging | i-07547cd20bee2dea5 |
| prod | i-0855d6efe7fa1a49d |