Toast Dev CLI (td)
Inspection, scaffolding, and development lifecycle management for the Toast codebase.
td is the Toast developer CLI. It solves two problems that make development friction worse over time:
- Agent blindness — agents and developers can't see the database schema without reading source files, can't inspect errors without hunting logs, and can't verify PR previews without manual curl commands.
- The scaffolding gap (pre-
td) — before generators, every new feature required manual route/service/repo/test scaffolding, and it was easy to miss thesiteIdmulti-tenancy requirement.
td is the Toast equivalent of Laravel's Artisan. It lives in packages/td and is never published — it's internal dev tooling only.
# Quick start
td status # What's running, what port, what environment
td schema # Live database schema: tables, columns, types, FKs
td generate feature newsletters # Scaffold a complete feature in secondsGenerators
This is the most important td capability. Generators scaffold most of the API boilerplate in the right directories with correct imports pre-wired and the multi-tenancy requirement baked in.
td generate feature <name>
Generates a full API feature scaffold: contract stub, repository, service, controller, route definitions, schemas, and tests.
td generate feature newslettersCreates:
shared/contracts/src/newsletters.ts # Contract stub
apps/api/src/repositories/newsletters.repository.ts
apps/api/src/services/newsletters.service.ts
apps/api/src/routes/newsletters/
├── routes.ts
├── newsletters.controller.ts
├── schemas.ts
└── index.tsAlso:
- Wires barrel exports in
apps/api/src/routes/index.ts,apps/api/src/services/index.ts, andapps/api/src/repositories/index.ts - Updates
shared/contracts/package.jsonexports - Prints a checklist of what still needs filling in
The repository template includes siteId scoping. You still need to add any table changes in shared/db/src/schema.ts and wire the new stack through container.ts, index.ts, and app.ts.
td generate migration <name>
Creates a migration SQL stub with a timestamp-based prefix:
td generate migration add-newsletters-table
# → shared/db/migrations/20260323230155_add-newsletters-table.sqltd generate event <name>
Scaffolds a typed domain event and handler stub:
td generate event newsletter-created
# → updates apps/api/src/events/domain-events.tstd generate driver <type> <name>
Scaffolds an implementation skeleton for a Toast driver interface:
td generate driver email resend
# → drivers/email-resend/src/index.tsInspection
Some inspection commands support remote environment or PR preview flags. Check td <command> --help for the exact surface area of each command.
td status
What's running, on which port, in which environment. Solves the worktree port problem — agents and developers shouldn't need to guess.
td status
# ✓ API http://localhost:3101 (worktree: frameworkisation)
# ✓ Admin http://localhost:5175
# ✓ PostgreSQL localhost:5433
# ✓ MinIO localhost:9002td schema
Live database schema: tables, columns, types, foreign keys, and indexes. Reads directly from information_schema — always reflects reality, not the source files.
td schema
td schema --env staging
td schema --pr currenttd routes
All registered API routes from the live OpenAPI spec — method, path, tags, request/response schemas.
td routes
td routes --env stagingtd migrations
Applied versus pending migrations. Critical for diagnosing PR preview environments.
td migrations
td migrations --pr 472td config
Resolved configuration values from the Zod env schema. Secrets are masked.
td config
# DATABASE_URL postgresql://...@localhost:5433/toast ✓
# BETTER_AUTH_SECRET •••••••••••••••• ✓
# EMAIL_DRIVER toast-driver-email-mailgun ✓
# MAILGUN_API_KEY •••••••••••••••• ✓td drivers
Driver configuration and package discovery — shows which email and storage drivers are installed and configured.
td drivers
# email toast-driver-email-mailgun ✓ configured
# storage toast-driver-storage-s3 ✓ configuredtd logs
Pino JSON logs from the running server, with filtering:
td logs # All logs, streaming
td logs --level error # Errors only
td logs --last 50 # Last 50 entries
td logs --service api # Filter by compose servicetd errors
Shorthand for the most common debugging command — the last 5 error-level log entries with full stack traces:
td errors
td errors --last 10td query "<sql>"
Read-only SQL against any environment. 100-row limit, 5-second timeout, production-safe:
td query "SELECT id, name FROM newsletters WHERE site_id = '...' LIMIT 10"
td query "SELECT COUNT(*) FROM content" --env stagingtd seed:status
Row counts per table — confirms whether the database is seeded:
td seed:status
# sites 1
# users 1
# content 12
# newsletters 0td info
Monorepo structure, package versions, Node/pnpm versions, and API health check:
td infoPR preview inspection
Use --pr on commands that explicitly support it (check td <command> --help):
td pr status # Current PR info + inferred preview URLs
td schema --pr current # Live schema in the PR environmentShorthand commands:
td pr status # PR info + inferred preview URLs, with optional Railway enrichment
td pr open # Open inferred PR admin preview URL in browser
td pr logs # Recent errors from PR preview
td pr compare schema --pr current # Schema diff: PR vs main
td pr compare routes --pr current # Routes diff: PR vs maintd pr status does not require Railway for the basic happy path. It always shows the inferred admin/API/docs preview URLs for the PR, then adds Railway environment details when the Railway CLI is installed, authenticated, and linked.
td staging
Staging follows the same inferred-URL-first model:
td staging status # Canonical staging URLs + optional Railway enrichment
td staging open # Open the staging admin URL in browsertd pr compare schema answers "did my migration actually run in the preview environment?" instantly — no manual curl commands needed.
Development lifecycle
td provides a single interface for the full development lifecycle:
td dx # Start everything (databases, migrations, dev servers)
td check # Lint, format, typecheck, test, build
td test # Run unit tests
td typecheck # Run type checker
td db generate <name> # Generate migration from schema changes
td db migrate # Apply pending migrations
td db push # Push schema directly (no migration file)
td db reset # Drop and recreate database, then seed
td db seed # Seed the database with fixture data
td db studio # Open Drizzle Studio (database GUI)td db runs commands directly in the shared/db package. The root pnpm db:* scripts still exist for CI and production deployments where td is not available.
td watch
Runs pnpm check (or pnpm check:strict) directly. Useful when you want to use the td command surface consistently during development:
td watch # runs pnpm check
td watch --strict # uses check:strict (no auto-fixes, coverage enforcement)Provider authentication
td auth manages credentials for external providers (Railway, Fly.io, etc.) so inspection commands can reach remote environments:
td auth add railway --token <token>
td auth login railway
td auth list
td auth remove railway
td auth status # Check all configured providers are reachableFor Railway-backed commands, prefer td auth login railway when you want td to launch Railway's native login flow for you. After that, td can reuse Railway CLI state to enrich commands like td pr status, td pr logs, and td staging status.
Credentials are stored in ~/.config/toast/credentials.json. Secrets are never committed to the repository.
CI status
td ci
Check GitHub CI status for a branch. Useful for verifying whether a failure is local or already broken on main:
td ci # Check main branch
td ci --branch my-pr # Check a specific branchtd test:status
Show the last test run results from Vitest JSON reports without re-running tests. Shows per-package pass/fail counts and report age:
td test:statusPackage location
td lives in packages/td/ and is never published to npm. It's a local dev dependency wired via the pnpm workspace:
# From anywhere in the monorepo
td status