New · Automation
A CLI for people and AI agents
entihub is not just a thin wrapper around curl. Each major REST API surface has a dedicated subcommand with consistent parameters — exactly what agents and CI need: predictable interface, machine-readable output, and secure sign-in.
What is new and why it fits AI workflows
- One command = one API operation — e.g. list entities, deploy, export a package, query the change log. No URL guessing; agents pick a semantic command from the hierarchy (
entities,packages,permissions, …). - Global
--jsonflag — server response including HTTP status in one JSON object on stdout. Easy parsing without regex over human-oriented text. - Two identity modes: interactive user sign-in (browser + token cache) or service principal via environment variables — ideal for long-running agents and hands-off pipelines.
- Raw
apimode — method, path, query string, and body from file; escape hatch when an agent needs something beyond predefined commands. - Same contract as the UI — the CLI calls the same
/api/v1as the app; no second “source of truth” for business rules.
OpenAPI and agents
Server Swagger/OpenAPI describes schemas and errors. OpenAPI + CLI + --json gives agents a clear map:
what can be called, request body shapes, and how to classify failures via a stable code.
Example workflow
# Instance config and identity
entihub config set --base-url https://your-enti-hub/ \
--tenant-id <tenant> --client-id <app-id>
entihub login
# Verify identity (also useful in scripts after login)
entihub whoami --json
# Agent / CI with service principal: set ENTIHUB_CLIENT_SECRET then e.g.
entihub entities list --json
Complex sample: CI/CD pipeline
End-to-end promotion: build an entity package in CI, gate on health and JSON status, deploy to staging or production with a service principal. Store secrets in your platform (GitHub Actions secrets, Azure DevOps variable groups, etc.).
1. Secrets and variables
ENTIHUB_BASE_URL— e.g.https://mdm.staging.contoso.com(CLI trims a trailing slash).ENTIHUB_TENANT_ID,ENTIHUB_CLIENT_ID,ENTIHUB_CLIENT_SECRET— Entra app registration with API permissions and app roles for MDM admin.ENTIHUB_SCOPE(or a pipeline secret) — OAuth scope for client credentials, typicallyapi://<your-api-app-id>/.default(same idea as interactive sign-in).ENTIHUB_API_KEY— alternative for CI/CD without OAuth. The runner sendsX-API-Key; authorize the API key principal by name in the Permissions UI.
2. Export options JSON (committed to repo)
Example mdm-config/export-package.json — entityStorageKeys are repository keys (often the entity technical name); omit the array to export all entities.
{
"entityStorageKeys": ["Customer", "Vendor", "Region"],
"autoIncludeDependencies": true,
"includePermissions": true,
"includeWebhooks": true,
"includeSeed": false
}
3. GitHub Actions workflow (excerpt)
name: Promote MDM package
on:
push:
branches: [main]
paths: ['mdm-config/**', '.github/workflows/mdm-promote.yml']
jobs:
promote:
runs-on: ubuntu-latest
environment: staging-mdm
steps:
- uses: actions/checkout@v4
- name: Install entihub CLI
run: |
curl -sSL -o entihub.tgz "https://entihub.com/downloads/entihub-linux-x64.tar.gz"
tar xzf entihub.tgz && sudo mv entihub /usr/local/bin/
- name: Smoke — API readiness
env:
ENTIHUB_BASE_URL: ${{ secrets.ENTIHUB_BASE_URL }}
run: |
curl -fsS "$ENTIHUB_BASE_URL/health/ready" | jq -e '.status == "ready" or . == {}'
- name: Export package (ZIP is binary — use curl -o, not entihub --json)
env:
ENTIHUB_BASE_URL: ${{ secrets.ENTIHUB_BASE_URL }}
ENTIHUB_TENANT_ID: ${{ secrets.ENTIHUB_TENANT_ID }}
ENTIHUB_CLIENT_ID: ${{ secrets.ENTIHUB_CLIENT_ID }}
ENTIHUB_CLIENT_SECRET: ${{ secrets.ENTIHUB_CLIENT_SECRET }}
ENTIHUB_SCOPE: ${{ secrets.ENTIHUB_SCOPE }}
run: |
TOKEN=$(curl -sS -X POST "https://login.microsoftonline.com/${ENTIHUB_TENANT_ID}/oauth2/v2.0/token" \
-H "Content-Type: application/x-www-form-urlencoded" \
--data-urlencode "client_id=${ENTIHUB_CLIENT_ID}" \
--data-urlencode "client_secret=${ENTIHUB_CLIENT_SECRET}" \
--data-urlencode "grant_type=client_credentials" \
--data-urlencode "scope=${ENTIHUB_SCOPE}" | jq -er .access_token)
curl -fsS -X POST "${ENTIHUB_BASE_URL}/api/v1/packages/export" \
-H "Authorization: Bearer ${TOKEN}" \
-H "Content-Type: application/json" \
--data-binary @mdm-config/export-package.json \
-o mdm-package.zip
file mdm-package.zip | grep -q ZIP
- name: Export package with API key (alternative to OAuth)
env:
ENTIHUB_BASE_URL: ${{ secrets.ENTIHUB_BASE_URL }}
ENTIHUB_API_KEY: ${{ secrets.ENTIHUB_API_KEY }}
run: |
curl -fsS -X POST "${ENTIHUB_BASE_URL}/api/v1/packages/export" \
-H "X-API-Key: ${ENTIHUB_API_KEY}" \
-H "Content-Type: application/json" \
--data-binary @mdm-config/export-package.json \
-o mdm-package.zip
file mdm-package.zip | grep -q ZIP
- name: Deploy package to target
env:
ENTIHUB_BASE_URL: ${{ secrets.ENTIHUB_BASE_URL }}
ENTIHUB_TENANT_ID: ${{ secrets.ENTIHUB_TENANT_ID }}
ENTIHUB_CLIENT_ID: ${{ secrets.ENTIHUB_CLIENT_ID }}
ENTIHUB_CLIENT_SECRET: ${{ secrets.ENTIHUB_CLIENT_SECRET }}
run: |
entihub packages deploy --file mdm-package.zip \
--overwrite-existing true \
--import-permissions true \
--import-webhooks true \
--import-seed false \
--json > deploy-result.json
jq -e '.statusCode >= 200 and .statusCode < 300' deploy-result.json
jq '.body' deploy-result.json
- name: Post-deploy — list entities
env:
ENTIHUB_BASE_URL: ${{ secrets.ENTIHUB_BASE_URL }}
ENTIHUB_TENANT_ID: ${{ secrets.ENTIHUB_TENANT_ID }}
ENTIHUB_CLIENT_ID: ${{ secrets.ENTIHUB_CLIENT_ID }}
ENTIHUB_CLIENT_SECRET: ${{ secrets.ENTIHUB_CLIENT_SECRET }}
run: entihub entities summary --json | jq '.body | fromjson'
packages/deploy returns JSON — entihub … --json plus jq is a good fit there. packages/export returns application/zip; write the bytes with curl -o (or an HTTP client that saves the raw body). Many teams publish mdm-package.zip as a build artifact between export and deploy jobs, or deploy only after PR approval to main.
Most CLI calls can also use API keys: set ENTIHUB_API_KEY (or pass --api-key) and the CLI will send X-API-Key instead of a Bearer token.
Complex sample: AI agent workflow
Agents need a closed set of tools, deterministic arguments, and structured results. Map each tool to one entihub invocation with --json; parse statusCode and JSON body for the next reasoning step.
1. Tool definitions (conceptual)
mdm_list_entities → entihub entities list --json
mdm_get_entity_yaml → entihub entities yaml <name> --json
mdm_validate_yaml → entihub entities parse-yaml --file <path> --json
mdm_deploy_entity → entihub entities deploy <name> --json
mdm_list_data → entihub entities data list <name> --take 20 --json
mdm_search_data → entihub search data --q <terms> [--take N] [--include-refs] --json
mdm_raw_api → entihub api GET|POST|PUT|DELETE <path> [--body file] [--query k=v]
2. Multi-step task: “Find duplicate customers and report”
The orchestrator runs tools in sequence; each step consumes JSON from the previous step (pseudo-shell).
# Auth option: API key mode (X-API-Key)
export ENTIHUB_API_KEY=<secret>
# Step A — discover entities (agent picks Customer from summary)
entihub entities summary --json > step_a.json
# Agent: parse .body, confirm "Customer" exists
# Step B — fetch sample rows for fuzzy match input
entihub entities data list Customer --take 50 --json > step_b.json
# Agent: build SimilarityRequest JSON from two candidate names, then:
# Step C — call similarity API (file body)
cat > similar-req.json <<'EOF'
{ "values": { "name": "Acme Corp", "code": "ACM-01" } }
EOF
entihub entities data similar Customer --file similar-req.json --json > step_c.json
# Agent: read matches from body; if user asked to fix, propose PUT payload
# Step D — optional write (human-approved or policy-gated)
entihub entities data update Customer <record-guid> --file patch.json --json
3. System prompt fragment (for the model)
You manage EntiHub via the entihub CLI only. Each tool call must use --json.
After every command, parse stdout as JSON: check statusCode (2xx = success).
The "body" field may be a JSON string or raw text — parse accordingly.
Never invent entity names; call mdm_list_entities first.
For bulk changes, prefer packages or bulk import endpoints; do not loop
hundreds of single-row updates without explicit user approval.
Use mdm_raw_api only when no dedicated subcommand exists.
Wire this to your agent runtime (Cursor, Copilot, custom LangGraph node, etc.) by executing the shell command the model emits and feeding the JSON result back into the conversation.
Download CLI packages
Prebuilt entihub binaries are produced by CI for Windows and Ubuntu/Linux.
Use these packages if you do not want to install via dotnet tool.
File names are stable:
entihub-win-x64.zip and entihub-linux-x64.tar.gz.
They are generated in CI artifacts and can be published to this website under /downloads/.
For your team
The CLI ships with the product — suited for DevOps, integrators, and experiments with LLM tools that should run approved operations against the MDM API.
Run entihub --help and per-level help for the full command list.