Skip to content
orca-aePublic

About

CLI to manage & interact with resources in Orca Agent Engine

Resources

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

ORK

CLI to manage & interact with resources in Orca Agent Engine

ORK stands for Orca Control: the k is for control, as in kubectl. The binary is ork rather than orca so it never collides with GNOME's Orca screen reader, which installs /usr/bin/orca on most Linux desktops.

ork works with the managed-agents API of an Orca Agent Engine deployment: agents and their versions, sessions and their event streams, environments, vaults and credentials, memory stores, files, skills and triggers. It also covers the policy and pricing extensions, and the resources that only the hosted distribution serves. ork local runs a complete engine on your machine with Docker Compose.

Install

Homebrew (macOS and Linux):

brew install orca-ae/tap/ork

Release archives. Each release has an ork_<tag>_<os>_<arch> archive for Linux, macOS and Windows on amd64 and arm64, and a checksums.txt. Check an archive before you unpack it:

sha256sum --ignore-missing -c checksums.txt   # on macOS: shasum -a 256 --ignore-missing -c checksums.txt

Each archive also carries the license, the notice and the licenses of the third-party code compiled into ork.

Go 1.25 or later:

go install github.com/orca-ae/orca-cli/cmd/ork@latest

Container image: ghcr.io/orca-ae/orca-cli. See Container image.

ork --version prints the installed version.

Maintainers publish through Release Please: merge the Release PR to trigger artifact publication, then merge the Homebrew formula PR. See Publishing a release.

Quick start

Start an engine on this machine, then use it. You need Docker with Compose v2.

LOCAL_DIR="$HOME/.ork-local"
ork local --data-dir "$LOCAL_DIR" start

export ORCA_REGISTRY_URL=http://127.0.0.1:8080
export ORCA_API_KEY="$(cat "$LOCAL_DIR/secrets/workspace-api-key")"
ork agent list

ork local --data-dir "$LOCAL_DIR" stop

Run a local engine describes what the stack contains and how to configure it.

Connect to a deployment

Pass the deployment host root as --registry-url, with no /v1, /v1/registry or /api/v1 suffix: every path resolves relative to the host root. A URL that ends in one of those legacy suffixes still works, and the CLI strips the suffix with a deprecation warning on stderr.

ork authenticates with one of two credentials, which are mutually exclusive:

  • --api-key: a workspace API key, sent as x-api-key. A self-hosted engine, including ork local, issues these.
  • --access-token: an OIDC access token, sent as Authorization: Bearer.
ork --registry-url http://localhost:8080 --api-key "$ORCA_API_KEY" agent list
ork --registry-url https://example.com --access-token "$TOKEN" agent list

Each flag has an environment default: ORCA_REGISTRY_URL, ORCA_API_KEY and ORCA_ACCESS_TOKEN. Help text never prints the credentials.

health, connections, sources, sinks, functions, kafka-connect, packages and agent providers manage resources that only the hosted distribution serves. They require the deployment to advertise the hosted extension group, cloud.sn.io, so a self-hosted engine doesn't have them. Run api-groups to see which API groups a deployment advertises, then api-resources to inspect a group's resources. Discovery is authenticated like the API surfaces it describes:

ork --registry-url https://example.com --access-token "$TOKEN" api-groups
ork --registry-url https://example.com --access-token "$TOKEN" api-resources -o json

ork has no workspace context or interactive connection selection, so pass --connection. --use-connection is reserved for programs that embed these commands and inject a selector.

Managed agents

Create a managed-agent cloud environment with package passthrough by repeating package-manager flags. The CLI sends these values as config.packages; it doesn't install packages locally.

ork --registry-url https://example.com --access-token "$TOKEN" \
  agent environments create --name claude-env \
  --scope account \
  --package-apt git --package-npm typescript --package-pip pytest

Create a managed-agent session with one or more vaults by repeating --vault-id. The CLI sends these values as the API's vault_ids array.

ork --registry-url https://example.com --access-token "$TOKEN" \
  agent sessions create --environment-id env_123 --agent agent_123 \
  --vault-id vlt_123 --title "Investigation"

ork --registry-url https://example.com --access-token "$TOKEN" \
  agent sessions update sess_123 --vault-id vlt_123 --vault-id vlt_456

Send typed session events and parse event streams as SSE. Cursor 0 replays the full transcript. A nonzero cursor is the SSE id: field (the outer .id in the CLI's NDJSON), not the evt_... ID inside data, and replay is inclusive.

ork --registry-url https://example.com --access-token "$TOKEN" \
  agent sessions events send message --session sess_123 --text "Run bash echo MARKER"

ork --registry-url https://example.com --access-token "$TOKEN" \
  agent sessions events stream --session sess_123 --from-cursor 0 \
  --event-delta agent.message --timeout 30s

Memory entries, memory versions, and file content downloads are exposed directly:

ork --registry-url https://example.com --access-token "$TOKEN" \
  agent memory-stores memories create --memory-store mems_123 \
  --path notes/project.md --content "project note"

ork --registry-url https://example.com --access-token "$TOKEN" \
  agent memory-stores memories list --memory-store mems_123 \
  --depth 1 --path-prefix notes/ --view full

ork --registry-url https://example.com --access-token "$TOKEN" \
  agent memory-versions list --memory-store mems_123 \
  --api-key-id key_123 --operation modified --view basic

ork --registry-url https://example.com --access-token "$TOKEN" \
  agent files content file_123 --output-file ./downloaded.txt

ork --registry-url https://example.com --access-token "$TOKEN" \
  agent sessions files content file_456 --session sess_123 --output-file ./session-output.txt

ork --registry-url https://example.com --access-token "$TOKEN" \
  agent sessions files list --session sess_123 --after-id file_123 --limit 100

Agent triggers use the core /v1/triggers API. A self-hosted engine supports cron triggers with SESSION_PER_EVENT; the hosted distribution additionally supports Kafka and Pulsar sources, more session modes, and multiple replicas. The deployment validates unsupported combinations. Trigger session templates use --vault-id, sent as session.vault_ids.

ork --registry-url https://example.com --access-token "$TOKEN" \
  agent triggers create --name daily-trigger --agent agent_123 \
  --source-type cron --session-mode SESSION_PER_EVENT \
  --schedule "0 9 * * *" --timezone Asia/Shanghai --payload "Create the daily report" \
  --environment-id env_123 --vault-id vlt_123

The hosted distribution also accepts --source-type kafka or --source-type pulsar, with --connection plus --topic or --topic-pattern, and supports the SESSION_PER_TOPIC, SESSION_PER_KEY and SHARED session modes.

Session outcomes and immutable skill-version bundles are available through the managed-agent command tree:

ork --registry-url "$REGISTRY_URL" --access-token "$TOKEN" agent sessions outcome session_123 -o json
ork --registry-url "$REGISTRY_URL" --access-token "$TOKEN" \
  agent skills versions content skill_123 1 --output-file ./skill.zip

Registry operations

Discover core API versions and call the unauthenticated core probes. healthz and readyz only require the deployment host root:

ork --registry-url https://example.com --access-token "$TOKEN" api-versions
ork --registry-url https://example.com healthz
ork --registry-url https://example.com readyz -o json

Discover and use the policy and pricing extensions. Every extension command first checks the deployment's authenticated GET /apis response, so an older or unsupported deployment fails with a clear capability error instead of an endpoint 404:

ork --registry-url "$REGISTRY_URL" --api-key "$ORCA_API_KEY" api-groups
ork --registry-url "$REGISTRY_URL" --api-key "$ORCA_API_KEY" \
  api-resources --group policy.runorca.ai

ork --registry-url "$REGISTRY_URL" --api-key "$ORCA_API_KEY" guardrails list-types -o json
ork --registry-url "$REGISTRY_URL" --api-key "$ORCA_API_KEY" guardrails create \
  --config-json '{"name":"protect-production","phases":["request"],"scope":"explicit","rule":{"kind":"expression","expression":"true","on_false":"deny"}}'
ork --registry-url "$REGISTRY_URL" --api-key "$ORCA_API_KEY" guardrails list --limit 100

ork --registry-url "$REGISTRY_URL" --api-key "$ORCA_API_KEY" model-prices list --limit 10
ork --registry-url "$REGISTRY_URL" --api-key "$ORCA_API_KEY" \
  model-prices get model-alpha --provider provider-a -o json

guardrails create and guardrails update accept either --config-json or --file with the full request object, including builtin or expression rules and nullable update fields.

Hosted resources

These commands need a deployment that serves the hosted extension group. Probe it, and validate a connection's configuration without creating it:

ork --registry-url https://example.com --access-token "$TOKEN" health ready
ork --registry-url https://example.com --access-token "$TOKEN" \
  connections validate --name kafka-dev --type kafka --kafka-bootstrap-servers broker:9092

Function, source and sink creation requires --connection, and connection assignment is immutable during updates. Functions, sources and sinks accept --sn-service-account, and source and sink configs also accept --log-topic. Lifecycle and status commands accept an optional instance ID; functions also expose stats, trigger and state APIs.

ork --registry-url "$REGISTRY_URL" --access-token "$TOKEN" functions status word-count 0
ork --registry-url "$REGISTRY_URL" --access-token "$TOKEN" functions stats word-count 0 -o json
ork --registry-url "$REGISTRY_URL" --access-token "$TOKEN" functions trigger word-count --data '{"value":1}' --topic input
ork --registry-url "$REGISTRY_URL" --access-token "$TOKEN" functions state put word-count counter --state-json '{"numberValue":7}'
ork --registry-url "$REGISTRY_URL" --access-token "$TOKEN" sources restart ingest 0
ork --registry-url "$REGISTRY_URL" --access-token "$TOKEN" sinks status archive 0

Kafka Connect commands include worker health, registry and installed plugin catalogs, raw config/status/task/topic views, restart options, and active-topic reset:

ork --registry-url "$REGISTRY_URL" --access-token "$TOKEN" kafka-connect health
ork --registry-url "$REGISTRY_URL" --access-token "$TOKEN" kafka-connect available-connectors
ork --registry-url "$REGISTRY_URL" --access-token "$TOKEN" kafka-connect get status orders-sink -o json
ork --registry-url "$REGISTRY_URL" --access-token "$TOKEN" kafka-connect get task-status orders-sink 0
ork --registry-url "$REGISTRY_URL" --access-token "$TOKEN" kafka-connect restart connector orders-sink --include-tasks --only-failed
ork --registry-url "$REGISTRY_URL" --access-token "$TOKEN" kafka-connect reset topics orders-sink

The hosted Kafka Connect runtime doesn't implement the connector config PATCH that its OpenAPI description declares, and plugin config validation is explicitly unsupported. Use kafka-connect apply with a complete config; --dry-run performs local checks only.

MCP OAuth vault credentials

The CLI can authorize an MCP HTTP server and register the resulting credential directly in a vault, without Python or manually copying tokens:

ork --registry-url https://example.com --access-token "$TOKEN" \
  agent vaults credentials create \
  --vault vlt_123 \
  --display-name "Example MCP" \
  --mcp-server-url https://mcp.example.com/mcp \
  --output json

The native Go flow discovers protected-resource and authorization-server metadata, uses Authorization Code + PKCE S256 and a random state, opens a browser, receives a loopback callback, exchanges the code, and sends the auth object directly to the registry. Progress and the authorization URL go to stderr; stdout contains only the credential result, not OAuth tokens. Tokens are not cached or written to local files. The registry owns subsequent token refresh.

By default, a new native client is dynamically registered on each run. The CLI prefers public client authentication (none), then client_secret_post, then client_secret_basic, according to the server metadata. An omitted methods list defaults to Basic. The actual registration response determines how the code is exchanged and how the registry refreshes tokens; a returned none method never sends or stores an incidental client secret. Secrets required for refresh are sent directly to the vault, never printed or saved locally.

For a pre-registered public client, pass --oauth-client-id <id> and configure its redirect URI as http://127.0.0.1:<port>/oauth/callback, selecting that port with --callback-address. The provider must accept this exact redirect URI (or explicitly permit dynamic loopback ports). Pre-registered clients requiring a secret and client-credentials grants are not supported by this browser flow.

For gateway interoperability, discovery accepts either an exact issuer match or HTTPS issuers with the same registrable domain (Public Suffix List, including private suffixes) and effective port. For example, https://mcp.example.com/tenant can delegate to https://auth.example.com/. Different github.io tenants are not considered the same registrable domain. IP addresses, localhost and unknown suffixes require an exact issuer match by default. This deliberately relaxes RFC 8414 section 3.3: a shared registrable domain is not proof of common administration. After discovery, the returned metadata issuer is pinned; any callback iss must match it exactly, and it is required when the server advertises authorization-response issuer support.

For a headless or SSH flow, pin and forward the callback port, then open the printed URL in a local browser:

# From the local machine, forward the callback port to the CLI host:
ssh -L 53900:127.0.0.1:53900 user@cli-host

# On the CLI host, with registry authentication configured:
ork agent vaults credentials create \
  --vault vlt_123 --display-name "Example MCP" \
  --mcp-server-url https://mcp.example.com/mcp \
  --no-browser \
  --callback-address 127.0.0.1:53900

Additional options:

  • --oauth-issuer <issuer> selects among multiple advertised authorization servers.
  • --oauth-allow-issuer-mismatch disables discovery issuer identity matching, including across registrable domains or ports. Use only with a trusted server; it emits a warning on stderr. Metadata must still contain a valid issuer URL. HTTPS, PKCE, state, resource validation and exact callback issuer checks remain enabled. This does not change --oauth-issuer selection or disable TLS certificate verification.
  • --oauth-scope "tools.read" overrides requested scopes; repeat as needed.
  • --oauth-timeout 5m bounds the complete OAuth flow.
  • --no-refresh disables requesting offline access/a refresh grant. Without a returned refresh token, the credential will eventually require reauthorization.
  • --allow-http permits numeric loopback HTTP endpoints for local tests only. All other OAuth endpoints require HTTPS; protocol redirects are not followed.

The credential includes expiry and refresh resource/scope when available. Use a registry version supporting these fields. A successful local OAuth flow does not guarantee the registry can reach the MCP/token endpoints: registry egress policies may prohibit private or loopback destinations.

If vault registration fails after OAuth, tokens are not saved for retry. Check the vault first (a lost response may hide a successful creation), then rerun if needed. The existing --auth-json <json> path remains supported and is mutually exclusive with --mcp-server-url. The standalone scripts/mcp_oauth_auth_json.py remains available as a legacy auth JSON helper; prefer the native flow to avoid passing OAuth secrets in process arguments.

Design reference: pi-mcp-adapter OAuth support.

Run a local engine

ork local starts a single-machine engine with Docker Compose. It doesn't need a Kubernetes cluster or a checkout of the engine repository, but it needs Docker with Compose v2 and a host installation of ork: the CLI container image doesn't contain the Docker client or the host socket.

LOCAL_DIR="$HOME/.ork-local"
ork local --data-dir "$LOCAL_DIR" start
ork local --data-dir "$LOCAL_DIR" status
ork local --data-dir "$LOCAL_DIR" stop

The stack runs the published Registry and Harness images, Postgres for the Registry, transcript, file and memory stores, and RustFS, an S3-compatible object store, for files. The first start creates a local organization, a workspace and a workspace API key. ork local start prints the key's path rather than its value. Without --data-dir, the directory is ork/local/ under the OS user configuration directory. stop keeps the Postgres and RustFS Docker volumes and the local key files.

The default engine images are ghcr.io/orca-ae/orca-registry-service-ts:0.5.1 (Registry and migrations), ghcr.io/orca-ae/orca-harness-server:0.5.1, and ghcr.io/orca-ae/orca-ai-gateway:0.4.3 for the optional gateway.

The CLI doesn't save provider credentials. Set ANTHROPIC_API_KEY or OPENAI_API_KEY in the shell before ork local start to pass them to Harness, and restart the stack after you change them.

This stack uses Harness's unisolated in-memory sandbox, so run only trusted agents and code. The Registry's local secret store keeps vault values only in process memory, so they don't survive a Registry restart.

ork local start --with-gateway also starts AI Gateway and switches Harness's default model egress to it; without the gateway, Harness calls model providers directly. MCP servers and gateway egress need the gateway.

ORCA_LOCAL_REGISTRY_PORT and ORCA_LOCAL_ADMIN_PORT override the loopback ports (8080 and 18082). ORCA_LOCAL_REGISTRY_IMAGE, ORCA_LOCAL_HARNESS_IMAGE and ORCA_LOCAL_GATEWAY_IMAGE override the image references, for testing another compatible release.

Container image

Tagged releases publish a multi-platform image for linux/amd64 and linux/arm64:

  • ghcr.io/orca-ae/orca-cli:vX.Y.Z
  • ghcr.io/orca-ae/orca-cli:X.Y.Z
  • ghcr.io/orca-ae/orca-cli:sha-<12-character-commit>
  • ghcr.io/orca-ae/orca-cli:latest, for stable releases only

Images carry BuildKit provenance and SBOM attestations, and are signed with keyless cosign through GitHub OIDC.

The image runs as UID/GID 1000, keeps /bin/sh so it can serve as a toolset pod, and uses /workspace as its working directory. ork is the entrypoint:

export ORCA_REGISTRY_URL=https://example.com
read -rsp 'Orca access token: ' ORCA_ACCESS_TOKEN && echo
export ORCA_ACCESS_TOKEN

docker run --rm \
  --env ORCA_REGISTRY_URL \
  --env ORCA_ACCESS_TOKEN \
  ghcr.io/orca-ae/orca-cli:X.Y.Z agent list

Pass credentials at runtime, never through Docker build arguments or image layers. For Kubernetes, source the registry credential and any provider API keys from Secrets, and avoid literal secret values in Helm values or Pod specs:

apiVersion: v1
kind: Pod
metadata:
  name: orca-toolset
spec:
  automountServiceAccountToken: false
  containers:
    - name: orca
      image: ghcr.io/orca-ae/orca-cli:X.Y.Z
      command: [/bin/sh, -c]
      args:
        - |
          child=
          shutdown() {
            if [ -n "$child" ]; then
              kill "$child" 2>/dev/null || true
              wait "$child" 2>/dev/null || true
            fi
            exit 0
          }
          trap shutdown TERM INT
          sleep infinity &
          child=$!
          wait "$child"
      env:
        - name: ORCA_REGISTRY_URL
          value: https://example.com
        - name: ORCA_ACCESS_TOKEN
          valueFrom:
            secretKeyRef:
              name: orca-toolset-registry
              key: access-token
      envFrom:
        # Optional provider credentials such as ANTHROPIC_API_KEY or
        # OPENAI_API_KEY for other tools executed in this pod.
        - secretRef:
            name: orca-toolset-provider-credentials
            optional: true
      securityContext:
        allowPrivilegeEscalation: false
        capabilities:
          drop: [ALL]
        runAsNonRoot: true
        runAsUser: 1000
        runAsGroup: 1000

Anyone allowed to exec into this pod can use its credentials. Restrict pods/exec RBAC, use least-privilege short-lived credentials where possible, restart the pod after rotating Secret-backed environment variables, and pin release tags or image digests instead of latest.

Documentation

Where to talk

Report bugs and request features in Issues, and ask questions or share ideas in Discussions. Problems in the engine itself belong in the engine repository.

Contributing

Contributions are welcome. CONTRIBUTING.md explains how to build and test, the DCO sign-off, and how to propose changes; read the AI policy if you use AI tools. The E2E guide covers the exhaustive command harness and the direct Managed Agents Helm/Kind suite, including deterministic execution, policy, and pricing scenarios. Report security vulnerabilities privately, as SECURITY.md describes.

License

ORK is licensed under the Apache License 2.0.

About

CLI to manage & interact with resources in Orca Agent Engine

Resources

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages