This release is a pre-release and may not be stable for production use.
insightfactory-cli
Profile-based authentication CLI for the InsightFactory Interfaces API. It
installs the if-cli command: browser OAuth login (authorization-code + PKCE),
token refresh, and authenticated API calls, with profiles stored in
~/.insightfactory in the same layout as the Node @insightfactory-ai/if-cli
so the two implementations can share a config directory.
This is the production Python CLI, published to public PyPI. Python 3.10 or newer is required.
Install
uv tool install insightfactory-cli # persistent install, on PATH
uvx insightfactory-cli profiles # or zero-install, run-once
uv tool upgrade insightfactory-cli # updates
uv fetches a managed Python automatically if the machine lacks one. Fallbacks:
pipx install insightfactory-cli
pip install insightfactory-cli
Develop-branch builds are published as PEP 440 .devN pre-releases. Install the
bleeding edge with:
pip install --pre insightfactory-cli
uv tool install --prerelease allow insightfactory-cli
PEP 440 orders 1.0.0.devN before 1.0.0, so a dependency spec of
insightfactory-cli>=1.0.0 does not match a develop-channel dev build.
An in-process consumer that wants those builds must use a pre-release-bearing
spec such as insightfactory-cli>=1.0.0.dev0, which matches both .devN
builds and the final 1.0.0 release.
Usage
# Create a profile and authenticate through the browser.
if-cli login -p example-dev --host https://factory.example
# Inspect profiles and cached-token status. Statuses are colour-coded on a TTY
# (green valid, yellow refreshable-but-expired, red missing or broken); set
# NO_COLOR=1 to disable or FORCE_COLOR=1 to keep colour when piping.
if-cli profiles
if-cli profiles --json
# Read a single non-secret profile value for scripting.
if-cli config get host -p example-dev
# Print a valid token, refreshing it when a refresh token is available.
if-cli token -p example-dev
if-cli token -p example-dev --env
if-cli token -p example-dev --env-name INSIGHTFACTORY_ACCESS_TOKEN_DEV
# Make an authenticated API request.
if-cli api -p example-dev /api/agent-projects
if-cli api -p example-dev -X POST -d '{"name":"example"}' /api/example
# Wait longer than the 30-second default for a long-running endpoint.
if-cli api -p example-dev --timeout 300 -X PUT -d '{"productionLineCodes":["PL001"]}' \
/api/orchestration/run
# Discover API routes from the factory's OpenAPI document.
if-cli api routes -p example-dev
if-cli api routes -p example-dev agent-projects
if-cli api describe -p example-dev GET /api/agent-projects/{id}
# Remove the cached credential for a profile.
if-cli logout -p example-dev
# Fallback for factories where browser OAuth is not available.
if-cli set-token -p example-dev
if-cli --version
Profile selection uses -p, then INSIGHTFACTORY_CONFIG_PROFILE, then
[DEFAULT]. Route discovery reads {host}/swagger/v1/swagger.json and does
not require a login. Authenticated API requests are restricted to the selected
factory origin so a profile token cannot be forwarded to another host. Profile
hosts must be bare origins rather than URLs containing application path
prefixes.
Requests time out after 30 seconds by default. Raise the deadline per
invocation with --timeout <seconds>, or for a whole session with
INSIGHTFACTORY_REQUEST_TIMEOUT; the flag wins over the environment variable,
and both are validated before the command touches the network. There is no
upper bound, because the right ceiling depends on the endpoint.
Both apply to the API request itself. The OAuth discovery and token-refresh
round trips keep the 30-second default, so if-cli token and in-process callers
of if_cli.oauth.get_valid_token always have a bounded wait that no ambient
environment value can redefine.
A timeout is a client-side deadline, not a rejection: the factory may have
accepted and completed the request after if-cli gave up. Re-issuing a
non-idempotent call (POST, PUT, PATCH, DELETE) can therefore apply it
twice, so the timeout message for those methods says to confirm the current
state before retrying rather than repeating the call.
Override the config directory with INSIGHTFACTORY_CONFIG_DIR (useful in tests
and CI). The default is ~/.insightfactory.
The request method goes in -X; if-cli api takes exactly one positional
argument and reads it as the path. A curl-shaped if-cli api GET /api/schedules
therefore parses GET as the path — write if-cli api -X GET /api/schedules
instead. The CLI names the misplaced verb rather than reporting a problem with
/api/schedules.
On Git Bash (MSYS2) on Windows, path conversion rewrites a leading-slash
argument such as /api/agent-projects into a Windows path. Prefix the command
with MSYS_NO_PATHCONV=1:
MSYS_NO_PATHCONV=1 if-cli api -p example-dev /api/agent-projects
Scripting against profiles
profiles --json and config get are the supported machine-readable
interfaces; the padded profiles columns are for humans and are not a
contract, and neither is the layout of ~/.insightfactory/config.
if-cli profiles --json prints an array — one entry per configured profile, in
file order — of name, host, and token:
[
{
"name": "example-dev",
"host": "https://factory.example",
"token": { "status": "valid", "expires_at": 1785918336, "refreshable": true }
},
{ "name": "other", "host": "https://other.factory.example", "token": { "status": "none" } }
]
token.status is valid, expired, none, or unknown; expires_at and
refreshable are present only when a cached token exists. valid means
if-cli token will hand back the cached token as-is, so a token inside the
60-second slack window that command refreshes within is reported as expired —
use the raw expires_at if you need the literal expiry instant instead. A
profile that cannot be resolved has a host of null (or its raw configured
value) and a top-level error describing the problem, and does not stop the
other profiles from being listed; token.error is set only when the token
cache itself could not be read.
if-cli config get <key> -p <profile> prints one newline-terminated value and
exits non-zero if the profile cannot be resolved, or the key is not configured
within it. A profile with no host cannot be resolved at all, so every key on it
fails, not just host. A key present but empty (client_id =) counts as not
configured:
curl -H "Authorization: Bearer $(if-cli token -p example-dev)" \
"$(if-cli config get host -p example-dev)/api/agent-projects"
The readable keys are host, audience, callback_port, client_id, and
organization — all non-secret, and resolved the same way the CLI itself
resolves them, so audience and callback_port return their defaults when the
profile omits them. Tokens are deliberately not readable this way; use
if-cli token.
Programmatic API
insightfactory-cli may be imported in-process as a library to resolve a
profile to a factory host and a fresh access token. These four symbols are a
supported programmatic surface for in-process consumers:
if_cli.config.load_configif_cli.config.get_profileif_cli.oauth.get_valid_tokenif_cli.runtime.CliError
They raise CliError on failure (never SystemExit or sys.exit), never
write to stdout, never launch a browser or block on interactive input, and use
only bounded waits. Changing or removing any of them is a breaking change and
requires a major version bump.
How authentication works
- Profiles are stored in
~/.insightfactory/config, one per customer/environment. - The profile file is managed by the CLI and is regenerated on updates; comments and empty sections are not preserved.
- Tokens are cached by host in
~/.insightfactory/token-cache.jsonwith file mode0600. - The configuration directory is
0700; configuration and cache updates are atomic. - Remote factory, authorization, and token endpoints must use HTTPS. HTTP is accepted only for loopback development.
- Login discovers OAuth metadata from
{host}/.well-known/oauth-authorization-server. - Authorization uses PKCE through the factory
/authorizeproxy with a loopback-only (127.0.0.1) callback. The CLI is a public OAuth client: the client ID is read from the factory's discovery document at runtime (no client secret).
Development
uv sync
uv run pytest
uv run ruff check .
uv run ty check
Smoke-test against a throwaway config directory, never ~/.insightfactory:
uv run if-cli --help
uv run if-cli --version
INSIGHTFACTORY_CONFIG_DIR=$(mktemp -d) uv run if-cli profiles
Python 3.10 or newer is required. Runtime code is stdlib-only.
Release
A release is cut by pushing a tag, not by merging. Merging to main runs CI and
publishes nothing.
git tag v1.0.1 && git push origin v1.0.1
Verify and build live in the reusable workflow
if_s_insightfactory_cli.yml
in insightfactory-ai/if_sre_github_actions. This repository's
.github/workflows/release.yml keeps only the OIDC publish job, because PyPI
Trusted Publishing is registered for this repo, workflow release.yml, and
environment pypi — a reusable workflow cannot be registered.
A one-time trusted-publisher registration is required on the PyPI project for
that triple. The publish job downloads the dist-release artifact staged by
the reusable workflow and uploads it with pypa/gh-action-pypi-publish.
| Trigger | Published version | PyPI role |
|---|---|---|
Push / merge to develop |
1.0.1.dev{N} |
pre-release (pip install --pre) |
Push of a v* tag |
the version in pyproject.toml, which the tag must match |
latest |
Merge to main |
nothing — CI only | — |
N is github.run_number of the reusable workflow: a per-workflow integer
that goes up on every run and stays the same across re-runs of that run (so a
failed publish can be retried under the same version). It does not depend on
git history or clone depth. After a successful release, bump version in
pyproject.toml on develop so later .devN builds sort after what just
landed; PEP 440 puts 1.0.1.devN before 1.0.1. Because of that ordering, a
dependency spec of insightfactory-cli>=1.0.0 does not match develop-channel
.devN builds; an in-process consumer that wants them must specify a
pre-release-bearing spec such as insightfactory-cli>=1.0.0.dev0 (which also
matches the final 1.0.0 release).
A v* tag whose name does not match pyproject.toml fails before publishing.
The two channels treat an already-published version differently, on purpose:
- Release channel (a tag): publishing fails, naming the fix. A tag is a request to release that version; if it cannot be honoured, the run must say so rather than report success having published nothing. (git also refuses to push a tag that already exists, so this is hard to reach.)
- Dev channel (
develop): publishing is skipped quietly..dev{N}usesgithub.run_number, which is stable across re-runs of one run, so an already-present version there can only mean a re-run of a run that already published — real idempotency, not a swallowed mistake.
This split is why releasing moved off main. While a merge was the trigger, an
already-published version had to be tolerated as a no-op for merges to stay green — so a
merge that released nothing looked exactly like one that released, and a forgotten version
bump shipped nothing silently.
Differences from the Node CLI
Behaviour matches @insightfactory-ai/if-cli except where the platforms
genuinely diverge:
- Unknown-option wording is aligned (
Unknown option '--flag'). Other argparse messages (for example a missing option value) still differ from Node'sutil.parseArgs. - Expiry timestamps in human-readable output use the C-locale
%cformat rather than JavaScriptDate#toLocaleString(). --versionreads the installed package metadata (1.0.0and later) rather than an npmpackage.json.
On-disk profile and token-cache paths, JSON shapes, and file permissions stay compatible with the Node CLI, so you can switch implementations without re-authenticating.
Licence
Copyright 2026 insightfactory.ai. All rights reserved. This package is proprietary and may be used only under a separate written agreement with insightfactory.ai.
Metadata
Release files for insightfactory-cli 1.0.2.dev13
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 | |
|---|---|---|---|---|
| insightfactory_cli-1.0.2.dev13.tar.gz | 62.0 kB | With provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| insightfactory_cli-1.0.2.dev13-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 95.4 kB
Release files / insightfactory_cli-1.0.2.dev13.tar.gz
| Download URL | insightfactory_cli-1.0.2.dev13.tar.gz |
|---|---|
| Size | 62.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
90efd7d674812e52d3a7a96625dd3ec78c8f67aec2267c730f7e536f8d3339ec
|
|
BLAKE2b-256 checksum How to use checksums |
3e24d544e771a1c963eb081d902ba40a3dbc73d9fee65e754c86fee9cacb6b49
|
| 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 1, 2026.
Transparency logRelease files / insightfactory_cli-1.0.2.dev13-py3-none-any.whl
| Download URL | insightfactory_cli-1.0.2.dev13-py3-none-any.whl |
|---|---|
| Size | 33.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
02a510096bdd828062408bb780cd8d4f8ad872e3329b37003c7e918102fd36d2
|
|
BLAKE2b-256 checksum How to use checksums |
96cc9baf812d3569011a24c5ca1be2afc6759f53f4340b8d1f8c1930630d0b81
|
| 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 1, 2026.
Transparency logSecurity for insightfactory-cli 1.0.2.dev13
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
All 2 files in this release have been uploaded with provenance metadata.
Attestation for insightfactory_cli-1.0.2.dev13.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 1, 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.