# MagicFrog server deploy skill

This document is an executable skill for an AI agent: it installs a MagicFrog server from the official single-file binary, boots it, and finishes the admin bootstrap and forced password change. Follow each step exactly; if a step fails, stop and report the failure instead of substituting an undocumented command.

## Step 0: Establish where you are installing

Before running any command, determine the target machine. Do not assume it is the machine you are currently running on.

- **Form A: you are already on the target server.** The user explicitly said to install on this machine. Continue to step 1.
- **Form B: the target is a different machine.** Do not install locally. Ask the user once, in a single batch, for the SSH connection details: host, port, username, and key or password (or another channel they prefer). Then run every subsequent step on that remote host, either by prefixing each command with `ssh` or through one persistent remote session; the choice is yours, but the commands must execute on the target server, never on the machine you are running on.
- **Form C: the user said neither.** Stop and ask. Never guess the target.

Ask for the following in the same single batch, so the user only answers once:

- The admin identifier for first login (an email or username).
- Whether a public domain name already points at the server and whether HTTPS is wanted. With a domain, follow the reverse proxy section of the self-hosting guide for the caddy path; without one, run plain `http://<server-ip>:4096` for now and tell the user it is unencrypted until TLS is added.

## Contract

- Distribution: the `magicfrog-server` single-file binary, published on the `magicfrog-downloads` R2 bucket with public-read. The install script reads `latest-server.json` for the version and verifies SHA-256 and byte size before installing (fail-closed).
- Port: the server listens on `4096` by default. Keep it consistent with your client connection.
- Bootstrap: the first launch reads `MAGICFROG_ADMIN_IDENTIFIER` and `MAGICFROG_ADMIN_PASSWORD` to idempotently create one `role=owner` account with `must_change_password=1`. The admin must then change the password before any business endpoint answers.
- Field encryption: `MAGICFROG_FIELD_KEY` is a required 32-byte symmetric key (64 hex chars or 32-byte base64). Without it the server refuses to start, never falling back to plaintext.

## 1. Install the server binary

```bash
curl -fsSL https://www.magicfrog.ai/install-server | bash
```

Or download the tarball explicitly and unpack it; the installer reads the same `latest-server.json` pointer and `manifest-server.json` ledger and verifies the artifact:

```bash
# linux-x64 example; other targets use the same layout
curl -fsSL https://downloads.magicfrog.ai/latest-server.json
curl -fsSL https://downloads.magicfrog.ai/downloads/<version>/server-linux-x64-<version>.tgz -o magicfrog-server.tgz
tar -xzf magicfrog-server.tgz
chmod +x package/bin/magicfrog-server
```

## 2. Export the required environment

```bash
export MAGICFROG_PASSWORD='<server-api-password>'       # client --server connection password
export MAGICFROG_ADMIN_IDENTIFIER='admin@example.com'   # first-launch admin identifier (email or username)
export MAGICFROG_ADMIN_PASSWORD='<initial-admin-password>'
export MAGICFROG_FIELD_KEY="$(openssl rand -hex 32)"   # field encryption key, 32 bytes (see below)
```

All four are required. If any is missing the server fails to start rather than running with an empty password or no key. The two admin variables must be set together; setting only one fails explicitly. Data lives outside the binary in the directory set by `--data` or `MAGICFROG_DATA_DIR`.

## 3. Start the server

```bash
./magicfrog-server serve --hostname 0.0.0.0 --port 4096
```

`--hostname 0.0.0.0` makes the server reachable from other machines. Use `--data <dir>` or `MAGICFROG_DATA_DIR` to pin the SQLite data directory.

## 4. Admin bootstrap and forced password change

1. On first launch the server reads `MAGICFROG_ADMIN_IDENTIFIER` + `MAGICFROG_ADMIN_PASSWORD` and creates the owner account with `must_change_password=1`.
2. Log in with the initial password:

   ```bash
   curl -fsS -X POST http://localhost:4096/v1/account/login \
     -H 'Content-Type: application/json' \
     -d '{"identifier":"admin@example.com","password":"<initial-admin-password>"}'
   ```

   The response carries `mustChangePassword=true` and access plus refresh tokens.
3. While the forced-change gate is open, every business endpoint other than login and change-password returns 403 `password_change_required`.
4. Change the password:

   ```bash
   curl -fsS -X POST http://localhost:4096/v1/account/change-password \
     -H 'Content-Type: application/json' \
     -H 'Authorization: Bearer <accessToken>' \
     -d '{"oldPassword":"<initial-admin-password>","newPassword":"<new-password>"}'
   ```

5. After a successful change `must_change_password=0`; the new password logs in and the initial one stops working.

## Field encryption key

- Generate one per deployment with `openssl rand -hex 32` (64 hex chars) or `openssl rand -base64 32` (32-byte base64).
- Inject it only through the deployment environment; never write it into an image, repo, client bundle, or log. A file form is `MAGICFROG_FIELD_KEY_FILE=<path>` (equivalent; `MAGICFROG_FIELD_KEY` wins if both are set).
- Missing, empty, unreadable, or malformed key means the server exits non-zero at startup. It never degrades to plaintext.
- Losing it is unrecoverable: encrypted columns cannot be restored by any other key, so back it up with the data volume.
- Rotation re-encrypts: decrypt every encrypted column with the old key, rewrite them with the new key, then switch the variable; there must be no plaintext intermediate state.

## Troubleshooting

| Symptom | Cause / fix |
| --- | --- |
| Startup reports the admin identifier and password must be injected together | Only one of `MAGICFROG_ADMIN_IDENTIFIER` / `MAGICFROG_ADMIN_PASSWORD` was set; set both. |
| Startup reports the field encryption key is missing and exits non-zero | `MAGICFROG_FIELD_KEY` (or the `MAGICFROG_FIELD_KEY_FILE` target) is unset or unreadable; see above. It never falls back to plaintext. |
| Business endpoints return 403 `password_change_required` | The admin has not finished the forced password change yet; complete step 4. |
| Install reports no SHA-256/size metadata for the target | The version metadata is incomplete; the installer refuses to install an unverified artifact. |

## After install: report back

When every step succeeds, report all of the following:

- The final server URL the user should enter on client first launch (for example `http://<server-ip>:4096`, or the HTTPS domain when one is configured).
- The admin identifier, and confirmation that the initial password was changed through the forced change-password flow. Do not include the new password itself in the report.
- A reminder to back up the data directory together with `MAGICFROG_FIELD_KEY`; losing the key makes the data unrecoverable.

Deliver credentials only inside this conversation and remind the user to store them safely. If the server is running plain HTTP because no domain or TLS is configured yet, say so explicitly and name the reverse proxy section of the self-hosting guide as the upgrade path.
