| name | aomi-deploy |
| description | Use when integrating Aomi one-shot agent deploy into a host app or site — a partner platform (launchpad, portal, marketplace) that wants users to spin up a live Aomi agent and chat with it. Covers the `@aomi-labs/deploy` toolkit: mount the server-side BFF route factories (`/bff`), wire the browser client (`/launch`), supply credentials, and build a deploy UI in your own stack against the typed client. The stable product is the client contract, not a UI component — build the UI your product needs.
|
| compatibility | Host app must have a server that can expose HTTP route handlers (Next.js App Router is the reference; any (Request) => Response server works). Requires an Aomi backend URL + activation token. |
| license | MIT |
| allowed-tools | Bash, Read, Edit, Write |
| metadata | {"author":"aomi-labs","version":"0.1"} |
Integrate Aomi one-shot deploy
You are wiring Aomi one-shot agent deploy into a host app. Outcome: a user
clicks through a short flow and ends with a live Aomi agent they can chat
with. This is a thin, self-contained integration — you mount a few server
routes, point a browser client at them, and render a UI.
@aomi-labs/deploy is a typed relay to the Aomi platform. It does not run
agents or hold business logic; it drives the deploy lifecycle
(scaffold → deploy → CI build → activate → live) over the Aomi backend.
The one rule: the server/browser boundary
Get this wrong and you leak a bearer token to the browser. Two of the four
entry points are server-only:
| Import | Runs | Holds |
|---|
@aomi-labs/deploy | server only | DeploymentClient + the activation bearer |
@aomi-labs/deploy/bff | server only | route factories that mint/inject the bearer |
@aomi-labs/deploy/launch | browser | typed fetch client to your own BFF routes — no secrets |
@aomi-labs/deploy/lifecycle | browser | pure helpers projecting deploy records into UI state |
The browser never talks to the Aomi backend directly. It talks to your
same-origin BFF routes; those hold the token. Never import @aomi-labs/deploy
or /bff from a client component.
Prerequisites (get from Aomi)
- Backend URL for your platform, e.g.
https://api.aomi.dev.
- Activation token for your platform (server-side secret). Aomi issues it;
you never ship it to the browser.
- The Aomi GitHub App performs the repo scaffolding and deploy PRs. The
OAuth client-id is baked into the auth routes; the client secret lives in the
Aomi backend. You register nothing on GitHub.
Install
npm install @aomi-labs/deploy
Step 1 — Mount the BFF routes (server)
Every handler is a plain (Request) => Promise<Response>. Build them once in a
server-only module and export the handlers:
import {
createLaunchRoutes,
createGitHubAuthRoutes,
createGitHubSessionCodec,
} from "@aomi-labs/deploy/bff";
import { DeploymentClient } from "@aomi-labs/deploy";
const client = () =>
new DeploymentClient({
aomi: {
backendUrl: process.env.AOMI_BACKEND_URL!,
activationToken: process.env.AOMI_ACTIVATION_TOKEN!,
},
});
const session = createGitHubSessionCodec({ secret: process.env.AOMI_SESSION_SECRET! });
export const launch = createLaunchRoutes({
client,
session: (req) => session.fromRequest(req),
});
export const githubAuth = createGitHubAuthRoutes({
client,
session,
callbackPath: "/api/bff/auth/github/callback",
returnTo: "/deploy",
});
Mount them (Next.js App Router shown; any fetch server maps the same):
Swappable seams (this is the flexibility — don't fork, inject):
session — any (req) => GitHubSession | null. If you already have the
signed-in GitHub user from your own auth, pass a function that returns it and
skip createGitHubAuthRoutes entirely.
guards — { read, write } request guards. Defaults: per-IP rate limit +
same-origin CSRF. Override for your infra (e.g. shared-store rate limiting).
config — platform/template/target-tags. Defaults read APP_DEPLOY_* env.
githubToken — optional; enables CI status enrichment + rerun
(process.env.GITHUB_TOKEN by default).
Step 2 — Wire the browser client
import { createLaunchClient } from "@aomi-labs/deploy/launch";
const launch = createLaunchClient();
LaunchClient is the entire browser surface. Methods (all typed):
fetchGitHubSession() → { signedIn, githubLogin, installationId }
githubSigninUrl → href for a "Sign in with GitHub" link
githubAppInstallUrl({app:2}) → URL to install the Aomi GitHub App
createRepo({installationId, repoName}) → scaffold from the template
preflight(input) / deploy(input) → dry-run / apply
status({deploymentId}) → one poll: building | releasing | ready | failed
watch({deploymentId}, onEvent) → poll to completion, backoff, never throws
activate({releaseTags, apps})→ promote the built release to live
appStatus({name, releaseTag})→ confirm the app is loaded & live
sources() → the signed-in user's deployed agents
platform / forPlatform(name) → the bound platform; a client scoped to another
deployments.* → project console (sources, history, secrets, promote, …)
Targeting a named partner platform? Bind it once —
createLaunchClient({ platform: "somm.finance" }) — rather than passing it on
every call; omitting it on one call silently falls back to the host default.
Step 3 — Build the UI (in your stack)
There is no UI component to install. The deploy UI is a fast-churn page,
not a stable primitive — Aomi doesn't ship it as a package you vendor, because
a copied page rots the moment upstream changes and there's no upgrade path.
The stable thing is the createLaunchClient contract above; build the UI your
product actually needs on top of it, in whatever framework you use.
The smallest useful flow (the entire happy path) is:
fetchGitHubSession() → if not signed in, link to githubSigninUrl.
- If
installationId is null, send the user to githubAppInstallUrl({app:2}).
createRepo({ installationId, repoName }) → get appSourceId + sourceRef.
deploy({ appSourceId, sourceRef }) → get deploymentId.
- Poll
status(deploymentId) until ready (or failed).
activate({ releaseTags, apps }) (both come off the deploy result / status).
appStatus(...) until live, then embed chat:
https://chat.aomi.dev?app=<name>&application_id=<id>&lock_app=1.
Render it however the host brand wants — a single button, a stepper, a config
form, a conversational intake — because the contract underneath is just those
calls. A launchpad usually wants far less than a full dashboard: often just
"deploy" → status → chat, plus a stop control.
Want a worked example to read (not vendor)? Aomi's own portal builds this
exact flow in React against the same client — the deployment feature under
apps/portal/src/features/launch/ in the aomi-widget repo (the one-shot
wizard plus a full operator console: deploy, promote, deactivate, env vars).
Read it for the wiring, then write your own; don't copy it in, or you inherit
Aomi's design stack (Tailwind, @aomi-labs/react, the aomi-theme tokens) and a
page you'll have to hand-reconcile on every upstream change.
Verify it works
- Server routes return JSON, not HTML:
curl -s localhost:3000/api/bff/auth/github/status → {"signedIn":false,...}.
- No secret in the browser bundle: grep your client build for the activation
token — it must not appear. If it does, you imported
@aomi-labs/deploy or
/bff from a client component.
- End-to-end: sign in → install → create → deploy → the status poll reaches
ready → activate → the chat embed loads the live agent.
Constraints & honest gotchas
- GitHub-identity today. The current user path assumes the user signs in
with GitHub and the agent's source repo is created in their GitHub account.
Fine for a developer-facing portal; heavy for a consumer launchpad. If your
users shouldn't touch GitHub, you want a managed-source deploy (Aomi owns
the template, users only supply config) — that is a backend arrangement; ask
Aomi rather than working around it client-side.
- Immutable source ref.
deploy takes a git commit SHA, never a branch.
createRepo/preflight resolve it for you; if you deploy by appSourceId
directly, pass the SHA.
- Secrets are write-only. App env-vars/secrets, where supported, return
key names only — values are never read back.
- Errors. BFF routes answer
{ error } with a faithful HTTP status
(launchErrorResponse maps DeployError/BackendError). Surface
json.error to the user.
- Not yet in the browser client: operator lifecycle (deactivate/"stop",
promote/rollback, deploy history) exists at the SDK layer but is not exposed
through
createLaunchClient yet. If you need a "stop my agent" button, add a
BFF route over DeploymentClient and a client method — ask Aomi for the
current shape.