- Add ene-node, ene-rds-chat, ene-rds-ephemeral, ene-rds-wiki, ene-storage, ene-sync crates to the ene-rds workspace - Extend ene-rds-core with shared types and cluster messaging - Add review doc and wiki page for the RDS Rust workspace - Fix devcontainer: custom /etc/passwd with researcher user, add gcc/glibc/binutils for VS Code server compatibility, include util-linux, gnutar, gzip; add LD_LIBRARY_PATH - Ignore Nix build output (`result`) and Rust artifacts Generated with [Devin](https://cli.devin.ai/docs) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
7.2 KiB
ENE RDS Rust Workspace
Overview
The ene-rds workspace replaces the Python RDS stack (ene_rds_* modules) with a unified Rust binary suite. All PostgreSQL surfaces—wiki, ephemeral nodes, chat logs, and the HTTP API—are now native Rust crates.
Location: 4-Infrastructure/infra/ene-rds/
Workspace Crates
| Crate | Type | Replaces | Purpose |
|---|---|---|---|
ene-rds-core |
lib | ene_rds_* base connection logic |
Shared RdsClient, DSN builder, vec_to_pgtext(), ingestion receipts |
ene-rds-wiki |
lib | ene_rds_wiki_layer.py |
Wiki pages, revisions, links, categories, full-text search |
ene-rds-ephemeral |
lib | ene_rds_ephemeral_node.py |
EphemeralNode thermal zones, tasks, receipts, scar events, metrics |
ene-rds-chat |
lib | ene_rds_chat_log.py |
Chat session ingestion, keyword search, semantic similarity |
ene-api |
bin | ene_chat_api.py |
Axum HTTP server on :3000 mounting all surfaces |
ene-sync |
bin | ene_claw_sync.py |
Polls opencode.db SQLite → upserts into RDS chat tables |
Build
cd 4-Infrastructure/infra/ene-rds
cargo build --release
Dependencies are fetched from crates.io on first build.
Run
Initialize schema only
export RDS_PASSWORD=...
./target/release/ene-sync init-schema
One-shot sync (opencode.db → RDS)
./target/release/ene-sync sync --embed
Watch mode (polls every 60s, incremental)
./target/release/ene-sync watch --interval 60 --embed
API server
./target/release/ene-api
Endpoints:
GET /health— service statusGET /sessions?limit=10— list chat sessionsGET /sessions/:id— get full session with messagesGET /search?q=query&limit=10— keyword search across messagesGET /wiki/search?q=query— wiki full-text searchGET /wiki/:slug— get wiki page by slugGET /ephemeral/nodes?zone=hot— list nodes by thermal zoneGET /ephemeral/nodes/:id— get single node
Environment Variables
| Variable | Default | Purpose |
|---|---|---|
RDS_HOST |
database-1.cluster-c9i0w8eu8fnv.us-east-2.rds.amazonaws.com |
PostgreSQL host |
RDS_PORT |
5432 |
PostgreSQL port |
RDS_USER |
postgres |
PostgreSQL user |
RDS_PASSWORD |
— | Password or IAM token |
RDS_DB |
postgres |
Database name |
OLLAMA_HOST |
http://localhost:11434 |
Ollama embedding endpoint |
OLLAMA_EMBED_MODEL |
nomic-embed-text |
Embedding model |
Architecture Changes from Python
| Concern | Python (old) | Rust (new) |
|---|---|---|
| PostgreSQL driver | psycopg2 |
tokio-postgres with with-serde_json-1 |
| JSONB handling | Manual string serialization | Native serde_json::Value ↔ JSONB |
| pgvector vectors | Python list → string | vec_to_pgtext() — '[0.1,0.2,...]'::vector |
| HTTP server | FastAPI | Axum |
| SQLite source | — | rusqlite with bundled bindings |
| Ollama embeddings | requests |
reqwest |
| Runtime | Python 3.11 + venv | Single static binary |
Database Schema
The Rust surfaces create the following tables on init_tables():
ene.chat_sessions
session_id TEXT PRIMARY KEYworkspace_fingerprint TEXT,workspace_root TEXTfork_parent_session_id TEXT(self-referential for session forks)compaction_count INTEGER,compaction_summary TEXTmessage_count INTEGER,token_input_total BIGINT,token_output_total BIGINTcreated_at_ms BIGINT,updated_at_ms BIGINTfirst_message_at_ms BIGINT,last_message_at_ms BIGINTembedding vector(768)— session-level semantic vectormeta JSONB— slug, agent, model, project_id, cost, cache tokensreceipt TEXT,updated_at TIMESTAMPTZ
ene.chat_messages
id BIGSERIAL PRIMARY KEYsession_id TEXT REFERENCES chat_sessionsmessage_index INTEGER(ordered within session)role TEXT— user, assistant, tool, systemblocks JSONB— typed content blocks (text, reasoning, tool_use, tool_result)text_content TEXT— concatenated text for full-text searchtoken_input BIGINT,token_output BIGINT,token_cache_creation BIGINT,token_cache_read BIGINTtool_calls JSONB— extracted tool calls for structured searchembedding vector(768)— per-message semantic vectorreceipt_hash TEXT— links to ingestion receiptcreated_at_ms BIGINT,created_at TIMESTAMPTZ
ene.ephemeral_nodes
node_id TEXT PRIMARY KEYthermal_zone TEXT— hot, warm, coldreliability_raw BIGINT— Q0_32 fixed-pointlatency_p95_ms BIGINTscar_count INTEGERlast_seen_ms BIGINTreputation_raw BIGINT— Q16_16 fixed-pointquarantine_until_ms BIGINTmeta JSONBcreated_at_ms BIGINT,updated_at_ms BIGINT
ene.ephemeral_tasks
task_id TEXT PRIMARY KEYsession_id TEXT,node_id TEXT REFERENCES ephemeral_nodestask_state TEXT— pending, dispatched, partial, complete, expired, abandonedpriority_raw BIGINT,ttl_ms BIGINTdispatched_at_ms BIGINT,completed_at_ms BIGINTresult_hash TEXT,meta JSONB
ene.ephemeral_receipts
receipt_id TEXT PRIMARY KEYtask_id TEXT,node_id TEXTcross_matrix JSONB— braid crossing matrixsidon_slack INTEGER,step_count INTEGERresidual_series BIGINT[]— Q0_32 residual serieswrite_timing_ms BIGINTscar_absent BOOLEAN
ene.ephemeral_scar_events
scar_id TEXT PRIMARY KEYnode_id TEXT,task_id TEXTscar_pressure BIGINT,failure_mode TEXT,coarsening_agent TEXT
ene.ephemeral_metrics
metric_id TEXT PRIMARY KEYnode_id TEXT,metric_name TEXTmetric_value_raw BIGINT,metric_scale INTEGERrecorded_at_ms BIGINT
Sync Daemon (ene-sync)
The sync binary reads from the OpenCode SQLite database at ~/.local/share/opencode/opencode.db:
- Sessions — metadata, tokens, costs, workspace fingerprint
- Messages — conversation turns with role and timing
- Parts — actual content (text, reasoning, tool calls, tool results)
- Session messages — lifecycle events (agent switches, model switches)
Content is normalized into ChatSession + ChatMessage structs, embeddings generated via Ollama, then upserted into RDS.
Incremental sync
Watch mode tracks MAX(time_updated) from the session table in a local state file (~/.cache/ene-sync/state.json). Only sessions updated since the checkpoint are re-ingested.
Python Bridge (Legacy Support)
For calling unported Python modules, bridge_wrapper.py auto-discovers classes with handle_request() methods and dispatches JSON requests. The Rust surfaces do not depend on this bridge.
Future Work
- Add
postgres-native-tlsorrustlsfor RDS TLS instead ofNoTls - Wire semantic search in
ene-api(currently returns placeholder error) - Add
pgvectorbinary format support for faster embedding inserts - Batch embedding requests if Ollama adds native batching
Related
4-Infrastructure/infra/ene-rds/README.md— crate-level README with quickstart4-Infrastructure/infra/ene_rds_wiki_layer.py— legacy Python wiki surface4-Infrastructure/infra/ene_rds_fractal_fold.py— legacy Python fractal surface0-Core-Formalism/lean/Semantics/EphemeralNode/— Lean thermal zone formalism