Skip to main content

Development setup

Prerequisites​

ToolVersionPurpose
Go1.26+Backends, agent, connector, shared packages
Node.js24 LTS + pnpm 10Web apps, @entrosity/ui, this documentation site
Docker + ComposerecentPostgres, MinIO, mailpit, Samba AD (tests)
sqlc1.31 (pinned)Query codegen; make gen runs it with go run (needs a C compiler for cgo)
oapi-codegenv2 (pinned)API codegen; also run by make gen
golangci-lintv2.13+Lint (brew install golangci-lint)
WiX Toolsetv4 (Windows only)MSI builds
A Windows 10/11 VM–Run the agent and connector for real (UTM, Parallels, VMware)

Clone the repositories​

The code lives in separate repositories. Clone the ones you need side by side in one folder; the scripts and Makefiles find each other there:

mkdir entrosity && cd entrosity
for r in infra shared-go ui axis.backend axis.frontend axis-agent axis-connector hub.backend hub.frontend docs; do
gh repo clone "entrosity/entrosity-$r"
done
export GOPRIVATE=github.com/entrosity # private Go modules
gh auth setup-git # Git credentials for go get
echo "//npm.pkg.github.com/:_authToken=<token with read:packages>" >> ~/.npmrc

Every Go repository is a single module: go build ./... and go test ./... work at its root, and make help lists its targets.

First run​

Users sign in on Entrosity Hub, so a development stack runs the Hub next to Axis: four processes, each in its own terminal.

cd entrosity-infra
cp deploy/.env.example deploy/.env # edit secrets if needed
make dev-up # postgres, minio (+ bucket), mailpit
docker compose -f deploy/docker-compose.yml exec postgres createdb -U rmm platform # the Hub's database (once)

cd ../entrosity-hub.backend
make migrate # the Hub's migrations
make bootstrap-admin [email protected] # type the password (12+ chars), Enter
make dev # the Hub's API on :8090 (internal API :8091)

cd ../entrosity-axis.backend
make migrate # Axis: river + app migrations
make dev # Axis's API on :8080 (curl localhost:8080/healthz)

cd ../entrosity-axis.frontend && pnpm install && pnpm dev # Axis's Vite server on :5173 (base /axis/)
cd ../entrosity-hub.frontend && pnpm install && pnpm dev # the Hub's web app on :5175

The backends read ../entrosity-infra/deploy/.env (override with ENV_FILE=…).

note

The dev stack runs PostgreSQL 18. A postgres-data volume left over from the monorepo's PostgreSQL 16 stack will not start: remove it (docker compose -f deploy/docker-compose.yml down -v in entrosity-infra) and migrate again.

Open http://localhost:5175: the Hub's dev server serves one origin like production, with the Hub at /, its API /api/platform (to :8090), Axis at /axis (to the Axis Vite server) and Axis's API at /axis/api (to :8080, prefix stripped like Caddy). Sign in as the admin, create an organization with Entrosity Axis enabled, and open Axis from the product list; Axis picks up the organization within its sync interval.

deploy/.env.example connects the two: RMM_PLATFORM_URL=http://localhost:5175 (the token issuer), RMM_PLATFORM_INTERNAL_URL=http://localhost:8091, RMM_PLATFORM_TOKEN equal to the rmm entry of PLATFORM_PRODUCT_TOKENS, and RMM_PORTAL_URL=http://localhost:5175/axis. E-mails (the Hub's invitations and password resets, Axis's alerts) land in mailpit at http://localhost:8025.

Non-interactive admin creation (in entrosity-hub.backend):

go run ./cmd/server bootstrap-admin --email [email protected] --password-stdin <<<'long passphrase'

Every variable is explained in the Configuration reference.

Row-level security in development​

RLS applies in development too. The pool connects as the owner rmm and switches to rmm_app, and sets the scope from the context before each use of a connection (Multi-tenancy). For ad-hoc SQL as the application: SET ROLE rmm_app; SET app.tenant_id = '<uuid>';.

Packages and object storage​

In dev mode the backend creates the bucket at start. The portal uploads package files straight to MinIO with a presigned PUT, so the MinIO endpoint must be reachable from the browser (the compose MinIO allows any origin). Set RMM_WINGET_SOURCE_URL=off when working offline.

Changing shared code​

  • @entrosity/ui: in entrosity-ui, pnpm build && pnpm pack, then in an app pnpm add ../entrosity-ui/entrosity-ui-<version>.tgz to try it (do not commit that). Release by tagging entrosity-ui; the apps are bumped automatically.
  • entrosity-shared-go: go work init . ../entrosity-shared-go in the consumer (the file is git-ignored). Release by tagging, then go get github.com/entrosity/[email protected] in every consumer.
  • An API contract: change api/openapi.yaml in the backend and run make gen; in the app, OPENAPI_SPEC=../entrosity-axis.backend/api/openapi.yaml pnpm fetch:api && pnpm gen:api (or …hub…). After the backend change reaches main, the app's openapi-bump workflow does the same.

Self-update releases locally​

  1. In entrosity-axis.backend, make release-keygen prints RMM_RELEASE_SIGNING_KEY=… (for the dev .env) and RELEASE_PUBLIC_KEY=… (for builds).
  2. Build with the public key: RELEASE_PUBLIC_KEY=<public> make build in entrosity-axis-agent and entrosity-axis-connector.
  3. Publish in the portal (Admin → Agent releases) or, in entrosity-axis.backend, make publish-release api=http://localhost:8080 file=../entrosity-axis-agent/dist/rmm-agent.msi version=… [product=connector] [channel=beta] [rollout=20] (RMM_RELEASE_TOKEN set in both environments).

Simulated agents accept updates too: they "install" by reconnecting with the new version.

Running the agent against a dev server​

  1. In the portal, create an agent enrollment token.
  2. Make the dev server reachable from the VM: the VM's host-gateway address (http://10.0.2.2:8080 on UTM/QEMU NAT), or ngrok http 8080 / Tailscale. Set RMM_PUBLIC_URL accordingly so download URLs work.
  3. make build in entrosity-axis-agent (or make msi on Windows). For fast iteration run the binary in the console instead of installing the service:
    .\rmm-agent.exe run --server http://10.0.2.2:8080 --token <token>
  4. The device appears under Devices within seconds. Logs: %ProgramData%\RMM\logs\agent.log.

Simulated agents (no Windows needed)​

In entrosity-axis.backend:

make sim token=<enrollment token> count=200
go run ./cmd/simagent --help

Fake agents enroll with unique identities, heartbeat, send canned inventories and execute jobs with fake results after 1–5 s. Flags include --failure-rate, --job-min, --job-max, --heartbeat, --heartbeat-jitter, --prefix, --offset, --ramp and --inventory-size. Enrollment is rate-limited per IP; the tool retries 429s, or raise RMM_ENROLL_RATE_PER_MINUTE.

Running the connector​

The LDAP part runs on macOS and Linux against the Samba AD test domain (in entrosity-axis-connector):

docker compose -f test/samba/docker-compose.yml up -d --wait samba # rmm.test, LDAPS on :10636
docker compose -f test/samba/docker-compose.yml exec -T samba bash /seed.sh # 50 computers in 4 OUs
# portal: Active Directory → Download connector → copy the token
RMM_CONNECTOR_DATA_DIR=/tmp/rmm-connector go run ./cmd/rmm-connector run \
--server http://localhost:8080 --token <connector token>

In the wizard use host 127.0.0.1, port 10636, LDAPS with Skip certificate verification, base DN DC=rmm,DC=test, bind CN=svc-rmm,CN=Users,DC=rmm,DC=test / Svc-Pa55word!.

Pushes need real Windows targets with SMB (ADMIN$) or WinRM enabled and a push account that is a local administrator there. Without object storage, set RMM_AGENT_MSI_URL to a reachable agent MSI.

make simconnector token=… [computers=200] in entrosity-axis.backend runs a simulated connector with a generated directory (no LDAP, no Windows).

Documentation site​

In entrosity-docs:

pnpm install
pnpm start # http://localhost:3000, live reload
pnpm build # static site in build/; fails on broken links

See Writing docs.