gray

agent
Security Audit
Pass
Health Pass
  • License — License: MIT
  • Description — Repository has a description
  • Active repo — Last push 0 days ago
  • Community trust — 17 GitHub stars
Code Pass
  • Code scan — Scanned 12 files during light audit, no dangerous patterns found
Permissions Pass
  • Permissions — No dangerous permissions requested

No AI report is available for this listing yet.

SUMMARY

Gray is an open-source (MIT) AI agent harness shipped as one static Rust binary. Bash-only tools, resumable JSONL sessions, a self-compacting context window, skills, plugins and cron. Works with any OpenAI-compatible provider using your own API keys.

README.md
Gray

gray

A minimal, modular AI agent harness.
Start small. Extend anything.

Website · Changelog · Releases

License: MIT Built with Rust Platform: linux and macOS Latest release


Gray is a tiny agent core — streaming tool calls over SSE, JSONL sessions, self-managing context — that you extend only when you need to: skills, stdio plugins, cron. Any OpenAI-compatible provider works out of the box. No plugin marketplace, no roadmap promises.

One binary, no runtime musl-static on Linux, Rust-static on macOS. curl | sh lands you in a REPL; gray update self-updates.
Any provider, your keys OpenAI, Anthropic, Google, OpenRouter, DeepSeek, Groq, Mistral, xAI — anything OpenAI-compatible, local models via Ollama — with Anthropic-style prompt caching on Claude models. Searchable model picker over the bundled models.dev catalog.
Sessions that survive JSONL transcripts in ~/.gray/sessions with parent-id branching. -c reopens the latest, /resume picks any of them. Interrupted turns keep what reached memory.
Context that manages itself The window auto-resolves from your provider, gray auto-compacts before the limit and retries once on overflow. /compact forces it by hand.
Bash only The default surface is bash — read, search, edit, run, all through bash. The model schedules its own recurring work by running gray cron add … through bash. Ctrl-C cancels a runaway turn.
Extend the harness Skills from SKILL.md, or sidecar plugins over stdio (frozen wire v1).

Install

curl -fsSL https://gray.alignment.id/install.sh | sh              # stable
curl -fsSL https://gray.alignment.id/install.sh | sh -s -- beta   # bleeding edge, rebuilt on every main push

or from source:

cargo build --release -p gray                          # harness core (image paste included)

harness core: CLI, TUI (with image paste), provider, sessions, tools, cron.

Windows

Native Windows 11 x64 — no WSL, no Linux distro, no elevation. Git for
Windows supplies the shell for tool calls; Gray does not install it or WSL.
Download the Windows release artifact, keep both scripts from its dist folder
together, inspect them, then run:

$hash = ((Get-Content .\gray-beta-x86_64-windows.zip.sha256).Trim() -split '\s+')[0]
.\dist\install.ps1 -ArchivePath .\gray-beta-x86_64-windows.zip -Sha256 $hash

-Native is accepted and is already the default. Pass -Wsl for the
compatibility route that installs the Linux build inside WSL. Native installs
never fall back to WSL. Artifacts are unsigned — the digest catches corruption,
not publisher identity — so follow your execution policy rather than disabling it.
Close Gray and rerun the installer to update; self-update is refused on native
Windows. Gateway and cron execution are unsupported and refused explicitly; cron
jobs can still be managed as files. See the
native installation guide.

macOS binaries are Rust-static but not notarized — curl-installed binaries run fine, browser downloads may hit Gatekeeper quarantine.

Quick start

gray

First run drops you straight at the prompt. Configure whenever you feel like it:

command what it does
/provider pick a provider — API key, free tier, or local
/key openrouter paste an API key right in the CLI (input hidden), stored per-provider in ~/.gray/auth.json
/login log this machine in to gray.alignment.id — optional, and nothing is gated on it
/whoami show the account the stored registry token belongs to
/logout revoke the registry token and forget it
/model searchable picker over the bundled models.dev catalog

Account (optional)

gray.alignment.id holds the plugin registry. An account is not required to run
gray, and nothing in the CLI is gated on one — the token only names you on
registry calls.

gray login                 # walks you through it, then prompts for the code
gray login <code>          # same, non-interactive
gray whoami                # who the stored token belongs to
gray logout                # revokes the token, then forgets it

Mint a code at gray.alignment.id/account
(sign in with GitHub, Google, or Discord, then "Generate CLI login code"). It
is one-time and expires in 5 minutes. The token lands in
~/.gray/registry-token.json (mode 0600). Point gray at a local registry with
GRAY_REGISTRY_URL=http://127.0.0.1:4000/api.

Watch it go

gray building HorseTinder — session replay from gray.alignment.id

Small core, open world

Dithered Blue Marble

Bring your provider, tools, and skills. Keep only what you use.

Background shell jobs

The AI can start independent commands without waiting for them to finish:

{"command":"cargo test", "background":true, "timeout":600}

Or let short commands finish normally, yielding a job ID only if still running:

{"command":"cargo test", "yield_ms":1000, "timeout":600}

Multiple jobs run concurrently (up to 32 per tool instance). Use the same bash
tool with action: "list", or action: "status", "output", or "cancel" plus
job_id. Status/output calls return immediately. Jobs are session-scoped;
finished outputs remain retrievable, with a bounded history of 128 jobs.

Completion notices reach the AI between model rounds. If the AI has already
finished its turn, notices arrive on the next user turn—jobs do not hold the
turn open or trigger an unsolicited model call. Cancellation and the total
runtime timeout still terminate the owned process tree; quitting Gray stops
managed jobs. Jobs are not restored after restart, but their logs remain.

Without background or yield_ms, bash retains its blocking behavior. Only
start jobs concurrently when they are independent; don't run competing writes
or builds against the same output directory.

Commands

Slash commands autocomplete: Enter completes and fires, Tab inserts for editing — suffixes too, so /context r suggests reserve.

/new · /resume [id|--last|--all] fresh conversation, or reopen a previous one
/model [id] · /provider · /key [provider] models, providers, keys — without leaving the chat
/compact [instructions] summarize context (auto-compacts near the limit)
/context [tokens|auto] inspect or set the window — 128k, 1m, auto to clear
/thinking · /effort [level] toggle reasoning, pick the effort
/usage session tokens & cost
/skills · /skills [name] [args] list skills, run one
/plugin <subcommand> list · search · install · remove · update · enable · disable · check
/agentsmd edit the full system prompt in the built-in editor (show, reset too)
/feedback <text> save feedback locally + open a prefilled GitHub issue
/help · /quit you know these

CLI surface

gray itself plus six subcommands — everything else is a slash command away:

subcommand what it does
gray resume [--last|--all] [SESSION_ID] resume a conversation — picker, most-recent, or by id/prefix
gray plugin <list|search|install|remove|update|enable|disable|check> manage plugins
gray cron <list|add|remove|show> recurring/one-shot jobs (fired by the gateway, serve, a tick host, or the REPL)
gray gateway <run|status|start|stop|restart|install|uninstall> the daemon that fires cron with no REPL open — cron ticker + control socket, supervised as a user service
gray sessions prune session store maintenance
gray update update gray to the latest release

Global flags: -p/--print (one-shot), -c/--continue (reopen latest), --session <ID>, --context-window <TOKENS>, --context-reserve, --context-keep, --dump-manifest, --json (machine-readable print mode).

--json print mode writes one JSON record per event and exits with the failure class: 0 success, 1 the turn failed (do not retry), 3 provider/network death (retrying the turn usually succeeds). The error record carries code (auth_failed, rate_limited, bad_request, context_overflow, server_error, stream_broken, connection_failed, timeout, loop_detected, cancelled, serialization, turn_failed), retryable, message, and a hint naming the command that fixes it — so harnesses branch on the class instead of parsing prose.

Extend

Make gray yours via skills, plugins, providers, and config.

Skills — SKILL.md bodies discovered in your global (~/.gray/skills) and project (.gray/skills) directories, plus a few conventional shared skill locations. /skills lists them, /skills [name] [args] pastes one into the chat and runs it (/skill is an alias). The model gets the fresh <available_skills> list every turn and reads matches with bash (cat <location>) — no skill tool, tools stay bash-only.

Plugins — sidecar child processes speaking newline-delimited JSON over stdio, with timeout and crash degradation. gray.yml profiles order built-ins and sidecars; plugins/echo/ is a copy-paste reference implementation.

Scheduling

The agent stores recurring work with gray cron add "<schedule>" "<prompt>" (manage with gray cron list/show/remove). Jobs fire when something ticks the store — the gateway daemon, gray cron serve, a gray cron tick host (cron/systemd timer), or an open REPL.

Gateway — gray gateway install writes a user service (runit on Void, systemd --user elsewhere; install --print previews) running gray gateway run: a 60s cron ticker plus a control socket at $GRAY_HOME/gateway.sock answering identify/status (one JSON line in, one out — a connectable socket with a well-formed answer is liveness). gray gateway status reports daemon + service + ticker health and exits 1 when down; start/stop/restart drive the service, uninstall removes it. The daemon claims $GRAY_HOME/gateway.pid (O_EXCL, start-time-checked against PID reuse), records why it stopped in gateway.state.json, and drains an in-flight fire up to 65s on SIGTERM.

Dithered Jupiter storm

Safety

gray executes shell commands from the model. There is no command guard and no approval prompt: the model's bash runs what it writes, with your user's privileges. There is no container or VM isolation — run gray in a container/VM for untrusted work. Security reports: SECURITY.md.

Persistence note: REPL sessions keep raw transcripts at 0600 under ~/.gray/sessions for exact resume — including any secret that crossed a tool call. gray -p print mode scrubs secrets before persisting. Plan backups, snapshots, and disk access accordingly.

Context window & auto-compact

The window resolves as: --context-window / GRAY_CONTEXT_WINDOW → auto-fetched provider value → LiteLLM model table → hardcoded fallback. Inspect with /context, set with /context 128k (or 1m; auto clears).

When usage nears the limit (tokens > window − 16k reserve), gray summarizes history into a 2-message summary before the next turn — the same flow as manual /compact — and on context_length / max_tokens overflow errors it compacts and retries once. Auto is the default; no flag needed.

Layout

crate role
gray REPL · onboarding · config · TUI · JSONL session store (src/session_store.rs, parent-id branching) · cron (src/cron/)
gray-core agent loop · events · messages
gray-provider OpenAI-compatible SSE streaming, retries, prompt caching
gray-tools bash · read · write · edit · grep · find · ls · shell control (profile-selectable)
gray-plugin plugin trait · manifest · gray.yml profile loader
gray-pkg plugin package management
gray-markdown streaming markdown renderer for the TUI

Design notes: streaming first — text deltas, tool calls, and usage arrive as typed events over SSE. Logs go to ~/.gray/logs/gray.log (GRAY_LOG=debug for the firehose).

Environment

The essentials — everything else is one --help or doc page away.

var meaning
GRAY_HOME config root (default ~/.gray)
GRAY_API_KEY / OPENAI_API_KEY API key — env beats stored keys
GRAY_MODEL · GRAY_BASE_URL defaults before ~/.gray/config.json is consulted
GRAY_CONTEXT_WINDOW override the window in tokens — 128000, 128k, 1m, or auto
GRAY_NO_UPDATE_CHECK=1 · GRAY_AUTO_UPDATE=1 silence the startup update check, or background self-update
GRAY_LOG error…trace (default info)
GRAY_PARALLEL_READS 0 runs every tool sequentially (default: read-only tools concurrent, input order preserved)

Platform support

OS / arch binary notes
Linux x86_64 / aarch64 musl-static fully supported — systemd user service (Linux-only)
macOS arm64 / x86_64 Rust-static, not notarized curl-installed binaries run fine; browser downloads may hit Gatekeeper quarantine
Windows x86_64 native, Windows 11+ Git Bash supplies the shell; gateway/cron execution unsupported

"Zero runtime deps" means no sidecar services — you still need sh, curl / wget, tar, and sha256sum / shasum for the installer.

Stability

The 1.x stability contract (CLI flags, session JSONL schema, plugin wire v1, ~/.gray layout) takes effect at 1.0 — on 0.x these are best-effort. Not stable: the TUI, internal crate APIs, gray-markdown. Per-release changes: CHANGELOG.md. Rollback is publisher-side today (manifest re-point); user-side gray update --to <version> is planned.

Dithered Saturn

Ideas and designs informed by the projects listed in THIRD_PARTY_NOTICES.md — thanks to those projects and their authors.

A naming note: cargo install gray belongs to another crate, so the install path is the installer script above (or a source build). The binary stays gray.

MIT © 2026 vstaln

Reviews (0)

No results found