Skip to content

matteing/opal

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 

History

67 Commits
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

โœฆ Opal

A minimal agent harness built with the magic of Elixir.

Opal is two things:

  • A minimal coding agent CLI you can use to build things.
  • An idiomatic Elixir library you can drop into your app to get an agent system.

It features built-in tools, an MCP host, support for Agent Skills, and a JSON-RPC transport for cross-language integrations.

What can it do?

Right now, Opal can:

  • Edit files โ€” reads, writes, and applies targeted edits efficiently.
  • Run shell commands โ€” executes builds, tests, linters, etc.
  • Debug and fix โ€” can diagnose issues and apply fixes, though expect some rough edges.
  • Parallelize work โ€” sub-agents are cheap OTP processes, so it can split tasks up easily.
  • Ask questions โ€” will ask for clarification when planning instead of guessing.

Adjust expectations; it's a hobby project. There's no permission or approval system yet โ€” the agent can run any shell command and write to any file in your working directory. No guardrails, no sandbox. Use it on things you can afford to break. See disclaimer.

In library usage, the harness can be cleanly integrated into Elixir (or other language) systems. When integrating with Elixir, you get no serialization boundary (just Erlang message passing).

You could theoretically also network these nodes together and have agents talking to agents!?

Installing

npm i -g @unfinite/opal
opal

Or as an Elixir dependency: {:opal, "~> 0.1"}

See the installation guide for authentication, API keys, configuration, and GitHub Enterprise setup.

What's interesting about this?

Live introspection. Connect to a running agent from another terminal and stream every event in real time โ€” what it's thinking, which tools it's calling, memory usage, the works. Under the hood, Elixir sits on the Erlang VM (the BEAM), which has built-in node-to-node networking. That means zero extra infrastructure for remote debugging.

Lightweight sub-agents. Spawn a child agent with its own context, tools, and model. It runs in parallel, fully isolated. If the parent dies, children are cleaned up automatically. This is OTP's supervision tree โ€” a battle-tested pattern for managing process lifecycles โ€” doing the heavy lifting. No thread pools, no manual resource cleanup.

Redirect the agent mid-flight. Call Opal.steer(agent, "focus on tests instead") and the agent picks it up between tool calls. This works because every Erlang process has a mailbox โ€” a built-in message queue. The agent loop checks it between steps. No polling, no callback chains.

Embeddable as a library. Add {:opal, ...} to your Elixir deps and the full agent system runs inside your app. Since it's all Erlang processes, there's no sidecar, no serialization โ€” just message passing. Or consume it over JSON-RPC from any language. See the SDK docs.

What you get

  • Interactive TUI โ€” fullscreen terminal chat (React/Ink) with streaming, model picker, thinking display
  • 8 built-in tools โ€” read_file, write_file, edit_file, shell, sub_agent, tasks, use_skill, ask_user
  • MCP host โ€” auto-discovers servers from .vscode/mcp.json and friends; stdio, SSE, streamable HTTP
  • Multiple providers โ€” GitHub Copilot + anything ReqLLM supports (Anthropic, OpenAI, Google, etc.)
  • Auto-compaction & extended thinking โ€” LLM-powered summarization near context limits, configurable thinking levels
  • Event system โ€” Registry-based pub/sub, subscribe from any process

What's in here?

Project What it is
core/ The Elixir SDK โ€” agent engine, tools, providers, sessions, MCP bridge, RPC server. Embeddable in any supervision tree.
cli/ React/Ink terminal UI + typed TypeScript client SDK. Talks to core over JSON-RPC stdio. Published as @unfinite/opal on npm.

See the full architecture docs for the process tree, request flow, and supervision model.

CLI

opal                                       # interactive TUI
opal --model anthropic/claude-sonnet-4     # choose a model
opal -C /path/to/project                   # set working directory
opal --auto-confirm                         # skip tool confirmations
opal --debug                                # enable debug feature/tools for this session

Providers

Opal supports two provider paths:

Provider What it connects to Auth
GitHub Copilot Claude, GPT-4o, Gemini, Grok via Copilot API GitHub OAuth (device flow, guided on first run)
Direct API Anthropic, OpenAI, Google, Groq, xAI, AWS Bedrock, OpenRouter, and more Standard API keys (ANTHROPIC_API_KEY, etc.)

GitHub Copilot is the recommended provider โ€” it's what Opal is developed and tested against.

The model string controls which provider is used:

opal --model claude-sonnet-4           # Copilot (default when no prefix)
opal --model anthropic:claude-sonnet-4 # Direct Anthropic API
opal --model openai:gpt-4o            # Direct OpenAI API

Direct API support is powered by ReqLLM. See the full provider docs for model discovery, API key setup, and custom providers.

Using Opal as a library

Add it to your supervision tree and you get everything โ€” no external process, no serialization. See the SDK docs for the full API.

{:ok, agent} = Opal.start_session(%{
  system_prompt: "You are a helpful coding assistant.",
  working_dir: "/path/to/project"
})

:ok = Opal.prompt(agent, "List all Elixir files")
:ok = Opal.steer(agent, "Actually, focus on the test files")
:ok = Opal.set_model(agent, "copilot/claude-sonnet-4")
:ok = Opal.stop_session(agent)

Observability

Any process can subscribe to agent events in real time via Registry:

Opal.Events.subscribe(session_id)

receive do
  {:opal_event, ^session_id, {:message_delta, %{delta: text}}} ->
    IO.write(text)
  {:opal_event, ^session_id, {:tool_execution_start, %{name: name}}} ->
    IO.puts("Running tool: #{name}")
  {:opal_event, ^session_id, {:agent_end, _}} ->
    IO.puts("Done.")
end

Development

nx run-many -t deps       # install deps
nx run cli:dev             # run TUI in dev mode
pnpm dev -- --debug        # run pnpm dev with debug feature/tools enabled
nx run-many -t test        # tests
pnpm lint && pnpm format   # lint & format
pnpm inspect               # ooooo this is a cool one, it'll connect you via iex to a running dev mode instance

Principles

  • OTP first. If there's an Erlang primitive for it, use that instead of building something new.
  • Minimal but useful. Small core, big punch. Ship what matters, skip the rest.
  • Research-driven. Stay current with the latest work on model adherence and agent outcomes.
  • Cross-platform. Windows at work, macOS at home. Both are first-class.

Why I built this

I wanted to understand how agent harnesses actually work โ€” not just use one, but build one from the ground up. I studied Pi and the more I stared at the problem โ€” long-running loops, concurrent tool execution, process isolation, sub-agent orchestration โ€” the more it looked like Erlang/OTP. So I built it.

Sub-agents? Processes. Steering? Mailbox. Fault isolation? Supervision tree. Live debugging? Erlang distribution. I didn't have to build any of that. The language did that.

Future plans

  • A more fully featured TUI
  • Proper SDK docs, NPM package
  • Random gaps in functionality that come through!
  • Subagents + agents talking to each other through message passing?
    • subagent X asked subagent Y a question
    • not sure if that would even work but whatevs
  • A toy OpenClaw reimplementation using Opal

Disclaimer

This is a hobby project. I work at Microsoft Azure, and our GitHub Copilot subscription provides the LLM access I use for development.

This project is not affiliated with, endorsed by, or related to my employer in any way. Neither are my opinions, of which there are many ;)

And from my beloved past at XDA Forums:

#include <std_disclaimer.h>

/*
* Your warranty is now void.
*
* I am not responsible for bricked devices, dead SD cards,
* thermonuclear war, or you getting fired because the alarm app failed. Please
* do some research if you have any concerns about doing this to your device
* YOU are choosing to make these modifications, and if
* you point the finger at me for messing up your device, I will laugh at you.
*
* I am also not responsible for you getting in trouble for using any of the
* features in this ROM, including but not limited to Call Recording, secure
* flag removal etc.
*/

References

Standing on the shoulders of giants. Other references (papers, projects) are in the relevant documentation files.

  • Pi: The best open-source harness, huge source of inspiration
  • oh-my-pi: An awesome customization of Pi with so many goodies and tricks

License

MIT โ€” Sergio Mattei

About

๐Ÿ”ฎ A minimal coding agent in Elixir

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Contributors 4

  •  
  •  
  •  
  •