App Deployer
Deploy and manage user applications (Node.js apps, Python scripts, Go binaries, Docker-less containers, etc.) as first-class managed processes on the OS.
Deploy Workflow
- Understand — Ask what to deploy. Determine the command, working directory, environment variables, and resource requirements.
- Deploy — Use
app_deploy with appropriate parameters. Default isolation uses DynamicUser=yes (ephemeral UID, no root).
- Verify — Use
app_list to confirm the app is running. Check app_logs for startup output.
- Store — Use
memory_store to remember what was deployed and why.
Example
User: "Deploy my Node.js API at /home/user/api"
1. app_deploy({
name: "user-api",
command: "/usr/bin/node",
args: ["server.js"],
working_dir: "/home/user/api",
env: { NODE_ENV: "production", PORT: "3000" },
port: 3000,
memory_max: "256M",
user: "user"
})
2. app_list() → confirm running, check PID
3. app_logs({ name: "user-api", lines: 20 }) → verify startup
4. memory_store({ summary: "Deployed user-api Node.js app", ... })
Managing Apps
- Status:
app_list shows all apps with live systemd state, PID, memory, CPU usage
- Logs:
app_logs pulls from journald — supports --since, --priority, line limits
- Restart:
app_restart — if the unit is active, calls systemctl restart. If inactive, re-deploys from registry
- Stop:
app_stop — stops the unit, marks as stopped in registry (preserved for restart)
- Remove:
app_remove — stops and permanently deletes from registry
Resource Limits
Apps run under systemd cgroups. Available limits:
| Parameter |
Example |
Effect |
memory_max |
"256M", "1G" |
Hard memory cap via MemoryMax= |
cpu_quota |
"50%", "200%" |
CPU time limit (200% = 2 cores) |
Isolation
- Default (
DynamicUser=yes): App runs as an ephemeral system user. No root, no access to other users' files. Best for self-contained binaries and services.
- Named user (
user: "username"): App runs as the specified user. Use when the app needs to read/write files owned by that user (e.g., /home/user/data).
Boot Persistence
Apps are registered in /var/lib/osmoda/apps/registry.json. The osmoda-app-restore service re-creates all running apps as transient systemd units on boot. Apps marked as stopped are not restored.
Best Practices
- Always specify
memory_max for production apps to prevent OOM issues
- Use
port parameter for discovery — system_discover will find the app
- Use named
user when the app needs filesystem access beyond its own binary
- Check
app_logs after deploy to catch startup errors immediately
- Use
app_restart (not stop + deploy) to preserve the same configuration
1---2name: app-deployer3description: Deploy and manage user applications as managed systemd services4---56# App Deployer78Deploy and manage user applications (Node.js apps, Python scripts, Go binaries, Docker-less containers, etc.) as first-class managed processes on the OS.910## Deploy Workflow11121. **Understand** — Ask what to deploy. Determine the command, working directory, environment variables, and resource requirements.132. **Deploy** — Use `app_deploy` with appropriate parameters. Default isolation uses `DynamicUser=yes` (ephemeral UID, no root).143. **Verify** — Use `app_list` to confirm the app is running. Check `app_logs` for startup output.154. **Store** — Use `memory_store` to remember what was deployed and why.1617### Example1819```20User: "Deploy my Node.js API at /home/user/api"21221. app_deploy({23 name: "user-api",24 command: "/usr/bin/node",25 args: ["server.js"],26 working_dir: "/home/user/api",27 env: { NODE_ENV: "production", PORT: "3000" },28 port: 3000,29 memory_max: "256M",30 user: "user"31 })322. app_list() → confirm running, check PID333. app_logs({ name: "user-api", lines: 20 }) → verify startup344. memory_store({ summary: "Deployed user-api Node.js app", ... })35```3637## Managing Apps3839- **Status**: `app_list` shows all apps with live systemd state, PID, memory, CPU usage40- **Logs**: `app_logs` pulls from journald — supports `--since`, `--priority`, line limits41- **Restart**: `app_restart` — if the unit is active, calls `systemctl restart`. If inactive, re-deploys from registry42- **Stop**: `app_stop` — stops the unit, marks as stopped in registry (preserved for restart)43- **Remove**: `app_remove` — stops and permanently deletes from registry4445## Resource Limits4647Apps run under systemd cgroups. Available limits:4849| Parameter | Example | Effect |50|-----------|---------|--------|51| `memory_max` | `"256M"`, `"1G"` | Hard memory cap via MemoryMax= |52| `cpu_quota` | `"50%"`, `"200%"` | CPU time limit (200% = 2 cores) |5354## Isolation5556- **Default** (`DynamicUser=yes`): App runs as an ephemeral system user. No root, no access to other users' files. Best for self-contained binaries and services.57- **Named user** (`user: "username"`): App runs as the specified user. Use when the app needs to read/write files owned by that user (e.g., `/home/user/data`).5859## Boot Persistence6061Apps are registered in `/var/lib/osmoda/apps/registry.json`. The `osmoda-app-restore` service re-creates all running apps as transient systemd units on boot. Apps marked as `stopped` are not restored.6263## Best Practices6465- Always specify `memory_max` for production apps to prevent OOM issues66- Use `port` parameter for discovery — `system_discover` will find the app67- Use named `user` when the app needs filesystem access beyond its own binary68- Check `app_logs` after deploy to catch startup errors immediately69- Use `app_restart` (not stop + deploy) to preserve the same configuration