# Tools built for agents — the Hyperframes pattern

Web page: https://academy.memberpress.ai/courses/tool-use/l9/

Lesson 9 of 9 in [Tool Use — From Calculator to Agent](https://academy.memberpress.ai/courses/tool-use/), 14 min.

Video: https://www.youtube.com/watch?v=Ba1jN5vk7JQ

Eight lessons asked: how do you build a tool a model can use? This one flips it. What does a tool look like when an agent authors *with* it, not just calls it?

**Run init and read what shows up**

```bash
npx hyperframes init
# → Created hyperframes.json
# → Created package.json
# → Created index.html
# → Created meta.json
# → Created AGENTS.md
# → Created CLAUDE.md
```

Six files. Two of them — `AGENTS.md` and `CLAUDE.md` — exist for one reason: so the agent never has to leave the repo to learn how to use the tool.

**The cognitive surface**

Hand someone a power saw without the safety label and you've handed them a different tool. The blade is the same. What changed: whether the warning sits next to the cut. The agent has the same constraint — it sees what's in the working directory. A docs site lives somewhere it doesn't.

`CLAUDE.md` lists thirteen slash-skills the project owns: `/hyperframes`, `/gsap`, `/lottie`, `/three`, `/website-to-hyperframes`. The docs aren't a site you read. They're a tool you invoke — same packaging as Anthropic's `superpowers`.

**The edit surface**

One file. `index.html`. Each `.clip` div carries `data-start`, `data-duration`, `data-track-index`. Animations live in GSAP timelines registered on `window.__timelines["main"]`, created paused.

```html
<!-- index.html -->
<div class="clip" data-start="0" data-duration="2" data-track-index="0">
  <h1 class="title">Hello</h1>
</div>

<script>
  const tl = gsap.timeline({ paused: true });
  tl.from(".title", { y: 100, opacity: 0, duration: 0.8 });
  window.__timelines["main"] = tl;     // load-bearing line
</script>
```

That last line is the whole lesson on this mechanic. The renderer is a headless browser that must seek to timestamps to capture frames. A running timeline doesn't expose seek; only a paused timeline registered on `window.__timelines` does. Forget the registration and the browser preview still plays — but the render freezes on frame 0. Same shape as the `os.path.realpath` boundary in l6: the failure is invisible until something outside the local environment exercises it.

**The lint pass**

```bash
npm run check
# → composition validated
# → 0 console errors
# → WCAG-AA: pass
```

Same discipline as the pytest suite in l8: fail loudly before shipping, with concrete checks, not vibes. The browser hid the console error; the headless run surfaces it.

**The catalog**

```bash
npx hyperframes add data-chart
# → compositions/data-chart.html (458 lines)
# → snippet copied to clipboard
```

shadcn-style. The file is in your repo. You own it, you edit it, no runtime import to a black-box component.

**The four-signal test**

When evaluating any tool that claims agent support:

1. Does it ship an `AGENTS.md` or `CLAUDE.md` at init?
2. Does it provide slash-skills or equivalent invocable docs?
3. Is the edit surface one file, not a component tree?
4. Does a lint pass catch headless-render failures before they ship?

Three of four missing means the tool was built for humans and retrofitted with an MCP server. The retrofitted version still works — but the agent spends tokens reading a website to learn what `AGENTS.md` could have told it for free.

**Hyperframes vs. Remotion**

Code-first agents → Hyperframes. The agent writes HTML it can read back; the renderer is local.

React-first humans → Remotion. Type-safe composition trees, prop-based reuse, JSX a person edits.

Same shape, different authors. Pick by who is writing.

**If you get stuck**

*Composition animates in the browser preview but freezes on frame 0 in the render:* the GSAP timeline is not registered on `window.__timelines["<id>"]`. Add the assignment line and confirm the timeline was created with `paused: true`.

*Render passes locally but `npm run check` reports a console error you didn't see:* the browser swallowed it. Open the page in devtools, reproduce, and fix the underlying error — the lint pass is reading the same buffer.

*Agent imports a block from npm instead of running `add`:* it pulled in a registry your project does not own. Delete the import, run `npx hyperframes add <name>`, edit the file that lands in `compositions/`.

**Cross-reference**

l7 and l8 built the consumer posture — your code calls tools the model authors. l9 is the author posture — you evaluate tools built for the model to author *with*. Same vocabulary, opposite end of the contract.

**Deliverable**

A 6-second composition rendered locally with `npx hyperframes` to a 200-300KB h264 file in `out/`. Plus `notes/tool-evaluation.md` applying the four-signal test to one other tool you use that claims agent support — name which signals are present, which are missing, and what the next agent author must read a website to learn.

**Further reading**

- ["What Agents Actually Need From Your API"](https://sethshoultes.com/blog/what-agents-need.html) — same boundary problem one layer down. The response shape that worked for human developers degrades reasoning when the caller is a model. Tooling has the same gradient.

## Try these prompts

- Run npx hyperframes init in a scratch directory, then describe what each of the six scaffold files is for and which two exist solely so an agent can read them before writing any code.
- Apply the four-signal agent-first test (AGENTS.md ships at init, slash-skills as docs, single-file edit surface, lint pass catches headless-render failures) to one tool you currently use that claims agent support; name which signals are present and which are missing.
- Explain in two sentences why a GSAP timeline that animates correctly in the browser preview can freeze on frame 0 in the headless render, and what one line of code prevents it.
