Getting started
Install Nexo, configure the harness with safe provider-neutral defaults, and build your first agent in five lines.
Install Nexo, configure the harness in one place, and build your first agent. Defaults are safe and provider-neutral — there is intentionally no hardcoded model.
Installation
Add to your Gemfile:
gem "nexo_ai"
Or install directly:
gem install nexo_ai
In a Rails app, run the install generator to create the conventional layout and an initializer:
rails g nexo:install
create app/agents/.keep
create app/workflows/.keep
create app/skills/.keep
create config/initializers/nexo.rb
require "nexo" works in plain Ruby with no Rails loaded.
Configuration
Configure the harness in one place with Nexo.configure:
Nexo.configure do |config|
config.default_model = ENV["NEXO_MODEL"] # provider-neutral: no default
config.default_sandbox = :virtual # :virtual | :local | :docker | :apple | a Hash | a Sandbox
config.default_permissions = :read_only # :read_only | :auto | :ask | :approve
config.skills_path = "app/skills"
config.concurrency = :threaded # :threaded | :async (opt-in fiber offload)
config.max_in_flight = 8 # Nexo.concurrent fan-out bound
config.buffer_workflow_events = false # buffer + flush-once workflow events
end
Nexo.config.default_sandbox # => :virtual
Nexo.config.default_permissions # => :read_only
Nexo.config.default_model # => nil unless set
There is deliberately no hardcoded model — you set NEXO_MODEL (or default_model) to any ruby_llm-supported model id.
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):
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")
Defaults are safe: an agent with no sandbox/permissions declared gets the in-memory :virtual sandbox and :read_only permissions, so an untrusted model has zero host access until you explicitly opt in.
Safe by default: agents start
:virtual+:read_only— an untrusted model has zero host access until you explicitly opt in.
Unregistered models — local tags, self-hosted, brand-new releases
ruby_llm normally validates a model id against its bundled models.json registry and infers the provider from it. A local Ollama tag (gemma3:12b), a self-hosted build, or a model newer than the installed registry isn’t listed there — so declare the provider explicitly and set assume_model_exists to skip the registry lookup:
class LocalReviewer < Nexo::Agent
model "gemma3:12b"
provider :ollama # required once the registry lookup is skipped
assume_model_exists true # opt out of models.json validation
instructions "You are a careful code reviewer."
end
Both are class macros with the same reader/writer convention as model. provider is passed straight through to RubyLLM.chat; assume_model_exists defaults to false (registry validation on). Setting assume_model_exists without a provider raises Nexo::ConfigurationError — ruby_llm can’t infer a provider once the lookup is skipped.
Where to next
- Sandboxes — the four execution environments and hardened defaults.
- Permissions — the capability gate and the four modes.
- Examples — runnable scripts including a local-Ollama code reviewer.