Skip to main content

Chat

anyy chat sends a single prompt through the running Anyy gateway and prints the reply. It is the non-interactive counterpart to the interactive app: no TUI, no prompt loop — one prompt in, one answer out. That makes it the building block for scripts, cron jobs, CI steps, and any place you want an Anyy answer without a terminal session.

Because the work is served by the resident daemon, the gateway must already be running (see Gateway). chat is a thin RPC client: it creates or reuses a session, sends your text, and renders the assistant's final message. For the full command surface see the CLI overview.

anyy chat [--home PATH] [--socket PATH] [--role ROLE] [--session ID] [--json] [--yes] PROMPT

The prompt is everything after the flags; multiple arguments are joined with spaces, so quoting is optional but recommended:

anyy chat "summarize my unread mail and list anything that needs a reply"

One-shot Prompt

A one-shot prompt creates a fresh session, runs a single turn, and prints the assistant's text to standard output. Nothing else is written to stdout, so the output is safe to capture:

reply=$(anyy chat "what's on my calendar tomorrow?")
echo "$reply"

Each invocation without --session starts a new session titled from the first 60 characters of your prompt. To continue an existing conversation instead, see Session Selection.

Diagnostics (errors, warnings, continuation notices) always go to stderr, and the assistant reply goes to stdout. This split lets you redirect them independently:

anyy chat "draft a reply to the latest support email" \
>reply.txt 2>chat.log

Role Selection

--role ROLE selects the Role used when a new session is created. Roles bundle a system prompt, default model, and tool policy (see Sessions for how Roles and sessions relate):

anyy chat --role researcher "find three recent papers on local-first sync"

The global form anyy --role ROLE chat "..." is equivalent; the command-level --role takes precedence when both are present.

--role only applies while creating a session, so it cannot be combined with --session (which targets an already-created session). Passing both is a usage error and exits 2:

✗ Cannot combine --role and --session

Reason:
--role only applies when creating a new session

Next:
omit --role, or start a new chat without --session

Session Selection

--session ID sends the prompt into an existing session instead of creating a new one, so the turn sees that session's prior history, memory, and Role:

# First turn creates a session; capture its id from JSON output.
sid=$(anyy chat --json "start a trip plan for Kyoto" | jq -r .session_id)

# Continue the same conversation.
anyy chat --session "$sid" "add a day for day trips to Nara"

Session ids are stable. Capture one from anyy chat --json output (the session_id field), or resume a session from the interactive app; see Sessions for how sessions persist. Targeting a session keeps multi-step scripts in a single coherent thread.

Approvals

When a turn wants to perform a state-changing or root-capable action, Anyy raises an approval instead of acting silently. The interactive app prompts you; anyy chat is non-interactive, so it applies a deterministic policy:

  • Default (no --yes): deny. Any pending approvals are denied, the reply (if any) is still printed, and the command exits 3:

    ✗ Approval required

    Reason:
    Anyy opened 1 pending approval(s), and noninteractive chat denies approvals by default

    Next:
    rerun with --yes to approve supported pending approvals
  • --yes: approve supported approvals. Each pending approval is approved with reason approved by anyy chat --yes, then chat waits up to 10 seconds for the turn to continue and prints the final reply:

    anyy chat --yes "move yesterday's screenshots into ~/Archive/2026-06"

This makes --yes the explicit opt-in for unattended automation. Use it only when you trust the prompt and the Role's tool policy, since it auto-approves the actions a human would otherwise confirm. ChangePlan, approval, and audit records are still written by the gateway regardless of how the decision is made.

If --yes approves everything but no new assistant text arrives within the continuation window, chat prints a timeout notice to stderr and returns the text it already had:

⚠ Continuation wait timed out

Reason:
no new assistant text arrived within 10s

Next:
open Anyy to inspect the session, or rerun anyy chat

Streaming Output

anyy chat is not a streaming client: it waits for the turn to finish and then prints the assistant's final message in one block. There is no token-by-token output and no --stream flag. For live, incremental output use the interactive app.

In the default (human) mode only the assistant text is written, followed by a trailing newline. If the turn produces no assistant text (for example, it only denied an approval), nothing is printed to stdout and the exit code carries the result.

JSON Mode

--json replaces the human reply with a single pretty-printed JSON object describing the turn — ideal for scripting and for inspecting approvals or the stop reason. The object is the only thing on stdout:

anyy chat --json "what timezone am I in?"
{
"session_id": "ses_01J9Z8...",
"turn_id": "trn_01J9Z8...",
"stop_reason": "completed",
"assistant_text": "You're in Asia/Shanghai (UTC+8).",
"approvals": []
}

Field shape:

FieldTypeMeaning
session_idstringSession the turn ran in (new or the one from --session).
turn_idstringIdentifier for this turn; empty if the turn never started.
stop_reasonstringWhy the turn ended, e.g. completed, max_iterations, output_limit.
assistant_textstringThe assistant's final text (empty if none was produced).
approvalsarrayApprovals still open after the policy ran; empty when none remain.

Each entry in approvals has this shape:

FieldTypeMeaning
idstringApproval id.
kindstringApproval category (the action class).
titlestringShort human-readable title.
riskstringRisk level reported for the action.
summarystringLonger description of what was requested.

With --json and the default deny policy, denied approvals still appear in the emitted object before the command exits 3, so a script can record exactly what was refused:

anyy chat --json "delete every file in /tmp" \
| jq '.approvals[] | {id, kind, risk}'

Combine --json with --session to capture the id once and reuse it:

out=$(anyy chat --json "begin a standup summary")
sid=$(echo "$out" | jq -r .session_id)
anyy chat --json --session "$sid" "now add yesterday's blockers" \
| jq -r .assistant_text

Exit Codes

anyy chat uses exit codes so scripts can branch without parsing text:

CodeMeaningTypical cause
0SuccessThe turn completed (and any approvals were approved).
1Runtime errorGateway not running / socket unreachable, or an RPC call failed.
2Usage errorMissing prompt, unparseable flags, or --role combined with --session.
3Approval deniedPending approvals were denied by the default non-interactive policy.

With --json, an exit of 3 is still accompanied by the JSON object (including the denied approvals); exit codes 1 and 2 print only the error block on stderr.

A runtime failure when the gateway is not running looks like this:

✗ Could not create chat session

Reason:
dial unix ~/.anyy/anyy.sock: connect: no such file or directory

Next:
start Anyy gateway, then run anyy chat again

Start the daemon first (anyy gateway start, see Gateway) and retry. A scripting pattern that distinguishes the "needs approval" case from a hard failure:

if anyy chat --yes "tidy my downloads folder"; then
echo "done"
else
case $? in
3) echo "blocked: an action needed approval the policy would not grant" ;;
2) echo "usage error — check the command" ;;
*) echo "gateway/runtime error — is the gateway up?" ;;
esac
fi

Selecting the gateway

By default chat finds the gateway socket from the active profile and home directory. Override either when you run more than one Anyy, or in scripts that target a specific instance:

  • --home PATH — use a specific Anyy home (also settable via ANYY_HOME); the socket is derived from it.
  • --socket PATH — connect to an explicit gateway Unix socket, bypassing profile/home resolution.
anyy chat --socket ~/.anyy/anyy.sock "ping"

See Sessions for how sessions and Roles persist across calls, and the CLI overview for the rest of the command set.