Steve Kinney

Porting the Shelf Loop to Another Stack

Shelf is a teaching app, not a religion.

If the loop only works in a SvelteKit + TypeScript toy repository, then we taught a demo, not an engineering pattern. This appendix is the translation layer.

I’m going to keep it at the level that actually matters: auth bootstrap, deterministic data, runtime probes, failure evidence, review, CI, and post-deploy checks. The details vary. The loop structure does not.

Prerequisite

Finish the core course first. This appendix is easier once you’ve seen the full loop in Shelf and can tell which parts are structural versus incidental.

The translation rule

Do not port file names. Port responsibilities.

That means:

  • CLAUDE.md becomes “where the agent learns the repository rules”
  • storage state becomes “how browser automation gets authenticated deterministically”
  • seed data becomes “how the repository resets to known state”
  • failure dossier becomes “the artifact bundle that makes a red run fixable”

Once you translate at that level, the stack mostly tells you where each piece wants to live.

Next.js-style translation

For a React or Next.js stack, the shape is pleasantly close.

The official Next.js testing guidance already assumes Playwright and unit-test tooling are normal parts of the workflow.

The mapping usually looks like this:

Shelf loopNext.js-style equivalent
CLAUDE.md rulesAGENTS.md, CLAUDE.md, or repo instructions file
storage state authPlaywright storage state or seeded test login route
deterministic dataseed script, test database reset, or fixture loader
Playwright suitePlaywright end-to-end tests against the app router or pages router
static layerESLint, TypeScript, dead-code checks, secret scan
dossierPlaywright traces, screenshots, console logs, workflow artifacts

That is mostly a one-to-one translation.

Rails-style translation

Rails is different in texture, not in need.

The Rails testing guide already gives you system tests, fixtures, and a test environment. Those are the raw materials for the same loop.

The mapping looks more like this:

Shelf loopRails-style equivalent
CLAUDE.md rulesAGENTS.md, repo docs, or prompt file the agent reads first
storage state authsystem-test login helper, seeded user, or browser bootstrap
deterministic datatest/fixtures, factories, database reset tasks
Playwright or browser loopRails system tests, Playwright, or both depending the team
static layerRuboCop, Brakeman, type tooling if used, secret scan
dossierscreenshots, logs, failing system-test output, CI artifacts

Rails gives you good primitives out of the box. The loop still needs to be made explicit for the agent.

What not to port blindly

Do not copy Shelf’s exact commands if your stack has better local primitives.

Examples:

  • Rails system tests may be a better first browser loop than Playwright for some teams
  • a monorepo may need path-scoped CI and instruction files
  • a mobile-web hybrid app may need runtime probes against a preview build, not just localhost

The rule is still the same: cheap loops early, strict loops later, and failure output that an agent can actually use.

The checklist I use when translating

For a new stack, I ask:

  • Where do the agent rules live?
  • How does the browser get logged in deterministically?
  • How do I reset data to known state?
  • What is the cheapest browser-level proof of correctness?
  • What artifacts make a failure fixable?
  • Which static checks should fire before CI?
  • What is the post-deploy smoke path?

If I can answer those seven questions, I can usually port the loop cleanly.

Success state

You have successfully translated the loop when:

  • every core responsibility has a concrete home in the new stack
  • the verification commands are explicit
  • the failure artifacts are still legible enough for an agent to recover

The one thing to remember

The stack is not the pattern. The pattern is “teach the agent the rules, give it cheap ways to check its own work, and make failures rich enough to fix.” Port that, and the framework details stop being the interesting part.

Additional Reading

Last modified on .