From bd49ea001a30492fd7a175f76cfbeef30099ad32 Mon Sep 17 00:00:00 2001 From: Dan Date: Sat, 3 Jan 2026 11:00:15 -0800 Subject: [PATCH] Add documentation for adding dev tools MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Covers four methods: system-wide, per-user nix profile, per-project devShell, and external flakes. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- .beads/issues.jsonl | 3 +- docs/adding-dev-tools.md | 125 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 127 insertions(+), 1 deletion(-) create mode 100644 docs/adding-dev-tools.md diff --git a/.beads/issues.jsonl b/.beads/issues.jsonl index fd33e1f..a541b49 100644 --- a/.beads/issues.jsonl +++ b/.beads/issues.jsonl @@ -41,10 +41,11 @@ {"id":"ops-jrz1-cpm","title":"Add admin alerting when killswitch fires","description":"Killswitch only logs to journald. Consider external notification (email, Matrix message, webhook) when users are terminated.","status":"open","priority":4,"issue_type":"task","created_at":"2026-01-03T08:40:26.416998752-08:00","created_by":"dan","updated_at":"2026-01-03T08:40:26.416998752-08:00"} {"id":"ops-jrz1-d38","title":"Add tmux to system packages","description":"Add tmux for session persistence. Users can run bots in tmux, disconnect, reconnect.","status":"closed","priority":2,"issue_type":"task","created_at":"2026-01-02T15:13:58.514256583-08:00","created_by":"dan","updated_at":"2026-01-02T17:25:59.102158299-08:00","closed_at":"2026-01-02T17:25:59.102158299-08:00","close_reason":"Closed"} {"id":"ops-jrz1-d58","title":"Build custom code-server container image","description":"Dockerfile with: code-server, opencode CLI, opencode VS Code extension (Open VSX), Python, Node, Git. Push to registry or build locally.","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-05T17:16:54.507577308-08:00","updated_at":"2025-12-28T00:05:44.736614157-05:00","closed_at":"2025-12-28T00:05:44.736614157-05:00","close_reason":"Parent epic cancelled - browser-based dev approach abandoned","dependencies":[{"issue_id":"ops-jrz1-d58","depends_on_id":"ops-jrz1-3so","type":"parent-child","created_at":"2025-12-05T17:17:36.369590207-08:00","created_by":"daemon","metadata":"{}"}]} -{"id":"ops-jrz1-dg9","title":"Document pattern for adding dev tools to system","description":"Create documentation for the standard pattern of adding dev tools.\n\n## Pattern\n1. Add flake input (if not in nixpkgs)\n2. Add to environment.systemPackages\n3. Run nixos-rebuild switch\n4. Config stays per-user/per-repo\n\n## Document should cover\n- How to add a tool from nixpkgs\n- How to add a tool from external flake\n- How to package a tool not yet packaged\n- How to update a tool (flake lock update)\n\n## Location\ndocs/adding-dev-tools.md or similar","status":"open","priority":3,"issue_type":"task","created_at":"2026-01-02T16:36:04.613581812-08:00","created_by":"dan","updated_at":"2026-01-02T16:36:04.613581812-08:00"} +{"id":"ops-jrz1-dg9","title":"Document pattern for adding dev tools to system","description":"Create documentation for the standard pattern of adding dev tools.\n\n## Pattern\n1. Add flake input (if not in nixpkgs)\n2. Add to environment.systemPackages\n3. Run nixos-rebuild switch\n4. Config stays per-user/per-repo\n\n## Document should cover\n- How to add a tool from nixpkgs\n- How to add a tool from external flake\n- How to package a tool not yet packaged\n- How to update a tool (flake lock update)\n\n## Location\ndocs/adding-dev-tools.md or similar","status":"closed","priority":3,"issue_type":"task","created_at":"2026-01-02T16:36:04.613581812-08:00","created_by":"dan","updated_at":"2026-01-03T10:47:43.998225051-08:00","closed_at":"2026-01-03T10:47:43.998225051-08:00","close_reason":"Created docs/adding-dev-tools.md covering system-wide, per-user, per-project, and external flake methods"} {"id":"ops-jrz1-dhj","title":"Port forwarding strategy for user apps","description":"When user runs app on localhost:3000, how do they view it? code-server has /proxy/\u003cport\u003e but URL is confusing for learners. Need clear UX or docs.","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-05T15:32:30.649292743-08:00","updated_at":"2025-12-05T17:41:01.486505687-08:00","closed_at":"2025-12-05T17:41:01.486505687-08:00","dependencies":[{"issue_id":"ops-jrz1-dhj","depends_on_id":"ops-jrz1-3so","type":"parent-child","created_at":"2025-12-05T17:05:47.175857247-08:00","created_by":"daemon","metadata":"{}"}]} {"id":"ops-jrz1-dt9","title":"Increase container RAM limits (2GB too tight)","description":"2GB hard limit will OOM with code-server + opencode + LSP + user app. Gemini/GPT recommend 3-4GB per container or add swap. Need to size server appropriately.","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-05T15:32:19.400171408-08:00","updated_at":"2025-12-05T17:38:54.770433169-08:00","closed_at":"2025-12-05T17:38:54.770433169-08:00","dependencies":[{"issue_id":"ops-jrz1-dt9","depends_on_id":"ops-jrz1-3so","type":"parent-child","created_at":"2025-12-05T17:05:47.066130377-08:00","created_by":"daemon","metadata":"{}"}]} {"id":"ops-jrz1-dux","title":"Container isolation: maubot API access only","description":"Security design for learner containers:\n\n**Container CAN access**:\n- maubot API (:29316) for plugin deploy\n- Matrix rooms via bot (through maubot)\n- Slack via bridge (through Matrix)\n\n**Container CANNOT access**:\n- Host filesystem\n- Other containers\n- PostgreSQL directly\n- Matrix homeserver directly\n- sops secrets\n\nImplementation: Podman network config, no --privileged, limited port exposure.","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-06T12:18:16.212646624-08:00","updated_at":"2025-12-28T10:12:31.107338781-05:00","closed_at":"2025-12-28T10:12:31.107338781-05:00","close_reason":"Depends on cancelled browser-dev epic (ops-jrz1-3so)","dependencies":[{"issue_id":"ops-jrz1-dux","depends_on_id":"ops-jrz1-3so","type":"parent-child","created_at":"2025-12-06T12:18:21.627621772-08:00","created_by":"daemon","metadata":"{}"}]} +{"id":"ops-jrz1-dw7","title":"Review opencode settings and configuration","description":"Investigate opencode CLI configuration options. What settings are available? Where does config live? Any server-specific tuning needed?","status":"open","priority":3,"issue_type":"task","created_at":"2026-01-03T10:46:29.904950557-08:00","created_by":"dan","updated_at":"2026-01-03T10:46:29.904950557-08:00"} {"id":"ops-jrz1-ecw","title":"Support multiple agentic coders: opencode, gemini, codex","description":"Ensure dev users can use their choice of agentic coding tool, not just Claude.\n\n## Tools Supported\n\n| Tool | Status | Install Method |\n|------|--------|----------------|\n| Claude Code | ✅ /usr/local/bin/claude | Manual install |\n| opencode | ✅ System package | Flake input (github:sst/opencode) |\n| gemini-cli | ✅ User install | `npm install -g @google/gemini-cli` |\n| codex | ✅ User install | `npm install -g @openai/codex` |\n\n## System Packages Added\n- `opencode` - AI coding agent (v1.0.224)\n- `nodejs_22` - For npm-based tool installation\n\n## User Install Instructions\nFor gemini-cli or codex:\n```bash\nnpm install -g @google/gemini-cli\nnpm install -g @openai/codex\n```\n\n## Auth Storage\nSee ops-jrz1-xz7 for multi-user auth research.\n\n## Remaining\n- gastown (gt) blocked - no release binaries yet (ops-jrz1-30e)","status":"closed","priority":2,"issue_type":"task","created_at":"2026-01-02T16:25:11.578992492-08:00","created_by":"dan","updated_at":"2026-01-02T17:41:40.793211973-08:00","closed_at":"2026-01-02T17:41:40.793211973-08:00","close_reason":"Closed"} {"id":"ops-jrz1-ezf","title":"Maubot plugin dev workflow for learners","description":"Design frictionless dev workflow for Python/Go learners building maubot plugins.\n\n**Requirements**:\n- No SSH tunnel setup for learners\n- Fast feedback loop (edit → see bot respond)\n- Circuit breakers (allowed_rooms, rate limits)\n- Test channel: #vlads-pad (Slack) ↔ Matrix\n\n**Options being considered**:\n1. Git-push deploy: push to repo → CI builds .mbp → deploys to maubot\n2. Code-server containers: browser IDE on VPS, deploy script talks to maubot locally\n3. Hybrid: code-server + git workflow\n\n**Related**: ops-jrz1-3so (browser-dev-environment epic)","status":"closed","priority":2,"issue_type":"feature","created_at":"2025-12-06T01:36:26.529372206-08:00","updated_at":"2025-12-28T10:12:31.096280407-05:00","closed_at":"2025-12-28T10:12:31.096280407-05:00","close_reason":"Depends on cancelled browser-dev epic (ops-jrz1-3so)","dependencies":[{"issue_id":"ops-jrz1-ezf","depends_on_id":"ops-jrz1-3so","type":"parent-child","created_at":"2025-12-06T12:18:06.743837766-08:00","created_by":"daemon","metadata":"{}"}]} {"id":"ops-jrz1-f15","title":"mautrix-slack ConvertEdit panic on message edits","description":"mautrix-slack v25.11 panics with nil pointer dereference at handleslack.go:575 when processing Slack message_changed events. \n\nFIX READY at /tmp/mautrix-slack-fix (branch: fix-convert-edit-nil-panic)\n\nThree changes needed in pkg/connector/handleslack.go:\n1. Line 181: Add 'evt.SubMessage != nil \u0026\u0026' before evt.SubMessage.SubType\n2. Lines 573-578: Add nil checks for SubMessage and SubMessage.Edited at start of ConvertEdit()\n3. Line 609: Add 's.Data.SubMessage != nil \u0026\u0026' before accessing Timestamp\n\nTo submit PR: fork mautrix/slack, push branch, open PR against main.","status":"closed","priority":2,"issue_type":"bug","created_at":"2025-12-27T10:03:28.857940916-05:00","created_by":"dan","updated_at":"2025-12-28T10:02:58.660206297-05:00","closed_at":"2025-12-28T10:02:58.660206297-05:00","close_reason":"Won't fix for now - fix ready in /tmp/mautrix-slack-fix if needed later"} diff --git a/docs/adding-dev-tools.md b/docs/adding-dev-tools.md new file mode 100644 index 0000000..754731f --- /dev/null +++ b/docs/adding-dev-tools.md @@ -0,0 +1,125 @@ +# Adding Dev Tools + +How to add development tools to the ops-jrz1 server. + +## Options + +### 1. System-wide (all users) + +Best for: common tools everyone needs (git, vim, htop, curl) + +```nix +# configuration.nix +environment.systemPackages = with pkgs; [ + tldr + bat + fd +]; +``` + +Then deploy: +```bash +nix flake check +nixos-rebuild switch --flake .#ops-jrz1 --target-host root@ops-jrz1 +``` + +### 2. Per-user (nix profile) + +Best for: personal preferences (editor configs, shell tools) + +```bash +# User runs on server: +nix profile install nixpkgs#tldr +nix profile install nixpkgs#bat + +# List installed: +nix profile list + +# Update all: +nix profile upgrade '.*' + +# Remove: +nix profile remove tldr +``` + +Survives reboots, user-managed, not in git. + +### 3. Per-project (flake devShell) + +Best for: project-specific dependencies + +```nix +# flake.nix in project directory +{ + inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + + outputs = { nixpkgs, ... }: + let + pkgs = nixpkgs.legacyPackages.x86_64-linux; + in { + devShells.x86_64-linux.default = pkgs.mkShell { + packages = with pkgs; [ + python3 + uv + ruff + ]; + }; + }; +} +``` + +Then: +```bash +nix develop # Enter shell +# or with direnv: +echo "use flake" > .envrc +direnv allow +``` + +### 4. External flake (not in nixpkgs) + +For tools packaged as flakes (like opencode, beads): + +```nix +# flake.nix inputs +inputs.sometool.url = "github:org/sometool"; + +# Pass to NixOS +specialArgs = { + sometool = inputs.sometool.packages.x86_64-linux.default; +}; + +# configuration.nix +environment.systemPackages = [ sometool ]; +``` + +## Finding Packages + +```bash +# Search nixpkgs +nix search nixpkgs tldr + +# Check if package exists +nix eval nixpkgs#tldr.meta.description +``` + +## Recommendations + +| Tool Type | Method | +|-----------|--------| +| Core utils (git, curl, vim) | System-wide | +| Build tools (go, rust, node) | System-wide | +| Personal prefs (tldr, bat, eza) | Per-user | +| Project deps (linters, formatters) | Per-project | +| AI tools with auth (claude, gemini) | Per-user | + +## Updating + +```bash +# Update flake inputs (external tools) +nix flake update +nixos-rebuild switch ... + +# Update user profile +nix profile upgrade '.*' +```