sdxc
SearchCtrlK

[ The sdxc command ]

Inspect a project

Read what an app holds without opening its files, with sdxc models, schedule, middleware, initializers, notes and stats, each as a table or as JSON for an agent.

Last updated 2026-10-19

After reading this guide, you will know

  • How to see each model's table and whether its migrations match it
  • How to check that every scheduled job has a trigger that fires it
  • How to read the middleware a request runs, and where each instance comes from

Six read-only commands answer the questions you would otherwise open files for. Each runs from any folder in the project, changes nothing, and takes --json for a script or an agent.

CommandAnswers
sdxc modelswhich tables the models declare, and whether migrations match
sdxc schedulewhich jobs run on a schedule, when next, and what fires them
sdxc middlewarewhich middleware a request runs, in order
sdxc initializerswhere the app's one instance of each thing is built
sdxc noteswhich TODO and FIXME comments are left
sdxc statshow much code each kind holds, and the code to test ratio

sdxc routes answers the seventh: which route reaches which controller.

Models and their migrations

sdxc models loads every model in app/models/ with your project's runtime, the way the app loads it, and compares its table with the migration chain:

sdxc models
Model  File                Table  Columns  Migrations
post   app/models/post.ts  posts  5        in step

Name a model to print it in full:

sdxc models post
post: the posts table, in app/models/post.ts

Column      Type     Null  Default  Key
id          text     no             primary
title       text     no
slug        text     no             unique
created_at  integer  no
updated_at  integer  no

Migrations: the migrations create this table
Factory: database/factories/post.ts

Migrations replays the default chain and diffs it against the table, as sdxc make migration does with --from-model. A model you changed after its migration ran reads behind, and the full view names the command that writes the SQL to catch up.

Scheduled jobs

A job made with --cron runs only when a Worker trigger delivers its exact expression. sdxc make job with --cron adds that trigger to cloudflare.config.ts beside the job, and sdxc schedule pairs every scheduled job in app/jobs/index.ts with the trigger that fires it, from cloudflare.config.ts or wrangler.jsonc:

sdxc make job digest --cron "0 8 * * *"
sdxc schedule
Job            Schedule   Next run              Trigger
digest         0 8 * * *  2026-10-20 08:00 UTC  cloudflare.config.ts
reports.daily  0 9 * * 1  2026-10-26 09:00 UTC  none; add triggers.scheduled({ schedule: "0 9 * * 1" })

A trigger no job declares is listed below the table, as cloudflare.config.ts fires "0 5 * * 1", which no job declares. Expressions are compared as parsed, so 0 9 * * MON-FRI matches 0 9 * * 1-5, and next runs are in UTC, the zone Workers deliver triggers in.

Middleware

sdxc middleware prints each router's global middleware in the order it runs, then every module in app/http/middleware/. A chain built with createMiddleware(…) is expanded to its members, and each module says how many routes run it:

sdxc middleware
app/initializers/router.tsx, the router's global middleware:
   1. asyncContext()  remix/middleware/async-context
   2. log(logger)     @sdxc/logger/middleware
   …

app/http/middleware/page.ts, a chain 2 routes run:
  1. formData()                              remix/middleware/form-data
  2. cop()                                   remix/middleware/cop
  3. session(sessionCookie, sessionStorage)  remix/middleware/session
  …

A middleware that sits inside a chain counts the routes of that chain, so a count of 0 is one no route reaches.

Initializers

sdxc initializers lists every module in app/initializers/, what it exports, and the package factories it calls to build it:

sdxc initializers
File                            Exports       Built with
app/initializers/cli.ts         cli           createCLI (@sdxc/cli), createLogger (@sdxc/logger)
app/initializers/database.ts    openDatabase  createD1DatabaseAdapter (@sdxc/data-table-d1)
app/initializers/dispatcher.ts  dispatcher    createJobDispatcher (@sdxc/jobs)

A factory is an imported create*, open*, define* or connect* the module calls; the app's own modules and Node's built-ins are left out.

Notes left in the code

The files sdxc make writes mark what is left to fill in with a TODO. sdxc notes lists them, with every TODO, FIXME, HACK and OPTIMIZE anyone left, by file and line:

sdxc notes
app/http/controllers/about.tsx:
  [24] TODO: render the page

app/jobs/reports/daily.ts:
  [18] TODO: do the work, through the services on `ctx`

--tag reads other tags instead, as sdxc notes --tag TODO,REVIEW. The notes come from comments alone, after //, /*, *, {/*, -- or <!--, in the folders the app layout names.

Lines of code

sdxc stats counts files, lines, and code lines without blanks and comments, for each kind of code the app layout names, with tests apart wherever they sit:

sdxc stats
Kind                 Files  Lines  Code
-------------------  -----  -----  ----
Controllers              9    225   122
Middleware               4    165    87
Jobs                     2     36    11
Models                   2     52    22
…
Tests                   24    855   514
-------------------  -----  -----  ----
Total                   90   2991  1669

Code: 1155  Tests: 514  Code to test ratio: 1:0.4

Where to go next

  • List routes — every route with its controller and middleware.

  • Check a project — the checks that fail a build, beside these listings that inform one.

Written by Sergio Xalambrí. Follow @sergiodxa for new packages, or sponsor the work.