An independent agent harness, written in Haskell.
nix run --accept-flake-config "github:digitallyinduced/haskell-agent"While a fullscreen terminal turn is running, plain text prompts steer the current turn.
Use /steer <prompt> to do this explicitly, or /queue <prompt> to wait
until the current turn finishes. Bare /queue lists waiting prompts.
When idle, either prompt command starts a new turn.
- OpenAI (Subscription)
- xAI (Subscription)
- Claude (Subscription)
- OpenRouter (API billing)
- Google Gemini (Google account or AI Studio API billing)
Most agent harnesses are effectively untyped imperative programming environments. A model emits loosely structured commands that mutate files, processes, conversation state, and other shared resources. Correctness depends on conventions enforced at runtime, often after effects have already begun.
haskell-agent is an exploration in a different direction. Model output is
treated as untrusted input at the boundary. Accepted actions are decoded into
typed values, state changes are expressed as pure transformations where
possible, and effects are interpreted explicitly by the runtime. The model
remains probabilistic; the environment in which its actions execute does not
have to be.
- A functional agent runtime: protocol states, tool policies, transport ownership, UI transitions, and agent lifecycles are modeled with algebraic data types. Pure transformations are separated from effectful boundaries, while STM coordinates shared concurrent state.
- GHCi as part of the agent architecture: every model gets a persistent typed workspace. The harness distinguishes pure expressions from effectful actions, preserves bindings across calls, and recovers or restarts GHCi when interruption makes its state uncertain.
- First-class model dialects: providers own authentication, billing, and transport, while dialects own the model-facing prompt, tool surface, schema conventions, project-instruction formatting, and subagent protocol. This keeps Codex-style and Grok Build behavior intact even when a transport such as OpenRouter serves models from several families.
- Cross-provider state and billing policy: provider transitions preserve the pending turn and durable session state. Credential failover understands account cooldowns and prevents automatic fallback from silently converting subscription usage into API-credit spending. When a usage window is exhausted and no other provider can take over, an interactive session waits for the provider's reset time (Esc cancels) and then resumes on its own: an interrupted turn continues with a real user message explaining the interruption, while a turn that never started is simply submitted again.
- Explicit response ownership: reusable WebSocket requests carry generation-scoped ownership. If an exchange is interrupted, malformed, or returned before its terminal frame, the connection is poisoned rather than risking old frames entering a later response.
- Types as a path toward safer agency: typed tool decoding, approval rules, and execution policies are the current foundation for deeper work with LLMs, ADTs, type checkers, effect systems, and program verification.
- Choice of models and billing: use OpenAI/Codex, xAI/Grok, OpenRouter, Google Gemini, or Claude Code through subscriptions or API keys, and add local or hosted Responses-compatible models through the user model catalog.
- Interactive terminal workflow: choose between fullscreen and inline interfaces with streaming Markdown, live todo progress, one-shot operation, and image attachments from files or the clipboard.
- PostgreSQL-backed memory and portable sessions: persist conversations and scoped learned guidance, resume or search past work, compact long histories, and switch supported providers without losing the pending turn or durable session state.
- Discoverable structured memory: sessions receive a catalog of existing user, repository, and checkout tables with their PostgreSQL comments, without loading records. The catalog is limited to 8,000 characters across all scopes, prioritizes names over descriptions, and reports omitted tables with guidance to inspect the complete catalog. It refreshes on resume, after compaction, and after table-name or description changes; schema and records remain available on demand.
- Efficient long-running agents: page persisted history on demand and virtualize TUI scrolling to bound memory and rendering work as conversations grow.
- Parallel agents and isolated work: delegate to persisted subagents with a configurable concurrency limit and create fresh sessions in managed Git worktrees.
- Built-in coding tools: run shell commands, opt into a persistent GHCi workspace, search the web, and connect local MCP servers. Approval policies keep mutating operations under user control.
- Natural-language Meta Console: press
Cmd+K(Alt+Kon terminals that report it that way), or use/meta <request>, to preview and apply typed model, account, MCP, web-fetch, LSP, shell, and concurrency configuration changes without adding the request to the coding conversation. - Guided agent workflows: use plan mode, reusable skills, and scoped learned guidance for repeatable tasks and project or user preferences.
- Multimodal input and live voice dictation: attach images and files, or
press
Ctrl+Ron macOS to stream microphone audio to OpenAI or xAI and insert the transcript into the prompt. - Telegram access: run a durable, allowlisted Telegram gateway with per-conversation sessions, multimodal messages, approvals, retries, and bounded concurrent processing.
These are important product features, but not the core differentiation.
Apple silicon Macs running macOS 14 or newer can use the standalone release archive:
(
set -e
archive=haskell-agent-macos-arm64
download_dir="$(mktemp -d)"
curl -fL \
"https://github.com/digitallyinduced/haskell-agent/releases/latest/download/$archive.tar.gz" \
-o "$download_dir/$archive.tar.gz"
curl -fL \
"https://github.com/digitallyinduced/haskell-agent/releases/latest/download/$archive.tar.gz.sha256" \
-o "$download_dir/$archive.tar.gz.sha256"
(cd "$download_dir" && shasum -a 256 -c "$archive.tar.gz.sha256")
mkdir -p "$HOME/.local/opt" "$HOME/.local/bin"
rm -rf "$HOME/.local/opt/haskell-agent-macos-arm64"
tar -xzf "$download_dir/$archive.tar.gz" -C "$HOME/.local/opt"
rm -rf "$download_dir"
ln -sfn \
"$HOME/.local/opt/haskell-agent-macos-arm64/bin/agent-cli" \
"$HOME/.local/bin/agent-cli"
"$HOME/.local/bin/agent-cli" --version
)Add $HOME/.local/bin to PATH if it is not already present. Keep the
extracted directory intact: agent-cli discovers its bundled libraries, data
files, PostgreSQL runtime, and helper tools relative to that directory. The
symlink may live anywhere.
macOS requires its system libraries and frameworks to remain dynamically linked. The archive statically links the Haskell dependency graph and carries all non-system dynamic libraries alongside the executable, so it has no Nix runtime dependency.
-
Install Determinate Nix by following its platform-specific installation instructions.
-
Copy this prompt to your coding agent to install:
Install haskell-agent by running `nix profile add --accept-flake-config github:digitallyinduced/haskell-agent`. If Nix says `haskell-agent` is already added, update it with `nix profile upgrade --refresh --accept-flake-config haskell-agent` instead. Verify the packaged runtime by running `agent-cli storage start`, `agent-cli storage doctor`, and `agent-cli storage stop`.Or install it yourself:
nix profile add --accept-flake-config github:digitallyinduced/haskell-agent--accept-flake-configenables the public IHP binary cache declared by the flake.
nix profile add does not replace an existing profile entry. Update an
existing installation with:
nix profile upgrade --refresh --accept-flake-config haskell-agentIf the profile entry cannot be upgraded, remove and reinstall it:
nix profile remove haskell-agent
nix profile add --refresh --accept-flake-config github:digitallyinduced/haskell-agentVerify that the packaged PostgreSQL runtime is available:
agent-cli storage start
agent-cli storage doctor
agent-cli storage stopStart an interactive session:
agent-cliOn Linux and macOS, supported OpenAI sessions can use the local desktop by
default in an interactive terminal. One-shot and non-interactive runs keep the
tool hidden unless --computer-use is supplied explicitly. Computer-use
requests require separate approval, including under --yolo; choose Always
allow this tool this session to let the workflow continue without prompting
for every action. A provider safety check still requires fresh approval.
/computer-use toggles the capability, while
/computer-use on and /computer-use off set it explicitly. Disabling or
re-enabling clears the workflow approval. On macOS, grant Screen Recording and
Accessibility access to the terminal application in System Settings →
Privacy & Security before using it. Start with
agent-cli --no-computer-use to hide the tool from the model, then enable it
later with /computer-use.
To embed the runtime through a local REST and Server-Sent Events API, run
nix run .#agent-server. It provides durable session management, concurrent
turn supervision, approvals, cancellation, and an OpenAPI 3.1 document. See
the agent server guide.
The provider's Bash/shell execution tool is enabled by default. Enable the
persistent run_ghci tool when needed:
agent-cli --ghciThe GHCi tool is optional and uses a ghci executable from PATH. Run the
agent with a Nix-provided GHC when enabling it:
nix shell nixpkgs#ghc -c agent-cli --ghciOn Linux, native X11 uses xrandr, maim, and xdotool. Native Wayland uses
the standard ScreenCast and RemoteDesktop portals with PipeWire. The Nix
package includes the required command-line and GStreamer dependencies. See the
computer-use guide for permissions, session behavior,
non-Nix prerequisites, and desktop-specific checks.
For GHCi-only operation, disable Bash explicitly:
agent-cli --ghci --no-bashDuring an interactive session, switch the available shell tools without restarting:
/shell ghci
/shell bashUse /shell to show the current selection. /shell both and /shell none
are also supported.
Run a one-shot task:
agent-cli -p \
"inspect this Cabal project, explain its architecture, and run its tests"Start in an isolated Git worktree:
agent-cli --worktreeBy default, managed worktrees fetch and branch from the selected remote's latest
default commit. Repositories without remotes instead branch from the current
local HEAD. To disable fetching, add this to ~/.haskell-agent/config.json:
{
"version": 1,
"worktree": {
"fetchLatestUpstream": false
}
}This policy applies to --worktree, /worktree, and subagent worktrees. The
remote is selected from the current branch's configured remote, then
upstream, origin, or the repository's sole remote. When a remote exists, a
fetch failure aborts worktree creation rather than falling back to a stale
commit.
Default-branch discovery first uses Git's local
refs/remotes/<remote>/HEAD symbolic reference, shared across linked worktrees.
The server is queried only when that reference is missing or invalid, or when
fetching the cached branch reports that it no longer exists. Successful
discovery and fetching refresh the local reference; unrelated fetch failures
are not retried. If the server changes its default but retains the old branch,
fetch the new default branch into its remote-tracking reference before
refreshing the cache. For a new default named main on origin:
git fetch origin refs/heads/main:refs/remotes/origin/main &&
git remote set-head origin --autoSubstitute the selected remote and its new default branch name.
set-head --auto requires the new remote-tracking reference to exist; the
agent's isolated fetches do not create it.
Connected organization gateways must include provider and protocol for every
entry in /v1/models. Supported pairs are openai/responses,
xai/responses, and anthropic/anthropic. Upgrade the gateway before the
client; missing or incompatible metadata fails closed.
The catalog selects the native provider transport, not the model name or a local dialect override. OpenAI uses the OpenAI transport, Grok uses xAI with its native compaction, and Claude uses the Claude gateway integration. Requests retain the organization's model alias and gateway credential/endpoint; provider environment variables cannot redirect gateway xAI requests to a personal endpoint.
Startup, resume, model switching, and child model selection use this catalog. Legacy top-level gateway sessions re-resolve their saved alias to its current provider. In-process subagents support OpenAI and xAI; Claude requires a separate child session.
Managed worktrees are collected only when clean, incorporated into another branch, and inactive for at least 24 hours (configurable to a longer interval). Dirty checkouts and unmerged work never expire merely because they are old. Inactivity means saved-session idle time, not commit age or time since merge. Ownership, active-session, protection and safety checks still apply.
Local proof uses exact commit ancestry into another surviving local or
remote-tracking branch, excluding the checkout's own branch and upstream.
An equal-tip copy alone is insufficient, except for the resolved default branch
(origin/HEAD, or local main/master when it is unavailable).
For squash/rebase merges, authenticated GitHub API evidence must identify a
merged PR with the checkout's exact HEAD. Its merge commit must exist locally
and be reachable from the target branch, with exact final content and modes
preserved for every branch-changed path. Missing or ambiguous evidence retains
the checkout. GC does not fetch; cached refs may miss recent merges.
Clean recovery reuses existing Git trees rather than launching a hashing
process for every file. Recovery refs also preserve checkout reflog commits,
REBASE_HEAD commits, and AUTO_MERGE trees. Active merge/rebase operations
still prevent collection.
Conversation history and historical recovery snapshots are retained, and
resuming a collected session restores its checkout.
Recognized, explicitly ignored build/cache directories are disposable and
are not restored (for example node_modules, dist-newstyle, and .venv).
An ignored result symlink directly into the Nix store is also disposable.
Known ignored agent settings (.haskell-agent/settings.json) and generated
OpenAI provider files (packages/agent-openai/data/models.json and prompt.md)
are permitted only when byte-identical regular copies remain in the primary
checkout; these duplicate copies are not restored. Additional files under
.haskell-agent or differing contents prevent collection.
Other ignored data, including .env files and local databases, prevents
collection. Protect a checkout if its build/cache directories contain
irreplaceable data.
Existing agent worktrees are automatically adopted only when their managed-root location, reciprocal linked-Git metadata, and saved-session provenance verify ownership. Their latest saved-session activity (including archived sessions and sessions in checkout subdirectories) initializes inactivity; adoption does not reset old worktrees to today. Missing or ambiguous ownership/activity retains the checkout. Database errors or incompatible session metadata defer adoption; stale legacy JSON and directory names/mtime are not activity fallbacks. Review the simulated adoption and retention reasons first:
agent-cli worktree gc --dry-run
agent-cli worktree enroll /absolute/path/to/managed/worktree
agent-cli worktree protect /absolute/path/to/managed/worktree
agent-cli worktree unprotect /absolute/path/to/managed/worktree
agent-cli worktree restore /absolute/path/to/managed/worktreegc --dry-run reports eligibility, retained reasons, and per-checkout and total
estimated bytes without writing registry entries or snapshots or collecting
checkouts. Estimates are gross apparent checkout bytes, excluding snapshot
overhead and filesystem/APFS sharing, not guaranteed net reclaimed disk space.
Adoption reads the existing session database
without starting it, migrating it, or importing old sessions. Manual enroll
remains available for a checkout whose provenance cannot be established and
starts its inactivity clock now. Manual gc examines every candidate and prints
progress, with a per-checkout deadline. Background maintenance retains its
short pass budget and rotates its starting point. Not-examined worktrees and
failed operations are reported separately from retained worktrees.
Active leases, explicit protection, unsupported Git state, incomplete snapshots,
or detected concurrent edits prevent deletion. Restoration refuses to overwrite
an existing directory and never resets a branch that moved after collection.
Restored checkouts use a detached HEAD. Recovery requires the original shared
Git repository and the registry under ~/.haskell-agent/worktrees/.registry;
these local snapshots are not an off-machine backup. An interrupted restore
that leaves a directory requires manual recovery rather than overwriting it.
External editors do not participate in agent leases: protect a checkout while
using it outside the agent, since edits after the final verification can race
with removal.
Existing saved-session lifetime and turn locks are also probed without creating
lock files; an active or unverifiable lock retains its checkout even if its last
saved activity is old. Stop pre-upgrade agents before explicit collection:
their locks can be observed, but an old binary starting after the final probe
does not participate in the new worktree lease protocol.
Configure a positive whole number of days with
"worktree": {"inactivityDays": 14} in ~/.haskell-agent/config.json, or use
worktree gc --inactivity-days 14 for one pass. Saving a conversation does not
protect a checkout forever; use worktree protect for long-lived work.
Use --provider openai, --provider xai, --provider openrouter,
--provider gemini, or --provider claude-code to override automatic
provider detection. Claude Code is selected explicitly rather than by
auto-detection.
Open /model and choose a Gemini model such as gemini-3.7-flash. If no
Gemini account is connected, the CLI opens Google sign-in in your browser and
stores the OAuth credential in the same managed credential store used by the
other providers:
/modelNo API key is required for this Google-account flow. For Google AI Studio API
billing instead, set GOOGLE_API_KEY (preferred) or GEMINI_API_KEY, then run
agent-cli --provider gemini --model gemini-3.7-flash.
Create a bot with BotFather, then run:
agent-telegram setup --provider openai --cwd /path/to/project \
--allowed-user 123456789
agent-telegram start
agent-telegram statusThe gateway supports durable per-conversation sessions, allowlists, multimodal messages, approvals, and concurrent chats. See the Telegram guide for setup, groups, commands, and NixOS deployment. You can also ask the agent to “set up a Telegram agent”.
Add local, hosted, or custom models through:
~/.haskell-agent/models.json
The built-in add-model skill can configure it for you. See the
model catalog guide for the schema, local-server example,
dialects, authentication, and compaction metadata.
Session titles use a cheap auxiliary model by default (Haiku on Claude, not
Fable). /title-model pins a catalog model in ~/.haskell-agent/settings.json;
/title-model --auto restores the automatic choice.
The built-in learn-about-user skill can derive consent-reviewed technical
defaults from a confirmed public GitHub profile. Invoke it with
/learn-about-user, $learn-about-user, or a natural-language request.
The built-in skill-installer skill installs Agent Skills from a GitHub
repository, gist, URL, or local path into ~/.haskell-agent/skills or the
project's .haskell-agent/skills directory. Invoke it with /skill-installer,
$skill-installer, or a natural-language request such as “install this skill”.
Works with your Codex, Grok, Google, and Claude accounts, plus provider API
keys. Gemini can be connected interactively from /model or /account;
GOOGLE_API_KEY (or GEMINI_API_KEY) remains an optional AI Studio fallback.
Press Ctrl+R in the prompt composer, speak, and press Enter to stop
(or Esc to cancel). Recording stays in the TUI; it does not suspend or close
the session. On macOS, the resulting transcript is inserted at the cursor.
Dictation follows the active model provider: OpenAI models use OpenAI and Grok
models use xAI. Claude models have no transcription API, so they borrow a
locally configured OpenAI account and fall back to an xAI account when no
OpenAI credential exists. ChatGPT/Codex OAuth uses the subscription-backed streaming
protocol used by the official desktop app and falls back to its buffered
ChatGPT transcription route with the same recording if streaming fails. API
keys use the public OpenAI Realtime API. Both OpenAI paths can update the
composer while recording. Subscription auth is preferred when both OpenAI
credential types are configured. OpenAI credentials can come from
CODEX_ACCESS_TOKEN, CODEX_AUTH_JSON, $CODEX_HOME/auth.json (defaulting to
~/.codex/auth.json),
OPENAI_API_KEY, CODEX_API_KEY, or a managed OpenAI account.
For Grok models, dictation uses the configured xAI subscription or API-key
credential; set XAI_STT_LANGUAGE to override xAI's default en.
When an organization gateway is connected, the recording is sent only to the
gateway's authenticated /v1/audio/transcriptions endpoint. The gateway uses
its organization-managed transcription pool and streams partial transcripts
into the composer while recording. Compatible older gateways and interrupted
streams use the final-only upload on the same endpoint with the already
captured recording; dictation never falls back to local provider credentials.
Dictation is currently unavailable for OpenRouter and Gemini models.
Install Claude Code, authenticate it with a first-party Claude subscription, and select the provider:
claude auth login
agent-cli --provider claude-code --model sonnetThe integration keeps a claude -p process alive through the reusable
claude-agent-sdk-haskell
package. Claude Code executes its built-in tools; complementary harness tools
are exposed through an in-process MCP bridge and use the same host approval
policy as other providers. The harness renders events, persists the session,
and performs isolated local-summary compaction before restarting the Claude
continuation. --yolo auto-approves ordinary calls, but host catastrophic
command and Plan Mode safeguards remain enforced.
Anthropic's June 15, 2026 subscription-policy
update
says that Claude Agent SDK, claude -p, and third-party app usage currently
draw from Claude subscription usage limits. Anthropic's current
Agent SDK documentation
also says third-party developers need prior approval to offer Claude.ai login
or subscription rate limits in their products. Technical availability does
not replace that approval requirement; consult the linked documents for
current terms. See packages/agent-claude/README.md
for details.
Use /mcp to add, authorize, enable, or remove MCP servers from the session
UI, or configure them in ~/.haskell-agent/config.json. Paste a remote
https://… URL or a local stdio command; HTTP servers that need OAuth can be
authorized with i. agent-cli mcp list, add, enable, and disable
manage the same catalog from the command line. See the MCP guide
for the configuration schema, startup strategies, and tool exposure rules.
Press Cmd+K to open a compact configuration prompt over the current session,
then describe a change such as “add the MCP server at
https://example.com/mcp” or “connect my Grok account”. /meta <request> is
the keyboard-independent fallback.
Meta Console uses a private, tool-free planner with no coding transcript. Its typed plan is validated and previewed before execution, and the normal approval policy still applies. Secrets are requested only through masked host-owned prompts and are never returned to the planner. See the Meta Console guide for supported actions and safety details.
The built-in ask_secret tool reads secrets through a masked prompt and gives
the model only a private temporary-file path, keeping values out of chat and
tool arguments. Files are removed when the tool runtime closes.
The built-in show_image tool displays an image file (PNG, JPEG, GIF, BMP,
TIFF) inline in the conversation next to the tool call: Kitty, Ghostty,
WezTerm, and iTerm2 draw the bitmap natively, other terminals get a
true-colour text approximation. The image is shown to the user only; it is
not added to the model context.
To inspect a local image, Codex and Grok Build expose view_image. That
tool attaches PNG, JPEG, WebP, and non-animated GIF files to the next
model request. read_file remains text-only.
In interactive terminal sessions, render_chart displays static line, bar,
area, and scatter charts from the same validated chart documents used by the
macOS app. Ghostty and Kitty display PNGs directly; other terminals retain a
readable text summary. No plotting program or browser is required.
Fullscreen conversation history recreates cached previews from saved chart
documents. Hover and zoom are not supported in the terminal.
Why an independent harness matters, why code and Haskell are useful
foundations, and how types, effects, and verification could make agents safer
are discussed in IDEAS.md.
agent-cli / agent-telegram / future clients
|
agent-runtime
sessions | model catalog | turn execution | gateways
/ |
agent-accounts agent-tools
|
provider-neutral events
|
+------------------- agent-core -------------------+
| loop | tool contracts | approvals | agents | state |
+-------------------------+------------------------+
|
canonical Responses model
|
+---------------+---------------+---------------+---------------+---------------+
| | | | |
agent-openai agent-xai agent-openrouter agent-gemini agent-claude
| | | | |
OpenAI / ChatGPT xAI OpenRouter Gemini Claude Code
The provider-neutral loop sees typed turns, tool calls, tool results, usage, and streamed events. Provider packages own wire formats, authentication, transport, and provider-specific continuation. Presentation consumes the same events through renderer-independent state.
agent-connectivity wraps individual provider submissions with replay-safe
retry policy. On macOS it also uses NWPathMonitor to wake an interrupted
submission as soon as the network path recovers; other platforms retain the
portable polling fallback.
agent-runtime replaces agent-cli-runtime as the headless support
library shared by the terminal CLI, server, and gateways. Its
Agent.Runtime.* modules own session persistence and lifecycle primitives,
model configuration, provider-neutral request construction and turn execution,
database and MCP support, shared process resources, gateway support, and
neutral host contracts. Product-level provider
assembly, tool registration, and session orchestration still live in
Agent.CLI.Runtime.Orchestration.*; extracting this support library does not
make it a complete frontend-independent composition root.
Interactive parsing, rendering, and TTY state also remain in
agent-cli, so Cabal builds of gateway libraries do not depend on or rebuild
the terminal frontend. The packaged Telegram service still carries the
agent-cli executable as a runtime dependency because managed child sessions
launch that executable.
agent-core owns the provider-neutral loop, tool contracts, scheduling,
approvals, and shared state, but not concrete tool implementations.
agent-tools implements filesystem, shell, GHCi/code-mode, image, and
multi-agent tools against those contracts; core never depends on it.
agent-accounts owns credential storage, account selection, authentication,
and gateway credentials. agent-computer-use owns desktop input,
accessibility, and platform backends used by the CLI and native integration;
the runtime does not depend on it. These packages and the runtime have
no CLI/TUI dependency or frontend module imports.
Repository review/delivery and process-hardening code lives in the independent
agent-repository package. Native administration helpers and the Darwin
foreign-library bridge live in agent-native-bridge. Its ordinary Haskell
library uses the headless runtime and does not depend on the CLI. The Darwin
foreign library still uses the CLI turn runner and legacy composition entry points;
migrating that FFI boundary is deliberately deferred. The production CLI
does not depend on native-only integration code.
The resulting production rebuild change is recorded in the
package-split benchmark.
scripts/check-package-boundaries.sh checks source ownership and invokes
the Python 3 package-graph guard. The graph conservatively includes all
components and conditional dependencies, including the deferred Darwin FFI
edge, and rejects missing local packages and cycles.
Discovery and bounded import of Codex, Claude, Cursor, and Grok histories lives
in agent-external-session. The CLI re-exports its public facade while keeping
the provider-specific parsers independently testable and reusable by future
frontends.
agent-claude delegates its generic process transport, protocol decoding, and
session client to
claude-agent-sdk-haskell,
leaving subscription policy and Agent.Loop translation in the provider
adapter.
Model targets resolve independently to a provider transport and a model-facing dialect. OpenAI models use the Codex dialect, xAI models use the Grok Build dialect, Gemini uses the portable Responses dialect over Google's native Code Assist or GenerateContent API, and OpenRouter selects Codex, Grok Build, or a portable Responses dialect from the model family.
All compiler and package dependencies come from the pinned Nix flake.
nix develop
cabal test allFrom the development shell, repl opens the agent under GHCi. Edit the
harness, leave the running agent, reload the changed modules, and resume the
same session without rebuilding the executable.
See AGENTS.md for the complete development workflow, including
multi-package GHCi sessions, Nix package maintenance, and CLI testing.
MIT. See LICENSE.