Caution
Sumeru is pre-alpha software. It is under active development and is not ready for production or commercial use.
- No production use. Do not deploy to production or run live business workloads. Stability, security, and data integrity are not guaranteed.
- Not for sale. Do not offer, resell, license, or deploy Sumeru to customers. This is not a commercial product.
- Evaluation only. Use for local development, testing, and feedback at your own risk.
APIs, data models, and behavior may change without notice. There is no migration guarantee and no production support.
Sumeru is an experimental ERP-style web application written in Go. It provides a PostgreSQL-backed ORM, installable addons (module XML under <sumeru> + manifests), model sync on startup, and a web UI (XML views, plain CSS, shell with sidebar and activity panel).
This repository is the core engine (module sumeru). Most teams keep it pull-only and run the server from sumeru_custom_addons.
- Modular addons with manifests, XML views/menus, and Go model registration
- PostgreSQL ORM with model sync on startup
- Web shell: apps catalog, home, settings, tree/form/kanban workspaces
- JSON-RPC at
POST /api/rpc(plusGET /api/health) - Stable addon API via
sumeru/core/sdk(prefer over importingsumeru/core/ormdirectly)
Sumeru is split into three repositories so you can pull updates to the engine and standard apps without mixing in customer-specific code.
sumeru_custom_addons ──replace + make generate──► sumeru (core)
│ │
└──replace + addons_path──────────────────────►│
│ ▼
└──make run────────────────────────────► HTTP server
▲
└── also loads sumeru_addons (standard business apps)
| Repository | Role | Remote |
|---|---|---|
sumeru |
Core engine + kernel addons (base, mail, …). Pull-only for most teams. |
git@github.com:ProjectMeru/sumeru.git |
sumeru_addons |
Standard business apps (CRM, Sales, Inventory, …). Pull-only. | git@github.com:ProjectMeru/sumeru_addons.git |
sumeru_custom_addons |
Your workspace: custom addons, local INI, generated imports, and the process you run. | git@github.com:ProjectMeru/sumeru_custom_addons.git |
Entry binary (this repo): cmd/sumeru/main.go → sumeru/core/server (server.Run). Library code under core/ has no main.
| Requirement | Notes |
|---|---|
| Go 1.26.2+ | See go.mod |
| PostgreSQL | Application database |
Clone all three repos as siblings, configure the custom workspace, generate blank-imports, then run.
mkdir -p ~/sumeru_erp && cd ~/sumeru_erp
git clone git@github.com:ProjectMeru/sumeru.git
git clone git@github.com:ProjectMeru/sumeru_addons.git
git clone git@github.com:ProjectMeru/sumeru_custom_addons.git
# Create an empty database matching db_name in your INI, e.g.:
# psql -c "CREATE DATABASE sumeru;"
cd sumeru_custom_addons
cp sumeru.conf.example sumeru.conf # edit db_* , http_port, addons_path
make replace-sumeru
make replace-sumeru-addons
make generate # → addonimports/zimports.go
make run # generate + go runOpen http://localhost:<http_port> (default 8080). / redirects to /web/apps.
cd ../sumeru && git pull
cd ../sumeru_addons && git pull
cd ../sumeru_custom_addons && make generate && make runFull workspace details: sibling sumeru_custom_addons/README.md.
Useful when you only need kernel addons under sumeru/addons/:
cd sumeru
cp sumeru.conf.example sumeru.conf # edit db_* ; addons_path = addons
make generate # refreshes cmd/sumeru/zimports.go
make run # or: go run ./cmd/sumeru -- -c sumeru.confInstall first apps (example), then serve:
go run ./cmd/sumeru -- -c sumeru.conf -i company,user --stop-after-init
go run ./cmd/sumeru -- -c sumeru.confINI format: key = value under [options]. Lines starting with # or ; are comments. Path-related values resolve from the INI file’s directory (and optional sumeru_home for default assets/templates). Prefer absolute paths in production.
Copy sumeru.conf.example → sumeru.conf.
| Key | Use case |
|---|---|
db_host, db_port |
PostgreSQL host and port |
db_user, db_password |
Database credentials |
db_name |
Database name (overridable with -d / --database) |
db_sslmode |
PostgreSQL SSL mode (e.g. disable for local dev) |
http_port |
HTTP listen port (default 8080; overridable with -p / --http-port) |
addons_path |
Comma-separated addon roots. Later roots override duplicate module names. Relative segments resolve from the INI directory. |
sumeru_home |
Optional path to the standard sumeru checkout; default assets/templates when those keys are omitted |
assets_path, templates_path |
Static files and HTML templates (defaults under core/engine/…) |
logo_path |
Optional image; served at /static/app-logo |
company_display_name, user_display_name |
Optional header labels |
brand_css |
Optional extra CSS; linked as /static/brand.css |
dev_mode |
Default false. When true, debug-level logs and dev-only behavior |
Logging: structured JSON via stdlib log/slog (sumeru/core/applog). When log_enabled=true, logs always go to stdout; log_file is optional (with log_rolling / size keys). See sumeru.conf.example.
| Endpoint | Use case |
|---|---|
GET /api/health |
Liveness; {"ok":true} (no auth) |
POST /api/rpc |
Model RPC with session cookie or API key (see below) |
Authentication: session cookie (sumeru_session) from /web/login, or X-API-Key: sk_… / Authorization: Bearer sk_….
Request (Content-Type: application/json):
Sumeru flat shape:
{
"model": "core.user",
"method": "search_read",
"args": [[["active", "=", true]], ["id", "login"]],
"kwargs": { "limit": 50, "offset": 0 }
}wrapper (also supported):
{
"params": {
"model": "core.user",
"method": "search",
"args": [[]],
"kwargs": {}
}
}Response envelope (always JSON; HTTP status reflects success or error class):
{ "ok": true, "result": <method-specific>, "error": null }{
"ok": false,
"result": null,
"error": {
"code": "ACCESS_DENIED",
"message": "access denied on core.user for operation read",
"details": {}
}
}Legacy clients may ignore ok and continue checking error == null.
Public methods
| Method | args |
kwargs |
result |
|---|---|---|---|
search |
[domain?] |
limit, offset |
[{record}, …] |
search_read |
[domain, fields] |
limit, offset |
[{record}, …] (field projection) |
read |
[ids, fields?] |
— | [{record}, …]; missing ids → NOT_FOUND with details.missing_ids |
create |
[values] |
— | int (new id) |
write |
[ids, values] |
— | true |
unlink |
[ids] |
— | true |
create_many |
[[values], …] |
— | [id, …] |
write_many |
[ids, values] |
— | true |
unlink_many |
[ids] |
— | true |
Default kwargs.limit is 500 (hard cap). offset is applied in SQL via ORM SearchPage (LIMIT/OFFSET), not an in-memory slice. Deep offsets are clamped (max 1_000_000).
Observability: every response includes X-Request-ID (echoed from the request header when set). Prometheus-style metrics are at GET /metrics (sumeru_rpc_*, sumeru_orm_ops_total, sumeru_db_query_duration_seconds) and require a session in base.group_system.
Architecture boundaries (ORM vs ERP modules): see docs/architecture/orm-boundaries.md.
Error codes (representative HTTP status)
error.code |
HTTP | Typical cause |
|---|---|---|
INVALID_JSON |
400 | Malformed JSON, empty body |
INVALID_ARGS |
400 | Bad args/kwargs shape or arity |
VALIDATION_ERROR |
400 | Missing model or method |
INVALID_BODY |
400 | Request body could not be read |
UNSUPPORTED_MEDIA_TYPE |
415 | Content-Type is not JSON |
PAYLOAD_TOO_LARGE |
413 | Body exceeds 4 MiB |
UNAUTHORIZED |
401 | No session or API key |
METHOD_NOT_ALLOWED |
403/405 | Unknown RPC method / wrong HTTP verb |
MODEL_NOT_FOUND |
404 | Model not in registry |
NOT_FOUND |
404 | Record id(s) not found on read |
ACCESS_DENIED |
403 | ORM security rule |
INTERNAL_ERROR |
500 | Unexpected server failure |
All entrypoints (go run ./cmd/sumeru --, ./sumeru.sh, ./sumeru, and the custom-workspace go run . --) accept:
| Flag | Use case |
|---|---|
-c <file> |
INI config path |
-d <name> / --database <name> |
Override db_name (--database wins if both set) |
-p <port> / --http-port <port> |
Override http_port (-p wins if both set) |
-i mod1,mod2 |
Install listed modules |
-u mod1,mod2 or -u all |
Update from disk; all = every installed module |
--stop-after-init |
After -i / -u, exit without starting HTTP |
Examples:
go run ./cmd/sumeru -- -c sumeru.conf -p 9090
go run ./cmd/sumeru -- -c sumeru.conf -i sales,crm --stop-after-init
go run ./cmd/sumeru -- -c sumeru.conf -u all -p 9090 --stop-after-init
make run EXTRA_RUN_FLAGS='-u sales -p 9090'Use -u after changing views/*.xml, menus.xml, or manifest.json data lists for an already-installed module.
ACL CSV: security/sys.access.csv is loaded automatically during sync; you do not need to list it in manifest data (XML entries only).
sumeru_ai is not linked into the default server binary (auto_import: false in its manifest). The setup wizard and platform spine install base only; AI hooks (ORM interceptors, shell FAB) run only after you opt in:
- Set
"auto_import": trueinaddons/sumeru_ai/manifest.jsonor add_ "sumeru/addons/sumeru_ai"to your workspacezimports.go. - Run
make generate && make build(relink Go hooks). - Install the module: Apps Install or
go run ./cmd/sumeru -- -i sumeru_ai.
Without steps 1–2, installing via Apps alone loads XML/data but does not register Go interceptors.
| Target | Use case |
|---|---|
make generate |
go generate ./cmd/sumeru: refresh cmd/sumeru/zimports.go from sumeru.conf.example |
make run |
Generate, then go run ./cmd/sumeru -- -c sumeru.conf (optional EXTRA_RUN_FLAGS) |
make build |
Generate, then go build -o sumeru ./cmd/sumeru |
make bp NAME=my_module |
Scaffold a core-tree addon (sdk.Model + views + security; then make generate) |
make css |
Reminder: plain CSS under core/engine/assets/css/ (no Sass build) |
make check-logs |
Forbid stdlib log and operational fmt.Printf in server paths |
make help |
List targets |
In sumeru_custom_addons, use that repo’s Makefile (make setup, make new MODULE=…, make generate, make run) so imports are written under addonimports/, not into this tree.
sumeru-import-gen (used by go generate / workspace make generate):
| Flag | Default | Use case |
|---|---|---|
-root |
cwd walk-up | Standard sumeru repo root |
-config |
sumeru.conf.example (via go generate in cmd/sumeru) |
INI path |
-out |
cmd/sumeru/zimports.go |
Output file (absolute path when writing under custom workspace) |
-package |
main |
e.g. addonimports for the workspace |
| Path | Use case |
|---|---|
core/orm/ |
PostgreSQL-backed models, CRUD, registry |
core/engine/ |
Module XML, view inherit, HTML render, templates/, assets/ |
core/server/ |
INI config, run.go, HTTP web handlers |
core/module/ |
Addon discovery, install/update, XML sync |
core/sdk/ |
Stable Go API for addons |
core/server/router/ |
Addon-extensible HTTP route registry |
core/module/addon_template/ |
Authoring reference for new addons |
cmd/sumeru/ |
Server main + generated zimports.go |
cmd/sumeru-import-gen/ |
Blank-import generator |
cmd/sumeru-bp/ |
Addon scaffold tool |
addons/ |
Kernel apps shipped with this repo |
test/ |
Unit and smoke tests (go test ./...) |
sumeru.conf.example |
Tracked template + import-gen input |
sumeru.sh |
Bash wrapper forwarding CLI flags |
Makefile |
generate, run, build, bp, help |
Styles are plain CSS under core/engine/assets/css/ (layout uses sum-* classes and design tokens). Global stack: DefaultStylesheetURLs() in core/engine/assets/stylesheets.go.
Canonical reference: keep the global CSS file table below only in this README. Other docs should link here instead of duplicating the list.
| File | Responsibility |
|---|---|
sumeru-theme.css |
Branding tokens (:root colors, typography, radii, shadows) |
sumeru-base.css |
Document defaults, scrollbars, .sr-only, etc. |
sumeru-shell.css |
Top bar, sidebar, workspace grid, activity dock chrome |
sumeru-messages.css |
Activity panel Messages tab |
sumeru-views.css |
Form sheets, list tables, notebooks, field chrome |
sumeru-compat.css |
Legacy .field blocks for login/setup templates |
sumeru-ai.css |
Optional AI shell widget (sumeru_ai) |
sumeru-login.css |
Standalone login card |
sumeru-pages.css |
Standalone pages (e.g. app logs) |
sumeru-apps.css |
/web/apps catalog (per-page) |
sumeru-home.css |
/web/home (per-page) |
sumeru-settings-hub.css |
/web/settings (per-page) |
sumeru-workspace.css |
/web workspace extras |
Per-addon optional static/css/theme-overrides.css is served as /static/addon-css/<module>.css. Optional brand_css loads after those. Workspace UI is SWC (core/swc/ → core/engine/assets/swc/swc.js); shell templates live under core/engine/templates/; shell/page assembly under core/engine/render/.
| Resource | Contents |
|---|---|
| This README | Setup, config, CLI, Makefile, CSS |
sumeru_addons/README.md |
Standard business addon module |
sumeru_custom_addons/README.md |
Workspace runner, make generate, custom addons |
Sibling docs/ (local workspace) |
Developer guides and how-tos when checked out next to this repo (e.g. ../docs/developer/). Not shipped inside this git tree |
See CONTRIBUTING.md for where to put changes, the generate/test loop, and PR expectations.
Please follow the Code of Conduct.
Report vulnerabilities privately. See SECURITY.md. Do not open public issues for undisclosed security problems.
Licensed under the Apache License, Version 2.0.