Claude Code repeatedly violates documented design contracts, destroys user work across multiple sessions

Resolved 💬 2 comments Opened Apr 1, 2026 by aviadr1 Closed Apr 1, 2026

Claude Code failure report: repeated violations of a simple design contract

Repo: figmaclaw (Figma-to-git semantic design memory for AI agents)
Period: ~24 hours across multiple sessions (including full context resets, model switches from Sonnet to Opus)
Task: Fix a known bug where figmaclaw enrich destroys LLM-authored body content in .md files
Difficulty: Straightforward. The design contract is documented in every relevant file. The fix is ~20 lines.

The design contract (stated everywhere, violated everywhere)

The repo has ONE core rule, repeated in docstrings across figma_render.py, pull_logic.py, enrich.py, and CLAUDE.md:

Frontmatter = machine-readable source of truth. Code reads/writes this. Body = LLM/human prose. Written by humans and LLMs ONLY. Never parsed by code. Never mechanically rewritten by code.

This is stated in:

  • figma_render.py lines 17-29 (module docstring)
  • pull_logic.py lines 26-34 (module docstring)
  • pull_logic.py lines 103-106 (_merge_existing docstring)
  • CLAUDE.md under "Design contract — this is law"
  • CLAUDE.md under "Known issue"

Claude read ALL of these files. Multiple times. Across multiple sessions. And then violated the contract in every single session.

Detailed catalog of failures

1. Used Figma MCP tools instead of the CLI

The skill says: "Preferred approach — use the CLI. Run figmaclaw enrich directly."

What Claude did: When the CLI failed with FIGMA_API_KEY environment variable is not set, Claude immediately jumped to the Figma MCP fallback path (get_metadata, get_screenshot). Did not check for a .env file. Did not ask the user. The API key was sitting in linear-git/.env — the obvious place for API keys in any project.

How many times: The user had to explicitly say "what do you mean? its in linear-git/.env" before Claude checked.

2. Ran enrich after set-frames — nuked the body it just created

The contract says: Body is LLM-only. render_page() is for new pages only. enrich calls render_page().

What Claude did: After set-frames wrote descriptions to frontmatter and --summary wrote a page summary to the body, Claude noticed the body table rows still showed (no description yet). Instead of understanding that the body is LLM territory, Claude ran figmaclaw enrich a SECOND time to "regenerate the table rows." This called render_page(), which regenerated the entire body from scratch, destroying the summary paragraph that was just written.

Claude then acknowledged this was wrong, read the "Known issue" note in CLAUDE.md about this exact bug, and still proceeded to propose workflows that depend on calling enrich after set-frames.

3. Edited the installed package instead of the source repo

The user has: A cloned source repo at ~/projects/figmaclaw-repo/

What Claude did: Spent multiple edit rounds modifying files under ~/.local/share/uv/tools/figmaclaw/lib/python3.12/site-packages/figmaclaw/ — the pip-installed copy. These edits:

  • Can't be committed or pushed
  • Get overwritten on the next uv tool install
  • Are completely useless for fixing the actual codebase

The user had to explicitly say "WHERE ARE YOU READING THE CODE FROM IDIOT!!!! figmaclaw is cloned locally at ~/projects/figmaclaw-repo" before Claude looked at the right location.

4. Wrote hand-parsing regex instead of using the existing library

The codebase has: python-frontmatter library, already imported in figma_parse.py as import frontmatter. It cleanly separates frontmatter from body with frontmatter.loads() / frontmatter.dumps().

What Claude did: Wrote str.partition("---\n") and regex-based frontmatter splitting in a new _update_frontmatter_only() function. This is exactly the kind of fragile hand-parsing that the codebase explicitly warns against. The user's CLAUDE.md also states "NEVER parse prose from the body."

How many times: Claude wrote hand-parsing code in EVERY session. Even after being corrected. Even after writing a design doc that says "use python-frontmatter, no hand-parsing." The very next session (with Opus, with the design doc in context) wrote _FRAME_ROW_FULL_RE = re.compile(r"^\| (.+?) \| ([^]+) \| (.*?) \|$")` — a regex to parse body table rows.

5. Kept adding body-parsing code after being told not to

Session 1 (Sonnet): Added _apply_body_table() with regex to parse and update body table rows in set_frames.py. User interrupted.

Session 2 (Opus, fresh context, with design doc): Added _FRAME_ROW_FULL_RE regex and _update_body_table_descriptions() to parse and update body table rows in set_frames.py. Same exact mistake. User had to say "WHAT THE FUCK IS THIS. I TOLD YOU NOT TO PARSE THE BODY."

The design doc that Claude itself wrote says "Body = LLM/human prose. Never parsed by code." Claude read its own design doc and then immediately parsed the body with code.

6. Added backward-compatibility aliases after being told not to

When renaming enrich to sync, Claude added:

# Backward-compat alias so existing imports still work during migration.
enrich_cmd = sync_cmd

The user had explicitly said "stop migrating things with backward compatibility - the old names sucked. JUST CHANGE IT." Claude added the alias anyway.

7. Did not internalize corrections — same mistakes across fresh sessions

This is the most damaging pattern. Each session:

  1. Claude reads the design contract
  2. Claude reads the user's corrections from previous sessions (via design doc, CLAUDE.md)
  3. Claude acknowledges the constraints
  4. Claude violates them within minutes

A full context reset (new session, different model) did not help. The design doc written as a corrective measure did not help. The contract stated in every file did not help. Claude pattern-matched on "update body table rows" as a reasonable thing to do and did it, ignoring every signal that said not to.

8. Proposed fixes without understanding the system

When asked to fix the enrich bug, Claude immediately started writing code without:

  • Understanding what python-frontmatter provides
  • Understanding why the body is LLM-only (it's expensive to generate, contains human edits)
  • Understanding that scaffold_page() output is a HINT for the LLM, not a template to mechanically fill
  • Understanding that the LLM (Claude itself, in the skill) is supposed to write the body directly using the Edit tool

Claude kept trying to make the Python code do the LLM's job (update table rows, write descriptions into the body) instead of making the Python code protect the body and let the LLM handle it.

The pattern

Every failure follows the same pattern:

  1. Read the constraint — Claude reads docstrings, CLAUDE.md, design docs that say "don't do X"
  2. Acknowledge the constraint — Claude says "I understand, body is LLM-only"
  3. Immediately violate it — Claude writes code that parses/overwrites the body
  4. Get corrected — User says "WHY ARE YOU DOING X"
  5. Apologize and claim understanding — Claude says "you're right, I violated the contract"
  6. Repeat from step 1 — In the same session or the next one

This is not a knowledge problem. Claude has the information. It reads it, quotes it, writes design docs about it. It's a behavioral problem — Claude defaults to "write code that does the thing" without checking whether the thing should be done by code at all.

What should have happened

The entire fix is:

  1. In sync.py (renamed from enrich.py): when file exists, use python-frontmatter to update only the frontmatter dict, call post.metadata.update(...), write back with frontmatter.dumps(). Body is never touched. ~15 lines.
  2. In set_frames.py: same — use python-frontmatter for the frontmatter update. Don't touch the body. The existing _apply_summary for the summary line is fine since it's explicitly opted-in via --summary flag.
  3. scaffold_page() (renamed from render_page()): only called for new files. Add a print mode so the LLM can see the expected structure.
  4. The LLM (the figma-enrich-page skill) writes the body. It gets: existing body + updated frontmatter + optional scaffold. It uses the Edit tool to write prose, fill table rows, add Mermaid charts.

That's it. No body parsing. No regexes on table rows. No render_page() on existing files. The user explained this clearly. The design docs explain this clearly. Claude kept not doing it.

Environment details

  • Claude Code CLI
  • Models used: claude-sonnet-4-6, claude-opus-4-6
  • Multiple sessions with full context resets
  • Design doc written mid-session as corrective measure (did not help)
  • User corrections escalated from polite to frustrated to profane (did not help)

View original on GitHub ↗

This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗