Skip to content

kit-sync skill

The kit-sync skill backs both /kit-sync (bulk install) and /kit-update (safe re-copy). It exists because /kit-add is per-component and /setup is one-time bootstrap — neither helps a developer who wants to vendor the entire kit at once or stay current with upstream changes without losing local edits.

Triggered by/kit-sync, /kit-update, plus phrases like “install all components”, “bulk copy the kit”, “sync the entire kit into my project”, “refresh anything I haven’t touched”
OutputComponent TSX/SCSS, ui.tsx foundation, theme CSS, and .acss-kit/manifest.json
Manifest<projectRoot>/.acss-kit/manifest.json — the source of truth for what was generated

.acss-kit/manifest.json records every generated file’s normalized SHA256 at the moment it was written. Drift detection compares on-disk content to that recorded hash to classify each tracked file as clean, modified, or missing.

{
"schemaVersion": 1,
"pluginVersion": "0.9.0",
"targetDir": "src/components/fpkit",
"stylesDir": "src/styles",
"themeFile": "acss-kit.theme.json",
"generatedAt": "2026-05-03T14:22:11Z",
"files": {
"src/components/fpkit/ui.tsx": {
"source": "asset:foundation/ui.tsx",
"sha256": "<hex>",
"pluginVersion": "0.9.0",
"kind": "foundation"
},
"src/components/fpkit/button.tsx": {
"source": "ref:components/button.md#tsx-template",
"sha256": "<hex>",
"pluginVersion": "0.9.0",
"kind": "component",
"component": "button"
}
}
}

kind is one of foundation (ui.tsx, foundation.css, and every file under foundation/sass/), component (a tracked TSX/SCSS pair), style (a generated theme CSS file), or theme (the user’s seed theme.json).

Drift detection runs SHA256 on normalized content, not raw bytes. The same normalization applies before recording the manifest hash and before comparing on-disk content:

  1. Replace CRLF / CR with LF.
  2. Strip trailing whitespace (spaces and tabs) from every line.
  3. Collapse trailing blank lines to a single trailing newline.

Without normalization, a Prettier or editor save would flip every file to modified immediately. The logic lives in scripts/hash_file.py and is duplicated in scripts/diff_status.py.

FlagEffect
--target=<dir>Override the components directory (default from .acss-target.json, fallback src/components/fpkit).
--styles-dir=<dir>Override the styles directory (default from .acss-target.json, fallback src/styles).
--seed=<hex>Seed colour for theme generation (default: prompt the developer).
--skip-stylesComponents-only sync; do not seed theme.
--dry-runPrint the plan tree, do not write files or manifest.
  1. Step S0 — Exit plan mode. If the session is in plan mode, exit it before any other work. The workflow shells out to detect_target.py, detect_stack.py, and manifest_read.py from Step S1 onward, and plan mode would block those Bash invocations even though they are read-only. The skill only stays in plan mode when the user explicitly asked for a description without running any scripts.

  2. Step S1 — Preflight. Detect project root via detect_target.py; halt if missing. Confirm cssPipeline includes sass via detect_stack.py. Read any existing manifest via manifest_read.py — if present, route every file through the safe-update diff/skip logic before writing.

  3. Step S2 — Enumerate the catalog. Read skills/components/references/components/catalog.md. Every component named in the Verification Status table is in scope, plus the inline catalogue entries (Badge, Tag, Heading, Text/Paragraph, Details, Progress) that have a Generation Contract. Excludes Form (lives as a skill) and UI (foundation) (handled separately as ui.tsx).

  4. Step S3 — Resolve dep tree, dedupe. For each in-scope component, walk its Generation Contract dependencies: recursively. Union all results into one ordered list, leaves first.

  5. Step S4 — Show the plan. Display the full plan (foundation, components, styles, manifest) and wait for confirmation. If --dry-run, exit without writing.

  6. Step S5 — Generate components bottom-up. For each entry: load the reference doc, substitute placeholders, hash the rendered TSX with hash_file.py --stdin before writing, then write. Repeat for SCSS where the contract has one. Re-sync runs route modified files into a skipped list.

  7. Step S6 — Foundation. For each file in scope (ui.tsx, foundation.css, and every file under foundation/sass/), apply the following three-case matrix — the manifest-aware equivalent of the /kit-add Step A4 matrix:

    Foundation file stateAction
    Absent from target dir and absent from manifest (fresh install)Copy ui.tsx, foundation.css, and the full foundation/sass/ tree; hash each file; record each as kind: "foundation" in the manifest; print an import hint
    ui.tsx present, foundation.css absent — regardless of manifest state (existing install)Prompt the developer before copying — explains the CSS reset, @layer ordering, and spacing/shadow tokens; the developer can opt out to avoid the foundation layer
    Both ui.tsx and foundation.css present and tracked in the manifestIf status is clean: overwrite and update the manifest hash. If status is modified: skip and add to the skipped summary
  8. Step S7 — Styles (skipped under --skip-styles). Resolve seed colour (--seed, prior acss-kit.theme.json, or prompt). Run generate_palette.py then tokens_to_css.py to emit <stylesDir>/theme/light.css and dark.css. Write acss-kit.theme.json for re-runs. Hash all three and record. Run validate_theme.py and surface any WCAG failures (non-blocking).

  9. Step S8 — Write the manifest. Pipe the assembled payload to manifest_write.py. The payload carries projectRoot (used to locate the write target — not persisted in the manifest itself), plus pluginVersion (from .claude-plugin/plugin.json), targetDir, stylesDir, themeFile, and a path-keyed files map matching the schema above.

  10. Step S9 — Verify integration. Run verify_integration.py and surface any missing-import reasons as a numbered fix-up list.

  11. Step S10 — Summary. Print created / skipped counts, the manifest path, and next-step hints (/kit-update, /kit-update --check).

FlagEffect
<component>...Restrict the update to a list of components. Default: every entry in the manifest.
--checkReport only — do not write.
--forceOverwrite modified files. Each is backed up to <file>.bak before being overwritten.
  1. Step U0 — Exit plan mode. If the session is in plan mode, exit it before any other work. Even --check runs invoke manifest_read.py and diff_status.py via Bash to produce the report, and plan mode would block them. The skill only stays in plan mode when the user explicitly asked for a description without running any scripts.

  2. Step U1 — Read the manifest. Run manifest_read.py. Halts on exists: false (telling the user to run /kit-sync first) or schemaMismatch: true (no fall-through to fresh-install — that would bypass drift protection on every tracked file).

  3. Step U2 — Compute drift. Run diff_status.py. Capture clean[], modified[], and missing[]. If a positional component filter was supplied, intersect each list with the requested set.

  4. Step U3 — Show the report. Display counts plus the modified and missing lists. If --check, stop here.

  5. Step U4 — Regenerate clean + missing. For each entry: re-run the bulk-install logic for that file’s kind and source, hash the new content, write the file, stage a manifest update.

  6. Step U5 — Handle modified. Without --force, skip and add to the summary. With --force, copy to <file>.bak, regenerate, write, hash, update.

  7. Step U6 — Rewrite the manifest. Pipe the merged payload to manifest_write.py. Existing entries that were not touched keep their previous SHA — no spurious churn.

  8. Step U7 — Summary. Print updated / skipped / recreated counts and the manifest path.

Both workflows write component TSX/SCSS, theme CSS, and the manifest, and they shell out to a dozen Python scripts. Exiting plan mode is therefore an explicit first step — Step S0 for the bulk install workflow and Step U0 for the safe-update workflow — so that the preflight/read scripts (detect_target.py, manifest_read.py, diff_status.py) can run via Bash. Plan mode would block those invocations even though they are read-only.

--dry-run and --check are not reasons to remain in plan mode — those flags suppress writes inside the workflow, but the workflow still has to run detect_target.py, manifest_read.py, and diff_status.py via Bash to produce the plan tree or drift report, and plan mode would block those.

The skill stays in plan mode only when the user explicitly asked for a description without running any scripts at all.

If a user phrase auto-triggers this skill, pick the workflow that fits:

  • “install everything”, “bulk copy”, “vendor the whole kit” → bulk install workflow.
  • “update unmodified”, “refresh clean components”, “safely re-copy” → safe-update workflow.

When ambiguous, the skill asks once: “Bulk install (writes everything) or safe update (only re-copies unmodified files)?”