diff --git a/.beads/issues.jsonl b/.beads/issues.jsonl index d4ffbfd..687e349 100644 --- a/.beads/issues.jsonl +++ b/.beads/issues.jsonl @@ -9,7 +9,7 @@ {"id":"ops-jrz1-2bu","title":"Direct Slack bot path for learners","description":"Alternative path: learners write Python bots using slack-bolt, connect directly to Slack via Socket Mode. No Matrix, no bridge.\n\n## Architecture\n```\nlearner code → slack-bolt → Socket Mode WebSocket → Slack API\n```\n\n## Status\n\n**Done:**\n- [x] /etc/slack-learner.env with shared tokens (xoxb-, xapp-)\n- [x] learners group for access control (dantest is member)\n- [x] learner-add.sh adds users to group, sources env in .bashrc\n- [x] Design doc: docs/learner-slack-direct.md\n\n**Not Done:**\n- [ ] Starter template (~/slack-bot-template/)\n- [ ] Process management (systemd user services or supervisor)\n- [ ] #learner-sandbox channel in Slack\n- [ ] End-to-end test with real learner\n\n## Tradeoffs vs Maubot/Matrix (ops-jrz1-2pm)\n- Faster feedback (direct to Slack)\n- Excellent slack-bolt docs\n- But: shared bot identity, manual process management\n\n## Ready to Use NOW\nWorks today with terminal editors (vim/nano):\n```bash\nssh alice@ops-jrz1\npip install slack-bolt\npython bot.py # responds in Slack\n```\n\nVS Code Remote-SSH needs nix-ld deployed first.","status":"open","priority":2,"issue_type":"epic","created_at":"2025-12-29T18:56:10.239324326-05:00","created_by":"dan","updated_at":"2026-01-02T10:04:58.786306917-08:00"} {"id":"ops-jrz1-2pm","title":"Remote dev environment for learners","description":"Set up dev environments for learners to build maubot plugins (Matrix bots that can bridge to Slack).\n\n## Approach\nVS Code Remote-SSH + shared maubot + per-user Unix accounts\n\n## Architecture\n```\nlearner code → maubot → Matrix → mautrix-slack bridge → Slack\n```\n\n## Status\n\n**Done:**\n- [x] learner-add.sh / learner-remove.sh scripts\n- [x] Hello-world plugin template (templates/plugin-skeleton/)\n- [x] Test user `dantest` created with ~/plugins/hello-dantest/\n- [x] Maubot running and healthy\n\n**Not Done:**\n- [ ] nix-ld for VS Code Remote-SSH (config added, not deployed)\n- [ ] Test full VS Code Remote-SSH flow\n- [ ] Test Claude Code extension over Remote-SSH\n- [ ] #learners-sandbox Matrix room\n- [ ] Onboarding doc polish\n\n## Tradeoffs vs Direct Slack (ops-jrz1-2bu)\n- Slower feedback (bridge hop)\n- Sparse maubot docs\n- But: managed process lifecycle, per-bot identity\n\n## Docs\n- docs/learner-onboarding.md\n- docs/learner-admin.md","status":"open","priority":2,"issue_type":"epic","created_at":"2025-12-28T10:13:21.90764918-05:00","created_by":"dan","updated_at":"2026-01-02T10:04:58.472361796-08:00"} {"id":"ops-jrz1-2r9","title":"Remove unused 'config' parameter from configuration.nix","description":"deadnix reports unused lambda pattern 'config' at line 1. Either remove it or prefix with underscore.","status":"closed","priority":4,"issue_type":"task","created_at":"2026-01-03T17:35:57.074498327-08:00","created_by":"dan","updated_at":"2026-01-05T18:40:08.564606182-08:00","closed_at":"2026-01-05T18:40:08.564606182-08:00","close_reason":"Fixed by deadnix cleanup in commit 2dd5684"} -{"id":"ops-jrz1-2y4","title":"Test musiclink deployment end-to-end","description":"Verification steps:\n\n1. systemctl status matterbridge musiclink\n2. journalctl -u matterbridge -u musiclink (check for errors)\n3. Post a Spotify link in configured Slack channel\n4. Verify bot responds with YouTube/Apple/Deezer links\n5. Test reverse direction (YouTube → Spotify)\n\nDocument any issues for future reference.","status":"open","priority":3,"issue_type":"task","created_at":"2026-01-08T12:59:10.160713165-08:00","created_by":"dan","updated_at":"2026-01-08T12:59:10.160713165-08:00"} +{"id":"ops-jrz1-2y4","title":"Test musiclink deployment end-to-end","description":"Verification steps:\n\n1. systemctl status matterbridge musiclink\n2. journalctl -u matterbridge -u musiclink (check for errors)\n3. Post a Spotify link in configured Slack channel\n4. Verify bot responds with YouTube/Apple/Deezer links\n5. Test reverse direction (YouTube → Spotify)\n\nDocument any issues for future reference.","status":"open","priority":3,"issue_type":"task","created_at":"2026-01-08T12:59:10.160713165-08:00","created_by":"dan","updated_at":"2026-01-08T12:59:10.160713165-08:00","dependencies":[{"issue_id":"ops-jrz1-2y4","depends_on_id":"ops-jrz1-hkb","type":"blocks","created_at":"2026-01-08T15:56:08.357534903-08:00","created_by":"dan"},{"issue_id":"ops-jrz1-2y4","depends_on_id":"ops-jrz1-8j9","type":"blocks","created_at":"2026-01-08T15:56:08.404257595-08:00","created_by":"dan"}]} {"id":"ops-jrz1-30e","title":"Add gastown (gt) to system packages via flake input","description":"Add gastown CLI (gt) as a system-wide package.\n\n## What is gastown?\nGastown (gt) is the orchestration layer to beads' memory layer. Together they form a workflow for AI-supervised coding.\n\n## Status\n**BLOCKED**: No releases available yet. Repo uses GoReleaser but no tags/releases published.\n- Requires Go 1.24 to build from source\n- Once releases exist, add like beads: flake input + systemPackages\n\n## Source\ngithub:steveyegge/gastown\n\n## Workaround\nUsers can build locally: `go install github.com/steveyegge/gastown@latest`","status":"closed","priority":2,"issue_type":"task","created_at":"2026-01-02T16:37:47.093900357-08:00","created_by":"dan","updated_at":"2026-01-02T19:08:28.742017652-08:00","closed_at":"2026-01-02T19:08:28.742017652-08:00","close_reason":"Won't fix - not adding gastown to this server"} {"id":"ops-jrz1-396","title":"Add killswitch script","description":"Script to immediately terminate all processes for a user.\n\n## Script: /usr/local/bin/killswitch\n```bash\n#!/usr/bin/env bash\n# Usage: killswitch \u003cusername\u003e [reason]\nset -euo pipefail\nUSER=\"$1\"\nREASON=\"${2:-manual kill}\"\n\nif ! id \"$USER\" \u0026\u003e/dev/null; then\n echo \"User not found: $USER\" \u003e\u00262\n exit 1\nfi\n\nlogger -t killswitch \"Killing all processes for $USER: $REASON\"\npkill -u \"$USER\" || true\nloginctl terminate-user \"$USER\" 2\u003e/dev/null || true\necho \"Killed $USER: $REASON\"\n```\n\n## Usage\n```bash\n# Manual kill\nkillswitch dan \"investigating suspicious activity\"\n\n# From watchdog\nkillswitch dan \"sustained CPU abuse (250%)\"\n```\n\n## Notes\n- Logs to syslog with 'killswitch' tag\n- Terminates user session and all processes\n- Safe to run if user has no processes","status":"closed","priority":2,"issue_type":"task","created_at":"2026-01-02T20:19:35.306146948-08:00","created_by":"dan","updated_at":"2026-01-02T20:25:38.950670564-08:00","closed_at":"2026-01-02T20:25:38.950670564-08:00","close_reason":"Closed"} {"id":"ops-jrz1-3au","title":"Research: Learner deployment pipeline","description":"How does learner code get to \"prod\" (running services)?\n\n## Current context\n- Maubot: Upload .mbp via web UI\n- Slack bots: Manual `python bot.py` or systemd user service\n\n## Questions\n1. Can learners run persistent services? (`systemctl --user`)\n2. Should they have access to maubot admin UI?\n3. Git-based deploy? Push to trigger reload?\n4. Who can restart what?\n\n## Options\n- **Manual only** - Learner runs in foreground/tmux\n- **User systemd** - `systemctl --user enable mybot`\n- **Supervised** - Central supervisor manages learner procs\n- **GitOps** - Push to deploy (complex)\n\n## Security considerations\n- What if learner bot crashes in loop?\n- Resource limits on user services?\n- Can learner affect other learners' services?","status":"open","priority":2,"issue_type":"task","created_at":"2026-01-02T12:27:34.107447487-08:00","created_by":"dan","updated_at":"2026-01-02T12:27:34.107447487-08:00"} @@ -46,7 +46,7 @@ {"id":"ops-jrz1-86g","title":"Add per-user resource limits (not just slice-wide)","description":"Currently user.slice has TasksMax=500, MemoryMax=80%, but individual user-XXXX.slice has infinity. One user can starve others. Add per-user limits via systemd drop-ins or user-XXXX.slice config.","status":"closed","priority":2,"issue_type":"task","created_at":"2026-01-03T08:40:25.937465595-08:00","created_by":"dan","updated_at":"2026-01-03T10:00:36.908904643-08:00","closed_at":"2026-01-03T10:00:36.908904643-08:00","close_reason":"Added per-user limits via activation script drop-in: MemoryMax=50%, TasksMax=200, CPUQuota=200%"} {"id":"ops-jrz1-88o","title":"Implement backup strategy for VPS","description":"No backups configured. Critical data: Matrix DB (622M), PostgreSQL (161M), Forgejo (2.5M), maubot (320K). No recovery path if disk fails. Need automated backups with off-site storage.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-04T22:55:25.546850172-08:00","updated_at":"2025-12-05T00:56:27.720623612-08:00","closed_at":"2025-12-05T00:56:27.720623612-08:00"} {"id":"ops-jrz1-8eb","title":"Obtain Spotify API credentials for musiclink","description":"Get Spotify API credentials:\n\n1. Go to https://developer.spotify.com/dashboard\n2. Create new app or use existing\n3. Get Client ID and Client Secret\n4. Add to sops secrets or musiclink config\n\nNote: Needed for Spotify link detection/conversion","status":"open","priority":2,"issue_type":"task","created_at":"2026-01-08T12:59:08.801148544-08:00","created_by":"dan","updated_at":"2026-01-08T12:59:08.801148544-08:00"} -{"id":"ops-jrz1-8j9","title":"Create musiclink config.toml with API credentials","description":"Create /var/lib/musiclink/config.toml with:\n\n[matterbridge]\n- url = ws://127.0.0.1:4242/api/websocket\n- token = (same as matterbridge API token)\n- gateway = \"main\"\n\n[services]\n- enabled = [\"spotify\", \"youtube\", \"apple\", \"deezer\"]\n\n[services.spotify]\n- client_id, client_secret from Spotify Developer Dashboard\n\n[services.youtube]\n- api_key from Google Cloud Console (optional, can skip initially)\n\nApple Music and Deezer don't need credentials.","status":"open","priority":2,"issue_type":"task","created_at":"2026-01-08T12:59:08.362889466-08:00","created_by":"dan","updated_at":"2026-01-08T12:59:08.362889466-08:00"} +{"id":"ops-jrz1-8j9","title":"Create musiclink config.toml with API credentials","description":"Create /var/lib/musiclink/config.toml with:\n\n[matterbridge]\n- url = ws://127.0.0.1:4242/api/websocket\n- token = (same as matterbridge API token)\n- gateway = \"main\"\n\n[services]\n- enabled = [\"spotify\", \"youtube\", \"apple\", \"deezer\"]\n\n[services.spotify]\n- client_id, client_secret from Spotify Developer Dashboard\n\n[services.youtube]\n- api_key from Google Cloud Console (optional, can skip initially)\n\nApple Music and Deezer don't need credentials.","status":"open","priority":2,"issue_type":"task","created_at":"2026-01-08T12:59:08.362889466-08:00","created_by":"dan","updated_at":"2026-01-08T12:59:08.362889466-08:00","dependencies":[{"issue_id":"ops-jrz1-8j9","depends_on_id":"ops-jrz1-qgm","type":"blocks","created_at":"2026-01-08T15:56:08.129810568-08:00","created_by":"dan"},{"issue_id":"ops-jrz1-8j9","depends_on_id":"ops-jrz1-8eb","type":"blocks","created_at":"2026-01-08T15:56:08.167928618-08:00","created_by":"dan"}]} {"id":"ops-jrz1-8m7","title":"Add cgroups limits for user slices","description":"Add soft resource limits to prevent one user/agent from crashing server.\n\n## Config\n```nix\nsystemd.slices.\"user\".sliceConfig = {\n MemoryMax = \"80%\";\n TasksMax = 500;\n CPUWeight = 100; # Fair sharing, no hard quota\n};\n```\n\n## Behavior\n- Memory: Users collectively can't exceed 80% RAM\n- Tasks: Max 500 processes per user (prevents fork bombs)\n- CPU: Fair sharing when contended, bursts allowed\n\n## Testing\n- Verify with `systemctl show user-1001.slice`\n- Test fork bomb doesn't crash server","status":"closed","priority":2,"issue_type":"task","created_at":"2026-01-02T20:16:22.600133044-08:00","created_by":"dan","updated_at":"2026-01-02T21:02:35.455928291-08:00","closed_at":"2026-01-02T21:02:35.455928291-08:00","close_reason":"Closed"} {"id":"ops-jrz1-8mc","title":"configuration.nix: Document UID range 1000:65534 rationale","description":"UID range 1000:65534 excludes root but includes nobody (65534). Add comment explaining rationale. configuration.nix:70","status":"closed","priority":4,"issue_type":"task","created_at":"2026-01-03T08:17:35.893969961-08:00","created_by":"dan","updated_at":"2026-01-03T09:32:23.604873295-08:00","closed_at":"2026-01-03T09:32:23.604873295-08:00","close_reason":"Added comment explaining UID range 1000:65534"} {"id":"ops-jrz1-8mm","title":"Consolidate olm insecure package permission to one location","description":"olm-3.2.16 is permitted in 3 places: configuration.nix:177-179, flake.nix:47-49, flake.nix:70-72. Redundant. Consolidate to one location.","status":"closed","priority":4,"issue_type":"task","created_at":"2026-01-05T15:44:41.269512798-08:00","created_by":"dan","updated_at":"2026-01-05T22:54:52.747856599-08:00","closed_at":"2026-01-05T22:54:52.747856599-08:00","close_reason":"Removed 1 redundant location. Full consolidation not possible: maubot needs it in nixpkgs, mautrix-slack needs it in pkgs-unstable."} @@ -90,7 +90,7 @@ {"id":"ops-jrz1-glk","title":"VS Code extension policy (security)","description":"Extensions can run arbitrary code. Decide: allow arbitrary installs, or curate/restrict? For non-programmers, pre-install safe set and optionally disable marketplace.","status":"closed","priority":3,"issue_type":"task","created_at":"2025-12-05T15:32:41.463030936-08:00","updated_at":"2025-12-28T00:08:06.752037252-05:00","closed_at":"2025-12-28T00:08:06.752037252-05:00","close_reason":"Browser-based dev environment cancelled","dependencies":[{"issue_id":"ops-jrz1-glk","depends_on_id":"ops-jrz1-3so","type":"parent-child","created_at":"2025-12-05T17:05:47.372120465-08:00","created_by":"daemon","metadata":"{}"}]} {"id":"ops-jrz1-gwk","title":"Declarative script deployment via NixOS","description":"Scripts in scripts/ are manually deployed via scp to /usr/local/bin/. Convert to NixOS declarative deployment using writeShellApplication.\n\nTwo packages (per orch consensus):\n1. watchdog-scripts - killswitch, cpu-watchdog, egress-watchdog\n → Referenced directly by systemd, NOT in PATH\n2. admin-scripts - learner-add.sh, learner-remove.sh\n → Added to systemPackages for interactive use\n\nSubtasks:\n- ops-jrz1-vw4: Create watchdog-scripts package\n- ops-jrz1-o9c: Create admin-scripts package (parallel)\n- ops-jrz1-ujw: Update systemd services to use store paths\n- ops-jrz1-sdz: Remove manual /usr/local/bin scripts\n- ops-jrz1-f6i: Update docs","status":"closed","priority":2,"issue_type":"epic","created_at":"2026-01-03T08:39:41.242421474-08:00","created_by":"dan","updated_at":"2026-01-03T09:21:09.83027789-08:00","closed_at":"2026-01-03T09:21:09.83027789-08:00","close_reason":"Epic complete: All scripts now deployed declaratively via writeShellApplication"} {"id":"ops-jrz1-hjs","title":"Evaluate wall/talk for dev-to-dev messaging","description":"Look at classic Unix messaging utilities (wall, talk, write, mesg) for dev-to-dev communication. Goal: make the server feel like a university CS department Unix box - collaborative, retro, educational vibe. Quick terminal pings, 'hey about to reboot', pair debugging invites. Part of the shared-machine culture.","status":"closed","priority":4,"issue_type":"task","created_at":"2026-01-05T11:14:14.813033486-08:00","created_by":"dan","updated_at":"2026-01-05T15:32:22.430901047-08:00","closed_at":"2026-01-05T15:32:22.430901047-08:00","close_reason":"Added bsd-finger, ytalk, fortune to systemPackages. Fortune on login via programs.bash.interactiveShellInit. Classic Unix social tools now available."} -{"id":"ops-jrz1-hkb","title":"Create matterbridge.toml config with Slack + API bridge","description":"Create /var/lib/matterbridge/matterbridge.toml with:\n\n1. [slack.workspace] - Connect to Slack using bot token\n2. [api.musiclink] - Local WebSocket API on 127.0.0.1:4242\n3. [[gateway]] - Route messages between Slack and API\n\nTemplate in /home/dan/proj/musiclink/docs/platform-setup.md\n\nSecrets needed:\n- Slack bot token (xoxb-...)\n- API token (generate with openssl rand -hex 32)","status":"open","priority":2,"issue_type":"task","created_at":"2026-01-08T12:59:07.733852326-08:00","created_by":"dan","updated_at":"2026-01-08T12:59:07.733852326-08:00"} +{"id":"ops-jrz1-hkb","title":"Create matterbridge.toml config with Slack + API bridge","description":"Create /var/lib/matterbridge/matterbridge.toml with:\n\n1. [slack.workspace] - Connect to Slack using bot token\n2. [api.musiclink] - Local WebSocket API on 127.0.0.1:4242\n3. [[gateway]] - Route messages between Slack and API\n\nTemplate in /home/dan/proj/musiclink/docs/platform-setup.md\n\nSecrets needed:\n- Slack bot token (xoxb-...)\n- API token (generate with openssl rand -hex 32)","status":"open","priority":2,"issue_type":"task","created_at":"2026-01-08T12:59:07.733852326-08:00","created_by":"dan","updated_at":"2026-01-08T12:59:07.733852326-08:00","dependencies":[{"issue_id":"ops-jrz1-hkb","depends_on_id":"ops-jrz1-kpw","type":"blocks","created_at":"2026-01-08T15:56:08.043060147-08:00","created_by":"dan"},{"issue_id":"ops-jrz1-hkb","depends_on_id":"ops-jrz1-mul","type":"blocks","created_at":"2026-01-08T15:56:08.311144656-08:00","created_by":"dan"}]} {"id":"ops-jrz1-i1g","title":"Pin beads and opencode flake inputs to commit hashes","description":"flake.nix:13-21 - beads and opencode inputs track HEAD, not pinned to specific commits. Builds may break unexpectedly. Fix: Pin to commit hashes like sops-nix is.","status":"closed","priority":2,"issue_type":"task","created_at":"2026-01-05T15:44:25.36700409-08:00","created_by":"dan","updated_at":"2026-01-05T20:56:59.260867509-08:00","closed_at":"2026-01-05T20:56:59.260867509-08:00","close_reason":"Closed"} {"id":"ops-jrz1-i1z","title":"Add timestamp to killswitch output","description":"scripts/killswitch echo output has no timestamp. Consider adding or document reliance on systemd journal.","status":"open","priority":4,"issue_type":"task","created_at":"2026-01-03T17:35:59.019670457-08:00","created_by":"dan","updated_at":"2026-01-03T17:35:59.019670457-08:00"} {"id":"ops-jrz1-i8i","title":"Enable mautrix-slack relay mode for bot bridging","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-06T19:09:42.087506995-08:00","updated_at":"2025-12-06T19:09:47.612545472-08:00","closed_at":"2025-12-06T19:09:47.612545472-08:00"} @@ -112,7 +112,7 @@ {"id":"ops-jrz1-ld4","title":"VM test: Add fail2ban smoke test","description":"Add basic check that fail2ban.service starts. Consensus says it's a cheap smoke test even without full integration. May need to check if it requires sshd or other deps.","status":"closed","priority":3,"issue_type":"task","created_at":"2026-01-08T00:58:32.21084618-08:00","created_by":"dan","updated_at":"2026-01-08T08:49:02.035160545-08:00","closed_at":"2026-01-08T08:49:02.035160545-08:00","close_reason":"Won't do - fail2ban requires sshd and other deps, not worth test complexity for smoke check"} {"id":"ops-jrz1-meh","title":"cpu-watchdog: Add flock for atomic strike counter updates","description":"Read-modify-write of strike counter not atomic. Systemd timer serializes runs so low risk now, but add flock if parallelism added later. scripts/cpu-watchdog:29-31","status":"closed","priority":3,"issue_type":"task","created_at":"2026-01-03T08:17:35.759126212-08:00","created_by":"dan","updated_at":"2026-01-03T10:08:38.50903714-08:00","closed_at":"2026-01-03T10:08:38.50903714-08:00","close_reason":"Wontfix: systemd timer serializes runs, race condition is theoretical only"} {"id":"ops-jrz1-mh2","title":"Research: Forgejo integration for shared projects","description":"How does beads/bd integrate with our Forgejo git server (git.clarun.xyz)?\n\n## Questions\n- Can bd sync to Forgejo repos?\n- How do dev users on the server collaborate on shared projects?\n- Is there a git workflow that makes sense (forks? shared repo? branches?)\n- Does bd need any special config for Forgejo vs GitHub?\n\n## Context\n- Forgejo running at git.clarun.xyz\n- Dev users have SSH access to server\n- May want shared project tracking via beads","status":"open","priority":2,"issue_type":"task","created_at":"2026-01-02T16:24:01.771168961-08:00","created_by":"dan","updated_at":"2026-01-02T16:24:01.771168961-08:00"} -{"id":"ops-jrz1-mul","title":"Add musiclink secrets to sops-nix","description":"Add to secrets/secrets.yaml:\n\n- matterbridge-api-token: (generated, shared between services)\n- matterbridge-slack-token: (xoxb-... for Slack connection)\n- spotify-client-id: (from Spotify dashboard)\n- spotify-client-secret: (from Spotify dashboard)\n- youtube-api-key: (optional, from Google Cloud)\n\nUpdate sops config in hosts/ops-jrz1.nix to expose these secrets.","status":"open","priority":2,"issue_type":"task","created_at":"2026-01-08T12:59:09.71440955-08:00","created_by":"dan","updated_at":"2026-01-08T12:59:09.71440955-08:00"} +{"id":"ops-jrz1-mul","title":"Add musiclink secrets to sops-nix","description":"Add to secrets/secrets.yaml:\n\n- matterbridge-api-token: (generated, shared between services)\n- matterbridge-slack-token: (xoxb-... for Slack connection)\n- spotify-client-id: (from Spotify dashboard)\n- spotify-client-secret: (from Spotify dashboard)\n- youtube-api-key: (optional, from Google Cloud)\n\nUpdate sops config in hosts/ops-jrz1.nix to expose these secrets.","status":"open","priority":2,"issue_type":"task","created_at":"2026-01-08T12:59:09.71440955-08:00","created_by":"dan","updated_at":"2026-01-08T12:59:09.71440955-08:00","dependencies":[{"issue_id":"ops-jrz1-mul","depends_on_id":"ops-jrz1-jho","type":"blocks","created_at":"2026-01-08T15:56:08.223426556-08:00","created_by":"dan"},{"issue_id":"ops-jrz1-mul","depends_on_id":"ops-jrz1-8eb","type":"blocks","created_at":"2026-01-08T15:56:08.266067255-08:00","created_by":"dan"}]} {"id":"ops-jrz1-n4g","title":"Benchmark VPS performance and evaluate upgrade options","description":"Current specs: 1 vCPU, 2GB RAM, swap in use (363MB). npm installs slow, general sluggishness reported. Investigate: (1) What's using memory? (2) Would 2 vCPU/4GB help significantly? (3) Any NixOS/systemd tuning possible? (4) Cost/benefit of upgrade vs optimization.","status":"open","priority":3,"issue_type":"task","created_at":"2026-01-03T12:29:00.208834799-08:00","created_by":"dan","updated_at":"2026-01-03T12:29:00.208834799-08:00"} {"id":"ops-jrz1-ndl","title":"Browser-based dev environment (code-server)","description":"Explore setting up browser-based development:\n\nOptions:\n- code-server / openvscode-server - VS Code in browser\n- ttyd / wetty - terminal in browser \n- PWA install to home screen for native app feel\n\nCould combine with Tailscale for secure access without exposing ports.\n\nRef: ops-dev thin client brainstorm session","notes":"Design doc created: specs/004-browser-dev-environment/design.md - covers architecture, tech choices, resource planning, security model, rollout phases","status":"closed","priority":2,"issue_type":"feature","created_at":"2025-12-04T15:08:02.406274744-08:00","updated_at":"2025-12-05T17:05:52.872944892-08:00","closed_at":"2025-12-05T17:05:52.872944892-08:00"} {"id":"ops-jrz1-nir","title":"RFC: SSH log noise reduction strategy","description":"Research showed 99.8% of SSH logs are scanner noise (9000 failed attempts/day). Options: (1) Change SSH port - simple, ~99% reduction (2) journald filter - surgical but complex (3) LogLevel ERROR - loses successful login audit trail (4) fail2ban - bans IPs, partial reduction. Orch consensus: Gemini opposed LogLevel ERROR due to losing audit trail, GPT supported. Need RFC to decide approach. See posture review from Dec 2025 session.","status":"open","priority":3,"issue_type":"task","created_at":"2025-12-04T22:55:13.990334935-08:00","updated_at":"2025-12-04T22:55:13.990334935-08:00"} @@ -122,7 +122,7 @@ {"id":"ops-jrz1-o9c","title":"Create admin-scripts package for systemPackages","description":"Package learner-add.sh, learner-remove.sh using writeShellApplication. Add to environment.systemPackages so they're available in PATH for interactive admin use.","status":"closed","priority":2,"issue_type":"task","created_at":"2026-01-03T08:45:35.623169977-08:00","created_by":"dan","updated_at":"2026-01-03T09:20:08.655105165-08:00","closed_at":"2026-01-03T09:20:08.655105165-08:00","close_reason":"Implemented admin-scripts (learner-add, learner-remove) using writeShellApplication, added to systemPackages"} {"id":"ops-jrz1-oxx","title":"Add disk quota or watchdog for /home","description":"No disk limits for users. Could fill /home. Options: ext4 quotas, btrfs subvolume limits, or simple watchdog.","status":"open","priority":3,"issue_type":"task","created_at":"2026-01-03T08:40:26.188569342-08:00","created_by":"dan","updated_at":"2026-01-03T08:40:26.188569342-08:00"} {"id":"ops-jrz1-p2d","title":"Add egress connection logging","description":"Log all new outbound connections for forensics.\n\n## Config\n```nix\nnetworking.firewall.extraCommands = ''\n # Log all new outbound from regular users\n iptables -A OUTPUT -m state --state NEW -m owner --uid-owner 1000:65534 \\\n -j LOG --log-prefix \"EGRESS: \" --log-level info\n'';\n```\n\n## Usage\n```bash\n# View egress logs\njournalctl -k | grep EGRESS\n\n# Watch live\njournalctl -kf | grep EGRESS\n```\n\n## Notes\n- Logs before rate limit rules (if both implemented)\n- Includes source UID, dest IP, dest port","status":"closed","priority":2,"issue_type":"task","created_at":"2026-01-02T20:17:39.566590459-08:00","created_by":"dan","updated_at":"2026-01-02T21:12:35.575052381-08:00","closed_at":"2026-01-02T21:12:35.575052381-08:00","close_reason":"Closed"} -{"id":"ops-jrz1-qgm","title":"Create musiclink NixOS service with buildGoModule","description":"Add systemd service for musiclink bot:\n\n1. Build Go binary with pkgs.buildGoModule from /home/dan/proj/musiclink\n2. Create systemd.services.musiclink with:\n - DynamicUser for isolation\n - StateDirectory for config\n - Hardening (ProtectSystem, ProtectHome, NoNewPrivileges)\n - After/Requires matterbridge.service\n3. Restart policy on failure\n\nAlternative: fetchFromGitHub if we push to git.clarun.xyz","status":"open","priority":2,"issue_type":"task","created_at":"2026-01-08T12:59:08.021057917-08:00","created_by":"dan","updated_at":"2026-01-08T12:59:08.021057917-08:00"} +{"id":"ops-jrz1-qgm","title":"Create musiclink NixOS service with buildGoModule","description":"Add systemd service for musiclink bot:\n\n1. Build Go binary with pkgs.buildGoModule from /home/dan/proj/musiclink\n2. Create systemd.services.musiclink with:\n - DynamicUser for isolation\n - StateDirectory for config\n - Hardening (ProtectSystem, ProtectHome, NoNewPrivileges)\n - After/Requires matterbridge.service\n3. Restart policy on failure\n\nAlternative: fetchFromGitHub if we push to git.clarun.xyz","status":"open","priority":2,"issue_type":"task","created_at":"2026-01-08T12:59:08.021057917-08:00","created_by":"dan","updated_at":"2026-01-08T12:59:08.021057917-08:00","dependencies":[{"issue_id":"ops-jrz1-qgm","depends_on_id":"ops-jrz1-kpw","type":"blocks","created_at":"2026-01-08T15:56:08.088021978-08:00","created_by":"dan"}]} {"id":"ops-jrz1-qj4","title":"Evaluate bun as faster npm alternative for AI tool installs","description":"npm install -g @google/gemini-cli takes ~1 min (580 packages). Bun is much faster. Consider: (1) Add bun to system packages, (2) Update dev-add onboarding to suggest bun install -g, (3) Or pre-install popular tools system-wide.","status":"closed","priority":3,"issue_type":"task","created_at":"2026-01-03T12:26:38.457885819-08:00","created_by":"dan","updated_at":"2026-01-04T13:49:50.343836853-08:00","closed_at":"2026-01-04T13:49:50.343836853-08:00","close_reason":"Added bun to systemPackages, updated dev-add.sh to use bun in PATH and onboarding"} {"id":"ops-jrz1-qts","title":"RFC: Seamless dev access to ops-jrz1 repo","description":"Devs on jrz1 should be able to access ops-jrz1 repo to learn and potentially contribute. Goal: minimal friction, leverage existing SSH access.\n\n## Options explored\n\n### 1. Bare repo on server (simplest)\n```\n/srv/git/ops-jrz1.git\n```\n- Devs clone via filesystem or SSH\n- Zero setup - already have access\n- \"PR\" = branch + Matrix conversation\n- No web UI\n\n### 2. Forgejo API provisioning\n- dev-add.sh creates Forgejo account + SSH key via API\n- Full web UI, real PRs\n- More setup but polished workflow\n\n### 3. Forgejo PAM auth\n- Unix users auto-authenticate to Forgejo\n- Needs password or SSH key sync\n- More complex\n\n### 4. Gitolite\n- Lightweight, reads authorized_keys directly\n- Less UI, seamless auth\n\n## Questions\n- Do we need web UI / PR workflow, or is branch + conversation enough?\n- Is this for learning (read-only) or real contribution?\n- How many devs realistically?\n\n## Recommendation\nStart with option 1 (bare repo) - zero friction, test the workflow. Graduate to option 2 if PR workflow needed.","status":"open","priority":2,"issue_type":"task","created_at":"2026-01-05T18:42:23.691289101-08:00","created_by":"dan","updated_at":"2026-01-05T18:52:35.398669839-08:00"} {"id":"ops-jrz1-qxr","title":"mautrix-slack message edit panic (upstream bug)","description":"Bridge upgraded to v25.11. Need to verify if edit panic is fixed by testing a Slack message edit. Watch logs: journalctl -u mautrix-slack -f | grep -E 'ERR|panic|edit'","status":"closed","priority":2,"issue_type":"bug","created_at":"2025-12-05T18:22:38.18203834-08:00","updated_at":"2025-12-05T19:36:00.556011621-08:00","closed_at":"2025-12-05T19:36:00.556011621-08:00","dependencies":[{"issue_id":"ops-jrz1-qxr","depends_on_id":"ops-jrz1-03o","type":"blocks","created_at":"2025-12-05T18:24:23.259399275-08:00","created_by":"daemon","metadata":"{}"}]}