idml — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited idml (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
An IDML (.idml) file is Adobe InDesign Markup — a ZIP package of XML files (an OCF container, the same family as EPUB). Unpacking it gives you a tree of human- and AI-readable XML you can read, diff, and edit directly, then pack back into a valid .idml that InDesign opens.
This skill uses Python 3 (stdlib only) — no pip install, nothing to set up. Python is the right tool here: it's already on macOS, and editing the unpacked XML is exactly what Claude is good at. The companion script is scripts/idmlutil.py.
Sibling skill: `indd` drives a live InDesign app via ExtendScript. Use `idml` (this one) when you want to manipulate the file's XML offline without launching InDesign; use `indd` when you need InDesign to render, export (PDF/PNG), or convert IDML↔INDD.
A plain zip -r out.idml folder/ produces a file InDesign rejects. The package must contain a mimetype entry that is:
application/vnd.adobe.indesign-idml-package.
InDesign reads those magic bytes from a fixed offset, so order and compression matter. idmlutil.py pack does this for you (every other file is DEFLATED). Always repack with this script, never with a generic zip command.
# Extract an .idml into a folder of XML (default folder: ./workspace)
python3 skills/idml/scripts/idmlutil.py unpack /abs/path/in.idml /abs/path/out_dir
# Repack a folder back into a valid .idml (default folder: ./workspace)
python3 skills/idml/scripts/idmlutil.py pack /abs/path/out.idml /abs/path/src_dir./workspace.unpack clears the destination folder first, so each extraction is clean.pack reads the mimetype from the source folder if present, otherwisewrites the standard constant; it skips .DS_Store.
If the user has the venv convention (.venv/bin/python), use that interpreter instead of python3; never pip install (the script needs no dependencies).
python3 .../idmlutil.py unpack book.idml work/designmap.xml — top-level map tying the package together.Stories/Story_*.xml — the actual text content (paragraphs, runs).The visible words live in <Content> elements.
Spreads/Spread_*.xml — page geometry and frames.Resources/Styles.xml — paragraph/character/object/table styles.Resources/Graphic.xml — colors / swatches, strokes.Resources/Fonts.xml, Resources/Preferences.xml.MasterSpreads/, XML/, META-INF/container.xml.Read/Edit, or Python). Keep itwell-formed UTF-8; don't disturb the self IDs / cross-references unless you know the matching reference.
python3 .../idmlutil.py pack book-edited.idml work/A story's words are split across <Content> runs inside ParagraphStyleRange / CharacterStyleRange elements. To change wording, edit the text inside the existing <Content>…</Content> tags rather than adding or removing runs — that preserves the per-run styling. Special markers like <Br/> (line break) appear between runs; leave them in place.
CJK / non-ASCII text is fine: the XML files are UTF-8, so Japanese content round-trips unchanged (verified — a <Story> containing こんにちは survived unpack→edit→pack intact). Save edits as UTF-8 without a BOM.
Adding a line / paragraph. A forced line break is a <Br /> element between <Content> runs inside one CharacterStyleRange; a new paragraph is a sibling <ParagraphStyleRange>. To add a line, insert <Br /><Content>…</Content> before the closing </CharacterStyleRange> — reusing the surrounding style so the new line inherits formatting (verified: grew a 3-line body to 4 lines this way).
Emphasising part of a line (bold/italic run). Split the run into sibling CharacterStyleRange elements and give the emphasised one a different FontStyle (e.g. FontStyle="Bold" / "W6"), keeping the same <AppliedFont>:
<CharacterStyleRange ... FontStyle="W3"><Content>ポンシェは</Content></CharacterStyleRange>
<CharacterStyleRange ... FontStyle="Bold"><Content>博多「ふくや」の明太子</Content></CharacterStyleRange>
<CharacterStyleRange ... FontStyle="W3"><Content>を使用。</Content></CharacterStyleRange>(Verified: rendered the middle run bold within the same family.)
Swapping a linked image. Placed images are referenced, not embedded. In the relevant Spreads/Spread_*.xml find the <Link … LinkResourceURI="file:/abs/old.jpg" …> and change the URI to the new absolute path. InDesign relinks on open (verified). The other <Link> attributes (LinkResourceSize, LinkImportStamp, modification times) can be left pointing at the old file — InDesign reconciles them on open; you only need to change the URI.
Almost always re-fit after a swap — not just on aspect-ratio change. The image's scale is baked into the parent <Image>'s ItemTransform, computed from the old file's pixel size. A replacement with different pixel dimensions — even at the identical aspect ratio — renders at the wrong scale (e.g. a 2420×1760 photo dropped onto a frame sized for a 220×160 one shows only a tiny crop). So after relinking, re-fit in InDesign via the indd skill:
frame.fit(FitOptions.FILL_PROPORTIONALLY);
frame.fit(FitOptions.CENTER_CONTENT);Matching the aspect ratio just means the re-fit fills cleanly with no awkward crop; it does not remove the need to re-fit. (Verified: same 1.375 aspect, 11× larger pixels, required the re-fit.)
Applying a paragraph style. Styles live in Resources/Styles.xml (<ParagraphStyle Self="ParagraphStyle/body" …>); a story applies one via AppliedParagraphStyle="ParagraphStyle/body" on its ParagraphStyleRange. Creating or restyling paragraph styles, reflowing frames, and building tables (<Table>/<Cell> markup is extremely verbose to hand-author) are far easier in the indd skill than by hand — do structural/layout changes there and edit text/links here.
Vertical Japanese text (縦書き / `vertical-rl`). The writing axis is a per-story attribute on the <StoryPreference> element inside each Stories/Story_*.xml. Set StoryOrientation="Vertical" (the default is "Horizontal") to turn that story 縦書き:
<StoryPreference … StoryOrientation="Vertical" StoryDirection="LeftToRightDirection" />The neighbouring StoryDirection is the bidi axis (LTR/RTL for Hebrew/Arabic) and stays LeftToRightDirection — it does not control vertical vs horizontal, so don't touch it for Japanese. Orientation only changes how text flows inside the frame; frame geometry/position in Spreads/Spread_*.xml is unaffected, and vertical-rl's right-to-left column order is implied by the vertical orientation (no extra attribute). Each frame's story carries its own setting, so flip it on every story you want vertical. (Verified: round-tripping the vertical pokemon_b.idml shows StoryOrientation="Vertical" StoryDirection="LeftToRightDirection" on every vertical story.)
Without launching InDesign you can confirm structural validity:
# mimetype must be the FIRST line and method "Stored"
unzip -v out.idml | head
# or, fully in Python:
python3 - <<'PY'
import zipfile
z = zipfile.ZipFile('out.idml')
i0 = z.infolist()[0]
assert i0.filename == 'mimetype' and i0.compress_type == zipfile.ZIP_STORED, 'bad mimetype entry'
assert z.read('mimetype') == b'application/vnd.adobe.indesign-idml-package'
print('OK — valid IDML container,', len(z.infolist()), 'entries')
PYFor a full visual/render check, hand the file to the `indd` skill: open it (app.open(File('/abs/out.idml'))), then export PNG/PDF and read the image back, or convert it to .indd. That's the authoritative "does InDesign accept it" test.
mimetypeand/or reorder entries, yielding an IDML InDesign won't open. Use the script.
zipfile, os, shutil); works on the systempython3 (3.6+). No third-party packages, no virtualenv needed.
unpack refuses archive entries that would escape the destination folder(zip-slip guard) and recreates empty directories.
self="…" IDs (e.g. a spread referencing astory). If you delete or rename objects, update every reference or InDesign will report a damaged file. Prefer editing values in place over adding/removing objects.
After a round-trip through InDesign (open → export IDML) the same story may move from e.g. Stories/Story_u101.xml to Story_u10f.xml. So locate a story by its content (grep for the text), not by a remembered filename — a hard-coded path will KeyError/404 after a re-export (verified). idmlutil.py unpack always reflects the current names.
render-verification step (via indd) needs macOS + InDesign.
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.