Tutorial: A Paint App

Step 6: Skills And An Agent

Wire the knowledge to the work, so the right definitions arrive with the right task.

Fourteen definitions describing the product. None of them will ever be loaded unless something points at them.

That is what this step is for. Skills are instructions; context is the wire that hands a skill the definitions it needs.

CanvasRules

The standing rules for touching pixels at all.

src/skills/CanvasRules.psy:

use "@psy/morphic"

import { Canvas, CanvasSurface, StrokeModel } from "../index"

export skill CanvasRules:
    description: The rules for writing to the bitmap.
    when: Use before changing anything that draws.

    context:
        - Paint
        - StrokeModel
        - Canvas
        - CanvasSurface

    prompt:
        Only CanvasSurface writes pixels. If a change seems to need a putPixel
        somewhere else, that is a design problem — say so rather than working
        around it.

        A stroke is one undo step. Snapshot before it starts, never during.

.claude/skills/canvas-rules/SKILL.md:

---
name: canvas-rules
description: The rules for writing to the bitmap. Use before changing anything that draws.
---

# CanvasRules

Only CanvasSurface writes pixels. If a change seems to need a putPixel
somewhere else, that is a design problem — say so rather than working around it.

A stroke is one undo step. Snapshot before it starts, never during.

## Context

Consult these definitions of how the product works:

- `paint` (Paint)
- `stroke-model` (StrokeModel)
- `canvas` (Canvas)
- `canvas-surface` (CanvasSurface)

Two things worth pausing on.

description and when were joined into the single frontmatter line. That is the field the platform reads to decide whether to load this skill, so the trigger has to be there rather than in the body. It is why when is required on skills.

The Context section is the payoff for all of Steps 1 to 5. An agent that picks up CanvasRules is handed the concept, the stroke model, the domain and the component — it does not go looking, and it does not guess.

ImplementTool

Adding a tool is the most common task in this program, so it gets its own skill that builds on the last one.

src/skills/ImplementTool.psy:

use "@psy/morphic"

import { CanvasRules } from "./CanvasRules"
import { Tools, ToolPalette, ColorPicker, DrawingTool } from "../index"

export skill ImplementTool extends CanvasRules:
    description: Add or change a drawing tool.
    when: Use when adding a tool or changing how an existing one draws.

    use:
        - CanvasRules

    context:
        + super
        - Tools
        - ToolPalette
        - ColorPicker
        - DrawingTool

    prompt:
        + super

        A tool is a stamp, not a drawing loop. If you are writing
        interpolation code, StrokeModel already does it — use it.

        Every tool keeps its own options. Adding a size to one tool does not
        touch another.

Two compositions there:

  • context: + super takes the four definitions from CanvasRules and adds four more, deduplicated in precedence order. See +.
  • prompt: + super appends the new paragraphs to the inherited ones rather than replacing them.

.claude/skills/implement-tool/SKILL.md:

---
name: implement-tool
description: Add or change a drawing tool. Use when adding a tool or changing how an existing one draws.
---

# ImplementTool

Only CanvasSurface writes pixels. If a change seems to need a putPixel
somewhere else, that is a design problem — say so rather than working around it.

A stroke is one undo step. Snapshot before it starts, never during.

A tool is a stamp, not a drawing loop. If you are writing interpolation code,
StrokeModel already does it — use it.

Every tool keeps its own options. Adding a size to one tool does not touch
another.

## Builds on

- CanvasRules

## Context

Consult these definitions of how the product works:

- `paint` (Paint)
- `stroke-model` (StrokeModel)
- `canvas` (Canvas)
- `canvas-surface` (CanvasSurface)
- `tools` (Tools)
- `tool-palette` (ToolPalette)
- `color-picker` (ColorPicker)
- `drawing-tool` (DrawingTool)

All four paragraphs, all eight definitions, from two files where the shared half is written once.

WriteInterfaceCopy

src/skills/WriteInterfaceCopy.psy:

use "@psy/morphic"

import { Voice } from "../index"

export skill WriteInterfaceCopy:
    description: Write or revise anything the user reads.
    when: Use when adding or changing any string shown in the interface.

    context:
        - Voice

    prompt:
        Write the copy, then read it back as though you were annoyed and in a
        hurry. Cut whatever does not survive that.
---
name: write-interface-copy
description: Write or revise anything the user reads. Use when adding or changing any string shown in the interface.
---

# WriteInterfaceCopy

Write the copy, then read it back as though you were annoyed and in a hurry. Cut
whatever does not survive that.

## Context

Consult these definitions of how the product works:

- `voice` (Voice)

The agent

src/agents/BuildPaint.psy:

use "@psy/morphic"

import { CanvasRules, ImplementTool, WriteInterfaceCopy } from "../skills"
import { Paint } from "../index"

export agent BuildPaint:
    description: Implement changes in the paint program.

    model: opus

    tools:
        - Read
        - Edit
        - Bash

    use:
        - CanvasRules
        - ImplementTool
        - WriteInterfaceCopy

    context:
        - Paint

    prompt:
        Implement the requested change, then run the tests and say plainly
        what passed and what did not.

        This is a paint program, not a vector editor. Before adding anything,
        check it against the Paint concept — several obvious-looking features
        are deliberate non-goals.

.claude/agents/build-paint.md:

---
name: build-paint
description: Implement changes in the paint program.
tools: Read, Edit, Bash
model: opus
---

# BuildPaint

Implement the requested change, then run the tests and say plainly what passed
and what did not.

This is a paint program, not a vector editor. Before adding anything, check it
against the Paint concept — several obvious-looking features are deliberate
non-goals.

## Skills

Use the following Psy-defined skills when carrying out this work:

- `canvas-rules` (CanvasRules)
- `implement-tool` (ImplementTool)
- `write-interface-copy` (WriteInterfaceCopy)

## Context

Consult these definitions of how the product works:

- `paint` (Paint)

The agent takes only the root concept. Everything else arrives through whichever skill turns out to be relevant, which keeps the agent's own context small and lets the platform load the rest on demand.

Note also that an agent's skill list gets a directing sentence — use the following — where a skill's "Builds on" list does not. An agent is expected to act on its skills; a skill is only declaring its lineage.

Wire up the index

src/index.psy:

export { Paint, StrokeModel } from "./concepts"
export { Canvas, Tools, Files } from "./domains"
export { DrawingTool, Pencil, Brush, Eraser, NewDrawing, SaveDrawing } from "./features"
export { CanvasSurface, ToolPalette, ColorPicker, FileStore } from "./components"
export { Voice, Naming } from "./references"
export { CanvasRules, ImplementTool, WriteInterfaceCopy } from "./skills"
export { BuildPaint } from "./agents"
psy check
check: no problems found in 24 file(s)

Next: Build It

On this page