Developer tools
The iohr command line
Install iohr on Linux, macOS or Windows, check what you installed, and find every command.
iohr signs you in, keeps each account you use as a profile, manages API tokens, makes
authenticated calls, generates clients and installs extensions. It is one binary, open source
in inorbithr/sdk, and talks only to
api.inorbit.hr and auth.inorbit.hr (and to the extension registry, only when you install
an extension). No telemetry, no update check.
The current release is 0.1.0-alpha.11, a pre-release: commands and output can still change before 1.0.
Install
sudo install -d -m 0755 /etc/apt/keyrings
curl -fsSL https://packages.inorbit.hr/iohr.gpg | sudo tee /etc/apt/keyrings/iohr.gpg >/dev/null
sudo tee /etc/apt/sources.list.d/iohr.sources >/dev/null <<'SOURCES'
Types: deb
URIs: https://packages.inorbit.hr/apt
Suites: stable
Components: main
Signed-By: /etc/apt/keyrings/iohr.gpg
SOURCES
sudo apt update && sudo apt install iohr- APT serves
amd64andarm64. Upgrades come withapt upgradelike any other package. - Homebrew uses the tap inorbithr/homebrew-tap;
brew install inorbithr/tap/iohradds it on first use. - winget is not available yet. The package,
InOrbit.iohr, is submitted to winget's catalogue from the first stable release; until then use the PowerShell installer or the.msifrom the release. - The installers (install.sh,
install.ps1) are short
enough to read before you pipe them to a shell. Each downloads the archive for your machine
from the GitHub release, refuses it unless its SHA-256 matches the release's
SHA256SUMS, checks its build attestation when the GitHub CLI is installed and signed in, and copies one binary into your user directory. - Every release also has plain archives (Linux musl, macOS, Windows; x86-64 and arm64), a
.deband an.msi, each with a CycloneDX SBOM: github.com/inorbithr/sdk/releases.
Check what you installed
The APT repository is signed with a key used for nothing else:
gpg --show-keys /etc/apt/keyrings/iohr.gpg| Key | Fingerprint |
|---|---|
| Primary (certifies, kept offline) | 5FF6 7AF3 D50A 6B06 FFE6 EA8A FFA5 11CF 585B F28D |
| Signing subkey (signs the repository, expires 2028-10-01) | 1725 799F E6C8 0810 9671 0D42 E7B1 639B 4435 8981 |
Every file on a release has a build provenance attestation from the SDK repository's release workflow:
gh release download iohr/v0.1.0-alpha.11 --repo inorbithr/sdk \
--pattern 'iohr-*-x86_64-unknown-linux-musl.tar.gz' --pattern SHA256SUMS
sha256sum --check --ignore-missing SHA256SUMS
gh attestation verify iohr-0.1.0-alpha.11-x86_64-unknown-linux-musl.tar.gz --repo inorbithr/sdkIf a check fails, do not use the file; report it privately as the repository's SECURITY.md describes.
First steps
iohr login # your browser, or a link and a code over SSH
iohr whoami
iohr api GET /v1/meSigning in, profiles, API tokens and CI use are in the public guide: Command line.
Commands
| Command | What it does |
|---|---|
iohr login [--web | --device] | Sign in and add a profile |
iohr login --with-token | Read an API token from stdin and add a profile |
iohr logout | Revoke the session and forget the profile on this machine |
iohr profile list | use | show | The profiles here and the default one |
iohr profile account NAME ID|SLUG | Point a signed-in profile at one of its teams |
iohr whoami | Subject, account, plan, scopes and expiry of the active profile |
iohr accounts list | The accounts the credential can see |
iohr token create | list | revoke | API tokens for an account (a signed-in person only) |
iohr api <METHOD> <PATH> | One call; -f k=v, -F k=json, --input file; --all walks every page of a list |
iohr openapi pull | The OpenAPI document this credential sees, to openapi.json |
iohr sdk generate --lang … --for P… --out DIR | A client cut to what the profiles may call (guide) |
iohr sdk check [--files] | Exit 1 with what moved when that cut changed; for CI |
iohr sdk add [LANG] [--version V] [--dry-run] | Add the published SDK to the project here with its own package manager (below) |
iohr sdk config [--profile NAME] | What an SDK's load would resolve here, secrets redacted |
iohr domains add | verify | confirm | list | rm | Prove the account controls a domain with one DNS TXT record (Domains) |
iohr connectors list [--category C] | show ID | The catalogue of apps a connection can be made from (Connections) |
iohr connections list | show | add | test | history | pause | resume | rename | delete | reconnect | The account's connections: connect an app with a key or by signing in at the provider |
iohr connections grant | grants | revoke-grant | Grant a product, an API key or an agent named actions of a connection until an expiry |
iohr ext install | list | upgrade | remove | verify | sync | Extensions: install, verify and pin them; iohr <name> … runs one |
iohr config set | get | unset | ext.registry (a mirror) and ext.trusted_keys |
iohr lab check [PATH…] | Check RFCs and studies offline |
iohr completion <shell> | A completion script for bash, zsh, fish, elvish or PowerShell |
Every command takes --profile (or IOHR_PROFILE), --json and --verbose. --verbose
prints method, path, status, time and request id on stderr, never a header, a query value or a
body. Exit codes: 0 success, 1 the call failed, 2 a usage error, 3 not signed in or the
token was refused, 4 forbidden by scope, role or plan.
Add the SDK to a project
iohr sdk add # the language and the package manager from the project's files
iohr sdk add go --version 0.2.2 # that release
iohr sdk add --dry-run # print the command, run nothingLANG is rust, typescript (ts, js), python (py) or go. Without it, iohr
looks for the project from the current directory up to the repository root (Cargo.toml,
package.json or deno.json, pyproject.toml, requirements.txt or a Python lock file,
go.mod); several or none is a usage error (exit 2) that names the commands. The package
manager is the one the project already uses:
| Project | Command |
|---|---|
Rust (needs Cargo.toml) | cargo add inorbithr |
pnpm-lock.yaml, yarn.lock, bun.lock | pnpm add, yarn add, bun add @inorbithr/sdk |
deno.json without package.json | deno add jsr:@inorbithr/sdk |
| other JavaScript and TypeScript | npm install @inorbithr/sdk (or the packageManager field's) |
uv.lock, poetry.lock, pdm.lock | uv add, poetry add, pdm add inorbithr |
| other Python, in an active virtualenv | <venv>/bin/python -m pip install inorbithr |
Go (needs go.mod) | go get github.com/inorbithr/sdk/go@latest |
Lock files are looked for up to the repository root, so a workspace member uses its
workspace's manager. Without a virtualenv and a uv, poetry or pdm lock, iohr installs
nothing into a system Python (exit 2) and prints the uv and venv commands instead.
--version installs that release; without it the manager picks the newest. C# and Java
are refused (exit 1): they are not published on NuGet or Maven Central yet.
iohr prints the command first, then runs it as one program with its arguments in the
project directory: no shell, never sudo, the program looked up only in absolute PATH
entries. The exit code is the package manager's. iohr contacts no host for it; the
package manager reaches its own registry. With --json, the manager's output goes to
stderr and stdout holds one object: lang, manager, dir, command (the argument
vector), dry_run.
Where things are kept
- Profiles:
config.tomlin the platform's config directory (~/.config/iohron Linux,~/Library/Application Support/hr.InOrbit.iohron macOS,%APPDATA%\InOrbit\iohr\configon Windows). No secret is written there. - Secrets: the operating system's credential store (macOS Keychain, Windows Credential
Manager, the Secret Service on Linux). Without one,
--insecure-storagekeeps the token in a file with mode 0600. - Extensions: the platform's data directory (
~/.local/share/iohr/extensionson Linux), owner-only, with the machine'siohr-ext.lock.