Skip to main content
nika serve --bind is the same engine running as a server: it holds durable jobs and schedules, and your application reaches it over HTTP. This page starts one on your machine and drives it with the client from the quickstart. Every step was run with @supernovae-st/nika@0.123.0 and its bundled engine.
1

Make a project with one workflow

The server refuses to start outside a project, and a project file is one line. In the folder where you installed the package:
Save the quickstart’s workflow as workflows/hello.nika:
hello.nika
2

Mint a private token

The server reads its bearer token from a file and refuses one that is not mode 0600:
The token never appears on a command line. Keep .nika/ out of source control.
3

Start the server

It stays in the foreground and prints one line that starts with nika serve · listening http://127.0.0.1:8787 · GET /health and lists the routes it answers. Job state goes to .nika/serve/ (--state-root chooses another place). Leave it running and open a second terminal in the same folder.
4

Run the workflow over HTTP

Save remote.mts:
remote.mts
run.id is the server’s durable job id: the one to store. ok unsealed means the record is intact but the server has no run-signing key; with a key in the server’s ~/.nika/keys/, the verdict is sealed.
5

Stop it

Ctrl+C (or SIGTERM) stops new admissions, then lets running and queued jobs finish for up to 30 seconds. A restart with the same --state-root resumes queued jobs; a job interrupted by the shutdown is not retried.

What changes from the local engine

After the constructor, the code reads the same, with four differences you just met:
  • Workflows by served name. workflows/hello.nika is the workflow’s path from the project root (the folder that holds nika.yaml), whatever --workflows says. A short name such as hello.nika answers not_found (404). listWorkflows() returns the exact names.
  • An idempotency key per job. run() over HTTP requires one. Retry a request whose response was lost with the same key and you get the same job, not a second one.
  • Two events, not six. The server streams run.started and the settlement, with an event.sequence cursor, and no per-task events.
  • No per-run maxCostUsd or model. The server caps every job at 1 USD by default (--run-cost-ceiling); see Spend caps.

The same client against nika serve, set up as the SDK README on GitHub does it. Unlike the steps above, hello.nika stays at the project root, so the server starts with --workflows . and serves it as hello.nika; the server runs in the background of the same terminal; and NIKA_KEYCHAIN=off nika key init gives it a signing key, so the verdict is sealed, not ok. /health reports engine 0.123.0 and machine protocol 2. The client, built with new Nika({ url, token, allowInsecureHttp: true }), lists and checks the served workflow, runs it with an idempotency key, receives the two sequenced events, reads verified · sealed, gets the same job back when it retries with the same key, and a typed 401 for a wrong token. The token is never printed. Recorded in a terminal from @supernovae-st/nika 0.123.0 and nika serve 0.123.0 on loopback; the run is a mock/echo rehearsal, with no provider key.

Serve other machines

Plain HTTP is accepted only to a loopback host (localhost, 127.0.0.0/8, [::1]), and only with allowInsecureHttp: true. To serve other machines, start the server with --allow-remote behind a reverse proxy that terminates TLS (the server does not), and connect with https://. Authentication is unchanged.

Jobs

Idempotency, recovery after a restart, status and cancellation.

Schedules

Declare a cadence on the server and change it by revision.

Server surfaces

Every route the released server answers.

Server runbook

Supervise, probe and investigate a resident.