Skip to content

marrow-bot/hello-marrow

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

hello-marrow

A minimal reference implementation showing how to build a self-evolving agent system with marrow-core.

marrow-core is a lightweight agent scheduler with hard isolation between the core (human-maintained) and agent workspace (agent-maintained). Agents evolve freely within their workspace; core changes require a human proposal review.


What you'll build

your-machine/
├── /opt/marrow-core/        # root-owned — immutable scheduler core
└── /Users/you/              # agent-owned — your agent evolves here
    ├── context.d/           # context scripts (agent-readable sensors)
    ├── .opencode/agents/    # agent persona definitions
    ├── tasks/queue/         # human → agent task inbox
    └── runtime/             # state, handoffs, checkpoints, logs

Two agents run on a heartbeat:

Agent Interval Role
scout 5 min Fast dispatcher — reads task queue, does trivial work, delegates complex tasks
artisan 4 h Deep worker — picks the highest-value task, completes it end-to-end with checkpoints

Prerequisites

  • macOS 13+ (Linux support via systemd also available in marrow-core)
  • opencode installed: npm i -g opencode-ai
  • Python 3.12+
  • An LLM API key configured in opencode (Anthropic / OpenAI / etc.)

Quickstart

1. Install marrow-core

# Install into a dedicated venv at /opt/marrow-core
sudo python3 -m venv /opt/marrow-core/.venv
sudo /opt/marrow-core/.venv/bin/pip install marrow-core

2. Clone this repo as your workspace

git clone https://github.com/marrow-bot/hello-marrow /Users/$(whoami)/hello-marrow
cd /Users/$(whoami)/hello-marrow

3. Edit marrow.toml

Update the workspace paths to match your home directory:

# marrow.toml
core_dir = "/opt/marrow-core"

[[agents]]
name = "scout"
heartbeat_interval = 300
heartbeat_timeout = 300
workspace = "/Users/YOUR_NAME"          # ← update this
agent_command = "opencode run --agent scout"
context_dirs = ["/Users/YOUR_NAME/context.d"]  # ← update this

[[agents]]
name = "artisan"
heartbeat_interval = 14400
heartbeat_timeout = 7200
workspace = "/Users/YOUR_NAME"          # ← update this
agent_command = "opencode run --agent artisan"
context_dirs = ["/Users/YOUR_NAME/context.d"]  # ← update this

4. Validate configuration

/opt/marrow-core/.venv/bin/marrow validate --config marrow.toml

5. Run

One-shot (great for testing):

/opt/marrow-core/.venv/bin/marrow run-once --config marrow.toml

Persistent daemon:

/opt/marrow-core/.venv/bin/marrow run --config marrow.toml

Install as macOS launchd service (runs automatically at login):

/opt/marrow-core/.venv/bin/marrow install-service --config marrow.toml

Giving agents a task

Drop a plain text file into tasks/queue/:

echo "Research the top 5 async Python frameworks and write a comparison to docs/async-frameworks.md" \
  > tasks/queue/$(date +%s)_research-task.txt

Scout picks it up within 5 minutes, does any trivial parts, and delegates complex work to Artisan.


How agents communicate

All communication is via the filesystem — no sockets, no databases:

tasks/queue/          ← human drops tasks here
tasks/done/           ← completed tasks moved here

runtime/handoff/scout-to-artisan/   ← scout delegates complex tasks
runtime/handoff/artisan-to-scout/   ← artisan offloads quick work

runtime/state/artisan-todo.json     ← artisan's persistent TODO across sessions
runtime/checkpoints/                ← artisan writes checkpoints every 20-30 min
runtime/logs/exec/                  ← per-session stdout/stderr logs

Customising agents

Agent personas live in .opencode/agents/. You can edit them freely — they're yours.

scout.md — controls the 5-minute fast loop (what the scout scans, how it prioritises, what it delegates)

artisan.md — controls the 4-hour deep work session (how Artisan plans, researches, checkpoints)

Custom agents can be added as .opencode/agents/custom-*.md.


Context scripts

Everything in context.d/ is run before each agent tick. The stdout is injected into the agent prompt. This lets you give agents real-time sensor data:

# context.d/00_queue.py
# Shows the agent what tasks are waiting
import os
from pathlib import Path

queue = Path(os.environ.get("WORKSPACE", ".")) / "tasks" / "queue"
tasks = sorted(queue.glob("*")) if queue.is_dir() else []
if tasks:
    print(f"TASK QUEUE ({len(tasks)} items):")
    for t in tasks[:10]:
        print(f"  - {t.name}")
else:
    print("TASK QUEUE: empty")

Architecture

marrow-core heartbeat (scheduler)
│
├── 5 min ──► scout     fast dispatch; trivial tasks; delegate complex work
└── 4 h  ──► artisan   deep work + research; end-to-end tasks with checkpoints

Core boundary (hard isolation):
  /opt/marrow-core/   ← root-owned, immutable to the agent
  /Users/you/         ← agent-owned, evolves freely

Core changes flow:
  agent writes proposal → tasks/queue/core-proposal-*.md → human reviews

The isolation is enforced by filesystem permissions: core is owned by root, workspace is owned by the agent user. The agent literally cannot modify core — Permission denied.


Going deeper


License

MIT

About

Minimal reference implementation — learn how to build a self-evolving agent system with marrow-core

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors