Developer tools

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 amd64 and arm64. Upgrades come with apt upgrade like any other package.
  • Homebrew uses the tap inorbithr/homebrew-tap; brew install inorbithr/tap/iohr adds 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 .msi from 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 .deb and 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
KeyFingerprint
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/sdk

If 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/me

Signing in, profiles, API tokens and CI use are in the public guide: Command line.

Commands

CommandWhat it does
iohr login [--web | --device]Sign in and add a profile
iohr login --with-tokenRead an API token from stdin and add a profile
iohr logoutRevoke the session and forget the profile on this machine
iohr profile list | use | showThe profiles here and the default one
iohr profile account NAME ID|SLUGPoint a signed-in profile at one of its teams
iohr whoamiSubject, account, plan, scopes and expiry of the active profile
iohr accounts listThe accounts the credential can see
iohr token create | list | revokeAPI 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 pullThe OpenAPI document this credential sees, to openapi.json
iohr sdk generate --lang … --for P… --out DIRA 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 | rmProve the account controls a domain with one DNS TXT record (Domains)
iohr connectors list [--category C] | show IDThe catalogue of apps a connection can be made from (Connections)
iohr connections list | show | add | test | history | pause | resume | rename | delete | reconnectThe account's connections: connect an app with a key or by signing in at the provider
iohr connections grant | grants | revoke-grantGrant a product, an API key or an agent named actions of a connection until an expiry
iohr ext install | list | upgrade | remove | verify | syncExtensions: install, verify and pin them; iohr <name> … runs one
iohr config set | get | unsetext.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 nothing

LANG 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:

ProjectCommand
Rust (needs Cargo.toml)cargo add inorbithr
pnpm-lock.yaml, yarn.lock, bun.lockpnpm add, yarn add, bun add @inorbithr/sdk
deno.json without package.jsondeno add jsr:@inorbithr/sdk
other JavaScript and TypeScriptnpm install @inorbithr/sdk (or the packageManager field's)
uv.lock, poetry.lock, pdm.lockuv 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.toml in the platform's config directory (~/.config/iohr on Linux, ~/Library/Application Support/hr.InOrbit.iohr on macOS, %APPDATA%\InOrbit\iohr\config on 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-storage keeps the token in a file with mode 0600.
  • Extensions: the platform's data directory (~/.local/share/iohr/extensions on Linux), owner-only, with the machine's iohr-ext.lock.