-
Notifications
You must be signed in to change notification settings - Fork 1
Deployment
Build and run the core Nebulus Atom agent:
# Build the image
docker build -t nebulus-atom:latest .
# Run with Docker Compose
docker compose up -d agent
# View logs
docker compose logs -f agentdocker compose up -d dashboardAccess at http://localhost:8501.
docker compose up -dStarts both the agent and dashboard services.
# Overlord image
docker build -t nebulus-overlord:latest -f nebulus_swarm/overlord/Dockerfile .
# Minion image
docker build -t nebulus-minion:latest -f nebulus_swarm/minion/Dockerfile .# Using Docker Compose
docker compose -f docker-compose.swarm.yml up -d overlord
# Or directly
docker run -d \
--name overlord \
-p 8080:8080 \
-v overlord-state:/var/lib/overlord \
-v /var/run/docker.sock:/var/run/docker.sock \
--env-file .env.swarm \
nebulus-overlord:latestThe Overlord needs access to the Docker socket to spawn minion containers.
curl http://localhost:8080/health
# {"status": "ok"}
curl http://localhost:8080/status
# {"paused": false, "active_minions": [], ...}OVERLORD_URL=http://localhost:8080 \
STATE_DB_PATH=/path/to/state.db \
streamlit run nebulus_swarm/dashboard/app.py┌─────────────────────────────────────────┐
│ nebulus-swarm network │
│ │
│ ┌───────────┐ ┌──────────────────┐ │
│ │ Overlord │ │ Minion(s) │ │
│ │ :8080 │◄──►│ (ephemeral) │ │
│ └─────┬─────┘ └────────┬─────────┘ │
│ │ │ │
└────────┼────────────────────┼────────────┘
│ │
▼ ▼
Docker Socket LLM Server
(host mounted) (external network)
The Overlord and Minions communicate over the nebulus-swarm Docker bridge network. The Overlord exposes port 8080 for external access (health checks, dashboard).
Mount the state database to a persistent volume:
volumes:
overlord-state:
driver: localMinion containers are created with:
- 2 GB memory limit
- 1 CPU core
- Auto-cleanup after exit
-
Health endpoint:
GET /healthreturns 200 when Overlord is running -
Status endpoint:
GET /statusreturns active minions, config, pending questions - Docker health check: Configured in docker-compose with 30s intervals
Back up the SQLite state database regularly:
# Copy from Docker volume
docker cp overlord:/var/lib/overlord/state.db ./backup/state.db
# Or if using a mounted volume
cp /path/to/state.db ./backup/state.dbConfigure structured logging for production:
LOG_LEVEL=INFO
LOG_FORMAT=json
LOG_FILE=/var/log/overlord/overlord.logThe Overlord handles SIGTERM gracefully:
- Stops accepting new work
- Waits for active minions to finish (or timeout)
- Saves state to SQLite
- Exits cleanly
docker compose -f docker-compose.swarm.yml downThe Overlord daemon runs as a persistent background process with scheduled sweeps, Slack command routing, and proactive detection. It runs natively (not in Docker) and manages the cross-project ecosystem.
-
overlord.yml configured at
~/.atom/overlord.yml(see Configuration) - Slack tokens set in environment (optional — daemon runs headless without them)
-
croniter installed (
pip install croniter)
The daemon now auto-loads .env from the current working directory on startup. You no longer need to source .env manually.
# Via CLI (auto-loads .env from cwd)
cd /path/to/nebulus-atom
nebulus-atom overlord daemon start
# Output shows:
# Loaded .env from /path/to/nebulus-atom/.env
# SLACK_BOT_TOKEN: yes | SLACK_APP_TOKEN: yes | SLACK_CHANNEL_ID: yes
# Logging to ~/.atom/overlord/daemon.log (level=INFO)
# Starting Overlord daemon...
# Headless mode (scheduler only, no Slack — just don't set Slack vars)
nebulus-atom overlord daemon startLogs are written to ~/.atom/overlord/daemon.log in structured JSON format. The log level defaults to INFO and can be overridden via the LOG_LEVEL environment variable.
# /etc/systemd/system/overlord-daemon.service
[Unit]
Description=Nebulus Overlord Daemon
After=network.target
[Service]
Type=simple
User=jlwestsr
WorkingDirectory=/home/jlwestsr/projects/west_ai_labs/nebulus-atom
EnvironmentFile=/home/jlwestsr/.atom/overlord.env
ExecStart=/home/jlwestsr/projects/west_ai_labs/nebulus-atom/venv/bin/python -m nebulus_atom.main overlord daemon start
Restart=on-failure
RestartSec=10
[Install]
WantedBy=multi-user.targetsudo systemctl daemon-reload
sudo systemctl enable overlord-daemon
sudo systemctl start overlord-daemon
sudo journalctl -u overlord-daemon -fpm2 start "nebulus-atom overlord daemon start" --name overlord-daemon
pm2 save
pm2 startupOverlordDaemon
├── SlackBot (Socket Mode) # Listens for @atom mentions
│ ├── SlackCommandRouter # Routes to Phase 2 modules
│ └── ProposalManager # Thread-based approval workflow
├── Startup Reconciliation # Catches missed approve/deny replies
├── Scheduler Loop (croniter) # Fires tasks on cron schedule
│ ├── scan (hourly) # Health check + detection
│ ├── test-all (nightly) # Test sweep
│ └── clean-stale-branches # Weekly branch cleanup
├── Cleanup Loop (5 min) # Expires stale proposals
├── DetectionEngine # Stale, ahead-of-main, failing
├── NotificationManager # Urgent + buffered digest
└── Signal Handler # SIGINT/SIGTERM → graceful stop
When the daemon starts with Slack integration, it performs a reconciliation sweep before entering the main loop. This catches approve/deny replies that were posted while the daemon was offline (Socket Mode does not buffer historical events).
How it works:
- After Socket Mode connects, the daemon queries all pending proposals with Slack threads
- For each proposal, it reads the thread history via the Slack API
- It scans replies (latest first) for approval keywords (
approve,approved,yes,lgtm) or denial keywords (deny,denied,no,reject) - Matching proposals are transitioned to APPROVED or DENIED
- A notification is posted in the thread explaining the reconciliation
Important limitation: DispatchPlans are cached in-memory and lost on restart. Reconciled approvals cannot auto-execute — the user is prompted to re-dispatch if the plan is still needed. Full plan persistence is a future enhancement.
Rate limiting: Proposals are processed in batches of 5 with a 1-second backoff between batches to avoid Slack API rate limits.
The daemon supports proper lifecycle management via the CLI:
# Check status
nebulus-atom overlord daemon status
# Stop gracefully (sends SIGTERM, waits up to 5s)
nebulus-atom overlord daemon stop
# Restart (stop + start)
nebulus-atom overlord daemon restart
# If running in foreground
Ctrl+C
# If running as a service
sudo systemctl stop overlord-daemon
# or
pm2 stop overlord-daemonThe daemon handles SIGINT and SIGTERM for clean shutdown:
- Sets the shutdown event
- Cancels scheduler, Slack bot, and cleanup tasks
- Waits for in-progress tasks to complete
- Stops the Slack bot connection
- Removes the PID file
- Logs shutdown complete
| Data | Location | Description |
|---|---|---|
| PID file | ~/.atom/overlord/daemon.pid |
Running daemon process ID |
| Daemon log | ~/.atom/overlord/daemon.log |
Structured JSON daemon logs |
| Proposals DB | ~/.atom/overlord/proposals.db |
Pending/completed proposals |
| Memory DB | ~/.atom/overlord/memory.db |
Cross-project observations |
| State DB | /var/lib/overlord/state.db |
Minion state (Phase 0) |
Back up proposal and memory databases regularly:
cp ~/.atom/overlord/proposals.db ~/backup/
cp ~/.atom/overlord/memory.db ~/backup/# Check logs (systemd)
sudo journalctl -u overlord-daemon -f
# Check logs (PM2)
pm2 logs overlord-daemon
# Slack: ask the daemon directly
@atom statusThe daemon logs all scheduled task executions, detection results, proposal state changes, and notification sends at INFO level.
| Feature | Headless | With Slack |
|---|---|---|
| Scheduled scans | Yes | Yes |
| Proactive detection | Yes (logged) | Yes (posted to Slack) |
| Slack commands | No | Yes |
| Proposal workflow | No | Yes (thread-based) |
| Urgent notifications | No | Yes |
| Daily digest | No | Yes |
| Proposal cleanup | Yes | Yes |
For development without Docker:
# Core agent
source .venv/bin/activate
python3 -m nebulus_atom.main start
# Swarm dashboard
streamlit run nebulus_swarm/dashboard/app.py
# Run tests
python3 -m pytest tests/ -v- Installation - First-time setup
- Configuration - Environment variables
- Nebulus Swarm - Swarm architecture
- Troubleshooting - Common deployment issues