Skip to main content

CLI for the OntologyEngine REST API — build, validate, and run ontology graphs

Project description

ontology-builder-cli

A typed Python CLI for the OntologyEngine REST API. Designed to be driven by agents (Claude Code, scripts, CI) more than by humans, but works fine for both.

What is this

ontology-builder-cli is a thin httpx + Pydantic + Typer wrapper around the OntologyBuilder backend at http://localhost:5286. Every resource the BE exposes (projects, nodes, edges, routing rules, assertions, validation, runs) has a corresponding command group, and every wire-format quirk (camelCase, int-encoded enums, JSON-string fields, discriminated condition trees) is hidden behind named flags and string enum choices.

There is no authentication today — the BE has no auth scheme registered. Run ontology-cli auth check to verify this against your environment.

Install

From PyPI

pip install ontology-builder-cli
# or
uv add ontology-builder-cli

From source

cd OntologyBuilderSkills
uv sync
uv run ontology-cli --help

uv creates a .venv in the project root. Use uv run ontology-cli ... or activate the venv directly.

Configuration

variable default meaning
ONTOLOGY_API_URL http://localhost:5286 Base URL of the BE.
--base-url flag (env or default) Per-invocation override.

Output formats

Every read or write command supports --json. Without it, the CLI prints a Rich panel/table for humans. With it, you get raw JSON to stdout — that is the form agents and scripts should use:

PID=$(uv run ontology-cli project create --name demo --json | jq -r .id)

Errors

API errors are caught and printed as HTTP <status> <method> <url> followed by the BE's code and message (when present). Exit code is 1 for 4xx/5xx, 0 for success, 2 for the validate command when error-severity issues exist.

The BE returns stable string error codes you can branch on:

  • Routing-rule conditions: CONDITION_UNKNOWN_FIELD, CONDITION_OPERATOR_NOT_SUPPORTED, CONDITION_VALUE_SHAPE_MISMATCH, CONDITION_VALUE_TYPE_MISMATCH, CONDITION_EMPTY_GROUP, CONDITION_NESTING_TOO_DEEP.
  • Output value rules: OUTPUT_VALUE_EMPTY_RULE, OUTPUT_VALUE_MISSING_DEFAULT, OUTPUT_VALUE_DEFAULT_NOT_LAST, OUTPUT_VALUE_TYPE_MISMATCH, OUTPUT_VALUE_CONDITION_INVALID.
  • Assertions: ASSERTION_EXPECTATIONS_CONFLICT (terminal + coverage expectations combined), ASSERTION_PATH_NODE_NOT_FOUND (unknown node id in expectedPath), ASSERTION_EXPECTED_OUTPUT_UNKNOWN_FIELD (node or output name in expectedNodeOutputs not declared in the project).
  • Nodes: DUPLICATE_IO_NAME (two inputs or two outputs on the same node share a name).
  • Runs: RUN_BLOCKED_BY_STATIC_ERRORS, RUN_NO_ASSERTIONS, RUN_NO_ENTRY, RUN_AMBIGUOUS_ENTRY.
  • Validation issue codes (returned in validate results, not as errors): EDGE_INTEGRITY, REFERENCE_INTEGRITY (rule's target node has no edge from the source — common when modelling error routes; create a sink node and an edge first), ROUTING_COMPLETENESS, UNREACHABLE_NODE, CYCLE_NO_EXIT, CONDITION_INTEGRITY.

Command map

ontology-cli
├── blueprint compile                write a .ont YAML, compile + import (preferred for new graphs)
├── auth check                       probe whether auth is enforced
├── project list / get / create / patch / delete / export / import
├── node    list / get / create / delete         (per project)
├── edge    list / create / delete               (per project)
├── rule    list / create / delete               (per node)
├── assertion list / create / delete             (per project)
├── imports list / get / cancel                  (project import jobs)
├── run     start / list / get                   (per project)
└── validate                                     (per project)

Use --help on any subcommand to see flags. Every command that takes project-scoped IDs takes them as positional arguments in the order they appear in the URL path.

Quickstart: build an ontology from a .ont blueprint (preferred)

The blueprint workflow is the recommended path for creating new ontologies — especially for AI agents. You write one YAML file with human-readable names, no UUIDs, and the CLI handles ID generation, expression parsing, and upload in a single command.

cat > auth_flow.ont <<'EOF'
name: AuthFlow

nodes:
  - name: entry
    inputs:
      - {name: user_type, type: string, values: [admin, guest]}
  - name: dashboard
  - name: public_view

edges:
  - {from: entry, to: dashboard,   label: to admin}
  - {from: entry, to: public_view, label: to guest}

rules:
  - {node: entry, to: dashboard,   when: "user_type == 'admin'"}
  - {node: entry, to: public_view, default: true}

assertions:
  - {name: admin, given: {user_type: admin}, expect: dashboard}
  - {name: guest, given: {user_type: guest}, expect: public_view}
EOF

uv run ontology-cli blueprint compile auth_flow.ont --import

This compiles the YAML to a valid .ob, posts it to the BE, polls until the import completes, and prints the new projectId. See the build-ontology skill in skills/build-ontology/SKILL.md for the full .ont reference (expressions, error routes, assertion semantics).

Advanced: build an ontology by individual REST calls

If you need to update an existing project, or your tooling can't write files, the imperative path is still available. The pattern is: create project → create nodes → create edges → create rules → create assertions → validate → run.

# 1. Project
PID=$(uv run ontology-cli project create --name "auth-flow" --json | jq -r .id)

# 2. Two nodes. The first declares an input we'll branch on.
cat > inputs.json <<'EOF'
[{"name":"user_type","type":"string","required":true,"values":["admin","guest"]}]
EOF
cat > outputs.json <<'EOF'
[{"name":"route","type":"string","required":true}]
EOF

CLASSIFY=$(uv run ontology-cli node create $PID \
  --label "Classify" --inputs @inputs.json --outputs @outputs.json --json | jq -r .id)
DASHBOARD=$(uv run ontology-cli node create $PID --label "Dashboard" --json | jq -r .id)

# 3. Edge connecting them.
EDGE=$(uv run ontology-cli edge create $PID --source $CLASSIFY --target $DASHBOARD --json \
  | jq -r .id)

# 4. Routing rule: when user_type == "admin", route to Dashboard.
#    The fieldId is the input id from the Classify node — read it back:
FIELD=$(uv run ontology-cli node get $PID $CLASSIFY --json | jq -r '.inputs[0].id')

cat > condition.json <<EOF
{"kind":"clause","fieldId":"$FIELD","compare":0,"value":{"type":"literal","value":"admin"}}
EOF

uv run ontology-cli rule create $PID $CLASSIFY \
  --target $DASHBOARD --condition @condition.json --order 0 --json

# 5. Assertions: given user_type=admin, expect the run to reach Dashboard.
cat > given.json <<'EOF'
{"user_type":"admin"}
EOF

# Terminal expectation — assert the run ends at Dashboard.
uv run ontology-cli assertion create $PID \
  --name "admin -> dashboard" --scope e2e \
  --given @given.json --expected-target-node $DASHBOARD --json

# Coverage expectation — assert the path and what Dashboard produced.
cat > path.json <<EOF
["$DASHBOARD"]
EOF
cat > outputs.json <<EOF
{"$DASHBOARD": {"route": "admin"}}
EOF

uv run ontology-cli assertion create $PID \
  --name "admin path + outputs" --scope e2e \
  --given @given.json --expected-path @path.json --expected-node-outputs @outputs.json --json

# 6. Validate, then run.
uv run ontology-cli validate $PID --json
uv run ontology-cli run start $PID --json

Notes on PowerShell: avoid passing JSON as an inline string — PowerShell mangles double quotes. Always use @file.json for --inputs, --outputs, --condition, --given, --expected-path, --expected-node-outputs, and --expected-side-effects. To capture an id from --json output in PowerShell:

$pid = (uv run ontology-cli project create --name demo --json | ConvertFrom-Json).id

Modelling error routes

--error-route does not create a new sink — it only marks a rule as fired by a raised error. You still need a real target node with an outbound edge from the source. Create a terminal node per error class (e.g. BadPasswordError), add an edge from the raising node to it, then create the rule with --error-route --error-name "bad_password" --target $ERR_NODE. Otherwise validate returns REFERENCE_INTEGRITY.

Bulk create via import

To seed a whole project at once, assemble an .ob file (raw UTF-8 JSON matching ExportDocumentV1, documented in BE-done.md § Project Export) and upload it:

# Fire-and-forget — returns the importJobId immediately.
uv run ontology-cli project import path/to/project.ob --name "optional-rename"

# Wait for the job to finish and print the final header + logs.
uv run ontology-cli project import path/to/project.ob --wait --json

Inspect or cancel jobs through ontology-cli imports:

uv run ontology-cli imports list --json
uv run ontology-cli imports list --project-id <pid> --json
uv run ontology-cli imports get <jobId> --json
uv run ontology-cli imports cancel <jobId>

To round-trip an existing project, project export <id> writes a .ob file you can re-import. Pass --out to override the filename.

Known gotchas

  • --expected-target-node conflicts with --expected-path / --expected-node-outputs. Combining them on the same assertion returns ASSERTION_EXPECTATIONS_CONFLICT. Use one or the other, or omit --expected-target-node when using coverage expectations. --expected-error can combine freely with either style.
  • --given scoped overrides for downstream stubs. For E2E assertions, keys of the form "NodeLabel.outputName" in the Given JSON inject a fixed output value when the engine reaches that node — no separate stub command needed. The BE warns with NODE_LABEL_NOT_UNIQUE if two nodes share a label and a scoped key is ambiguous.
  • Node-scoped assertions still enter at the graph's entry node. --target-node only narrows what is asserted; the engine still walks from the entry. Your --given payload must include the entry node's inputs even when targeting a downstream node.
  • rule delete is delete <project-id> <node-id> <rule-id> (three positional args, no --json). It is the only resource where delete takes a parent id beyond the project.

Reference: condition trees

Routing rules and (per-output) value rules use the same discriminated tree:

// Single comparison
{ "kind": "clause", "fieldId": "<input-uuid>", "compare": 0,
  "value": { "type": "literal", "value": "admin" } }

// AND/OR group
{ "kind": "group", "op": 0, "children": [<clause>, <clause>] }

op: 0 = AND, 1 = OR.

compare codes:

code name requires value valid types
0 eq literal any
1 neq literal any
2 gt literal number, date
3 gte literal number, date
4 lt literal number, date
5 lte literal number, date
6 contains literal string
7 startsWith literal string
8 endsWith literal string
9 isEmpty (omit value) string, array
10 isNotEmpty (omit value) string, array
11 isNull (omit value) any
12 isNotNull (omit value) any
13 in list any
14 notIn list any

Max nesting depth is 4. Empty groups are rejected.

Reference: enums on input

The CLI accepts these as named strings (lowercase). They map to the BE's int wire format internally.

flag choices
node create --mode simulated (default), implemented
assertion --scope e2e (default), node (coming soon)
rule --async-behavior immediate (default), delayed, conditional

Reference: enums in responses

Responses contain bare ints. Decode them with the table from BE-done.md (also mirrored in src/ontology_builder_cli/enums.py):

  • node.mode: 0 simulated, 1 implemented
  • assertion.scope: 0 node, 1 e2e
  • rule.asyncBehavior: 0 immediate, 1 delayed, 2 conditional
  • validation issue.severity: 0 error, 1 warning
  • run.status: 0 running, 1 passed, 2 failed, 3 errored
  • runStep.kind: 0 assertionStarted, 1 nodeEntered, 2 nodeExited, 3 edgeTraversed, 4 assertionFinished, 5 error
  • runStep.payload[outcome] (when kind=4): 0 passed, 1 failed, 2 errored

Project layout

OntologyCli/
├── pyproject.toml
├── README.md
└── src/ontology_builder_cli/
    ├── __init__.py
    ├── cli.py              # root Typer app + auth probe
    ├── client.py           # httpx wrapper, one method per BE route
    ├── enums.py            # IntEnums mirroring the BE wire format
    ├── models.py           # Pydantic models, camelCase aliases
    ├── _io.py              # printing, JSON loading, error decorator
    └── commands/
        ├── projects.py
        ├── nodes.py
        ├── edges.py
        ├── rules.py
        ├── assertions.py
        └── runs.py

Each file is small enough to read at a glance. Wire-format quirks live in exactly one place (models.py aliases, enums.py ints), so the CLI surface stays clean.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

ontology_builder_cli-0.0.1.tar.gz (24.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

ontology_builder_cli-0.0.1-py3-none-any.whl (33.4 kB view details)

Uploaded Python 3

File details

Details for the file ontology_builder_cli-0.0.1.tar.gz.

File metadata

  • Download URL: ontology_builder_cli-0.0.1.tar.gz
  • Upload date:
  • Size: 24.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for ontology_builder_cli-0.0.1.tar.gz
Algorithm Hash digest
SHA256 2700a27d92211ae70840ec1748226c5e86573aebc991eebfa7c38bc65b7c7b8e
MD5 ce1563af7c4069407b4d3c1ac22c6c47
BLAKE2b-256 b28ff18cd8163b4b26021850785d565a43f0118a599577d0a261822dabcc59b0

See more details on using hashes here.

Provenance

The following attestation bundles were made for ontology_builder_cli-0.0.1.tar.gz:

Publisher: publish.yml on radumocanu1/OntologyBuilderSkills

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file ontology_builder_cli-0.0.1-py3-none-any.whl.

File metadata

File hashes

Hashes for ontology_builder_cli-0.0.1-py3-none-any.whl
Algorithm Hash digest
SHA256 e40397bb00d553189770bd65846ecb8c652dc5e391dd4a3c47239791365b760b
MD5 c28a29a5ae2dfc138e0770d7ffa80fa6
BLAKE2b-256 ea9f80ec446092b371c6e3b7fcfd09dcd8a3f32b06f748e6cb3dd72f02c16683

See more details on using hashes here.

Provenance

The following attestation bundles were made for ontology_builder_cli-0.0.1-py3-none-any.whl:

Publisher: publish.yml on radumocanu1/OntologyBuilderSkills

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page