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).
Copyable agent prompt
Section titled “Copyable agent prompt”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, thescreenshots with each page's rubric result, the local URL and anything left.Do not deploy or publish unless explicitly requested.
1. Scaffold
Section titled “1. Scaffold”From a source checkout, over a disposable copy of the database:
npm run start -- --config ./tablewalk.json --scaffold-app ./my-appnpm run start -- check --app ./my-app --config ./tablewalk.jsonnpm run start -- --config ./tablewalk.json --app ./my-app --port 4720The 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.
2. Page by page
Section titled “2. Page by page”Take the pages in this order — shell, lists, dashboard, record pages, forms — and for each one:
- Read its guide:
tablewalk docs compose-shell,compose-list,compose-dashboard,compose-record-page,compose-overvieworcompose-form. Each rule is “when X, use Y” and names one sample file and line. - Edit, then run
tablewalk check --app ./my-appuntil it exits 0. - Lint the composition:
tablewalk check --app ./my-app --designwarns where a page, a form or the shell will come out basic, each with its fix (design checks); fix every one it names. - Screenshot it:
tablewalk shot --app ./my-app <route> --bothserves 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). - Compare your screenshot with the guide’s worked example, side by side: the same skeleton, the same kinds of values dressed the same way.
- 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:
npx tablewalk --config ./tablewalk.json --app ./my-app --export types > my-app/tablewalk-schema.d.tsnpx tsc -p ./my-app --noEmitnpx 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).
3. Acceptance: the rubric
Section titled “3. Acceptance: the rubric”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.
Choose the right building block
Section titled “Choose the right building block”| 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.
Definition of done
Section titled “Definition of done”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 checkexits 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 thatcheck --designcould 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.