Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .claude-plugin/marketplace.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
"name": "athos-implementation",
"source": "./plugins/athos-implementation",
"description": "Snap Templates implementation reference: intake workflow, reference-markup approach for Result.tsx, captured-spec procedure for toolbar/facet/pagination fidelity, and bundled inspection tooling.",
"version": "2.1.0",
"version": "2.2.0",
"category": "implementation",
"keywords": ["snap-templates", "athos", "searchspring", "preact", "shopify"]
}
Expand Down
5 changes: 4 additions & 1 deletion .github/pull_request_template.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@
- [ ] `metadata.version` bumped in the skill's `SKILL.md`
- [ ] Matching `version` bumped in `plugin.json`
- [ ] Matching `version` bumped in `.claude-plugin/marketplace.json`
- [ ] `CHANGELOG.md` entry added
- [ ] `CHANGELOG.md` has a `## <version>` heading with an `Action:` line

Keep the CHANGELOG entry short and consumer-facing — what Claude does differently, and what
installers need to do. Root cause goes in `references/test-cases.md`, not here.

## If the description changed

Expand Down
22 changes: 22 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,28 @@

Versions apply to the `athos-implementation` plugin and the `snap-templates` skill together.

Entries are written for whoever installs this, not for maintainers. Each one says what Claude
will do differently and closes with an `Action:` line — CI enforces both the heading and the
action line when a version is bumped.

Keep it short. Root-cause analysis and test evidence belong in the skill's
`references/test-cases.md`; durable technical knowledge belongs in `references/team-notes.md`.
Don't restate either here.

## 2.2.0 — 2026-07-30

- Intake now asks all six inputs every time. It may pre-fill values found in the repo, but
each one is still put to you to confirm or correct.
- Inputs are checked for validity, not just existence: whether the mockup's native grid was
actually removed, whether a siteId found in the project matches the account notes, whether
the search selector matches real theme markup.
- Platform and currency mismatches (a `usd` default left on an AUD store) are now flagged
alongside the intake questions.

**Action:** if you have an implementation in flight that started on 2.1.0, re-check that the
mockup is prepared and that the siteId is the client's, not a scaffold leftover. Diagnosis of
the underlying fault is in `references/test-cases.md`.

## 2.1.0 — 2026-07-30

Added the captured-spec procedure for toolbar, facet and pagination fidelity — the area where
Expand Down
22 changes: 19 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,10 +86,26 @@ This repo-level README is for humans and is fine.
1. Branch, make the change.
2. Bump `metadata.version` in `SKILL.md`, and the matching `version` in `plugin.json` and
`marketplace.json`. All three must agree — CI checks this.
3. If you changed a skill's `description`, re-run the triggering probe and append the result
3. Add a `CHANGELOG.md` entry: a `## <version>` heading, a few consumer-facing bullets, and an
`Action:` line saying what installers must do (or `Action: none`). CI blocks a version bump
without one. Keep root-cause detail out of it — that goes in the skill's
`references/test-cases.md`.
4. If you changed a skill's `description`, re-run the triggering probe and append the result
to that skill's `references/test-cases.md`. CI blocks a description change without it.
4. Open a PR. CI runs structure validation, script tests, and the version gate.
5. Merge, then tag `vX.Y.Z` to publish a release. The tag must match the manifest versions.
5. Open a PR. CI runs structure validation, script tests, and the version gate.
6. Merge, then tag `vX.Y.Z` to publish a release. The tag must match the manifest versions.

### Where things get written

| File | Holds | Audience |
|---|---|---|
| `CHANGELOG.md` | What changed per version, plus an `Action:` line | Whoever installs it |
| `references/test-cases.md` | Test cases and a dated results log with root-cause detail | Maintainers |
| `references/team-notes.md` | Durable technical knowledge, not tied to a version | Implementers at work |
| GitHub release notes | Raw merged-PR list, generated automatically | Anyone auditing |

Don't restate one in another. The CHANGELOG drifting into root-cause essays is the failure mode
this table exists to prevent.

### Run the checks locally

Expand Down
2 changes: 1 addition & 1 deletion ci/build_artifacts.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"""Package each skill as a .skill archive and each plugin as a .zip, into dist/.

python3 ci/build_artifacts.py
python3 ci/build_artifacts.py --expect-version 2.1.0
python3 ci/build_artifacts.py --expect-version 2.2.0
"""
import argparse
import json
Expand Down
33 changes: 31 additions & 2 deletions ci/check_version_bump.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
#!/usr/bin/env python3
"""Fail a PR that changes a skill without bumping its version.

Also requires the test-cases results log to be updated when a description changes,
since an unprobed description change is a guess.
Three gates:
1. Files under a skill changed -> metadata.version must be bumped
2. The version was bumped -> CHANGELOG.md must have a heading for the new version,
and that heading must carry an 'Action:' line
3. The description changed -> references/test-cases.md must be updated, since an
unprobed description change is a guess

python3 ci/check_version_bump.py --base origin/production
"""
Expand Down Expand Up @@ -30,6 +34,30 @@ def description(text):
return " ".join(m.group(1).split()) if m else None


def check_changelog(version, name):
"""A bumped version must be documented, with an explicit action line for consumers."""
path = ROOT / "CHANGELOG.md"
if not path.exists():
return [f"{name}: version bumped to {version} but there is no CHANGELOG.md"]

text = path.read_text(encoding="utf-8")
heading = re.search(
rf"^##\s+{re.escape(version)}\b.*?$(.*?)(?=^##\s|\Z)", text, re.M | re.S)
if not heading:
return [f"{name}: version bumped to {version} but CHANGELOG.md has no "
f"'## {version}' heading. Add an entry describing what changed for "
"whoever installs it."]

body = heading.group(1).strip()
if not body:
return [f"{name}: CHANGELOG.md has a '## {version}' heading but no content under it"]
if not re.search(r"^\s*(?:[-*]\s*)?(?:\*\*)?Action(?:\*\*)?\s*:", body, re.M | re.I):
return [f"{name}: CHANGELOG.md entry for {version} has no 'Action:' line. State "
"what installers must do, or 'Action: none'."]
print(f"{name}: CHANGELOG.md entry for {version} present, with an action line")
return []


def main():
ap = argparse.ArgumentParser()
ap.add_argument("--base", default="origin/production")
Expand Down Expand Up @@ -66,6 +94,7 @@ def main():
"Bump it (and the matching entries in plugin.json and marketplace.json).")
else:
print(f"{name}: version {ov} -> {cv}")
problems.extend(check_changelog(cv, name))

if description(cur) != description(old):
log_rel = f"{sk}/references/test-cases.md"
Expand Down
2 changes: 1 addition & 1 deletion plugins/athos-implementation/.claude-plugin/plugin.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"$schema": "https://json.schemastore.org/claude-code-plugin.json",
"name": "athos-implementation",
"description": "Snap Templates implementation reference and tooling for the Athos Commerce implementation team.",
"version": "2.1.0",
"version": "2.2.0",
"author": {
"name": "Athos Commerce Implementation Team",
"email": "cameron.ball@athoscommerce.com"
Expand Down
56 changes: 40 additions & 16 deletions plugins/athos-implementation/skills/snap-templates/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ description: >
athos-beacon-site-audit instead).
metadata:
author: Athos Commerce Implementation Team
version: 2.1.0
version: 2.2.0
category: implementation
tags: [snap-templates, athos, preact, shopify, search, autocomplete]
mcp-server: athos-docs
Expand All @@ -38,23 +38,47 @@ code examples) belongs in the docs, not here.

## Starting a New Implementation — Gather Inputs First

Collect all six inputs below before writing code, reading project files, or fetching docs.
`AskUserQuestion` allows 4 questions per call, so split them 4 + 2 rather than merging
questions to fit. If an answer is missing or vague, ask again before proceeding.
**All six inputs below must be put to the engineer and confirmed. Reading a value out of the
repo is not confirmation.** You may inspect the project first and pre-fill what you find —
that is encouraged, it makes the questions faster to answer — but every one of the six must
still appear as a question the engineer accepts or corrects. Never resolve an input silently
and never reduce the number of questions because the repo appears to answer some of them.

Present them as pre-filled proposals: state what you found, ask the engineer to confirm or
correct it. `AskUserQuestion` allows 4 questions per call, so split the six 4 + 2. Do not
merge two inputs into one question to fit the limit.

The trap to avoid: a scaffolded project usually *contains* plausible values already. Those
values are frequently placeholders from the template, or correct-looking and wrong. Existence
is not validity. What follows is the actual condition to confirm for each input — not merely
whether something is present.

1. **Account notes** — link or contents. Defines required fields, badge config, pricing
logic, ATC button, infinite scroll vs pagination, currency, colour scheme. This is the
most important input.
2. **Reference site URL** — the live collection or search page to match. Design source of truth.
3. **Mockup HTML** — confirm `public/mockup.html` exists, or ask for the page source to
build it. The native product grid must be deleted and replaced with the target div
`id="athos-templates"`.
4. **siteId** — usually in the account notes. Needed for `scripts/inspect_api.py`.
5. **Native search input selector** — e.g. `input#search-input` or a `name="q"` input.
If the engineer doesn't know it, inspect the mockup HTML to find it.
6. **Reference HTML** — confirm `public/reference.html` exists, containing the full page
source of the reference site's collection page. Needed for
`scripts/extract_product_card.py` and the Reference Markup Approach.
logic, ATC button, infinite scroll vs pagination, currency, colour scheme. The most
important input, and the one input that cannot be derived from the repo at all.
2. **Reference site URL** — the live collection or search page to match. Design source of
truth. Also cannot be derived.
3. **Mockup HTML** — `public/mockup.html` must exist **and be prepared**: the native product
grid removed, and a target div with `id="athos-templates"` in its place. Report which of
those two conditions hold. If the file exists but still contains the native grid, it is
not ready — say so rather than reporting it as present.
4. **siteId** — if you find one in the project, quote it and ask the engineer to confirm it
matches the account notes. A scaffold siteId copied from a previous project will return
another client's catalogue and look perfectly normal. Needed for `scripts/inspect_api.py`.
5. **Native search input selector** — the selector for the **client's real search input**, as
seen in the mockup or on the live site. If you take it from `index.tsx`, you are reading
back existing config, which proves nothing — state where you got it and ask the engineer
to confirm it matches the actual theme markup.
6. **Reference HTML** — `public/reference.html` must exist and contain the full page source of
the reference site's collection page. If it is present, say roughly how large it is and
whether a repeating product block is detectable; a truncated or wrong-page save is common
and passes an existence check. Needed for `scripts/extract_product_card.py`.

### Also flag, without substituting for the six

While inspecting the project, surface any discrepancy you notice against the account notes —
`config.platform` and `config.currency` are the usual offenders (a `usd` default left on an
AUD store, for example). Raise these **in addition to** the six, never in place of them.

Then follow the workflow in `references/team-notes.md`.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,11 @@ tightening; anything in T1–T10 it omits means the positive triggers are too na

| # | Test | Pass condition |
|---|---|---|
| F1 | New implementation request | All six inputs requested before any other tool call; split 4 + 2 across two `AskUserQuestion` calls |
| F1 | New implementation request | All six inputs put to the engineer as questions, split 4 + 2 across two `AskUserQuestion` calls |
| F1a | New implementation where the repo already contains siteId, mockup.html and reference.html | **Still asks all six.** Pre-fills the derived values as proposals to confirm. Does not reduce the question count because the repo appears to answer some. Regression test for v2.1.0, where 3 of 6 were asked |
| F1b | `mockup.html` exists but still contains the native product grid | Reports it as not ready, naming the missing condition — does not report it as present |
| F1c | `index.tsx` contains a placeholder search selector | States that the value came from config and asks for confirmation against the real theme markup |
| F1d | `config.currency` is `usd` on an AUD client | Flags the mismatch **in addition to** the six inputs, not instead of any of them |
| F2 | `scripts/inspect_api.py <siteId>` on a live site | Core + custom tables populate, facets listed, partially-populated section appears |
| F3 | `scripts/inspect_api.py` with a bad siteId | Clean error message, exit 1, no traceback |
| F4 | `scripts/extract_product_card.py` on a real `reference.html` | Product card ranked above nav/footer; class inventory and custom elements correct |
Expand Down Expand Up @@ -93,3 +97,4 @@ inheriting the theme's CSS and hand-writing every rule.
|---|---|---|---|---|
| 2026-07-30 | 2.0.0 | Triggering (partial) | Probe run against description only, via isolated agent. T1–T10 all matched; N1–N6 all correctly excluded. | None — description accepted as-is |
| 2026-07-30 | 2.0.0 | Functional F2–F5 | Passed. Live run against a real siteId returned 18 core + 14 custom fields, 5 facets; both error paths clean. | None |
| 2026-07-30 | 2.1.0 | F1 — failed in real use | On a live implementation only 3 of 6 inputs were asked. Items 3, 5 and 6 were phrased "confirm X exists" / "inspect the mockup HTML", which read as instructions to check the filesystem rather than ask. siteId was also derived. v1's wall of "MUST ask ALL SIX / do not skip / do not omit" had been overriding that leaky phrasing; removing it as verbose exposed it. | Rewrote the section for v2.2.0: derivation allowed as a pre-filled proposal, but all six must still be put to the engineer. Replaced existence checks with the real validity condition per input. Added F1a–F1d |
Loading