Skip to content

Shank Local Development

Prerequisites

  • Node >=18 (matches the docs repo’s engines.node).
  • pnpm (the project pins pnpm@8.10.2 in apps/shank/react-templates/package.json via packageManager; corepack will pick it up automatically).
  • Nothing else. Shank has no env vars, no DB, no queue.

Install

All shank commands run from apps/shank/react-templates/.

Terminal window
cd apps/shank/react-templates
pnpm install

This installs react-email 3.0.6, @react-email/components 0.0.32, react@19.0.0, and react-dom@19.0.0 (per package.json).

Preview templates

Terminal window
pnpm dev

Runs email dev, which serves a live preview at http://localhost:3000. The browser reload picks up TSX edits automatically.

The sidebar lists every template under emails/. Click a template to view its rendered HTML and the source side-by-side. Placeholder tokens ({{CHARACTER_NAME}}, {{CHARACTER_ID}}) render literally — sirloin substitutes them at send time, not the preview.

If port 3000 is taken:

Terminal window
pnpm dev -- --port 3001

Build (sanity check)

Terminal window
pnpm build

Runs email build. Useful as a “does this template compile?” gate. Does not write to sirloin. CI does not currently run this (grep -rn shank .github/workflows returns no matches). TODO(@zen): decide whether to add a CI gate.

Export to sirloin

Terminal window
pnpm export

Runs email export --outDir='../../sirloin/internal/pkg/emails/templates'. This is the only step that writes outside apps/shank/. It overwrites training-done.html and training-failed.html in sirloin’s embedded template directory.

After export, review the diff with git diff apps/sirloin/internal/pkg/emails/templates/. The output should change only where you changed the TSX.

Test data

react-email does not have a built-in props panel for the existing templates because they declare no props — {{TOKEN}} placeholders are substituted later by sirloin. To preview with realistic content, temporarily inline a string in the TSX (e.g. replace {{CHARACTER_NAME}} with "Test Character") and revert before exporting. TODO(@zen): decide whether to upgrade templates to take typed props with default values so the preview shows realistic content without source edits — the existing TSX in apps/shank/react-templates/emails/ declares no props.

End-to-end test send

There is no shank-side test-send. To exercise the full path:

  1. Run sirloin locally pointed at a fake SMTP (e.g. Mailpit or MailHog on localhost:1025).
  2. Trigger the worker that calls the relevant Send* method — for training-done that is apps/sirloin/internal/app/worker/checkmediageneration.go.
  3. Open the Mailpit UI to inspect the rendered email.

TODO(@zen): document the exact local SMTP setup used by the team so template authors do not have to discover it. Sirloin’s loader (apps/sirloin/internal/app/config/config.go) requires SIRLOIN_EMAIL_HOST, SIRLOIN_EMAIL_PORT, SIRLOIN_EMAIL_USER, SIRLOIN_EMAIL_PASSWORD, SIRLOIN_EMAIL_SENDER — the canonical container image and ports are not pinned in any compose file in this repo.

Lint / format

apps/shank/react-templates/ does not include its own lint or format config (no .eslintrc, no prettier config in package.json at last review). Editor defaults apply. Match the existing TSX style: import components from @react-email/components, wrap content in <Tailwind>, use Tailwind class names for all styling.

What lives where

apps/shank/
├── CLAUDE.md # service-level agent notes
├── AGENTS.md
└── react-templates/
├── package.json # scripts: dev / build / export
├── readme.md # upstream react-email starter readme
└── emails/
├── training-done.tsx
└── training-failed.tsx

There is no src/ directory and no shared components/ directory at present. If you extract reusable JSX, add a sibling folder (components/ or partials/) and import from emails/*.tsx.