Genie CLI
genie — terminal access to your workspace. Templates, pages, social, marketing, lists, webhooks, logs.
The genie CLI gives you a terminal to a GenieOS workspace.
It covers the same public API surface the SDKs use, so CI, local
dev loops, and ad-hoc scripts can do the same things.
Install
npm install -g @genie-os/clipnpm add -g @genie-os/cliyarn global add @genie-os/clibun install -g @genie-os/clinpx -y @genie-os/cli help
# pnpm dlx @genie-os/cli help
# bunx @genie-os/cli helpThe CLI binary is genie. Verify:
genie --version
# 0.1.0No system dependencies, runs on Node 18+. The published package is fully self-contained (the SDK is bundled in), so global installs add zero runtime dependencies.
Authenticate
genie loginOpens a TTY prompt: create a key at
app.genieos.pro → Settings → API keys,
paste the gos_live_* (or gos_test_*) value, and the CLI writes it to
~/.genieos/credentials.json (mode 600). That key is shared by every
subsequent command.
For headless contexts (CI), set GENIEOS_API_KEY and skip login:
export GENIEOS_API_KEY=gos_live_...
genie whoamiwhoami prints the workspace name, plan, scopes, and rate limit.
Shape of the surface
Every subcommand follows the same noun-verb form, mirroring the REST API and the SDKs:
genie whoami
genie keys list | get
genie templates list | get | render | send | create | compose
genie sequences list | get | enroll
genie events emit
genie webhooks list | create | delete
genie pages list | get | publish | unpublish
genie brand list | get
genie sms kit | catalog | send | deliveries
genie social networks | posts | get | create | schedule | publish | delete
genie marketing strategy | icps | defaults | set-defaults
genie creations list | get | spawn | approve
genie lists list | get | create | add-members
genie links list | get | utm-suggestions | create | update | analytics
genie qr create | render
genie logs tailReuse prior UTMs, then create a tracked short link
# See what the workspace has used before (same as Links designer autocomplete)
genie links utm-suggestions
genie links utm-suggestions --field=source
genie links list --limit=20
genie links create --url=https://acme.com/sale \
--slug=summer \
--label="Summer sale" \
--utm-source=newsletter \
--utm-medium=email \
--utm-campaign=summer-2026 \
--utm-content=hero-cta \
--tags=launch,q3
genie links get lnk_…
genie links update lnk_… --destination-url=https://acme.com/sale-v2
genie links analytics --link-id=lnk_… --days=30
# QR design → print PDF into Assets
genie qr create --link-id=lnk_… --label="Flyer QR"
genie qr render qr_… --format=pdf --save-to-assetsUTMs are stamped onto the redirect destination at click time. Scope:
links:read for list / get / suggestions / analytics / render;
links:write for create / update / QR create and render-with-save
(create link = 1 credit; QR create = 1 credit; print PDF = 5 credits).
--help is wired up at every level:
genie webhooks --help
genie social --helpCommon workflows
Compose a draft from a brief
genie templates compose "Welcome email for new Glow subscribers — warm, one CTA" \
--key=welcome-glow \
--name="Welcome · Glow"Charges compose-template credits; returns id / key / subject. Open
the draft in the designer to refine, then send:
genie templates send welcome-glow \
--to=ada@example.com \
--vars='{"first_name":"Ada"}'Create a blank draft
genie templates create --name="Untitled promo" --key=promo-blankSame seed as New email in the SPA. Prefer compose when you have a brief.
Send a one-off transactional
Useful for support flows / smoke tests:
genie templates send welcome \
--to=ada@example.com \
--vars='{"first_name":"Ada","plan":"pro"}'Tail the audit log
genie logs tail
genie logs tail --interval=5000 --limit=50Each line is a JSON object — actor, action, target, request id, ts.
CI usage
Every command exits non-zero on failure and writes errors to stderr in the standard envelope:
// stderr
{
"error": {
"type": "validation_error",
"code": "schema_contract_violation",
"fields": [...]
}
}So CI scripts can pipe stderr through jq for fine-grained matching.
A typical "compose a draft in CI" GitHub Action:
name: Compose welcome draft
on:
workflow_dispatch:
inputs:
brief:
description: Email brief
required: true
jobs:
compose:
runs-on: ubuntu-latest
steps:
- run: npm install -g @genie-os/cli@latest
- env:
GENIEOS_API_KEY: ${{ secrets.GENIEOS_API_KEY }}
run: |
genie templates compose "${{ inputs.brief }}" \
--key=welcome-ci \
--name="Welcome (CI)"Configuration
~/.genieos/config.json (created on first login):
{
"default_workspace": "ws_01JABC...",
"base_url": "https://api.genieos.pro",
"credentials_path": "~/.genieos/credentials.json"
}Override per-command with flags or env:
genie --workspace ws_OTHER ... # one-off
GENIEOS_BASE_URL=https://staging.api.genieos.pro genie ... # stagingLogout
genie logoutRemoves the credentials file. Does not revoke the key on the server — revoke from app.genieos.pro → Settings → API keys.
The CLI is the SDK
Internally, the CLI is a thin wrapper around @genie-os/sdk. Anything
the CLI can do, your Node code can — the CLI just wires up TTY,
credentials, and pretty output. If you find yourself shelling out from
Node, import the SDK instead.