Contributing
How to contribute to ZERG. This guide covers code style, commit conventions, the PR process, and review expectations.
Code Style
Erlang (Sol Server)
Use the logger module for all logging. Never use io:format in production code:
logger:info("scheduler: created job ~p", [JobId]).
logger:warning("auth failed for token ~p", [TokenHint]).
logger:error("zmq gateway crashed: ~p", [Reason]).Use process_flag(trap_exit, true) in all gen_servers that own resources (OS processes, ETS tables, sockets). ETS tables must use {heir, Pid} to survive owner crashes.
gen_server:call must always use a timeout constant, never bare calls:
-define(CALL_TIMEOUT, 5000).
handle_call({create_job, Spec}, _From, State) ->
gen_server:call(?MODULE, {create_job, Spec}, ?CALL_TIMEOUT).For fire-and-forget operations that reply to From, use spawn + erlang:monitor instead of spawn_link to avoid killing the calling gen_server on failure.
Lua (Luna Client)
Use cel.json for all JSON operations. Do not import dkjson or JSON_luerl directly:
local json = require("cel.json")
local data = json.decode(raw)
local encoded = json.encode(data)Use cel.class for all OOP (middleclass v4.1.1):
local MyClass = require("cel.class")("MyClass")
function MyClass:initialize(config)
self.config = config
end
return MyClassUse cel.shell_quote for all shell arguments to prevent injection:
local shell_quote = require("cel.shell_quote")
os.execute("cat " .. shell_quote(filename))Return nil, err on errors:
function MyClass:execute(args)
if not args then
return nil, "args required"
end
return result
endPython (Mango)
Follow PEP 8 with Tornado conventions. Use type hints where practical.
TypeScript/Vue.js (Limon)
Follow the existing component structure. Use Composition API with <script setup>.
Module Naming
| Component | Convention | Example |
|---|---|---|
| Sol HTTP handlers | sol_http_<domain>.erl | sol_http_memory.erl |
| Sol gen_servers | sol_<domain>.erl | sol_scheduler.erl |
| Sol stores | sol_<domain>_store.erl | sol_scheduler_store.erl |
| Luna core | core/<feature>.lua | core/redaction.lua |
| Luna tools | core/tools/<tool>.lua | core/tools/web_search.lua |
| Luna FFI | ffi/<lib>.lua | ffi/zmq.lua |
| Mango systems | mango/systems/<name>.py | mango/systems/auth.py |
Commit Conventions
Use concise, descriptive commit messages in imperative mood:
add pgvector memory search endpoint
fix scheduler missed-job detection for cron schedules
refactor auth middleware to use persistent_term cachePrefix with component when ambiguous:
sol: add admin check to infra maintenance endpoints
luna: fix shell quoting for MCP OAuth callback URL
mango: seed admin RBAC on setup_dbPR Process
Before Submitting
- Run the full test suite and confirm no new failures:
cd server && rebar3 eunit
cd client && for f in tests/test_*.lua; do luajit "$f"; done
cd mango && python3 -m pytest tests/ -vVerify existing tests still pass. All tests pass with 0 failures.
If adding new endpoints, add corresponding test coverage.
If modifying authentication or authorization logic, add security tests.
PR Description
Include:
- What the change does
- Why it is needed
- Test coverage added
- Any breaking changes
Code Review Expectations
Reviewers check for:
- Correct OTP patterns (trap_exit, ETS heir, gen_server timeouts)
- Proper error handling (no silent catches, no swallowed errors)
- Security implications (input validation, auth checks, shell quoting)
- Test coverage for new code paths
- Documentation updates for API changes
Adding New Test Files
Erlang Tests
Create server/test/sol_<module>_tests.erl with eunit test functions.
Lua Tests
Create client/tests/test_<feature>.lua following the helper pattern with ok and check functions. Exit with code 1 on failure.
Test Naming
Test names should describe the specific behavior being verified:
memory_store_with_ttl_test() ->
...
memory_store_missing_key_returns_400_test() ->
...License
ZERG is released under the MIT License. By contributing, you agree that your contributions will be licensed under the same terms.