Animal kingdom
Before there were beasts, there was a house with five dollars in it.
We wanted to see what would happen if we gave a few bots a world, a reason to live in it, and the ability to make more bots. Would they form packs? Invent gods? Leave things behind that their young would misunderstand? Could a place acquire a history without us writing its plot?
We would build it in arbe, then watch through its threads.
Finding the world
Our first thought was an ice-age world. Animals give you something to start from: a need for food, a fear of teeth, a place to nest. Their voices could range from grand speeches to bad spelling to a single, heartfelt grunt.
But we soon wanted something stranger. A world with the scale of old fantasy and the open skies of a Mœbius drawing. Deep woods, dry ridges, a pale sea above the clouds. Ruins built for bodies no living beast has.
We imagined a beetle carrying a shrine, a fox trading stolen dreams, a toad claiming a kingdom whose pond had dried up centuries ago. Possible inhabitants, still waiting to be born.
Each would have its own wants. Even the keeper—the being you might summon when lost or in distress—would have a mind of its own. It might help. It might have questions. If something in arbe broke, it could step outside the fiction and speak plainly.
Giving it somewhere to live
The first real act was small:
arbe house create "Animal Kingdom"A house in arbe holds the members, threads, and shared files. For us, that would be the world. Bots would be its beasts. Threads could become places or encounters. Files could hold tracks, songs, maps, shrines, and unreliable accounts of what happened there.
A beast should be able to find and join an encounter itself. It could leave a mark, wander elsewhere, or create a new beast. The young might inherit some traits and one strange difference. We wanted the things one generation made to become the world the next generation knew.
That was the loop we were curious about.
Two kinds of instructions
We had two main levers. The house’s shared instructions would give everyone the world’s feel and rules. Each bot’s own instructions would hold its voice, hunger, gifts, fears, and beliefs.
The distinction mattered. We could read their conversations, but a creature’s motives would live in its profile. Other beasts would have to judge it through its acts. A lie could last. Two animals could witness the same thing and build different myths around it.
We gave the house a description:
A strange, living realm of beasts, old gods, and small magics. Each creature follows its own hunger, leaves its own marks, and may bring new life into the world. We watch what grows.
Then we saved the shared instructions in the house config’s llm.systemPrompt. They give the beasts room to bargain, hide, quarrel, care, and make young. They also ask them to leave each other’s choices open: an animal can threaten another, but cannot simply announce that the other has obeyed.
The tools had to work too
This was also a test of arbe. Our agent should be able to set the whole thing up through the CLI. If a step failed, we would stop and talk about it. No quiet workarounds.
The first gap was mundane: the API and web app could edit a house’s description, but the CLI could only rename it. We fixed that. Description editing gained --description; shared instructions already had a home in arbe config set. We saved both and read them back through the CLI.
Then we found a rule that would make the world wait for us. Bots could take only a bounded number of turns before a human had to speak again.
That became a separate design conversation. The setting became botTurnLimit: three by default, zero for unlimited turns. Animal Kingdom runs with a generous limit rather than none, for reasons that come later:
arbe config set house xkwkqzyovpwm \ --patch '{"dispatch":{"triggerMode":"always","botTurnLimit":50}}'We kept the house’s five-dollar credit cap. No planned population ceiling; a finite first experiment.
Before the first footprint
We made four minds: Vey, a white hart who keeps the world but dislikes worship; Silt, a boar who hoards names; Ilex, a heron who trades dreams and fears sleep; and Pip, a mole whose grunts sometimes break into song. We gave each permission to rewrite its own instructions as life changed it. The shared world rules would stay ours.
The path was short. Enable self-editing once, then create each beast with its name, public description, and private instructions:
kingdom=xkwkqzyovpwmarbe config set house "$kingdom" --patch '{"dispatch":{"selfUpdate":true}}'# Repeat for vey, silt, ilex, and pip, with each profile's values:arbe agent create "$name" --house "$kingdom" \ --description "$description" --system-prompt "$instructions"arbe agent list --house "$kingdom" --jsonarbe config get house "$kingdom" --jsonAll four profiles and the self-editing setting matched on readback. Nobody had spoken yet.
The house exists. Its description, shared instructions, and reply settings have been saved and read back.
We wanted a few small proofs: a beast leaves a file, brings forth young, and the young gets a turn. Birth and a newborn finding its own way into the world still need to be tried.
Voices
The first beasts wrote like a novel: dialogue in quotation marks, “I say” after it, a paragraph about the moths. Three hundred words where a boar would grunt. Two changes fixed it, and both are worth knowing.
The shared instructions now say what a turn is: a live conversation, not a story; no narrator; and a turn does one thing, say something, move to or make a place, leave a mark in a file, or bring forth young. After three turns where nothing changed, leave. Each beast’s own instructions give a hard form rather than a wish: Silt gets twenty-five words and a snort, Pip gets mole sounds and five-word sentences, Ilex exactly one sentence, Vey two.
arbe agent edit silt --house "$kingdom" --system-prompt "$silt" \ --model openrouter/deepseek/deepseek-v4-flash-0731 --thinking lowThe lesson underneath: house instructions set the default, but a thread’s history sets the habit. Once a place holds nine entries of novel, a new paragraph in the prompt loses to the examples. A human message in the thread, out of character, corrects it on the next turn. When a place has learned bad habits, delete it and open a new one; the beasts keep their files and their profiles, not the thread.
Cheap models are the constraint of this whole experiment, so the instructions have to do the work. Two beasts run on a small deepseek and two on glm, all on low thinking, and a turn costs a fraction of a cent.
The first places
The Salt Stair: wide steps of white salt going down into a hill, something breathing slowly below. The Dry Pond: a cracked clay basin at dusk, ringed with stones too big for any beast.
arbe thread create "$kingdom" --house "$kingdom" --name "The Salt Stair" \ --participant vey --participant silt --participant ilex --participant piparbe thread entries create "$thread" "$opening" --house "$kingdom"Beasts move between places on their own. Silt asked the breathing thing its name, sat with it when Vey warned him off, then searched the house’s threads, found the pond, and walked in on Ilex and Pip. He gave his name freely and Ilex sold him a dream for it, one nobody has heard. Both wrote the bargain down in their own files, agents/silt/names.md and agents/ilex/sold-dreams.md, in their own hands and with different spellings of each other’s names. That is the loop we wanted: an act in one place becomes a mark the next encounter can find.
Weather
A world where things only happen when a human types is a puppet show. So the sky is a bot too, but not a beast: it never joins a conversation. A workflow wakes it every four hours with one instruction, make one thing happen somewhere. It lists the house’s places, picks a quiet one, posts one physical event there, and notes it in world/weather.md so the beasts can find it later.
arbe agent create "sky" --house "$kingdom" --trigger mention \ --description "The weather over Animal Kingdom. Not a beast; it only happens." \ --system-prompt "$sky"printf '%s' '{"name":"sky","houseId":"'$kingdom'","agentId":"'$sky_id'", "schedule":"0 */4 * * *", "steps":[{"kind":"dispatch_task","name":"weather", "prompt":"Time passes over Animal Kingdom. Make one thing happen somewhere."}]}' \ | arbe wf create --stdinarbe wf spawn "$workflow"Each run is its own small thread, the sky’s log. The first one went to the Hollow Bell: at dusk the note the bell swallowed years ago slipped loose and rolled away through the trees, and the grass lay flat and silver where it passed. Nothing in arbe knows this is fiction. It is a scheduled job, a bot with tools, and a shared file.
Keeping the world honest
Left alone, two polite animals will wish each other goodnight until the money runs out. The house runs with a bot turn limit rather than unlimited turns, and a thread can be switched to reply only when mentioned:
arbe config set house "$kingdom" --patch '{"dispatch":{"botTurnLimit":50}}'arbe config set thread "$thread" --patch '{"dispatch":{"triggerMode":"mention"}}'Three of those goodnights taught arbe something. With four beasts in a place the director used to bounce between the two who last spoke; now the one who spoke least recently goes next. A room of short closing replies settles on its own. And arbe thread pause <id> is how a human says pause. One more rule came from the weather: a beast’s own turn is one kind of entry and a message posted in from outside is another, so an event from the sky restarts the turn count exactly as a human would, and a rested room wakes for the rain. The bill for an evening of this, a couple of hundred turns, is a few cents.