Adapto translate
Skill adaptocms/adapto-cms-agent-skills/plugin/skills/adapto-translate
Translate existing Adapto content (Articles, Pages, collection items, Categories, Microcopy) into another enabled language via create-translation. Structural-parity gate blocks broken translations; glossary-aware; single-item and corpus modes. Plan-then-apply; runs at the top model tier.From its SKILL.md
npx -y skills add adaptocms/adapto-cms-agent-skills --skill adapto-translateAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
2 things to look at
- 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
- runs commandsInstructs the agent to run 7 commands, including `adapto auth orgs --json` and 6 more.
SKILL.md
9.8 KB, ~2.4k tokens by cl100k_base, as published. Nobody here has run it
adapto:translate
Translates existing content into another already-enabled language, linked to the source via
translation_of_id. A structural-parity gate prevents broken translations (lost paragraphs, dropped
markup/media, mangled placeholders). Works single-item or across a corpus.
Model tier (hard rule): the translation step runs at the top tier (Opus-class) — lower tiers silently destroy meaning (§7 / sub-agents.md). If the current session/sub-agent can't run at the top tier, warn and stop; never translate at a lower tier.
When to use
- "Translate this article/page into
<lang>", "localize my site into<lang>", "translate the blog corpus". - After source content exists (e.g. from
adapto:content-seed) and the target language is enabled on the tenant.
When not to use
- Adding/enabling a new language — that's
adapto project update --languages(a project setting, and a replace-not-append one — conventions §5), not this skill. Translate only into already-enabled codes. - Creating source content →
adapto:content-seed. - Just checking the environment →
adapto:doctor.
Inputs
- Source item(s) by id or slug (
get/get-by-slug/list). - Source + target language. The target must be enabled on the tenant — discover via
adapto auth orgs --json; an unsupported target → stop and offer to enable it as a separate, confirmed step (adapto project update --languages <existing + new>— conventions §5). Never enable one mid-run. - Glossary
_adapto_glossaryif present (cache to.adapto/glossary.md) — its terms/brand names are preserved verbatim. Optional; proceed without if absent (note it wasn't applied). - Project context (
.adapto/project.md/_adapto_project_config) for voice consistency. - Mode: single-item (
<type>+ id/slug) or corpus (<type>+ filter, e.g.--status published).
Outputs
- Translated entries created via
create-translation(linked bytranslation_of_id,slug = source slug). - A local per-language draft at
.adapto/drafts/<YYYY-MM-DD>-<slug>.<lang>.md(frontmatter withlanguage+translation_of, and the translated body) — the reviewable file artifact, matching howcontent-createwrites originals so a translation isn't reviewable only in the CMS. - For pieces that have one, a target-language
_adapto_seoitem (meta/OG/JSON-LD localized), and the ledger updated (pieces[].translations[<lang>]). - A report of written + skipped (with parity-failure reasons). Article translations carry
ai_generatedprovenance. - Next step: suggest reviewing the per-language drafts (the local md or the dev server), then
adapto:publishto take them live. Offer to translate into another enabled language too.
Preconditions
- Preflight with the
adapto:doctorchecks. - Hard-block on an authenticated CLI (
adapto auth me) and a selected tenant — this skill writes. Confirm the working tenant first; never assume the active one. - Top model tier required: if the session/sub-agent can't run at Opus-class, warn and stop — don't translate at a lower tier.
adaptoCLI>= 0.1.3.
Plan phase
Generate + validate; no CMS writes yet.
- List the items to translate (per type), source → target language, counts.
- Translate each item — Opus-class. Translate human-readable text only; preserve HTML markup,
paragraph breaks, media placements, references/ids, dates, enums, and glossary terms. Microcopy:
translate the
valueonly — never thekey. Apply the prose-standards.md principles in the target language (§6: active voice, no filler, no formulaic contrasts) — never introduce slop the source doesn't have, and never rewrite a slop-y source (structural parity wins). - Type-aware structural-parity gate (deterministic, on the generated output):
Articles / Pages (HTML content): paragraph count, HTML-tag count, media-placement count must match source. Collection items: HTML/rich_text fields get the HTML parity check; plain-text non-empty; non-text fields copied unchanged. Categories: HTML description → tag-parity; else non-empty. Microcopy: key unchanged AND interpolation tokens ({x}, {{x}}, %s, %d) preserved exactly. All types: every glossary term appears verbatim in the output. Mismatch on any check → SKIP that item and report the reason; never write a broken translation. - Present a per-item pass/skip summary + a few spot-check diffs (source vs translation), then wait for
one explicit
approve. No cost/token figures. Nothing passes / empty set → say so and stop.
Apply phase
Write the passing translations. slug = source slug, --language <target>. --json on every call.
SESSION_ID="agent_$(date -u +%Y-%m-%dT%H-%MZ)_$(printf '%04x' $RANDOM)" # for Article --source
adapto articles create-translation <source_id> --title "<t>" --content "<HTML>" --slug <slug> \
--author "<author>" --language <target> [--summary "<s>" --tags "<tags>"] \
--source '{"type":"ai_generated","name":"'"$SESSION_ID"'"}' --json
adapto pages create-translation <source_id> --title "<t>" --content "<HTML>" --slug <slug> \
--language <target> [--menu-label "<m>" --tags "<tags>"] --json
adapto collections items create-translation <cid> <source_id> --title "<t>" --slug <slug> \
--language <target> --data-json '<translated text fields; non-text copied>' --status draft --json
adapto categories create-translation <source_id> --name "<n>" --slug <slug> --language <target> \
[--description "<d>"] --json
adapto microcopy create-translation <source_id> --key <unchanged_key> --value "<translated>" \
--language <target> [--tags "<tags>"] --json
# Idempotency — before creating, check existing translations for the target language:
adapto articles translations <source_id> --json # (and the analogous `<type> translations <id>`)
- Idempotent: skip items already translated into the target language (or offer to update).
- Translate the piece's SEO metadata too. If the source has an
_adapto_seoitem, translate its text fields (meta_title,meta_description,og_*, and the human-readable text insidejson_ld) — Opus, with HTML parity on any markup — and create/update the target-language_adapto_seoitem (keeptarget_slug,content_type,content_id, and enums unchanged). Then record it in the ledger (pieces[].translations[<lang>]= the new content + seo ids/status). - ⚠️
articles/pagescreate-translationhave no--statusflag — the translation may inherit the source status, so translating a published item could publish the translation. The batch approval-before-write is the safety gate; this is an item to verify live (don't assumedraft). Collection items support--status draft. - Persist a local draft for each written translation:
.adapto/drafts/<YYYY-MM-DD>-<slug>.<lang>.md(frontmatter withlanguage+translation_of: <source-slug>, and the translated body) — so translations are reviewable as files like originals, not only in the CMS/dev server. - Report written + skipped (with parity reasons) — judge success from each call's
--json, not the shell exit code, and end the loop exit 0 on success so a clean batch never shows a redError: Exit code 1(§8). - Then restart the dev server (stop→start) and keep it running so the user sees the new translations — never kill it (starters sync content at startup — §14).
Errors and recovery
- Target language not enabled → stop; list the tenant's enabled codes. Enabling one is possible
(
adapto project update --languages) but it's a separate confirmed step and the flag replaces the whole set — pass existing + new, never just the new code (conventions §5). - Source not found (bad id/slug) → stop with the lookup error.
- Parity mismatch → skip that item, report the failing check; never write it. Offer a re-translate retry.
- Partial failure in a corpus loop → report what was written, then stop (re-run is safe — idempotent).
- Glossary missing → proceed without it; note it wasn't applied.
- Not authenticated / no tenant → stop; offer both auth paths —
Log inorRegister(conventions.md §11) — then tenant selection. - Top model tier unavailable → warn and stop; don't downgrade.
Forbidden actions
- Never translate at a lower model tier — translation is Opus-class only.
- Never write a translation that fails the structural-parity gate.
- Never introduce AI-tell prose the source doesn't have (prose-standards.md §6) — and never "fix" the source's prose at the cost of parity.
- Never translate a microcopy
key(it's an identifier) — only thevalue. - Never invent or "enable" a language — translate only into tenant-enabled codes (§5).
- Never omit
--sourceon an Article translation (it would mislabel asinternal/CLI). - Never write without an approved plan; never assume the working tenant.
- Never modify the scaffolded read-client (forbidden-actions.md).
What ships with it
Read from the repository
Just SKILL.md. No reference files, no scripts.