Agent Rig System
Overview
A rig is a collection of riglets that provide knowledge and tools for AI agents. Rigs and riglets are packaged as Nix flake outputs, so they can both be used inside the project defining them and by other projects depending on it.
Core Concepts
Riglet
A riglet is executable knowledge packaged with its dependencies, as a Nix module:
- Metadata: When should this riglet be used, is it production-ready or experimental, etc.
- Knowledge: SKILL.md + detailed
references/*.mdfiles documenting processes and recipes - Tools: Nix packages needed to execute those recipes
- Configuration: Settings to adapt tools' behaviour to project context
Rig
A project-level structure that declares which riglets are active:
- Uses
buildRigto compose riglet modules - Builds combined tool environment declaratively
- Exposes riglets' tools and documentation
rigup
A Nix library and CLI tool: http://github.com/YPares/rigup.nix
rigup Nix library
Main functions:
buildRig: evaluates riglet modules and ensures they comply with the riglet schema used by rigup. Returns the rig as an attrset:{ toolRoot = <derivation>; meta = { <riglet> = {...}; }; docAttrs = { <riglet> = <derivation>; }; docRoot = <derivation>; home = <derivation>; shell = <derivation>; }resolveProject: inspects theriglets/folder of a project and itsrigup.tomlto find out which riglets and rigs it defines. It callsbuildRigfor each rig in therigup.tomlgenManifest: generates a markdown+XML manifest file describing the contents of a rig, primarily for AI agent's consumptionmkRiglib: creates a set of utility functions to be used to define riglet Nix modules
Defined in {{repoRoot}}/lib/default.nix.
rigup CLI tool
A Rust app. It provides convenient access to rig outputs, via commands like rigup build and rigup shell, and project scaffolding via rigup new. This tool is meant for the user primarily. Agents should not have to call it directly.
Defined in {{repoRoot}}/packages/rigup
Riglet Structure
Riglets are Nix modules with access to riglib helpers
Example Riglet
# First argument: the defining flake's `self`
# Gives access to `self.inputs.*` and `self.riglets.*`
# Use `_:` if you don't need it
self:
# Second argument: module args from evalModules
{ config, pkgs, lib, riglib, ... }: {
# Riglet-specific options (optional)
options.myRiglet = {
myOption = lib.mkOption {
type = lib.types.str;
description = "Example option";
};
};
# Riglet definition
config.riglets.my-riglet = {
# Dependency relationship/Inheritance mechanism: if B imports A, then whenever B is included in a rig, A will automatically be included too
imports = [ self.riglets.base-riglet self.inputs.foo.riglets.bar ... ];
# Tools can be:
# - Nix packages: pkgs.jujutsu, pkgs.git, etc.
# - Script paths: ./scripts/my-script (auto-wrapped as executables)
tools = [
pkgs.tool1
pkgs.tool2
./scripts/helper-script # Becomes executable "helper-script"
];
# Metadata for discovery and context
meta = {
description = "What this riglet provides";
mainDocFile = "SKILL.md"; # Where to start reading the docs (SKILL.md by default)
intent = "cookbook"; # What the agent should expect from this riglet
whenToUse = [
# When the AI Agent should read/use this riglet's knowledge, recipes and tools
"Situation 1" # or
"Situation 2" # or
...
];
keywords = [ "keyword1" "keyword2" ];
status = "experimental"; # Maturity level
version = "x.y.z"; # Semantic version of riglet's interface (configuration + provided methods, procedures, docs...)
disclosure = lib.mkDefault "lazy" # How much to show about riglet in manifest
# mkDefault makes it possible for end users to override this in their rigup.toml
};
# Documentation file(s) (Skills pattern: SKILL.md + references/*.md)
docs = riglib.writeFileTree {
"SKILL.md" = ...; # A main documentation file
references = { # Optional. To add deeper knowledge about more specific topics, less common recipes, etc.
# SKILL.md MUST mention when each reference becomes relevant
"advanced.md" = ...;
"troubleshooting.md" = ...;
};
};
# Files can be defined either as inlined strings or nix file derivations/paths.
# Folders can be defined either as nested attrsets or nix folder derivations/paths,
# so if you have a ready to use folder you can do:
#docs = ./path/to/skill/folder;
# Configuration files (optional) for tools following the
# [XDG Base Directory Specification](https://specifications.freedesktop.org/basedir/latest/)
configFiles = riglib.writeFileTree {
# Built from a Nix attrset
myapp."config.toml" = riglib.toTOML {
setting = "value";
};
# Read from existing file
myapp."stuff.json" = ./path/to/stuff.json;
# Inlined as plain text
myapp."script.sh" = ''
#!/bin/bash
echo hello
'';
};
# EXPERIMENTAL: Prompt commands (slash commands for harnesses like Claude Code)
promptCommands.my-cmd = {
template = "Do something specific with $ARGUMENTS";
description = "What this command does";
useSubAgent = false;
};
};
# EXPERIMENTAL: MCP (Model Context Protocol) servers
mcpServers.some-local-mcp.command = pkgs.my-mcp-server;
mcpServers.some-remote-mcp = {
url = "https://...";
useSSE = true; # false by default
};
}
The full Nix module schema of a riglet is defined in {{repoRoot}}/lib/rigletSchema.nix.
Examples of actual riglets: {{repoRoot}}/riglets.
Metadata
When defining a riglet, the meta section specifies its purpose, maturity, and visibility. See references/metadata-guide.md for comprehensive details on:
- meta.intent - Primary focus (base, sourcebook, toolbox, cookbook, playbook)
- meta.status - Maturity level (stable, experimental, draft, deprecated, example)
- meta.version - Semantic versioning of the riglet's interface
- meta.broken - Temporary non-functional state flag
- meta.disclosure - Visibility control (none, lazy, shallow-toc, deep-toc, eager)
Implementation Utilities
See references/riglib-utilities.md for details on helper functions available via riglib:
- riglib.writeFileTree - Convert nested attrsets to directory trees
- riglib.useScriptFolder - Convert folder of scripts into wrapped tool packages
riglib is defined in {{repoRoot}}/lib/mkRiglib.nix
Experimental Features
WARNING: These features are still experimental and their schema may change.
Prompt Commands
Riglets can define reusable prompt templates (slash commands) for agent harnesses like Claude Code:
promptCommands.analyze = {
template = "Analyze $1 for potential issues";
description = "Perform code analysis";
useSubAgent = false; # Whether to run in a sub-agent
};
Templates use standard Claude command syntax: $ARGUMENTS for all args, or $1, $2, etc. for specific positional arguments.
MCP Servers
Riglets can provide MCP (Model Context Protocol) servers to extend agent capabilities:
mcpServers.my-tools = {
command = pkgs.my-mcp-server; # Package that starts the server
};
WARNING: API still experimental.
Cross-Riglet/Flake Interaction
Advanced patterns for composing riglets together and sharing configuration. See references/advanced-patterns.md for:
- Sharing configuration via
config - Dependencies and inheritance via
imports - Using packages from external flakes
Defining Rigs in Projects
Recommended: Use rigup.toml
Add a rigup.toml file to your project root:
[rigs.default.riglets]
self = ["my-riglet"]
rigup = ["git-setup"]
[rigs.default.config.agent.identity]