Skip to content

Caretize CLI

@caretcms/caretize scans .astro templates and proposes data-caret bindings. It can also add editable() wrappers to data arrays. Before writing, it confirms that each changed template still parses as valid Astro.

Template text remains the default until an editor saves an override. Caretize only marks which elements are editable.

Terminal window
npx @caretcms/caretize init

For projects that don’t have CaretCMS yet:

  1. Installs @caretcms/core
  2. Wires caret() into astro.config.mjs
    • Static Astro projects: caret({ delivery: 'static' }) — no SSR adapter
    • Server projects (output: 'server' already): keeps or adds adapter wiring
  3. Scaffolds .env with a generated CARET_SESSION_SECRET

Existing configs are only edited via verified pure insertions (shown as a diff you confirm, backed up first). When the config shape isn’t safe to touch automatically, caretize prints a snippet to paste instead.

After init, run caretize again to tag templates (or continue manually).

Terminal window
# preview only — no writes
npx @caretcms/caretize --dry-run
npx @caretcms/caretize --diff
# default: apply safe edits, then show a diff you can undo
npx @caretcms/caretize
# approve each change before writing
npx @caretcms/caretize --review

By default Caretize writes changes that pass its confidence and syntax checks, then prints a before/after diff. Use --dry-run to inspect without writing. If the result isn’t what you wanted:

Terminal window
npx @caretcms/caretize --restore # revert the most recent run from .caret/.caretize-bak/

Use --review when you want to approve every binding interactively before anything hits disk.

Target Result
Pure-text leaf elements (h1h6, p, li, a, button, …) data-caret="collection::id::field"
<img src="…"> data-caret on the image element, bound to its URL field
Static const items = [...] arrays in frontmatter editable("collection::id::field", [...]) wrap
Mixed inline markup (with --rich) data-caret-rich for sanitizer-safe formatting
Styled spans (with --rich-class) data-caret-rich once those classes are listed in allowedClasses
getCollection().map() loops (with --bind-collections) Per-row data-caret on {item.data.field} leaves
Dynamic routes (with --bind-routes) Binds [slug].astro detail pages via getStaticPaths props
Named-import loops, astro:assets <Image> / <Picture> Tagged when patterns match (included in --all)

Field names can be derived from visible text ("Our Programs 🎨"our_programs). Names are deterministic and won’t collide with existing bindings — re-runs are idempotent on already-tagged elements.

Some patterns need explicit flags (or --all):

Flag Additional changes allowed
--bind-collections Collection list loops rendered inline
--bind-routes Dynamic collection-detail routes
--rich Mixed-content blocks → data-caret-rich
--rich-class Rich blocks whose inline children carry a CSS class (implies --rich)
--min-confidence low Lower-confidence candidates (included in --all)
--all Every tier above at once — review the diff afterward

When --rich-class finds classes that would be stripped by the sanitizer, caretize prints an allowedClasses snippet to copy into caret():

caret({
allowedClasses: { span: ['gold'], strong: ['big'] },
})

See Inline editing → Rich text.

With --review, each candidate is shown in context:

src/pages/index.astro
<h1> "Launch faster with Acme"
+ data-caret="pages::home::launch_faster_with_acme" (high)
[a]ccept [s]kip [e]dit [A]ll [S]kip-file [q]uit >

Richer tiers skipped in the default pass are offered afterward in an [Y/n/customize] prompt (use --review to approve every tag up front).

  • Verified before write: every output must re-parse as valid Astro and be a pure insertion of the original bytes.
  • All-or-nothing per run: if any file fails verification, the run aborts with nothing written.
  • Backups: each written file is copied to .caret/.caretize-bak/ first.
  • Preflight: caretize checks that @caretcms/core is wired in astro.config.mjs and may recommend explicit delivery: 'static' for static output. Core 0.5.0 also supports automatic delivery detection.
caretize [path] [options]
caretize init
init wire CaretCMS (deps + astro.config + .env)
path file or directory (default: src/)
--review approve each change before writing
--dry-run print the plan, write nothing
--diff preview exact before→after, write nothing
-y, --yes auto-accept at/above min-confidence
--min-confidence <lvl> high (default) | medium | low
--no-images skip <img> elements
--no-props skip hoisting static component-prop strings
--bind-collections bind getCollection().map() loops
--bind-routes bind dynamic collection-detail routes
--rich tag sanitizer-safe mixed-content blocks
--rich-class tag styled-span rich blocks (needs allowedClasses)
--all every opt-in tier + low confidence
--scope <collection::id> override inferred scope
--report <file> write JSON report
--restore restore most recent backup
  1. npm run dev
  2. Sign in at /admin — with no CARET_EDIT_PASSWORD, a temporary dev password prints in the terminal
  3. Click tagged elements to edit; Studio lives at /admin/cms
  4. Static delivery: Publish, then astro build and deploy (optionally wire delivery.publish.webhookUrl)
  5. Server delivery: visitors see edits on the next request after save/publish