Directory CLI
Command-line client for the IB1 Directory member API. Built to make the API easy to exercise as it grows, and to be drivable by scripts and code agents (machine-readable output, real exit codes, no prompts).
Authenticate either by logging in (browser, authorization-code + PKCE, token cached in
the OS keyring) or by pasting a token (--token / DIRECTORY_TOKEN) for short runs and
CI.
Install
pip install ib1-directory-cli
For local development from a clone:
pip install -e ".[dev]" # or: uv sync --extra dev
This installs a directory command.
Configuration
| Option | Env var | Default |
|---|---|---|
--api-url |
DIRECTORY_API_URL |
https://directory.core.sandbox.trust.ib1.org |
--token |
DIRECTORY_TOKEN |
(none) |
--organization |
DIRECTORY_ORGANIZATION |
(none) |
--json |
pretty-printed |
The default API is the sandbox. Point --api-url or DIRECTORY_API_URL at another
environment, or at http://localhost:8000 for a locally running API.
Login needs no configuration beyond the API URL. directory login asks the API for its
Cognito hosted UI domain, client id and scopes (GET /.well-known/directory-cli). These optional
variables override what the API publishes, e.g. against an API that doesn't publish it:
| Env var | Meaning |
|---|---|
DIRECTORY_COGNITO_DOMAIN |
Hosted UI base URL, e.g. https://<prefix>.auth.<region>.amazoncognito.com |
DIRECTORY_COGNITO_CLIENT_ID |
The public (no-secret) CLI app client id |
DIRECTORY_OAUTH_SCOPES |
Space-separated scopes. Default: whatever the API publishes, else openid email |
DIRECTORY_REDIRECT_PORT |
Default 8400 (must match the client's registered callback) |
The API is only asked when DIRECTORY_COGNITO_DOMAIN and DIRECTORY_COGNITO_CLIENT_ID aren't
both set.
Login
directory login # opens a browser, caches the token in your OS keyring
directory logout # clears the cached token for this API
directory token # prints a current id token (refreshing if needed)
After directory login, me get / me update use the cached token automatically. Token
precedence is --token then DIRECTORY_TOKEN then the keyring cache.
Tokens are cached per API URL, so you can be logged in to several environments at once and
--api-url picks which token is used. The Cognito client that issued a token is cached with
it, so refreshing the token doesn't call the API.
directory token is the bridge for agents/CI that can't open a browser: a human runs it and
passes the value as DIRECTORY_TOKEN. The token is short-lived, so this suits short runs.
Usage
# Read your organisation
directory --token "$ACCESS_TOKEN" me get
# Same, token from the environment, compact JSON for piping
export DIRECTORY_TOKEN=...
directory --json me get | jq .identifier
# Partial update (only the flags you pass are sent — a merge-patch)
directory me update --street-address "1 New Road" --email ops@acme.example
directory me update --country GB --postal-code "AB1 2CD"
Editable fields: --email, --street-address, --locality, --region, --state,
--postal-code, --country, --privacy-policy, --data-protection-url.
Organisations (owning more than one)
Most users own a single organisation and need nothing extra. Some own several — for example an
energy data provider that also owns an example CAP organisation, which it acts as to generate test
certificates. List the ones you own, then pass --organization <identifier> (or set
DIRECTORY_ORGANIZATION) on any command to say which one you are acting as.
# List the organisations you own
directory me orgs
# Act as a specific organisation
directory --organization cap12345 me get
directory --organization cap12345 cert sign abc12345 client
# Or set it once for the session
export DIRECTORY_ORGANIZATION=cap12345
directory me get
If you own more than one organisation and don't pass a selector, the API returns an error asking you
to pick one. There is no -o short flag for --organization because -o is the output-path flag on
ca download and cert download.
Applications
# List your applications (optionally filter by scheme short name)
directory apps list
directory apps list --scheme perseus
# Read one application by identifier
directory apps get abc12345
# Create an application under a scheme (roles are repeatable role identifier URLs)
directory apps create --scheme perseus --title "My App" \
--role https://registry.trust.ib1.org/scheme/perseus/role/data-provider \
--home-page-url https://app.example.com
# Create with a data service (title, conforms-to and endpoint-url go together)
directory apps create --scheme perseus --title "My App" \
--data-service-title "My Feed" \
--data-service-conforms-to https://standard.example.com \
--data-service-endpoint-url https://api.example.com
# Partial update (only the flags you pass are sent; --role replaces the whole set)
directory apps update abc12345 --title "Renamed" --support-url https://support.example.com
# Delete (destructive, so --yes is required; the API refuses with 409 if certificates exist)
directory apps delete abc12345 --yes
The publisher on a data service is set by the server to your organisation, so there is no
flag for it. Application create/update accept --description, --home-page-url,
--support-url, --message-delivery, --role, and the four --data-service-* flags.
Administration
Admin commands require your Cognito account to be in the directory admin group; other users get a 403.
# Onboard a new organisation (creates the org, its scheme membership + role, and the
# officer contacts). The scheme is fixed per environment; the role is a slug within it.
directory admin create-org \
--legal-name "Acme Ltd" --email contact@acme.example \
--street-address "1 Main St" --locality London --postal-code "AB1 2CD" \
--company-number 12345678 --role energy-data-provider \
--data-officer-name "Dana" --data-officer-email dana@acme.example \
--licence-officer-name "Lee" --licence-officer-phone "+441234567890"
# Add a user to an organisation and send them a Cognito invite (they become an owner)
directory admin add-member <organization-identifier> --email new.owner@acme.example
Each officer needs an email or a phone. --region and --effective-date (ISO YYYY-MM-DD,
default today) are optional. Onboarding = create-org, then add-member for each owner.
Certificates
# Sign a certificate for an application. With no --csr, a private key and CSR are
# generated locally; the key is written to disk (mode 0600) and the signed cert saved.
directory cert sign abc12345 client
# → my-app writes abc12345-client-key.pem and abc12345-client-cert.pem, prints the cert id
# Use your own CSR instead of generating one (no key is written):
directory cert sign abc12345 signing --csr my.csr --cert-out signing.pem
# Download a certificate by id (default filename comes from the server)
directory cert download <certificate-id> -o cert.pem
# Revoke a certificate (destructive, so --yes is required; this is a soft revoke)
directory cert revoke <certificate-id> --yes
cert sign takes the application identifier and the type (client or signing). The CA
forces the certificate subject to your organisation regardless of the CSR, so a generated
CSR's subject does not matter. Download the CA root/intermediate bundle with
directory ca download <client|signing>.
Exit codes
| Code | Meaning |
|---|---|
| 0 | Success |
| 1 | API or transport error (4xx/5xx, connection failure) |
| 2 | Usage error (no token, update with no fields, delete without --yes, login against an API that publishes no login configuration) |
Prerequisites for login (one-time, out of this repo)
Interactive login needs a public Cognito app client on the existing user pool:
- no client secret
- authorization-code grant with PKCE
- callback URL
http://localhost:8400/callback(the exact port must matchDIRECTORY_REDIRECT_PORT) - scopes
openid email
The API it logs in to must then be configured with:
COGNITO_ALLOWED_CLIENT_IDSincluding the client id, so the API accepts tokens it issuesCOGNITO_DOMAINandCOGNITO_CLI_CLIENT_ID, so the API publishes them at/.well-known/directory-clifor the CLI to discover
These are deploy/infra steps (AWS and the deployments repo), not part of the CLI.
Tests
pip install -e ".[dev]" # or: uv sync --extra dev
pytest # or: uv run pytest
Metadata
Release files for ib1-directory-cli 0.5.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| ib1_directory_cli-0.5.1.tar.gz | 56.6 kB | With provenance | Details for ib1_directory_cli-0.5.1.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| ib1_directory_cli-0.5.1-py3-none-any.whl | Python 3 | none | any | Details for ib1_directory_cli-0.5.1-py3-none-any.whl |
Total release size: 74.4 kB
Release files / ib1_directory_cli-0.5.1.tar.gz
| Download URL | ib1_directory_cli-0.5.1.tar.gz |
|---|---|
| Size | 56.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
a99e539d3db274493f2d5fd57b7dbc8b39531e71f1ffa6b1eb05e3f1c491889b
|
|
BLAKE2b-256 checksum How to use checksums |
32a0392cfe39d4bfdfd961e58211f8c6146b2214b19783365a338d1390f4da42
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 15, 2026.
Transparency logRelease files / ib1_directory_cli-0.5.1-py3-none-any.whl
| Download URL | ib1_directory_cli-0.5.1-py3-none-any.whl |
|---|---|
| Size | 17.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
2475340d6f3443e71b94dd24a1ef3844e11c07d77285d8764f40b16ee7350d92
|
|
BLAKE2b-256 checksum How to use checksums |
19737892eb9129fe096fd103c4f5628662de2782890729433ece91afc92d09ca
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 15, 2026.
Transparency logSecurity for ib1-directory-cli 0.5.1
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
Both files in this release have been uploaded with provenance metadata.
Attestation for ib1_directory_cli-0.5.1.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 15, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.