OPERATE / NAH STUDIO
Host Studio where your agents can reach it.
Run the NAH Studio server as a long-lived Node process, keep its SQLite database on persistent storage, and send agent traces to its HTTP API. This guide covers local development and a single-host deployment.
What Studio does
NAH Studio is the dashboard and API for agent visibility: it stores agent registrations and run traces, serves the browser UI, and exposes live updates over server-sent events. The executable is nah-studio; nah serve is a convenience command from the NAH CLI that starts Studio locally.
Studio is separate from nah-js. Use nah-js to serve your own agent through a web application API. Use Studio to inspect agents and traces. An application can use both: serve user requests with nah-js and report those runs to Studio.
Start locally
On your development machine, start the dashboard from a shell or from an active nah session:
nah serve
# or choose a port
nah serve --port 5000
# check, print the URL, or stop it
nah serve status
nah serve url
nah serve stopFor a direct package invocation, nah-studio listens on 127.0.0.1:4111 by default. Open the printed URL in a browser. The loopback default needs no token.
Deploy a persistent Studio server
Install nah-studio on a supported Node host, provision a writable persistent directory for SQLite, and keep the process running under your process manager. For example:
export NAH_STUDIO_TOKEN='replace-with-a-long-random-secret'
npx --yes nah-studio \
+ --host 0.0.0.0 \
+ --port 4111 \
+ --db /var/lib/nah-studio/studio.sqlite \
+ --no-publishUse a process manager such as systemd, Docker with a mounted volume, or your platform's long-running service. Keep the database path on that persistent volume, restart the process after a crash, and route HTTPS traffic through your reverse proxy or platform ingress. Restrict access to the Studio host and its API to the users and agents that should see traces.
Set NAH_STUDIO_TOKEN in the service's secret environment. When Studio binds beyond loopback, it requires a bearer token on every request, including browser requests. Do not put the token in a URL or commit it to source control. --no-publish prevents this server from writing its endpoint to the service account's ~/.nah/studio.json; use it for a standalone deployment that remote clients configure explicitly.
Connect agents on the same host
When Studio starts without --no-publish, it writes its URL and token to ~/.nah/studio.json with owner-only file permissions. NAH CLI sessions running as that same OS user discover the endpoint and report agent presence and traces automatically. The endpoint file is local discovery; a process on another host cannot read it.
# Start Studio on this machine
nah serve
# In another terminal, start an agent as the same user
nah -p "Summarize the changes in this repository"Reporting is enabled when a live local Studio endpoint exists. Turn it off for a session with NAH_TELEMETRY=off, or use /telemetry off in the CLI to remember the preference.
Connect agents on another host
A remote NAH CLI does not currently have a supported setting to point its built-in telemetry discovery at a remote Studio URL: it reads the local endpoint file and checks that the recorded Studio process is alive on that machine. For agents you own, send trace data to Studio's HTTP API from your server-side agent runtime. The token belongs in server configuration, never in browser code.
The trace ingest endpoint accepts an agent identity, a trace, and its spans. This example shows the wire format; map your runtime's trace and span objects to the Studio schema.
const response = await fetch(`${process.env.NAH_STUDIO_URL}/api/traces`, {
method: "POST",
headers: {
"content-type": "application/json",
authorization: `Bearer ${process.env.NAH_STUDIO_TOKEN}`,
},
body: JSON.stringify({
agent: {
id: "support-prod-01",
name: "support-agent",
cwd: "/srv/support-agent",
host: process.env.HOSTNAME ?? "worker",
pid: process.pid,
model: "provider:model-id",
version: "1.0.0",
},
trace, // trace id, name, startTime, endTime, rootSpanId, status, tags, metadata
spans, // the spans belonging to this trace
final: true,
}),
});
if (!response.ok) {
throw new Error(`Studio ingest failed: ${response.status}`);
}Use a stable agent ID so runs group under one agent. A trace can also be posted in partial batches with final: false; the finished post uses final: true. Ingest is idempotent by trace ID, and a trace post registers its agent if needed. The server checks the token on every request.
Health checks and API
Use the health endpoint for a process or load-balancer check. Add the bearer header when the server is token protected.
curl --fail \
+ -H "Authorization: Bearer $NAH_STUDIO_TOKEN" \
+ https://studio.example.com/api/healthThe server also exposes GET /api/agents, GET /api/traces, GET /api/overview, and GET /api/stream. See the nah-studio API reference for the complete route list and query parameters.
Operational notes
- Back up the SQLite file while Studio is stopped or with a SQLite-aware backup process.
- Use one Studio process per database file; the documented deployment is a single long-lived instance with local SQLite storage.
- Studio can launch and stop agents only on the host where those processes run. A remote client reporting traces does not make its process controllable from Studio.
- Keep the server's working directory and
--nah-binconfigured appropriately if you use Studio features that launch agents or run workspace workflows.
For building an HTTP agent endpoint instead of hosting the observability dashboard, see nah-js and web frameworks.