"Our struggle is not against flesh and blood, but against the rulers, against the authorities, against the powers of this dark world." — Ephesians 6:12
Codex Astartes is a personal, always-on defensive security system for macOS — built as a multi-agent Python framework, voiced by ElevenLabs TTS, and themed around the Warhammer 40,000 Ultramarines Chapter.
Every agent runs as a daemon thread, patrols a specific threat surface, and reports through a central orchestrator. When a threat is detected, the system speaks it aloud and writes it to a persistent log.
| Agent | Lore Role | Security Function |
|---|---|---|
| Calgar | Chapter Master | Orchestrator — receives all threats and commands response |
| Torias | Scout Sergeant | Network watcher — monitors suspicious connections and ports |
| Cassius | Chaplain | Process/malware hunter — hunts rogue and suspicious processes |
| Pythol | Apothecary | System health monitor — CPU, RAM, and Disk thresholds |
| Tigurius | Chief Librarian | File sentinel — watches sacred paths for unauthorized changes |
| Servitor | Chapter Servitor | Downloads folder guardian — detects clutter, sorts files at EOD |
| Sicarius | Captain 2nd Company | LaunchAgent warden — detects new persistence entries in launchd |
| Ventris | Captain 4th Company | USB sentinel — alerts when external drives are mounted |
main.py
│
├── core/
│ ├── calgar.py ← Orchestrator: enlists agents, deploys threads, routes threats
│ ├── threat.py ← Threat dataclass: agent, description, severity, timestamp, metadata
│ ├── voice.py ← ElevenLabs TTS engine: speaks every threat aloud
│ └── logger.py ← File logger: writes all threats to logs/chapter.log
│
├── agents/
│ ├── torias.py ← Network connections monitor (psutil)
│ ├── cassius.py ← Process scanner (psutil)
│ ├── pythol.py ← CPU / RAM / Disk health (psutil)
│ ├── tigurius.py ← File system watcher (watchdog)
│ ├── servitor.py ← Downloads folder guardian (os + shutil)
│ ├── sicarius.py ← LaunchAgent watcher (watchdog + plistlib)
│ └── ventris.py ← USB / external volume monitor (psutil)
│
├── worlds/
│ ├── NEW_WORLD_TEMPLATE.env ← Template for new machines
│ └── com.codex.astartes.plist ← launchd auto-start agent (macOS)
│
├── logs/
│ └── chapter.log ← Local threat log (gitignored)
│
├── .env ← Machine secrets (gitignored — never committed)
└── requirements.txt
Agent detects event
↓
calgar.report(Threat)
↓
┌───┴────────────────┐
│ print to terminal │
│ log to chapter.log │
│ speak via TTS │
└────────────────────┘
- macOS (tested on MacBook Pro M3, macOS Sequoia)
- Python 3.9+
- Homebrew
ffmpeg(for audio playback)- An ElevenLabs account (free tier works)
brew install ffmpeggit clone https://github.com/diegogallegof/codex-astartes.git
cd codex-astartesEach machine gets its own branch. This keeps machine-specific config out of main.
git checkout -b world/<your-machine-name>
# Example: git checkout -b world/macraggepython3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txtcp worlds/NEW_WORLD_TEMPLATE.env .envEdit .env with your values (see Configuration section below). This file is gitignored — it will never be committed.
python main.pyOr to run detached from the terminal (survives terminal close):
python main.py > /tmp/codex-astartes.log 2>&1 &
disownInstall the provided launchd plist so the Chapter deploys automatically every time the machine starts:
cp worlds/com.codex.astartes.plist ~/Library/LaunchAgents/
launchctl load ~/Library/LaunchAgents/com.codex.astartes.plistImportant: After installing the plist, grant Full Disk Access to the Python binary so agents like Servitor can access protected directories (Downloads, Documents, etc.):
- Open
System Settings → Privacy & Security → Full Disk Access - Click
+ - Press
⌘ ⇧ Gand paste:/path/to/your/codex-astartes/.venv/bin/python - Toggle it ON
Chapter output (when running via launchd) is written to /tmp/codex-astartes.log.
| Variable | Default | Description |
|---|---|---|
ELEVENLABS_API_KEY |
— | Your ElevenLabs API key |
ELEVENLABS_VOICE_ID |
— | Voice ID from your ElevenLabs account |
CPU_ALERT_PERCENT |
85 |
CPU usage % that triggers a Pythol alert |
RAM_ALERT_PERCENT |
90 |
RAM usage % that triggers a Pythol alert |
DISK_ALERT_PERCENT |
95 |
Disk usage % that triggers a Pythol alert |
PROCESS_POLL_INTERVAL |
15 |
Cassius scan interval (seconds) |
NETWORK_POLL_INTERVAL |
10 |
Torias scan interval (seconds) |
HEALTH_POLL_INTERVAL |
20 |
Pythol scan interval (seconds) |
DOWNLOADS_SCAN_INTERVAL_MINUTES |
30 |
Servitor patrol interval (minutes) |
DOWNLOADS_MAX_AGE_DAYS |
30 |
Age in days before a file is flagged as old |
DOWNLOADS_MAX_FILES |
100 |
Max items in Downloads before alert |
EOD_SORT_HOUR |
20 |
Hour (24h) when Servitor auto-sorts Downloads |
WATCHED_PATHS |
~/.ssh,~/.zshrc,... |
Comma-separated paths for Tigurius to watch |
SUSPICIOUS_PORTS |
4444,6666,31337,... |
Ports that trigger a Torias HIGH alert |
TRUSTED_IPS |
127.0.0.1,... |
IPs excluded from Torias network alerts |
The Chapter Master. All agents report to Calgar via calgar.report(Threat). On every report, Calgar:
- Prints the threat to the terminal
- Writes it to
logs/chapter.logvia the logger - Speaks it aloud via ElevenLabs TTS
Calgar runs each agent's patrol() method in a dedicated daemon thread.
Monitors all active network connections using psutil.net_connections(). Flags any outbound connection to a port in SUSPICIOUS_PORTS that is not coming from a trusted IP or a trusted process.
Trusted processes: symptomsd (Apple diagnostics) — whitelisted to prevent false positives.
Known fix: On macOS, psutil.net_connections() raises AccessDenied for system-owned connections. Torias catches this silently at both the scan and per-connection level.
Scans all running processes every PROCESS_POLL_INTERVAL seconds. Flags any process whose name matches known malware keywords:
xmrig, minerd, cryptominer, netcat, ncat, socat,
msfconsole, meterpreter, metasploit, backdoor, rootkit,
keylogger, mimikatz, cobalt strike
Maintains a MACOS_ALLOWLIST of legitimate macOS system processes to prevent false positives (e.g. launchd, NotificationCenter, SiriNCService).
Polls CPU, RAM, and Disk usage every HEALTH_POLL_INTERVAL seconds. Reports:
HIGHwhen CPU exceedsCPU_ALERT_PERCENTHIGHwhen RAM exceedsRAM_ALERT_PERCENTHIGHwhen Disk exceedsDISK_ALERT_PERCENT
Uses the watchdog library to monitor WATCHED_PATHS for file system events (create, modify, delete). Events are batched into a 5-second window to prevent spam when many files change at once (e.g. bulk deletions).
- Single file event → names the specific file
- Multiple files in the window → reports count (e.g. "12 files deleted")
Severities: MEDIUM for deletions/modifications, LOW for creations.
Patrols ~/Downloads every DOWNLOADS_SCAN_INTERVAL_MINUTES. Performs three checks each cycle:
- Loose file detection — flags any file sitting directly in the Downloads root (not inside a category folder)
- Age check — flags files not modified in the last
DOWNLOADS_MAX_AGE_DAYSdays - Count check — alerts if total items exceed
DOWNLOADS_MAX_FILES
End-of-day auto-sort: At EOD_SORT_HOUR (default 20:00), Servitor automatically moves all loose files into category subfolders based on extension:
| Folder | Extensions |
|---|---|
| Images | png, jpg, jpeg, gif, webp, svg |
| Documents | pdf, docx, doc, pptx, ppt, txt |
| Data | csv, xlsx, xls, numbers, gz |
| Archives | zip |
| Videos | mp4, mov |
| Audio | wav, mp3 |
| Installers | dmg, pkg, apk |
| Web | html, htm |
| Dev | sqlite, ics, db, md |
| Misc | everything else |
System files (.DS_Store, .localized, desktop.ini) are permanently ignored.
Permission note: When running via launchd without Full Disk Access, Servitor prints a clear message and skips the patrol cycle rather than crashing.
Watches launchd persistence directories for new .plist files using watchdog:
~/Library/LaunchAgents— user-level auto-start entries/Library/LaunchAgents— system-wide user agents/Library/LaunchDaemons— system-wide daemons (requires root)
When a new .plist appears, Sicarius parses it with plistlib to extract the command it will execute, then reports HIGH severity via Calgar.
This is the #1 persistence vector for macOS malware — any program that wants to survive reboots must register here.
Polls psutil.disk_partitions() every 5 seconds. Any new mount point under /Volumes/ triggers a MEDIUM severity alert with the volume name and mount path. Ejections are logged silently to the terminal.
Powered by ElevenLabs TTS. Every threat passed to calgar.report() is spoken aloud using your configured voice.
- Model:
eleven_turbo_v2_5(compatible with free tier) - Audio playback via
ffplay(part of ffmpeg) - Falls back to
print()if no API key is configured or quota is exceeded
Setup:
- Create an account at elevenlabs.io
- Copy your API key and a Voice ID into
.env
All threats are written to logs/chapter.log in addition to terminal output and voice alerts. The log is gitignored — local only.
Log format:
2026-02-28 20:15:32 | HIGH | [Sicarius] New LaunchAgent registered: 'com.example.plist' — Command: /usr/bin/curl ...
2026-02-28 20:16:01 | MEDIUM | [Tigurius] File deleted: /Users/.../Documents/report.pdf
2026-02-28 20:16:45 | INFO | [Servitor] Old file detected: archive.zip (last modified 2025-09-01)
Severity mapping: LOW → INFO, MEDIUM → WARNING, HIGH → ERROR, CRITICAL → CRITICAL
To monitor in real time:
tail -f logs/chapter.logOr use the shell alias (if configured):
chapter-log| Branch | Purpose |
|---|---|
main |
Sacred core — shared logic, no secrets, no machine-specific config |
world/<name> |
Per-machine branch — .env values, plist paths, local overrides |
All development happens on world/<name>. Changes are merged into main via PR to keep contribution history intact.
Never commit to main directly. Never commit .env files.
Add to your .zshrc:
alias codex="cd ~/Projects/codex-astartes && source .venv/bin/activate"
alias deploy="python main.py > /tmp/codex-astartes.log 2>&1 & disown && echo 'Chapter deployed.'"
alias chapter-log="tail -f ~/Projects/codex-astartes/logs/chapter.log"
alias reload="source ~/.zshrc"- Check ElevenLabs quota — free tier has a monthly character limit
- Confirm
ELEVENLABS_API_KEYandELEVENLABS_VOICE_IDare set in.env - Confirm
ffmpegis installed:which ffplay - Voice alerts have a ~5 second delay when fired through Tigurius (batch window)
- Grant Full Disk Access to the Python binary in
System Settings → Privacy & Security → Full Disk Access
- Fixed in current version —
AccessDeniedfrompsutil.net_connections()is caught silently
- Confirm plist is loaded:
launchctl list | grep astartes - Check output:
cat /tmp/codex-astartes.log - Reload:
launchctl unload ~/Library/LaunchAgents/com.codex.astartes.plist && launchctl load ~/Library/LaunchAgents/com.codex.astartes.plist
pkill -f "main.py"then reload via launchctl
psutil
watchdog
python-dotenv
elevenlabs
Install: pip install -r requirements.txt
For His Word and His Glory. The Chapter stands eternal.