
> Agent = Model + Harness. Nexo is the connective tissue linking RubyLLM to tools, sandboxes, skills, and runs.

A model alone forgets everything the moment a response ends. The harness is everything else. Nexo gives the RubyLLM ecosystem one cohesive front door with safe defaults — build a working agent in five lines without wiring anything.

---

## Compose, don't reimplement

Nexo does not rebuild skill loading, the tool-call loop, MCP, or structured output — those already live in the RubyLLM ecosystem (`ruby_llm` core, `ruby_llm-skills`, `ruby_llm-mcp`, `ruby_llm-schema`). Nexo **composes** them behind one front door and adds only the two pieces the ecosystem is missing:

- **Sandbox + Permissions seam** — a pluggable execution environment (virtual / local / remote / container) with explicit authorization gating. Default: `:virtual` + `:read_only`.
- **WorkflowRun lifecycle** — a finite-job primitive (runId, status, payload, result, inspectable event log) that nothing else in the ecosystem provides cleanly.

---

## Build an agent in five lines

Subclass `Nexo::Agent`, declare the pieces with class macros, and call `#prompt`. No sandbox, permission, or tool object is wired by hand, and nothing is vendor-specific — the agent runs on any `ruby_llm`-supported model (set `NEXO_MODEL`, e.g. a local `gemma3:12b` via Ollama, or a hosted model):

```ruby
require "nexo"

class CodeReviewer < Nexo::Agent
  model       ENV.fetch("NEXO_MODEL")   # any ruby_llm model — never a hardcoded vendor default
  sandbox     :local
  permissions :read_only

  instructions "You are a careful code reviewer. Read files and report issues. Do not write files."
end

CodeReviewer.new(cwd: "/path/to/repo").prompt("Review the auth module")
```

> **Safe by default:** agents start `:virtual` + `:read_only` — an untrusted model has zero host access until you explicitly opt in.

---

## Installation

Add to your Gemfile:

```ruby
gem "nexo_ai"
```

Or install directly:

```sh
gem install nexo_ai
```

In a Rails app, run the install generator to create the conventional layout and an initializer:

```sh
rails g nexo:install
```

```
      create  app/agents/.keep
      create  app/workflows/.keep
      create  app/skills/.keep
      create  config/initializers/nexo.rb
```

---

## The guides

| Guide | What's inside |
|-------|---------------|
| [Getting started](getting-started/) | install, configuration, first agent, unregistered/local models |
| [Sandboxes](sandboxes/) | virtual / local / remote / container + hardened defaults |
| [Permissions](permissions/) | modes, the gate, the MCP gate, `:ask`, `:approve` |
| [Tools](tools/) | ReadFile / WriteFile / Shell / Glob |
| [Loops](loops/) | RubyLLM vs AgentSDK, the turn-cap caveat |
| [Workflows](workflows/) | lifecycle, staging, artifacts, `run_agent`, tasks & actions |
| [Durable workflows](durable-workflows/) | checkpoint / suspend / resume |
| [Skills](skills/) | SKILL.md packages, gated tools |
| [MCP](mcp/) | `mcp` macro, fail-closed gate, transports |
| [Web](web/) | fetch tool + SSRF guard, search tool + injected backend |
| [Sessions](sessions/) | continuing, addressable memory |
| [Rails](rails/) | engine, `run_later`, broadcasting, generators |
| [Concurrency](concurrency/) | opt-in async, buffered emit, fiber servers |
| [Examples](examples/) | runnable scripts — offline and live |

---

## Requirements

- Ruby 3.3+
- [ruby_llm](https://github.com/crmne/ruby_llm) >= 1.16
- [ruby_llm-skills](https://github.com/kieranklaassen/ruby_llm-skills) — optional, only when you use the `skills` macro
- [ruby_llm-mcp](https://github.com/patvice/ruby_llm-mcp) — optional, only when you attach an MCP server with the `mcp` macro
- `ruby_llm-agent_sdk` — optional, only when you choose the Anthropic-oriented `Loops::AgentSDK` backend

---

## Status

**Early development.** The API is not stable. Nexo ships safe defaults and honest caveats — every escalation is an explicit opt-in, and every reduced guarantee is documented rather than silently dropped.

---

## Next steps

<div class="not-prose mt-8 grid grid-cols-1 gap-4 sm:grid-cols-2">
  <a href="getting-started/" class="group relative rounded-2xl border border-zinc-200 p-6 hover:border-[#50B1FD]/50 dark:border-zinc-800 dark:hover:border-[#50B1FD]/50 transition">
    <h3 class="font-sora font-semibold text-zinc-900 dark:text-white group-hover:text-[#50B1FD] transition">
      Get started
    </h3>
    <p class="mt-2 text-sm text-zinc-600 dark:text-zinc-400">
      Install Nexo, configure the harness, and build your first agent.
    </p>
  </a>

  <a href="examples/" class="group relative rounded-2xl border border-zinc-200 p-6 hover:border-[#50B1FD]/50 dark:border-zinc-800 dark:hover:border-[#50B1FD]/50 transition">
    <h3 class="font-sora font-semibold text-zinc-900 dark:text-white group-hover:text-[#50B1FD] transition">
      Examples
    </h3>
    <p class="mt-2 text-sm text-zinc-600 dark:text-zinc-400">
      Runnable scripts — offline primitives and live agents, MCP, and workflows.
    </p>
  </a>

  <a href="https://github.com/maquina-app/nexo" target="_blank" rel="noopener" class="group relative rounded-2xl border border-zinc-200 p-6 hover:border-[#50B1FD]/50 dark:border-zinc-800 dark:hover:border-[#50B1FD]/50 transition">
    <h3 class="font-sora font-semibold text-zinc-900 dark:text-white group-hover:text-[#50B1FD] transition">
      GitHub Repository
    </h3>
    <p class="mt-2 text-sm text-zinc-600 dark:text-zinc-400">
      Source code, issues, and the full guide set in the repo.
    </p>
  </a>

  <a href="https://rubygems.org/gems/nexo_ai" target="_blank" rel="noopener" class="group relative rounded-2xl border border-zinc-200 p-6 hover:border-[#50B1FD]/50 dark:border-zinc-800 dark:hover:border-[#50B1FD]/50 transition">
    <h3 class="font-sora font-semibold text-zinc-900 dark:text-white group-hover:text-[#50B1FD] transition">
      RubyGems
    </h3>
    <p class="mt-2 text-sm text-zinc-600 dark:text-zinc-400">
      Install the latest version from RubyGems.
    </p>
  </a>
</div>