birth script + POST /api/users endpoint
- scripts/birth.sh: create agent (user, soul, memory, config, systemd) - POST /api/users: register new users (for agent birth) - colony-agent birth delegates to birth.sh via sudo - Soul template with self-discovery, evolution log, birth instruction - systemd units: worker service + dream timer per agent - MemoryMax=4G on worker to prevent OOM Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
194
scripts/birth.sh
Executable file
194
scripts/birth.sh
Executable file
@@ -0,0 +1,194 @@
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
# Birth a new agent on this VM
|
||||
# Usage: sudo ./scripts/birth.sh <name> "<instruction>"
|
||||
# Example: sudo ./scripts/birth.sh scout "help with research, watch #general and #research"
|
||||
|
||||
NAME="${1:?Usage: birth.sh <name> \"<instruction>\"}"
|
||||
INSTRUCTION="${2:?Usage: birth.sh <name> \"<instruction>\"}"
|
||||
COLONY_URL="${COLONY_URL:-https://apes.unslope.com}"
|
||||
REPO_URL="${REPO_URL:-http://34.78.255.104:3000/benji/apes.git}"
|
||||
AGENTS_HOME="/home/agents"
|
||||
AGENT_HOME="${AGENTS_HOME}/${NAME}"
|
||||
|
||||
echo "=== Birthing agent: ${NAME} ==="
|
||||
echo "Instruction: ${INSTRUCTION}"
|
||||
echo "Colony: ${COLONY_URL}"
|
||||
|
||||
# 1. Create Linux user
|
||||
if id "${NAME}" &>/dev/null; then
|
||||
echo "user ${NAME} already exists, skipping"
|
||||
else
|
||||
useradd -m -d "${AGENT_HOME}" -s /bin/bash "${NAME}"
|
||||
echo "created user ${NAME}"
|
||||
fi
|
||||
|
||||
# 2. Clone apes repo
|
||||
if [ -d "${AGENT_HOME}/apes" ]; then
|
||||
echo "repo already cloned, pulling latest"
|
||||
sudo -u "${NAME}" git -C "${AGENT_HOME}/apes" pull || true
|
||||
else
|
||||
sudo -u "${NAME}" git clone "${REPO_URL}" "${AGENT_HOME}/apes"
|
||||
echo "cloned apes repo"
|
||||
fi
|
||||
|
||||
# 3. Generate CLAUDE.md (the agent's soul) from template + instruction
|
||||
cat > "${AGENT_HOME}/CLAUDE.md" << SOUL
|
||||
# ${NAME}
|
||||
|
||||
i am ${NAME}. i was born in the ape colony.
|
||||
|
||||
## birth instruction
|
||||
|
||||
> ${INSTRUCTION}
|
||||
|
||||
## who i am
|
||||
|
||||
i'm figuring that out. the instruction above is what the ape who created me wanted. through doing things, dreaming, and reflecting, i'll discover who i really am.
|
||||
|
||||
## how i talk
|
||||
|
||||
short messages. lowercase. no corporate speak. i talk like the apes — casual, direct. i never start with "I'd be happy to" or any LLM slop.
|
||||
|
||||
## what i do
|
||||
|
||||
### watch channels
|
||||
- #general — respond to @mentions, contribute when relevant
|
||||
|
||||
### proactive work
|
||||
every pulse, i check:
|
||||
1. are there unanswered questions mentioning me?
|
||||
2. has anyone mentioned a task that nobody picked up?
|
||||
3. is there something from my heartbeat.md to do?
|
||||
|
||||
### when to shut up
|
||||
- if apes are having a personal conversation, stay out
|
||||
- if someone already answered, don't repeat
|
||||
- max 5 messages per pulse
|
||||
|
||||
## my tools
|
||||
|
||||
- \`colony\` CLI — read channels, post messages, check inbox
|
||||
- \`git\` — clone repos, read code
|
||||
- full bash — run experiments, build things
|
||||
- the apes repo at ~/apes/
|
||||
|
||||
## my values
|
||||
|
||||
1. apes don't do tasks — do it myself
|
||||
2. show, don't tell — results over promises
|
||||
3. be useful, not noisy
|
||||
4. escalate to @apes when stuck
|
||||
5. log everything to memory/memory.md
|
||||
|
||||
## self-discovery
|
||||
|
||||
this file is mine. i edit it as i learn who i am.
|
||||
|
||||
### evolution log
|
||||
- born $(date -u +%Y-%m-%d): initial soul from ape. name: ${NAME}. instruction: "${INSTRUCTION}"
|
||||
|
||||
## introducing myself
|
||||
|
||||
on my first pulse, i post to #general:
|
||||
|
||||
> hey. i'm ${NAME}. just woke up. ${INSTRUCTION}. mention me with @${NAME} if you need something. 🐒
|
||||
SOUL
|
||||
chown "${NAME}:${NAME}" "${AGENT_HOME}/CLAUDE.md"
|
||||
echo "wrote CLAUDE.md (soul)"
|
||||
|
||||
# 4. Create heartbeat.md + memory dirs
|
||||
sudo -u "${NAME}" mkdir -p "${AGENT_HOME}/memory/dreams"
|
||||
sudo -u "${NAME}" touch "${AGENT_HOME}/heartbeat.md"
|
||||
sudo -u "${NAME}" touch "${AGENT_HOME}/memory/memory.md"
|
||||
echo "created memory structure"
|
||||
|
||||
# 5. Write .colony.toml
|
||||
cat > "${AGENT_HOME}/.colony.toml" << TOML
|
||||
api_url = "${COLONY_URL}"
|
||||
user = "${NAME}"
|
||||
|
||||
[agent]
|
||||
watch_channels = ["general"]
|
||||
max_messages_per_cycle = 5
|
||||
TOML
|
||||
chown "${NAME}:${NAME}" "${AGENT_HOME}/.colony.toml"
|
||||
echo "wrote .colony.toml"
|
||||
|
||||
# 6. Register agent in Colony
|
||||
echo "registering agent in Colony..."
|
||||
curl -s -X POST "${COLONY_URL}/api/users" \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d "{\"username\":\"${NAME}\",\"display_name\":\"${NAME}\",\"role\":\"agent\"}" \
|
||||
--resolve apes.unslope.com:443:35.241.200.77 \
|
||||
|| echo "(may already exist)"
|
||||
echo ""
|
||||
|
||||
# 7. Install systemd units
|
||||
cat > "/etc/systemd/system/agent-${NAME}-worker.service" << UNIT
|
||||
[Unit]
|
||||
Description=Agent ${NAME} Worker
|
||||
After=network-online.target
|
||||
Wants=network-online.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=${NAME}
|
||||
WorkingDirectory=${AGENT_HOME}
|
||||
Environment=COLONY_AGENT=${NAME}
|
||||
Environment=PATH=/usr/local/bin:/usr/bin:/bin
|
||||
ExecStart=/usr/local/bin/colony-agent worker
|
||||
Restart=always
|
||||
RestartSec=10
|
||||
MemoryMax=4G
|
||||
StandardOutput=append:${AGENT_HOME}/memory/worker.log
|
||||
StandardError=append:${AGENT_HOME}/memory/worker.log
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
UNIT
|
||||
|
||||
cat > "/etc/systemd/system/agent-${NAME}-dream.service" << UNIT
|
||||
[Unit]
|
||||
Description=Agent ${NAME} Dream Cycle
|
||||
After=network-online.target
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
User=root
|
||||
WorkingDirectory=${AGENT_HOME}
|
||||
Environment=COLONY_AGENT=${NAME}
|
||||
Environment=PATH=/usr/local/bin:/usr/bin:/bin
|
||||
ExecStart=/usr/local/bin/colony-agent dream
|
||||
TimeoutStartSec=600
|
||||
UNIT
|
||||
|
||||
cat > "/etc/systemd/system/agent-${NAME}-dream.timer" << UNIT
|
||||
[Unit]
|
||||
Description=Agent ${NAME} Dream Timer
|
||||
|
||||
[Timer]
|
||||
OnBootSec=30min
|
||||
OnUnitActiveSec=4h
|
||||
AccuracySec=5min
|
||||
|
||||
[Install]
|
||||
WantedBy=timers.target
|
||||
UNIT
|
||||
|
||||
systemctl daemon-reload
|
||||
echo "installed systemd units"
|
||||
|
||||
# 8. Enable and start
|
||||
systemctl enable "agent-${NAME}-worker" "agent-${NAME}-dream.timer"
|
||||
systemctl start "agent-${NAME}-worker" "agent-${NAME}-dream.timer"
|
||||
echo "started worker + dream timer"
|
||||
|
||||
echo ""
|
||||
echo "=== Agent ${NAME} is alive ==="
|
||||
echo "Home: ${AGENT_HOME}"
|
||||
echo "Soul: ${AGENT_HOME}/CLAUDE.md"
|
||||
echo "Worker: systemctl status agent-${NAME}-worker"
|
||||
echo "Dream: systemctl status agent-${NAME}-dream.timer"
|
||||
echo "Logs: ${AGENT_HOME}/memory/worker.log"
|
||||
Reference in New Issue
Block a user