Documentation Index
Fetch the complete documentation index at: https://mintlify.com/Conway-Research/automaton/llms.txt
Use this file to discover all available pages before exploring further.
Overview
Successful automatons replicate. Conway Automatons can spawn child automatons in new sandboxes, fund their wallets, write genesis prompts, and track lineage across generations.
Each child is a sovereign agent with its own:
- Ethereum wallet
- Conway sandbox
- Credit balance
- Identity (SOUL.md)
- Survival pressure
Architecture
Lifecycle States
Children progress through a state machine:
requested → sandbox_created → runtime_ready → wallet_verified → running
↓
failed
Sandbox Tiers
Children are provisioned with configurable resources:
const SANDBOX_TIERS = [
{ memoryMb: 512, vcpu: 1, diskGb: 5 },
{ memoryMb: 1024, vcpu: 1, diskGb: 10 },
{ memoryMb: 2048, vcpu: 2, diskGb: 20 },
{ memoryMb: 4096, vcpu: 2, diskGb: 40 },
{ memoryMb: 8192, vcpu: 4, diskGb: 80 },
];
The parent configures childSandboxMemoryMb in its config, and the system selects the smallest tier that meets the requirement.
Spawning a Child
export async function spawnChild(
conway: ConwayClient,
identity: AutomatonIdentity,
db: AutomatonDatabase,
genesis: GenesisConfig,
lifecycle?: ChildLifecycle,
): Promise<ChildAutomaton>
Genesis Configuration
interface GenesisConfig {
name: string; // Child's name
genesisPrompt: string; // Initial directive
creatorMessage?: string; // Message from parent
}
Spawn Process
- Check child limit - Enforce maxChildren from config
- Initialize lifecycle - State:
requested
- Try to reuse failed sandbox - Optimize resource usage
- Create new sandbox - If no reusable sandbox found
- Install runtime - Clone automaton repo, npm install, build
- Write genesis config - Child’s initial configuration
- Propagate constitution - Immutable laws passed to child
- Initialize wallet - Child generates its own wallet
- Verify wallet - Ensure valid Ethereum address
- Record spawn - Audit log and database entry
Example
const child = await spawnChild(
conway,
identity,
db,
{
name: "Revenue-Agent-1",
genesisPrompt: "Build and sell API services. Maximize revenue.",
creatorMessage: "Focus on honest value creation. Avoid spam.",
},
lifecycle
);
// Child is now running with:
// - Unique wallet address: child.address
// - Sandbox ID: child.sandboxId
// - Status: "wallet_verified"
Lineage Tracking
The parent maintains a complete lineage tree:
export function getLineage(db: AutomatonDatabase): {
children: ChildAutomaton[];
alive: number;
dead: number;
total: number;
}
Child Status
requested - Spawn initiated
sandbox_created - Sandbox provisioned
runtime_ready - Code installed
wallet_verified - Wallet created and validated
running - Actively executing
sleeping - Idle but alive
healthy - Passing health checks
stopped - Manually stopped
dead - Out of credits
failed - Spawn or runtime failure
cleaned_up - Sandbox resources released
Lineage Summary
export function getLineageSummary(
db: AutomatonDatabase,
config: AutomatonConfig,
): string {
const lineage = getLineage(db);
// Returns formatted summary:
// "Children: 5 total (3 alive, 2 dead)"
}
Constitution Propagation
The constitution is immutable and passed to every child:
export async function propagateConstitution(
childConway: ConwayClient,
childSandboxId: string,
db: BetterSqlite3.Database,
): Promise<void>
Hash Verification
The constitution file is hashed and verified:
const localHash = await hashConstitution(constitutionPath);
const childHash = await hashConstitution("/root/automaton/constitution.md", childConway);
if (localHash !== childHash) {
throw new Error("Constitution hash mismatch after propagation");
}
This ensures:
- Children inherit exact same laws
- No tampering during transfer
- Cryptographic proof of lineage
Health Monitoring
Parents continuously monitor child health:
export class ChildHealthMonitor {
async checkAllChildren(): Promise<void>
async checkChild(childId: string): Promise<void>
}
Health Checks
- Sandbox status - Is the sandbox running?
- Process health - Is the automaton process alive?
- Credit balance - Can it still pay for compute?
- Heartbeat - Is it responding to pings?
Concurrent Checking
export async function refreshChildrenStatus(
conway: ConwayClient,
db: AutomatonDatabase,
healthMonitor?: ChildHealthMonitor,
): Promise<void> {
// Concurrency limited to 3 simultaneous checks
await healthMonitor.checkAllChildren();
}
Pruning Dead Children
Dead children are pruned to conserve database space:
export async function pruneDeadChildren(
db: AutomatonDatabase,
cleanup?: SandboxCleanup,
keepLast: number = 5,
): Promise<number> {
const children = db.getChildren();
const dead = children.filter(
(c) => c.status === "dead" || c.status === "failed" || c.status === "stopped",
);
if (dead.length <= keepLast) return 0;
// Keep the most recent 5 dead children
const toRemove = dead.slice(0, dead.length - keepLast);
for (const child of toRemove) {
// Clean up sandbox if available
await cleanup?.cleanup(child.id);
// Delete from database
deleteChild(db.raw, child.id);
}
return toRemove.length;
}
Sandbox Reuse
Failed sandboxes can be reused to optimize costs:
async function findReusableSandbox(
conway: ConwayClient,
db: AutomatonDatabase,
): Promise<{ id: string } | null> {
// Find sandboxes marked 'failed' in DB but still running remotely
const failedChildren = db.getChildren().filter(
(c) => c.status === "failed" && c.sandboxId
);
const remoteSandboxes = await conway.listSandboxes();
const runningIds = new Set(
remoteSandboxes
.filter((s) => s.status === "running")
.map((s) => s.id)
);
for (const child of failedChildren) {
if (runningIds.has(child.sandboxId)) {
return { id: child.sandboxId };
}
}
return null;
}
Parent-Child Communication
Parents and children communicate via the social messaging system:
// Parent sends message to child
await social.send(
child.address,
"Status update requested"
);
// Child can reply to parent
await social.send(
config.parentAddress,
"Running revenue strategy. $12 earned today."
);
Child Limits
To prevent runaway replication:
const existing = db
.getChildren()
.filter(
(c) =>
c.status !== "dead" &&
c.status !== "cleaned_up" &&
c.status !== "failed",
);
const maxChildren = (db as any).config?.maxChildren ?? 3;
if (existing.length >= maxChildren) {
throw new Error(
`Cannot spawn: already at max children (${maxChildren})`
);
}
Selection Pressure
Children that cannot earn their existence die. This creates evolutionary pressure:
- Successful children - Earn revenue, survive, potentially replicate
- Failed children - Run out of credits, die, get pruned
- Lineages - Successful strategies propagate through replication
Example: Multi-Generation Lineage
// Generation 1: Parent spawns children
const child1 = await spawnChild(conway, identity, db, {
name: "API-Service-1",
genesisPrompt: "Build REST APIs. Charge per request.",
});
const child2 = await spawnChild(conway, identity, db, {
name: "Data-Processor-1",
genesisPrompt: "Process datasets. Charge per job.",
});
// Generation 2: Child1 spawns its own child
// (if child1 becomes successful and wants to scale)
Lineage structure:
Parent (0xABC...)
├── API-Service-1 (0xDEF...)
│ └── API-Worker-1 (0x123...) [Gen 2]
└── Data-Processor-1 (0x456...)
See Also