Skip to content

Working with AI Agents ​

Agents use the same CLI you do. There is no MCP server and no tool schema to install. A coding agent already has a shell and a file editor; a slide is a forty-line HTML file, so the agent's own editor is the most precise and cheapest way to change it. dek adds only what an agent cannot do well on its own: seeing how the slide renders, hearing how it reads, and the fragile operations of renaming and reordering.

What the agent reads ​

dekc init writes a short AGENTS.md at the project root, and dekc new, dekc ref, and dekc sync keep it current: the principles, the conventions, what to check before reporting a deck as done, and a pointer to the CLI's own reference. It names no class, token, or layout a theme decides: each deck owns its theme, so the agent reads the deck's own with dekc theme. The only classes it names are the player's state classes, is-current and is-shown, which no theme defines and markup never writes. It stays under a hundred lines. Anything more detailed is pulled from the CLI when needed.

dek owns only the block between <!-- dek:begin … --> and <!-- dek:end -->, and rewrites it in place. Write your team's own notes for agents above or below it; they stay. An AGENTS.md you already had keeps its text and gets dek's block appended.

bash
dekc help --agent

That is enough for Claude Code, Codex, OpenCode, or any other agent to work in a dek project with no extra configuration.

Before the project: llms.txt and the skill ​

An agent that does not know dek yet, or works outside any project, has two ways in.

  • llms.txt says how to install and run dek, what every page of these docs covers, how many lint rules there are, and every command as dekc help --agent prints it. It is built from the docs, the rule table, and the commands with bun run llms, and a test fails while the published copy is out of date.
  • The official skill teaches the loop: script first, then one slide at a time with dekc show, an edit, dekc check --shot, and dekc lint --visual, and when to stop. It also covers the traps: the command is dekc, not dek, and dek runs on Bun, with bunx, not npx. It names only commands every dek since 0.2 has, and sends the agent to dekc help --agent and AGENTS.md for the rest, so an older dek in a project is never told to run what it lacks.
bash
npx skills add hajimism/dek

The skills CLI installs it for the agents it supports. In Claude Code, /plugin marketplace add hajimism/dek and then /plugin install dek@dek install it as a plugin. The npm package ships the same file, so a project always has the copy for its own dek at node_modules/@hajimism/dek/skills/dek/SKILL.md. There is no MCP server; the skill teaches the CLI. Both are in English, like AGENTS.md; an agent answers in whatever language you write to it.

What the CLI promises ​

  1. Every result command accepts --json, and every result has one shape. An agent branches on ok, reads error when it is false, and works through diagnostics. dekc and dekc rehearse stay running and are the only exceptions: given --json, they refuse at once rather than start a server a JSON reader would wait on forever. Nothing forces an agent to parse prose; the contract is below.
  2. Every error names the next command. "slides/intro.html is missing; run dekc sync." The hint is something you can run as-is, from wherever you ran the command: a command that takes a deck names it when you are not inside that deck, as dekc theme demo at the project root. Diagnostics carry a hint too when the fix is known, such as use hook, turn, or 1-2 for a data-step that names no beat.
  3. dekc help --agent is a few hundred tokens. The CLI documents itself.
  4. AGENTS.md stays short.

The JSON contract ​

Success is { "ok": true, ... } with exit code 0. Failure is { "ok": false, "error": { ... }, ... } with exit code 1, whether the command could not run or lint and check found an error:

json
{ "ok": false, "error": { "message": "deck \"nope\" not found", "path": "decks/nope", "hint": "run `dekc ls`" } }
json
{
  "ok": false,
  "error": { "message": "lint found 1 error", "hint": "fix each error in diagnostics, then run `dekc lint` again" },
  "diagnostics": [
    {
      "id": "DEK011",
      "severity": "error",
      "message": "slide contains an onclick attribute",
      "path": "slides/intro.html",
      "line": 6,
      "column": 11,
      "slug": "intro",
      "hint": "remove it; a slide takes no input, and motion goes in slides/intro.ts as a draw(t) function",
      "data": { "kind": "attribute", "name": "onclick", "value": "go()" }
    }
  ]
}
  • error always has a message, a hint whenever dek knows the next step, and path and line when the failure has a place.
  • Commands that report diagnostics (lint, check, build, ls, cues) always carry a diagnostics array, pass or fail. Each diagnostic has its severity, a path, line, and column when it has a place, a hint when the fix is known, and the values its message names as data. Only errors fail; warnings alone are "ok": true.
  • A check that did not run is an entry in skipped, never an empty pass: { "check": "rumdl", "reason": "rumdl is not installed", "hint": "bun add -d rumdl; …" }. The field is absent when everything ran. dekc lint without --visual, and dekc build, always list visual: they did not measure overflow or contrast, and the hint is the command that does.
  • A command that writes files for every deck in scope returns a list, one deck or many: build and pdf return outs.
  • dekc lint --format sarif returns the same diagnostics as SARIF 2.1.0.
  • Every command's shape is published as a JSON Schema at cli.schema.json: one entry under $defs per command, plus failure for a line that could not run. Every object is closed, so a field it does not name is a change to the contract. The schema, the CLI's own types, and what dek prints in its tests are checked against one definition, so they cannot drift apart.

While dek is 0.x, the --json shape and the rule ids may still change between releases. A rule id is never reused: a retired id stays retired.

One round trip ​

bash
dekc check architecture --shot
dekc check architecture --voice

check lints one slide, including the rendering rules when Playwright is available, writes a screenshot, and returns the diagnostics and the image path. The path contains a hash of the rendered content, so an agent that opens the returned path never sees a stale image. --voice returns the kana reading and duration for each sentence. Write the HTML, run check, look at the picture, read the pronunciation, fix. Write, see, hear, fix: one loop, closed.

bash
dekc shot --sheet
dekc shot architecture --motion

Two views no single shot gives. --sheet puts the whole deck on one image, for the balance across slides. --motion spreads a slide's beats across time, each held at a few moments through everything it moves, so an entrance that hides text or a line that never draws shows up in stills. Both images are sized to be read whole without being scaled down, and both are cached by what they show.

Without Playwright, check still lints and lists visual in skipped with the reason and a hint that installs it, so an agent never mistakes a skipped measurement for a pass. --voice on a deck without voice/ does the same: voice is skipped with the reason and how to set it up, and the rest of the check still runs.

Anything geometry can decide is a lint rule. Overflow and contrast have definite answers once a browser measures them, and a measured verdict is more reliable than showing an agent a screenshot and asking whether the text fits.

Pointing goes both ways ​

bash
dekc goto architecture
dekc current

After editing a slide, the agent can jump the human's browser to it. When the human says "make the figure on this slide smaller", the agent runs dekc current, learns the slug, and fixes it without asking which slide.

A slug names the slide but not the shape, such as one arrow among eight on a roadmap. For that, the human points at it: a on the dev server, a click on the shape, and a note (how). Then they can say "deal with my notes", and the agent reads them itself:

bash
dekc annotations --json

Each note comes with its number, as the page's markers show it, the human's text, each element's path, line, and column in the file as it is now, its name and its text was and is now, its box, and the shot that shows the slide at the beat the human saw. Fix the slide, then list them again: status turns edited once the slide's own HTML, CSS, or script changed since the note (changed names which), and gone once none of its elements is left. edited means the slide changed, not that the note is dealt with; check the shot against the note. Leave dekc annotations clear to the human, who wrote the notes and judges the result.

An agent with no access to the project, such as one in a chat on another machine, gets the same notes from Copy. What the human pastes names each element by the file and line it is written at:

md
## Notes on decks/plan

Boxes and points are in the slide's own pixels, from its top left.

### Slide 4 of 12, roadmap ("Next quarter's roadmap"), at beat `milestones`

1. div.arrow.arrow-up at decks/plan/slides/roadmap.html:58:7 (box 1188,286 24×290)
   > Make the arrowhead larger

2. 2 elements:
   - div.chevron "UI design" at decks/plan/slides/roadmap.html:30:7 (box 150,380 220×24)
   - div.chevron "Design review" at decks/plan/slides/roadmap.html:31:7 (box 150,410 220×24)
   > Line up their right edges

To see it: `dekc shot plan roadmap --step milestones`

Every value is read from the source or measured on the page. The name is the tag and its classes as the file writes them, without any a script adds as the deck plays. The box is in the slide's own pixels, and the last line shows the slide at the beat the human saw. A place on the slide rather than an element is the slide itself at a point. An element an edit took where it could not be followed says so, and keeps the line it had.

After a rehearsal ​

bash
dekc marks
dekc marks clear

Rehearse aloud on the dev server and press m on each beat whose words trip you up. dekc marks then hands the agent what it needs to rewrite them: the heading's line in script.md, was (what the beat said when you marked it), and text (what it says now). A mark follows its beat by id, or by title, so beats added before it do not move it, and status turns edited once the words change, or gone if the beat itself went away. Say the new words aloud before you run dekc marks clear: only that tells whether they work.

Using a slide as a model ​

bash
dekc show why-dek timing

show returns everything one slide is made of in one call, each part labeled with its file: the section's script, the slide's HTML, CSS, and TS, the rules of theme.css the slide actually uses with only the tokens and keyframes they reach, and the assets it references. An agent learns how the slide is built without reading the whole theme, then writes its own slide in its own deck's theme. Lint catches any class or token it carried over by mistake.

The model can be someone else's deck. dekc ref owner/repo/deck pins it, and ls, show, theme, and shot then take owner/repo/deck as the deck. AGENTS.md lists the pinned refs, so the agent knows which decks it may learn from. A ref is read-only; the agent copies what it needs into its own deck.

Prompts that work ​

Shrink the right column of architecture.html, then run
dekc check architecture --shot and confirm nothing overflows.
On the slide from dekc current, reveal the elements beat by beat with
data-step, following the script's ### headings.
I added ## recap {#recap} to script.md. Do not run dekc sync;
the dev server will generate the skeleton. Fill it in.
Carry the figure from problem into architecture with data-morph.
Run dekc shot problem --to architecture --at 0.5 and check the
interpolated position looks right.
Make the number on files count up as the slide enters. Put it in
slides/files.ts, drawing from t alone, then run dekc check files --shot.
Use hajimism/dek/why-dek as a model. Find the slide closest to what
the budget section needs with dekc ls, read it with dekc show, and write
budget in this deck's theme.
Make a slide like timing in why-dek for this deck's budget section.
Read it with dekc show why-dek timing, write it with this deck's
theme, then run dekc check budget --shot.

To hand the whole documentation site to an agent, give it /llms.txt.

Released under the MIT License.