6.7 KiB
6.7 KiB
AGENTS.md
Repository guidelines for AI coding agents.
Issue Tracking (Beads)
Session start: Run bd ready to see available work.
Commands:
bd ready- Issues with no blockersbd show <id>- Issue detailsbd update <id> --status=in_progress- Claim workbd close <id>- Complete workbd create --title="..." --type=task|bug|feature- New issuebd dep add <issue> <depends-on>- Add dependency
Session end: git status, git add, git commit. Ephemeral branch - merge to main locally.
Overview
NixOS-based Matrix homeserver (conduwuit) with mautrix-slack bridge for Slack ↔ Matrix messaging.
Technologies: Nix 2.x, NixOS 24.05+, conduwuit, mautrix-slack, PostgreSQL 15, sops-nix
Project Structure
.
├── hosts/ # NixOS host configurations
│ └── ops-jrz1.nix # VPS configuration
├── modules/ # NixOS modules
│ ├── dev-services.nix # PostgreSQL, Forgejo, bridge coordination
│ ├── mautrix-slack.nix # Slack bridge module
│ └── matrix-continuwuity.nix # Matrix homeserver
├── secrets/ # sops-encrypted secrets
│ └── secrets.yaml # Encrypted credentials (age)
├── specs/ # Feature specifications
│ ├── 001-extract-matrix-platform/
│ └── 002-slack-bridge-integration/
├── docs/ # Documentation
│ ├── platform-vision.md # North star document
│ └── worklogs/ # Deployment logs
└── scripts/ # Utility scripts (packaged via writeShellApplication)
├── killswitch # Emergency user termination
├── cpu-watchdog # CPU abuse detection
├── egress-watchdog # Egress rate limit abuse detection
├── dev-add.sh # Add dev user account
└── dev-remove.sh # Remove dev user account
Commands
Deployment
# Deploy to VPS
nixos-rebuild switch --flake .#ops-jrz1 --target-host root@ops-jrz1 --build-host localhost
# Validate before deploy
nix flake check
nix build .#nixosConfigurations.ops-jrz1
Bridge Management
# Check bridge status
ssh root@ops-jrz1 'systemctl status mautrix-slack'
# View bridge logs
ssh root@ops-jrz1 'journalctl -u mautrix-slack -f'
# Check for errors
ssh root@ops-jrz1 'journalctl -u mautrix-slack --since "1 hour ago" | grep -E "ERR|WRN|FTL"'
Secrets Management
# Edit encrypted secrets
sops secrets/secrets.yaml
# View decrypted (never commit output)
sops -d secrets/secrets.yaml
SSH Tunnels
# Maubot web UI
ssh -L 29316:localhost:29316 root@ops-jrz1
# Access: http://localhost:29316
# Matrix homeserver (debugging)
ssh -L 8008:localhost:8008 root@ops-jrz1
Forgejo Administration
# Find the correct gitea binary (Forgejo uses gitea internally)
# Use the version matching your deployed Forgejo - check with: systemctl status forgejo
GITEA_BIN=$(find /nix/store -name "gitea" -path "*forgejo-7*" -type f -executable | head -1)
# Generate a scoped API token (runs as forgejo user)
ssh root@ops-jrz1 "sudo -u forgejo $GITEA_BIN admin user generate-access-token \\
--username dan \\
--token-name 'temp-task-name' \\
--scopes 'write:repository,read:repository' \\
--config /var/lib/forgejo/custom/conf/app.ini"
# Common scopes:
# write:admin,read:admin,write:user - User provisioning (dev-add.sh)
# write:repository,read:repository - Repo settings (default branch, etc.)
# Update repo settings (e.g., default branch)
ssh root@ops-jrz1 'curl -s -X PATCH "http://localhost:3000/api/v1/repos/OWNER/REPO" \
-H "Authorization: token YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d "{\"default_branch\": \"main\"}"'
# After using temp token, delete via: https://git.clarun.xyz/user/settings/applications
Gotchas:
- Token at
/run/secrets/forgejo-api-tokenhas admin scope only (for dev-add.sh) - Binary version must match DB schema - newer binaries fail with column errors
- Forgejo API docs: https://git.clarun.xyz/api/swagger
Coding Conventions
- Two-space indentation in Nix files
- Use
lowerCamelCasefor options, kebab-case for filenames - Format with
nix fmtbefore committing - NixOS modules: Use nixpkgs pattern (options, config, mkIf)
- Never hardcode secrets, use sops-nix
Git Workflow
Trunk-Based Development:
main: Single long-lived branch, always deployable- Feature branches: Short-lived, naming
###-feature-name - Tag releases after merging:
v0.MINOR.PATCH
Commits:
- Clear, concise messages (~70 chars)
- No emojis or marketing language
- Reference specs/worklogs in body
Development Patterns
Slack Bridge
- Authentication: Interactive login via Matrix chat (
login appcommand) - Socket Mode: WebSocket connection, no public endpoint needed
- Portal Creation: Automatic based on activity
- Tokens: Bot token (xoxb-) + app-level token (xapp-)
Secrets Flow
- Encryption: Age via SSH host key
- Storage: secrets/secrets.yaml (encrypted, safe to commit)
- Runtime: Decrypted to /run/secrets/ (tmpfs)
Deployment Workflow
- Make configuration changes locally
- Run
nix flake checkto validate - Commit to git
- Deploy via nixos-rebuild (scripts deploy automatically)
- Verify service status and logs
- Document in worklogs/
Architecture
┌─────────────────────────────────────────────────────┐
│ clarun.xyz VPS │
│ │
│ nginx :443 (HTTPS) │
│ ├─→ conduwuit :8008 (Matrix homeserver) │
│ └─→ Forgejo :3000 │
│ │
│ mautrix-slack :29319 │
│ └─→ PostgreSQL (unix socket) │
│ │
└─────────────────────────────────────────────────────┘
│
└─→ Slack API (Socket Mode WebSocket)
Critical: All internal services use IPv4 (127.0.0.1), NOT "localhost" (which resolves to IPv6).
Known Issues
- olm-3.2.16 marked insecure (permitted via nixpkgs.config)
- Fresh database required after conduwuit version upgrades
Testing
nix flake check- minimum gate- Add VM tests in
hosts/ops-jrz1-vm.nixfor new services - Capture verification steps in
docs/worklogs/ - Test message latency: should be <5 seconds