Building a multi-tenant design system tooling on top of Penpot’s plugin SDK
(via the MCP server, used by an LLM agent to author DS docs/components),
and I’m hitting a hard wall on shape.applyToken().
Context. Working on an open-source firmware project
(openTRNTBL, a Sonos-streaming turntable), the design system is built around Tokens
Studio with 11 sets / 13 themes (light/dark/HC/4 vision modes/density),
imported via drag-drop UI. Now trying to programmatically generate the
token visual documentation directly in Penpot using the plugin API.
Bug.shape.applyToken(tok, ['fill']) consistently throws a generic
error on every token type tested (color, dimension, opacity), regardless
of the signature variation:
Call
Result
applyToken(tok, ['fill'])
Field message is invalid
applyToken(tok) (default property)
Field message is invalid
applyToken(tok, 'fill')
Field message is invalid: . Field message is invalid: .
tok.applyToShapes([r], ['fill'])
Doesn't support name: 0
Detailed reproduction steps + analysis in the GitHub issue I just opened:
Workaround currently used. Fall back to Library.createColor() + LibraryColor.asFill() for colors — works fine, but breaks the
token->shape lineage and forces a duplicated layer (Library Colors must
stay in sync with Tokens Studio tokens via external script). For
non-color tokens (dimension, opacity, font-size…), no clean equivalent.
Asking the community:
Anyone using applyToken successfully on the latest 2.15 SDK? If yes,
what’s the magic signature?
Has the Penpot team mentioned this bug or its fix on the roadmap?
Anyone using a different mirror approach (Library + script sync) at
scale and has feedback on the trade-offs?
The bug feels related to the async state race that was fixed in #8698
(theme.addSet) — same generic “Field message is invalid” error pattern.
Curious if anyone else has investigated.