@gsb-core/cli
v0.1.3
Published
CLI tool for syncing GSB serverless functions and libraries
Readme
GSB CLI Tool
A command-line interface for syncing GSB serverless functions and libraries to the GSB backend.
Features
- 🚀 Push TypeScript/JavaScript files to GSB backend
- 📄 Pull/Push document templates with multilingual support
- 🧪 Test functions without saving them
- 📋 Dry-run mode to preview changes
- 🔧 Auto-detection of function vs library types
- 📖 Support for metadata files
- 📁 Organized folder structure for document templates
- ⚙️ Configuration from existing MCP setup
Installation
Node.js 20 or newer and pnpm are supported.
Local Development
pnpm install
pnpm --filter @gsb-core/cli buildGlobal Installation (NPX)
npm install -g @gsb-core/cliThe installed gsb --version value is read from the published package metadata.
Configuration
Credential precedence is explicit environment variables, then the OS-native
credential keyring referenced by .gsb/<tenantCode>/credentials.json, then a
mode-0600 token in that file when no keyring is available, and finally the
legacy .cursor/mcp.json entry.
This allows CI credentials to override a developer's saved login. Conflicting
tenant selectors, token aliases, or API URL aliases fail before any request.
Use GSB_TOKEN, GSB_TENANT_CODE, and GSB_BASE_URL for CI. GSB_API_KEY and
GSB_API_URL remain supported aliases. Do not commit credentials; the MCP form
below is retained only for existing installations.
Sign in interactively with gsb init --tenant dev1. For non-interactive setup,
put the password in a temporary environment variable and name that variable rather
than passing the secret as a command argument:
gsb init --tenant dev1 --email [email protected] \
--password-env GSB_LOGIN_PASSWORD --force --jsonNon-interactive initialization never prompts. Missing inputs use the same stable JSON error envelope and exit codes as other automated commands.
Expected structure:
{
"mcpServers": {
"GSB Back End": {
"env": {
"GSB_API_KEY": "your-api-key",
"GSB_TENANT_CODE": "your-tenant-code"
}
}
}
}Usage
Shell Completion
Generate completion candidates directly from the installed CLI command tree:
# Bash
source <(gsb completion bash)
# Zsh
source <(gsb completion zsh)
# Fish
gsb completion fish | sourceAdd the matching command to the shell profile to enable it for future sessions. The generated script includes nested commands and options from the installed CLI version, so it stays aligned with the published command surface.
Automation Output
Migrated commands support --json. Successful envelopes are written to stdout,
while progress and error envelopes are written to stderr. Errors include a stable
error.code, and commands never prompt when required approval is absent.
gsb call query --json --input '{"queryParams":{"entDefName":"Order"}}'
gsb call save --json --yes --input-file ./request.json
gsb tools --read-only --json
gsb backup list --status completed --json
gsb backup show <backup-id-or-code> --jsongsb call --raw remains available for scripts that expect the legacy unwrapped
result. New automation should use --json.
gsb tools --json returns the local MCP registry without requiring tenant credentials;
--read-only filters the structured result to tools classified as read.
backup list --json validates filters before authentication, while backup show
--json returns one backup record. Both use the same stable result or error envelope.
Backup mutations require approval bound to the selected tenant. Generic --yes
does not authorize restore or deletion:
gsb backup add "Before release" --confirm-tenant dev1 --json
gsb backup restore <backup-id-or-code> \
--confirm-tenant dev1 --json
gsb backup delete <backup-id-or-code> \
--confirm-tenant dev1 --jsonInteractive use prompts for the tenant code. Non-interactive use never prompts and
fails with APPROVAL_REQUIRED unless --confirm-tenant exactly matches the verified
target. If backup creation succeeds but starting it fails, the error is
PARTIAL_APPLICATION and includes the created backup record for recovery.
gsb config --json reports the resolved tenant, effective API URL, credential
source, and backend-verified user id. Operational commands call
/api/auth/verifyToken while resolving their execution context and reject an invalid
identity or a verified tenant that differs from the selected tenant. The CLI does not
decode and trust JWT claims.
Use the standalone diagnostic to inspect authenticated or public identity details:
gsb verify-token --json
gsb verify-token --anonymous --jsonBoth forms make exactly one POST /api/auth/verifyToken request with
{"variation":{"tenantCode":"..."}}. The first sends the configured JWT and
returns its verified email, role IDs, groups, and positions. The backend wire field is
auth.roles, but its values are immutable role IDs, not names. --anonymous omits the
JWT and requires no saved credential; it returns the tenant's public user identity and
role IDs with a successful response.
Generate checked TypeScript interfaces from pulled entity schemas and verify the committed output has not drifted:
gsb schema-types --out .gsb/dev1/schema/entities.d.ts
gsb schema-types --out .gsb/dev1/schema/entities.d.ts --checkUse gsb inspect workflow <instanceId> --json or
gsb inspect task <jobId> --json for the unified read-only inspection surface.
Run pnpm --dir packages/public/platform/cli docs:generate to regenerate
COMMANDS.md from the installed Commander tree and deprecation registry.
Local Change Status
gsb status
gsb status --all
gsb status --jsonstatus compares local resources with their last successful pull or verified push.
It reports clean, modified, or legacy-untracked; human output hides clean
resources unless --all is set, while JSON always includes every resource and its
current and baseline hashes. The report states remoteComparison: "not-requested"
until three-way remote comparison is implemented.
gsb diff
gsb diff --remote
gsb diff --jsondiff reports canonical resource-level hash changes. Modified resources include
their baseline and current hashes. Resources created before content-hash tracking
are reported as unavailable instead of presenting timestamp evidence as a content
diff. Add --remote to authenticate against the selected tenant and compare each
resource's immutable identity and saved cloud lastUpdateDate with the live row.
This detects cloud-only updates, deletions, and name conflicts even when local files
are clean. It is a cloud revision comparison, not a remote payload hash or field diff.
gsb plan --output change-plan.json
gsb plan --output change-plan.json --allow-create NewLibrary
gsb plan --output change-plan.json --allow-renames --json
gsb apply change-plan.json --output apply-result.json --json
gsb verify apply-result.json --jsonplan reads live asset identities without mutating them and writes a versioned,
content-addressed artifact. Existing updates require a content-hash baseline. New
resources require exact-name approval, renames require --allow-renames, and an
existing output file is never overwritten. Plans bind remote identity and
lastUpdateDate; apply rechecks every precondition before each operation, performs
the normal GSB save only when the revision matches, and reads every write back.
It stops with applied, failed, and remaining operations if an operation fails.
verify accepts either a plan or an apply-result artifact.
Backend revision strings are preserved exactly, including values without a timezone,
so comparison uses the byte-for-byte value returned by the API.
A missing or changed revision stops the save: pull and reevaluate the edits before
creating a replacement plan. Per-operation failures are reported as
precondition-failed; neither the cloud revision nor the local edit baseline is
advanced by the check. There is no claim write, deployment lock, or automatic stale
plan retry.
For schema changes, pull immediately before editing, record a migration, then create the deployment plan:
gsb pull Order --schema
gsb migration plan .gsb/dev1/schema/Order \
--recovery forward-repair \
--recovery-instructions "Revert with a reviewed follow-up migration"
gsb migration check --json
gsb plan --output change-plan.jsonSchema plans require the latest tenant migration artifact to match the schema identity
and authoritative remote/local definition fingerprints. Existing-schema chains bind
IDs into every fingerprint. Chains that create a schema use authored-content
fingerprints throughout so server-assigned schema and property IDs do not invalidate
the reviewed migration. Migration sequence, artifact checksum, transformation checksum,
and recovery policy are checked again before apply. Apply-result verification checks
the recorded migration binding and authoritative fingerprint rather than the
server-normalized schema file hash. Additive and compatible migrations can be applied. Migrations
requiring data transformation can be recorded for review but are rejected by plan
until a typed transformation runtime exists.
Migration artifact writes take an exclusive per-tenant filesystem lock so concurrent
CLI processes cannot claim the same global sequence with different filenames.
To reverse the latest compatible migration for one schema, prepare a compensating migration, review it, and deploy it through the normal immutable lifecycle:
gsb migration rollback <sequence> \
--recovery-instructions "Reapply the reviewed change if compensation must be reversed"
gsb status --json
gsb plan --output rollback-plan.json --json
gsb verify rollback-plan.json --json
gsb apply rollback-plan.json --output rollback-result.json --json
gsb verify rollback-result.json --json
gsb migration check --jsonmigration rollback never writes to the backend. It restores the checksummed
pre-change schema into the checkout and records a new forward migration whose hashes
reverse the target migration. Only the latest migration for that schema is eligible,
and local and live fingerprints must still match its toHash. The command fails
closed for old artifacts without snapshots, schema creation, property removal,
type/data reversals, stale state, and any reverse classified as destructive or
requiring data transformation. Adding a property is safe forward but cannot currently
be rolled back automatically because the reverse operation deletes that property.
Schema definitions are not entity-version-enabled. Tenant backup restore is a separate,
destructive disaster-recovery operation and requires migration-chain reconciliation;
it is not routine schema rollback.
When upgrading from the former app-local checkout layout, move the complete directory atomically with the shipped codemod. It refuses an existing destination instead of merging potentially unrelated tenant state:
node node_modules/@gsb-core/cli/codemods/move-tenant-checkout.mjs \
apps/my-app/.gsb dev1 .Deployment uses ordinary GSB saves and does not block unrelated operations.
The read-then-save revision check is intentionally not atomic: a concurrent save
between the check and the write, or brief cross-asset misalignment, remains possible.
Tenant-wide locks are not required. gsb migration check still reports backend
ledger and lock availability, but these are not deployment prerequisites.
CI/CD, Automated Deployment, and Seeds
See the delivery and resource-pack guide or the published guide for CI credentials, a protected GitHub Actions example, workflow-based deployment, seed mechanisms, query-selected data promotion, and installation conflict policies.
- Build one resource pack and promote its exact
packIdfrom staging to production. - Templates select module resources, definition data, and saved-query subsets through
dataDefinitionsanddataQueries; build-timemoduleFieldsselects asset families. - Choose
skipUserModified: trueto preserve supported target edits orfalseto allow overwrites. Verify schema/property behavior and skipped dependencies before release. - Pack build/install are Application Service APIs, not currently
gsb calltools. gsb bulk savesupports reviewed entity seeds;gsb assistant seedhandles assistant configuration. Assistant seeding requires exact--confirm-tenant <code>approval and supports stable--jsonenvelopes. Explicit manifests are validated before authentication; a failed later write reportsPARTIAL_APPLICATIONwith applied, failed, and remaining configuration keys. Neither seed path implies universal idempotency or a generalgsb seedcommand.- Use
pnpm exec gsbfor parsed output. Inspect business results and terminal job state, not just a successful CLI envelope. Useplan -> apply -> verifyfor mutations.
Query Entities
The CLI uses the same QueryParams model as @gsb-core/core. TypeScript callers use
the fluent builder; gsb call receives its serialized fields:
gsb call query --input '{
"queryParams": {
"entDefName": "Order",
"filters": [{
"col": { "name": "status" },
"val": { "value": "open" },
"function": 0
}],
"selectCols": [{ "name": "id" }, { "name": "status" }],
"startIndex": 0,
"count": 25,
"calcTotalCount": true
}
}' --rawThe query-shaped read tools normalize this JSON into a real QueryParams instance.
Legacy GSB code-library payloads using query, propVal, or colName remain readable,
but new scripts should use filters, col / val, and name. Only filters is sent
over the wire; the server honors it directly.
Every property referenced by a query must have effective Read permission. This applies
even when the property is used only in a filter, sort, group, aggregate, include, subquery,
or permission queryStr and is not returned in selectCols. Dotted paths require Read
access to the relationship and traversed property. Entity-level Read/Query permission
does not bypass property permissions; the backend rejects inaccessible references with an
error such as User does not have access right for property. GsbTenant-partner_id : Read.
The full server wire model is accepted: selectCols with aggregateFunction,
dateModifier, groupBy, distinct, and scripts; filters with every QueryFunction
value, relation ("and" / "or"), relationLevel, negate, extra (the Between
bounds, as { value1, value2 }), subqueries via val.valQuery, and nested children
groups; includes with their own nested query fields; sortCols; searchText;
queryType;
and calcTotalCount. The fluent aliases take / limit (→ count) and
skip (→ startIndex) are also honored, and a filter val may be a bare scalar as
shorthand for { "value": … }.
Bulk Operations
A CLI or MCP call awaits its own response, so the core batching window never fills — those
services run with useBulk: false and skip the 50ms wait. For mass operations use gsb bulk,
which posts a chunk of calls to /api/entity/bulk as one request:
# One tool, many inputs
gsb bulk save --input-file rows.json --chunk-size 200 --yes
# Mixed tools
gsb bulk --yes --input '[
{ "tool": "save", "input": { "request": { "entDefName": "Order", "entity": { "title": "A" } } } },
{ "tool": "delete", "input": { "request": { "entDefName": "Order", "entityId": "…" } } }
]'Accepted input shapes: an array of { tool, input }, a single { tool, inputs: [...] }
fan-out, or a bare array of inputs when the tool name is given as the argument.
Bulk carries the entity endpoints only — query, queryMapped, save, saveMulti,
saveMappedItems, removeMappedItems, delete, deleteQuery. Anything else is one round
trip by nature and stays on gsb call.
Options
-i, --input <json>/--input-file <path>: the calls to run--chunk-size <n>: calls per request (default 100)--stop-on-error: stop after the first failing chunk-y, --yes: approve write, destructive or side-effecting tools--raw: JSON only, no progress or summary
Results are printed as an array of { index, tool, ok, result, error } in input order; the
command exits non-zero if any call failed.
Push Command
Push a TypeScript/JavaScript file to GSB backend:
# Basic push
gsb push path/to/function.ts
# Push with type specification
gsb push path/to/library.ts --type library
# Dry run (preview without pushing)
gsb push path/to/function.ts --dry-run
# Push schemas, libraries, functions, workflows, and templates changed since sync
gsb push --all-changed
gsb push --all-changed --dry-run
# Verbose output
gsb push path/to/function.ts --verboseOptions
-t, --type <type>: Specify type:function,library, orauto(default: auto)-d, --doc-template: Push document template from folder--all-changed: Push changed or never-synced schemas, libraries, functions, workflows, and document templates--allow-renames: Approve collision-free immutable-ID renames without an interactive prompt--force: Explicitly approve a stale local cloud baseline while retaining the apply-time revision comparison--dry-run: Show what would be pushed without actually pushing-v, --verbose: Enable verbose output
Successful pulls and verified pushes record a canonical SHA-256 hash in
serverSync.contentHash. --all-changed compares current payload content with that
baseline, including file additions, removals, and renames. JSON key order,
serverSync, line endings, and filesystem timestamps do not create false changes.
Older metadata uses timestamp detection until its next successful pull or push.
Document Template Commands
The CLI supports pulling and pushing document templates with multilingual content.
Pull Document Templates
# Pull all document templates
gsb pull -d
# Pull specific template by name
gsb pull -d "My Template"
# Pull with verbose output
gsb pull -d --verboseSchema Commands
Entity-definition schemas use
.gsb/<tenantCode>/schema/<name>/<name>.json, with independently tracked property
documents under properties/. Definition and property documents contain immutable
identity, sync timestamps, and canonical content hashes.
gsb pull --schema
gsb pull Order --schema
gsb list --schema
gsb push .gsb/<tenantCode>/schema/Order --schema --dry-run
gsb push .gsb/<tenantCode>/schema/Order --schemaRoutine additive schema work, such as creating one definition or adding a column, does not require a manual cache clean. The server updates the affected definition caches as part of the operation.
After a large migration or a mass update spanning many entity definitions, clean the tenant's server caches before validating the new schema:
gsb --tenant <tenantCode> cache clean --confirm-tenant <tenantCode>This is a safety step for stale or temporarily inconsistent caches across cluster nodes, not a
command to run after every schema change. After cleaning, verify representative definitions and
queries through the normal load-balanced endpoint; if nodes still disagree, repeat the clean or
escalate the cluster synchronization issue. Cache clearing requires exact target-specific approval
and returns a stable result or error envelope with --json.
Background task inspection also uses stable envelopes. Cancellation is target-bound and generic
--yes cannot replace the exact tenant approval:
gsb task status <job-id> --json
gsb task cancel <job-id> --confirm-tenant <tenantCode> --jsonPush Document Templates
# Push document template from folder
gsb push .gsb/<tenantCode>/docTemplates/myTemplate -d
# Push with dry run
gsb push .gsb/<tenantCode>/docTemplates/myTemplate -d --dry-run
# Push with verbose output
gsb push .gsb/<tenantCode>/docTemplates/myTemplate -d --verboseList Document Templates
# List all local document template folders
gsb list -d
# List with verbose output
gsb list -d --verboseDocument Template Structure
Document templates are stored in a structured folder format:
.gsb/
<tenantCode>/
docTemplates/
myTemplate/
meta.json # Template metadata
en_us.html # English content
tr_tr.html # Turkish content
fr_fr.html # French content
... # Other language files
content.html # Non-multilingual content (if applicable)Multilingual Templates
For multilingual templates, each language is stored as a separate HTML file:
en_us.html- English (US)tr_tr.html- Turkishko_kr.html- Koreanhi_in.html- Hindiar_sa.html- Arabicde_de.html- Germanja_jp.html- Japanesefr_fr.html- Frenchru_ru.html- Russianzh_cn.html- Chinesees_es.html- Spanishpt_pt.html- Portugueseit_it.html- Italian
Non-Multilingual Templates
For non-multilingual templates, the content is stored in content.html.
Template Metadata
The meta.json file contains template metadata:
{
"id": "template-uuid",
"name": "myTemplate",
"title": "My Document Template",
"fileName": "template.html",
"isMultilingual": true,
"languageScript": "latin",
"module_id": "module-uuid",
"tags": [{ "id": "tag-uuid", "name": "report" }],
"defaultPrintOptions": "{}",
"enableOverride": false,
"createDate": "2024-01-01T00:00:00.000Z",
"lastUpdateDate": "2024-01-01T00:00:00.000Z"
}Test Command
Test a function without saving it to GSB backend:
# Basic test
gsb test path/to/function.ts
# Test with entity context
gsb test path/to/function.ts --entity '{"id":"123","name":"test"}'
# Test with parameters
gsb test path/to/function.ts --params '{"param1":"value1"}'
# Test with both entity and parameters
gsb test path/to/function.ts --entity '{"id":"123"}' --params '{"debug":true}'Run Command
gsb test covers a single function. gsb run covers a whole workflow: it starts a run and
then tails the three tables GSB records it in — GsbWorkflowInstance (where the run is),
GsbWfLog (the engine's step-by-step trace, prefixed sys) and GsbWfInstanceHistory (what
people did on human tasks, prefixed user). Activity ids are resolved to their names, and the
command exits non-zero when the run ends in Error or Cancelled.
# Start a workflow by name and follow it
gsb run registration --entity '{"email":"[email protected]","name":"Ada"}'
# Take the folder instead of the name, using its workflow.test.json for input
gsb run .gsb/<tenantCode>/workflows/OrderApproval
# Block on runWorkflow rather than startWorkflow
gsb run OrderApproval --sync --entity-id order-123
# Watch a run someone else started, without starting anything
gsb run --attach <instanceId>GSB writes a GsbWfLog row only for workflows whose enableLog flag is on, so an otherwise
healthy run can tail completely silent. gsb run says so before starting, and --enable-log
turns the flag on first.
When the run settles, the summary prints result, responseStr and parentResult from
the instance, plus the code, message and logId the run answered with. Potentially
sensitive instance parameters are omitted. The last three fields matter: a function that
sets instance.code / instance.message has those returned as the HTTP status and body,
never stored on the instance, so the response is the only place a failure reason exists.
--json emits the sanitized summary in the standard result envelope; validation and failed
workflow outcomes use the standard error envelope on stderr.
❌ Run ended: Error
Instance: 07f4b3fe-76db-45d3-b2a6-21d8f3dee8ff
Code: 409
Message: No tenant to register. Please provide tenant with a unique code
Log id: d43bf17c-db6d-42d9-9245-01b0432374beOptions:
| Option | Description |
| ----------------------- | ------------------------------------------------- |
| --entity <json> | entity the run operates on |
| --entity-id <id> | run against an existing entity row |
| --entity-def <id> | GsbEntityDef id of that entity |
| --params <json> | instance parameters |
| --input-file <path> | read the whole request from a JSON file |
| --sync | use runWorkflow instead of startWorkflow |
| --attach <instanceId> | follow an existing instance, start nothing |
| --enable-log | turn on the workflow's enableLog before running |
| --no-follow | return as soon as the run is accepted |
| --interval <ms> | poll interval, default 1000 |
| --timeout <seconds> | stop following after this long, default 300 |
| --json | print a stable sanitized result or error envelope |
Sample input lives in workflow.test.json next to workflow.meta.json, mirroring
<name>.test.json for functions. It holds either the instance itself or a full request:
{ "entityDefinition_id": "8be90815-…", "entity": { "email": "[email protected]" } }Command-line flags override the file, and workflow_id is always taken from the resolved
workflow. A run that parks on a user task keeps polling until --timeout; advance it with
gsb call iterateTask --yes.
Config Command
Show current GSB configuration:
gsb configUser Commands
Create a user, assign a role ID, and optionally update ignored test env files. Automation reads an existing password from an environment variable, or generates one only when an ignored env-file destination is provided.
gsb users roles --json
gsb users list --limit 50 --json
gsb users add [email protected] \
--role-id <role-id> \
--write-env apps/account/.env.local apps/workspace/.env.local \
--confirm-tenant <tenantCode> --json
gsb users assign-role [email protected] <role-id> \
--confirm-tenant <tenantCode> --json
GSB_NEW_PASSWORD='replace-me' \
gsb users reset-password [email protected] \
--password-env GSB_NEW_PASSWORD \
--confirm-tenant <tenantCode> --jsonRole and user listing return stable result or error envelopes with --json; user limits must be
positive integers and are validated before authentication. Role assignment also returns a stable
envelope, accepts only a role ID, and requires exact target-specific approval; generic --yes
cannot authorize it. User creation has the same approval requirement and never prints or returns
a password. Use --password-env <name> to supply one, or --write-env <path> to store a generated
password without emitting it. Password reset follows the same secret-input and approval rules; if
credential-file writing fails after the reset, the CLI returns PARTIAL_APPLICATION with the user
and successfully written file paths, never the password.
File Structure
All pulled schemas/properties, workflows, functions/operations, libraries, and document
templates can be committed alongside application code. Commit identity and sync metadata
with their resources; never commit credentials or sensitive test inputs. The CLI writes
source files but does not create Git commits or push a Git remote. gsb status compares
local payloads with their sync baseline, not Git history or current remote content.
See Backend source control with Git for the complete layout, branch/PR workflow, safe refresh, and commit-to-release traceability.
Functions
gsb pull -f writes one folder per function. Pass a name to pull a specific function.
Functions are shared many-to-many with workflow activities, so each row lives in exactly one
folder, chosen by its standalone flag: standalone functions in serverless/functions-std/,
workflow-only functions in serverless/functions-wf/. When the flag flips, the copy in the
other folder is removed so a function is never duplicated on disk.
Operation-based functions keep their logic in operations, not code, so each operation gets
its own file:
.gsb/
<tenantCode>/
serverless/
functions-std/
sendResetPasswordEmail/
sendResetPasswordEmail.ts # the function's `code` (empty for operation-only functions)
sendResetPasswordEmail.meta.json # id, name, title, module_id, standalone, testInstance
op-1.ts # RunScriptCode operation body
op-1.json # that operation's config, minus scriptCode
op-2.json # a non-script operation (email, notification, …)
functions-wf/
CalculateTotal/ # same layout, referenced by workflow activities
libraries/
myLibrary.ts
myLibrary.meta.json (optional)op-N files are ordered numerically and pushed back in that order. Push and test take the
folder:
gsb push .gsb/<tenantCode>/serverless/functions-std/sendResetPasswordEmail
gsb test .gsb/<tenantCode>/serverless/functions-std/sendResetPasswordEmail --params '{"email":"[email protected]"}'Loose <name>.ts files from before the folder layout are still pushed and listed.
Workflows
gsb pull -w writes one folder per workflow. Activities reference functions by name, never
by body, so pushing a workflow can never overwrite code shared with another workflow. Function
bodies change only through a function push.
.gsb/
<tenantCode>/
workflows/
OrderApproval/
workflow.meta.json # id, name, title, enableLog, enableUseExisting, module_id
workflow.test.json # optional sample input for `gsb run`
design.json # canvas positions, isolated so drags don't churn logic files
activities/
010-Start.json # activity fields plus functions / afterFunctions / prevFunctions
020-Approve.json
transitions/
010-StartToApprove.json # `from` and `to` are activity namesNumeric prefixes keep the order stable; files are read back in numeric order. Push resolves every function name to its server id and fails before writing if a name is unknown:
gsb pull -w # all workflows
gsb pull -w OrderApproval # one workflow
gsb push .gsb/<tenantCode>/workflows/OrderApproval --dry-run
gsb list -w --verboseBecause references key on function names, every function row needs a unique name. Report the functions that lack one, then apply the derived PascalCase names:
gsb normalize-functions # report only
gsb normalize-functions --applyExisting names are never changed, and duplicate names are reported as errors because they make a reference ambiguous.
Activities have the same problem in a worse form: GSB names every activity default. The real
label lives in the workflow's designer payload, keyed by activity refId, so it can be lifted
onto the rows:
gsb normalize-activities # report only
gsb normalize-activities --workflow registration # one workflow
gsb normalize-activities --applyUnlabelled Start/End/Timer nodes are named after their activity type. Re-run gsb pull -w
afterwards so the local folders pick up the new names.
Document Template Files
Document templates are stored in the .gsb/<tenantCode>/docTemplates/ folder:
.gsb/
<tenantCode>/
docTemplates/
template1/
meta.json
en_us.html
tr_tr.html
fr_fr.html
template2/
meta.json
content.html (for non-multilingual)
template3/
meta.json
en_us.html
de_de.html
es_es.htmlMetadata Files
Optional .meta.json files can provide additional metadata:
{
"id": "uuid-of-existing-function",
"name": "functionName",
"title": "Human Readable Title",
"description": "Function description",
"references": [{ "id": "service-dependency-id" }]
}Metadata Properties
id: GSB function/library ID (for updates)name: Function/library name (defaults to filename)title: Display title (defaults to formatted name)description: Optional descriptionreferences: Array of service dependency IDs
Examples
Push a Function
# Push a pulled function folder (code plus its operations)
gsb push .gsb/<tenantCode>/serverless/functions-std/myFunction
# Push a single loose file
gsb push .gsb/<tenantCode>/serverless/functions-std/myFunction.ts --verboseTest a Function
# Test with sample data
gsb test .gsb/<tenantCode>/serverless/functions-std/calculateTotal \
--entity '{"order":{"items":[{"price":10,"quantity":2}]}}' \
--params '{"applyTax":true}'Inspect the Serverless Runtime Contract
The CLI exposes the same canonical serverless guide as MCP and the documentation app:
gsb call getServerlessFunctionDocs --rawUse this guide to inspect injected globals, _runtime fields, email delivery paths, task
scheduling constraints, and current document-generation prerequisites. Runtime-provided modules
such as nodemailer, bullmq, and ioredis are used directly; do not load them with require().
The guide also documents the native password contract used by Emotion Guru:
POST /api/auth/changePassword accepts either oldPassword for a signed-in password change or
email plus resetToken for reset-link confirmation, together with newPassword. Reset-link
confirmation is delegated to the tenant's trusted sendResetPasswordEmail function; do not edit
GsbUser.password directly. Inspect the tenant implementation and its metadata with:
gsb pull -f .gsb/<tenantCode>/serverless/functions-wf/Change-Password
gsb pull -f .gsb/<tenantCode>/serverless/functions-std/sendResetPasswordEmailVersion an Entity Before a Risky Change
Explicit snapshots are optional and apply to one version-enabled entity. Create one before a meaningful function, workflow, or configuration change; use a tenant backup for broad releases or disaster recovery. Schema definitions are not version-enabled and use reviewed compensating migrations where the reverse is supported.
# Snapshot the current function, then push the edit
gsb version add <function-id> \
--definition GsbWfFunction \
--note "Before registration validation rewrite" \
--confirm-tenant <tenantCode>
gsb push .gsb/<tenantCode>/serverless/functions-wf/myFunction
# Inspect snapshots and automatic field-change audit rows
gsb version list <entity-id> --json
gsb version changes <entity-id> --json
# Restore by GsbEntityVersion row ID, not by live entity ID
gsb version restore <version-row-id> --confirm-tenant <tenantCode>Snapshot creation and restore require exact target-specific approval; generic approval cannot
authorize either mutation. GsbEntityDef.isVersioned enables explicit snapshots.
GsbEntityDef.isTracked enables automatic
GsbTrackVersion rows on every create/update. The systems are independent. The CLI decodes tracked
values from Base64 JSON. Both read commands return stable result or error envelopes with decoded
records and validate positive --limit values before authentication. Both snapshot mutations also
return stable envelopes and never prompt during JSON execution. Run
gsb call getEntityVersioningDocs --raw for endpoint payloads, MCP tool names, restore safeguards,
and current version-number behavior.
Document Template Examples
# Pull all document templates from server
gsb pull -d
# Pull specific template
gsb pull -d "Invoice Template"
# List local templates
gsb list -d
# Push updated template
gsb push .gsb/<tenantCode>/docTemplates/invoiceTemplate -d
# Preview template push
gsb push .gsb/<tenantCode>/docTemplates/invoiceTemplate -d --dry-runDry Run
# Preview what would be pushed
gsb push .gsb/<tenantCode>/serverless/functions-std/newFunction.ts --dry-run
# Preview document template push
gsb push .gsb/<tenantCode>/docTemplates/myTemplate -d --dry-runType Detection
The CLI automatically detects whether a file is a function or library based on:
- File path (contains
functionsorlibraries) - Metadata
typeproperty - Default to
functionif unclear
Error Handling
The CLI provides clear error messages for common issues:
- Missing MCP configuration
- Invalid file paths
- Network/API errors
- Invalid JSON in metadata
- TypeScript/JavaScript file validation
Development
Building
npm run buildDevelopment Mode
npm run dev -- push path/to/file.tsAdding New Commands
- Add command definition in
src/index.ts - Implement logic in appropriate service files
- Add types to
src/types.ts - Update README documentation
File Structure
src/
index.ts # Main CLI entry point with all commands
config.ts # Configuration management
gsbService.ts # GSB backend service wrapper
fileUtils.ts # File reading, validation, and doc template utilities
types.ts # TypeScript type definitionsTroubleshooting
"MCP configuration not found"
Ensure your project has .cursor/mcp.json with GSB backend configuration.
"Invalid TypeScript file"
Only .ts and .js files are supported.
API Connection Issues
Check your GSB_API_KEY and GSB_TENANT_CODE in the MCP configuration.
Function Test Failures
Ensure your function code is compatible with GSB serverless environment.
Document Template Issues
"Pull functionality is not yet implemented"
The document template pull functionality requires proper API configuration. This will be available once the GSB backend API methods are properly configured.
"Document template folder not found"
Ensure the folder path exists and contains a valid meta.json file.
"meta.json not found in folder"
Each document template folder must contain a meta.json file with template metadata.
Contributing
- Fork the repository
- Create feature branch
- Add tests for new functionality
- Submit pull request
License
MIT License
