This file contains guidelines and commands for agentic coding agents working on the self project - an AI-native virtual machine with the Ego programming language.
self is a Rust-based workspace implementing:
- CLI (
selfcli) - Ego language compiler and command-line interface - Core (
self-vm) - Virtual machine runtime with native AI integration - Emulator - Bytecode execution environment
The project implements Ego (.ego files), an AI-first programming language that compiles to bytecode and runs on the self-VM.
# Build entire workspace
cargo build
# Build with optimizations
cargo build --release
# Build specific component
cargo build -p selfcli
cargo build -p self-vm
cargo build -p emulator
# Run CLI compiler
cargo run -p selfcli -- [args]
# Run emulator
cargo run -p emulator -- [args]
# Format code
cargo fixfmt
cargo fmtc # check formatting
# Clean build artifacts
cargo cleanThis project uses manual testing via .ego files rather than automated test suites:
# Run test files manually
cargo run -p selfcli -- run test.ego
cargo run -p selfcli -- run test_bound_access.ego
cargo run -p selfcli -- run main.ego
# Test with emulator
cargo run -p emulator -- [bytecode_file]Note: No automated test framework is configured. Tests are manual .ego files in the root directory.
- Use
use crate::for internal imports - Group external imports separately
- Module organization with
mod.rsfiles - Extensive use of
pubvisibility modifiers
// Preferred import style
use std::io::{self, Write};
use crate::{
core::error::VMError,
memory::{Handle, MemObject},
std::{heap_utils::put_string, NativeMember},
types::{
object::func::{Engine, Function},
Value,
},
vm::Vm,
};- Functions/Variables:
snake_case - Types/Structs:
PascalCase - Constants:
SCREAMING_SNAKE_CASE - Modules:
snake_case
- Custom error enums:
VMError,ErrorType - Use
Result<T, Error>for recoverable errors - Use
throw()function for fatal errors (exits process) - Error handling via
std::process::exit(1)
// Custom error pattern
pub fn read_line(
vm: &mut Vm,
_self: Option<Handle>,
params: Vec<Value>,
debug: bool,
) -> Result<Value, VMError> {
if params.is_empty() {
return Err(VMError::RuntimeError(
"read_line requires no parameters".to_string(),
));
}
// ... implementation
}- Native functions follow three-part pattern:
*_def()- Metadata definition*_obj()- Object creation*()- Native implementation
pub fn print_line_def() -> NativeMember { /* ... */ }
pub fn print_line_obj() -> MemObject { /* ... */ }
pub fn print_line(vm: &mut Vm, _self: Option<Handle>, params: Vec<Value>, debug: bool) -> Result<Value, VMError> { /* ... */ }- Import statements at top:
import ai,import env,import io - Function declarations with
fn identifier() {} - Use
letfor variable declarations - Arrow functions:
(params) -> { body }
// chain usage
import ai
import env
import io
env.read()
let chain = ai.chain(
"prompt description",
"error description"
)
let result = chain.unfold((link) -> {
println("THOUGHT: ", link.def)
println(" `- ", link.action.module, ".", link.action.member)
let out = link.action.exec()
return { continue: true, resolved: out }
})
// function to send emails
fn send_email(to, subject, body) {
// send an emails with the findings
let resend_api_key = env.get("RESEND_API_KEY")
let res = http.post("https://api.resend.com/emails", {
headers: {
"content-type": "application/json",
"authorization": "Bearer "+resend_api_key
},
body: json.encode({
from: "friend@self.computer",
to: to,
subject: subject,
html: body
})
})
}
send_email("test@gmail.com", "self test", "<p>Hi, friend</p>")
- CLI: AST, parser, compiler, commands
- Core: VM, instructions, types, runtime, stdlib, error handling
- Stdlib: Native modules (ai, io, env, http, fs, etc.)
When adding new stdlib functions:
- Create function in
core/src/std/[module]/members.rs - Add to
core/src/std/[module]/mod.rs - Update module exports in
core/src/std/mod.rs - Follow three-part pattern:
*_def(),*_obj(),*()
- VM Level:
VMErrorfor runtime errors - CLI Level:
ErrorTypefor compilation errors - Module-specific:
AIError,IOError,NetError, etc.
- Build First: Always run
cargo buildbefore testing - Manual Testing: Use
.egofiles for testing functionality - Format Code: Run
cargo fixfmtbefore committing - Cross-Platform: Consider macOS, Linux, Windows compatibility
- Runtime:
tokiowith multi-threaded runtime - Web:
reqwest,chromiumoxidefor browser automation - Serialization:
serde,serde_json - AI:
rmcpfor AI model communication - WASM:
wasm-bindgenfor web support
- Warning Suppression:
#![allow(warnings)]is used in main.rs - No Formal Tests: Manual testing via
.egofiles only - AI-First Design: Native AI integration is a core feature
- Cross-Platform: Supports desktop and WebAssembly targets
- Error Handling: Fatal errors use process exit, not Result propagation
- Rust:
.rs - Ego Language:
.ego - Bytecode: (varies, typically no extension or
.bin) - Configuration:
.toml(Cargo),.env(environment)
let result = chain.unfold((link) -> {
// implementation
return { continue: true, resolved: out }
})
pub fn function_name(
vm: &mut Vm,
_self: Option<Handle>,
params: Vec<Value>,
debug: bool,
) -> Result<Value, VMError> {
// implementation
}pub fn generate_struct() -> (String, Vec<(String, MemObject)>) {
let mut fields = vec![];
fields.push(("function_name".to_string(), function_name_obj()));
("module_name".to_string(), fields)
}