muse agent-config's canonical source file is never tracked by Muse, defeating its own purpose
muse agent-config's canonical source file is never tracked by Muse, defeating its own purpose
Background
The entire premise of muse agent-config is: one canonical, versioned source
file per repo/workspace, from which any developer on any tool (Claude, Codex,
Cursor, Windsurf) can generate their adapter file via muse agent-config sync
— enabling a new developer to clone the repo and get the right config for
their setup automatically.
That promise is broken. The canonical source lives at .muse/agent.md
(muse/core/paths.py::agent_md_path()), and .muse/ is unconditionally
excluded from every snapshot:
# muse/plugins/code/plugin.py:157-166
# Directories that are never versioned regardless of .museignore.
# These are implicit ignores that apply to all code repositories.
_ALWAYS_IGNORE_DIRS: frozenset[str] = frozenset({
".git",
".muse",
...
})
Confirmed live, not assumed: editing ~/ecosystem/.muse/agent.md (the
workspace-level rules file) produces zero change in muse status, and
the file is absent from muse ls-files entirely. CLAUDE.md at the repo
root is tracked, but it's just a one-line @.muse/agent.md include — the
actual rules content is local-only and would not survive a fresh clone.
This is not a workspace misconfiguration — agent_md_path() is a single,
hardcoded function every agent-config subcommand (init, sync, read,
status, inspect) routes through, so every user of Muse who has ever run
muse agent-config init has the identical problem: their canonical config
only exists on the machine it was created on.
Goal
The canonical agent-config source file must be a normal tracked file — living
outside .muse/ entirely — so it survives clone/push/pull like any other
repo content, restoring the actual promise: clone, run muse agent-config sync, get your tool's adapter.
Decided (2026-07-07): the new canonical filename is .museagent.md at
the repo/workspace root — matches the existing .museignore/.museattributes
dotfile naming convention, and avoids the near-collision risk of AGENT.md
vs. the existing AGENTS.md (the Codex adapter's generated output, not the
source).
"Done" means: agent_md_path() returns <root>/.museagent.md; every existing
.muse/agent.md in this workspace (muse, musehub, ~/ecosystem workspace
root, and any other member repo that has one) is migrated; generated adapter
files reference @.museagent.md not @.muse/agent.md; a one-time forward
migration (not a permanent fallback) handles repos that still have the old
file when init/sync runs.
Out of Scope
- Any change to what content
agent.md/.museagent.mdholds — this is a location fix, not a content redesign. - Per-tool adapter rendering logic beyond the path string itself (the
_render_adaptertemplates stay the same, just fed a different path). - Retroactively renaming the concept from "agent.md" to something else in prose/docstrings beyond what's needed for the new filename to make sense.
Phases
Phase 1 — Red: pin the bug and the target behavior
ACFG_01—agent_md_path(root)currently returns a path whose parent directory name is.muse— assert this is no longer true after the fix (returns<root>/.museagent.md). Must fail against current code.ACFG_02— Aftermuse agent-config initin a fresh repo, the created file must not be excluded by_ALWAYS_IGNORE_DIRS/ must appear inmuse ls-filesaftermuse code add .+ commit. Real integration test, not just a path-string assertion — this is the actual bug.ACFG_03— GeneratedCLAUDE.mdcontent contains@.museagent.md, not@.muse/agent.md, for both standalone and workspace-member scope (the latter also covers the workspace-root relative path,../.museagent.md).
Deliverable: all three red against current code, confirmed before any Phase 2 change.
Phase 2 — Fix: move the canonical path, migrate existing files
- Change
agent_md_path()inmuse/core/paths.pyto returnroot / ".museagent.md". - Update every literal
.muse/agent.md/{rel}/.muse/agent.mdstring inmuse/cli/commands/agent_config.py(path-building logic, docstrings, help text) to.museagent.md/{rel}/.museagent.md. - One-time forward migration: if
initorsyncfinds.muse/agent.mdpresent and.museagent.mdabsent, move the content across (not copy — the old location must not linger, per this workspace's "no legacy" convention) and log what happened. This is a migration step, not a permanent fallback path — no dual-read logic survives after the move. - Update
_WORKSPACE_ROOT_TEMPLATE/_WORKSPACE_MEMBER_TEMPLATE/_STANDALONE_TEMPLATEif they reference the old path internally.
Deliverable: ACFG_01-03 green.
Phase 3 — Migrate this workspace's existing files
- Run the migration (via
muse agent-config syncor manually) inmuse,musehub,~/ecosystem(workspace root), and any other member repo with an existing.muse/agent.md. - Commit each migrated
.museagent.md— verify withmuse ls-filesthat it's genuinely tracked this time, not just present on disk. - Regenerate all adapters (
muse agent-config sync --force) so everyCLAUDE.md/AGENTS.mdreferences@.museagent.md.
Deliverable: ACFG_04 — a fresh muse clone of each affected repo has
.museagent.md present and correct, with no manual agent-config init
required.
Phase 4 — Regression sweep
- Full
tests/test_cmd_agent_config.pyandtests/test_agent_config_envelope.pygreen — expect many existing assertions to need updating from.muse/agent.mdliterals to.museagent.md, not just the new tests passing. muse code test --jsonfor downstream impact.grep -rn '\.muse/agent\.md' muse/(excluding this ticket's own historical references) returns zero remaining hits in source or tests.
Deliverable: zero regressions, zero remaining old-path references.
Acceptance Criteria
agent_md_path()never returns a path inside.muse/.- A fresh
muse agent-config init+ commit produces a file that survivesmuse clone— proven by an integration test, not inferred. - Every existing
.muse/agent.mdin this workspace has been migrated and is now genuinely tracked. - Zero remaining
.muse/agent.mdreferences inmuse/'s source, tests, or docstrings. docs/agent-guide.mdand every workspaceCLAUDE.md/AGENTS.mdreflect the new path.
Implementation Order
Phase 1 → Phase 2 → Phase 3 → Phase 4. Phase 3 (migrating this workspace's real files) cannot start until Phase 2's migration logic exists and is tested — don't hand-migrate files before the tool that's supposed to do it is proven correct.
Phases 1-3 (migration tool + auto-migrate on init/sync + this workspace's muse and musehub repos) landed on dev/main tonight, part of v0.2.0-nightly.3. Leaving open — the workspace root's own CLAUDE.md still resolves via
.muse/agent.md, and Phase 4 (docs/workspace-wide sweep) hasn't been verified complete across every member repo.