← Docs · Reference

Configuration Reference

Complete reference for colony.toml, environment variables, and runtime configuration options.

Colony reads colony.toml to figure out what to run, where to run it, and how to route traffic to it.

colony.toml Structure

A complete colony.toml example:

[colony]
name = "my-app"
template = "web-app"
description = "My awesome application"

[colony.environment]
node_version = "22"
package_manager = "bun"
rust_version = "1.83"

[colony.services.web]
command = "npm run dev"
port = 3000
working_dir = "frontend"
env = { NODE_ENV = "development" }

[colony.services.api]
command = "cargo run --release"
port = 8080
working_dir = "backend"
env = { RUST_LOG = "info" }

[colony.database]
type = "sqlite"
path = "data/app.db"

[colony.dns]
enabled = true

Configuration Sections

[colony]

Basic metadata.

FieldTypeRequiredDefaultDescription
namestringYesColony identifier (alphanumeric + hyphens)
templatestringNo"generic"Template preset (web-app, api, fullstack)
descriptionstringNo""What this colony does

Example:

[colony]
name = "payment-service"
template = "api"
description = "Payment processing microservice"

[colony.environment]

Tell Mycelium which runtimes to provision.

FieldTypeRequiredDefaultDescription
node_versionstringNoLatest LTSNode.js version (e.g., "22", "20.10.0")
package_managerstringNo"npm"Package manager (npm, bun, pnpm, yarn)
rust_versionstringNoLatest stableRust toolchain version
python_versionstringNoSystem defaultPython version
go_versionstringNoLatestGo version
Future Enhancement

Phase 1 does basic environment provisioning. Phase 2+ will integrate Nix for full reproducibility.

Example:

[colony.environment]
node_version = "22"
package_manager = "bun"
rust_version = "1.83"
python_version = "3.12"

[colony.services.*]

Services Colony spawns. Each gets its own process and Caddy route.

FieldTypeRequiredDefaultDescription
commandstringYesShell command to start the service
portintegerYesPort the service listens on
working_dirstringNoRepository rootWorking directory for the command
envtableNo{}Environment variables (key-value pairs)
health_checkstringNo""HTTP endpoint to check health

Example:

[colony.services.web]
command = "npm run dev"
port = 3000
working_dir = "apps/frontend"
env = { NODE_ENV = "development", API_URL = "http://api.colony.local" }
health_check = "/health"

[colony.services.api]
command = "cargo run --release"
port = 8080
working_dir = "apps/backend"
env = { RUST_LOG = "debug", DATABASE_URL = "sqlite://data/app.db" }

Service URLs:

With DNS enabled:

http://{colony-name}-{port}.colony.local

So name = "my-app" and port = 3000 gives you:

http://my-app-3000.colony.local

[colony.database]

Database config. Each colony gets its own isolated instance.

FieldTypeRequiredDefaultDescription
typestringNo"sqlite"Database type (sqlite, postgres, mysql)
pathstringNo"data/colony.db"SQLite file path (relative to workspace)
hoststringNo"localhost"Host for networked databases
portintegerNoVariesPort for networked databases

Example (SQLite):

[colony.database]
type = "sqlite"
path = "data/app.db"

Example (Postgres):

[colony.database]
type = "postgres"
host = "localhost"
port = 5432
database = "my_colony_db"
user = "colony"
password = "secret"
Postgres/MySQL Support

Phase 1 focuses on SQLite. Postgres/MySQL require Soil (shared infrastructure) which is planned for Phase 2.

[colony.dns]

DNS resolution configuration for *.colony.local domains.

FieldTypeRequiredDefaultDescription
enabledbooleanNotrueEnable DNS resolution via dnsmasq

Example:

[colony.dns]
enabled = true

Environment Variables

Colony reads environment variables for global configuration:

VariableDefaultDescription
COLONY_HOME~/.colonyBase directory for workspaces and data
COLONY_LOG_LEVELinfoLog level (debug, info, warn, error)
MYCELIUM_PORT8000HTTP API port for Mycelium
CADDY_ADMIN_PORT2019Caddy JSON API port for route registration

Set these before starting Mycelium:

export COLONY_LOG_LEVEL=debug
export MYCELIUM_PORT=9000
gleam run

Caddy Configuration

Colony uses Caddy’s JSON API for dynamic routes. No config files. No reloads. Routes added/removed at runtime.

Dynamic Route Registration

When a colony spawns:

  1. Mycelium reads colony.toml services
  2. For each service, POSTs a route to http://localhost:2019/config/apps/http/servers/colony/routes

Route pattern:

{
  "match": [
    {
      "host": ["{colony-name}-{port}.colony.local"]
    }
  ],
  "handle": [
    {
      "handler": "reverse_proxy",
      "upstreams": [
        {
          "dial": "localhost:{port}"
        }
      ]
    }
  ]
}

Manual Caddy Inspection

To view current Caddy configuration:

curl http://localhost:2019/config/ | jq

This shows all registered routes. Useful for debugging DNS/routing issues.

Port Allocation Strategy

Ports are explicit. You declare them in colony.toml.

  1. Services declare their ports
  2. Mycelium checks for conflicts
  3. Caddy routes by hostname (not port)

Why explicit ports?

  • Predictableweb = 3000 always means port 3000
  • Debuggable — No guessing which port
  • Safe — Mycelium rejects colonies with overlapping ports
Port Ranges

Use high ports (3000-9999) to avoid system reserved ports (0-1023) and common services (e.g., Postgres on 5432).

DNS Setup (dnsmasq)

Run scripts/setup-dns.sh to configure dnsmasq for *.colony.local.

What it does:

  1. Installs dnsmasq (if needed)
  2. Listens on 127.0.0.1:5354
  3. Adds wildcard rule: address=/colony.local/127.0.0.1
  4. On macOS, creates /etc/resolver/local to route .local queries to dnsmasq

Verify:

dig @127.0.0.1 -p 5354 test.colony.local
# Should return 127.0.0.1

Why not /etc/hosts?

/etc/hosts needs one entry per hostname. With dynamic colonies, that’s unmanageable. dnsmasq wildcards fix this.

Configuration Validation

Mycelium validates colony.toml on spawn. Common errors:

ErrorCauseFix
name must be alphanumericInvalid characters in nameUse only a-z, 0-9, -
port conflictAnother colony uses this portChange port in colony.toml
service command emptyMissing command fieldAdd required command field
unknown templateInvalid template valueUse valid template or omit

Template Presets

Templates give you sensible defaults for common stacks:

TemplateDefault EnvironmentExample Services
web-appNode.js 22, Bunweb on port 3000
apiRust 1.83api on port 8080
fullstackNode.js + Rustweb (3000), api (8080)
genericNoneUser-defined

Override anything:

[colony]
template = "web-app"  # Sets node_version=22

[colony.environment]
node_version = "20"  # Override to Node 20

Next Steps