ask-app-server

Gem Version

JSON-RPC/stdio session host for ask-rb agents. Exposes Ask::Agent::Session behind the canonical ask-session-protocol wire contract: one versioned interface for driving an agent as a service, with sessions, streamed canonical events, resolvable interactions (approvals, plans), and turn lifecycle. Any client that speaks the protocol can drive your agent, and the client never needs to know it's talking to Ruby. The method surface is app-server compatible — the same shape Codex and ZCode expose — while the event vocabulary and interaction model are the ask ecosystem's own canonical contract.

What is this?

ask-app-server turns an ask-rb agent into a programmable service that speaks JSON-RPC over stdio. Any client that speaks the canonical session protocol can drive your agent:

  • IDE extensions and editors — stream model deltas, tool events, and approvals into an editor surface over stdio or a socket
  • Custom chat UIs and desktop apps — stream canonical events into your own interface
  • Bots and assistants — drive sessions programmatically from any runtime that can spawn a subprocess
  • Headless automation — CI/CD pipelines, batch processing, scriptable agent tasks

Installation

gem install ask-app-server

Or add to your Gemfile:

gem "ask-app-server"

Quick Start

# Start the server (reads JSON-RPC from stdin, writes to stdout)
ask-app-server

# Or expose a unix socket for multi-client attach (runs alongside stdio):
ask-app-server --socket ~/.ask-app-server/app-server.sock

Running inside a herdr pane? Nothing to configure: herdr injects HERDR_SOCKET_PATH/HERDR_PANE_ID into the pane, the host detects them, and keeps the herdr sidebar accurate with first-party state — working while a turn runs, blocked while an approval is pending, idle otherwise — plus the session id (for future resume) and model tokens. No screen scraping needed; the host knows its own state.

Clients connect to the socket and speak the same protocol as NDJSON lines (ASK_APP_SERVER_SOCKET env var works too):

nc -U ~/.ask-app-server/app-server.sock
{"id":1, "method":"initialize", "params":{}}

Any number of clients can attach to the same sessions: each connection tracks its own event-delivery cursor, so session/subscribe replays what that client hasn't seen and every client receives each event exactly once.

From another process, send JSON-RPC requests:

{"id":1, "method":"session/create", "params":{"workspace":{"workspacePath":"."}}}
{"id":2, "method":"session/send",  "params":{"sessionId":"...", "content":"List files in this directory"}}

Protocol

Methods

Method Description
initialize Handshake; negotiates protocolVersion and capabilities
session/create Create a new agent session
session/list List active sessions
session/resume Resume an existing session
session/subscribe Subscribe to the event stream (with replay snapshot)
session/send Prompt an idle session or inject mid-run (steered/queued/stale)
session/events Poll for events after a sequence number
session/abort Abort the current turn
session/close Close the session
session/artifacts · session/artifact/get List and fetch tool artifacts
interaction/list List pending approval interactions
interaction/approve · interaction/reject Resolve an approval by id
interaction/approve-all · interaction/reject-all Resolve all approvals
interaction/respond Answer user-input elicitation (not yet implemented)
plan/approve · plan/reject Approve/reject the pending plan proposal
workspace/readState Read workspace and approval-mode state

Events (server → client notifications)

Every event is a canonical {type, seq, payload} envelope, delivered as a session/event notification on subscribed sessions:

Event When
session.created · session.ended Session lifecycle
turn.started · turn.completed · turn.failed · turn.aborted Turn lifecycle
model.streaming · model.thinking Model output deltas
tool.use · tool.delta · tool.result Tool execution
approval.required · approval.updated Resolvable approval interactions
plan.proposed · plan.approved · plan.rejected Plan mode
todos.updated Todo list changes
error Non-fatal errors

The full vocabulary, payload shapes, method specs, and versioning live in the ask-session-protocol gem (JSON Schema artifact included).

Clients

Any client that speaks the app-server protocol can connect — including existing app-server SDKs, such as OpenAI's openai-codex (Python) and @openai/codex-sdk (TypeScript), which spawn an app-server subprocess and drive it over stdio. Or write your own client in any language: the protocol is documented and the wire format is plain JSON-RPC over newline-delimited JSON.

Configuration

Flags: --version, --help, --config PATH.

The config file is searched in order: ASK_APP_SERVER_CONFIG env var, then ./.ask-app-server.json, then ~/.ask-app-server/config.json.

Environment variables:

Variable Default Description
ASK_APP_SERVER_CONFIG auto-detected Path to the config file
ASK_APP_SERVER_MODEL opencode_go/deepseek-v4-flash Model identifier (overrides config file)
ASK_APP_SERVER_PERMISSIONS on_request Permission mode (on_request, never, auto)
DEBUG unset Set to 1 for debug logging

Development

git clone https://github.com/ask-rb/ask-app-server.git
cd ask-app-server
bundle install
bundle exec rake test

Full documentation

The full ask-rb documentation lives at https://ask-rb.github.io/ask-docs. The App Server guide covers the protocol, events, and configuration; the Gem reference (Agent Infrastructure section) lists this gem alongside ask-acp and ask-coding-providers.

License

MIT