Quickstart
In about ten minutes you will scaffold a project, declare a two-table authority, serve it, read from it over REST, write to it over GraphQL, hit your first derived error, and read the contract that predicted it.
This guide requires spock@0.5.4 or later. 0.5.4 is the first npm release
that packages the strict Uhura 0.4 client used by the full-stack scaffold;
framework releases 0.5.0 through 0.5.3 carry the retired frontend and
cannot run these client files, while releases through 0.4.0 have no
framework client.
Scaffold a project
npm install --global spock@0.5.4spock --versionspock new democd demodemo/βββ spock.tomlβββ backend/β βββ app.spockβββ client/ βββ uhura.toml βββ host.toml βββ machine.uhura βββ ui.uhura βββ evidence.uhuraThis is a framework project: a spock.toml manifest composing a Spock
backend with an Uhura client. The scaffolded backend/app.spock is
deliberately empty β a project whose authority is not designed yet can
already serve its client, health, and status surfaces. This page fills the
backend; the client half has its own page.
Declare the authority
Replace the contents of backend/app.spock with a complete program:
auth table user { key id: uuid = auto username: text unique}
table post { key id: uuid = auto author: user caption: text at: timestamp = now}
seed { ada = user { username: "ada" } lin = user { username: "lin" } post { author: ada, caption: "hello from the authority" } post { author: lin, caption: "works on my machine" }}Two tables and a seed. auth table user makes user the programβs
anchor β the one table identity references point at.
author: user is a reference; = auto and = now are defaults; unique is
a constraint the whole surface will enforce. Field syntax, types, and
constraints are covered in Tables, types, and defaults. The seed
block populates the database through the ordinary write path on every start β
seed replay, the reason a prototype always boots into
believable state.
Check it
spock checkok: project `demo` β 2 table(s), 0 record(s), 0 fn(s), 4 seed row(s), 2 preview(s), 1 replay-derived preview(s), 1 unchecked link(s), 1 warning(s)warning: link: application-owned provider adapter code remains uncheckedcheck does more than parse: it materializes the schema in memory, validates
every declaration, and replays the seed through the runtime write path. The
counts after the seed rows β previews, links, the warning β describe the
Uhura client half of the project. Spock checks that client as part of the same
project: an invalid Uhura machine, Web UI, evidence corpus, host entry, or
provider contract makes the whole spock check fail.
Serve it
spock devwarning: backend inputs (including referenced seed assets) and spock.toml topology changes are observed but not applied; restart `spock dev` to reconstruct backend state from seedlistening on http://127.0.0.1:4000 GET / Uhura Editor GET /play Uhura Play GET /~studio Spock Studio GET /~contract active Spock contract GET /~project/status framework generation status GET /~health aggregate readiness * /rest/v1/* authority REST and RPC POST /graphql/v1 GraphQL when the contract is non-emptyOne process, one origin: the root path serves the Uhura Editor, and the authority protocols mount beside it. The warning is the development doctrine in one line β state is disposable, so backend edits take effect by restarting and replaying the seed, never by migrating in place.
First read
curl -sS http://127.0.0.1:4000/rest/v1/user{ "rows": [ { "id": "019f751c-3a75-7cb3-ba39-92e36fb6dd87", "username": "ada" }, { "id": "019f751c-3a75-7cb3-ba39-92fb2cbe32ca", "username": "lin" } ]}You declared no route and no serializer. Every table receives a derived read/write surface β the floor β with list and by-key reads over REST, ordered by key ascending.
First write
Open http://127.0.0.1:4000/graphql/v1 in a browser: GET serves GraphiQL, with the full derived schema behind introspection. Run an insert:
mutation { insert_user_one(object: { username: "grace" }) { id username }}{ "data": { "insert_user_one": { "id": "019f751c-7c1d-7b83-a31f-a5201b4d2ebe", "username": "grace" } }}insert_user_one was derived from the table declaration, in the
Hasura-mirrored dialect specified in the GraphQL specification β
standard GraphQL tooling consumes it unmodified.
First derived error
Run the same mutation again:
{ "data": null, "errors": [ { "message": "user.username is already taken", "locations": [{ "line": 1, "column": 12 }], "extensions": { "code": "user_username_taken", "kind": "unique", "table": "user", "fields": ["username"] } } ]}user_username_taken was minted at compile time from the unique constraint
on username β the code existed in the contract before any request was made,
and generated clients ship it as a typed union rather than parsing a message
string. Derived errors are the product surface of your constraints, not
incidental runtime strings; The derived API
catalogs the kinds.
The contract
Everything above was derived from one artifact, served verbatim:
curl -sS http://127.0.0.1:4000/~contractThe contract is the compiled JSON the program produces: its tables, fields, seed, and β the part the previous section exercised β each tableβs derived errors, declared before any request:
[ { "code": "user_already_exists", "kind": "key", "fields": ["id"], "status": 409 }, { "code": "user_username_taken", "kind": "unique", "fields": ["username"], "status": 409 }, { "code": "user_username_required", "kind": "required", "fields": ["username"], "status": 422 }, { "code": "user_restricted", "kind": "restricted", "fields": [], "status": 409 }]That array is tables[0].errors β the failure surface of the user table,
enumerated by the compiler. The contractβs shape is normative in the
v0 specification, Β§6; spock gen types turns it into TypeScript when you
want the codes as literal unions.
Where next
For the backend on its own:
- The tutorial β build a mini-Instagram backend: functions, refusals, personas, and the deliberate surface.
- The language guides β tables onward: types, references, seeds, functions, and the actor seam.
- The reference β endpoint tables, error codes, CLI commands, and the manifest.
For the full stack with Uhura:
- The tutorial still comes first β the authority is the same either way.
- Uhura β what the client language owns, and the Editor and
Play surfaces you saw at
/. - Examples β the portfolio, including the canonical full-stack Instagram project.