node-app-build 6.5.0

Mini app developer CLI: scaffold, validate, package node-app-* Debian packages
# 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

| File | Why |
|---|---|
| `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.