Appearance
Machine-Readable State
An agent cannot act on infrastructure it cannot see. Nanokit exposes its view of the world as structured data — not log scrapes — through three channels.
What is observable today
State is reported per project and per environment for four resource families:
| Family | What state includes |
|---|---|
| Services | Desired vs. running status, image/config drift, health, exposure |
| Databases | Engine, mode, branch topology, volume backing |
| Secrets | Which keys are declared/resolved — never their values |
| Domains | Declared hosts, TLS/certificate state |
Channel 1 — the bridge WebSocket
A bridge process runs alongside your project and listens on ws://127.0.0.1:3006 by default (override with -p or $NANOKIT_BRIDGE_PORT). It is started and managed for you by nkapp up, or explicitly with nkapp hub --start.
It carries telemetry and accepts request/response messages, so an agent can read live state and trigger guarded actions (e.g. volume maintenance) over a single persistent connection. The protocol is message-based JSON validated against Zod contracts — see UI Bridge (WebSockets) for the wire details.
Typical loop for an agent:
- Connect to the bridge.
- Request current inventory (services/databases/secrets/domains).
- Compare against intent; if a change is needed, edit
nanokit.yml(see The Declarative Contract). - Re-read state to verify convergence.
Channel 2 — the CLI
The same information is available offline via nkapp:
| Command | What it gives an agent |
|---|---|
nkapp plan -e <env> | The exact reconcile plan before anything executes — the cheapest way to validate a config edit. Also written as JSON to .nanokit/plans/latest.json (or --output <path>), which is the most directly machine-readable artifact Nanokit produces today. |
nkapp doctor | Environment health and common failure classes, including container and image accumulation. Always exits 0, so parse the output rather than the exit code. |
nkapp infra resources | A live cloud inventory queried straight from the provider APIs (--orphans for resources not declared in the config) — distinct from infra status, which reads the possibly-stale local state file. |
nkapp secrets list | Declared secret keys; values are never printed. |
nkapp export k8s | The whole config as standard Kubernetes manifests — a fully structured rendering of intent, no cluster required. |
Most output is human-formatted
Apart from the plan JSON and export k8s/export helm, the CLI prints human-readable tables and coloured text, not a stable machine format. There is no global --json flag today. Treat CLI stdout as a convenience surface and prefer the plan JSON or the bridge messages for anything a program must depend on.
Both channels report state, never narrative: consumers get typed fields they can branch on, which is what makes closed-loop agent behavior tractable — the loop terminates because convergence is checkable.
Channel 3 — the MCP server
nkapp mcp serves the same state as typed tool results, with no parsing: get_environment (one environment's full structured state, including a drift hash, secret keys only), get_state (live inventory with blast-radius flags), get_plan, get_deploy_scope, list_services, list_databases, list_secrets, list_domains, list_backups, get_logs (capped and redacted) and doctor. Every response is a JSON envelope with ok, data, error, warnings and meta. This is the channel to prefer when the consumer is an agent host.
The same server also takes changes, under a plan-then-apply rule and the declarative agent: policy block. See The MCP Server.
Direction
Still on the roadmap, not shipped:
- Filtering the tool list by your team role. The resolver exists, but the server does not yet resolve the role from your account token, so today only the
agent:block filters. - Destructive agent tools (
destroy,restore, deleting a database branch). These remain human-only commands. - A Hub "Agent activity" panel with approve-from-Hub, and a hosted (remote) MCP endpoint.