@ossy/cli
v1.40.3
Published
Command line tool that makes it easier to interact with our APIs
Downloads
1,724
Readme
@ossy/cli
Unified CLI for the Ossy platform.
Install
npm install -g @ossy/cliAfter install, the ossy command is on your PATH:
ossy --version
ossy --help
ossy <command> --helpFor one-off use without installing, you can still run npx @ossy/cli <command>.
How the CLI is organized
The contract for everything the platform can do is the SDK action POJO in @ossy/sdk ({ id, endpoint, method, payload }). The CLI is one channel onto that catalog, organized in three layers:
- Local utilities — no API call, or per-machine state.
auth,workspace,app init,app build,app validate. - Action dispatcher —
invoke <action.id>invokes any action in the SDK catalog. New endpoints added to the SDK are callable from the terminal with no extra CLI wiring. - High-level workflows — verbs that wrap one or more actions and add value the dispatcher doesn't (reading
src/config.js, formatting output for CI, multi-step pipelines). Each workflow's docs name the underlying action(s) so you can drop down toossy invokeif you outgrow the verb.
| Layer | Command | Description |
|-------|---------|-------------|
| Local | auth login \| logout \| status | Save / delete / inspect the Ossy API token under ~/.config/ossy/credentials.json |
| Local | workspace use <id> \| list \| current | Manage the active workspace (saved to ~/.config/ossy/config.json) |
| Local | app init [dir] | Scaffold a new Ossy app (default: current directory) |
| Local | app build | Production build of the app in the current directory |
| Local | app validate | Validate src/config.js (workspaceId) without calling the API |
| Dispatcher | invoke <action.id> | Invoke any Ossy SDK action by id (ossy invoke --help for the full catalog) |
| Workflow | app upload | Informational — schemas live in *.schema.js and are discovered at app build |
| Workflow | app publish | Upload build/ to the CMS and register the app domain |
| Workflow | upload-dir <dir> <location> | Recursively mirror a local directory into the CMS (mkdir + upload per file) |
If you need an endpoint that no verb wraps, reach for ossy invoke — it's the universal channel.
Auth and active workspace
Once installed, the recommended flow is to log in once and pick an active workspace; subsequent commands inherit those:
ossy auth login # paste your Ossy API token
ossy workspace list # see workspaces you can access
ossy workspace use <workspace-id> # set the active one
ossy auth status # confirmCredentials live in ~/.config/ossy/credentials.json (chmod 600); the active workspace lives in ~/.config/ossy/config.json. Both honor XDG_CONFIG_HOME.
Resolution order for every command that needs auth:
--authentication/-aflagOSSY_API_KEYenv var- Saved credentials
Resolution order for the workspace id (when a command isn't reading it from src/config.js):
--workspace-id/-wflagOSSY_WORKSPACE_IDenv var- Saved active workspace
So existing CI scripts that set OSSY_API_KEY keep working unchanged; you only need ossy auth login for interactive use.
Generic dispatcher: ossy invoke
ossy invoke invokes any Ossy API action by id. The action catalog comes from @ossy/sdk, so any new endpoint added to the SDK is callable from the terminal with no extra wiring.
# Discover what's available
ossy invoke --help # full catalog, grouped by domain
ossy invoke resources.create --help # one action's method, endpoint, default payload
# Read calls
ossy invoke workspaces.get-current
ossy invoke resources.list --search 'location=/docs'
# Write calls — flag names map to payload keys (--first-name -> firstName)
ossy invoke resources.create-directory --location /docs --name images
ossy invoke workspaces.invite-user --email [email protected]
# Use --json for nested or non-string payloads
ossy invoke resources.update-content --id res_abc --json '{"content":{"title":"Hi"}}'
# Upload a file: --file fills name/type/size as defaults, then PUTs the bytes
# when the response carries content.uploadUrl (works for resources.upload,
# resources.upload-named-version, etc.)
ossy invoke resources.upload --location /docs --file ./hero.jpg
ossy invoke resources.upload-named-version --id res_abc --name medium --file ./hero.jpg
# Per-call overrides (otherwise resolved from `ossy auth login` / `ossy workspace use`)
ossy invoke workspaces.get-all -a <jwt> --api-url http://localhost:3001/api/v0Output is JSON pretty-printed to stdout on success. Errors go to stderr with a non-zero exit. Add --raw to get the response body verbatim (useful for piping non-JSON responses).
--file <path> is a shortcut for upload-style actions: the CLI stats the file, fills name/type/size as defaults (any explicit --name / --type / --size flag wins), and after the dispatch it PUTs the bytes to result.content.uploadUrl with the right Content-Type/Content-Length. If the response doesn't include an upload URL, the bytes are skipped and a warning is printed.
App: build
ossy app buildOptions: e.g. --config for src/config.js. See packages/app/README.md for app build behavior.
App: publish
Publishes a built app: mirrors the build/ folder into the CMS and registers the domain → workspace mapping. Run from the app package directory (where src/config.js lives) so config values are read automatically.
Schemas are not uploaded by app publish — they come from installed packages' *.schema.js files and are merged into the app manifest at app build time.
cd packages/my-website
npm run build # produce build/ first (discovers schemas)
ossy app publish # reads src/config.js, uploads build/Workflow:
- Upload
build/to the CMS →@ossy/resources/actions/create-directory+@ossy/resources/actions/uploadper file (same pattern asupload-dir), default destination/@ossy/apps/{domain}. - Register
domain→workspaceIdviaPOST /apps/domains.
Config extraction
publish reads workspaceId, apiUrl, and domain from src/config.js without executing it (static regex + Babel AST parse), so imports like @ossy/themes that only resolve under Rollup are never run.
Authentication
Requires --authentication / -a or OSSY_API_KEY: an Ossy API JWT (workspace API token).
cd packages/my-website
export OSSY_API_KEY=<ossy-api-jwt>
npm run build
ossy app publish
# or with explicit options:
ossy app publish \
--config src/config.js \
--build-dir ./build \
--build-dest /@ossy/apps/my-site.seOptions
| Flag | Description |
|------|-------------|
| -a, --authentication | Ossy API JWT (or OSSY_API_KEY, or ossy auth login) |
| -c, --config | Path to src/config.js (default: ./src/config.js) |
| --build-dir | Override build directory (default: <package>/build) |
| --build-dest | Override remote CMS location (default: /@ossy/apps/{domain}) |
| --api-url | API base URL (or OSSY_API_URL; relative apiUrl in config is ignored) |
CI example
- name: Publish
run: |
npm run build
npx --yes @ossy/cli app publish \
--authentication ${{ secrets.OSSY_API_KEY }}App: upload
Deprecated as an upload workflow. ossy app upload now prints guidance that schemas are defined in package *.schema.js files and discovered automatically at app build time — it does not POST to the API.
To import schemas manually (e.g. one-off workspace bootstrap), use the dispatcher:
ossy invoke @ossy/workspaces/actions/import-schemas --json '{"schemas":[…]}'The low-level HTTP helper postSchemas() in upload-schemas.js targets POST /schemas when you need a direct fetch from custom tooling.
Config consistency
- App (
build), app (app upload/app validate/app publish), and upload-dir all use--config(-c) for the app / workspace config file (src/config.jsby default when present).
Workflow example
Prefer app publish after app build so the built site is deployed. Schemas ship with the build manifest — no separate upload step.
name: Deploy app
on:
workflow_dispatch:
jobs:
publish:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: "20"
- run: npm ci && npx ossy app build
- run: npx ossy app publish --authentication ${{ secrets.OSSY_API_KEY }}app validate
Validate an ossy config file before uploading:
ossy app validate --config src/config.jsWhen --config is omitted, ./src/config.js is used if it exists.
Arguments
| Argument | Description | Required |
|----------|-------------|----------|
| --authentication, -a | Ossy API JWT (primary; same role as OSSY_API_KEY) | Yes (upload only) |
| --config, -c | App config (workspaceId, …) | Optional if ./src/config.js exists |
| --api-url | API base URL for upload (…/api/v0) | No |
Upload a directory
Recursively mirrors a local directory tree into the Ossy CMS, preserving the folder structure.
ossy upload-dir ./public /my-folderThis:
- Walks the local tree and collects all subdirectories (breadth-first) and files.
- Creates each remote directory with
resources.create-directory(parents before children; already-existing directories are skipped silently). - Uploads each file with
resources.upload+ S3 presigned PUT, in the same order they were discovered. - Logs per-item progress and prints a summary at the end.
Per-item errors are logged and skipped — the command continues to the next item and exits non-zero when any item failed.
Options:
| Flag | Description |
|------|-------------|
| --dry-run | Print what would happen without making any API calls |
| -a, --authentication | Ossy API JWT (or OSSY_API_KEY, or ossy auth login) |
| -w, --workspace-id | Workspace id (or OSSY_WORKSPACE_ID, or ossy workspace use) |
| --api-url | Override the API base URL |
Examples:
# Preview before committing
ossy upload-dir ./public /my-folder --dry-run
# Upload into a nested location
ossy upload-dir ./assets /projects/2026/assets
# Point at a local API
ossy upload-dir ./public /my-folder --api-url http://localhost:3001/api/v0App: init
Scaffold a new Ossy app:
ossy app init
ossy app init my-appCreates src/home.page.jsx, src/config.js, and package.json (if missing).
