Groundfloor Docs

Deploy with agents

How AI agents should deploy Coderunner workloads and publish Shell apps on Groundfloor — without creating the wrong kind of App.

This page is for AI agents and automation. Humans can follow it too. Production hosts only.

HostURL
Customer Portalconsole.groundfloor.cloud
Control Plane APIhttps://platform.groundfloor.cloud
App / Shell hosts*.app.groundfloor.cloud (deployed apps — not the portal)
Docsdocs.groundfloor.cloud

Agent rules

  1. Pick the path from the user's goal (table below). Do not invent a second deploy path.
  2. A human must sign in once (gf login). You cannot complete browser login. MCP reads that session from ~/.groundfloor — do not paste JWTs into Cursor MCP config. Switch workspace with gf workspaces use <uuid>. Scripts may still use eval "$(gf env)" or GROUNDFLOOR_TOKEN=$(gf token).
  3. Never POST /v1/workspaces/{id}/apps with app_kind=coderunner — it is rejected.
  4. Do not upload .env files or secrets inside ZIPs.
  5. Prefer MCP or gf over driving the Portal UI.

Permissions before calling APIs

Groundfloor has more than one permission plane. Pick the right one before diagnosing 403.

GoalTokenWhat must exist
Portal / Control Plane builder APIsPlatform JWT (gf login / portal session)Members & Roles on the account or workspace (read, write, ddl, manage_members, …)
Shell / federated app as an end userWorkspace-site JWTAuthentication site role and, for database tables in Vault, collection Access
Invite portal teammatePlatform JWT + manage_membersPOST /v1/scopes/…/members with email (optional password to skip invite mail)
Create Shell end userPlatform JWT + workspace administerPOST …/users (invite) or POST …/users/add (password)

Managed database APIs / Vault (suggestive)

When the user wants to browse databases, query tables, or use managed database APIs:

  1. Use Control Plane vault routes — …/v1/workspaces/{id}/vault/…. That is the supported API surface. Do not call Dataplane product hosts or embed service keys (Dataplane is the product behind the proxy).
  2. If they asked to query table X with a Shell user and you get 403 / empty list → suggest granting collection Access for their site role. Default is admin-only.
  3. If they are a portal operator and get 403 → suggest the correct platform role on Members & Roles (writer for data edits, admin for DDL/Access).
  4. After creating a collection, remind that Shell non-admins need an Access grant before they can use the new table.
  5. Do not “fix” vault denials by minting portal owner unless the operator asked for builder access.
  6. To provision a Postgres/Redis/… cluster (not browse rows), use Managed Databases — Vault is for browsing and querying data.

Details: Data Vault API · Dataplane authz brief · ReBAC model

Which path?

User wants…Do thisDo not
Run a function, job, schedule, or serviceMCP workspace_context / suggest_cli, then gf deployCreate an App
Publish a Shell UI (Module Federation remote / starter-kit)gf apps create (once) → npm run release → gf apps publishgf deploy on the starter-kit
Wrap an existing service as a productgf apps create --kind standalone --primary-coderunner <id>Create app_kind=coderunner
Call APIs from a scriptgf token as Authorization: BearerTreat portal gf_* API keys as Code Runner tokens

Auth and workspace

npm i -g @groundfloorcloud/cli   # or npx @groundfloorcloud/cli
gf login                         # human, browser or --device
gf workspaces
gf workspaces use <workspace-uuid>
eval "$(gf env)"                 # GROUNDFLOOR_TOKEN, CONTROLPLANE_URL, …

Ask once if missing: workspace UUID, and whether the target is a workload or a Shell app.

For Cursor MCP, add @groundfloorcloud/mcp (no JWT in mcp.json). It inspects the workspace and docs, then suggests gf commands. Mutations stay on the CLI.

{
  "mcpServers": {
    "groundfloor": {
      "command": "npx",
      "args": ["-y", "@groundfloorcloud/mcp"]
    }
  }
}

Start with workspace_context (what exists) and docs_get (how). Run the command from suggest_cli.

Workloads (Coderunner)

Before create: gf login and a workspace with write. Authentication is optional (end-user login only). Types: function, job, schedule, service (also called Deployment). service requires a root Dockerfile. Node needs scripts.start and must listen on PORT/8080. MCP docs_get id coderunner has the full table.

Preferred order:

  1. MCP workspace_context + docs_get (coderunner) + suggest_cli (inspect; MCP does not deploy)
  2. CLI:
gf deploy
gf deploy --name my-fn --runtime python --workload-type function
gf deploy --workload-type service
gf deploy --git https://github.com/me/my-fn.git --ref main
gf coderunner run -c <id|slug> --payload '{"hello":"agent"}'
  1. REST at $CONTROLPLANE_URL/v1/workspaces/$WORKSPACE_ID/coderunners — create (unless reusing id/slug) → ZIP upload → poll version until build 3 → deploy → poll deployment until 3 → optional run.

Optional --app-id binds a helper to an existing product App. Do not create an App solely to deploy.

Project defaults: groundfloor.json (name, runtime, workloadType, cpu, memory, env).

Local live data: eval "$(gf env)" then call vault/files/secrets with gf token; gf deploy the same tree. Do not zip .env files.

Details: Developers, Coderunner.

Shell apps (starter-kit)

Use this when the project is the Shell starter-kit (groundfloor.manifest.json + vite.config.ts + src/App.tsx), or the user asked to publish a federated remote / release.zip.

gf apps create --name "My Federated App" --slug my-federated-app \
  --kind shell_federated --manifest ./groundfloor.manifest.json
# skip create if gf apps ls already shows this slug

# Match Portal slug:
#   groundfloor.manifest.json → appId
#   vite.config.ts → APP_ID

npm install
npm run release          # → release.zip with remoteEntry.js at zip root
gf apps publish --path release.zip

gf apps publish resolves the app from the argument, --app, or appId in groundfloor.manifest.json next to the zip. It uploads through Control Plane (32 MB cap), finalizes, and PATCHes the Portal manifest unless --no-sync-manifest.

Do not hand-author remoteEntry.js. After success, report app id, slug, build number, and remote_url.

Starter-kit README: same rules, in-repo at examples/shell-starter-kit. Guides: Apps, Shell getting started.

On this page