From 9ca23fefad5c096d219841f8b1cca3fb2d94fe8e Mon Sep 17 00:00:00 2001 From: Dan Date: Sat, 3 Jan 2026 17:11:11 -0800 Subject: [PATCH] bd sync: 2026-01-03 17:11:11 --- .beads/issues.jsonl | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.beads/issues.jsonl b/.beads/issues.jsonl index a541b49..ac8d35a 100644 --- a/.beads/issues.jsonl +++ b/.beads/issues.jsonl @@ -1,6 +1,8 @@ {"id":"ops-jrz1-00e","title":"Upgrade NixOS from 24.05 to 24.11","description":"Running NixOS 24.05.20241230 (Uakari). Current stable is 24.11. May be missing security patches. Low priority as no known critical CVEs, but should plan upgrade.","status":"open","priority":3,"issue_type":"task","created_at":"2025-12-04T21:03:22.760228514-08:00","updated_at":"2025-12-04T21:04:35.805980055-08:00","comments":[{"id":1,"issue_id":"ops-jrz1-00e","author":"dan","text":"Analysis Findings:\n1. Version Mismatch: Local flake.nix is pinned to 'nixos-24.05', but the dev environment reports '25.11' (Unstable), indicating state divergence.\n2. Upstream Bugs: Blocking issues in mautrix-slack (ops-jrz1-blh) and maubot (sync failure) are present in the current unstable revision (2025-12-02).\n3. Recommendation: Upgrade platform to NixOS 24.11 (Stable) to align environment, ensure stability, and pull fresh upstream fixes.","created_at":"2025-12-08T23:54:57Z"}]} {"id":"ops-jrz1-03o","title":"Upgrade mautrix-slack to v25.11","description":"Upgrade is just flake update + deploy. Current deployed: v0.2.3+dev.unknown (Oct 13). Flake lock: v25.10 (Oct 22). Latest nixpkgs-unstable: v25.11. Run: nix flake update nixpkgs-unstable \u0026\u0026 deploy. May fix edit panic (ops-jrz1-qxr).","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-05T18:24:18.332067067-08:00","updated_at":"2025-12-05T19:07:09.156981447-08:00","closed_at":"2025-12-05T19:07:09.156981447-08:00"} +{"id":"ops-jrz1-0tk","title":"Set up backup strategy for /home dev directories","description":"User home directories contain work that should be backed up. Options: (1) Daily tarball to object storage, (2) Restic/borg to remote, (3) Syncthing to another host, (4) Just document that users should push to git. Consider: frequency, retention, restore process, cost.","status":"open","priority":2,"issue_type":"task","created_at":"2026-01-03T14:17:56.208262155-08:00","created_by":"dan","updated_at":"2026-01-03T14:17:56.208262155-08:00"} {"id":"ops-jrz1-1bk","title":"Add CPU watchdog timer","description":"Systemd timer that detects sustained CPU abuse and kills offending user.\n\n## Script: /usr/local/bin/cpu-watchdog\n```bash\n#\\!/usr/bin/env bash\n# Detect sustained CPU abuse, kill after 5 consecutive violations\nTHRESHOLD=180 # 180% CPU (almost 2 cores)\nCOUNTFILE=\"/var/lib/cpu-watchdog\"\nmkdir -p \"$COUNTFILE\"\n\nfor user in $(ls /home); do\n id \"$user\" \u0026\u003e/dev/null || continue\n pct=$(ps -u \"$user\" -o %cpu= 2\u003e/dev/null | awk '{s+=$1}END{print int(s)}')\n pct=${pct:-0}\n \n if [ \"$pct\" -gt \"$THRESHOLD\" ]; then\n count=$(cat \"$COUNTFILE/$user\" 2\u003e/dev/null || echo 0)\n count=$((count + 1))\n echo \"$count\" \u003e \"$COUNTFILE/$user\"\n logger -t cpu-watchdog \"User $user at ${pct}% CPU (strike $count/5)\"\n \n if [ \"$count\" -ge 5 ]; then\n /usr/local/bin/killswitch \"$user\" \"sustained CPU abuse (${pct}%)\"\n rm -f \"$COUNTFILE/$user\"\n fi\n else\n rm -f \"$COUNTFILE/$user\"\n fi\ndone\n```\n\n## Systemd timer\n```nix\nsystemd.services.cpu-watchdog = {\n script = ''/usr/local/bin/cpu-watchdog'';\n serviceConfig.Type = \"oneshot\";\n};\nsystemd.timers.cpu-watchdog = {\n wantedBy = [ \"timers.target\" ];\n timerConfig = {\n OnBootSec = \"1min\";\n OnUnitActiveSec = \"1min\";\n };\n};\n```\n\n## Behavior\n- Runs every minute\n- 5 consecutive minutes at \u003e180% CPU = kill\n- Resets counter if CPU drops below threshold","status":"closed","priority":2,"issue_type":"task","created_at":"2026-01-02T20:20:53.246401154-08:00","created_by":"dan","updated_at":"2026-01-02T21:02:35.469465906-08:00","closed_at":"2026-01-02T21:02:35.469465906-08:00","close_reason":"Closed","dependencies":[{"issue_id":"ops-jrz1-1bk","depends_on_id":"ops-jrz1-396","type":"blocks","created_at":"2026-01-02T20:21:14.270063028-08:00","created_by":"dan"}]} +{"id":"ops-jrz1-1kv","title":"Set up terminfo for xterm-ghostty and other modern terminals","status":"open","priority":3,"issue_type":"task","created_at":"2026-01-03T11:34:42.133192121-08:00","created_by":"dan","updated_at":"2026-01-03T11:34:42.133192121-08:00"} {"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-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"} @@ -19,6 +21,7 @@ {"id":"ops-jrz1-5fk","title":"Smoke test Maubot service","description":"Verify Maubot is healthy: check management UI accessible via SSH tunnel, verify bot instances running, test plugin functionality. Quick health check after deployments.","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-05T18:09:47.33773092-08:00","updated_at":"2025-12-05T18:19:33.061388913-08:00","closed_at":"2025-12-05T18:19:33.061388913-08:00"} {"id":"ops-jrz1-5ki","title":"Set up programmatic QA test user for bridge testing","status":"open","priority":3,"issue_type":"task","created_at":"2025-12-05T20:17:04.312571398-08:00","updated_at":"2025-12-05T20:17:04.312571398-08:00"} {"id":"ops-jrz1-5oe","title":"Create NixOS module for code-server containers","description":"Module to manage per-user Podman containers, nginx routing, secrets. Use virtualisation.oci-containers. Generate systemd units.","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-05T17:16:54.656121092-08:00","updated_at":"2025-12-28T00:05:44.743524099-05:00","closed_at":"2025-12-28T00:05:44.743524099-05:00","close_reason":"Parent epic cancelled - browser-based dev approach abandoned","dependencies":[{"issue_id":"ops-jrz1-5oe","depends_on_id":"ops-jrz1-3so","type":"parent-child","created_at":"2025-12-05T17:17:36.386278268-08:00","created_by":"daemon","metadata":"{}"},{"issue_id":"ops-jrz1-5oe","depends_on_id":"ops-jrz1-d58","type":"blocks","created_at":"2025-12-05T17:17:38.694752468-08:00","created_by":"daemon","metadata":"{}"}]} +{"id":"ops-jrz1-62b","title":"dev-add: check devs group exists before creating user","description":"dev-add failed silently when devs group was missing. User was created but SSH key wasn't set up. Script should validate prerequisites first.","status":"closed","priority":2,"issue_type":"bug","created_at":"2026-01-03T11:50:57.134573631-08:00","created_by":"dan","updated_at":"2026-01-03T11:53:40.714806901-08:00","closed_at":"2026-01-03T11:53:40.714806901-08:00","close_reason":"Added devs group check before user creation in dev-add.sh"} {"id":"ops-jrz1-6of","title":"AI cost/rate limiting per user","description":"One user could drain API credits with runaway script. Need rate limiting per user, either via proxy middleware or opencode config. Track usage.","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-05T15:32:30.772304538-08:00","updated_at":"2025-12-05T17:42:42.773613559-08:00","closed_at":"2025-12-05T17:42:42.773613559-08:00","dependencies":[{"issue_id":"ops-jrz1-6of","depends_on_id":"ops-jrz1-3so","type":"parent-child","created_at":"2025-12-05T17:05:47.206816868-08:00","created_by":"daemon","metadata":"{}"},{"issue_id":"ops-jrz1-6of","depends_on_id":"ops-jrz1-wj2","type":"blocks","created_at":"2025-12-05T17:17:38.658742196-08:00","created_by":"daemon","metadata":"{}"}]} {"id":"ops-jrz1-6t9","title":"Evaluate llm CLI: per-repo vs system-wide install","description":"Simon Willison's llm CLI tool. Options: (1) System-wide via nixpkgs, (2) Per-user via uv/pip, (3) Per-project .envrc. Consider: multiple users, plugin ecosystem, update frequency.","status":"open","priority":3,"issue_type":"task","created_at":"2026-01-03T09:35:13.705897177-08:00","created_by":"dan","updated_at":"2026-01-03T09:35:13.705897177-08:00"} {"id":"ops-jrz1-7j4","title":"Git credential strategy for non-programmers","description":"Non-programmers can't manage SSH keys. Pre-configure git-credential-store or provide simple PAT workflow with docs. Store in persistent home with 600 perms.","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-05T15:32:19.673999683-08:00","updated_at":"2025-12-05T17:38:54.788694408-08:00","closed_at":"2025-12-05T17:38:54.788694408-08:00","dependencies":[{"issue_id":"ops-jrz1-7j4","depends_on_id":"ops-jrz1-3so","type":"parent-child","created_at":"2025-12-05T17:05:47.139749437-08:00","created_by":"daemon","metadata":"{}"}]} @@ -65,6 +68,7 @@ {"id":"ops-jrz1-lae","title":"egress-watchdog: Fix subshell gotcha in while-read pipeline","description":"while-read in pipeline runs in subshell - variables don't persist outside loop. Use process substitution: while read ...; done \u003c \u003c(echo \"$hits\" | grep ...). scripts/egress-watchdog:25","status":"closed","priority":2,"issue_type":"task","created_at":"2026-01-03T08:17:35.401495377-08:00","created_by":"dan","updated_at":"2026-01-03T09:30:50.535018144-08:00","closed_at":"2026-01-03T09:30:50.535018144-08:00","close_reason":"Fixed: using process substitution instead of pipeline subshell"} {"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-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"} {"id":"ops-jrz1-nvx","title":"Slack bot architecture: Matrix-first approach","description":"**Decision**: Use Matrix as primary platform for Slack bot development.\n\n**Architecture**: Bots run as maubot plugins (or Matrix bots), communicate to Slack via mautrix-slack bridge.\n\n**Rationale**:\n- Existing infrastructure (maubot deployed, bridge working)\n- Single platform to manage\n- Bots work with Matrix users too\n- Avoid Socket Mode contention (only one xapp- connection allowed)\n\n**Trade-offs accepted**:\n- Bridge dependency (edit panic bug exists)\n- Extra latency through bridge hop\n- Limited to bridged channels\n\n**Alternative considered (Option B - direct Slack API)**:\n- Could use xoxb- token for outbound-only (REST)\n- Would need new Slack app for full Socket Mode independence\n- Deferred for now\n\n**Credentials available**:\n- slack-oauth-token (xoxb-) - shareable for REST calls if needed\n- slack-app-token (xapp-) - reserved for bridge Socket Mode\n\n**Status**: DECIDED - staying with Matrix-first","status":"closed","priority":3,"issue_type":"task","created_at":"2025-12-05T23:12:22.011872713-08:00","updated_at":"2025-12-05T23:12:28.329467732-08:00","closed_at":"2025-12-05T23:12:28.329467732-08:00"} @@ -72,6 +76,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-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":"open","priority":3,"issue_type":"task","created_at":"2026-01-03T12:26:38.457885819-08:00","created_by":"dan","updated_at":"2026-01-03T12:26:38.457885819-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":"{}"}]} {"id":"ops-jrz1-rkp","title":"Add egress abuse watchdog","description":"Monitor for users hitting egress rate limits, kill if sustained.\n\n## Script: /usr/local/bin/egress-watchdog\n```bash\n#\\!/usr/bin/env bash\n# Kill users who keep hitting egress limits\nTHRESHOLD=10 # EGRESS-LIMIT hits per minute\nCOUNTFILE=\"/var/lib/egress-watchdog\"\nmkdir -p \"$COUNTFILE\"\n\n# Count recent limit hits per UID\njournalctl -k --since \"1 minute ago\" 2\u003e/dev/null | grep \"EGRESS-LIMIT\" | \\\n grep -oP 'UID=\\K[0-9]+' | sort | uniq -c | while read count uid; do\n \n user=$(getent passwd \"$uid\" | cut -d: -f1)\n [ -z \"$user\" ] \u0026\u0026 continue\n \n if [ \"$count\" -gt \"$THRESHOLD\" ]; then\n strikes=$(cat \"$COUNTFILE/$user\" 2\u003e/dev/null || echo 0)\n strikes=$((strikes + 1))\n echo \"$strikes\" \u003e \"$COUNTFILE/$user\"\n logger -t egress-watchdog \"User $user hit egress limit $count times (strike $strikes/3)\"\n \n if [ \"$strikes\" -ge 3 ]; then\n /usr/local/bin/killswitch \"$user\" \"egress abuse ($count hits)\"\n rm -f \"$COUNTFILE/$user\"\n fi\n else\n rm -f \"$COUNTFILE/$user\"\n fi\ndone\n```\n\n## Behavior\n- Runs every minute (same timer as CPU watchdog, or separate)\n- 3 consecutive minutes of \u003e10 blocked connections = kill\n- Works with egress rate limiting (ops-jrz1-cmv)\n\n## Dependencies\n- Requires ops-jrz1-cmv (egress rate limiting)\n- Requires ops-jrz1-396 (killswitch script)","status":"closed","priority":2,"issue_type":"task","created_at":"2026-01-02T20:21:09.516724064-08:00","created_by":"dan","updated_at":"2026-01-03T06:02:02.132992356-08:00","closed_at":"2026-01-03T06:02:02.132992356-08:00","close_reason":"Egress watchdog deployed and tested. Script monitors EGRESS-LIMIT kernel log entries, tracks strikes per user, kills after 3 strikes.","dependencies":[{"issue_id":"ops-jrz1-rkp","depends_on_id":"ops-jrz1-396","type":"blocks","created_at":"2026-01-02T20:21:14.314011866-08:00","created_by":"dan"},{"issue_id":"ops-jrz1-rkp","depends_on_id":"ops-jrz1-cmv","type":"blocks","created_at":"2026-01-02T20:21:14.352411765-08:00","created_by":"dan"}]} {"id":"ops-jrz1-sdz","title":"Remove /usr/local/bin scripts from server","description":"After declarative deployment works, clean up manually deployed scripts from /usr/local/bin on the server.","status":"closed","priority":3,"issue_type":"task","created_at":"2026-01-03T08:39:54.483032394-08:00","created_by":"dan","updated_at":"2026-01-03T09:20:34.591216526-08:00","closed_at":"2026-01-03T09:20:34.591216526-08:00","close_reason":"Removed all manual scripts from /usr/local/bin/","dependencies":[{"issue_id":"ops-jrz1-sdz","depends_on_id":"ops-jrz1-ujw","type":"blocks","created_at":"2026-01-03T08:40:02.851476398-08:00","created_by":"dan"},{"issue_id":"ops-jrz1-sdz","depends_on_id":"ops-jrz1-o9c","type":"blocks","created_at":"2026-01-03T08:45:48.023849189-08:00","created_by":"dan"}]}