Skip to content

Build an App with a coding agent

This page is what to hand a coding agent that is building a Tablewalk App: a brief, the loop it runs page by page, and the rubric it grades its own screenshots against.

npx tablewalk agent init installs the same guidance as a skill the agent loads on its own (the agent skill).

Replace the bracketed part with who uses the App, the records they work with and one complete journey — for example, “a clinic’s front desk: book a visit, check the patient in, record the claim”.

Build a Tablewalk App for [users, records and first complete journey].
Use a tablewalk source checkout at the current release or newer, not an older package.
Before editing:
1. Read CLAUDE.md in this checkout, then this page
(site/src/content/docs/docs/build-with-an-agent.md).
2. Inspect the actual database schema. Summarize the data model, permissions,
first journey and unsupported needs. Ask before touching existing data,
exposing a server publicly or widening the requested scope.
Build in the loop on this page:
1. Scaffold the App from the database, and run tablewalk check.
2. Then page by page — shell, lists, dashboard, each record page, each form:
read that page type's guide (for a record page, tablewalk docs
compose-record-page), edit, run
tablewalk check, screenshot the page, compare it with the guide's worked
example, and fix what differs before the next page.
3. Grade every screenshot against the rubric on this page, at a desk and on a
phone. A page is done when every check passes.
Rules:
- Use the TypeScript DSL from tablewalk/app with checked schema types.
- Business handlers go in a separate server entry (tablewalk/commands).
- Connections and secrets stay in server configuration. Opt in to only the
writes the App needs; hiding a button is not security.
- Prefer the built-in blocks. Do not invent keys, import private src/server
modules or patch the framework. Report missing capabilities instead.
- Never reseed an existing database; use a new disposable one for tests.
- Walk the whole journey in a browser: reload persistence, invalid input, the
empty state and the keyboard. Do not call unrun checks passed.
Deliver the App, a README with exact setup/check/start commands, the
screenshots with each page's rubric result, the local URL and anything left.
Do not deploy or publish unless explicitly requested.

From a source checkout, over a disposable copy of the database:

Terminal window
npm run start -- --config ./tablewalk.json --scaffold-app ./my-app
npm run start -- check --app ./my-app --config ./tablewalk.json
npm run start -- --config ./tablewalk.json --app ./my-app --port 4720

The draft passes tablewalk check and check --design as written and starts at the samples’ floor: a look, a logo and a grouped top menu; statuses in tones; money, units and words from the catalog; records named by their parent (“Maple Court B103”); a page for every table others point at, in the record anatomy, with the parent’s card and the current child beside its tabs; and each New form in groups named by what they hold, with its created-on date starting today. Then set a stable id (it is the address and names the account store) and each resource’s access, and delete what you do not need. --name names the App.

Take the pages in this order — shell, lists, dashboard, record pages, forms — and for each one:

  1. Read its guide: tablewalk docs compose-shell, compose-list, compose-dashboard, compose-record-page, compose-overview or compose-form. Each rule is “when X, use Y” and names one sample file and line.
  2. Edit, then run tablewalk check --app ./my-app until it exits 0.
  3. Lint the composition: tablewalk check --app ./my-app --design warns where a page, a form or the shell will come out basic, each with its fix (design checks); fix every one it names.
  4. Screenshot it: tablewalk shot --app ./my-app <route> --both serves the App with a temporary config directory and prints the path of a PNG at a desk and on a phone (--as <role> signs in; no route, every page).
  5. Compare your screenshot with the guide’s worked example, side by side: the same skeleton, the same kinds of values dressed the same way.
  6. Fix what differs, and go round again from step 2.

tablewalk check runs these steps, each with its own verdict:

Step What it does Exit code on failure
Schema types Regenerates tablewalk-schema.d.ts when the database or the App’s rollups changed 2
Typecheck The App’s tsconfig.json; errors as file:line, the mismatch and a hint 3
Validation --check-app against the database; preview lines and warnings never fail 4
Components Only with custom components: compile and source checks 5

Pass --commands, --jobs and --policy as a start would; --routes prints every address the App serves. A running server reloads the App but never rewrites its types, so run check after a migration. The same loop by hand:

Terminal window
npx tablewalk --config ./tablewalk.json --app ./my-app --export types > my-app/tablewalk-schema.d.ts
npx tsc -p ./my-app --noEmit
npx tablewalk --config ./tablewalk.json --app ./my-app --check-app

Outside a checkout the App directory needs a package.json with "type": "module" and tablewalk as a dependency, and a tsconfig.json like Thread’s ("module": "NodeNext", "moduleResolution": "NodeNext", "allowImportingTsExtensions": true, "verbatimModuleSyntax": true, "noEmit": true, "skipLibCheck": true); the scaffold writes both. Commands also need @types/node and the command journal provisioned once (migrateSqliteCommandJournal(path) from tablewalk/commands).

Grade each screenshot, desk and phone, against its page type. Every check is yes or no; a no is fixed before the page is done.

Record page

  • The name is words (not “Visit #12” or a bare code), with the state beside it.
  • Three or four facts under the name, with units; none repeats the name.
  • The figures share one row; no card wraps alone.
  • Child lists are tabs; no column is cut and the status is visible.
  • The aside holds the parent’s card, the current child and a property rail, nothing wider than two columns.
  • On a phone, the main work comes before the aside.
  • The filled button is the forward verb; destructive verbs come last.

Form

  • A sentence under the heading says what a new record is for.
  • Fields sit in groups named by nouns, none longer than seven.
  • Every required field starts filled or is plainly the reader’s to fill; created-on dates start today.
  • Choices read as words, references as names.
  • Long text has a box of several lines; a dependent picker offers only the chosen parent’s records.
  • Add and Cancel sit together at the end.

Overview page

  • The name appears once, with its avatar or mark.
  • A row of three to five figures, each with its unit or word.
  • A chart of activity in time order, no taller than it needs.
  • Lists of what it made, every column readable; an empty one is left out.
  • No aside half empty beside a long main column.

List

  • The first column names the row; no raw id, and a reference reads by name.
  • Four to seven columns fit at 1280 wide without cutting the status.
  • Tabs are counted, in working order, All last.
  • Money has its currency, states are a tone and a word, due dates say how far.
  • The filters are the ways it is narrowed (a rail for three or more).
  • On a phone the rows read without a sideways scroll.

Dashboard

  • The first row is three or four figures of one width.
  • Every figure says its window; a compared one says against what.
  • Charts run in time order with readable axes.
  • A breakdown’s words are words, and its total matches the figure it divides.
  • The page ends where its content ends.

Navigation and shell

  • A chosen look, not the default, and a mark beside the App’s name.
  • At most seven top-level entries; groups named by the work.
  • Every entry has an icon of what it lists; counts beside the lists.
  • Home is the page a person starts the day on.
  • The folded rail and the phone menu still reach every entry.
Need Use
Lists, filters, record details, related rows List views and page sections
Create or edit a record A resource’s form and a write grant — Composing a form
Set a fixed value (complete, reopen) An action with set; when only hides the button
A decision checked against stored state, across tables A command
Something later, or a webhook after commit A durable job or effects (preview) — events and jobs
Sign-in, roles, field and row access Sign-in, roles & data
A public front page A landing view
A drawing no built-in makes A custom component (preview)
Live collaboration Not available — report it as a gap

Tenant Apps are a preview with their own startup contract; do not fake tenancy with a tenant_id filter. MCP can inspect a development database but does not act as an App user; test authorization over HTTP.

The agent’s report shows evidence, not “it should work”:

  • Setup: a new engineer can follow the App’s README without a missing table, hidden variable or private import.
  • Checks: tablewalk check exits 0 against the real fixture.
  • Pages: each page’s desk and phone screenshots (tablewalk shot --both), each looked at, with its rubric passed and nothing left that check --design could fix.
  • Journey: create, read and change a record; state survives a reload.
  • Failure states: empty lists, invalid values, denied operations and failed writes behave honestly; an unknown command outcome is not a failure.
  • Limits: unsupported needs, checks not run and production work left.