The Dark Arts of Skill Engineering — Paul Bakaus, Renaissance Geek (Impeccable)
Read the talk
The Dark Arts of Skill Engineering
Paul Bakaus explains how Impeccable grew from a design prompt into a harness extension, using independent critics, creative seeds, selective instructions, persistent context, scripts, hooks, and browser feedback. Making those mechanisms work across models requires more than portable prose—and some design judgments still need human eyes.
From a talk by Paul Bakaus
At a glance
Ideas worth remembering
Separate visual judgment from deterministic defect detection. Independent reviewers prevent a linter’s issue count from becoming the whole assessment of a design.
Unexpected seeds change generation’s starting point. Discarding safe choices, generating a broad pool with independent ranking, and script-selected colors push beyond repeated defaults in different ways.
Load instructions for the current job and design register; save critiques and user preferences so later sessions can build on earlier decisions.
Scripts can return environment-specific next steps, while hooks validate edits automatically. Pre-tool hooks can block a write; post-tool feedback depends on the model repairing it. Ignore rules accommodate false positives.
Portability requires adapting execution behavior as well as text. Delegation permissions, question tools, task completion, hooks, and model tendencies affect whether the workflow works.
Evaluate software behavior, agent procedures, and individual rules separately. Aesthetic judges can reward the wrong preferences, so Bakaus uses them for a first pass and retains human evaluation.
A quick design is only the beginning
Coding agents could quickly produce something Paul Bakaus could look at. Getting that result back into an enterprise app’s design system was much harder. His first skill, Normalize, addressed that gap: bring what Claude generated back into the existing design language. More design skills followed, eventually becoming Impeccable, an open-source package that extends coding agents into a design workflow. 1:09
The opening example is a fake children’s iPad reader app built with Claude Code and Anthropic’s front-end design skill. Its italic serif, capitalized hero, small eyebrow label, and beige background make a recognizable combination. Bakaus calls the background “Claude Beige.” Each choice can work individually. The problem is that apparently creative generation keeps arriving at the same recognizable style.
A list of bans can move that style without solving the repetition. Forbid Inter, and the model reaches for its next familiar font. Forbid purple gradients, and another common look takes over. Bakaus connects this to shipping jQuery UI’s orange default theme: he expected users to customize it, and instead watched them keep it. He also attributes the prevalence of purple gradients to Tailwind’s sample styling. These are his explanations of how defaults spread, rather than a measured account of their relative influence. 5:16
“The median is the model’s gravity.” In this framing, even 250 carefully written lines of skill prose do too little to pull a model away from familiar choices. The useful shift is to treat a skill as an extension of the harness: the surrounding tools and execution environment. A skill can run code, separate contexts, store results, intercept edits, and connect interfaces. The workshop’s nine techniques add mechanisms that a packaged prompt alone cannot supply.
Suggest correction
This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.
1. Keep the critics blind until synthesis
Reviewing a design in the thread that created it invites anchoring: the model already has a story about why its decisions were good. Adding a deterministic linter introduces another anchor. A beautiful page might have 500 detectable polish issues and receive an unduly harsh overall judgment. An empty or ineffective page might trigger no checks and receive an undeserved endorsement. Issue count and design quality answer different questions. 8:15
Impeccable’s critique separates those questions into two subagents that do not see each other’s work:
- Design director: An LLM uses available browser tools to assess hierarchy, familiar AI styling, and design heuristics.
- Detector and evidence collector: A second agent runs deterministic checks for contrast, font count, and spacing near an element’s edge, while collecting browser evidence.
The main thread waits for both results and synthesizes one critique. Keeping the visual assessment independent prevents the detector’s findings from deciding the aesthetic judgment before it begins. 10:20
Where does independence enter the review? The diagram separates the assessments before they reach the main thread. There is no exchange between reviewers: disagreement becomes material for synthesis rather than something one reviewer absorbs from the other.
The architecture also depends on permission to delegate. In the Codex setup Bakaus tested, subagent use required an explicit user request. Impeccable therefore asks when the capability exists but permission is missing, and requires a reduced review to be described as a degraded experience. That makes silently omitting the second reviewer less attractive. The live Cursor attempt produced a critique, but Bakaus could not establish whether it had spawned the intended subagents; the demonstration illustrates the output format rather than confirming the two-reviewer execution.
The same separation can serve code review, security audits, planning, or ranking generated outputs. The workshop repository contains a starter kit and a demo page in its dark arts materials. These provide a way to build a small version of the machinery around an ordinary page and follow the workshop’s checkpoints.
A landing page or other design supplied to the critique command.
Visual judgment and detectable defects meet only after each reviewer has formed its own assessment.
Suggest correction
This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.
2. Give generation an unexpected starting point
A ban leaves the model choosing among familiar alternatives. An anti-attractor, Bakaus’s term, introduces something the model would not have selected for itself. The seed can come from the user or a script. Its job is to change the starting point of generation, so the next design develops along a different path. 16:59
Three approaches vary in how they push that change:
- Discard the safe picks: Ask for the model’s top three fonts, throw those choices away, and repeat the exercise three times. This removes several easy answers, though convergence eventually returns. It is a selection exercise; it does not modify the model’s weights.
- Generate broadly, rank independently: For Radiant Shaders, a library intended to contain around 100 shaders, requests for 10 new ideas kept returning familiar concepts. Celebrity-inspired prompts—what would Rihanna or Beyoncé look like as a shader?—supplied a different creative starting point. The model then generated 100 ideas, and a fresh subagent ranked them without inheriting the generation thread’s attachments.
- Choose a seed outside the model: Impeccable’s
color.jsdraws from over 100 hand-selected primary colors. These are starting colors, not finished palettes. The model builds a palette around the returned color, and the user can reject the proposal.
The shader example changes both creation and selection. The celebrity prompt interrupts the repeated idea pattern; a larger pool makes more alternatives available; a separate ranking context can reorder that pool without defending ideas it just produced. The color script achieves a related effect with a smaller intervention: the same brief can develop differently because its initial color came from outside the model’s usual choice. Diversity still needs judgment. The user decides whether the different result is useful.
Suggest correction
This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.
3–4. Load the right rules, then remember what happened
As a general-purpose skill grows, its instructions can blur together. A rule to avoid system fonts can make sense for a landing page trying to establish a distinctive brand, while a product interface may benefit from feeling native. Putting both cases into an expanding set of conditional instructions consumes context and makes the applicable rule harder to follow. 20:59
Impeccable uses a mixture-of-experts analogy for routing instruction files. There are two choices:
- Route by job:
critiqueandpolishload different Markdown files for their respective tasks. - Route by design register: The brief determines whether the work concerns attention-seeking brand design or the product itself. Each register loads different rules.
This is selective loading of skill instructions. A product interface does not have to carry every landing-page instruction into its design decisions.
Selective context addresses the current task. Files address the next session. Impeccable stores critiques in a .impeccable folder at the repository root, ignored by Git by default. A later request to polish the page can read the earlier critique even when the original conversation is gone. Multiple critiques also provide a history of the page’s progression. 22:59
That history can include disagreement. If the user rejects a critique and wants to keep a font choice, the skill can record the preference and stop treating it as an unresolved mistake. The mechanism is ordinary persistence: save the useful result, then reload it as context. Bakaus applies a similar approach to refactoring across sessions, taking one TSX file and its surrounding connections at a time while accumulating enough context to continue through the codebase.
Suggest correction
This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.
5. Let scripts return the next action
A skill built for one model may rely on instruction-following behavior other users never get. Bakaus observed weaker models failing to load required Markdown files or start live mode, particularly as skills became longer. Impeccable therefore combines prose with scripts that run at specific moments and return instructions tied to the actual environment.
Each invocation runs context.mjs. It gathers product-strategy and design documents and inserts their contents into the session. Product strategy supplies questions such as who the audience is and what the product should achieve—often more useful input than a preference for rounded borders. If a needed document is missing, the script returns structured JSON describing the absence and what the model should do next. It can also detect an available skill update and tell the model to ask the user before updating. 27:17
A fresh tool result says what matters now, whereas a rule buried in an instruction file must be remembered and applied. Bakaus found instructions returned on standard output more effective at steering the next step. That makes the technique useful for onboarding, environment setup, repository-state checks, and other flows where the correct action depends on something a script can inspect.
Dynamic output carries a caching tradeoff. The later Q&A narrows the warning: the static skill can still be cached; the changing shell result inserted into the conversation cannot be treated as the same static content. Bakaus favors the technique for interactive work, while warning against expecting the entire invocation to remain cacheable across repeated runs. 51:03
Suggest correction
This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.
6. Put validation on the edit path
Even a useful skill does nothing when the agent forgets to invoke it. Impeccable’s design hooks move validation onto the edit path, so checks run without the user remembering a command. In the workshop’s implementation, the installer configures hooks for Claude Code, Cursor, Codex, and GitHub Copilot. A design linter supplies feedback when generated code violates the chosen rules. 29:41
Hook timing changes what the system can enforce:
- Post-tool hook: The file is written, then the hook reports a problem such as poor contrast. The model must respond by fixing the edit.
- Pre-tool hook: The hook prevents the proposed write from happening. This is heavier-handed, but avoids depending on a model that may ignore feedback after the fact.
Bakaus needed the second approach for some weaker model and harness combinations. Hook syntax and behavior differ by provider, so installation has to configure the appropriate form.
The rules can reflect a project’s design system, ESLint rules, or syntax expectations. In the illustrative hook demo, an image receives a hover zoom effect—a tendency Bakaus associates with Gemini—and the hook flags it so the agent can course-correct. The demo makes normally quiet feedback visible; it is not an independently observed edit-and-repair run.
Blocking edits makes false positives costly. A distributed hook system needs ignore rules rather than assuming every finding is correct. Impeccable supports exclusions at granular levels, including files and individual CSS rules. Users can preserve an intentional exception while keeping the remaining checks active.
Suggest correction
This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.
7. Turn a browser selection into an agent event
Design iteration is awkward when every pixel change has to begin as a chat message. Impeccable’s live mode connects a page interaction to the main agent through the harness’s browser and shell capabilities. It starts a development server and a small live poller, inserts a snippet into the development page, and waits for user input. The implementation described here does not use MCP. 34:38
The crucial step is that the poller stops when an event arrives and returns a standard-output message. The model receives that tool result, recognizes the requested action, and follows the skill’s event-handling instructions. It builds a design for the selected section and sends the result back through the live machinery. Ending the waiting process converts browser activity into something the agent’s tool loop knows how to handle.
The Cursor demonstration follows one selected element through a visible change. Picker mode adds a bar to the page and lets Bakaus select an element. An overlay offers subcommands, each corresponding to a Markdown instruction file, and a control for the desired variation. Pressing Go sends the request. The poller stops, the main thread picks up the signal, and the agent wraps the selected element in special markup before generating CSS-marked variants. The page updates with three alternatives that Bakaus can click through. Accept chooses an alternative; Escape returns to normal mode if none is wanted. 37:35
How does clicking Go in a page produce work in a chat thread? The diagram follows the request through the stopping poller and back to the browser. The alternatives come from an agent turn triggered by a tool result. The page supplies the selection and comparison interface.
The same connection carries annotations, drawn comments, dictated input, inserted elements, and whole-page steering. The browser also provides a place to visualize design documentation as a page rather than leave it as Markdown. The user points at an element or sees a design rule, and the agent receives a more concrete signal.
The browser overlay supplies a subcommand and variation request.
The poller’s completion bridges browser input and the main agent’s tool loop.
Suggest correction
This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.
8. Port behavior, not just instruction files
Symlinking instruction files is convenient for a personal setup. Distributing an interactive skill exposes differences shared text cannot erase. Impeccable’s portability work responds to harness behavior Bakaus encountered during development; these details describe those tested setups, rather than guarantees about every later version. 40:07
Several differences change the workflow directly:
- Delegation: Harnesses differ in who may spawn subagents and in the syntax for predefined agents.
- Questions: Bakaus’s Codex setup exposed its structured question tool only in plan mode. Without explicit instructions to ask, the agent could infer an answer instead of interviewing the user.
- Job completion: Claude Code could resume the agent when a background task finished. For the Cursor and Codex live-mode paths he describes, Impeccable used a foreground task to ensure the result reached the agent, at the cost of blocking the chat thread while it waited.
- Watchers and hooks: Watching a log could be throttled more heavily than waiting on a task, and edit hooks required provider-specific handling.
The browser loop therefore needs a different execution strategy depending on how the harness delivers events.
Models introduce a separate set of differences. Bakaus associates Gemini with image hover animation and Codex with excessive rounding, hairline borders, and unwanted letter spacing. Applying every corrective rule to every model can overcorrect: his example is Claude responding to an anti-letter-spacing instruction by shifting too far in the opposite direction. Impeccable consequently creates harness-specific and model-specific builds, substitutes the appropriate user-question tool, and inserts targeted rules through model-specific XML blocks. 45:36
Compilation only helps if installation preserves its outputs. Bakaus found that npx skills took the first skill directory and copied or symlinked it across harness locations, losing the distinction between builds. Impeccable’s own CLI installs the appropriate version instead. The maintenance cost is real, but a shared folder would discard the adaptations that made the skill portable.
Suggest correction
This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.
9. Make every required step visible
A weaker model can still have opinions; what it may lack is the discipline to follow the user’s procedure. Impeccable loads a Codex-specific instruction file with eight gates, requires each one to be passed, and forbids compressing them. The agent must log each result instead of silently treating a few completed steps as representative of the whole sequence. 47:39
“If the gate can be skipped, it will be.” That is Bakaus’s operational warning about models taking an easier path through difficult instructions. Requiring a result for each gate makes omissions easier to notice; pre-tool hooks, where applicable, go further by preventing an invalid action. These mechanisms provide different strengths of enforcement. A logged gate should not be confused with a tool-level block.
The result is a substantially larger package than the original prompt. Bakaus does not recommend applying all nine techniques to every skill: some are exotic, and some only earn their complexity in particular workflows. Impeccable is open source under Apache 2, making its implementation a useful place to study how prose and executable pieces fit together.
Suggest correction
This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.
Inside the evaluation harness
The Q&A explains how the growing machinery gets tested. Impeccable has LLM-driven end-to-end tests and Playwright tests, useful for checking live-mode scripts. A separate evaluation harness, not open source at the time of the recording, recreates the conditions and tools of Claude Code, Codex, and Gemini, including browser screenshot capabilities. It uses the Claude Code SDK as part of that work. 52:31
Testing a generated page also requires testing the conversation that produced it. Impeccable initialization asks interactive questions, so another LLM acts as the user and answers the agent across turns. A mixture of design judges evaluates the resulting pages. Bakaus runs across 20 niches, including an Italian restaurant, and the models he cares about, with five to ten tests for each on a skill release. He also compares against the front-end design skill to see where behavior becomes better or worse.
Ablation asks a narrower question: does an individual instruction change the behavior it is meant to change? Rules have unique identifiers in XML tags. The evaluation harness removes a rule, runs evaluations across models, restores the rule, and uses the deterministic detector to assess the difference. For a rule about gray text on colorful backgrounds, the feedback loop checks the associated contrast behavior. This connects instruction editing to a detectable consequence instead of assuming another sentence must improve the skill. 54:56
Bakaus describes every line of Impeccable as ablation-tested, but also calls the process harder and more expensive than ordinary evaluation. Testing that the software runs, testing that the agent follows the workflow, and testing whether an instruction contributes to the result answer different questions. A personal skill may not need the full apparatus; a package promising consistent behavior across users has more combinations to account for.
Suggest correction
This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.
A design judge can reward the wrong thing
Functional questions are easier to evaluate than taste. A judge can check whether the right content appears in the first viewport. Asking whether that viewport looks great introduces preferences that may disagree with the user’s. In Bakaus’s experience, a Gemini judge rated the first viewport more highly as more material was crammed into it. A higher score could reward density when the design needed restraint. 56:22
He sometimes inverts a judge’s response when its bias makes a high rating a useful warning. That is a targeted workaround for an observed preference, not a general way to create a reliable taste evaluator. His description of the design-director tool as marginally better than random is a qualitative assessment: it is useful for a first pass, after which he evaluates and annotates results with his own eyes.
Bakaus’s stronger position is that taste may remain fundamentally human because it depends on scarcity and distinctiveness. Once everyone uses the same taste, the result becomes ubiquitous and loses the quality that made it desirable. That is his judgment about the limits of model-level taste, and it echoes the opening problem: a new shared aesthetic can become the next recognizable default.
Suggest correction
This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.
When a skill starts to outgrow the platform
Live mode exposes the limits of the skill format. Bakaus calls it a “Jurassic Park experiment”: could the browser connection be made to work? It worked better than he expected and still had many problems. A first-party harness integration or dedicated tool would be a better home for the interaction than a skill coordinating scripts around existing capabilities. 58:51
A personal skill can target the model and setup its author uses. A public package should work beyond that environment. Bakaus would prefer fewer, better-tested skills to a larger ecosystem of packages that fail when users choose a different model. An audience suggestion raises the possibility of releasing his evaluation tooling, installer, or compiler separately; he treats that as an opportunity, not an announced release.
The discussion of serving skills through MCP remains exploratory. Bakaus had not tried or closely studied the proposal raised by an attendee. His concern is context pollution: extra material from MCP or skills can crowd the session and interfere with the work. That concern reinforces the earlier choice to load instructions selectively, without establishing whether the proposed server-based distribution would cause the same problem.
Packaging is the final unresolved engineering problem. Native marketplaces are provider-specific, and Bakaus reports unreliable updates and caching issues in his experience with Claude Code’s marketplace. Projects such as skills.sh offer a shared distribution route, but the npx skills behavior he encountered did not preserve per-harness compiled builds. He had proposed a change and was still discussing it. Standardizing around a shared installer appealed to him; maintaining his own CLI did not. 62:27
For now, the custom installer earns its place by putting each build and its hooks in the right part of each harness. Once a skill coordinates tools, events, permissions, and model-specific behavior, distribution has to preserve that machinery. Copying the prose is only one part of shipping the capability.
Suggest correction
This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.
Resources
From the talk
The design skill package used throughout the workshop; its site provides a starting point for installing it and studying how the design commands work together.
Contains the talk materials, a starter kit, and a demo page for building a small skill extension through the workshop’s checkpoints.
Related talks
- Don't Build Agents, Build Skills Instead – Barry Zhang & Mahesh Murag, Anthropic
Introduces reusable packages of procedural expertise, providing a foundation for Impeccable’s more elaborate skill machinery.
- Don't Ship Skills Without Evals
Continues the closing question of how to test a skill before distributing it.
- Harnesses in AI: A Deep Dive — Tejas Kumar, IBM
A companion on the execution environments that skills extend through tools and workflow controls.