CLI
The nistor command: manage rules as code, run services, build distributions and scaffold tools.
nistor is Nistor's command-line tool. It does two kinds of work:
- It sends configuration that you keep as files to the backend's API: scheduling rules, alert channels and policies, data contracts, resource patterns, environment mappings, the compiler's configuration and deployment records. These commands need a backend.
- It runs the platform itself:
nistor servestarts a server role,nistor migrateapplies the database migrations andnistor distbuilds the runtime image.nistor tool newscaffolds a tool. These commands need no backend.
Install#
From a clone of the repository, make dev installs the CLI and every open-source package into .venv:
git clone https://gitlab.com/nistor-io/nistor.git
cd nistor
make dev
.venv/bin/nistor --help
Once released, the CLI is on PyPI as nistor-cli. Until then, install from a clone. It needs Python 3.11 or later, and
has three extras:
| Extra | Adds |
|---|---|
gcp |
Google identity tokens for a backend on Cloud Run (see Connect to a backend). |
dist |
The pinned uv and setuptools that nistor dist lock runs. |
postgres |
The PostgreSQL driver that nistor migrate connects with. |
Connect to a backend#
Two global options tell the CLI where the backend is. They go before the command group:
nistor --api-url https://nistor.example.com --token <token> rules list
| Option | Variable | Meaning |
|---|---|---|
--api-url |
NISTOR_API_URL |
The backend's base URL. Every command that calls the API needs it, and stops with an error without it. |
--token |
NISTOR_API_TOKEN |
The bearer token sent with every request. |
When you give no token and the URL is a Cloud Run address (*.run.app), the CLI mints a Google identity token for it.
With GOOGLE_IMPERSONATE_SERVICE_ACCOUNT set, the token is that service account's, and your own Google credentials must
be allowed to impersonate it. Otherwise it comes from a service-account key in GOOGLE_APPLICATION_CREDENTIALS or from
the metadata server of the machine. This needs the gcp extra. The backend accepts a Google identity token only from a
service account listed in its TRUSTED_SERVICE_ACCOUNTS. In any other case the CLI sends no token.
The Quickstart stack publishes its backend on http://localhost:8000 and accepts requests without a
token.
nistor auth test checks a URL and a token: it calls /api/v1/health without the token, then one route that needs it.
A request that gets a 503 or no connection is retried, and so is a GET, PUT or DELETE that gets a 500, 502 or 504.
The CLI waits between attempts (as long as Retry-After says, when the backend sends it) and gives up after 180 seconds,
so a sync that lands while the backend starts or reloads waits for it.
Commands log what they do on stdout; LOG_LEVEL sets the level (INFO by default). Most failures exit with status 1.
Command groups#
Run nistor <group> --help and nistor <group> <command> --help for every option.
| Group | Commands | Does | Calls the API |
|---|---|---|---|
nistor rules |
sync, list, validate, check-platform-targets |
Scheduling rules kept as files (see below) | All but validate |
nistor alerts |
sync, list |
Alert channels, policies and email settings kept as JSON | Yes |
nistor odcs |
sync |
Data contracts kept as *.odcs.yaml |
Yes |
nistor patterns |
sync, list |
Resource patterns (resources_pattern.json by default) |
Yes |
nistor env-mapping |
sync, show |
Environment mappings (environment_mappings.json by default) |
Yes |
nistor compiler |
sync, show |
The compiler's configuration (compiler_config.json by default) |
Yes |
nistor deployments |
record |
Report the resources a deployment manages, from terraform show -json |
Yes. A report that cannot be delivered is a warning, unless you pass --fail-if-not-recorded. |
nistor auth |
test |
Check the URL and the token | Yes |
nistor admin |
user list, user list-permissions, user grant, user revoke, audit export |
Users, permissions and the audit log | Yes |
nistor connections |
create-gcp-from-env |
Create a Google Cloud connection from environment variables, for local development | Not with --dry-run |
nistor migrate |
none | Apply the database migrations: core, then tools, then plugins | No: it connects to the database |
nistor serve |
one role | Start one server role (see below) | No |
nistor dist |
lock, build, verify |
Lock a distribution and build the runtime image from the lock | No |
nistor release |
prepare, verify-tag, parse-tag, members, changelog, notes, names |
Release tooling for maintainers | No |
nistor tool |
new |
Scaffold a tool package (see below) | No |
The sync commands of alerts, odcs, patterns, env-mapping and compiler all take --dry-run. nistor admin
prints its examples with --help, for instance nistor admin user grant alice@example.com iam:view and
nistor admin audit export --since 7d --format csv.
Rules as code: nistor rules#
Rules and scheduling explains the rule files: code_id, status_by_env, and
why a synced rule is locked. This section is the reference of the commands.
validate, sync and check-platform-targets take their files in one of three ways:
| Option | Reads |
|---|---|
--dir DIR |
Every *.json, *.yaml and *.yml file under DIR, subdirectories included. |
--files FILE … |
The files you name. |
--all |
A fixed directory of Nistor's own deployment repository. Use --dir or --files instead. |
nistor rules validate#
nistor rules validate --dir rules/
It needs no backend and no token, so it can run as a merge-request check. It reports every problem it finds, then exits with status 1 if there is one:
- a file that does not parse, or that is not a list of rules (a YAML file may hold a single rule). A sync skips a JSON
file that is not a list, and
--delete-orphanedwould then delete its rules; - files that hold no rule at all;
- a rule without a
code_id, and acode_idornameused twice across the files; - every rule as the sync would send it to
dev,testandprod, checked against the rule schema of the installed version, including every key that the schema does not know and the backend would silently drop.
A valid set prints one line:
✓ 1 rule(s) in 1 file(s) are valid for dev, test, prod
A misspelt key fails:
❌ 1 problem(s) in the rule files:
- rules/marts.yaml: marts/mart-sales-daily: if.quiet_period_secnds: not a rule field this checkout knows — the backend would silently drop it (typo?)
nistor rules sync#
nistor rules sync --env prod --dir rules/ --dry-run
nistor rules sync --env prod --dir rules/ --delete-orphaned --source-repo acme/rules
The sync matches rules by code_id. It creates the rules that are new, updates the ones that changed and leaves the
others alone. If it cannot read the current rules from the backend, it stops and pushes nothing.
| Option | Effect |
|---|---|
--env dev|test|prod |
Required. The environment the rules are synced for; status_by_env is resolved for it. |
--dry-run |
Show what would change, and change nothing. |
--delete-orphaned |
Delete the rules that came from files and are no longer in them. With --source-repo, only the rules of that repository. |
--source-repo PATH |
The repository that owns these rules (group/project), recorded on each rule. |
--adopt-rules-without-source-repo |
With --source-repo and --delete-orphaned, also treat as this repository's the rules synced before any --source-repo was passed. Pass it only from the repository that pushed them. |
--source-branch BRANCH |
The branch recorded on each rule, for its "View source" link. By default, the CI branch or the working directory's branch. |
--validate |
Ask the backend to validate the rules first. Invalid rules stop the sync (exit status 1) unless --continue-on-error. If the validation call itself fails, the sync goes on with a warning. |
--require-rules-format |
Push nothing, and exit with status 1, unless the backend stores at least the rules format of this CLI. An older backend would drop the fields it does not know. |
--continue-on-error |
Exit with status 0 even when some rules failed. |
--output-json FILE |
Write a report of the run as JSON. |
--record-sync-event |
Record the run in the backend (POST /api/v1/gitops/sync-events), under the repository that --source-repo or the CI variables name. A failure to record is a warning. |
After the sync, the CLI checks the exact node ids that each rule listens to (include_node_ids): that the node exists,
that it is upstream of the rule's nodes, and that it was written to recently. Each finding is a warning. These checks
never change the exit status.
nistor rules list and check-platform-targets#
nistor rules list prints the rules stored in the backend, grouped by the type of their action.
nistor rules check-platform-targets is for a deployment pipeline. It fails unless every rule of Nistor's own maintenance
jobs that the files make active in --env is active in the backend and matches at least one node. It retries for
--wait-seconds (120 by default).
In GitLab CI#
The repository has a GitLab CI template for a rules repository,
ci/templates/rules-repo.yml. Its validation job runs nistor rules sync with
--dry-run and --continue-on-error on merge requests, against the environment of the target branch. Its deployment job
syncs on a push to dev, test or prod, with --delete-orphaned and --record-sync-event. Both read the backend's
URL from NISTOR_API_URL_DEV, NISTOR_API_URL_TEST and NISTOR_API_URL_PROD, and authenticate with Google credentials
(GCP_SERVICE_ACCOUNT_KEY when the runner has none) of a service account that the backend trusts. The template installs
nistor-cli[gcp] from PyPI at a release version, so it needs a published release. It does not run
nistor rules validate: add a job for it.
Scaffold a tool: nistor tool new#
nistor tool new acme_warehouse --dest .
It writes a complete tool package to <dest>/packages/integrations/<id> (--dest is the working directory by default)
and needs no backend:
✅ Created tool 'acme_warehouse' in packages/integrations/acme_warehouse
Next steps:
1. cd packages/integrations/acme_warehouse
2. In a virtualenv with nistor-core and nistor-testing installed: pip install --no-deps -e .
3. pytest tests # the conformance kit runs over the tool as installed
4. Replace client.py with your vendor's client and re-record tests/conformance/*; see README.md
- The id is a lowercase letter followed by 1 to 30 lowercase letters, digits or underscores. It may not end with an
underscore or hold two in a row, and it may not be
hello_world. - The names follow the id: the module is
nistor_tool_acme_warehouse, the distributionnistor-tool-acme-warehouse, the classesAcmeWarehouse…and the settingsACME_WAREHOUSE_…. - The template is the Hello World example (
examples/providers/hello_world), shipped inside the CLI, so the command works from any install. The new package drops the example's "do not upload" classifier, so you can publish it. - Nothing is overwritten. If the target directory exists, the command changes nothing and exits with status 1.
The package passes its own tests, the conformance kit included, as generated. Writing a tool describes its files and the next steps.
Run the platform#
nistor serve <role> starts one server role: backend, scheduler, jobs, compiler, input-logs, mcp, runner,
workspace-events or dq-rebuild. It listens on --port, else $PORT, else 8080, and binds --host (0.0.0.0 by
default). It is the entry point of the runtime image. It refuses to start, with exit status 78, outside an image built by
nistor dist build (no /etc/nistor/distribution.json) unless NISTOR_DEV=1, and it refuses NISTOR_DEV=1 on Cloud
Run. runner and dq-rebuild start a runner of the Data quality module (Nistor Enterprise)
and do not start without it.
nistor migrate applies the database migrations, core first, then tools, then plugins. See Install on GCP
and Upgrading for when to run it.
nistor dist lock, build and verify take an environment's directory (--env-dir), which holds distribution.toml
and distribution.lock. lock writes the lock, build builds the runtime image from it, and verify checks the lock,
an image or the running environment. See Integrations for what a
distribution file activates.