# AGENTS.md — coding agent onboarding for {{name}}
> **You are a coding agent working in `node-app-{{name}}`.**
> This app was scaffolded by `node-app new --profile standalone-native`.
> It is a **standalone Rust binary** with its own systemd unit. The platform
> discovers it via `manifest.json` but does NOT own its lifecycle —
> `systemctl start node-app-{{name}}.service` does.
## Why standalone? Why am I NOT shared-runtime eligible?
Standalone is the **escape hatch** in the node-app model. It exists for
apps that genuinely need:
- Their own systemd unit (long-lived hardware bridges, LCD daemons, OTA
controllers, anything that must survive a `node.service` restart).
- A process lifecycle the platform should NOT own.
- A separate user/group, capabilities, RuntimeDirectory, etc.
Because the platform does not start or stop this process, this app is
**explicitly excluded** from the shared Bun runtime feature (#810). That
feature is also Bun-only — Rust apps wouldn't benefit from it either way.
Compared to `--profile native`: native apps load **in-process** inside
`node.service` via `dlopen`. They get faster invocations (no UDS round-
trip), but a panic crashes the host. Standalone gives you process
isolation at the cost of an extra hop.
If you don't have a specific reason to be standalone, **move to
`--profile native` instead** — same Rust, but loaded by the platform.
## How the platform talks to me
- The platform reads `manifest.json` from `/usr/lib/node/apps/{{name}}/`
and routes inbound `{{name}}.*` capability invocations to the UDS at
`/run/node-app-{{name}}.sock` as line-delimited JSON-RPC 2.0.
- The skeleton in `src/main.rs` is a minimal Tokio event loop with a
graceful shutdown signal — wire your UDS dispatcher there.
- For outbound platform capability calls (e.g. `core.notifications.create`,
`core.cron.register`), this app should dial `/run/node/control.sock`
itself. The systemd unit's `Group=node` makes the SO_PEERCRED check
pass.
## First files to open
| `src/main.rs` | Tokio entry point — wire your UDS dispatcher here |
| `manifest.json` | declare capabilities; `app_type: "standalone"`, `standalone.socket_path` |
| `systemd/node-app-{{name}}.service` | the systemd unit |
| `Cargo.toml` | add crate deps (Tokio, serde, tracing pre-installed) |
| `node-app.toml` | per-app dev config |
## Useful commands
```bash
node-app audit # check this app against the blueprint
node-app dev # hot-reload dev loop against a local monorepo
cargo build --release # build the binary
node-app package # build .deb (phase 3 of #868; standalone wiring planned)
```
## Don'ts
- Don't expect shared-runtime memory savings. That feature is Bun-only.
- Don't bind a TCP listener for the platform-facing API; use the UDS at
`manifest.standalone.socket_path`.
- Don't HTTP-loopback to platform ports; use JSON-RPC over
`/run/node/control.sock`.
- Don't run as a non-`Group=node` user without re-checking
`/run/node/control.sock` peer-cred behaviour.
- Don't use `.unwrap()` in production paths — the systemd unit will
`Restart=on-failure`, but a panic loop is worse than a graceful error.