muse-attributes.md
markdown
| 1 | # `.museattributes` Reference |
| 2 | |
| 3 | > **Format:** TOML · **Location:** repository root (next to `.muse/`) |
| 4 | > **Loaded by:** `muse merge`, `muse cherry-pick`, `muse attributes` |
| 5 | |
| 6 | `.museattributes` declares per-path, per-dimension merge strategy overrides for |
| 7 | a Muse repository. It uses TOML syntax for consistency with `.muse/config.toml` |
| 8 | and to allow richer structure (comments, typed values, named sections). |
| 9 | |
| 10 | --- |
| 11 | |
| 12 | ## File Structure |
| 13 | |
| 14 | ```toml |
| 15 | # .museattributes |
| 16 | # Merge strategy overrides for this repository. |
| 17 | # Documentation: docs/reference/muse-attributes.md |
| 18 | |
| 19 | [meta] |
| 20 | domain = "midi" # must match .muse/repo.json "domain" field (optional but recommended) |
| 21 | |
| 22 | [[rules]] |
| 23 | path = "drums/*" |
| 24 | dimension = "*" |
| 25 | strategy = "ours" |
| 26 | |
| 27 | [[rules]] |
| 28 | path = "keys/*" |
| 29 | dimension = "pitch_bend" |
| 30 | strategy = "theirs" |
| 31 | |
| 32 | [[rules]] |
| 33 | path = "*" |
| 34 | dimension = "*" |
| 35 | strategy = "auto" |
| 36 | ``` |
| 37 | |
| 38 | --- |
| 39 | |
| 40 | ## Sections |
| 41 | |
| 42 | ### `[meta]` (optional) |
| 43 | |
| 44 | | Key | Type | Description | |
| 45 | |-----|------|-------------| |
| 46 | | `domain` | string | The domain this file targets. When present, must match `.muse/repo.json "domain"`. If they differ, `muse merge` logs a warning but proceeds. | |
| 47 | |
| 48 | `[meta]` has no effect on merge resolution. It provides a machine-readable |
| 49 | declaration of the intended domain and enables validation tooling to warn when |
| 50 | rules may be targeting the wrong plugin. |
| 51 | |
| 52 | --- |
| 53 | |
| 54 | ### `[[rules]]` (array) |
| 55 | |
| 56 | Each `[[rules]]` entry is a single merge strategy rule. Rules are evaluated |
| 57 | **top-to-bottom**; the **first matching rule wins**. |
| 58 | |
| 59 | | Field | Type | Required | Description | |
| 60 | |-------|------|----------|-------------| |
| 61 | | `path` | string | yes | An `fnmatch` glob matched against workspace-relative POSIX paths (e.g. `"drums/*"`, `"src/**/*.mid"`). | |
| 62 | | `dimension` | string | yes | A domain axis name (e.g. `"pitch_bend"`, `"notes"`) or `"*"` to match any dimension. | |
| 63 | | `strategy` | string | yes | One of the five strategies below. | |
| 64 | |
| 65 | --- |
| 66 | |
| 67 | ## Strategies |
| 68 | |
| 69 | | Strategy | Behaviour | |
| 70 | |----------|-----------| |
| 71 | | `auto` | Use the merge engine's automatic algorithm. This is the default when no rule matches. | |
| 72 | | `ours` | Always take the current branch's version. The incoming branch's changes to this path are discarded. | |
| 73 | | `theirs` | Always take the incoming branch's version. The current branch's changes to this path are discarded. | |
| 74 | | `union` | Combine both versions (union semantics). Applicable to set-like dimensions. | |
| 75 | | `manual` | Report this path as a conflict regardless of whether the engine could auto-resolve it. Forces human review. | |
| 76 | |
| 77 | --- |
| 78 | |
| 79 | ## Matching Rules |
| 80 | |
| 81 | - **Path matching** uses Python's `fnmatch.fnmatch()`. Patterns are matched |
| 82 | against workspace-relative POSIX path strings (forward slashes, no leading `/`). |
| 83 | - **Dimension matching**: `"*"` in the `dimension` field matches any dimension. |
| 84 | A named dimension (e.g. `"pitch_bend"`) matches only that dimension. |
| 85 | - **First match wins.** Order your rules from most-specific to least-specific. |
| 86 | |
| 87 | --- |
| 88 | |
| 89 | ## Multi-Domain Repositories |
| 90 | |
| 91 | If a repository has multiple domain plugins active (multi-domain mode), the |
| 92 | `[meta] domain` field scopes the rules to a specific plugin. Each domain's |
| 93 | `.museattributes` rules should live in a separate file or be clearly delimited. |
| 94 | |
| 95 | For single-domain repositories (the common case), `[meta] domain` ensures the |
| 96 | rules are validated against the active plugin — a useful guard when copying |
| 97 | `.museattributes` between repositories. |
| 98 | |
| 99 | --- |
| 100 | |
| 101 | ## Examples |
| 102 | |
| 103 | ### Music repository — drums always ours, keys harmonic auto |
| 104 | |
| 105 | ```toml |
| 106 | [meta] |
| 107 | domain = "midi" |
| 108 | |
| 109 | [[rules]] |
| 110 | path = "drums/*" |
| 111 | dimension = "*" |
| 112 | strategy = "ours" |
| 113 | |
| 114 | [[rules]] |
| 115 | path = "keys/*" |
| 116 | dimension = "pitch_bend" |
| 117 | strategy = "auto" |
| 118 | |
| 119 | [[rules]] |
| 120 | path = "*" |
| 121 | dimension = "*" |
| 122 | strategy = "auto" |
| 123 | ``` |
| 124 | |
| 125 | ### Force manual review for all structural changes |
| 126 | |
| 127 | ```toml |
| 128 | [meta] |
| 129 | domain = "midi" |
| 130 | |
| 131 | [[rules]] |
| 132 | path = "*" |
| 133 | dimension = "track_structure" |
| 134 | strategy = "manual" |
| 135 | |
| 136 | [[rules]] |
| 137 | path = "*" |
| 138 | dimension = "*" |
| 139 | strategy = "auto" |
| 140 | ``` |
| 141 | |
| 142 | ### Genomics repository — reference sequence is always ours |
| 143 | |
| 144 | ```toml |
| 145 | [meta] |
| 146 | domain = "genomics" |
| 147 | |
| 148 | [[rules]] |
| 149 | path = "reference/*" |
| 150 | dimension = "*" |
| 151 | strategy = "ours" |
| 152 | |
| 153 | [[rules]] |
| 154 | path = "edits/*" |
| 155 | dimension = "*" |
| 156 | strategy = "auto" |
| 157 | ``` |
| 158 | |
| 159 | --- |
| 160 | |
| 161 | ## Generated Template |
| 162 | |
| 163 | `muse init --domain <name>` writes the following template to the repository root: |
| 164 | |
| 165 | ```toml |
| 166 | # .museattributes — merge strategy overrides for this repository. |
| 167 | # Documentation: docs/reference/muse-attributes.md |
| 168 | # |
| 169 | # Format: TOML. [[rules]] entries are matched top-to-bottom; first match wins. |
| 170 | # Strategies: ours | theirs | union | auto | manual |
| 171 | |
| 172 | [meta] |
| 173 | domain = "<name>" # must match .muse/repo.json "domain" field |
| 174 | |
| 175 | # Add [[rules]] entries below. Examples: |
| 176 | # |
| 177 | # [[rules]] |
| 178 | # path = "tracks/*" |
| 179 | # dimension = "*" |
| 180 | # strategy = "auto" |
| 181 | # |
| 182 | # [[rules]] |
| 183 | # path = "*" |
| 184 | # dimension = "*" |
| 185 | # strategy = "auto" |
| 186 | ``` |
| 187 | |
| 188 | --- |
| 189 | |
| 190 | ## Related |
| 191 | |
| 192 | - `.muse/config.toml` — per-repository user, auth, remote, and domain configuration |
| 193 | - `.museignore` — snapshot exclusion list (paths excluded from `muse commit`) |
| 194 | - `muse attributes` — CLI command to display current rules and `[meta]` domain |
| 195 | - `docs/reference/type-contracts.md` — `MuseAttributesFile` TypedDict definition |