Shank Local Development
Prerequisites
- Node
>=18(matches the docs repo’sengines.node). pnpm(the project pinspnpm@8.10.2inapps/shank/react-templates/package.jsonviapackageManager; 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/.
cd apps/shank/react-templatespnpm installThis 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
pnpm devRuns 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:
pnpm dev -- --port 3001Build (sanity check)
pnpm buildRuns 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
pnpm exportRuns 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:
- Run sirloin locally pointed at a fake SMTP (e.g. Mailpit or MailHog
on
localhost:1025). - Trigger the worker that calls the relevant
Send*method — for training-done that isapps/sirloin/internal/app/worker/checkmediageneration.go. - 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.tsxThere 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.