Expand description
rig-harness: the harness of the rig coding agent, a Bevy app on the
rig_ecs kernel. It holds what the binary needs to run and be
relaunched (the session, the rig launcher protocol, how the agent was
started: Invoked) and the services every
plugin shares. Everything else, the terminal view, --print, /reload
and the built-in tools included, is a plugin crate in the repository’s
plugins/ folder, built only on this crate’s public API.
HeadlessPlugins is what a terminal app takes from Bevy, and
RigHarnessPlugins is the harness. The launcher’s generated main.rs
adds the plugins plugins.toml lists with load. The error handler is
the application’s to set:
use rig_harness::load;
use rig_harness::prelude::*;
#[derive(Default)]
struct HelloPlugin;
impl Plugin for HelloPlugin {
fn build(&self, _app: &mut App) {}
}
fn main() -> AppExit {
let mut app = App::new();
app.set_error_handler(rig_harness::error::warn)
.add_plugins((HeadlessPlugins, RigHarnessPlugins));
load::<HelloPlugin>(&mut app, "rig-hello", "path plugins/hello");
app.run()
}plugin_guide is the guide to writing a plugin; rig plugin new <name>
makes one.
Re-exports§
pub use describe::run;pub use rig_core;pub use rig_ecs;pub use rig_harness_protocol as harness_protocol;pub use rig_memory;pub use rig_tools;
Modules§
- agent_
title - An agent’s title, saved where a library program reads it.
- ask
- Questions for the user that any front answers: an approval, a choice or a
line of text. An
Askis an open effect, recorded like any and answered by deciding it (Decision) withAnswer::outcome; the first decision wins. A plugin that waits on the answer spawns it as a hold (HoldOf(call)) on what it asks about, so stopping the turn closes it in every front at once. - clock
- Waking the loop that sleeps while nothing happens. Bevy’s clock, which
timers and delayed commands run on, stops while the machine sleeps; a
WakeAtis a wall-clock instant instead. Once it passes, the entity getsDueinFirst, and the headless loop sleeps no longer than until the earliest one. A plugin reacts toAdd<Due>, and arms the next time by inserting a newWakeAt, which takesDueaway. AKeepAwakekeeps the loop running at its pace while it lives. - commands
- Slash commands. A command is an entity: its
Nameis the/nametyped, itsSlashCommandsays what it does, and it is the one-shot system that runs it, so despawning it unregisters both. A plugin adds one withAppCommandsExt::add_command, a system that reads theCommandArgs, such as one that triggers an event. - describe
- How the built agent tells the
riglauncher what its plugins add to the command line: their commands, their options and the secrets they ask for (AgentDescription). The launcher asks after each build, by running the binary withenv::DESCRIBEnaming a file;run, which the generatedmain.rsends with, then builds the app (every plugin’sbuild,finishandcleanup), writes the report to that file and exits without running a frame. While it describes, no front takes the run, so no front sets itself up, and the session has no directory. - error
- Bevy’s error handlers, for
App::set_error_handler:warnlogs a failing system, observer or command instead of stopping the app. Error handling for Bevy systems, commands, and observers. - host
- What the binary needs to run as a process and be relaunched: the
session directory and its log, the loop and its signals, the
riglauncher protocol with the plugins’ options and fronts, and why the app exits. - main_
agent - The agent the user talks to when no agent is named, such as the one a
front shows first and
--printsends to: of the agents nothing spawned, the first by id; and the agent the user looks at (ShownAgent). - per_
call - Tools whose every call is built for where it works
(
AppPerCallExt::add_tool_per_call): the app’s workspace, the calling agent’sWorkDiror else theProjectRoot, and, for a tool that reports its output as it runs, where it reports it (CallPlace). A plugin builds such a call somewhere else, such as on an overlay of the workspace, withPerCallTools. - pick
- Choices for the user that any front shows and answers: a plugin’s
Picker, a filterable list on an entity of the plugin’s. Inserting a newPickerreplaces what it shows, and despawning it closes it. A front that shows pickers (Query<(Entity, &Picker)>) triggersPickon the one the user picked from, or closed: the harness then runs the item’s command, for the picker’s agent or else the agent the user is looking at (ShownAgent), triggersPickedon it, and despawns it. A picker may take several items (Picker::multiple): the harness runs each one’s command in list order. AChosenholds the items picked and the text typed, either or both. A front answers an openAskthe same way: aPickon it decides the answer, a question’s choices with the note typed on them. - plugin_
data - Where a plugin keeps files of its own, by how long they live:
PluginData, in every run. A plugin names its files under its own name, such asvim/registers.json. - plugin_
guide - Writing a plugin for the rig agent: the rules every plugin follows, then a short, copy-ready example per extension point.
- prelude
- What a plugin needs, so a typical one imports only this: the kernel’s
prelude and the harness’s services. A plugin crate’s own types come from
that crate, such as the terminal view’s panels from
rig-tui. - progress
- How far a running call got, for every front:
ToolProgress, and the output a running call’s tool reports as it works (CallOutput). - secrets
- Secrets a plugin needs before any front runs, such as the passphrase of an encrypted session store, which opens before the session is restored.
- services
- What every plugin shares about the process it runs in, as resources:
the
RIG_HOMElayout (RigHome), the project the session works on (ProjectRoot) and the directory an agent works in when not that one (WorkDir), how child processes start (Processes), and the tokio runtime rig’s HTTP requests run on (TokioRuntime). Each is taken from the environment unless the app inserted one first, which is how a test points a plugin at a directory of its own; a plugin that should also work in an app without the harness’s plugins inits the ones it reads (app.init_resource::<ProjectRoot>()). - settings
- The user’s settings for plugins:
RIG_HOME/settings.toml, one table per plugin. A plugin names its table and a type that reads it, and gets that type as a resource, itsDefaultwhere the user set nothing. A table that does not read as the type leaves the default and says why at startup, as does a file that is not TOML. - successor
- Following an effect to its successor. Any plugin may take an effect
over by spawning a successor it is
SupersededBy, such as a watchdog sending a stalled call again (resend): the old effect then settles as superseded, with no outcome applied. The plugin that owns the effect, and waits for its outcome by a marker of its own, follows it with the kernel’sfollow_successor, so the successor’s outcome is the one it takes. - timings
- How long each system ran, as data:
SystemTimings, read per plugin throughPluginTimings. It is filled when the harness is built with itstracefeature, which turns on Bevy’s spans around every system and schedule run; a plugin crate turns it on by depending on rig-harness withfeatures = ["trace"]. The spans are info level, so aRUST_LOGthat setsbevy_ecsbelow info leaves it empty. A run is charged to the plugin that added the system or observer (PluginSystems,ProvidedBy), and kept with the schedule it ran in: a run inAgentPass(a stage system, or an observer its commands set off) is work an agent’s pass waited on. - watch
- Watching files. An entity with a
FileWatchon a file or a directory gets aFileChangesmessage naming the files there when it was armed, then one for each batch of files created, changed or removed under it, as the system reports them, and the loop is woken for each; despawning it, or removing theFileWatch, stops the watch. A plugin that reloads templates or skills from a directory watches it, and reads them on its firstFileChanges, so no file made in between is missed. - workspace
- The workspace the agent works in:
ProjectWorkspace.
Structs§
- App
Appis the primary API for writing user applications. It automates the setup of a standard lifecycle and provides interface glue for plugins.- Headless
Plugins - What a terminal app takes from Bevy where a windowed one has
DefaultPlugins: Bevy’sMinimalPluginswith task pools sized for an agent and the frame count and clock, the log written to the session with its warnings and errors passed on as data, a clean exit on SIGINT, SIGTERM and SIGHUP, and in place of Bevy’sScheduleRunnerPlugina loop that runs the schedules on the main thread and sleeps untilWaked or until the clock’s next deadline. Added beforeRigHarnessPlugins, so the kernel runs on its clock; a windowing plugin added later throughwindowedsets its own runner in place of this loop (seeplugin_guide). - Keeps
- What a plugin keeps with the session, on the entity
loadspawned for it: the saved values it owns, by their saved key (the type path, such asmy_plugin::Counter, or a stable one such asrig::model), and its folders of session files inPluginData::session, such asvim. A plugin says so inbuild,finishorcleanup(AppKeepsExt); nothing infers it. A saved value no plugin keeps is the kernel’s or the harness’s, or one whose plugin did not say. - Plugin
Entity - The entity
loadspawned for the pluginP, for whatPspawns while the app runs. - Plugin
Source - Where a plugin comes from, on the entity
loadspawns for it. - Plugin
Systems - Which plugin added each schedule system, by the system’s name and its
schedule’s label (such as
AgentPass), asloadsaw it. Two plugins that add a system of the same name to one schedule are told apart by neither; a system a plugin adds later, while the app runs, is no plugin’s. - Provided
By - The plugin that spawned this entity.
- Provides
- What a plugin spawned.
- RigHarness
Plugins - The harness: the session and its log, the kernel
(
rig_ecs::AgentPlugin,rig_ecs::session_log::SessionLogPlugin), the launcher protocol, and the services every agent uses: slash commands, the clock the loop sleeps by, file watches, the questions and pickers every front answers, and tool progress. Everything else is a pluginplugins.tomllists, which can leave it out. - SavedAs
- A saved value’s key, as
AppKeepsExt::saved_asrecorded it.
Enums§
- AppExit
- A
Messagethat indicates theAppshould exit. If one or more of these are present at the end of an update, the runner will end and (maybe) return control to the caller.
Constants§
- PLUGIN_
GUIDE - Where the plugin guide (
plugin_guide) is on disk, for an agent that reads it: in this crate’s own source, from a checkout or from crates.io alike.
Traits§
- AppKeeps
Ext - Saying what a plugin keeps with the session, in its
build,finishorcleanup, onto itsKeeps. A plugin added withoutloadhas no entity to say it on, and nothing is recorded.
Functions§
- check_
stages_ at_ start - Shows each of the app’s
stage_conflictsas a warning notice at its start. The generatedmain.rsadds it to a debug build. - load
- Adds
P, unless the app has it already (another plugin added it), as the generatedmain.rsadds each pluginplugins.tomllists: with an entity of its own, named after it, frompackageatsource. - stage_
conflicts - Each pair of systems of one
AgentPassstage that use the same data, one writing it, with no order between them, so which runs first is chance: one line each, naming their plugins (by type, orthe harnessfor the harness’s, the kernel’s and Bevy’s own), the systems and the data. It initializes the agent loop, as the loop’s first run would; an app without one has none.rig plugin check --buildreports these for the pluginsplugins.tomllists, and a debug build at its start (check_stages_at_start). - task_
pools - Bevy’s pools sized for an agent rather than a game. Model calls stream
on the IO pool and tool calls run on the async compute pool, each with
2 to 4 threads, so a few agents’ calls run side by side; blocking tool
work runs on threads of its own through
prelude::blocking. Bevy’s own systems keep the rest of the cores.HeadlessPluginssets them; a test app sets them too, so it runs its calls as the agent does. - windowed
plugins, such as Bevy’sDefaultPlugins, without whatHeadlessPluginsalready sets: the log, the task pools, the frame count, the clock, the signal handler and the loop. Its windowing plugin then runs the loop;plugin_guideshows how a window plugin wakes it.