Skip to content

Troubleshooting

Almost every “Ony.ai never rings” problem collapses into the hook’s silent fail-safe: when something is wrong, the gate steps aside rather than blocking your agent, so you just see no call. ony doctor makes each cause visible.

Terminal window
ony doctor

It prints one actionable line per check and exits non-zero if anything fails. Run it from the project directory whose Claude wiring you want checked (or pass --project <repo>). The checks cover:

  • config - ~/.ony/config.json exists, parses, and (on POSIX) is owner-only.
  • enrollment - the device id, token, and server URL are present.
  • decision key - the per-device key used to verify signed verdicts is present. Without it, every phone verdict fails verification and downgrades to “ask”.
  • server - the Ony.ai server is reachable, with a compatible signing scheme.
  • clock - your local clock is within ~60s of the server’s.
  • signing - a sign-and-verify roundtrip works locally.
  • call readiness - a real carrier is configured and you have a verified phone number.
  • mode - the current /ony mode.
  • claude hooks - the project’s PreToolUse gate is registered, each hook entry has a >60s timeout, and the baked interpreter path and package root still exist.

Fix the failing lines top to bottom, then re-run. Most sections below map directly to one check.

Not enrolled. ony doctor says config or enrollment is missing. Fix:

Terminal window
ony enroll --url <your-ony-url> --email <you>

Wrong /ony mode. In off, Ony.ai does nothing. In on, it phones only for high-risk actions, so routine steps never ring. Check with ony status; switch with ony away (every actionable step) or ony on (high-risk only). See the modes page.

Server unreachable. The gate cannot raise a handoff, so it fails safe and steps aside. Confirm the server is up and --url points at it. For a self-hosted server, bring it back with docker compose up -d (or ony up for the local Lite server).

Mock carrier, so no phone rings. Out of the box the server uses the built-in mock carrier: handoffs surface in the dashboard (Approve / Deny), but no phone rings. Add a real provider under Settings -> Integrations -> Telephony and verify your number. See carrier setup.

No verified phone. Even with a real carrier, ony away will not ring anyone until you verify a contact number in the dashboard (Settings -> Profile). ony doctor’s call-readiness check flags this.

Missing decision key. If enrollment did not return a decision key, every verdict fails signature verification and silently downgrades to “ask”. Re-enroll to receive one: ony enroll.

Clock skew. A signed verdict expires about 60 seconds after it is signed. If your local clock is off by more than that, every verdict looks expired and each decision downgrades to “ask” - so the call may even connect but the answer never lands. Sync your system clock; ony doctor’s clock check shows the drift.

Stale hook wiring. If the venv or package moved after install, the baked interpreter path or package root in .claude/settings.json no longer resolves and the hook cannot run. ony doctor flags this; fix it by re-running ony hooks install --project <repo> from the right environment.

This usually means the server can place a call but the carrier’s webhook path back to the server is not signing correctly, so the call connects without instructions. ony doctor’s call-readiness check reports a carrier that is “not fully configured (missing credentials or webhook signing)”. Recheck the carrier’s credentials and webhook signing secret in Settings -> Integrations against your provider, and confirm the webhook URL is reachable from the carrier. See carrier setup.

You are almost certainly in away mode, which phones for every actionable step. That is by design for remote control. When you are back at the keyboard, switch to high-risk-only calls:

Terminal window
ony here # or: ony on

This is intentional, and it holds in every mode. Ony.ai composes with Claude Code’s own permission surface by pure inheritance: it rings exactly when Claude itself would stop and prompt you. Work you already pre-authorized - allowlisted commands, accept-edits, bypass-permissions - never prompts Claude, so it never reaches the gate and never rings, in on or in away alike. Switching to away widens the calls to every ask Claude would have shown you, not to steps Claude was already going to run silently. If you want a phone call for a command, take it off the allowlist - that is the phone-level kill switch. The one exception is the opt-in headless install (ony hooks install --headless), whose pre-execution PreToolUse gate decides independently of Claude’s dialogs. More on this composition is in how the gate works and on the modes page.

Re-run ony doctor after each change, and check the dashboard’s session and audit views to see whether handoffs are being raised at all. Carrier-specific setup lives in carrier setup; how gating composes with your agent is on the modes page.