From manaurum-dev-sdk
Deploy a ManAurum OS app. As of 2026-05, the default flow is Platform v2 (containerized — `POST /api/dev/v2/deploy` with an `mna_*` token). Legacy v1 (iframe bundle — `POST /api/dev/apps/deploy` with an `mnu_*` token) is supported for existing apps. Use whenever the user wants to deploy, publish, host, upload, or release their ManAurum/SeregaOS app. Covers token issuance, build context preparation, deploy contract, rejection codes, rollback, and the post-deploy install/open flow.
How this skill is triggered — by the user, by Claude, or both
Slash command
/manaurum-dev-sdk:manaurum-deployThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
> ## ⚡ v2 is the default (2026-05)
⚡ v2 is the default (2026-05)
Two paths exist. Pick by token format the user has:
mna_*→ v2 hosted runtime.POST /api/dev/v2/deploy. Builds a Docker image from a tarball, pushes to a private registry, runs as a Swarm service, exposes athttps://<slug>.apps.manaurum.com. Default for all new work.mnu_*→ v1 iframe runtime.POST /api/dev/apps/deploy. Uploads a zip bundle, served in an iframe at/t/<tenant>/apps/<slug>. Legacy — only for existing v1 apps.If unsure or the user has neither, ask them to mint an
mna_*from Dev Hub → "v2 Tokens (Beta)" → Generate. The two surfaces are not interchangeable — amnu_*token will be rejected by the v2 endpoint and vice versa.
mna_* token in .env.manaurum as MANAURUM_V2_TOKEN=.... Mint one in Dev Hub → "v2 Tokens (Beta)" → Generate. Shown ONCE, save immediately.manifest_v2.json + Dockerfile + your source files. See manaurum-app/SKILL.md for the full manifest reference.cd my-app
tar cf /tmp/ctx.tar \
--exclude='.env*' --exclude='.git' --exclude='node_modules' \
--exclude='deploy.sh' --exclude='*.tar' --exclude='*.zip' \
.
B64=$(base64 -w0 /tmp/ctx.tar)
jq -n \
--arg b "$B64" \
--argjson m "$(cat manifest_v2.json)" \
'{manifest_json: $m, archive_b64: $b}' > /tmp/deploy.json
curl -sS -X POST https://manaurum.com/api/dev/v2/deploy \
-H "Authorization: Bearer $MANAURUM_V2_TOKEN" \
-H "Content-Type: application/json" \
-d @/tmp/deploy.json | jq .
Successful response (sync — usually returns in ~7–10s):
{ "deploy_job_id": "...", "status": "succeeded" }
If status: pending (rare for hosted runtime), poll the job:
curl -sS https://manaurum.com/api/dev/v2/deploy/<deploy_job_id> \
-H "Authorization: Bearer $MANAURUM_V2_TOKEN" | jq .
Final response carries the URL:
{
"status": "succeeded",
"result": {
"app_id": "<uuid>",
"version_id": "<uuid>",
"image_tag": "manaurum-registry:5000/v2-app-my-app:1.0.0",
"url": "https://my-app.apps.manaurum.com"
}
}
The URL is live with a Let's Encrypt cert within seconds of the deploy completing.
migration.breaking: true).POST /build to the engine API).manaurum-registry.v2_apps + v2_app_versions rows under the home tenant (FORCE-RLS).v2-app-<slug>-<tenant_short> on dokploy-network./etc/dokploy/traefik/dynamic/v2-app-<slug>.yml so the URL routes to the service.jq '.version = "1.0.1"' manifest_v2.json > /tmp/m && mv /tmp/m manifest_v2.json
# rerun the curl above — the platform updates the swarm service in-place
The URL stays the same. Existing connections drain; new requests hit the new version.
curl -sS -X POST https://manaurum.com/api/dev/v2/apps/<app_id>/rollback \
-H "Authorization: Bearer $MANAURUM_V2_TOKEN"
Restores the previous version's image. Same URL, no traffic interruption.
# describe
curl -sS https://manaurum.com/api/dev/v2/apps/<app_id> -H "Authorization: Bearer $MANAURUM_V2_TOKEN"
# version history
curl -sS https://manaurum.com/api/dev/v2/apps/<app_id>/versions -H "Authorization: Bearer $MANAURUM_V2_TOKEN"
# tail logs (stub — full streaming TBD)
curl -sS https://manaurum.com/api/dev/v2/apps/<app_id>/logs -H "Authorization: Bearer $MANAURUM_V2_TOKEN"
| HTTP | error | Meaning | Fix |
|---|---|---|---|
| 401 | invalid_credential | Bad/expired/revoked mna_* token, or not an mna_*. | Mint a fresh one in Dev Hub. |
| 401 | missing_authorization | No Authorization header. | Add -H "Authorization: Bearer $MANAURUM_V2_TOKEN". |
| 412 | missing_tenant_id_header | (capability calls only) X-Manaurum-Tenant-Id not set. | Set it from process.env.MANAURUM_TENANT_ID. |
| 422 | manifest validation failed | Manifest fails v2 JSON Schema. | Read errors[]. Common: bad app_id slug, non-semver version. |
| 422 | migration_validation_failed | Destructive DDL without migration.breaking: true. | Make additive-only or set breaking: true. |
| 422 | invalid_archive_b64 | Bundle isn't valid base64. | Use base64 -w0 (no line wrapping). |
| 502 | (in result.error) | Image build failed. | Inspect the error string — usually a Dockerfile issue (COPY src not found, missing EXPOSE, etc.). |
The v2 manifest's visibility.mode controls which tenants can install the app:
private (default) — only the home tenant (the one tied to your mna_* token) sees it.public — any tenant can install it via App Store v2.allow_list with a tenants array — explicit list of tenant UUIDs.For public / allow_list, the install itself is initiated by a tenant admin in the consuming tenant via POST /api/app-store/v2/install. The deploy is a separate operation done once by the developer.
This is fundamentally different from v1, where each tenant requires its own deploy. v2 has a global app registry; v1 had per-tenant catalogs.
Don't use this for new apps. v1 is for maintaining existing iframe-based builtins.
mnu_* token (NOT mna_*). Mint via:
curl -sS -X POST https://manaurum.com/api/developer/tenant-tokens \
-H "Authorization: Bearer $SESSION_JWT" \
-H "Content-Type: application/json" \
-d '{"name": "ci-deploy"}'
Or via Dev Hub → "API Tokens" tab in the UI. Default scopes ["app.deploy", "app.read"].manifest.json (v1 schema — manifest_version: "1") + a zip bundle with index.html at the root.cd my-app
zip -r bundle.zip . -x "*.DS_Store" "node_modules/*" ".git/*" ".env*"
B64=$(base64 -w0 bundle.zip)
jq -n --arg b "$B64" --slurpfile m manifest.json '{manifest: $m[0], bundle: $b}' \
| curl -sS -X POST https://manaurum.com/api/dev/apps/deploy \
-H "Authorization: Bearer $MANAURUM_TENANT_TOKEN" \
-H "Content-Type: application/json" \
-d @- | jq .
Success body:
{
"application_id": "...",
"version_id": "...",
"version_number": "1.0.0",
"url": "/t/<tenant_slug>/apps/<app_slug>"
}
After deploy, a workspace owner inside the same tenant must install the app via the AppStore desktop app. Members can then open /t/<tenant_slug>/apps/<app_slug> and the iframe loads.
.html .htm .js .mjs .jsx .ts .tsx .css .svg .png .jpg .jpeg .gif .webp .ico .avif .woff .woff2 .ttf .otf .eot .txt .md .map .webmanifest.sk_live_, AKIA, ghp_, …), undeclared 3rd-party SDKs, disallowed URLs.| HTTP | rejection | Fix |
|---|---|---|
| 401 | rejected_token_invalid | Issue a fresh mnu_*. |
| 403 | rejected_insufficient_scope | Token needs app.deploy. |
| 400 | rejected_manifest_invalid | Read findings[]; fix manifest. |
| 400 | rejected_version_conflict | Bump semver. |
| 413 | rejected_bundle_too_large | > 50 MB — trim. |
| 422 | rejected_bundle_credential_detected | Remove the credential. |
| 422 | rejected_bundle_sdk_undeclared | Declare in manifest.integrations[]. |
A mnu_* token is bound to ONE tenant. Deploying the same app to a second tenant requires a separate mnu_* from THAT tenant.
# list (no raw_token returned)
curl -sS https://manaurum.com/api/developer/tenant-tokens \
-H "Authorization: Bearer $SESSION_JWT"
# revoke
curl -sS -X DELETE "https://manaurum.com/api/developer/tenant-tokens/<token_id>" \
-H "Authorization: Bearer $SESSION_JWT"
Cap: 5 active tokens per (user, tenant). Revoke an old one if you hit 409 max_active_tokens_reached.
deploy.sh template (v2)When scaffolding a new project, drop this in:
#!/bin/bash
# Deploy a v2 ManAurum app — POST /api/dev/v2/deploy
set -e
if [ -f .env.manaurum ]; then
set -a; source .env.manaurum; set +a
fi
if [ -z "$MANAURUM_V2_TOKEN" ]; then
echo "Error: MANAURUM_V2_TOKEN not set. Mint one at https://manaurum.com (Dev Hub → v2 Tokens)."
echo "Save as MANAURUM_V2_TOKEN=mna_<...> in .env.manaurum"
exit 1
fi
if [ ! -f manifest_v2.json ]; then
echo "Error: manifest_v2.json missing. See manaurum-app/SKILL.md."
exit 1
fi
if [ ! -f Dockerfile ]; then
echo "Error: Dockerfile missing. v2 apps build images."
exit 1
fi
echo "Bundling build context…"
tar cf /tmp/ctx.tar \
--exclude='.env*' \
--exclude='.git' \
--exclude='node_modules' \
--exclude='deploy.sh' \
--exclude='*.tar' \
--exclude='*.zip' \
.
echo "Deploying…"
B64=$(base64 -w0 /tmp/ctx.tar)
RESP=$(jq -n --arg b "$B64" --argjson m "$(cat manifest_v2.json)" \
'{manifest_json: $m, archive_b64: $b}' \
| curl -sS -X POST https://manaurum.com/api/dev/v2/deploy \
-H "Authorization: Bearer $MANAURUM_V2_TOKEN" \
-H "Content-Type: application/json" \
-d @-)
JOB_ID=$(echo "$RESP" | jq -r .deploy_job_id)
STATUS=$(echo "$RESP" | jq -r .status)
echo "Job: $JOB_ID — status: $STATUS"
if [ "$STATUS" != "succeeded" ]; then
curl -sS https://manaurum.com/api/dev/v2/deploy/$JOB_ID \
-H "Authorization: Bearer $MANAURUM_V2_TOKEN" | jq .
exit 1
fi
curl -sS https://manaurum.com/api/dev/v2/deploy/$JOB_ID \
-H "Authorization: Bearer $MANAURUM_V2_TOKEN" \
| jq -r '.result | "✓ Live at \(.url)"'
rm -f /tmp/ctx.tar
Make executable: chmod +x deploy.sh.
Provides CDSS development patterns for drug interaction checking, dose validation, clinical scoring (NEWS2, qSOFA), and alert classification integrated into EMR workflows.
npx claudepluginhub sergeysuaib-ui/manaurum-dev-sdk --plugin manaurum-dev-sdk