@ora-ai/ax
v0.5.3
Published
Score any site's agent readiness and watch real AI agents navigate it — powered by ora
Readme
ax — the ora CLI
Score any site's agent readiness — and watch real AI agents navigate it. Powered by ora's hosted APIs.
npx @ora-ai/ax audit https://stripe.comFour commands:
audit <url>— run ora's hosted agent-readiness audit against a site: live progress, then a layered report of what passed, what's broken, and ora's ranked list of the highest-impact fixes (or--jsonfor the raw contract payload). No account or API key needed. Gate CI with--min-score.deep-journey <url>— run a real AI agent at a site on one of ora's curated tasks through the public journey API: no key, no workspace. A partner API key unlocks free-text tasks (--task) and a larger allowance.journey "<intent>"— send a real AI agent (claude-code, codex, …) at a site and watch its navigation live as a boxed node-graph, then get the scored insight, tokens, and cost. Requires anORA_API_KEY.skill [name]— list, print, or install ora's agent skills, digest-verified from the public registry.
audit
ax audit <url> [--min-score n] [--max-age s] [--force] [--tunnel-cmd c] [--api-key k] [--json] [--show-passing] [--show-skipped] stripe.com 78/100 B+
Stripe offers strong developer resource discoverability, but lacks an OpenAPI specification.
Discovery ██████░░░░ 6/9 passed · 1 skipped
✗ Issues (2)
┌───┬──────────────┬───────────────────────────┬──────────────────────────────┐
│ │ Check │ What's wrong │ How to fix │
├───┼──────────────┼───────────────────────────┼──────────────────────────────┤
│ ✗ │ sitemap.md │ status 404 │ Publish /sitemap.md listing… │
├───┼──────────────┼───────────────────────────┼──────────────────────────────┤
│ ⚠ │ robots.txt │ partially restricted │ Allow AI crawlers in robots… │
└───┴──────────────┴───────────────────────────┴──────────────────────────────┘
Top fixes (ranked by ora)
1. sitemap-md ≈ +4 pts
2. robots-txt ≈ +1.2 pts
cached result (43 min old) · pass --force for a fresh scan
Full report: https://ora.ai/stripe.com| Flag | Effect |
|---|---|
| --min-score <n> | Exit 1 when the score is below n (0-100) — the CI gate |
| --max-age <s> | Accept a cached result up to s seconds old (server default 6h, clamped to 1-24h) |
| --force | Bypass the cache and rescan — spends the stricter 6/day force budget |
| --tunnel-cmd <c> | Expose a local target through your own tunnel command and audit the public URL it prints (also read from ORA_TUNNEL_CMD) |
| --api-key <k> | ora-issued scan API key — lifts every scan rate limit (also read from ORA_SCAN_API_KEY) |
| --json | The raw ora audit payload on stdout, exactly as the API served it |
| --show-passing | List every passing check, not just the per-layer summary bar |
| --show-skipped | Include not-applicable/pending checks with their reason |
The Top fixes list is ranked by ora server-side (non-bonus fixes first, then estimated score uplift) — the CLI renders it verbatim. All ≈ +N pts figures are estimates. Check tiers (required / recommended / emerging) are advisory display metadata and never determine the score.
CI gate
- name: Agent-readiness gate
run: npx @ora-ai/ax audit https://your-site.com --min-score 70Exit codes are the contract:
| Code | Meaning |
|---|---|
| 0 | success (and score ≥ --min-score when given) |
| 1 | score below --min-score |
| 2 | usage error — bad flags, malformed URL, local target without a tunnel |
| 3 | API unreachable, timeout, or rate limit exhausted |
Budget notes: ora allows 30 scans + 6 --force scans per rolling 24h per IP (plus a 10/min burst limit). Results served from the freshness cache cost nothing, so a CI job that audits on every push stays well inside the budget — tune the window with --max-age, and reserve --force for verifying a fix you just deployed. High-volume callers can present an ora-issued scan API key (--api-key or ORA_SCAN_API_KEY), which exempts them from all of these limits; keys are issued manually by ora (no self-serve signup), and an unrecognized key silently falls back to the keyless limits rather than erroring. An auth-gated MCP target reports mcpAuthRequired and scores 0 as "could not evaluate"; --min-score deliberately skips the gate rather than failing on it.
Auditing localhost (--tunnel-cmd)
A local dev server only exists on your machine, so ora can't reach it. The simplest option is to audit a publicly reachable deployment of the same code (e.g. a preview URL). To audit localhost itself, bring your own tunnel: pass --tunnel-cmd (or set ORA_TUNNEL_CMD) with a command that exposes the local server and prints its public https:// URL. The CLI runs it, audits the URL it prints, and tears the tunnel down when done.
ax audit localhost:3000 --tunnel-cmd 'ngrok http 3000 --log stdout'- The CLI ships no tunnel vendor and never downloads executables at runtime — any tunnel tool you already have works, as long as it prints its public URL to stdout or stderr.
- The result is stored as ephemeral: excluded from ora's rankings and deleted after a few days.
- Off-site checks (registry listings, brand search) usually fail for a throwaway tunnel hostname — the report says so. Use tunnel audits to iterate on your on-site surface, not to compare scores.
- Free tiers of some tunnel vendors serve an interstitial warning page to browser-like requests, which can distort what the scanner sees — prefer a vendor/plan that serves your origin directly.
deep-journey
ax deep-journey <url> [--intent id | --task text] [--agent id] [--api-key k] [--no-stream] [--json]ax deep-journey stripe.com --intent pricing
ax deep-journey zapier.com --task "Find how to build a Slack → Sheets zap" # needs a partner keyRuns a real AI agent at a site through ora's public journey API — no key, no workspace needed for curated tasks. The agent's trajectory streams live as progress lines; the terminal output is ora's verdict, the billable step count, and the generated insight:
✓ task satisfied stripe.com
14 steps · 6 turns · 41.2s
The agent found the pricing page in two hops via llms.txt and correctly
summarised the standard and custom tiers.
- llms.txt was load-bearing: it linked /pricing directly
- no web search was needed; every path came from on-site links
For the 4-layer readiness audit, run: ax audit stripe.comAnonymous callers run curated intents (pricing, signup, api-docs, integrate, support, …) — list them with GET https://ora.ai/api/journey/intents, and the accepted agents with GET https://ora.ai/api/journey/agents. The public caps are 100 runs per rolling 24h per target and 200 runs per 24h per IP (plus a 20/min burst limit); a target at its cap answers with the most recent stored run (rate_limited: true) instead of an error, so repeat CI invocations are cheap. Verdict and step count come from ora's contract as-is — the CLI never re-judges a run.
Keyed tier: an ora-issued partner API key (--api-key, or ORA_PARTNER_API_KEY / ORA_SCAN_API_KEY in the environment) unlocks --task — a free-text task of 4–300 characters that replaces the curated intent — and moves the caller to an allowance of 1000 runs per rolling 24h per key with no per-target cap and no burst guard. Keys are issued manually by ora (no self-serve signup). A wrong or unrecognized key with a curated intent silently degrades to the anonymous tier; --task without a recognized key is an error.
If the live stream goes quiet (no frames for 120s) the CLI does not abandon the run — it switches to polling the run detail until the server reports a terminal state.
| Flag | Effect |
|---|---|
| --intent <id> | Curated task id (server default when omitted) |
| --task <text> | Free-text task — needs a partner API key; mutually exclusive with --intent |
| --api-key <k> | ora partner API key; also read from ORA_PARTNER_API_KEY (then ORA_SCAN_API_KEY) |
| --agent <id> | Agent from the public roster (default: ora's pick) |
| --no-stream | Poll for the result instead of streaming the trajectory |
| --json | Print the terminal run detail (verdict, step_count, result) as JSON |
deep-journey exit codes: 0 run succeeded (any verdict) · 1 run failed · 2 usage error · 3 API unreachable / rate-limited.
This differs from ax journey (below), which drives the authenticated platform with free-text goals and renders the full trajectory graph; deep-journey is the zero-setup public path.
skill
ax skill # list the registry
ax skill agent-ready-website # print a SKILL.md
ax skill agent-ready-website --install # write .claude/skills/<name>/SKILL.md
ax skill --json # the raw registry indexSkills come from ora's public registry (https://ora.ai/.well-known/agent-skills/) and every byte is verified against the registry's sha256 digest before it is printed or installed. Skill content is never bundled into this package. --dir <path> overrides the install directory, and --json prints the registry index as JSON instead of the formatted list.
journey
ax journey "<intent>" [--domain d] [--harness h] [--model m] [--json]ax journey "Find the API docs and how to authenticate" --domain stripe.comTriggers a real agent run on ora's platform and renders the journey live — the whole graph repaints in place as the agent moves:
▶ stripe.com · claude-code
9 steps · 3 reasoning · 1 search
╭────────────────────────────────────────────────────────────────────────────────╮
│ ◆ Find the API docs and how to authenticate. Fetch the actual pages to verify. │
╰─┬──────────────────────────────────────────────────────────────────────────────╯
│ (…) The user is asking me to find the API documentation for Stripe…
│ ╭──────────────────────────────────────────────╮
╰──┤ 🔍 "Stripe API documentation authentication" │
╰─┬────────────────────────────────────────────╯
│ ╭─────────────────────────────────────────╮
├──┤ 🌐 docs.stripe.com/api/authentication ✓ │
│ ╰─────────────────────────────────────────╯
│ ╭───────────────────────────╮
╰──┤ 🌐 docs.stripe.com/apis ✓ │
╰───────────────────────────╯
────────────────────────────────────────────────────
✓ completed 9 turns · 30.8s · 119.1k tokens · $0.031
Visibility █████████████████████░ 95/100 ✓ intent satisfiedEdges come from ora's own per-step attribution (link-follows nest under the page that linked them; searches hang off the intent). (…) markers are the agent's reasoning, placed above the action it led to.
| Flag | Effect |
|---|---|
| --domain <d> | Site the agent targets (e.g. stripe.com) |
| --harness <h> | Agent harness: claude-code (default), codex, openclaw, hermess, claude-agent, eve, … |
| --model <m> | Model override (e.g. claude-haiku-4-5-20251001 — cheap and good for demos) |
| --json | Full result as JSON: run metadata, usage, insight, and the raw trajectory |
Note: run-to-run variance is real — agents sometimes answer from search snippets without fetching, which scores differently. Run a few journeys before drawing conclusions.
Journey exit codes: 0 run outcome success · 1 non-success outcome · 2 any error.
Setup
journey needs an ora platform API key (scopes runs:read + runs:write):
export ORA_API_KEY=ora_sk_... # your shell, CI secret store, etc.
ax journey "Find the pricing page" --domain example.comFor local development, copy .env.example to .env — the CLI reads a .env in the working directory on startup (exported variables win over the file).
Library use
The same contract-typed client the CLI uses is importable:
import { audit } from "@ora-ai/ax";
const { result } = await audit("stripe.com");
console.log(result.score, result.grade, result.topFixes);result is the raw versioned audit payload (AuditScanResult / AuditScoreResult, generated from ora's OpenAPI spec). fetchSkill / fetchSkillIndex expose the digest-verified skill registry.
The public journey client is exported too — the same no-key path as ax deep-journey:
import { deepJourney, fetchJourneyAgents } from "@ora-ai/ax";
const { agents, defaultId } = await fetchJourneyAgents();
const agent = agents.find((a) => a.id === defaultId)!;
const { detail } = await deepJourney("stripe.com", {
intentId: "pricing",
harness: agent.harness,
model: agent.model,
});
console.log(detail.verdict, detail.step_count, detail.result?.insight.summary);detail is the contract's JourneyRunDetail; fetchJourneyIntents lists the curated intents. The same public caps apply — a capped target resolves with the most recent stored run (cached: true on the outcome), not an error.
Environment variables
All configuration is environment-first: the consumer defines the variables, the CLI only reads them.
A .env in the working directory is read on startup — copy .env.example and fill it in. Anything already exported wins over the file, so a key set for your shell or by CI beats a stale .env.
| Var | Used by | Default | Purpose |
|---|---|---|---|
| ORA_API_URL | audit, deep-journey, skill | https://ora.ai | Public API base (no auth) |
| ORA_PLATFORM_URL | journey | https://api.agentfront.sh | Authenticated platform API base |
| ORA_TUNNEL_CMD | audit | — (optional) | Tunnel command for a local target (same as --tunnel-cmd) |
| ORA_API_KEY | journey | — (required) | Secret key (ora_sk_…), exchanged for a short-lived bearer token |
| ORA_SCAN_API_KEY | audit, deep-journey | — (optional) | ora-issued scan API key; lifts every scan rate limit (issued manually by ora). deep-journey accepts it as a partner-key fallback |
| ORA_PARTNER_API_KEY | deep-journey | — (optional) | ora-issued partner API key; unlocks --task and the 1000/24h keyed allowance |
Contract versioning
The audit types are generated from ora's served OpenAPI spec (pnpm contract:gen); the build is pinned to a contract version and CI fails when production drifts from the checked-in types. At runtime, the CLI prints one stderr warning when ora reports a newer contract than the build — upgrade with npm i -g @ora-ai/ax@latest.
Migrating from 0.1.x
ax scanis nowax audit(no alias).--jsonprints the raw ora audit payload instead of the old reshaped envelope: stable check ids, layer ids,grade,topFixes, andcontractVersion— key your scripts to those fields.- Audit API failures now exit
3(usage errors stay2).
Development
pnpm install
pnpm test # vitest (watch)
pnpm test:ci # single run + coverage
pnpm typecheck
pnpm lint
pnpm contract:gen # regenerate src/contract/ from the served OpenAPI spec
pnpm build # tsup → dist/main.cjs (bin) + dist/index.* (library)
pnpm smoke # run the built binary the way a user would (needs build)
pnpm verify:pack # check the tarball npm would publish (needs build)
node dist/main.cjs audit https://example.comManual testing without burning the live scan rate limit:
node scripts/mock-scan-server.mjs &
ORA_API_URL=http://localhost:8799 node dist/main.cjs audit https://example.comTo exercise the published-package experience locally: npm pack, then npx ./ora-ai-ax-<version>.tgz audit https://example.com, or pnpm link --global and use ax directly.
Releasing
Publishing runs from GitHub Actions only — Actions → Release → Run workflow,
pick a patch/minor/major bump. See RELEASING.md for the
runbook, required setup, and failure recovery.
License
MIT
