Skip to content

MWPW-198143: add mas-author skill for safe M@S authoring via Odin MCP#1024

Merged
afmicka merged 27 commits into
mainfrom
MWPW-198143
Jul 27, 2026
Merged

MWPW-198143: add mas-author skill for safe M@S authoring via Odin MCP#1024
afmicka merged 27 commits into
mainfrom
MWPW-198143

Conversation

@yesil

@yesil yesil commented Jul 1, 2026

Copy link
Copy Markdown
Contributor
  • SKILL.md: stop rule, allow/deny lists, and guardrail workflows (publish, placeholder+index, safe delete, en_US tags, one-variation-per-locale) for driving the Odin MCP.
  • references/content-model.md: M@S content-fragment model IDs, reference fields, path/locale grammar, and variation rules. No code references.

Type install http://mas.adobe.com/docs/mas-author skill in Claude or ChatGPT.

Conversation Thread
You: /mas-author open fragment 597d1655-ab30-4f5d-9ea8-d777edf93249 in studio
Claude: Card model, path is /content/dam/mas/sandbox/en_US/create11111121129, so surface = sandbox.
Here's the M@S Studio link for CC Plans Merch Card: CC Pro: Individuals: apac-cci-q3fy26-promo-ph-th:
https://mas.adobe.com/studio.html#page=fragment-editor&fragmentId=597d1655-ab30-4f5d-9ea8-d777edf93249&path=sandbox

You: create a locale variation for egyprt
Claude: Egypt has two existing M@S locale folders: ar_EG (Arabic) and en_EG (English). Which one should I create the variation for?
You: en_EG (English)
Claude: The parent's variations field is empty, so no en_EG variation exists yet — clear to create.
[Created the fragment, working through a couple of schema/format errors along the way — fields needed to be an array of {name, type, values} objects rather than a plain object, and originalId needed to match the parent's originalId value rather than its own id, to keep it consistent with the en_US source.]
Shell created at /content/dam/mas/sandbox/en_EG/create11111121129 (id c36b05e0-fd15-4f4b-844c-4e3a21d14ffc). Now linking it to the parent's variations field.
Done. The en_EG variation is created and linked:

New fragment: c36b05e0-fd15-4f4b-844c-4e3a21d14ffc at /content/dam/mas/sandbox/en_EG/create11111121129
Shell fields carried over: osi, variant, size, cardName, promoCode, and originalId (matching the en_US parent's original id) — non-translatable structural fields only
Linked to the parent's variations field

Translatable content (title, description, badge, prices, CTAs, etc.) is intentionally left empty — that's MAS Studio's job, not something I should fill in with raw fragment edits. Studio link to open the new variation:
https://mas.adobe.com/studio.html#page=fragment-editor&fragmentId=c36b05e0-fd15-4f4b-844c-4e3a21d14ffc&path=sandbox

You: update tags of en_EG one
Claude: That variation is at en_EG, not en_US — so I can't edit its tags directly.
Tags belong on the en_US default fragment and are inherited by its locale variations, so editing tags on the en_EG copy wouldn't do anything meaningful (and could create drift from the parent). Reading its tags is fine, but writes should happen on the en_US fragment instead.
Want me to update the tags on the en_US parent (597d1655-ab30-4f5d-9ea8-d777edf93249) instead? If so, let me know what changes you want (add/replace/remove which tags).

Resolves https://jira.corp.adobe.com/browse/MWPW-198143
QA Checklist: https://wiki.corp.adobe.com/display/adobedotcom/M@S+Engineering+QA+Use+Cases

Please do the steps below before submitting your PR for a code review or QA

  • C1. Cover code with Unit Tests
  • C2. Add a Nala test (double check with #fishbags if nala test is needed)
  • C3. Verify all Checks are green (unit tests, nala tests)
  • C4. PR description contains working Test Page link where the feature can be tested
  • C5: you are ready to do a demo from Test Page in PR (bonus: write a working demo script that you'll use on Thursday, you can eventually put in your PR)
  • C.6 read your Jira one more time to validate that you've addressed all AC's and nothing is missing

🧪 Nala E2E Tests

Nala tests run automatically when you open this PR.

To run Nala tests again:

  1. Add the run nala label to this PR (in the right sidebar)
  2. Tests will run automatically on the current commit
  3. Any future commits will also trigger tests as long as the label remains

To stop automatic Nala tests:

  • Remove the run nala label

Note: Tests only run on commits if the run nala label is present. Add the label whenever you need tests to run on new changes.

Test URLs:

yesil added 2 commits July 1, 2026 18:32
- SKILL.md: stop rule, allow/deny lists, and guardrail workflows (publish, placeholder+index, safe delete, en_US tags, one-variation-per-locale) for driving the Odin MCP.
- references/content-model.md: M@S content-fragment model IDs, reference fields, path/locale grammar, and variation rules. No code references.
@aem-code-sync

aem-code-sync Bot commented Jul 1, 2026

Copy link
Copy Markdown

Hello, I'm the AEM Code Sync Bot and I will run some actions to deploy your branch.
In case there are problems, just click the checkbox below to rerun the respective action.

  • Re-sync branch
Commits

@codecov

codecov Bot commented Jul 1, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 89.86%. Comparing base (df856ef) to head (ab07dec).

Additional details and impacted files

Impacted file tree graph

@@           Coverage Diff           @@
##             main    #1024   +/-   ##
=======================================
  Coverage   89.86%   89.86%           
=======================================
  Files         298      298           
  Lines       94939    94939           
=======================================
+ Hits        85317    85318    +1     
+ Misses       9622     9621    -1     

see 9 files with indirect coverage changes


Continue to review full report in Codecov by Harness.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update df856ef...ab07dec. Read the comment docs.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Comment thread .hlxignore Outdated
@@ -1,4 +1,6 @@
.*
!.claude/skills/mas-author/SKILL.md
!.claude/skills/mas-author/references/content-model.md

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we want to exclude both files from being ignored, I think we should move them after the last line, because right now line 4 (*.md) cancels out both exclude rules.

@Axelcureno

Copy link
Copy Markdown
Member

Strong skill — docs-only, allow/deny/stop structure is right, and the .hlxignore allowlist is a good catch.

Two things before merge:

  1. Add model routing. New skills should carry `model:`/`effort:` per `.claude/plans/skill-model-routing.md`. This is a gating/decision skill (deny-list errors can delete published content), so `model: sonnet` + `effort: medium` — not haiku like the pure-reference skills.

  2. Confirm the batch tool name. Deny list says `aem_create_batch`; every other tool uses the `create-aem-*` hyphenated form. If the name is wrong the guardrail no-ops.

@yesil
yesil requested a review from Andrei4226 July 20, 2026 14:19
@yesil

yesil commented Jul 20, 2026

Copy link
Copy Markdown
Contributor Author

@Axelcureno I don't see .claude/plans/skill-model-routing.md but I added model/effort params.

@Andrei4226 Andrei4226 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM
Nit: the one-variation-per-locale rule documented here doesn't cover geo-scoped promo variations (multiple pznTags-scoped variations can exist per locale under the same promo project)

Clarify the rule bounds locale variations only; geo-scoped promo
variants (pznTags-scoped siblings) can legitimately share a locale under
one promo project. Addresses PR review nit.
@yesil

yesil commented Jul 24, 2026

Copy link
Copy Markdown
Contributor Author

Thanks @Andrei4226 incorporated your latest comment.

Comment on lines +170 to +316
### acom, acom-cc, acom-dc, nala, sandbox
| Language | Default locale | Regional variation locales |
|---|---|---|
| Arabic (`ar`) | `ar_SA` | `ar_DZ`, `ar_EG`, `ar_KW`, `ar_QA`, `ar_AE` |
| Bulgarian (`bg`) | `bg_BG` | — (default only) |
| Czech (`cs`) | `cs_CZ` | — (default only) |
| Danish (`da`) | `da_DK` | — (default only) |
| German (`de`) | `de_DE` | `de_AT`, `de_LU`, `de_CH` |
| Greek (`el`) | `el_GR` | — (default only) |
| English (`en`) | `en_US` | `en_DZ`, `en_BE`, `en_CA`, `en_EG`, `en_GR`, `en_HK`, `en_ID`, `en_IE`, `en_IL`, `en_KW`, `en_LU`, `en_MY`, `en_MU`, `en_NZ`, `en_NG`, `en_PH`, `en_QA`, `en_SA`, `en_SG`, `en_ZA`, `en_TH`, `en_TM`, `en_AE`, `en_VN` |
| English (`en`) | `en_GB` | `en_AU`, `en_IN` |
| Estonian (`et`) | `et_EE` | — (default only) |
| Finnish (`fi`) | `fi_FI` | — (default only) |
| Filipino (`fil`) | `fil_PH` | — (default only) |
| French (`fr`) | `fr_FR` | `fr_BE`, `fr_CA`, `fr_LU`, `fr_CH` |
| Hebrew (`he`) | `he_IL` | — (default only) |
| Hindi (`hi`) | `hi_IN` | — (default only) |
| Hungarian (`hu`) | `hu_HU` | — (default only) |
| Indonesian (`id`) | `id_ID` | — (default only) |
| Italian (`it`) | `it_IT` | `it_CH` |
| Japanese (`ja`) | `ja_JP` | — (default only) |
| Korean (`ko`) | `ko_KR` | — (default only) |
| Lithuanian (`lt`) | `lt_LT` | — (default only) |
| Latvian (`lv`) | `lv_LV` | — (default only) |
| Malay (`ms`) | `ms_MY` | — (default only) |
| Norwegian Bokmål (`nb`) | `nb_NO` | — (default only) |
| Dutch (`nl`) | `nl_NL` | `nl_BE` |
| Polish (`pl`) | `pl_PL` | — (default only) |
| Portuguese (`pt`) | `pt_BR` | — (default only) |
| Portuguese (`pt`) | `pt_PT` | — (default only) |
| Romanian (`ro`) | `ro_RO` | — (default only) |
| Russian (`ru`) | `ru_RU` | `ru_TM` |
| Slovak (`sk`) | `sk_SK` | — (default only) |
| Slovenian (`sl`) | `sl_SI` | — (default only) |
| Spanish (`es`) | `es_ES` | `es_AR`, `es_CL`, `es_CO`, `es_CR`, `es_DO`, `es_EC`, `es_GT`, `es_MX`, `es_PE`, `es_PR` |
| Swedish (`sv`) | `sv_SE` | — (default only) |
| Thai (`th`) | `th_TH` | — (default only) |
| Turkish (`tr`) | `tr_TR` | — (default only) |
| Ukrainian (`uk`) | `uk_UA` | — (default only) |
| Vietnamese (`vi`) | `vi_VN` | — (default only) |
| Chinese (`zh`) | `zh_CN` | — (default only) |
| Chinese (`zh`) | `zh_TW` | `zh_HK` |

### ccd
| Language | Default locale | Regional variation locales |
|---|---|---|
| Czech (`cs`) | `cs_CZ` | — (default only) |
| Danish (`da`) | `da_DK` | — (default only) |
| German (`de`) | `de_DE` | `de_AT`, `de_LU`, `de_CH` |
| English (`en`) | `en_US` | `en_AU`, `en_BE`, `en_CA`, `en_EG`, `en_GR`, `en_HK`, `en_IN`, `en_ID`, `en_IE`, `en_IL`, `en_KW`, `en_LU`, `en_MY`, `en_NZ`, `en_NG`, `en_PH`, `en_QA`, `en_SA`, `en_SG`, `en_ZA`, `en_TH`, `en_AE`, `en_VN` |
| Finnish (`fi`) | `fi_FI` | — (default only) |
| French (`fr`) | `fr_FR` | `fr_BE`, `fr_CA`, `fr_LU`, `fr_CH` |
| Hindi (`hi`) | `hi_IN` | — (default only) |
| Hungarian (`hu`) | `hu_HU` | — (default only) |
| Indonesian (`id`) | `id_ID` | — (default only) |
| Italian (`it`) | `it_IT` | `it_CH` |
| Japanese (`ja`) | `ja_JP` | — (default only) |
| Korean (`ko`) | `ko_KR` | — (default only) |
| Norwegian Bokmål (`nb`) | `nb_NO` | — (default only) |
| Dutch (`nl`) | `nl_NL` | `nl_BE` |
| Polish (`pl`) | `pl_PL` | — (default only) |
| Portuguese (`pt`) | `pt_BR` | — (default only) |
| Russian (`ru`) | `ru_RU` | — (default only) |
| Spanish (`es`) | `es_ES` | `es_AR`, `es_CL`, `es_CO`, `es_CR`, `es_EC`, `es_GT`, `es_MX`, `es_PE`, `es_PR` |
| Swedish (`sv`) | `sv_SE` | — (default only) |
| Thai (`th`) | `th_TH` | — (default only) |
| Turkish (`tr`) | `tr_TR` | — (default only) |
| Ukrainian (`uk`) | `uk_UA` | — (default only) |
| Vietnamese (`vi`) | `vi_VN` | — (default only) |
| Chinese (`zh`) | `zh_CN` | — (default only) |
| Chinese (`zh`) | `zh_TW` | — (default only) |

### express
| Language | Default locale | Regional variation locales |
|---|---|---|
| Danish (`da`) | `da_DK` | — (default only) |
| German (`de`) | `de_DE` | `de_AT`, `de_LU`, `de_CH` |
| English (`en`) | `en_GB` | — (default only) |
| English (`en`) | `en_US` | `en_BE`, `en_CA`, `en_EG`, `en_GR`, `en_HK`, `en_IN`, `en_ID`, `en_IE`, `en_IL`, `en_KE`, `en_KW`, `en_LU`, `en_MY`, `en_MU`, `en_NZ`, `en_NG`, `en_PH`, `en_QA`, `en_SA`, `en_SG`, `en_ZA`, `en_TH`, `en_AE`, `en_VN` |
| Finnish (`fi`) | `fi_FI` | — (default only) |
| French (`fr`) | `fr_FR` | `fr_BE`, `fr_CA`, `fr_LU`, `fr_CH` |
| Indonesian (`id`) | `id_ID` | — (default only) |
| Italian (`it`) | `it_IT` | `it_CH` |
| Japanese (`ja`) | `ja_JP` | — (default only) |
| Korean (`ko`) | `ko_KR` | — (default only) |
| Norwegian Bokmål (`nb`) | `nb_NO` | — (default only) |
| Dutch (`nl`) | `nl_NL` | `nl_BE` |
| Portuguese (`pt`) | `pt_BR` | — (default only) |
| Spanish (`es`) | `es_ES` | `es_AR`, `es_CL`, `es_CO`, `es_CR`, `es_EC`, `es_GT`, `es_MX`, `es_PE`, `es_PR` |
| Swedish (`sv`) | `sv_SE` | — (default only) |
| Chinese (`zh`) | `zh_CN` | — (default only) |
| Chinese (`zh`) | `zh_TW` | — (default only) |

### adobe-home
| Language | Default locale | Regional variation locales |
|---|---|---|
| Czech (`cs`) | `cs_CZ` | — (default only) |
| Danish (`da`) | `da_DK` | — (default only) |
| German (`de`) | `de_DE` | `de_AT`, `de_LU`, `de_CH` |
| English (`en`) | `en_US` | `en_AU`, `en_BE`, `en_CA`, `en_EG`, `en_GR`, `en_HK`, `en_IN`, `en_ID`, `en_IE`, `en_IL`, `en_KW`, `en_LU`, `en_MY`, `en_NZ`, `en_NG`, `en_PH`, `en_QA`, `en_SA`, `en_SG`, `en_ZA`, `en_TH`, `en_AE`, `en_VN` |
| Finnish (`fi`) | `fi_FI` | — (default only) |
| French (`fr`) | `fr_FR` | `fr_BE`, `fr_CA`, `fr_LU`, `fr_CH` |
| Hungarian (`hu`) | `hu_HU` | — (default only) |
| Indonesian (`id`) | `id_ID` | — (default only) |
| Italian (`it`) | `it_IT` | `it_CH` |
| Japanese (`ja`) | `ja_JP` | — (default only) |
| Korean (`ko`) | `ko_KR` | — (default only) |
| Norwegian Bokmål (`nb`) | `nb_NO` | — (default only) |
| Dutch (`nl`) | `nl_NL` | `nl_BE` |
| Polish (`pl`) | `pl_PL` | — (default only) |
| Portuguese (`pt`) | `pt_BR` | — (default only) |
| Russian (`ru`) | `ru_RU` | — (default only) |
| Spanish (`es`) | `es_ES` | `es_AR`, `es_CL`, `es_CO`, `es_CR`, `es_EC`, `es_GT`, `es_MX`, `es_PE`, `es_PR` |
| Swedish (`sv`) | `sv_SE` | — (default only) |
| Thai (`th`) | `th_TH` | — (default only) |
| Turkish (`tr`) | `tr_TR` | — (default only) |
| Ukrainian (`uk`) | `uk_UA` | — (default only) |
| Vietnamese (`vi`) | `vi_VN` | — (default only) |
| Chinese (`zh`) | `zh_CN` | — (default only) |
| Chinese (`zh`) | `zh_TW` | — (default only) |

### commerce
| Language | Default locale | Regional variation locales |
|---|---|---|
| Czech (`cs`) | `cs_CZ` | — (default only) |
| Danish (`da`) | `da_DK` | — (default only) |
| German (`de`) | `de_DE` | `de_AT`, `de_LU`, `de_CH` |
| English (`en`) | `en_US` | `en_AU`, `en_BE`, `en_CA`, `en_EG`, `en_GR`, `en_HK`, `en_IN`, `en_ID`, `en_IE`, `en_IL`, `en_KW`, `en_LU`, `en_MY`, `en_NZ`, `en_NG`, `en_PH`, `en_QA`, `en_SA`, `en_SG`, `en_ZA`, `en_TH`, `en_AE`, `en_VN` |
| Finnish (`fi`) | `fi_FI` | — (default only) |
| French (`fr`) | `fr_FR` | `fr_BE`, `fr_CA`, `fr_LU`, `fr_CH` |
| Hungarian (`hu`) | `hu_HU` | — (default only) |
| Indonesian (`id`) | `id_ID` | — (default only) |
| Italian (`it`) | `it_IT` | `it_CH` |
| Japanese (`ja`) | `ja_JP` | — (default only) |
| Korean (`ko`) | `ko_KR` | — (default only) |
| Norwegian Bokmål (`nb`) | `nb_NO` | — (default only) |
| Dutch (`nl`) | `nl_NL` | `nl_BE` |
| Polish (`pl`) | `pl_PL` | — (default only) |
| Russian (`ru`) | `ru_RU` | — (default only) |
| Spanish (`es`) | `es_ES` | `es_AR`, `es_CL`, `es_CO`, `es_CR`, `es_EC`, `es_GT`, `es_MX`, `es_PE`, `es_PR` |
| Swedish (`sv`) | `sv_SE` | — (default only) |
| Thai (`th`) | `th_TH` | — (default only) |
| Turkish (`tr`) | `tr_TR` | — (default only) |
| Ukrainian (`uk`) | `uk_UA` | — (default only) |
| Vietnamese (`vi`) | `vi_VN` | — (default only) |
| Chinese (`zh`) | `zh_CN` | — (default only) |
| Chinese (`zh`) | `zh_TW` | — (default only) |

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should probably locate the source of truth directly in locale.js, to avoid duplication / integrity issues

Files were previously under .claude/ (skipped by prettier's default
dot-dir ignore); now checked at skill/, so normalize tables, emphasis,
and list indentation to satisfy the Check Formatting CI.
@afmicka
afmicka merged commit a012c6b into main Jul 27, 2026
27 of 33 checks passed
@afmicka
afmicka deleted the MWPW-198143 branch July 27, 2026 12:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants