
chatmail-sync
Synchronize NixOS chatmail modules with upstream relay project. Use when user wants to update module
Chatmail Sync
Synchronize NixOS modules with the upstream relay project.
When to use
- User asks to sync/update modules from relay
- User asks to check for new features in relay
- User asks to update configurations from upstream
- User mentions "source of truth" or "relay upstream"
Arguments
This skill accepts optional directory arguments:
| Argument | Description | Default |
|---|---|---|
--relay PATH | Path to relay repository | ../forks/relay (relative to project) |
--nixpkgs PATH | Path to nixpkgs repository | ../forks/nixpkgs (relative to project) |
Example usage:
/chatmail-sync
/chatmail-sync --relay ~/projects/relay --nixpkgs ~/nixpkgs
Source paths
| Variable | Default | Description |
|---|---|---|
$RELAY_PATH | ../forks/relay relative to project | Upstream relay repository |
$PROJECT_PATH | Current working directory | This project root |
$NIXPKGS_PATH | ../forks/nixpkgs or system nixpkgs | nixpkgs for API reference |
CRITICAL: Update sources first
ALWAYS pull latest changes before any sync work.
Step 0: Update relay repository
cd "$RELAY_PATH" && git pull origin main
cd "$PROJECT_PATH"
CRITICAL: Exploration first
NEVER assume you know the relay structure. ALWAYS explore thoroughly first.
Step 1: Discover relay structure
tree -a "$RELAY_PATH" -I '.git|__pycache__|*.pyc|.mypy_cache'
find "$RELAY_PATH" -type f \( -name "*.conf*" -o -name "*.ini*" -o -name "*.j2" -o -name "*.toml" -o -name "*.yaml" -o -name "*.yml" -o -name "*.lua" \)
find "$RELAY_PATH" -type f -name "*.service*" -o -name "*.timer*"
find "$RELAY_PATH" -type f -name "*.py" | head -50
Step 2: Check recent changes
cd "$RELAY_PATH"
git log --oneline -30
git diff HEAD~20 --name-only
git log --oneline -10 -- chatmaild/
git log --oneline -10 -- cmdeploy/
Step 3: Deep dive into components
For EACH component you need to sync:
-
Search for ALL related files in relay:
grep -r "component_name" "$RELAY_PATH" --include="*.py" --include="*.j2" --include="*.conf*" -
Read the actual implementation - don't guess
-
Check for dependencies between components
Step 4: Compare with NixOS implementation
ls -la "$PROJECT_PATH/modules/"
ls -la "$PROJECT_PATH/pkgs/"
diff <(grep -h "key_setting" "$RELAY_PATH"/**/*.j2 2>/dev/null) \
<(grep -h "key_setting" "$PROJECT_PATH/modules/"*.nix 2>/dev/null)
Step 4.5: Sync packages
grep -E "rev|hash" "$PROJECT_PATH/pkgs/chatmail-www/default.nix"
cd "$RELAY_PATH" && git log --oneline -1
grep -E "version|rev|hash" "$PROJECT_PATH/pkgs/chatmaild/default.nix"
Step 5: Check nixpkgs for native support
Before implementing anything custom, check if nixpkgs has it:
find "$NIXPKGS_PATH/nixos/modules/services/" -name "*.nix" | xargs grep -l "feature_name"
grep -A 20 "options\." "$NIXPKGS_PATH/nixos/modules/services/mail/dovecot.nix"
Sync checklist
Discovery phase (REQUIRED)
- Ran
treeon relay project - Found ALL config files (not just expected ones)
- Found ALL systemd units
- Checked git history for recent changes
- Identified ALL Python modules in chatmaild
Comparison phase
- Compared each relay component with NixOS module
- Checked INI template vs INI generation
- Compared systemd services
- Compared config file contents
- Compared package versions with relay
Extra additions phase (NixOS → relay)
- Checked for nginx locations not in relay
- Checked for deprecated components (
present=Falsein deployers.py) - Searched relay for each NixOS feature to confirm it exists
- Removed features that don't exist in relay
Implementation phase
- Checked nixpkgs for native support first
- Updated NixOS modules to match relay
- Added missing options
- Removed extra additions not in relay
- Updated INI generation if needed
- Updated package revisions if needed
Verification phase
- Nix syntax is valid
- All relay features are implemented
- No extra features added (strict relay compatibility)
Common patterns
Finding what chatmaild reads from INI
grep -E "params\[|params\.get|self\." "$RELAY_PATH/chatmaild/src/chatmaild/config.py"
Finding how relay configures a service
grep -r "dovecot" "$RELAY_PATH" --include="*.py" --include="*.j2" --include="*.conf*" -l
Checking what ports relay uses
grep -rE "port|PORT|:([0-9]{2,5})" "$RELAY_PATH" --include="*.py" --include="*.j2" --include="*.conf*"
Finding extra additions in NixOS
grep -E "location\s+/" "$RELAY_PATH/cmdeploy/src/cmdeploy/nginx/nginx.conf.j2"
grep -E '"/[^"]*"\s*=' "$PROJECT_PATH/modules/nginx.nix"
grep -r "feature_name" "$RELAY_PATH" --include="*.j2" --include="*.conf*" --include="*.py"
Finding deprecated components
grep -B2 -A2 "present=False" "$RELAY_PATH/cmdeploy/src/cmdeploy/deployers.py"
grep -B2 -A2 "running=False\|enabled=False" "$RELAY_PATH/cmdeploy/src/cmdeploy/deployers.py"
Known deprecated components (NOT to be implemented):
mta-sts-daemon- removed from relay (present=False)echobot.service- disabled in relay (running=False, enabled=False)rspamd- removed from relay (present=False)doveauth-dictproxy.service- legacy, replaced by doveauth.service
Checking INI options with relay defaults
Before removing or modifying any INI option, check if relay has a default:
grep -E "params\.get\(\"OPTION\"" "$RELAY_PATH/chatmaild/src/chatmaild/config.py"
grep -r "config\.OPTION\|self\.OPTION" "$RELAY_PATH/chatmaild/src/chatmaild/"*.py
grep -r "OPTION" "$PROJECT_PATH/modules/"*.nix
Rule:
If relay has: params.get("option", default)
And NixOS uses: different_value
Then: MUST set in INI (cannot rely on relay default)
Before removing any INI option:
- Check if relay has
params.get()default - Compare relay default with NixOS value
- Check if option is used by multiple services
- If values differ → keep in INI
Verifying each NixOS feature exists in relay
For EACH feature in NixOS modules:
- Search for it in relay:
grep -r "feature" "$RELAY_PATH" - If not found → it's our addition → remove it
- If found with
present=False→ deprecated → remove it
NixOS-native vs Debian workarounds
Relay is designed for Debian/pyinfra deployment. NixOS has native declarative solutions for many things that Debian requires workarounds for.
Principle
Don't copy Debian-specific patterns. Find the NixOS-native way.
How to identify Debian workarounds in relay
grep -E "Environment=" "$RELAY_PATH/cmdeploy/src/cmdeploy/service/"*.service*
grep -E "server\.shell|run_shell" "$RELAY_PATH/cmdeploy/src/cmdeploy/deployers.py"
grep -E "apt\.|packages\." "$RELAY_PATH/cmdeploy/src/cmdeploy/deployers.py"
find "$RELAY_PATH" -name "*.cron*" -o -name "*cron*.j2"
grep -E "files\.put|files\.template" "$RELAY_PATH/cmdeploy/src/cmdeploy/deployers.py"
Decision process
For each Debian pattern found:
- Identify the intent - what is relay trying to achieve?
- Search nixpkgs for native support:
find "$NIXPKGS_PATH/nixos/modules/" -name "*.nix" | xargs grep -l "feature" - If NixOS has native option → use it instead of copying Debian approach
- If no native option → implement following relay's approach
Common patterns
| Relay Pattern | Check NixOS For |
|---|---|
Environment=VAR=... in systemd | Global NixOS option that sets this |
/etc/cron.d/* files | systemd.timers |
acmetool / certbot scripts | security.acme module |
apt install package | Service module dependencies |
useradd/groupadd | users.users/users.groups |
iptables commands | networking.firewall |
Template to /etc/file | Service's configFile or extraConfig |
Verification
Before adding any relay systemd setting to NixOS:
grep -r "SETTING_NAME" "$NIXPKGS_PATH/nixos/modules/"
grep -A5 "mkOption" "$NIXPKGS_PATH/nixos/modules/services/mail/SERVICE.nix"
Output
After sync, report:
- Files examined in relay
- Changes made to NixOS modules
- Package updates (rev/hash changes)
- Features added from relay (if any)
- Extra additions removed (features that were in NixOS but not in relay)
- Deprecated components removed (relay has
present=False) - Discrepancies found and resolved