Penpot MCP And Codex Retrospective
This note is a deeper research and opinion surface for the Penpot work done through Codex, local MCP, backend API, and exported .penpot snapshots.
It is intentionally more detailed than a public forum post.
Its job is to:
- preserve why Penpot was attractive for this line of work
- distinguish what actually worked from what only seemed promising
- keep exact evidence references available for later investigation
- support shorter public Penpot posts with a stronger traceable source
This is not a single upstream bug report.
It is a retrospective over one serious integration attempt.
When this note is linked publicly, it should be framed as Ivan's research/opinion surface rather than as an official Penpot bug report or neutral product documentation.
Current Publication Strategy
The recommended publication stack for this material is:
- a focused GitHub issue for one concrete reproducible bug
- a shorter Penpot community forum post for the broader narrative
- this deeper research note as the full evidence and interpretation trail
For public linking, prefer human-facing GitHub blob URLs to this note rather than local file-system paths.
Current public Penpot trace that should be included in that chain:
- API and MCP issues
- Penpot MCP Server showcase + ask for help
- Push the Penpot MCP to its Limits. Join the Beta test!
Additional already-posted public links from this specific workstream should be added here once collected:
- existing GitHub issue for one MCP aspect:
- penpot/penpot issue #8826
- existing Penpot forum posts for related aspects:
- What’s working and what’s missing in Penpot plugins?
- Penpot bug report on text rendering overrides
Why Penpot Was Attractive
Penpot was not approached here as "just another design tool".
The attraction was that it looked like a plausible bridge between:
- Event Modeling and path work
- reusable component and token work
- a live visual projection surface
- AI-assisted inspection and manipulation
- later generated application surfaces
The motivating idea was not shallow design export.
It was closer to:
- penpotDesign -> ingestion -> model
- model -> projection -> artifact
- with Penpot as one of the live projection surfaces
That is, part of the real hope was that a design created in Penpot, or an already-existing design brought into Penpot, could be ingested into the modeling layer and then used as part of real app production rather than treated only as a terminal design artifact.
Motivation Trace
Useful historical references:
- bootstrap the event model from the design surface:
- 019d174f-2c90-79b5-beb8-99077a7d6fe0.toml#L625
- use Penpot for the event model until equivalent in-app functionality existed:
- 019d174f-2c90-79b5-beb8-99077a7d6fe0.toml#L1040
- define a graph/model to Penpot interface:
- 019d174f-2cce-7c36-a16b-4057b71a0212.toml#L22
- prove design export into an app pipeline:
- 019d174e-ea7b-71ca-91ea-5f3ad56b32fd.toml#L148
- represent a screen state as a board built from reusable components:
- 019d174e-ea7b-71ca-91ea-5f3ad56b32fd.toml#L159
- recreate an already-designed HTML screen in Penpot:
- 019d174e-ea7b-71ca-91ea-5f3ad56b32fd.toml#L618
What Worked
The Penpot attempt was not a total failure.
Several things did work well enough to matter:
- live backend API access
- authenticated
.penpotexport through backendexport-binfile - live file/page/board inspection
- board-level visual export on the plugin path
- Penpot as design evidence and projection material
- component-oriented experimentation
Good durable summaries:
- local companion note in adjacent worktree:
NEXUS-EMERGING-main/docs/penpot-live-backend-and-export.md#L1 - local companion note in adjacent repo/branch:
CheddarBooks/docs/laundrylog/event-modeling/penpot-projection.md#L1
What Failed Or Became Too Fragile
The main problem was not one single bug.
It was cumulative workflow fragility.
1. MCP Transport Fragility
The strongest hard log-backed failure was the MCP transport conflict.
Codex hit:
Already connected to a transport. Call close() before connecting to a new transport...
Best exact references:
- local Codex session log:
~/.codex/sessions/2026/03/28/rollout-2026-03-28T02-27-32-019d3320-5d98-7771-9b93-48c49ffc8715.jsonl#L27073 - local Codex session log:
~/.codex/sessions/2026/03/28/rollout-2026-03-28T02-27-32-019d3320-5d98-7771-9b93-48c49ffc8715.jsonl#L27077
Durable interpretation:
- local companion note in adjacent worktree:
NEXUS-EMERGING-main/docs/penpot-live-backend-and-export.md#L100
2. Plugin/API Surface Divergence
The backend API and MCP/plugin were both useful, but they were not interchangeable.
That meant:
- the backend was often the reliable live/export surface
- the plugin path was the stronger live editing surface
- real work had to juggle both rather than trust one unified integration seam
Durable notes:
- local companion note in adjacent worktree:
NEXUS-EMERGING-main/docs/penpot-surface-comparison.md#L1 - local companion note in adjacent worktree:
NEXUS-EMERGING-main/docs/penpot-live-backend-and-export.md#L1
3. Instance Overrides Stored But Not Rendered
This was one of the deeper workflow breakers.
The higher-on-the-ladder reusable seam was correct:
- use
LibraryComponent.instance()
But in the current lab:
- instance text overrides were present in live shape data
- the live canvas still painted the master/default text
- export also painted the master/default text
Best durable references:
- local companion note in adjacent worktree:
NEXUS-EMERGING-main/docs/penpot-surface-comparison.md#L228 - local companion note in adjacent repo/branch:
CheddarBooks/docs/laundrylog/event-modeling/penpot-projection.md#L261
4. Active-Page / Top-Level Placement Quirks
Another major source of brittleness was that top-level board creation and reparenting followed the active page.
That meant automation had to respect Penpot page focus in a way that felt more operational than semantic.
Best durable reference:
- local companion note in adjacent worktree:
NEXUS-EMERGING-main/docs/penpot-surface-comparison.md#L411
Historical trace:
5. Token And Render Uncertainty
Token work and text/render behavior both required explicit skepticism.
Current local durable cautions:
shape.applyToken(...)threw a Penpot-sidecheck error- some text/render paths required resizing or overlays
- whole-page export was not a safe default
Best references:
- local companion note in adjacent repo/branch:
CheddarBooks/docs/laundrylog/event-modeling/penpot-projection.md#L400 - local companion note in adjacent worktree:
NEXUS-EMERGING-main/docs/penpot-surface-comparison.md#L200 - local companion note in adjacent worktree:
NEXUS-EMERGING-main/docs/penpot-live-backend-and-export.md#L140
Why Penpot Was Abandoned For Now
The decision was not:
- "Penpot is useless"
The decision was:
- Penpot was useful research
- Penpot remained good projection and evidence material
- but Penpot was not deterministic enough to be the primary working engine for this phase
The best concise local summary of that shift is:
- local companion note in adjacent repo/branch:
CheddarBooks/docs/laundrylog/html-path-renderer-proving-ground.md#L1
Short reason:
Penpot was abandoned for now because the workflow stopped being deterministic enough for the phase of work being done. MCP transport was fragile, plugin/API behavior diverged, reusable instance overrides were not trustworthy on canvas/export, and automation kept requiring Penpot-specific workarounds. At that point Penpot was producing more integration friction than modeling leverage.
What Replaced It For Now
The active work shifted to deterministic renderers:
- typed F#
- self-contained HTML/CSS
- reviewable file-based artifacts
That replacement direction lives here:
- local companion note in adjacent repo/branch:
CheddarBooks/docs/laundrylog/html-path-renderer-proving-ground.md#L1 - local companion note in adjacent repo/branch:
CheddarBooks/docs/laundrylog/html-screen-renderer-proving-ground.md#L1 - local companion note in adjacent repo/branch:
CheddarBooks/docs/laundrylog/html-screen-path-renderer-proving-ground.md#L1
Suggested Public Post Split
GitHub Issue
Keep it narrow.
Use it for:
- the exact MCP transport/connection failure
Reference:
- local Codex session log:
~/.codex/sessions/2026/03/28/rollout-2026-03-28T02-27-32-019d3320-5d98-7771-9b93-48c49ffc8715.jsonl#L27073
Forum Post
Keep it broader.
Use it for:
- motivation
- what worked
- what failed
- why Penpot was paused
- link to this research note
- link to the narrow GitHub issue
Things Penpot Team Could Investigate
These are the most actionable questions from this work:
- Is the current MCP transport/session model intentionally single-client in the way the observed failure suggests?
- Should plugin-connected + Codex-connected workflows be expected to coexist cleanly?
- Are connected component instance text overrides expected to render immediately on canvas and export in the
LibraryComponent.instance()path? - Are active-page semantics for top-level creation/reparenting intentional or an implementation quirk?
- What is the intended trustworthy token-application contract for plugin-side automation?
Working Rule For Future Notes
When a shorter public Penpot post is created from this work:
- keep the public text concise
- link here for the full trail
- keep exact logs and stronger interpretation here rather than dumping them into the public post