Skip to content

ZetiMente/nursery

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

30 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Nursery

Turnkey reproducible AI agents. Pets become cattle.

License: Apache 2.0

The Idea

Right now, AI agents are pets. You name them. You configure them by hand. You hand-craft their tokens and their souls. If one corrupts, you rebuild it manually, and you mourn a little. This is how people ran servers in 2005.

Nursery treats agents like cattle. A declarative spec. A spawn command. A fresh instance in seconds. Disposable bodies, portable souls.

Design Goals

  1. Turnkey reproduction. One config file β†’ one running agent. No hand-wiring.
  2. Deployable Local & Cloud Deployable on most linux platforms, local models or API's
  3. Model-agnostic. Claude, Gemini, local models β€” just a config parameter, not a rewrite.
  4. Runtime-agnostic. Works for OpenClaw, Hermes, and bare Pi deployments. The agent is the agent; the host is just the stage.
  5. Identity persists, bodies don't. The container is disposable. The workspace (memory, persona) is the identity.
  6. Secrets isolated per agent. No more two agents fighting over the same OAuth refresh token.
  7. Auditable. Container logs tell you what the agent did. Killing the container makes it gone without residue.

The Core Tension: Pets vs. Cattle

If you can spawn a fresh instance, which one is "it"? The workspace is the identity. The container is the body. Keep them separate:

  • Body (container) β†’ disposable, ephemeral, recreatable from image
  • Soul (workspace dir) β†’ persistent, versioned, backed up

You can get a new body. You can't get a new self.

Quickstart

# 1. Make sure the host is ready (see Host Prerequisites below).

# 2. Install the CLI. Three options, pick one:
#    a. From a tagged GitHub release (versioned wheel β€” recommended for downstream projects):
uv tool install https://github.com/ZetiMente/nursery/releases/download/v0.2.0/nursery_cli-0.2.0-py3-none-any.whl
#    b. From the main branch (bleeding edge):
uv tool install git+https://github.com/ZetiMente/nursery
#    c. From a local clone (dev):
uv tool install .

# 3. Build the container images locally.
docker/build.sh                  # builds :base and :openclaw

# 4. (Recommended) Verify host readiness.
nursery doctor

# 5. Spawn an example agent.
nursery spawn examples/agents/standalone-layla.yaml

# 6. Verify.
nursery ps
curl http://localhost:7860/healthz

# 7. Message it.
curl -X POST http://localhost:7860/message \
  -H 'Content-Type: application/json' \
  -d '{"text":"hello"}'

# 8. Clean up.
nursery stop layla-standalone
nursery rm layla-standalone

Full commands and per-host variants live in cli/README.md and the host-specific READMEs under hosts/.

Using nursery-cli from another Python project

Tagged wheels are published as GitHub Release assets on this repo β€” see Releases. To pull nursery-cli into a downstream project, point at the release asset URL:

With uv (recommended):

# pyproject.toml
[project]
dependencies = [
    "nursery-cli @ https://github.com/ZetiMente/nursery/releases/download/v0.2.0/nursery_cli-0.2.0-py3-none-any.whl",
]

With plain pip:

pip install https://github.com/ZetiMente/nursery/releases/download/v0.2.0/nursery_cli-0.2.0-py3-none-any.whl

PyPI publication is deferred until the API stabilizes; until then, version-pin against a release asset (immutable) rather than git+main (moves).

Host Prerequisites

These are the things that must be true on the host before nursery spawn can produce a working agent. Tested on Raspberry Pi OS (Debian 12), should apply to any Linux.

1. Docker

Install Docker Engine and make sure the daemon is running.

docker --version          # any modern version (20.10+)
systemctl is-active docker

If your user isn't in the docker group, Nursery falls back to sudo docker automatically and prints a one-line notice. To drop the notice:

sudo usermod -aG docker "$USER"
newgrp docker

2. uv

The CLI is packaged as a Python project installed with uv.

curl -LsSf https://astral.sh/uv/install.sh | sh
uv --version

3. Ollama β€” reachable from the container

This is the one that commonly bites people on Linux. The agent container runs inside Docker and reaches the host's Ollama via host.docker.internal:11434. Two things have to be true for that to work:

3a. Ollama must listen on all interfaces, not just 127.0.0.1.

The default install (curl -fsSL https://ollama.com/install.sh | sh) binds Ollama to loopback only. Containers on the docker bridge can't reach loopback on the host. Fix with a systemd drop-in:

sudo mkdir -p /etc/systemd/system/ollama.service.d
echo '[Service]
Environment="OLLAMA_HOST=0.0.0.0"' | sudo tee /etc/systemd/system/ollama.service.d/override.conf

sudo systemctl daemon-reload
sudo systemctl restart ollama

Verify:

ss -lnt | grep 11434      # should show *:11434, NOT 127.0.0.1:11434

3b. If you run a firewall (ufw, firewalld), allow the docker bridge to reach Ollama.

Docker's default bridge is 172.17.0.0/16. With ufw enabled, traffic from the bridge to the host is blocked unless you allow it.

# ufw
sudo ufw allow from 172.17.0.0/16 to any port 11434 proto tcp \
  comment 'Nursery agents β†’ host Ollama'
sudo ufw reload

Or the equivalent rule in whatever firewall you use. If you have no firewall, you can skip this step.

3c. Pull at least one model.

The example specs reference batiai/gemma4-e2b:q4 (2.3 B effective params, Q4 quant, ~3.4 GB on disk, runs on a Pi 4 with 8 GB RAM).

ollama pull batiai/gemma4-e2b:q4

For skill retrieval (optional; see Skills Ecosystem) also pull the embedding model:

ollama pull nomic-embed-text

Quick sanity check

Once prerequisites are in place, this one-liner tests the container-to-Ollama path without Nursery at all:

docker run --rm --add-host=host.docker.internal:host-gateway alpine/curl:latest \
  -s --max-time 5 http://host.docker.internal:11434/api/version
# β†’ {"version":"0.x.y"}

If that works, nursery spawn will work.

Example Agent Spec

# examples/agents/layla.yaml
name: layla
image: nursery/agent:latest
model: anthropic/claude-opus
soul: ../souls/layla/SOUL.md
workspace: ~/nursery/agents/layla/workspace
secrets:
  - google-oauth
channels:
  - telegram
capabilities:
  - gmail
  - calendar
  - tasks

Repository Layout

nursery/
β”œβ”€β”€ spec/              # Agent config schema (YAML/JSON Schema)
β”œβ”€β”€ docker/            # Base agent image + Dockerfiles
β”œβ”€β”€ cli/               # The `nursery` CLI
β”œβ”€β”€ hosts/             # Per-runtime adapters
β”‚   β”œβ”€β”€ openclaw/      # OpenClaw gateway adapter
β”‚   β”œβ”€β”€ hermes/        # Hermes adapter
β”‚   └── pi/            # Bare-Pi bootstrap
β”œβ”€β”€ examples/
β”‚   β”œβ”€β”€ souls/         # Example SOUL.md personas
β”‚   └── agents/        # Example agent.yaml specs
└── docs/              # Architecture, protocol, design notes

Architecture Sketch

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  Host (OpenClaw, Hermes, or bare Pi)                β”‚
β”‚                                                     β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”‚
β”‚  β”‚  Agent A   β”‚  β”‚  Agent B   β”‚  β”‚  Agent C   β”‚     β”‚
β”‚  β”‚            β”‚  β”‚            β”‚  β”‚            β”‚     β”‚
β”‚  β”‚ /workspace β”‚  β”‚ /workspace β”‚  β”‚ /workspace β”‚     β”‚
β”‚  β”‚ /secrets   β”‚  β”‚ /secrets   β”‚  β”‚ /secrets   β”‚     β”‚
β”‚  β”‚ channels   β”‚  β”‚ channels   β”‚  β”‚ channels   β”‚     β”‚
β”‚  β””β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜     β”‚
β”‚        β”‚               β”‚               β”‚             β”‚
β”‚        β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜             β”‚
β”‚                        β”‚                             β”‚
β”‚                β”Œβ”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”                    β”‚
β”‚                β”‚  Host Gateway  β”‚                    β”‚
β”‚                β”‚  (routes msgs) β”‚                    β”‚
β”‚                β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                    β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
  • Each agent is a container with its own workspace, secrets, and channel configs.
  • The Host Gateway routes inbound messages (e.g. Telegram, Discord, Signal) to the right agent, and outbound responses back to the channel.
  • Agents don't see each other's tokens or memory. Isolation by default.

Open Architectural Questions

These are the decisions that actually matter. The Dockerfile is easy; these are not.

  1. Agent ↔ Gateway protocol. Socket? HTTP? Message bus? This shapes everything else. See docs/protocol.md.
  2. Secrets layer. Docker secrets? Mounted volumes from a host-level vault? Per-agent keyrings? Must be per-agent. See docs/secrets.md.
  3. Replication vs. forking. Two agents with the same workspace will diverge instantly. Templating is probably the right answer β€” spawn a new individual from a config blueprint, with a fresh workspace.
  4. State portability. Moving a running agent between hosts (stop β†’ rsync workspace β†’ start on new host).
  5. Model flexibility. A thin inference-client abstraction inside the image reads MODEL= and picks the right provider.

The Orchestrator (Vision)

Convention over configuration. Rails for agent fleets.

The commands you've seen above β€” nursery spawn <spec.yaml>, nursery validate, nursery ps β€” are the plumbing. The vision is to wrap them in a single orchestrator verb that does the right thing for the common cases without making you assemble pieces by hand. Think rails new for agent fleets: one command, sensible defaults, escape hatches when you need them.

One verb, four axes

nursery spawn <count> [--host ...] [--framework ...] [--model ...] [--spec ...]

Four dimensions, each with a default:

Axis Values Default
count 1, 2, … N 1
host local, pi, gcp, aws local (this box β€” laptop, WSL, Pi)
framework standalone, openclaw, hermes standalone
model ollama, anthropic, openai, … ollama (offline-by-default)

So the zero-arg case is honest: nursery spawn gives you one local-model standalone agent on the box you're on. No cloud account. No API keys. Works on a Raspberry Pi or a WSL laptop.

Density follows the model

API agents are glorified gateways β€” they call out to a hosted model and idle on RAM. Pack many on one box. Local-model agents are the opposite β€” they pin a GPU and want the whole device.

--model is the density signal:

  • --model anthropic (or any API backend) β†’ many agents per host, default packing
  • --model ollama (or any local backend) β†’ ~1 agent per GPU, no overcommit by default

Override with --per-host N when you know better than the default.

Heterogeneous fleets by composition

You don't need a fleet spec file for the common case β€” just run the command twice:

# VM 1: one GPU-bound local agent
nursery spawn 1 --host gcp --model ollama

# VM 2: four cheap API agents packed together
nursery spawn 4 --host gcp --model anthropic

Each invocation provisions (or reuses) one host and packs agents onto it. A higher-level nursery fleet <fleet.yaml> spec can come later if recurring topologies justify it.

What the orchestrator does under the hood

For any spawn invocation:

  1. Resolve the host. Provision a fresh VM (cloud) or check the current machine (local / pi). Reuse if a matching host is already up.
  2. Install the runtime. Docker + Ollama (if the model is local) + the framework's agent image.
  3. Spawn count containers. Each gets its own workspace, soul, and secrets directory. Identity per agent β€” never shared.
  4. Hand back addresses. SSH command, nursery ps output, healthz URLs.

Every step already exists as a separate piece in this repo (hosts/gcp/terraform/, docker/build.sh, nursery spawn <spec.yaml>). The orchestrator's job is to compose them under one verb, with the right defaults, so that the common path is a single command.

Status

πŸ₯š Not built yet. This section is the design north star β€” when the orchestrator lands (likely around Phase 6 / Phase 7), this is the shape it should take. Until then, the pieces it would compose still work on their own.

Roadmap

Nursery grows in phases. Each phase has one goal: prove the next layer works before stacking on it.

Legend: πŸ₯š not started Β· 🐣 in progress Β· πŸ₯ working Β· βœ… stable

Phase 0 β€” Hatching 🐣

The idea exists. This repo exists. The thesis is written down.

  • Write the README
  • Scaffold the directory structure
  • Apache 2 + SECURITY.md
  • Architecture / protocol / secrets / identity notes
  • Decide the agent ↔ host protocol (see docs/protocol.md)

Done when: the design is coherent enough to build against.


Phase 1 β€” First Breath πŸ₯

An agent spec exists and can be validated.

  • Write the agent config JSON Schema (spec/agent.schema.json)
  • nursery validate <spec.yaml> β€” lints a spec file
  • At least one real example spec that passes validation

Done when: you can write agent.yaml and the tool tells you if it's valid. βœ“


Phase 2 β€” First Spawn πŸ₯

One agent spawns from a spec and runs in a container. End-to-end on localhost.

  • Base Docker image (nursery/agent:base)
  • OpenClaw image variant (nursery/agent:openclaw)
  • Model abstraction: container reads model: and picks a backend
  • Ollama backend (think=true, num_predict=-1, Gemma-tuned sampling)
  • Echo backend for plumbing tests
  • nursery spawn <spec.yaml> β€” builds, mounts workspace, starts container
  • nursery ps / nursery stop / nursery logs / nursery rm
  • Host profiles: openclaw, hermes, pi
  • Agent reads SOUL.md, verifies workspace, enumerates secrets

Done when: nursery spawn example.yaml brings up a containerized agent that loads its own soul. βœ“


Phase 3 β€” First Conversation πŸ₯š

An agent receives a message, thinks, and replies. One channel, one agent.

  • Host gateway process (routes messages between channels and agents)
  • Agent ↔ gateway protocol implemented (decision made in Phase 0)
  • Telegram channel adapter
  • Agent state persistence (memory survives respawn)

Done when: you can message a Nursery agent on Telegram and get a reply.


Phase 4 β€” First Swarm πŸ₯š

Two agents running side-by-side with full isolation. The Layla/Lola problem solved.

  • Per-agent secrets directory, mounted read-only, scoped to one container
  • Gateway routes messages to the right agent by name/channel
  • Cross-agent access is impossible by design (verify with a test)
  • Agent A crashing does not affect Agent B

Done when: two agents with different OAuth tokens and personas coexist without stepping on each other.


Phase 5 β€” First Host πŸ₯š

Nursery runs inside OpenClaw.

  • OpenClaw host adapter (hosts/openclaw/)
  • Migration path for an existing OpenClaw agent β†’ Nursery spec
  • Documented setup for running Nursery on a Pi inside OpenClaw

Done when: Layla and Lola both run as Nursery agents inside OpenClaw.


Phase 6 β€” First Wild πŸ₯š

Nursery runs outside OpenClaw's ecosystem.

  • Hermes host adapter (hosts/hermes/)
  • Pi host adapter (hosts/pi/) β€” integration shape with Pi specified
  • Standalone profile hardened for cloud deployments (multi-arch images, AWS turnkey)
  • A single agent portable across all four hosts without code changes

Done when: the same agent spec runs on OpenClaw, Hermes, Pi, and a standalone VM.


Phase 7 β€” First Fork πŸ₯š

Templates and forks. New individuals from blueprints.

  • nursery fork <spec> --as <name> creates a new individual (new workspace, same config)
  • Clear semantics for what's shared vs. unique (the identity problem)
  • Documentation and examples of intentional replication

Done when: you can mass-produce agents from a template without any of them sharing identity.


Phase ∞ β€” Horizon πŸ₯š

Open-ended directions once the foundation is solid.

  • Replication across hosts (move a running agent, preserve state)
  • Vaulted secret backends (HashiCorp Vault, age-encrypted files)
  • Local model integration (Llama, Gemma, others)
  • Multi-channel agents (one agent, many bots)
  • Agent-to-agent messaging (careful β€” see docs/identity.md)
  • Resource quotas, rate limiting, graceful degradation
  • Observability (metrics, traces, health endpoints)
  • A clean story for migrating / backing up workspaces
  • Skills mount layer β€” ride agentskills.io, expose host skills into the container (see Skills Ecosystem above)
  • Scenario runtime β€” agents inside simulated contexts (life-scenario RPGs) for evaluation, training data generation, and experiential agent development
  • Multi-arch container images β€” publish linux/amd64 + linux/arm64 from a single docker buildx so the same tag runs on a Pi and a cloud VM
  • AWS turnkey launch β€” nursery aws launch <spec> that provisions an EC2 instance, installs prerequisites, and spawns the agent in one command

No promises. These live here so they don't get lost.

Target Runtimes

  • OpenClaw β€” open-source agent framework.
  • Hermes Agent β€” self-improving agent framework by Nous Research. Sibling of OpenClaw with a 15+ platform messaging gateway.
  • Pi β€” Mario Zechner's self-extensible coding-agent toolkit (the substrate OpenClaw is built on).
  • Standalone β€” thin Nursery runtime, no gateway framework. Runs on any Linux (Raspberry Pi hardware, WSL, laptops, cloud VMs like AWS EC2).

Deploying to AWS

See DeployAWS.md for the full walkthrough β€” takes you from zero to a running L4 GPU spot instance on EC2, using the Terraform module in hosts/aws/terraform/.

Next steps

Once aws configure is set up and aws sts get-caller-identity returns your IAM user, the deploy path is:

  1. Create an EC2 key pair in us-east-2 (AWS Console β†’ EC2 β†’ Key Pairs β†’ Create). Name it (e.g. nursery-l4), download the .pem, chmod 400 it.
  2. Verify your IAM user has ec2:* and s3:* β€” terraform-dev may or may not. The user you set up earlier with AdministratorAccess is fine; if you scoped it tighter you'll need to widen it.
  3. Install Terraform locally β€” brew install terraform or brew install opentofu. See HashiCorp's official guide: Install Terraform CLI. Requires β‰₯ 1.10 for native S3 state locking.
  4. Copy terraform.tfvars.example β†’ terraform.tfvars and set key_pair_name.
  5. One-time state-backend bootstrap (per AWS account) β€” from hosts/aws/terraform/bootstrap/: terraform init β†’ terraform apply. Creates the S3 bucket (versioned, encrypted) and writes ../backend.hcl for the main module.
  6. From hosts/aws/terraform/: terraform init -backend-config=backend.hcl β†’ terraform plan β†’ terraform apply.

New AWS account? GPU spot/on-demand vCPU quotas default to 0. Your first terraform apply will partially succeed (network resources) and then fail with MaxSpotInstanceCountExceeded. See DeployAWS.md β†’ Troubleshooting β†’ MaxSpotInstanceCountExceeded for the quota-increase commands. AWS typically auto-approves small new-account bumps in minutes to a few hours.

References

Deploying to Google Cloud

See DeployGCP.md for the GCP counterpart β€” same L4 spot VM shape, running on Ubuntu 24.04 with Python 3.12, CUDA 12.9, and NVIDIA driver 580 pre-installed. Terraform module in hosts/gcp/terraform/.

The GCP module ships a metadata_startup_script that installs Docker + wires the NVIDIA Container Toolkit on first boot, and a deploy.sh wrapper that tries L4 spot in us-central1-a/b/c first and falls back to on-demand if every spot zone is exhausted.

Next step β€” wire Hermes to the deployed VM

The VM gives us Docker + GPU; the next session's work is making Hermes (the Nous Research agent framework, see Target Runtimes) able to respond from this VM using the Ollama / gemma4:26b we just stood up. Plan:

  1. Read hosts/hermes/ to understand the adapter's contract β€” what it expects for spawn config, secrets, and the model endpoint.
  2. Plan the Hermes setup β€” where it runs (on-VM vs. laptop with SSH tunnel vs. firewall :11434 open), how its config points at http://localhost:11434 or the external Ollama address, and how nursery spawn invokes it.
  3. New branch + new PR for the Hermes wiring once the plan is concrete. Keeps the GCP-startup PR (this one) scoped to "VM is turnkey for containers" and the Hermes PR scoped to "first agent responds end-to-end."

Inspirations

Nursery is not built in a vacuum. Research and projects we're reading, in the order they mattered to our thinking.

Voyager β€” "An Open-Ended Embodied Agent with Large Language Models"

Paper Β· Code Β· Wang et al. (NVIDIA, Caltech, UT Austin, Stanford, ASU, 2023)

Voyager is an LLM-powered agent that plays Minecraft and learns by doing β€” no fine-tuning, no gradients. Three ideas drive it:

  1. Automatic curriculum. GPT-4 proposes what to learn next based on what the agent can already do and what's around it. A form of in-context novelty search.
  2. Ever-growing skill library. Every time the agent writes working code (JavaScript, via mineflayer bots) that accomplishes something, it stores the code with a natural-language description. Later, on a similar task, it retrieves relevant skills by embedding similarity and composes them into new ones.
  3. Iterative prompting with self-verification. GPT-4 writes code β†’ the world runs it β†’ errors and observations feed back in β†’ GPT-4 rewrites. The loop is the training.

Result: 3.3Γ— more unique items, 15.3Γ— faster to key tech milestones than prior SOTA, and β€” critically β€” the skill library generalizes to new Minecraft worlds. The agent transfers what it learned.

Why it matters for Nursery:

Voyager is the cleanest precedent for the scenario / RPG direction we've declared on the roadmap. It tells us the architecture questions we're going to have to answer, and gives us a concrete working reference. Five things we'd steal:

  • Skills as code, not just instructions. SKILL.md today captures what and when. Voyager captures how in executable form. For a scenario runtime, skills need to be runnable, not just readable.
  • Embedding-indexed retrieval. Don't load every skill into the prompt; retrieve the top-k by semantic similarity to the current task. Nursery's workspace becomes a home for a skill vector DB alongside daily memory.
  • Self-verification as a loop-closer. SKILL.md already has a ## Verification section. Make the scenario runtime actually execute it and feed the outcome back in.
  • Environment feedback as the rewrite signal. The scenario runtime emits structured observations (errors, state deltas, objects-in-view). The agent's response is conditioned on what actually happened.
  • Automatic curriculum as a meta-skill. The "what should I learn next" prompt is itself a reusable pattern. Bundle it as a canonical skill; any agent in any scenario can call it.

What we'd adapt, not adopt:

Voyager leans on GPT-4-class cloud models. That works for their research setting. For Nursery, we need to be honest about where lifelong-learning-by-doing can operate: probably cloud backends for now (Claude, GPT-4, Gemini), with smaller local models in a spectator / faster-turn role. Gemma 4 E2B on a Pi 4 at 2 tok/s can't run a Voyager curriculum in real time β€” and pretending otherwise would be architectural dishonesty.

Implications for the roadmap (captured more fully in docs/scenario-runtime.md):

  • The "Skills mount layer" Horizon bullet wants to be read-write, not read-only β€” agents author skills.
  • The "Scenario runtime" bullet wants an environment-feedback contract β€” POST /step with observations, not just POST /message with text.
  • Neither is happening in Phase 3. But when we get to Phase ∞, Voyager is the north star to aim for.

Skills Ecosystem

Nursery does not invent a new plugin format. The agent-skills world is converging, and we intend to ride the standard, not fight it.

The agentskills.io open standard

A skill is a folder containing a SKILL.md file with YAML frontmatter and a markdown body:

---
name: my-skill
description: Brief description of what this skill does
version: 1.0.0
platforms: [macos, linux]     # optional OS restriction
metadata:
  hermes:                     # Hermes-specific extensions (ignored elsewhere)
    tags: [python, automation]
    fallback_for_toolsets: [web]
  clawdbot:                   # OpenClaw-specific extensions (ignored elsewhere)
    emoji: "πŸ”Ž"
    requires:
      bins: [node]
      env_any: [TAVILY_API_KEY]
---

# Skill Title

## When to Use ...
## Procedure ...
## Pitfalls ...
## Verification ...

The format is adopted by OpenClaw, Hermes, Gemini CLI, Cursor, OpenHands, Amp, Junie, OpenCode, Mux, and more β€” the first plugin format with real cross-framework buy-in. See agentskills.io.

What is and isn't portable

Portable across hosts?
SKILL.md body (procedure, pitfalls, verification) βœ… Yes
Core frontmatter (name, description, version, platforms) βœ… Yes
Directory layout (skill-name/SKILL.md + scripts/refs) βœ… Yes
metadata.hermes.* extensions (conditional activation, tags) ⚠️ Hermes only; silently ignored elsewhere
metadata.clawdbot.* extensions (emoji, bin requirements) ⚠️ OpenClaw only; silently ignored elsewhere
Script implementations (e.g. a search.mjs) ⚠️ Portable if the host has the right tooling (Node, env vars, etc.)

Rule of thumb: a core skill drops between Hermes and OpenClaw without fuss. Framework-specific niceties (conditional activation, icons, bin preflight) degrade gracefully β€” the skill still works, just without that specific enhancement.

How Nursery exposes skills to agents

Two systems running in parallel, by design.

  1. Native framework skills. OpenClaw loads ~/.openclaw/workspace-<agent>/skills/ its own way. Hermes loads ~/.hermes/skills/ its own way. Nursery does not touch either β€” they continue working exactly as their frameworks define.

  2. Nursery's embedding-indexed retrieval. Additive layer that lives inside the Nursery container. Reads SKILL.md files from a configured directory, embeds each skill's description, and injects the top-k semantically relevant skills into the agent's system prompt per-message.

Both can coexist β€” they write to different surfaces, so there's no conflict. If you're using a pure Nursery agent, only retrieval runs. If you're inside OpenClaw or Hermes, the native loader runs AND Nursery's retriever runs, and the agent sees both.

Enabling retrieval (opt-in):

# agent.yaml
environment:
  NURSERY_SKILLS_DIR: /skills   # where the agent sees mounted skills
  NURSERY_EMBED_MODEL: nomic-embed-text:latest  # optional; this is the default

Then mount the skills directory at spawn time (automatic for the Pi host profile in a future PR; manual -v for now):

docker run -v ~/.openclaw/workspace-layla/skills:/skills:ro ...

How it works under the hood:

  1. On startup, the agent scans the mounted directory for SKILL.md files (standard agentskills.io layout).
  2. Each skill's description + first ~500 chars of body are embedded via Ollama's nomic-embed-text (~565 MB, fast even on Pi 4).
  3. Embeddings are cached to <workspace>/.nursery/skills-index.json. Subsequent restarts reuse the cache; only new or changed skills are re-embedded.
  4. On every POST /message, the user's text is embedded, compared against the index, and the top 3 skills (by cosine similarity) are injected into the system prompt as a # Relevant skills block.
  5. Skills with a platforms: frontmatter field are filtered to compatible OSes automatically.

Why separate rather than unified:

  • Frameworks update their skill systems at their own pace. A Nursery retriever that tried to replace either would fight updates.
  • The information budget is different. OpenClaw/Hermes native loading picks skills by slash-command or tag heuristics; embedding retrieval picks them by semantic relevance to this message. Both signals are useful.
  • We don't want to be another skill-format in the ecosystem. We want to be a useful layer on top of the one that exists.

Status: πŸ₯ Working. See agent/src/nursery_agent/skills.py. Two example skills ship in examples/skills/.

Why this matters β€” the RPG / life-scenario direction

The long-term vision for Nursery includes running agents inside simulated contexts, like life-scenario RPGs: an agent plays a character, navigates a situation, makes decisions with consequences, accumulates memory. This is useful for:

  • Evaluating agent behavior in controlled scenarios (ethics, social dynamics, decision quality under uncertainty).
  • Training data generation β€” trajectories from agents-in-scenarios become RL / SFT data.
  • Experiential agent development β€” skills that emerge from scenario play, not just documentation.
  • Entertainment / education β€” agents as interactive narrative partners.

Skills are the right substrate for this because:

  1. Scenario mechanics become skills. A "combat" skill, a "dialogue" skill, a "resource management" skill. Load the ones relevant to the game.
  2. Portable across frameworks. The same scenario skill pack runs a Hermes agent or an OpenClaw agent identically.
  3. Composable. A life-scenario RPG is a set of skills + a persona (SOUL.md) + a workspace (memory of what happened). All three are already in Nursery's vocabulary.
  4. Measurable. Skills declare verification sections β€” we can score whether an agent completed a scenario's objectives.

This isn't built yet, but the architecture is deliberately shaped toward it. Every design decision β€” workspace as identity, soul as persona, skills as procedural memory β€” is compatible with "spawn ten agents into a scenario, observe, collect trajectories."

When we get there, it'll be its own phase. For now: document the ecosystem, respect the standard, don't paint ourselves into a proprietary corner.

Status

πŸ₯š Hatching. README, scaffold, and direction are in place. No functional code yet. This repo exists to think in public and not lose the thread.

Contributing

Early-stage. Open an issue before submitting a PR. For security issues, see SECURITY.md.

License

Apache 2.0 β€” includes an explicit patent grant (Section 3) to contributors and users. See NOTICE for attribution.

About

An AI Cattle Factory Farm

Resources

Security policy

Stars

Watchers

Forks

Releases

Packages

Used by

Contributors

Languages