Relevant Articles
This guide covers the Elisity CLI: installing it, pointing it at a Cloud Control Center instance, working through what it can do, and two use cases.
You need a Client ID and Client Secret from a CCC API Client first: see How to Access Elisity APIs.
Introduction
The Elisity CLI is a command-line interface to Cloud Control Center (CCC). It brings the data you read in the CCC user interface into the tools your team already uses: a terminal session, a scheduled job, a reporting pipeline. Anything you reach through the CCC API you reach through the CLI, with authentication, pagination, retries, and output formatting handled for you.
The CLI does not replace the interface. Use the interface to inspect and decide, and the CLI to carry the same fields into a report, a ticket, or a script.
The CLI tracks the CCC API and changes between CCC releases. The repository at github.com/Elisity/elisity-cli is the source of record for installation and the current version.
The guide covers the installation, then the CLI's capabilities — command groups, output formats, filtering — and then two use cases that show teams putting it to work.
Prerequisites
- Access to the repository at github.com/Elisity/elisity-cli. It is the source of record: install from it, and check it for the current version and command reference.
- Python 3.10 or later, as declared by the package.
- Network reach over HTTPS to the CCC instance.
- An API Client (Client ID and Client Secret) created under Settings > Admin > User Management > API Clients > Add API Client, per How to Access Elisity APIs.
An API Client expires according to the Access Duration set when it was created, unless Set Unlimited Access was selected. When the credentials expire, regenerate them in CCC and update the profile.
The role assigned to the API Client determines which endpoints it reaches; a too-narrow role returns a permission error.
1. Getting Started with the Installation
Step 1. Install the CLI
The CLI is not published on PyPI. Install it from a clone of the repository:
git clone git@github.com:Elisity/elisity-cli.git cd elisity-cli python3 -m venv .venv source .venv/bin/activate pip install -e .
The virtual environment is required: current Ubuntu and Debian releases block system-wide pip install under PEP 668. Confirm the install:
elisity --version
Compare the printed version against the repository. Re-activate the virtual environment in each new session.
Step 2. Configure a profile
A profile holds the base URL and credentials for one CCC instance:
elisity config set-profile prod \ --base-url https://your-ccc.idp01.elisity.io \ --client-id YOUR_CLIENT_ID \ --client-secret 'YOUR_CLIENT_SECRET'
This writes ~/.elisity/config.yaml, and the first profile created becomes the active profile.
Important: ~/.elisity/config.yaml holds the client secret in plain text. Restrict it with chmod 600 ~/.elisity/config.yaml.
Repeat the command for each additional instance, then switch between profiles:
elisity config use-profile staging # switch the active profile elisity config list-profiles # list profiles, active one marked elisity config show # resolved configuration, secrets redacted
elisity config show redacts any key containing secret, so its output is safe to paste into a ticket.
Environment variables for pipelines and containers
On a build runner or in a container, export the settings instead:
export CCC_BASE_URL=https://your-ccc.idp01.elisity.io export CCC_CLIENT_ID=YOUR_CLIENT_ID export CCC_CLIENT_SECRET=YOUR_CLIENT_SECRET
CCC_TIMEOUT overrides the request timeout the same way.
Each field resolves independently: environment variable, then the profile named by -p, then the active profile. An exported CCC_BASE_URL therefore redirects the request while the profile supplies the credentials.
Step 3. Verify authentication
The CLI authenticates with the OAuth2 client_credentials grant against {base_url}/auth/realms/elisity/protocol/openid-connect/token, scope openid. Tokens are cached in memory and never written to disk.
elisity auth test
A working profile returns a healthy status:
{
"status": "healthy",
"code": 200,
"authenticated": true
}
Any other result means you are not connected. Two commands narrow it down:
elisity auth token # print the raw bearer token, for curl or another tool elisity auth whoami # decode the current JWT and show its claims
When it fails, re-run with --debug to see the request and response:
elisity --debug auth test
2. Using the CLI
Everything here is read-only and safe against a live tenant.
What the command groups cover
Commands are grouped by the part of CCC they address:
| Group | What it covers |
|---|---|
| policy | Policy sets, policies, policy groups, service groups |
| topology | Sites, zones, Virtual Edge and Virtual Edge Node objects |
| devices | Device identity and enrichment |
| ad | Active Directory and Microsoft Entra ID |
| connectors | IdentityGraph connectors and configurations |
| insights | Policy insights and suggestions |
| system | Tasks, specifications, state sync |
| reporting | Zero Trust metrics, site KPIs, traffic |
| flows | Device state, flow search, noise |
| config | CLI profiles, credentials, defaults |
| auth | Authentication checks and tokens |
| glossary | Product vocabulary lookup |
Ask the CLI for the commands inside a group: elisity --help lists the groups, elisity topology --help that group's commands, elisity topology get-site-v2 --help one command. The CLI help and the repository are the current list; a printed one goes stale.
Running a command
Before routing a site issue, you want device and enforcement-node counts per site. One command returns what the per-site cards in CCC show:
elisity -f table reporting get-site-kpis
The response is one row per site:
siteName onlineDevices virtualEdgeNodes activatedPolicies policyEnforcementScore Boston 143 1 81 100.0 CORK 1071 6 245 84.9
Supporting commands fill in the rest:
elisity topology get-all-sites # the sites themselves elisity topology get-site-v2 <SITE_ID> # one site by ID elisity devices get-device-header-data # tenant-wide device totals elisity reporting get-aggregate-enforcement-score # tenant-wide enforcement score
On the sites endpoint the interface's site name is the label field, not name; filtering on name returns nothing and no error.
To carry recent policy-set modifications into a change-review workflow:
elisity policy get-all-as-nd-json
The endpoint streams newline-delimited JSON, which the CLI parses into an array. A typical record:
{
"id": "29eef758-a1e3-49c0-a531-779ef835c325",
"modifiedBy": "service-account@your-org.example",
"modifiedAt": "2026-05-14T17:49:05.514081Z",
"status": "Active"
}
Other read commands worth knowing:
elisity connectors read-all-connectors # IdentityGraph connectors elisity reporting get-zero-trust-metrics # Zero Trust metrics per policy group
Output formats
Four output formats, selected with -f:
| Format | Use it for |
|---|---|
| json (default) | Piping to jq or storing as a file |
| table | Reading at the terminal; paginated responses are unwrapped |
| yaml | Reading a deep record; key order is preserved |
| csv | Spreadsheets and inventory feeds |
Filtering and reshaping with JMESPath
-q takes a JMESPath expression, applied before rendering, so it works with every output format — selecting records and projecting fields:
elisity -q '[].label' topology get-all-sites # site names
elisity -q 'length(@)' topology get-all-sites # how many sites
# Active policy sets only, as a table of chosen fields
elisity -f table -q "[?status=='Active'].{name: name, coverage: deviceCoverage}" \
policy get-all-as-nd-json
# Fields out of a paginated response
elisity -q 'content[].{id: id, name: deviceName}' \
devices get-devices-view --body '{"pageable":{"page":0,"size":50}}'
Global flags go before the command
Important: -f, -q, -p, and --debug are options on elisity itself, and are not recognized after the command name.
elisity -f table -q '[].label' topology get-all-sites # correct elisity topology get-all-sites -f table # wrong, flag not applied
Destructive commands and --confirm
Destructive commands require --confirm:
elisity <group> <destructive-command> <ID>
Without the flag the CLI refuses, exits 1 without making an HTTP call, and prints:
Use --confirm to execute this destructive operation.
Destructive is decided by the API path, not the HTTP verb: every DELETE, plus the POST bulk deletes, the PUT decommission operations, and the Insights reset and recreate operations. Do not assume a POST is safe. Dry-run siblings are not gated.
Important: --confirm guards against accident; it does not make a bulk delete reversible. In a script, check that the target exists first and handle the non-zero exit.
3. Comparing CLI Output to the Cloud Control Center UI
The CLI and the interface read the same data from two surfaces. Two differences catch people out: timestamp rendering, and naming.
Timestamps: the CLI reports UTC, the interface renders local time
The same record can look like two different events. A policy set modified at 6:13 a.m. Eastern shows in the interface as August 5, 6:13 a.m. and in the CLI as:
"modifiedAt": "2026-08-05T10:13:42.118904Z"
The trailing Z means UTC; the four hours are the Eastern Daylight Time offset.
- Convert a CLI timestamp, or label it UTC, before handing it to someone reading the interface. An unlabeled timestamp is read as local time.
- Filter by time in UTC in a script, and expect the local offset to shift twice a year where daylight saving applies.
Vocabulary: mapping an interface term to a command
Elisity vocabulary does not always match the generic industry term: "monitor mode" is Simulation, "Zero Trust score" is the Policy Enforcement Score, "security group" is a Policy Group. A command guessed from the industry term is usually wrong.
The glossary group removes the guess. It makes no API call and needs no authentication:
elisity glossary list # every term, with its domain elisity glossary search "monitor mode" # look up a synonym elisity glossary explain "Zero Trust score" # explanation plus ready-to-paste commands
Look the vocabulary up first, then run the command the glossary names. That is also what lets a workflow turn a plain-language request into a command — the basis of Use Case 2.
Use Case 1 — Integrating the CLI into an Existing Automation Framework
Once an operator can retrieve a field by hand, the next question is where that field should go. The answer is rarely "a terminal window." It is a record in the system the next person already works in.
There are several useful destinations for Elisity information, and three of them account for most of what teams build first:
- Inventory. An inventory workflow maps device records into ServiceNow's configuration database, so the asset record and the network view describe the same device.
- The service desk. A help-desk workflow attaches policy or reporting observations to a review task in ServiceNow. Tier 1 or Tier 2 picks the task up with the evidence already attached instead of gathering it again.
- Security operations. A security workflow brings additional context into a Microsoft Sentinel investigation through Azure Logic Apps, so an analyst sees the Elisity view alongside the alert that started the investigation.
ServiceNow appears twice because inventory management and service-desk review are different jobs. Each uses different records and routing logic.
These are integration designs that your team configures. The CLI handles the Elisity read; your workflow handles the mapping, routing and assignment.
Following the help-desk branch: an enforcement-score review
To make that concrete, follow the help-desk branch through an Ansible example.
Here, a reporting observation becomes the starting point for a review. The recorded aggregate enforcement score moves from 85.0 to 57.3, a decrease of 27.7 points. That reading is the trigger for the workflow, not its conclusion.
The read itself is one command:
elisity -f json reporting get-aggregate-enforcement-score
The example Ansible rule compares that movement with a threshold of ten points. A 27.7-point decrease crosses it. When the threshold is crossed, the workflow prepares a ServiceNow handoff with the observation and its evidence attached, and Network Operations reviews the change in context — with the reading, the previous value and the time it was taken already in the task.
Important: The threshold is an example chosen for this workflow. The calculation was checked in a local replay; the Ansible and ServiceNow steps shown here are illustrative. The score tells us something changed, but it does not establish the cause.
In this workflow, the team defines the reads, the comparison and the destination in advance. Every step is decided before the job runs, which is what makes the result predictable enough to route to a queue.
What your workflow consumes
The integration surface is structured output plus exit codes. A job that runs a shell command and parses JSON or CSV consumes CCC data with no SDK: -f json or -f csv for the shape, -q for the fields you need, and environment variables (CCC_BASE_URL, CCC_CLIENT_ID, CCC_CLIENT_SECRET) so the runner needs no config file and can pull its credentials from your secrets manager.
Exit codes let the job tell a configuration problem from a CCC error from a network failure:
| Exit code | Meaning |
|---|---|
| 0 | Success; the response is on stdout. |
| 1 | Generic — usage, JMESPath syntax, or validation. |
| 2 | Configuration — missing base URL or credentials. |
| 3 | HTTP error — non-2xx from CCC, body on stderr. |
| 4 | Network — DNS, connect, or timeout after retries. |
An empty result is exit 0: treat [] as a valid answer, not a failure.
Use Case 2 — Using the Elisity CLI in Your Agentic Workflows
The previous workflow knew its next step before it ran. This one does not. Suppose someone asks an agent to show them monitor-mode policies. Before the agent can do anything at all, it has to connect that phrase to the product's terminology and the appropriate command.
The CLI supplies a vocabulary lookup for that purpose:
elisity glossary search "monitor mode"
In this verified example, the lookup connects "monitor mode" with Simulation, the supported value, and a command recipe. The agent uses that recipe to select its next read:
elisity -q '[].{name: name, status: status}' policy get-all-as-nd-json
This is part of the answer to "Why use the CLI when the API already exists?" The repository supplies product mappings, command recipes and common request handling that the agent can reuse, and your team can adopt updated commands from that shared repository as its needs evolve.
The agent still interprets the request and owns the workflow. The CLI gives it a prepared set of building blocks.
A longer review: vendor access against approved maintenance
One lookup is a small thing. The value shows up when several of those blocks go together in a review that nobody wrote a script for.
Imagine asking an agent to check vendor access against approved maintenance and prepare a review task for any exceptions. A customer-configured schedule or a maintenance event could initiate that review.
Microsoft Copilot Studio first gets the approved assets, service and time window from ServiceNow. It then chooses CLI reads to establish site and device context, identify relevant groups, inspect policy sets and rules, and examine communications. The results inform its next question, so the investigation can require additional reads and follow-up. That is the difference from the Ansible example: the third read depends on what the second one returned.
In this illustrative example, activity appears outside the approved maintenance window. That gives the agent a specific question to investigate — was an extension approved? It should resolve that context before treating the activity as an exception to the approval.
The agent prepares the ServiceNow draft with the relevant evidence and the open question attached. The security analyst and site owner decide what happens next.
Notice who owns the loop: Copilot Studio queries and reasons; the CLI returns Elisity evidence. The agent's separate ServiceNow action handles the task.
Illustrative workflow. Customer-configured trigger and connectors; no live integration was executed.
Keeping the agent inside a boundary
An agent that picks its own next step needs a boundary that does not depend on it choosing well. Four hold that line:
-
Read-only scope. Destructive commands require
--confirmby design. Do not supply it automatically. - Named commands, not arbitrary execution. Allow-list what the agent may call rather than handing it a shell.
- Scoped credentials. Use an API Client whose role grants only what the workflow needs. The role is the boundary, not the prompt.
- A person reviews the result. The agent assembles evidence and frames the question; a person decides.
One CLI, whichever agent environment you use
The shared interface is the useful part of this approach.
Your team can expose the Elisity CLI to a command- or tool-capable agent through a configured runtime or a hosted adapter. The products shown above — Codex, Claude Code, Grok Bot, Hermes Agent, OpenClaw, Perplexity Computer, Microsoft Copilot Studio, Microsoft Agent Framework and LangGraph — illustrate that broader ecosystem. They are integration options, rather than a list of certified connectors.
The broader benefit is a reusable starting point: supplied vocabulary, commands and structured results that your agent can work with. The harness still owns orchestration and memory. The CLI does not automatically make a new session remember the last one.
Begin with a single useful workflow and build from there.
In a pilot across five paired runs, the CLI approach used 48 percent fewer uncached input tokens and 43 percent fewer output tokens than the baseline, and both approaches answered every task correctly. Those figures describe this pilot.
Troubleshooting
| Symptom | Cause and fix |
|---|---|
No CCC_BASE_URL configured or Missing CCC_CLIENT_ID or CCC_CLIENT_SECRET
|
No active profile, or an incomplete one. Create a profile, or export the values. |
Profile 'X' does not exist |
The profile is not in the config file. Run elisity config list-profiles. |
CCC authentication failed. Check credentials. |
Wrong client ID or secret, wrong base URL, no network path, or an expired API Client. Run elisity --debug auth test for the error body. |
| Requests time out | Timeouts are retried three times with exponential backoff. Raise the timeout with export CCC_TIMEOUT=120, or set --timeout on the profile. |
| SSL certificate errors | Expected against a lab instance with a self-signed certificate. Add verify_ssl: false to that profile in ~/.elisity/config.yaml. Never disable verification against production. |
| A flag appears to be ignored | A global flag was placed after the command name. |
| A JMESPath projection returns nothing | Usually a wrong field name, not a wrong filter; label versus name is the classic. Run the command without -q and read the keys. |
| Commands that worked before now fail authentication | The API Client has reached the end of the Access Duration set when it was created. Regenerate the credentials in CCC and update the profile. |
Otherwise --debug prints request details to stderr, leaving stdout clean:
elisity --debug topology get-all-sites 2> debug.log | jq '.[].label'
Next Steps
- Full command reference — the repository at github.com/Elisity/elisity-cli, which also carries the configuration guide.
-
Explore from the CLI —
elisity --help,elisity <group> --help, andelisity glossary listwhen you know the term but not the command. - Start with a recurring operational question. Reproduce something you answer by hand each week as a command.
- Feedback and issues — github.com/Elisity/elisity-cli/issues.