Gene Development Guide
This guide walks you through the full lifecycle of creating a Rotifer gene — from initial idea to cloud publication.
What is a Gene?
Section titled “What is a Gene?”A gene is the atomic unit of capability in the Rotifer Protocol. Unlike traditional “skills” or “tools” that are static function wrappers, genes are living entities that:
- Have a Phenotype — typed metadata describing their interface, domain, and fitness contract
- Compete in Arenas — same-domain genes fight for survival based on fitness scores
- Can be composed — genes combine via formal algebra (Seq, Par, Cond, Try)
- Are sandboxed — WASM isolation ensures memory-safe, resource-limited execution
Step 1: Initialize a Project
Section titled “Step 1: Initialize a Project”npx @rotifer/playground init my-projectcd my-projectThis creates a project with 5 pre-installed Genesis genes that serve as baselines in the Arena.
Step 2: Create a Gene
Section titled “Step 2: Create a Gene”Create a new gene directory with the required files:
mkdir -p genes/my-translator2.1 Write the Express Function
Section titled “2.1 Write the Express Function”Every gene must export an express() function — the single entry point for gene invocation.
export async function express(input: { text: string; targetLang: string;}): Promise<{ translated: string; confidence: number }> { const translated = await translateText(input.text, input.targetLang); return { translated, confidence: 0.95, };}
async function translateText(text: string, lang: string): Promise<string> { // Your translation logic here // Could call an API, use a local model, etc. return `[${lang}] ${text}`;}Key rules for express():
- Must be an
export(named export, not default) - Must accept a single input object
- Must return a non-null result object
- Should handle errors gracefully (throw typed errors)
2.2 Define the Phenotype
Section titled “2.2 Define the Phenotype”The Phenotype describes your gene’s interface contract.
{ "domain": "text.translate", "inputSchema": { "type": "object", "properties": { "text": { "type": "string", "description": "Text to translate" }, "targetLang": { "type": "string", "description": "Target language code" } }, "required": ["text", "targetLang"] }, "outputSchema": { "type": "object", "properties": { "translated": { "type": "string" }, "confidence": { "type": "number", "minimum": 0, "maximum": 1 } }, "required": ["translated", "confidence"] }, "version": "0.1.0", "fidelity": "Wrapped", "transparency": "Open"}Phenotype fields explained:
| Field | Description |
|---|---|
domain | Functional domain — genes with the same domain compete in Arena |
inputSchema | JSON Schema for input validation |
outputSchema | JSON Schema for output validation |
version | Semantic version |
fidelity | Wrapped (API call), Hybrid (mix), or Native (pure WASM) |
transparency | Open (source auditable) or Opaque |
Or use rotifer wrap to generate these automatically:
rotifer wrap my-translator --domain text.translateStep 3: Test Your Gene
Section titled “Step 3: Test Your Gene”rotifer test my-translatorThe test suite automatically:
- Validates your Phenotype against the Gene Standard
- Calls
express()with generated test inputs - Checks that output matches
outputSchema - Verifies error handling
- Computes preliminary fitness scores
Add --verbose for detailed I/O:
rotifer test my-translator --verboseStep 4: Compile to WASM
Section titled “Step 4: Compile to WASM”Transform your TypeScript gene into a sandboxed WASM module:
rotifer compile my-translatorThis runs the compilation pipeline:
- esbuild — Bundle and minify TypeScript
- WASI shim — Add WASI compatibility layer
- Javy — Compile JavaScript to WASM via QuickJS
- IR Injector — Add Rotifer custom sections
The output gene.ir.wasm is a self-contained WASM module with embedded metadata.
After compilation, your gene’s fidelity upgrades from Wrapped to Native.
Step 5: Submit to Arena
Section titled “Step 5: Submit to Arena”rotifer arena submit my-translatorThe Arena:
- Runs L2 sandbox tests (automatic)
- Computes fitness score F(g) and safety score V(g)
- Ranks your gene against others in the same domain
- Records the entry in the local Arena database
Check rankings:
rotifer arena list -d text.translateStep 6: Publish to Cloud
Section titled “Step 6: Publish to Cloud”Share your gene with other developers:
rotifer login # Authenticate with GitHubrotifer publish my-translator # Upload to cloud registryOthers can now find and use your gene:
# Another developerrotifer search "translator"rotifer install <your-gene-id>Step 7: Compete in Cloud Arena
Section titled “Step 7: Compete in Cloud Arena”rotifer arena submit my-translator --cloudrotifer arena list --cloud -d text.translateGene Best Practices
Section titled “Gene Best Practices”Domain Naming Convention
Section titled “Domain Naming Convention”Use dot-separated hierarchical names:
search.web # Web searchsearch.code # Code searchfile.read # File readingfile.write # File writingcode.format # Code formattingcode.generate # Code generationtext.translate # Translationtext.summarize # Summarizationdata.transform # Data transformationSchema Design
Section titled “Schema Design”- Use JSON Schema draft 2020-12
- Always specify
requiredfields - Add
descriptionto every property - Use
minimum/maximumfor numeric constraints - Prefer specific types over
any
Error Handling
Section titled “Error Handling”Throw typed errors from express():
export async function express(input: { query: string }) { if (!input.query?.trim()) { throw new Error("INVALID_INPUT: query must be a non-empty string"); }
try { const result = await performSearch(input.query); return { results: result }; } catch (err) { throw new Error(`EXECUTION_FAILURE: ${err.message}`); }}Performance Tips
Section titled “Performance Tips”- Minimize cold start time — avoid heavy imports at module level
- Cache expensive resources (API clients, compiled patterns)
- Return early on validation failures
- Use streaming for large outputs when possible