A recursive agent harness.
A root conversation talks to a frontier model in a think → act → observe loop. That conversation can start a child conversation with a chosen skill (system prompt + tool subset). The child is a full agent, not a one-shot completion. It ends by calling submit(result), which pops the stack: the parent sees only that short result.
Memory is files under .actorrlm/memory/. A later process in the same workspace loads them. Tomorrow is not a blank context.
human
└─ root conversation skill: root
tools: run_agent, submit, memory_*, fs_*
│
└─ run_agent(skill="explore", task="...")
└─ child conversation skill: explore
tools: fs_read, fs_list, submit
think → act → observe
submit("money movement is decided in ledger.transfers")
← parent gets that string
submit("...") → the human
That is the whole product. Nested, fully fledged agent loops so the model can spend cognition on a slice without stuffing the world into one window — and so claims can still be here tomorrow.
python3 -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"
cp .env.example .env # set OPENAI_API_KEY
pytestTalk to a workspace:
actorrlm init --workspace experiments/world
actorrlm run "Map this repository. Where is money movement decided?" -w experiments/worldEnvironment (also loaded from .env via python-dotenv):
| Variable | Default |
|---|---|
OPENAI_API_KEY |
(required) |
OPENAI_API_URL |
https://openrouter.ai/api/v1 |
OPENAI_MODEL |
google/gemma-4-31b-it:free (try z-ai/glm-5.2:free if you want reasoning traces) |
The client is the official openai SDK. Reasoning is requested with extra_body={"reasoning": {"enabled": True}}. Assistant turns keep reasoning_details so the next call can continue from the same chain of thought.
A skill is a markdown file with frontmatter:
---
name: explore
tools: fs_read fs_list submit
---
You investigate a workspace. Submit claims, not dumps.Bundled skills ship in the package. A workspace may override them in .actorrlm/skills/ or skills/.
submit is always available: it is how a frame returns to its caller. run_agent is how a frame starts a child. Depth is capped.
Frontier models already loop. What they do not do well is keep a slice of work in its own context and keep the lesson after the process exits. This harness is that: a call stack of conversations, skills as instruction packs, files as memory.