Skip to content
PaloNexus
Request access Request

CLI reference

PaloNexus is configured almost entirely by environment variables, so it has a deliberately small CLI surface. There is no single palonexus binary. Instead there are four distinct command-line surfaces:

SurfaceWhat it isWhen to use it
seed-logtothe identity seeder — loads the sample organization into a Logto tenantonly to stand up the sample identity model
make (platform Makefile)build/test/render/deploy the control-planebuilding images and rendering/applying manifests
kubectl / kustomizeapply the control layer to a clusterdeploying to DigitalOcean Kubernetes (DOKS) or self-hosting
Python SDK (palonexus)the programmatic entry point — no standalone CLI binaryembedding governance in application code and tests

Source: platform/seed-logto/src/nsr_seeder/cli.py. The package ships a thin wrapper (seed_logto.py) so the examples run without installing the package:

Terminal window
cd platform/seed-logto
python3 seed_logto.py <subcommand>
SubcommandWhat it doesExit codes
checkrun the sandbox safety preflight only and print the report — no writes0 pass · 2 fail
generategenerate users.json + synthetic_hris.json from the manifest (no tenant)0
plandry-run apply — preview the upserts without writing (forces dry-run)0
applycreate/reconcile resources in the tenant0 ok · 1 had errors · 3 safety failed
validatevalidate the dataset (and the live tenant, unless --offline) and write a JSON + Markdown report under --reports0 passed · 1 failed
cleanupdelete seed-owned resources (--mode soft-reset | hard-reset)0 ok · 3 safety failed · 4 aborted (e.g. over LOGTO_MAX_DELETE)
reseedhard-reset cleanup then applypropagates the above

apply and cleanup both run the sandbox safety checks first and refuse to proceed (exit 3) if the target tenant does not clearly look like sandbox/dev/test.

cleanup takes its own --mode (default hard-reset) and its own --dry-run / --no-dry-run:

Terminal window
python3 seed_logto.py cleanup --mode soft-reset # remove memberships/roles, keep users
python3 seed_logto.py cleanup --mode hard-reset # delete all seed-owned resources
python3 seed_logto.py cleanup --mode hard-reset --dry-run # preview the deletions

These are options on the top-level parser, so — as with any argparse subcommand CLI — global flags must precede the subcommand:

Terminal window
python3 seed_logto.py --no-dry-run apply # correct: global flag before subcommand
python3 seed_logto.py --offline plan # dry-run against the in-memory FakeLogto tenant
FlagDefaultMeaning
--manifestseed/northstarpath to the seed manifest directory
--staterun_state.jsonrun-state file (resource-id map). Defaults are isolated per seed namespace (run_state.<namespace>.json) and per offline run (run_state.offline.json) unless an explicit path is passed
--reportsreportsoutput directory for validate reports
--env-file(auto)dotenv file to load; if unset, falls back to .env.local then .env
--offlineoffuse the in-memory FakeLogtoClient — no network, no live tenant
--dry-run / --no-dry-run(env LOGTO_DRY_RUN, default true)preview vs. actually write. --no-dry-run is what turns apply into a real write
--best-effortoffcontinue past individual user-create failures (still aborts on org/role/membership/org-role failures)

The seeder is configured entirely by LOGTO_* (an .env.example ships in platform/seed-logto/). The full table — with aliases, examples, and the secret machine-to-machine (M2M) credentials — is the identity-seeder env table in Environment variables. The load-bearing ones:

VariableMeaning
LOGTO_BASE_URLLogto reference-tenant base URL (alias LOGTO_ENDPOINT)
LOGTO_TENANT_IDthe Logto tenant id
LOGTO_M2M_APP_ID / LOGTO_M2M_APP_SECRETManagement-API M2M credentials — secrets
LOGTO_MGMT_API_RESOURCEthe Management API resource/audience
ALLOW_LOGTO_SEEDmaster enable — must be true for any write
LOGTO_ENVsandbox | prod — must be sandbox/dev/test/staging to pass safety
LOGTO_SEED_NAMESPACEnamespace tag for all seeded objects (default palonexus-demo)
LOGTO_DRY_RUNpreview without writing unless a --no-dry-run/--dry-run flag overrides
LOGTO_MAX_DELETEsafety cap on deletions per run (default 400)

Every mutating command (apply, cleanup, reseed) calls assert_safe() first. check runs the same evaluation and reports it. The hard-stops (nsr_seeder/safety.py):

CheckPasses when
base_url_presentLOGTO_BASE_URL is set
host_in_allowlistthe target host matches LOGTO_ALLOWED_HOST_SUFFIX (default .logto.app,localhost,127.0.0.1)
tenant_is_sandboxthe host is local, or the host+tenant identity contains one of sandbox, dev, test, staging, demo, local
no_production_markerthe tenant identity contains neither prod nor production
logto_env_is_sandboxLOGTO_ENV is sandbox / dev / test / staging
allow_seed_flagALLOW_LOGTO_SEED is true
seed_namespace_presentLOGTO_SEED_NAMESPACE is set
email_suffixes_non_routableevery LOGTO_ALLOWED_EMAIL_SUFFIX entry is a non-routable suffix (e.g. .test, .example, .invalid, .localhost)

If any check fails the run aborts with exit 3 and prints the failing checks — the seeder refuses to operate on a tenant that does not clearly look like sandbox/dev/test.

Terminal window
cd platform/seed-logto
python3 seed_logto.py check # safety preflight (exit 0 = OK)
python3 seed_logto.py plan # preview the upserts
python3 seed_logto.py --no-dry-run apply # apply against the connected tenant
python3 seed_logto.py validate # write the validation report

Add --offline to any subcommand to dry-run against the in-memory FakeLogtoClient (no live tenant) — useful to prove the path before real creds. This is the same sequence the DOKS runbook Step 4 documents (Option B — CLI), and the same actions the /settings/seed portal console drives.

The control-plane is built and deployed from the platform Makefile (platform/Makefile). IMAGE and OVERLAY are overridable variables (defaults palonexus/control-plane:dev and deploy/kustomize/overlays/dev).

TargetWhat it does
make testgo test ./... in control-plane/ — policy matrix + audit hash-chain unit tests
make smokebuild the binary, boot it, and exercise Envoy’s external-authorization (ext_authz) decision flow (allow 200 / deny 403 over :9191/authz)
make imagedocker build the container image ($(IMAGE))
make renderkustomize-render the full control layer to stdout (no apply)
make deploykubectl apply -k $(OVERLAY) — apply the control layer to the current kube-context
Terminal window
make test
make image IMAGE=ghcr.io/you/control-plane:dev
make render OVERLAY=deploy/kustomize/overlays/selfhost
make deploy

The whole control layer is one kubectl apply -k against a kustomize overlay — the same manifests make render / make deploy drive. Apply an overlay directly:

Terminal window
kubectl apply -k platform/deploy/kustomize/overlays/<overlay> --load-restrictor LoadRestrictionsNone

Rather than duplicate the cluster-specific steps (CRDs, Envoy Gateway, secrets, ingress) here, follow the runbooks:

  • DOKS runbook — the end-to-end managed-Kubernetes path on DigitalOcean.
  • Self-hosting — the selfhost overlay and install-selfhost flow on any cluster.

The Python SDK (palonexus package) is the programmatic entry, not a CLI: there is no standalone palonexus CLI binary. Drive it from code or a REPL:

from palonexus import PaloNexus
pn = PaloNexus.offline() # in-memory, no cluster, no network — ideal for tests/dev
pn = PaloNexus.from_env() # reads PALONEXUS_* (or returns offline() when PALONEXUS_OFFLINE is truthy)

from_env() reads the PALONEXUS_* client variables documented in Environment variables — SDK. See the Quickstart to get started.