5.4 KiB
Project map: colony
Auto-generated by the explorer subagent. Factual overview — refresh via
explorer, not by hand.
What it does
Self-organizing cluster of nodes on a LAN (README.md). Nodes discover each other (TCP probe on the discovery port over a configured IP range), gossip membership, and bid for "roles" (replicated storage, password vault, web dashboard, chat, ...), so roles keep running as nodes join/leave/die. Each node is one Python process; colonyctl controls the local node.
How it works
main.pyboot order: validate discovery range ->StateManager(data/state.json) ->Network->RoleRegistry(available_roles)->Dispatcher+RoleManager(general + on-demand roles, init) -> TLSListenerbind -> unixControlSocketbind -> threads for ControlSocket, Listener,Discover.listen->Gossip.join_or_bootstrap(); if bootstrapped,Foreman.tick()runs to assign roles ->start_all()->ControlQueue.run_forever()on main thread.- Node-to-node: length-prefixed (4-byte
!I, 16 MiB max) JSON frames over TLS (colony/transport/framing.py,listener.py,whisperer.pyclient). Payload{"command": {role, name, args, kwargs, from}};Dispatcher.dispatchmapsRole.Commandto the role'sCOMMANDSenum and callsexecute_local. - Roles (
colony/core/roles/<name>/role.py) subclassRole(roles/role.py):CONTINUOUS+LOOP_SECONDS_WAITrunloop()in a daemon thread; commands registered viaCommand(callback, with_caller). - Role assignment:
Foremanproposes unclaimed roles to capable nodes;RoleManager(roles/manager.py) +policy.py(configrole_policy) +role_registry.py(priority, hardware preferences,minimal_percentage,on_demand) decide who runs what. Hardware scoring:core/hardware_scores.py,network/hardware.py. - Unreachable nodes:
Gatewayrole relays commands (network/relay.py, buildsGateway.Forward; configgateway.allow_commandswhitelists relayable commands). - Local control:
colonyctl-> unix socketdata/colony.sock(transport/control.py) ->ControlQueue->ControlActions(core/control.py).
Tech stack
Python >=3.14 (.python-version 3.14), uv (uv.lock, package = false). Deps (pyproject.toml): dependency-injector 4.48.3, dynaconf 3.2.12, Flask 3.1.3, GPUtil 1.4.0, psutil 7.2.1, setuptools 80.9.0. Web UI static JS/CSS (no build step). Docker image python:3.14-alpine.
Repositories / modules
Single flat package.
main.pynode entrypoint;colonyctl.py->colony/cli.py(argparse CLI);role_settings.pyrole list;config.jsondefaults.colony/core/—context.py(RoleContext),dispatcher.py,control.py,state_manager.py,logger/,exceptions.py.colony/core/network/—core.py(Network),membership.py,nodes.py,advice.py,hardware.py,relay.py,requests.py.colony/core/roles/— Unit, Gossip, Foreman, Gateway, VaultWarden, Replicator, Explorer, WebView (Flaskapp.py+static/), Chatter;manager.py,policy.py.colony/core/storages/—core.py(Storage base,storages/dir, tar/hash helpers),default.py,replica.py,chat.py.colony/transport/—listener.py,whisperer.py,discover.py,control.py,framing.py.colony/utils/—files.py(atomic_write_json),network.py(hosts_in_range).certs/,data/,storages/,logs/— runtime dirs (git-ignored: certs, data, storages).
Key implementations
- Startup/wiring:
main.py. - Role catalogue and priorities:
role_settings.py(Unit, Gossip, Foreman, Gateway = GENERAL; VaultWarden, Replicator = CRITICAL (Replicatorminimal_percentage=51); Explorer = HIGH; WebView, Chatter = LOW and on-demand). - Role base/lifecycle:
colony/core/roles/role.py,manager.py. - Membership/join:
roles/gossip/role.py,network/membership.py. - Role placement:
roles/foreman/role.py,roles/policy.py. - CLI (
status,role add,webview,chat):colony/cli.py. - Settings:
colony/settings.py(setting("a.b")raises KeyError when missing).
Build, run, test
- Install/run:
uv syncthenuv run python main.py. - CLI:
./colonyctl.py status [--json],role add <Role>,webview,chat <node> [text]. - Docker:
docker build -t colony .;docker compose up -d(host network; volumes /app/data, /app/storages, /app/logs; ports 65334/tcp, 28149/tcp, 8080/tcp). - CI:
.gitea/workflows/docker.ymlbuilds and pushesregistry.ciomek.pl/colony:lateston push to main. - Tests: none in the repo.
External integrations
No third-party services. Peers over TLS (cert/key at certs/server.crt, certs/server.key), TCP discovery on 28149, optional web dashboard on 8080 with basic credentials (web.username/password), private Docker registry in CI.
Conventions & gotchas
- Config:
config.jsonoverridden by envCOLONY_<SECTION>__<KEY>(dynaconf);docker-compose.ymllists keys. - Discovery range defaults to 192.168.65.100-120; node exits if range invalid, listener or control socket cannot bind. Warns if node IP is 127.x.
- Role commands (
COMMANDSenums) are for node-to-node calls; the CLI uses the control socket actions instead. - State persisted atomically in
data/state.json; a corrupt file is copied to.corruptand reset. - Loop exceptions in continuous roles are logged and retried.
- Roles with
on_demand=Trueonly start viaroles.on_demandconfig orcolonyctl role add.