CLI
A single static binary that validates HL7v2 messages and FHIR resources against your Interoperall specs from a terminal, a Makefile, or a CI pipeline. Same auth, same engine, same results as the Bridge agent.
Overview
The CLI is built for short-lived, exit-code-driven use cases — the opposite of the long-running MLLP agent. Pipe HL7 into it, get a JSON or JUnit report out, and let CI decide pass/fail.
# Validate one file interoperall validate --spec adt-strict ./message.hl7 # Validate many files (shell expansion) interoperall validate --spec adt-strict test/*.hl7 # Pipe from another process cat msg.hl7 | interoperall validate --spec adt-strict # Get JUnit XML for your CI dashboard interoperall validate --spec adt-strict test/*.hl7 --reporter junit > results.xml
Install
One-line installer (macOS / Linux)
curl -fsSL https://interoperall.com/install/cli | bash
Detects your OS and architecture, downloads the right binary, drops it into /usr/local/bin (or$INTEROPERALL_INSTALL_DIR), and chmods it executable.
Direct download
The same binaries are available individually:
Available at https://interoperall.com/api/downloads/cli/<filename>. SHA-256 checksums are at the same path under SHA256SUMS.txt.
Authenticate
On a dev machine, just run interoperall login — it prints a URL and an 8-character code:
$ interoperall login
Open this URL in your browser:
https://interoperall.com/connect?code=K7T2-NP3X
Or visit https://interoperall.com/connect and enter:
K7T2-NP3X
Waiting for authorization...Click Authorize on the page (you must be logged into Interoperall there) and the CLI finishes setup automatically. The token is saved to ~/.interoperall/config.toml with mode 0600. Future interoperall commands just work.
Token resolution priority on every command, in order:
INTEROPERALL_TOKEN in your repo secrets, and skip login entirely. The CLI picks the env var up automatically.validate
interoperall validate [files...]
--spec <slug[@version]> which spec to validate against (required)
Append @1.2.3 to pin to a specific published version
instead of the current production release.
--reporter <fmt> pretty | json | junit | github | auto (default: auto)
--token <iob_…> override env / config token
--api-base <url> override API URL
--concurrency <n> max in-flight requests (default 4)
--fhir treat input as FHIR JSON instead of HL7v2Files are passed as positional args. If none are given, the CLI reads a single message from stdin.
Pinning a specific version
Append @<version> to the spec slug to validate against a specific published release instead of whatever is currently in production. Useful when you have a vendor agreement on a particular version, or when you want CI to fail loudly the moment a spec gets bumped under you.
# Always tracks current production interoperall validate --spec adt-strict test/*.hl7 # Pinned — never moves unless you change this line interoperall validate --spec adt-strict@1.0.0 test/*.hl7
The spec's share portal has a Version historytab showing all published versions and their release notes — that's where vendors discover which versions exist.
Glob expansion is handled by your shell — the CLI receives whatever paths the shell expanded. For complex patterns:
# Recursively find HL7 messages, then validate find fixtures -name '*.hl7' -print0 | xargs -0 interoperall validate --spec adt
FHIR mode
Pass --fhir to send the file body as a FHIR JSON resource (Content-Type application/fhir+json) instead of HL7v2. The CLI parses the JSON before sending — invalid JSON exits with parse-error.
Concurrency
The CLI fans out up to --concurrency in-flight requests (default 4, max 16). For batches of hundreds of files this is the single biggest perf knob.
specs
interoperall specs [--json]
Lists every spec your token can see. Default output is a small table; pass --json for piping into scripts.
doctor
interoperall doctor
Walks through your setup, one check per line, and exits non-zero if anything fails. Run this when something looks off — it's usually faster than reading the error message of whatever broke.
✓ token configured (prefix=iob_a1b2c3… api=https://interoperall.com) ✓ heartbeat succeeds (server_time=2026-05-20T10:00:00.000Z) ✓ agent version compatibility (server minimum=0.1.0) ✓ spec listing (3 spec(s) visible)
login
interoperall login # device-authorization flow (recommended) interoperall login --token iob_… # paste a token you already have
With no arguments, runs the device-authorization flow: the CLI prints a URL and a short code, you approve it in your browser, and the CLI saves the resulting token to ~/.interoperall/config.toml with mode 0600. You never see or type the token yourself.
Pass --token iob_… to skip the device flow and use a token you already have (e.g. one issued in Settings for an agent on another machine). With this form, the token is verified with a heartbeat call before being saved; pass --no-verify to skip (useful when offline or against a self-hosted instance).
Reporters
Pick the output format that fits your environment. Defaults to auto, which picks intelligently based on TTY and CI env vars.
pretty
✓ test/adt-01.hl7 PASS (12 rules, 23ms)
✗ test/adt-02.hl7 FAIL (12 rules, 25ms)
⨯ PID^3 error PID-3 must be present
⚠ PV1^2 warning PV1-2 should be one of [I, O, E]
────────────────────────────────────────────────────────────
FAIL · 2 files 1 pass 1 fail · 48msjson
Stable shape — bump report_version when it changes:
{
"report_version": 1,
"total_ms": 48,
"counts": { "total": 2, "passed": 1, "failed": 1, "warnings": 0, "errored": 0 },
"files": [
{ "file": "test/adt-01.hl7", "spec": "adt-strict",
"status": "pass", "duration_ms": 23,
"score": 100, "summary": { ... }, "failed_rules": [] },
{ "file": "test/adt-02.hl7", "spec": "adt-strict",
"status": "fail", "duration_ms": 25,
"score": 75, "summary": { ... },
"failed_rules": [ { "ruleId": "...", "severity": "error", ... } ] }
]
}junit
Surefire-compatible XML. Most CI providers auto-pick up a file at a known path (e.g. junit.xml) and render a test results UI:
interoperall validate --spec adt-strict test/*.hl7 --reporter junit > junit.xml
github
Emits GitHub Actions workflow commands so each rule failure shows up as an inline annotation on the PR diff:
::error file=test/adt-02.hl7,title=PID^3::PID-3 must be present ::warning file=test/adt-02.hl7,title=PV1^2::PV1-2 should be one of [I, O, E]
Exit codes
CI/CD integration
The CLI was designed around CI. A few patterns that work well:
GitHub Actions (manual install)
name: Validate HL7
on: [pull_request]
jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: curl -fsSL https://interoperall.com/install/cli | bash
- run: interoperall validate --spec adt-strict test/fixtures/*.hl7
env:
INTEROPERALL_TOKEN: ${{ secrets.INTEROPERALL_TOKEN }}Jenkins
stage('Validate HL7') {
steps {
sh 'curl -fsSL https://interoperall.com/install/cli | bash'
withCredentials([string(credentialsId: 'interoperall-token', variable: 'INTEROPERALL_TOKEN')]) {
sh 'interoperall validate --spec adt-strict test/*.hl7 --reporter junit > junit.xml'
}
}
post {
always {
junit 'junit.xml'
}
}
}GitLab CI
validate_hl7:
stage: test
image: alpine:latest
before_script:
- apk add curl bash
- curl -fsSL https://interoperall.com/install/cli | bash
script:
- interoperall validate --spec adt-strict test/*.hl7 --reporter junit > junit.xml
artifacts:
when: always
reports:
junit: junit.xmlGitHub Action
We ship a composite action that bundles install + invocation into one step. Inline failures appear directly on the PR diff.
- name: Validate HL7 fixtures
uses: interoperall/Interoperall/.github/actions/validate-hl7@main
with:
token: ${{ secrets.INTEROPERALL_TOKEN }}
spec: adt-strict
files: |
test/messages/*.hl7
fixtures/**/*.hl7
fhir: false # set true to send FHIR JSON
reporter: github # default — PR-diff annotationsInputs:
Environment variables
Troubleshooting
"no token configured" (exit 2)
The CLI couldn't find a token via --token, env var, or config file. In CI, double-check the secret is named exactly INTEROPERALL_TOKEN and is set on the job step.
"no files given and stdin was empty"
Globs may have expanded to nothing. Try running the glob in the shell first (echo test/*.hl7) to see what your shell sees.
All requests return 401 / token revoked
Tokens are revocable. Generate a new one in Settings → HL7 Bridge agent, update your secrets, and re-run.
429 rate-limit errors in CI
The agent endpoint is rate-limited to 600 requests/min per token. If you're hitting that, either lower --concurrency or batch validations into fewer test files.