Development Guide
Set up the ZERG development environment, build all components, and understand the codebase structure.
Prerequisites
| Dependency | Version | Purpose |
|---|---|---|
| Erlang/OTP | 28 | Sol server |
| rebar3 | Latest | Erlang build tool |
| LuaJIT | 2.1+ | Luna agent, CLI |
| Python | 3.11+ | Mango auth service |
| Node.js | 18+ | Limon, docs-site |
| PostgreSQL | 16+ | Memory/embeddings (optional) |
Building the Server
cd server
rebar3 compileFor a release build:
rebar3 as prod releaseRun in development mode:
rebar3 shellThe development shell starts the Sol application with default configuration. The HTTP API is available at http://127.0.0.1:21434.
Building the Luna Client
cd client
bash build/build.shThe build script produces a stripped binary at client/build/luna (approximately 994KB). The build pipeline compiles Lua to bytecode, applies XOR obfuscation, and appends CRC32 checksums.
Building the CLI
cd zerg-cli
bash build/build.shProduces a standalone binary at zerg-cli/build/zerg (321-377KB). Built with luastatic, XOR, and UPX compression.
Running Tests
Server Tests (Erlang eunit)
cd server
rebar3 eunit4,600+ test functions across 433 test files.
Luna Tests (LuaJIT)
cd client
luajit tests/test_redaction.lua
luajit tests/test_shell_quoting.lua
luajit tests/test_permission_checker.luaRun all tests:
for f in client/tests/test_*.lua; do luajit "$f"; doneMango Tests (Python)
cd mango
python3 -m pytest tests/ -v348 tests, 0 expected failures.
CLI Tests
cd zerg-cli
bash tests/run.sh487 assertions, 0 expected failures.
Limon Tests
cd limon
npm test379 tests, 0 failures (11 pre-existing known).
Code Structure
Server (server/src/)
The server follows OTP conventions with 289 modules:
| Module Prefix | Count | Purpose |
|---|---|---|
sol_http_ | ~15 | HTTP request handlers |
sol_zmq_ | ~8 | ZMQ gateway and protocol |
sol_plugin_ | ~12 | Plugin system (Luerl sandbox) |
sol_worker_ | ~5 | Worker process management |
sol_infra_ | ~5 | Infrastructure (health, metrics, SLO) |
sol_memory_ | ~5 | Memory and embedding storage |
sol_sched_ | ~3 | Scheduler (cron/at/every) |
Client (client/)
| Directory | Purpose |
|---|---|
core/ | Core agent logic, tools, providers |
ui/ | TUI rendering (LTUI/ncurses) |
ffi/ | Foreign function interface bindings |
vendor/ | Third-party libraries (middleclass, etc.) |
Naming Conventions
Erlang modules: sol_<domain>_<component>.erl
sol_http_conversations.erl-- HTTP handler for conversationssol_zmq_gateway.erl-- ZMQ gateway gen_serversol_scheduler.erl-- Scheduler gen_serversol_plugin_manager.erl-- Plugin manager gen_server
Lua modules: <domain>_<component>.lua or <domain>/<component>.lua
core/redaction.lua-- Secret redaction enginecore/permission_checker.lua-- Permission evaluationffi/zmq.lua-- ZMQ FFI bindings
Adding New HTTP Endpoints
1. Create the Handler Module
Create server/src/sol_http_mymodule.erl:
-module(sol_http_mymodule).
-export([handle/2]).
handle(mymodule_list, Req) ->
Items = [],
{200, sol_http_json:json_response(#{items => Items})};
handle(mymodule_detail, Req) ->
Id = cowboy_req:binding(id, Req),
{200, sol_http_json:json_response(#{id => Id})}.2. Register the Route
Add the route in sol_http.erl to the Cowboy dispatch list:
{"/api/v1/mymodule", ?MODULE, [mymodule_list]},
{"/api/v1/mymodule/:id", ?MODULE, [mymodule_detail]}3. Wire the Handler
Map the route atom to the handler module:
mymodule_list => {sol_http_mymodule, handle},
mymodule_detail => {sol_http_mymodule, handle}4. Add Ownership Check (if needed)
For user-scoped resources, use sol_identity:check_resource_owner/3.
Adding New Luna Tools
1. Create the Tool Module
Create client/core/tools/my_tool.lua:
local MyClass = require("cel.class")("MyTool")
function MyClass:initialize(config)
self.config = config
end
function MyClass:execute(args)
return {output = "result"}
end
return MyClass2. Register in Tool Registry
Add the tool definition following the builtin__ prefix convention.
3. Follow Conventions
- Use
cel.jsonfor all JSON operations (no direct dkjson imports) - Use
cel.classfor OOP (middleclass v4.1.1) - Use
cel.shell_quotefor all shell arguments - Return
nil, erron errors
Development Configuration
The default sys.config runs with authentication disabled for local development:
[
{sol, [
{http_port, 21434},
{http_ip, "127.0.0.1"},
{mango_auth_enabled, false},
{memory_pg_enabled, false},
{pgvector_enabled, false}
]}
].Enable individual features as needed for testing. Authentication, memory, and pgvector are all optional for development.