# App Deployer

> Deploy and manage user applications as managed systemd services

- Skill: `bolivian-peru/app-deployer` (Agent Skill)
- Install (CLI): `npx skillmds@latest add bolivian-peru/app-deployer`
- Raw SKILL.md: https://api.skillmd.com/api/skills/bolivian-peru/app-deployer/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: DevOps & Infra
- Author: bolivian-peru (https://skillmd.com/u/bolivian-peru)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/bolivian-peru/app-deployer

---


# 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

1. **Understand** — Ask what to deploy. Determine the command, working directory, environment variables, and resource requirements.
2. **Deploy** — Use `app_deploy` with appropriate parameters. Default isolation uses `DynamicUser=yes` (ephemeral UID, no root).
3. **Verify** — Use `app_list` to confirm the app is running. Check `app_logs` for startup output.
4. **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

