npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@groundfloorcloud/cli

v0.2.7

Published

Groundfloor gf CLI — sign in, deploy coderunners, publish Shell apps, and manage secrets, files, and Dataplane.

Readme

@groundfloorcloud/cli (gf)

Sign in to Groundfloor, manage workspaces, and work with Coderunner, secrets, feature flags, files, apps, and Dataplane from your terminal.

gf login opens a browser, you sign in, and the session is cached and refreshed automatically.

Agents in Cursor use @groundfloorcloud/mcp against the same gf login session to inspect the workspace and docs, then run gf commands to take action.

Install

npm i -g @groundfloorcloud/cli
gf login

Without a global install:

npx @groundfloorcloud/cli login

Requires Node.js 20 or later. gf checks npm at most once a day and prints a one-line upgrade notice when a newer @groundfloorcloud/cli exists. Unknown subcommands include the installed vs latest version so a stale binary is not read as wrong docs.

gf login signs in to production (https://platform.groundfloor.cloud). Use --dev or --stage for other cells; later commands reuse that session.

Quick start

gf login                 # production
gf login --stage
gf login --dev
gf whoami
gf workspaces
gf workspaces use <uuid>
gf coderunner ls
gf deploy

Non-interactive use (CI, containers): set GROUNDFLOOR_TOKEN to a Control Plane JWT. It takes precedence over the saved gf login session (an expired GROUNDFLOOR_TOKEN is ignored when a saved session exists, so a stale export does not shadow it). Mint one from an M2M client:

export GROUNDFLOOR_TOKEN="$(gf m2m token)"   # needs GROUNDFLOOR_M2M_CLIENT_ID / _SECRET
export GROUNDFLOOR_WORKSPACE_ID=<workspace-id>
# non-production cells also need GROUNDFLOOR_API_URL
gf coderunner ls

Use the session from a shell or script:

eval "$(gf env)"
curl -H "Authorization: Bearer $(gf token)" \
  "$CONTROLPLANE_URL/v1/workspaces"

Deploy workloads

gf deploy packages your code and runs the full Coderunner lifecycle: create if needed, upload a version, wait for the build, deploy, poll until complete, and print IDs and the URL.

Do not create an App just to run a function, job, schedule, or service (Deployment). Use gf deploy. Bind --app-id only when the coderunner should be a helper of an existing product App.

App authentication is optional. Team write can create Coderunners when mode is None. For Vault and Files from the workload, attach an M2M client (Access → Machine clients) and use gf m2m token — not a Dataplane key. gf coderunner vault-token is deprecated.

Workload types

| --workload-type | Also called | Package notes | |-------------------|-------------|---------------| | function | Function | HTTP on 0.0.0.0:PORT/8080. Node needs scripts.start. | | job | Background job | Run-to-completion. Then gf coderunner run. | | schedule | Scheduled job | Cron via --schedule or groundfloor.json schedule. No public URL. | | service | Deployment | Long-running HTTP. Root Dockerfile is required. |

gf deploy
gf deploy --git https://github.com/me/my-fn.git --ref main
gf deploy --name my-fn --runtime python --cpu 250m --memory 256Mi \
  -e LOG_LEVEL=debug
gf deploy --workload-type service
gf deploy --workload-type schedule --schedule "*/5 * * * *"
gf deploy --app-id <app-uuid>

How the target is chosen:

  • --coderunner <id> deploys into that coderunner.
  • Otherwise the name comes from --name, then groundfloor.json, then the folder or repo name. A matching slug is reused; otherwise a new coderunner is created.
  • --app-id applies only when a new coderunner is created. When an existing one is reused or -c is given, it is ignored and gf deploy warns.

Deploy target safety:

  • The workspace comes from -w, GROUNDFLOOR_WORKSPACE_ID, or the saved machine-wide default (gf workspaces use). The saved default is shared by every shell on the machine, so it is never used silently: without an interactive terminal gf deploy refuses and asks for -w <workspace-id>; on a terminal it prints the workspace name and id and asks to confirm. -w and GROUNDFLOOR_WORKSPACE_ID deploy without that prompt.
  • Reusing a same-named coderunner prints its name, id and environment and asks to confirm. Without a terminal, pass -y/--yes.
  • Check the printed coderunner id and URL after the deploy; an unexpected new id means it went somewhere you did not intend.

Redeploys and env vars. The platform stores only the env var names of a deployment, never the values. A redeploy that does not resend a variable (-e, or groundfloor.json env) drops it from the new deployment. gf deploy warns about previously-set keys that are not being resent. Resend every variable you need on each deploy.

Secrets on deploy. Never pass credentials with -e (credential-shaped names are rejected). Store the secret in the coderunner's environment and deploy with a reference:

printf '%s' "$PF_SECRET" | gf secrets set PF_SECRET - -e <environment-id>
gf deploy --secret PF_SECRET                     # env var PF_SECRET from secret PF_SECRET
gf deploy --secret DB_PASS=prod_db_password      # env var DB_PASS from secret prod_db_password
gf deploy --no-secrets                           # remove every saved reference
  • Only names travel: the Control Plane reads the values from the coderunner's bound environment (no fallback to dev) and hands them to the workload through a Kubernetes Secret. Values never appear in the deploy body, the CLI output, logs or API responses.
  • References are saved. A deploy without --secret keeps the last deploy's references (and gf deploy says which); any --secret replaces the whole list; --no-secrets removes them. References come from flags only, not from groundfloor.json. A changed secret value reaches the workload on the next deploy.
  • Secret references must be switched on for the Groundfloor cell. Until they are, a deploy with --secret is refused with 422, reason secret_refs_disabled; read the secret at runtime instead with an M2M client that has secrets:read (gf m2m token, then GET /v1/workspaces/{id}/secrets/{key}?environment_id=…).
  • Refusals print the server message, the reason: code and one hint for that code: secret_ref_missing (not in the coderunner's environment), secret_ref_unbound (no active environment), secret_ref_invalid, secret_ref_forbidden (platform-managed secret, or an M2M caller without secrets:read), secret_ref_too_large (64 references / 64 KiB), secret_ref_version_ineligible, secret_ref_store_failed (502) and secret_ref_apply_failed (502/503; nothing was deployed).

Runtime is auto-detected when omitted (package.json → node, requirements.txt / pyproject.toml → python), defaulting to python. Node without a Dockerfile uses the platform bootstrap (CMD ["npm","start"], port 8080). Add "scripts": { "start": "node index.js" } and bind 0.0.0.0. gf deploy fails immediately if scripts.start is missing.

Local with live data

eval "$(gf env)"
export PORT=8080
npm start
# files/secrets / operator Vault (builder token):
curl -sS -H "Authorization: Bearer $(gf token)" \
  "$CONTROLPLANE_URL/v1/workspaces/$GROUNDFLOOR_WORKSPACE_ID/files"
# M2M (Coderunner / CI — not gf token):
curl -sS -H "Authorization: Bearer $(gf m2m token)" \
  "$CONTROLPLANE_URL/v1/workspaces/$GROUNDFLOOR_WORKSPACE_ID/vault/collections"

Then gf deploy the same tree. Do not zip .env files. gf token is the wrong identity for testing Coderunner Vault/Files as the workload.

groundfloor.json

{
  "name": "my-fn",
  "runtime": "python",
  "workloadType": "function",
  "cpu": "250m",
  "memory": "256Mi",
  "env": { "STAGE": "dev" },
  "schedule": "*/5 * * * *"
}

Deploy flags

| Flag | Description | |------|-------------| | -w, --workspace <id> | Target workspace. Required without a terminal unless GROUNDFLOOR_WORKSPACE_ID is set; the saved default needs an interactive confirm. | | -n, --name <name> | Coderunner name (else groundfloor.json, then folder name). | | -c, --coderunner <id\|slug> | Deploy into this existing coderunner. | | --app-id <uuid> | Bind a new coderunner to an App as a helper. Ignored on reuse. | | --secret <NAME\|ENV=SECRET> | Reference a secret from the coderunner's environment (repeatable). Any --secret replaces the saved references; omitted keeps them. Needs secret references switched on for the cell. | | --no-secrets | Remove every saved secret reference. | | --api-url <url> | Control Plane base URL override. | | -y, --yes | Skip the reuse confirmation (required without a terminal) and the prompt shown with -c when the deploy would drop previously deployed env variables (key names only; values are not stored). | | -p, --path <dir> | Directory to package (default: cwd). | | --git <url> / --ref <ref> | Clone and deploy a remote repo. | | --subdir <dir> | Package a subdirectory of the source. | | --runtime <r> | Language slug from GET …/coderunners/languages (node, python, go, dotnet, dotnet-script, …). | | --workload-type <t> | function | service (Deployment) | job | schedule. Service requires a Dockerfile. | | --schedule <cron> | Cron for schedule workloads (or groundfloor.json schedule). | | --cpu / --memory | Resource requests, e.g. 250m / 256Mi. | | -e, --env KEY=VALUE | Deployment env var (repeatable). | | -m, --message <text> | Version description. | | --skip-deploy | Upload a new version but do not deploy it. |

What is never uploaded

gf deploy drops credential files from the package on both paths — the plain-directory walk and the git file list (which includes untracked files that no .gitignore rule covers). Excluded by name: .env*, .npmrc, .yarnrc*, .netrc/_netrc, .pypirc, .git-credentials, .htpasswd, .pgpass, .s3cfg, id_rsa/id_dsa/id_ecdsa/id_ed25519 (but not their .pub halves), *.pem, *.key, *.p12, *.pfx, *.jks, *.keystore, *.ppk, *.kdbx, *.gpg, *.tfstate*, and anything under .ssh/, .aws/, .azure/, .gcloud/, .gnupg/, .docker/, .kube/, .terraform/ or .chef/.

Every exclusion is printed, and so is every dot-file that survived the filter. There is no flag to turn it off: keep credentials in gf secrets and reference them with --secret or read them at runtime (M2M secrets:read), or pass non-sensitive config with -e KEY=VALUE. Credential-shaped -e keys are rejected.

This is a denylist, so it only knows names. A secret in a file called config.json, settings.py or serviceAccount.json is still uploaded — check what the packaged file list says before deploying.

Publish a Shell app

Product Apps are packaging (Shell Module Federation remotes, or a standalone wrapper around a service). That is separate from gf deploy.

Always start from the official starter-kit. Do not scaffold App.tsx or put BrowserRouter in the federated export — that crashes the Shell.

gf apps init --slug my-federated-app
cd my-federated-app
gf apps create --name "My Federated App" --slug my-federated-app \
  --manifest ./groundfloor.manifest.json
npm install
npm run release
gf apps publish --path release.zip

gf apps init downloads the public ZIP from the Client Portal (/downloads/shell-starter-kit.zip on the current cell) and stamps APP_ID / groundfloor.manifest.json appId to the slug.

gf apps publish uploads only release.zip from npm run release. It flattens a Vite dist/assets/ layout when needed, rewrites ./assets/ imports in remoteEntry.js, then rejects a zip that is only remoteEntry.js (missing __federation_*.js / CSS) or whose federation name does not match federationRemoteName(slug). A lone .js file is also rejected. Pass an app id/slug, or set appId in groundfloor.manifest.json next to the zip.

Wrap an existing service coderunner as a product:

gf apps create --kind standalone --name "My Product" --slug my-product \
  --primary-coderunner <coderunner-id>

Do not create app_kind=coderunner. Functions, jobs, schedules, and services use gf deploy.

App sign-in (end users of a standalone app)

In a workspace that uses Groundfloor login, every app has its own public sign-in client, app-<app_id>. The app signs users in with PKCE; its backend checks that tokens were issued to that client (use @groundfloorcloud/app-auth).

gf apps auth my-product                                  # client id, issuer, redirect URIs, origins, sync status
gf apps auth add-origin my-product http://localhost:5173 # extra web origin (never a redirect URI)
gf apps auth add-callback my-product /login/done         # extra callback path on the app's own hosts
gf apps auth remove-origin my-product http://localhost:5173
gf apps auth remove-callback my-product /login/done

Redirect URIs are exact: https://<host>/auth/callback (plus up to 5 extra paths) on the app's public host and verified custom domains. Extra origins: up to 20, https://host[:port] (a DNS name, not an IP address) or http://localhost[:port] / http://127.0.0.1[:port], no wildcards. Extra callback paths may not contain wildcards, queries, .. segments or encoded ., /, \ (%2e, %2f, %5c); gf checks this before sending. Viewing needs workspace read, changing needs write. Workspaces that use their own identity provider have no app client.

Secrets, files, Dataplane

gf dataplane status
gf dataplane provision

gf secrets ls
printf '%s' "$DATABASE_URL" | gf secrets set DATABASE_URL -   # stdin keeps the value out of shell history; empty stdin is refused
gf secrets get DATABASE_URL
gf secrets rm DATABASE_URL

gf files ls
gf files upload ./report.pdf
gf files download <file-id> -o ./report.pdf
gf files rm <file-id>

gf apps ls
gf apps get <id|slug>

Secret keys become environment variables: letters, digits and _ only, starting with a letter or _, at most 256 characters (TELNYX_API_KEY, not telnyx-api; anything else is a 422). DATAPLANE_SERVICE_API_KEY and MANAGED_DB_* are platform-managed and can't be set or removed (403).

gf env and gf secrets get print raw secret values to stdout by design; do not run them where output is logged. For gf m2m token, set GROUNDFLOOR_M2M_CLIENT_SECRET instead of --client-secret (argv is visible in ps and shell history).

Feature flags

Per-environment toggles and config values. -e takes an environment id or name (dev, staging, prod); without it the workspace default (dev) is used.

gf flags ls -e prod
gf flags set new-checkout true -e dev          # boolean (inferred)
gf flags set max-items 25 -e dev               # number (inferred)
gf flags set banner '{"text":"Hi"}' --type json -e dev
gf flags get new-checkout -e prod
gf flags compare dev prod
gf flags promote dev prod --dry-run            # then without --dry-run
gf flags rm new-checkout -e dev

Keys are lowercase letters, digits, -, _ and ., starting with a letter. Apps read flags at runtime from GET /v1/workspaces/{id}/flags/runtime: Shell apps with the end-user token, Coderunners with gf m2m token (read-only). See https://docs.groundfloor.cloud/docs/configure/feature-flags.

Commands

| Command | Description | |---------|-------------| | gf login [--dev\|--stage] [--device] | Browser sign-in (production default). | | gf logout | Clear the cached session. | | gf whoami | Show identity and verify the Control Plane session. | | gf token | Print a fresh access token. | | gf env | Print export … lines for eval "$(gf env)". | | gf environments ls (envs) | List workspace environments. | | gf workspaces (ws) | List workspaces; gf workspaces use <id> sets the default. | | gf coderunner ls (cr ls) | List coderunners. | | gf coderunner status -c <id\|slug> | Status and current deployment. | | gf coderunner logs -c <id\|slug> | Process Log (stdout/stderr). Also printed automatically on gf deploy failure. | | gf coderunner cancel-deployment -c <id\|slug> | Destructive. Deletes the current (or --deployment-id) deployment; if it is the live one the service goes offline. Confirms on a terminal; requires -y/--yes without one. | | gf coderunner run -c <id\|slug> [--payload '{}'] | Invoke a deployed function or job. | | gf m2m token | Print a short Control Plane JWT from M2M client_id + secret. Not gf token. | | gf coderunner vault-token | Deprecated. Use gf m2m token. | | gf deploy | Package code and deploy as a coderunner (see Deploy flags). | | gf domains ls\|add\|rm\|verify --app <id\|slug> | Custom domains for a standalone App. Domains belong to Apps; standalone coderunner domain routes are not supported. | | gf identities ls\|mint --identity <id> | Workload identities (Vault principals); first mint returns refresh_secret once. | | gf usage [--account <id>] [--since-days <n>] [--json] | Read-only account quota/usage and billing estimate. The account is the billing parent of the workspace, not the workspace id. | | gf api <path> [-X <method>] [--body <json>] | Call a Control Plane path; {workspace_id} expands to the current workspace. | | gf secrets ls\|get\|set\|rm | Workspace secrets. | | gf flags ls\|get\|set\|rm\|compare\|promote | Feature flags per environment (-e <id\|name>). | | gf files ls\|upload\|download\|rm | Workspace files. | | gf apps init --slug <slug> | Download the official Shell starter-kit and stamp APP_ID. | | gf apps ls\|get\|create\|publish | Product apps (Shell publish / standalone wrap). | | gf apps auth <app> / add-origin / add-callback / remove-origin / remove-callback | An app's sign-in client: show it, or change its extra web origins and callback paths. | | gf dataplane status\|provision | Dataplane setup for the workspace. |

Configuration

Settings resolve as: command flags > environment > ~/.groundfloor/config.json

Groundfloor production.

gf login with no cell flag always uses production, even if a previous --dev / --stage session is still in config.json. Pass --dev, --stage, or --env <production|stage|dev> to pick another cell. --api-url / --issuer still override the hosts for that login.

| Setting | Flag | Env | Production default | |---------|------|-----|--------------------| | Control Plane URL | --api-url | GROUNDFLOOR_API_URL | https://platform.groundfloor.cloud | | IdP issuer | --issuer | GROUNDFLOOR_ISSUER | Groundfloor managed IdP | | OIDC client id | --client-id | GROUNDFLOOR_CLIENT_ID | groundfloor-cli | | Default workspace | (via gf workspaces use) | GROUNDFLOOR_WORKSPACE_ID | (none) | | Access token | (none) | GROUNDFLOOR_TOKEN | (none; wins over the saved session) |

State is stored under ~/.groundfloor/:

  • auth.json — cached tokens (chmod 600).
  • config.json — non-secret defaults (issuer, client id, api url, workspace); chmod 600.

Redirect URI mismatch

gf login uses a loopback callback (http://127.0.0.1:<port>/callback). If sign-in fails with an invalid redirect URI:

  • Prefer 127.0.0.1 (the CLI default).
  • If your identity provider only allows localhost, run gf login --redirect-host localhost.
  • To pin a port: gf login --redirect-port 8976.

More