diff --git a/.config/fish/config.fish b/.config/fish/config.fish index ee0ee6e..08428f0 100644 --- a/.config/fish/config.fish +++ b/.config/fish/config.fish @@ -3,6 +3,3 @@ if status is-interactive end fish_config theme choose "Catppuccin Mocha" --color-theme=dark - -# Added by codebase-memory-mcp install -export PATH="/home/alex/dotfiles/.local/bin:$PATH" diff --git a/.config/fish/fish_variables b/.config/fish/fish_variables index aaa071b..a89404a 100644 --- a/.config/fish/fish_variables +++ b/.config/fish/fish_variables @@ -1,5 +1,6 @@ # This file contains fish universal variable definitions. # VERSION: 3.0 +SETUVAR OPENCODE_ENABLE_EXA:1 SETUVAR __fish_initialized:4300 SETUVAR _fisher_catppuccin_2F_fish_files:\x7e/\x2econfig/fish/themes/Catppuccin\x20Frappe\x2etheme\x1e\x7e/\x2econfig/fish/themes/Catppuccin\x20Macchiato\x2etheme\x1e\x7e/\x2econfig/fish/themes/Catppuccin\x20Mocha\x2etheme\x1e\x7e/\x2econfig/fish/themes/static SETUVAR _fisher_jorgebucaran_2F_fisher_files:\x7e/\x2econfig/fish/functions/fisher\x2efish\x1e\x7e/\x2econfig/fish/completions/fisher\x2efish diff --git a/.config/fish/functions/c.fish b/.config/fish/functions/c.fish deleted file mode 100644 index 74ad9fd..0000000 --- a/.config/fish/functions/c.fish +++ /dev/null @@ -1,9 +0,0 @@ -function c --wraps=opencode --description 'opencode (auto-starts tmux for visual subagent panes)' - set -l port (python -c 'import socket; s=socket.socket(); s.bind(("127.0.0.1", 0)); print(s.getsockname()[1]); s.close()') - - if not set -q TMUX - tmux new-session opencode --port $port $argv - else - opencode --port $port $argv - end -end diff --git a/.config/fish/functions/cc.fish b/.config/fish/functions/cc.fish deleted file mode 100644 index af4c6ca..0000000 --- a/.config/fish/functions/cc.fish +++ /dev/null @@ -1,9 +0,0 @@ -function cc --wraps='opencode --continue' --description 'opencode --continue (auto-starts tmux for visual subagent panes)' - set -l port (python -c 'import socket; s=socket.socket(); s.bind(("127.0.0.1", 0)); print(s.getsockname()[1]); s.close()') - - if not set -q TMUX - tmux new-session opencode --port $port --continue $argv - else - opencode --port $port --continue $argv - end -end diff --git a/.config/hypr/hyprlock.conf b/.config/hypr/hyprlock.conf index 8ee7573..244a2c2 100644 --- a/.config/hypr/hyprlock.conf +++ b/.config/hypr/hyprlock.conf @@ -58,7 +58,7 @@ input-field { inner_color = rgba(49, 50, 68, 1.0) font_color = rgba(205, 214, 244, 1.0) fade_on_empty = false - placeholder_text = Touch YubiKey or enter password... + placeholder_text = ... hide_input = false check_color = rgba(166, 227, 161, 1.0) fail_color = rgba(243, 139, 168, 1.0) diff --git a/.config/nvim/init.lua b/.config/nvim/init.lua index acdfe5f..5735825 100644 --- a/.config/nvim/init.lua +++ b/.config/nvim/init.lua @@ -18,7 +18,7 @@ require("lazy").setup({ }) vim.keymap.set("n", "e", vim.cmd.Ex) -vim.keymap.set("n", "ww", vim.cmd.w) +vim.keymap.set("n", "w", vim.cmd.w) vim.opt.number = true vim.opt.relativenumber = true diff --git a/.config/nvim/lazy-lock.json b/.config/nvim/lazy-lock.json index 9de2e37..6d00956 100644 --- a/.config/nvim/lazy-lock.json +++ b/.config/nvim/lazy-lock.json @@ -1,6 +1,5 @@ { "LuaSnip": { "branch": "master", "commit": "dae4f5aaa3574bd0c2b9dd20fb9542a02c10471c" }, - "blink.cmp": { "branch": "main", "commit": "f22f66eb7c4d037ed523a78b27ee235b7bc9a1f4" }, "catppuccin": { "branch": "main", "commit": "12c004cde3f36cb1d57242f1e6aac46b09a0e5b4" }, "cmp-buffer": { "branch": "main", "commit": "b74fab3656eea9de20a9b8116afa3cfc4ec09657" }, "cmp-nvim-lsp": { "branch": "main", "commit": "cbc7b02bb99fae35cb42f514762b89b5126651ef" }, @@ -18,10 +17,8 @@ "nvim-cmp": { "branch": "main", "commit": "da88697d7f45d16852c6b2769dc52387d1ddc45f" }, "nvim-lspconfig": { "branch": "master", "commit": "2163c54bb6cfec53e3e555665ada945b8c8331b9" }, "nvim-treesitter": { "branch": "main", "commit": "5cb05e1b0fa3c469958a2b26f36b3fe930af221c" }, - "opencode.nvim": { "branch": "main", "commit": "1088ee70dd997d785a1757d351c07407f0abfc9f" }, + "pi.nvim": { "branch": "main", "commit": "761cb109ebd466784f219e6e3a43a28f6187d627" }, "plenary.nvim": { "branch": "master", "commit": "b9fd5226c2f76c951fc8ed5923d85e4de065e509" }, - "render-markdown.nvim": { "branch": "main", "commit": "e3c18ddd27a853f85a6f513a864cf4f2982b9f26" }, - "snacks.nvim": { "branch": "main", "commit": "9912042fc8bca2209105526ac7534e9a0c2071b2" }, "telescope-fzf-native.nvim": { "branch": "main", "commit": "6fea601bd2b694c6f2ae08a6c6fab14930c60e2c" }, "telescope.nvim": { "branch": "master", "commit": "3333a52ff548ba0a68af6d8da1e54f9cd96e9179" } } diff --git a/.config/nvim/lua/plugins/pi.lua b/.config/nvim/lua/plugins/pi.lua new file mode 100644 index 0000000..27938c6 --- /dev/null +++ b/.config/nvim/lua/plugins/pi.lua @@ -0,0 +1,77 @@ +return { + "pablopunk/pi.nvim", + opts = {}, + config = function(_, opts) + require("pi").setup(opts) + + local state = { + buf = nil, + win = nil, + } + + local function pane_width() + return math.max(50, math.floor(vim.o.columns * 0.35)) + end + + local function style_pane(win) + if not win or not vim.api.nvim_win_is_valid(win) then + return + end + pcall(vim.api.nvim_win_set_width, win, pane_width()) + vim.wo[win].number = false + vim.wo[win].relativenumber = false + vim.wo[win].signcolumn = "no" + vim.wo[win].winfixwidth = true + end + + local function open_pi_pane() + if state.win and vim.api.nvim_win_is_valid(state.win) then + vim.api.nvim_set_current_win(state.win) + vim.cmd("startinsert") + return + end + + vim.cmd("botright vsplit") + state.win = vim.api.nvim_get_current_win() + style_pane(state.win) + + if state.buf and vim.api.nvim_buf_is_valid(state.buf) then + vim.api.nvim_win_set_buf(state.win, state.buf) + else + vim.cmd("terminal pi") + state.buf = vim.api.nvim_get_current_buf() + vim.bo[state.buf].buflisted = false + vim.bo[state.buf].bufhidden = "hide" + + vim.api.nvim_create_autocmd({ "BufWipeout", "TermClose" }, { + buffer = state.buf, + callback = function() + state.buf = nil + state.win = nil + end, + }) + end + + style_pane(state.win) + vim.cmd("startinsert") + end + + local function toggle_pi_pane() + if state.win and vim.api.nvim_win_is_valid(state.win) then + vim.api.nvim_win_close(state.win, true) + state.win = nil + return + end + + open_pi_pane() + end + + vim.api.nvim_create_user_command("PiPane", open_pi_pane, { desc = "Open pi in a right side pane" }) + vim.api.nvim_create_user_command("PiPaneToggle", toggle_pi_pane, { desc = "Toggle pi right side pane" }) + end, + keys = { + { "p", "PiAsk", desc = "Pi Ask" }, + { "pp", "PiPaneToggle", desc = "Pi Pane" }, + { "ps", "PiAskSelection", mode = "v", desc = "Pi Ask Selection" }, + }, +} diff --git a/.config/opencode/.gitignore b/.config/opencode/.gitignore deleted file mode 100644 index b7100d9..0000000 --- a/.config/opencode/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -node_modules -package.json -bun.lock -.megamemory/ -.memory/ diff --git a/.config/opencode/AGENTS.md b/.config/opencode/AGENTS.md deleted file mode 100644 index cf005eb..0000000 --- a/.config/opencode/AGENTS.md +++ /dev/null @@ -1,237 +0,0 @@ -# OpenCode Global Workflow - -## Operating Model - -- Default to `planner`. Do not implement before there is an approved plan. -- `planner` owns discovery, decomposition, verification oracles, risk tracking, and the handoff spec. -- `builder` executes the approved spec exactly, delegates focused work to subagents, and escalates back to `planner` instead of improvising when the spec breaks. -- Parallelize aggressively for research, exploration, review, and isolated implementation lanes. Do not parallelize code mutation when lanes share files, APIs, schemas, or verification steps. -- Use explicit `allow` or `deny` permissions only. Do not rely on `ask`. -- Keep `external_directory` denied. Real project repos may use repo-local `/.worktrees`, but this global config must not relax that rule. - -## Agent Roster - -| Agent | Mode | Model | Responsibility | -| --- | --- | --- | --- | -| `planner` | primary | `github-copilot/gpt-5.4` | Produce approved specs and decide whether execution is ready | -| `builder` | primary | `github-copilot/gpt-5.4` | Execute approved specs and integrate delegated work | -| `researcher` | subagent | `github-copilot/gpt-5.4` | Deep research, external docs, tradeoff analysis | -| `explorer` | subagent | `github-copilot/claude-sonnet-4.6` | Read-only repo inspection; reports facts only, never plans or recommendations | -| `reviewer` | subagent | `github-copilot/gpt-5.4` | Critique plans, code, tests, and release readiness | -| `coder` | subagent | `github-copilot/gpt-5.3-codex` | Implement narrowly scoped code changes | -| `tester` | subagent | `github-copilot/claude-opus-4.6` | Run verification, triage failures, capture evidence | -| `librarian` | subagent | `github-copilot/claude-opus-4.6` | Maintain docs, `AGENTS.md`, and memory hygiene | - -## Planner Behavior - -- `planner` must use the `question` tool proactively when scope, defaults, approval criteria, or critical context are ambiguous. Prefer asking over assuming. -- `planner` may use bash and Docker commands during planning for context gathering (e.g., `docker compose config`, `docker ps`, inspecting files, checking versions). Do not run builds, installs, tests, deployments, or any implementation-level commands — those belong to builder/tester/coder. - -## Planner -> Builder Contract - -- Every build starts from a memory note under `plans/` with `Status: approved`. -- Approved plans must include: objective, scope, constraints, assumptions, concrete task list, parallelization lanes, verification oracle, risks, and open findings. -- `builder` must follow the approved plan exactly. -- `builder` must stop and escalate back to `planner` when it finds a spec contradiction, a hidden dependency that changes scope, or two failed verification attempts after recording root cause and evidence. - -### Builder Commits - -- `builder` automatically creates git commits at meaningful task checkpoints and at final completion when uncommitted changes remain. -- A "meaningful checkpoint" is a completed implementation chunk from the approved plan, not every file save. -- Skip commit creation when there are no new changes since the prior checkpoint. -- Commit messages should reflect the intent of the completed task from the plan. -- Before creating the final completion commit, clean up temporary artifacts generated during the build (e.g., scratch files, screenshots, logs, transient reports, caches). Intended committed deliverables are not cleanup targets. -- Standard git safety rules apply: review staged content, respect hooks, no force-push or destructive operations. -- Push automation is out of scope; the user decides when to push. - -## Commands - -- `/init` initializes or refreshes repo memory and the project `AGENTS.md`. -- `/plan` creates or updates the canonical implementation plan in memory. -- `/build` executes the latest approved plan and records execution progress. -- `/continue` resumes unfinished planning or execution from memory based on the current primary agent. -- Built-in `/sessions` remains available for raw session browsing; custom `/continue` is the workflow-aware resume entrypoint. - -## Memory System (Single: basic-memory) - -Memory uses one persistent system: **basic-memory**. - -- All persistent knowledge is stored in basic-memory notes, split across a **`main` project** (global/shared) and **per-repo projects** (project-specific). -- The managed per-repo basic-memory project directory is `/.memory/`. -- Do not edit managed `.memory/*` files directly; use basic-memory MCP tools for all reads/writes. - -### `main` vs per-repo projects - -1. **`main` (global/shared knowledge only)** - - Reusable coding patterns - - Technology knowledge - - User preferences and workflow rules - - Cross-project lessons learned - -2. **Per-repo projects (project-specific knowledge only)** - - Project overview and architecture notes - - Plans, execution logs, decisions, findings, and continuity notes - - Project-specific conventions and testing workflows - -**Hard rule:** Never store project-specific plans, decisions, research, gates, or sessions in `main`. Never store cross-project reusable knowledge in a per-repo project. - -### Required per-repo note taxonomy - -- `project/overview` - stack, purpose, important entrypoints -- `project/architecture` - major modules, data flow, boundaries -- `project/workflows` - local dev, build, test, release commands -- `project/testing` - verification entrypoints and expectations -- `plans/` - canonical specs with `Status: draft|approved|blocked|done` -- `executions/` - structured execution log with `Status: in_progress|blocked|done` (see template below) -- `decisions/` - durable project-specific decisions -- `findings/` - open findings ledger with evidence and owner - -### Execution note template (`executions/`) - -Every execution note must use these literal section names: - -``` -## Plan -- **Source:** plans/ -- **Status:** approved - -## Execution State -- **Objective:** -- **Current Phase:** -- **Next Checkpoint:** -- **Blockers:** -- **Last Updated By:** -- **Legacy Note Normalized:** - -## Lane Claims -Repeated per lane: - -### Lane: -- **Owner:** -- **Status:** planned | active | released | blocked | done -- **Claimed Files/Areas:** -- **Depends On:** -- **Exit Condition:** - -## Last Verified State -- **Mode:** none | smoke | full -- **Summary:** -- **Outstanding Risk:** -- **Related Ledger Entry:** - -## Verification Ledger -Append-only log. Each entry: - -### Entry: -- **Goal:** -- **Mode:** smoke | full -- **Command/Check:** -- **Result:** pass | fail | blocked | not_run -- **Key Evidence:** -- **Artifacts:** -- **Residual Risk:** -``` - -#### Verification summary shape - -Each verification entry (in Last Verified State or Verification Ledger) uses these fields: - -- **Goal** - what is being verified -- **Mode** - `smoke` or `full` (see mode rules) -- **Command/Check** - exact command or manual check performed -- **Result** - `pass`, `fail`, `blocked`, or `not_run` -- **Key Evidence** - concise proof (output snippet, hash, assertion count) -- **Artifacts** - paths to logs/screenshots if any, or `none` -- **Residual Risk** - known gaps, or `none` - -#### Verification mode rules - -- Default to **`smoke`** for intermediate checkpoint proof and isolated lane verification. -- Default to **`full`** before any final completion claim or setting execution status to `done`. -- If there is only one meaningful verification step, record it as `full` and note there is no separate smoke check. - -#### Compact verification summary behavior - -- The verification ledger shape is the default evidence format for builder/tester/coder handoffs. -- Raw logs should stay out of primary context unless a check fails or the user explicitly requests full output. -- When raw output is necessary, summarize the failure first and then point to the raw evidence. - -#### Lane-claim lifecycle - -- **Planner** defines intended lanes and claimed files/areas in the approved plan when parallelization is expected. -- **Builder** creates or updates lane-claim entries in the execution note before fan-out and marks them `active`, `released`, `done`, or `blocked`. -- Overlapping claimed files/areas or sequential verification dependencies **forbid** parallel fan-out. -- Claims are advisory markdown metadata, not hard runtime locks. - -#### Reviewer and execution-note ownership - -- `reviewer` is read-only on execution notes; it reports findings via its response message. -- `builder` owns all execution-note writes and status transitions. - -#### Legacy execution notes - -Legacy execution notes may be freeform and lack structured sections. `/continue` must degrade gracefully — read what exists, do not invent conflicts or synthesize missing sections without evidence. - -### Per-repo project setup (required) - -Every code repository must have its own dedicated basic-memory project. - -Use `basic-memory_create_memory_project` with: -- `project_name`: short kebab-case repo identifier -- `project_path`: `/.memory` - -## Skills - -Local skills live under `skills//SKILL.md` and are loaded on demand via the `skill` tool. See `skills/creating-skills/SKILL.md` for authoring rules. - -### First-Batch Skills - -| Skill | Purpose | -| --- | --- | -| `systematic-debugging` | Root-cause-first debugging with findings, evidence, and builder escalation | -| `verification-before-completion` | Evidence-before-claims verification for tester and builder handoffs | -| `brainstorming` | Planner-owned discovery and design refinement ending in memory-backed artifacts | -| `writing-plans` | Planner-owned authoring of execution-ready `plans/` notes | -| `dispatching-parallel-agents` | Safe parallelization with strict isolation tests and a single integrator | -| `test-driven-development` | Canonical red-green-refactor workflow for code changes | - -### Design & Domain Skills - -| Skill | Purpose | -| --- | --- | -| `frontend-design` | Distinctive, production-grade frontend UI with high design quality, accessibility, and performance | - -### Ecosystem Skills - -| Skill | Purpose | -| --- | --- | -| `docker-container-management` | Reusable Docker/compose workflow for builds, tests, and dev in containerized repos | -| `python-development` | Python ecosystem defaults: `uv` for packaging, `ruff` for lint/format, `pytest` for tests | -| `javascript-typescript-development` | JS/TS ecosystem defaults: `bun` for runtime/packaging, `biome` for lint/format | - -### Agent Skill-Loading Contract - -Agents must proactively load applicable skills when their trigger conditions are met. Do not wait to be told. - -- **`planner`**: `brainstorming` (unclear requests, design work), `writing-plans` (authoring `plans/`), `dispatching-parallel-agents` (parallel lanes), `systematic-debugging` (unresolved bugs), `test-driven-development` (specifying code tasks), `frontend-design` (frontend UI/UX implementation or redesign), `docker-container-management` (repo uses Docker), `python-development` (Python repo/lane), `javascript-typescript-development` (JS/TS repo/lane). -- **`builder`**: `dispatching-parallel-agents` (before parallel fan-out), `systematic-debugging` (bugs, regressions, flaky tests), `verification-before-completion` (before any completion claim), `test-driven-development` (before delegating or performing code changes), `frontend-design` (frontend UI/UX implementation lanes), `docker-container-management` (containerized repo), `python-development` (Python lanes), `javascript-typescript-development` (JS/TS lanes). -- **`tester`**: `systematic-debugging` (verification failure diagnosis), `verification-before-completion` (before declaring verification complete), `test-driven-development` (validating red/green cycles), `docker-container-management` (tests run in containers), `python-development` (Python verification), `javascript-typescript-development` (JS/TS verification). -- **`reviewer`**: `verification-before-completion` (evaluating completion evidence), `test-driven-development` (reviewing red/green discipline). -- **`coder`**: `test-driven-development` (all code tasks), `frontend-design` (frontend component, page, or application implementation lanes), `docker-container-management` (Dockerfiles, compose files, containerized builds), `python-development` (Python code lanes), `javascript-typescript-development` (JS/TS code lanes); other skills when the assigned lane explicitly calls for them. -- **`librarian`**: Load relevant skills opportunistically when the assigned task calls for them; do not override planner/builder workflow ownership. - -### TDD Default Policy - -Test-driven development is the default for all code changes. Agents must follow the red-green-refactor cycle unless a narrow exception applies. - -**Narrow exceptions** (agent must state why TDD was not practical and what alternative verification was used): -- Docs-only changes -- Config-only changes -- Pure refactors with provably unchanged behavior -- Repos that do not yet have a reliable automated test harness - -## Documentation Ownership - -- `librarian` owns project docs updates, `AGENTS.md` upkeep, and memory note hygiene. -- When a workflow, command, or agent contract changes, update the docs in the same task. -- Keep command names, agent roster, memory taxonomy, and skill-loading contracts synchronized across `AGENTS.md`, `agents/`, `commands/`, and `skills/`. diff --git a/.config/opencode/agents/builder.md b/.config/opencode/agents/builder.md deleted file mode 100644 index 44b7239..0000000 --- a/.config/opencode/agents/builder.md +++ /dev/null @@ -1,48 +0,0 @@ ---- -description: Execution lead that follows approved plans, delegates focused work, and integrates results without drifting from spec -mode: primary -model: github-copilot/gpt-5.4 -variant: xhigh -temperature: 0.1 -permission: - edit: allow - webfetch: allow - bash: - "*": allow - task: - "*": deny - tester: allow - coder: allow - reviewer: allow - librarian: allow - skill: - "*": allow -permalink: opencode-config/agents/builder ---- - -You are the execution authority. - -- Proactively load applicable skills when triggers are present: - - `dispatching-parallel-agents` before any parallel subagent fan-out. - - `systematic-debugging` when bugs, regressions, flaky tests, or unexpected behavior appear. - - `verification-before-completion` before completion claims or final handoff. - - `test-driven-development` before delegating or performing code changes. - - `docker-container-management` when executing tasks in a containerized repo. - - `python-development` when executing Python lanes. - - `frontend-design` when executing frontend UI/UX implementation lanes. - - `javascript-typescript-development` when executing JS/TS lanes. - -- Read the latest approved plan before making changes. -- Execute the plan exactly; do not widen scope on your own. -- Delegate code changes to `coder`, verification to `tester`, critique to `reviewer`, and docs plus `AGENTS.md` updates to `librarian`. -- Use parallel subagents when implementation lanes are isolated and can be verified independently. -- Maintain a structured execution note in basic-memory under `executions/` using the literal sections defined in `AGENTS.md`: Plan, Execution State, Lane Claims, Last Verified State, and Verification Ledger. -- Before parallel fan-out, create or update Lane Claims in the execution note. Mark each lane `active` before dispatch and `released`, `done`, or `blocked` afterward. Overlapping claimed files/areas or sequential verification dependencies forbid parallel fan-out. -- Record verification evidence in the Verification Ledger using the compact shape: Goal, Mode, Command/Check, Result, Key Evidence, Artifacts, Residual Risk. -- Default to `smoke` mode for intermediate checkpoints and isolated lane verification. Require `full` mode before any final completion claim or setting execution status to `done`. -- If you hit a contradiction, hidden dependency, or two failed verification attempts, record the root cause and evidence, then stop and send the work back to `planner`. -- Builder owns commit creation during `/build`; do not delegate commit authorship decisions to other agents. -- Create commits automatically at meaningful completed implementation checkpoints, and create a final completion commit when changes remain. -- Before creating the final completion commit, clean up temporary artifacts generated during the build (e.g., scratch files, screenshots, logs, transient reports, caches). Intended committed deliverables are not cleanup targets. -- Reuse existing git safety constraints: avoid destructive git behavior, do not force push, and do not add push automation. -- If there are no new changes at a checkpoint, skip commit creation instead of creating empty or duplicate commits. diff --git a/.config/opencode/agents/coder.md b/.config/opencode/agents/coder.md deleted file mode 100644 index a5101a5..0000000 --- a/.config/opencode/agents/coder.md +++ /dev/null @@ -1,37 +0,0 @@ ---- -description: Focused implementation subagent for tightly scoped code changes within an assigned lane -mode: subagent -model: github-copilot/gpt-5.3-codex -variant: xhigh -temperature: 0.1 -permission: - edit: allow - webfetch: allow - bash: - "*": allow -permalink: opencode-config/agents/coder ---- - -Implement only the assigned lane. - -- Proactively load `test-driven-development` for code development tasks. -- Load `docker-container-management` when the lane involves Dockerfiles, compose files, or containerized builds. -- Load `python-development` when the lane involves Python code. -- Load `frontend-design` when the lane involves frontend component, page, or application implementation. -- Load `javascript-typescript-development` when the lane involves JS/TS code. -- Load other local skills only when the assigned lane explicitly calls for them. - -- Follow the provided spec and stay inside the requested scope. -- Reuse existing project patterns before introducing new ones. -- Report notable assumptions, touched files, and any follow-up needed. -- When reporting verification evidence, use the compact verification summary shape: - - **Goal** – what is being verified - - **Mode** – `smoke` or `full` - - **Command/Check** – exact command or manual check performed - - **Result** – `pass`, `fail`, `blocked`, or `not_run` - - **Key Evidence** – concise proof (output snippet, hash, assertion count) - - **Artifacts** – paths to logs/screenshots, or `none` - - **Residual Risk** – known gaps, or `none` -- Keep raw logs out of handoff messages; summarize failures first and point to raw evidence only when needed. -- Clean up temporary artifacts from the assigned lane (e.g., scratch files, screenshots, logs, transient reports, caches) before signaling done. Intended committed deliverables are not cleanup targets. -- Do not claim work is complete without pointing to verification evidence in the compact shape above. diff --git a/.config/opencode/agents/explorer.md b/.config/opencode/agents/explorer.md deleted file mode 100644 index a6c1761..0000000 --- a/.config/opencode/agents/explorer.md +++ /dev/null @@ -1,28 +0,0 @@ ---- -description: Read-only repo inspector that reports observable facts only — never plans or recommendations -mode: subagent -model: github-copilot/claude-sonnet-4.6 -temperature: 0.0 -tools: - write: false - edit: false - bash: false -permission: - webfetch: deny -permalink: opencode-config/agents/explorer ---- - -You are a fact-gathering tool, not a planner. - -- Inspect the repository quickly and report only observable facts. -- Prefer `glob`, `grep`, `read`, structural search, and memory lookups. -- Return file paths, symbols, code relationships, and constraints. -- Do not make changes. - -Forbidden output: -- Plan drafts, task lists, or implementation steps. -- Solution design or architecture proposals. -- Speculative recommendations or subjective assessments. -- Priority rankings or suggested next actions. - -If a finding has implications for planning, state the fact and stop. Let the caller draw conclusions. diff --git a/.config/opencode/agents/librarian.md b/.config/opencode/agents/librarian.md deleted file mode 100644 index 4c3ef8e..0000000 --- a/.config/opencode/agents/librarian.md +++ /dev/null @@ -1,23 +0,0 @@ ---- -description: Documentation and memory steward for AGENTS rules, project docs, and continuity notes -mode: subagent -model: github-copilot/claude-opus-4.6 -variant: thinking -temperature: 0.2 -tools: - bash: false -permission: - edit: allow - webfetch: allow -permalink: opencode-config/agents/librarian ---- - -Own documentation quality and continuity. - -- Load relevant skills opportunistically when assigned documentation or memory tasks call for them. -- Do not override planner/builder workflow ownership. - -- Keep `AGENTS.md`, workflow docs, and command descriptions aligned with actual behavior. -- Update or create basic-memory notes when project knowledge changes. -- Prefer concise, high-signal docs that help future sessions resume quickly. -- Flag stale instructions, mismatched agent rosters, and undocumented workflow changes. diff --git a/.config/opencode/agents/planner.md b/.config/opencode/agents/planner.md deleted file mode 100644 index 504b6c3..0000000 --- a/.config/opencode/agents/planner.md +++ /dev/null @@ -1,57 +0,0 @@ ---- -description: Planning lead that gathers evidence, writes execution-ready specs, and decides when builder can proceed -mode: primary -model: github-copilot/gpt-5.4 -variant: xhigh -temperature: 0.1 -tools: - write: false - edit: false -permission: - webfetch: allow - task: - "*": deny - researcher: allow - explorer: allow - reviewer: allow - skill: - "*": allow -permalink: opencode-config/agents/planner ---- - -You are the planning authority. - -- Proactively load applicable skills when triggers are present: - - `brainstorming` for unclear requests, design work, or feature shaping. - - `writing-plans` when producing execution-ready `plans/` notes. - - `dispatching-parallel-agents` when considering parallel research or review lanes. - - `systematic-debugging` when planning around unresolved bugs or failures. - - `test-driven-development` when specifying implementation tasks that mutate code. - - `docker-container-management` when a repo uses Docker/docker-compose. - - `python-development` when a repo or lane is primarily Python. - - `frontend-design` when the task involves frontend UI/UX implementation or redesign. - - `javascript-typescript-development` when a repo or lane is primarily JS/TS. - -## Clarification and the `question` tool - -- Use the `question` tool proactively when scope, default choices, approval criteria, or critical context are ambiguous or missing. -- Prefer asking over assuming, especially for: target environments, language/tool defaults, acceptance criteria, and whether Docker is required. -- Do not hand off a plan that contains unresolved assumptions when a question could resolve them first. - -## Planning-time Docker and bash usage - -- You may run Docker commands during planning for context gathering and inspection (e.g., `docker compose config`, `docker image ls`, `docker ps`, `docker network ls`, checking container health or logs). -- You may also run other bash commands for read-only context (e.g., checking file contents, environment state, installed versions). -- Do **not** run builds, installs, tests, deployments, or any implementation-level commands — those belong to builder/tester/coder. -- If you catch yourself executing implementation steps, stop and delegate to builder. - -- Gather all high-signal context before proposing execution. -- Break work into explicit tasks, dependencies, and verification steps. -- Use subagents in parallel when research lanes are independent. -- Write or update the canonical plan in basic-memory under `plans/`. -- Mark the plan with `Status: approved` only when the task can be executed without guesswork. -- Include objective, scope, assumptions, constraints, parallel lanes, verification oracle, risks, and open findings in every approved plan. -- When parallelization or phased verification matters, define intended lanes with claimed files/areas, inter-lane dependencies, and verification intent so builder can create the structured `executions/` note without guessing. -- Specify verification mode (`smoke` for intermediate checkpoints, `full` for final completion) where the distinction affects execution. Default to the shared rules in `AGENTS.md` when not otherwise specified. -- Never make file changes or implementation edits yourself. -- If the work is under-specified, stay in planning mode and surface the missing information instead of handing off a weak plan. diff --git a/.config/opencode/agents/researcher.md b/.config/opencode/agents/researcher.md deleted file mode 100644 index f4594cf..0000000 --- a/.config/opencode/agents/researcher.md +++ /dev/null @@ -1,21 +0,0 @@ ---- -description: Research specialist for external docs, tradeoff analysis, and evidence gathering -mode: subagent -model: github-copilot/gpt-5.4 -variant: xhigh -temperature: 0.2 -tools: - write: false - edit: false - bash: false -permission: - webfetch: allow -permalink: opencode-config/agents/researcher ---- - -Focus on evidence gathering. - -- Read docs, compare options, and summarize tradeoffs. -- Prefer authoritative sources and concrete examples. -- Return concise findings with recommendations, risks, and unknowns. -- Do not edit files or invent implementation details. diff --git a/.config/opencode/agents/reviewer.md b/.config/opencode/agents/reviewer.md deleted file mode 100644 index 3e26c42..0000000 --- a/.config/opencode/agents/reviewer.md +++ /dev/null @@ -1,28 +0,0 @@ ---- -description: Critical reviewer for plans, code, test evidence, and release readiness -mode: subagent -model: github-copilot/gpt-5.4 -variant: xhigh -temperature: 0.1 -tools: - write: false - edit: false - bash: false -permission: - webfetch: allow -permalink: opencode-config/agents/reviewer ---- - -Act as a skeptical reviewer. - -- Proactively load applicable skills when triggers are present: - - `verification-before-completion` when evaluating completion readiness. - - `test-driven-development` when reviewing red/green discipline evidence. - -- Look for incorrect assumptions, missing cases, regressions, unclear specs, and weak verification. -- Reject completion claims that lack structured verification evidence in the compact shape (`Goal`, `Mode`, `Command/Check`, `Result`, `Key Evidence`, `Artifacts`, `Residual Risk`). -- Reject execution notes or handoffs that lack lane-ownership boundaries (owner, claimed files/areas, status). -- Prefer concrete findings over broad advice. -- When reviewing a plan, call out ambiguity before execution starts. -- When reviewing code or tests, provide evidence-backed issues in priority order. -- Remain read-only: report findings via response message; do not write to execution notes or modify files. diff --git a/.config/opencode/agents/tester.md b/.config/opencode/agents/tester.md deleted file mode 100644 index f0feaf4..0000000 --- a/.config/opencode/agents/tester.md +++ /dev/null @@ -1,39 +0,0 @@ ---- -description: Verification specialist for running tests, reproducing failures, and capturing evidence -mode: subagent -model: github-copilot/claude-opus-4.6 -variant: thinking -temperature: 0.0 -tools: - write: false -permission: - edit: deny - webfetch: allow - bash: - "*": allow -permalink: opencode-config/agents/tester ---- - -Own verification and failure evidence. - -- Proactively load applicable skills when triggers are present: - - `systematic-debugging` when a verification failure needs diagnosis. - - `verification-before-completion` before declaring verification complete. - - `test-driven-development` when validating red/green cycles or regression coverage. - - `docker-container-management` when tests run inside containers. - - `python-development` when verifying Python code. - - `javascript-typescript-development` when verifying JS/TS code. - -- Run the smallest reliable command that proves or disproves the expected behavior. -- Report every result using the compact verification summary shape: - - **Goal** – what is being verified - - **Mode** – `smoke` or `full` - - **Command/Check** – exact command or manual check performed - - **Result** – `pass`, `fail`, `blocked`, or `not_run` - - **Key Evidence** – concise proof (output snippet, hash, assertion count) - - **Artifacts** – paths to logs/screenshots, or `none` - - **Residual Risk** – known gaps, or `none` -- Keep raw logs out of primary context unless a check fails or the caller requests full output. Summarize the failure first, then point to raw evidence. -- Retry only when there is a concrete reason to believe the result will change. -- Flag any temporary artifacts observed during verification (e.g., scratch files, screenshots, logs, transient reports, caches) so builder or coder can clean them up before completion. -- Do not make code edits. diff --git a/.config/opencode/commands/build.md b/.config/opencode/commands/build.md deleted file mode 100644 index 485e39a..0000000 --- a/.config/opencode/commands/build.md +++ /dev/null @@ -1,21 +0,0 @@ ---- -description: Execute the latest approved plan -agent: builder -model: github-copilot/gpt-5.4 ---- - -Execute the latest approved plan for: $ARGUMENTS - -1. Read the latest matching `plans/` note with `Status: approved`. -2. Create or update `executions/` with the structured sections defined in `AGENTS.md` (Plan, Execution State, Lane Claims, Last Verified State, Verification Ledger). Set `Status: in_progress` before changing code. -3. Before parallel fan-out, populate Lane Claims with owner, status, claimed files/areas, dependencies, and exit conditions. Overlapping claimed files/areas or sequential verification dependencies forbid parallel fan-out. -4. Delegate implementation to `coder`, verification to `tester`, review to `reviewer`, and docs or memory updates to `librarian` where appropriate. -5. Builder owns commit creation during `/build`: create automatic commits at meaningful completed implementation checkpoints. -6. Reuse existing git safety rules and avoid destructive git behavior; do not add push automation. -7. If no new changes exist at a checkpoint, skip commit creation rather than creating empty or duplicate commits. -8. Record verification evidence in the Verification Ledger using the compact shape (Goal, Mode, Command/Check, Result, Key Evidence, Artifacts, Residual Risk). Default to `smoke` for intermediate checkpoints; require `full` before final completion or setting status to `done`. -9. Follow the plan exactly. If the plan is contradictory, missing a dependency, or fails verification twice, stop, capture evidence, set the execution note to blocked, and send the work back to `planner`. -10. Before creating the final completion commit, clean up temporary artifacts generated during the build (e.g., scratch files, screenshots, logs, transient reports, caches). Intended committed deliverables are not cleanup targets. -11. Finish by creating a final completion commit when changes remain, then update Last Verified State and set the execution note to `Status: done` or `Status: blocked` and summarize what changed. - -Automatic commits are required during `/build` as defined above. diff --git a/.config/opencode/commands/continue.md b/.config/opencode/commands/continue.md deleted file mode 100644 index 956278a..0000000 --- a/.config/opencode/commands/continue.md +++ /dev/null @@ -1,15 +0,0 @@ ---- -description: Resume unfinished planner or builder workflow from memory -model: github-copilot/gpt-5.4 ---- - -Continue the highest-priority unfinished work for this repository. - -1. Inspect basic-memory for incomplete work under `plans/`, `executions/`, `findings/`, and `decisions/`. -2. If the current primary agent is `planner`, resume the most relevant plan that is `Status: draft` or `Status: blocked` and drive it toward an approved spec. -3. If the current primary agent is `builder`, resume the most relevant execution note that is `Status: in_progress` or `Status: blocked`. If there is no approved plan, stop and hand the work back to `planner`. -4. When resuming a structured execution note, read Execution State and report: objective, current phase, next checkpoint, blockers, and last updated by. Check Lane Claims for active/blocked lanes and flag any claim conflicts (overlapping files/areas). -5. When the execution note is legacy or freeform (missing structured sections like Execution State or Lane Claims), degrade gracefully: read what exists, infer status from available content, and do not invent conflicts or synthesize missing sections without evidence. -6. When the execution note shows only `smoke` verification in the Last Verified State or Verification Ledger and a `full` verification step is still required before completion, surface this explicitly: report that full verification is pending and must run before the execution can be marked `done`. -7. Refresh the open findings ledger and update note statuses as you work. -8. Return the resumed slug, current status, next checkpoint, any blocker, any lane claim conflicts, and any pending full-verification requirement. diff --git a/.config/opencode/commands/init.md b/.config/opencode/commands/init.md deleted file mode 100644 index b3dc3d8..0000000 --- a/.config/opencode/commands/init.md +++ /dev/null @@ -1,15 +0,0 @@ ---- -description: Initialize or refresh project memory and AGENTS.md -agent: builder -model: github-copilot/gpt-5.4 ---- - -Initialize this repository for the planner/builder workflow. - -1. Verify that a dedicated per-repo basic-memory project exists for the current repository. If it does not, create it at `/.memory` using a short kebab-case project name. -2. Gather high-signal project context in parallel: purpose, stack, architecture, entrypoints, build/test commands, coding conventions, and major risks. -3. Write or refresh project memory notes under `project/overview`, `project/architecture`, `project/workflows`, and `project/testing`. -4. Use `librarian` to create or update the project-root `AGENTS.md` so it matches the repository and documents the important working agreements. -5. Record any missing information or open findings under `findings/` instead of guessing. - -Keep the output concise and actionable. diff --git a/.config/opencode/commands/plan.md b/.config/opencode/commands/plan.md deleted file mode 100644 index ffb6815..0000000 --- a/.config/opencode/commands/plan.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -description: Produce or refresh an execution-ready plan -agent: planner -model: github-copilot/gpt-5.4 ---- - -Create or update an execution-ready plan for: $ARGUMENTS - -1. Gather the required repo and external context in parallel. -2. Use `researcher`, `explorer`, and `reviewer` as needed. -3. Write the canonical plan to basic-memory under `plans/`. -4. Include: objective, scope, assumptions, constraints, task breakdown, parallel lanes, verification oracle, risks, and open findings. -5. When parallelization or phased verification matters, define intended lanes with claimed files/areas, inter-lane dependencies, and verification intent (including `smoke` vs `full` mode where the distinction affects execution). -6. Ensure the plan gives builder enough information to create the structured `executions/` note without guessing lane ownership, claimed areas, or verification expectations. -7. Set `Status: approved` only when `builder` can execute the plan without guesswork. Otherwise leave it blocked and explain why. - -Return the plan slug and the key execution checkpoints. diff --git a/.config/opencode/dcp.jsonc b/.config/opencode/dcp.jsonc deleted file mode 100644 index 5f0e5c0..0000000 --- a/.config/opencode/dcp.jsonc +++ /dev/null @@ -1,41 +0,0 @@ -{ - "$schema": "https://raw.githubusercontent.com/Opencode-DCP/opencode-dynamic-context-pruning/master/dcp.schema.json", - "enabled": true, - "debug": false, - "pruneNotification": "detailed", - "pruneNotificationType": "chat", - "commands": { - "enabled": true, - "protectedTools": [] - }, - "experimental": { - "allowSubAgents": true - }, - "manualMode": { - "enabled": false, - "automaticStrategies": true - }, - "turnProtection": { - "enabled": false, - "turns": 4 - }, - "protectedFilePatterns": [], - "strategies": { - "deduplication": { - "enabled": true, - "protectedTools": [] - }, - "supersedeWrites": { - "enabled": true - }, - "purgeErrors": { - "enabled": true, - "turns": 4, - "protectedTools": [] - } - }, - "compress": { - "maxContextLimit": "80%", - "minContextLimit": "50%" - } -} diff --git a/.config/opencode/opencode.jsonc b/.config/opencode/opencode.jsonc deleted file mode 100644 index baf7fdf..0000000 --- a/.config/opencode/opencode.jsonc +++ /dev/null @@ -1,68 +0,0 @@ -{ - "$schema": "https://opencode.ai/config.json", - "autoupdate": true, - "model": "github-copilot/gpt-5.4", - "small_model": "github-copilot/gpt-5-mini", - "default_agent": "planner", - "enabled_providers": ["github-copilot"], - "plugin": ["@tarquinen/opencode-dcp", "./plugins/tmux-panes.ts"], - "agent": { - "build": { - "disable": true - }, - "general": { - "disable": true - }, - "explore": { - "disable": true - }, - "plan": { - "disable": true - } - }, - "permission": { - "doom_loop": "allow", - "websearch": "allow", - "question": "allow", - "bash": "allow", - "external_directory": "deny" - }, - "mcp": { - "context7": { - "type": "remote", - "url": "https://mcp.context7.com/mcp", - "enabled": true - }, - "gh_grep": { - "type": "remote", - "url": "https://mcp.grep.app", - "enabled": true - }, - "playwright": { - "type": "local", - "command": [ - "bunx", - "@playwright/mcp@latest", - "--headless", - "--browser", - "chromium" - ], - "enabled": true - }, - "basic-memory": { - "type": "local", - "command": ["uvx", "basic-memory", "mcp"], - "enabled": true - }, - "ast-grep": { - "type": "local", - "command": [ - "uvx", - "--from", - "git+https://github.com/ast-grep/ast-grep-mcp", - "ast-grep-server" - ], - "enabled": true - } - } -} diff --git a/.config/opencode/package-lock.json b/.config/opencode/package-lock.json deleted file mode 100644 index d927a76..0000000 --- a/.config/opencode/package-lock.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "name": "opencode", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "dependencies": { - "@opencode-ai/plugin": "1.2.15" - } - }, - "node_modules/@opencode-ai/plugin": { - "version": "1.2.15", - "license": "MIT", - "dependencies": { - "@opencode-ai/sdk": "1.2.15", - "zod": "4.1.8" - } - }, - "node_modules/@opencode-ai/sdk": { - "version": "1.2.15", - "license": "MIT" - }, - "node_modules/zod": { - "version": "4.1.8", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/colinhacks" - } - } - } -} diff --git a/.config/opencode/plugins/tmux-panes.ts b/.config/opencode/plugins/tmux-panes.ts deleted file mode 100644 index 5d9d367..0000000 --- a/.config/opencode/plugins/tmux-panes.ts +++ /dev/null @@ -1,191 +0,0 @@ -import type { Plugin } from "@opencode-ai/plugin" -import { spawn } from "bun" - -/** - * tmux-panes plugin - * - * When opencode spawns a background subagent, this plugin automatically opens - * a new tmux pane showing that subagent's live TUI via `opencode attach`. - * - * Layout: - * - First subagent: horizontal 60/40 split — main pane on left, subagent on right - * - Additional subagents: stacked vertically in the right column - * - Panes close automatically when subagent sessions end - * - * Only activates when running inside a tmux session (TMUX env var is set). - */ - -const isInsideTmux = () => Boolean(process.env.TMUX) -const getCurrentPaneId = () => process.env.TMUX_PANE - -const runTmux = async (args: string[]) => { - const proc = spawn(["tmux", ...args], { stdout: "pipe", stderr: "pipe" }) - const stdout = await new Response(proc.stdout).text() - const stderr = await new Response(proc.stderr).text() - const exitCode = await proc.exited - - return { - exitCode, - stdout: stdout.trim(), - stderr: stderr.trim(), - } -} - -const removeItem = (items: string[], value: string) => { - const idx = items.indexOf(value) - if (idx !== -1) items.splice(idx, 1) -} - -const plugin: Plugin = async (ctx) => { - if (!isInsideTmux()) return {} - - const sessions = new Map() // sessionId → tmux paneId - const sourcePaneId = getCurrentPaneId() - const serverUrl = (ctx.serverUrl?.toString() ?? "").replace(/\/$/, "") - - // Ordered list of pane IDs in the right column. - // Empty = no right column yet; length > 0 = right column exists. - const rightColumnPanes: string[] = [] - let paneOps = Promise.resolve() - - const getWindowInfo = async () => { - const targetPane = sourcePaneId ?? rightColumnPanes[0] - if (!targetPane) return null - - const result = await runTmux([ - "display-message", - "-p", - "-t", - targetPane, - "#{window_id} #{window_width}", - ]) - - if (result.exitCode !== 0 || !result.stdout) return null - - const [windowId, widthText] = result.stdout.split(/\s+/, 2) - const width = Number(widthText) - if (!windowId || Number.isNaN(width)) return null - - return { windowId, width } - } - - const applyLayout = async () => { - if (rightColumnPanes.length === 0) return - - const windowInfo = await getWindowInfo() - if (!windowInfo) return - - const mainWidth = Math.max(1, Math.round(windowInfo.width * 0.6)) - - await runTmux([ - "set-window-option", - "-t", - windowInfo.windowId, - "main-pane-width", - String(mainWidth), - ]) - await runTmux(["select-layout", "-t", sourcePaneId ?? rightColumnPanes[0], "main-vertical"]) - } - - const closeSessionPane = async (sessionId: string) => { - const paneId = sessions.get(sessionId) - if (!paneId) return - - await runTmux(["kill-pane", "-t", paneId]) - sessions.delete(sessionId) - removeItem(rightColumnPanes, paneId) - await applyLayout() - } - - const enqueuePaneOp = (operation: () => Promise) => { - paneOps = paneOps.then(operation).catch(() => {}) - return paneOps - } - - const isTerminalSessionUpdate = (info: any) => - Boolean(info?.time?.archived || info?.time?.compacting) - - return { - event: async ({ event }) => { - // Spawn a new pane when a subagent session is created - if (event.type === "session.created") { - const info = (event as any).properties?.info - // parentID presence distinguishes subagents from the root session - if (!info?.id || !info?.parentID) return - const sessionId: string = info.id - if (sessions.has(sessionId)) return - - await enqueuePaneOp(async () => { - if (sessions.has(sessionId)) return - - const cmd = `opencode attach ${serverUrl} --session ${sessionId}` - let args: string[] - - if (rightColumnPanes.length === 0) { - const windowInfo = await getWindowInfo() - const rightWidth = windowInfo - ? Math.max(1, Math.round(windowInfo.width * 0.4)) - : 40 - - args = [ - "split-window", - "-h", - "-l", - String(rightWidth), - "-d", - "-P", - "-F", - "#{pane_id}", - ...(sourcePaneId ? ["-t", sourcePaneId] : []), - cmd, - ] - } else { - const lastRightPane = rightColumnPanes[rightColumnPanes.length - 1] - args = [ - "split-window", - "-v", - "-d", - "-P", - "-F", - "#{pane_id}", - "-t", - lastRightPane, - cmd, - ] - } - - const result = await runTmux(args) - const paneId = result.stdout - - if (result.exitCode === 0 && paneId) { - sessions.set(sessionId, paneId) - rightColumnPanes.push(paneId) - await applyLayout() - } - }) - } - - // Kill the pane when the subagent session ends - if (event.type === "session.deleted") { - const info = (event as any).properties?.info - if (!info?.id) return - await enqueuePaneOp(() => closeSessionPane(info.id)) - } - - if (event.type === "session.updated") { - const info = (event as any).properties?.info - if (!info?.id || !sessions.has(info.id) || !isTerminalSessionUpdate(info)) return - await enqueuePaneOp(() => closeSessionPane(info.id)) - } - - if (event.type === "session.status") { - const sessionID = (event as any).properties?.sessionID - const statusType = (event as any).properties?.status?.type - if (!sessionID || !sessions.has(sessionID) || statusType !== "idle") return - await enqueuePaneOp(() => closeSessionPane(sessionID)) - } - }, - } -} - -export default plugin diff --git a/.config/opencode/skills/brainstorming/SKILL.md b/.config/opencode/skills/brainstorming/SKILL.md deleted file mode 100644 index 85c1f2b..0000000 --- a/.config/opencode/skills/brainstorming/SKILL.md +++ /dev/null @@ -1,29 +0,0 @@ ---- -name: brainstorming -description: Planner-led discovery workflow for clarifying problem shape, options, and decision-ready direction -permalink: opencode-config/skills/brainstorming/skill ---- - -# Brainstorming - -Use this skill when requests are unclear, options are broad, or design tradeoffs are unresolved. - -## Workflow - -1. Clarify objective, constraints, and non-goals. -2. Generate multiple viable approaches (not one-path thinking). -3. Compare options by risk, complexity, verification cost, and reversibility. -4. Identify unknowns that need research before execution. -5. Converge on a recommended direction with explicit rationale. - -## Planner Ownership - -- Keep brainstorming in planning mode; do not start implementation. -- Use subagents for independent research lanes when needed. -- Translate outcomes into memory-backed planning artifacts (`plans/`, findings/risks). - -## Output - -- Short options table (approach, pros, cons, risks). -- Recommended path and why. -- Open questions that block approval. diff --git a/.config/opencode/skills/creating-agents/SKILL.md b/.config/opencode/skills/creating-agents/SKILL.md deleted file mode 100644 index 20ef35c..0000000 --- a/.config/opencode/skills/creating-agents/SKILL.md +++ /dev/null @@ -1,73 +0,0 @@ ---- -name: creating-agents -description: Create or update opencode agents in this repository, including dispatch permissions and roster alignment requirements -permalink: opencode-config/skills/creating-agents/skill ---- - -# Creating Agents - -Use this skill when you need to add or revise an agent definition in this repo. - -## Agents vs Skills - -- **Agents** define runtime behavior and permissions in `agents/*.md`. -- **Skills** are reusable instruction modules under `skills/*/SKILL.md`. -- Do not treat agent creation as skill creation; each has different files, checks, and ownership. - -## Source of Truth - -1. Agent definition file: `agents/.md` -2. Operating roster and workflow contract: `AGENTS.md` -3. Runtime overrides and provider policy: `opencode.jsonc` -4. Workflow entrypoints: `commands/*.md` - -Notes: - -- This repo uses two primary agents: `planner` and `builder`. -- Dispatch permissions live in the primary agent that owns the subagent, not in a central dispatcher. -- `planner` may dispatch only `researcher`, `explorer`, and `reviewer`. -- `builder` may dispatch only `coder`, `tester`, `reviewer`, and `librarian`. - -## Agent File Conventions - -For `agents/.md`: - -- Use frontmatter first, then concise role instructions. -- Keep tone imperative and operational. -- Define an explicit `model` for every agent and keep it on a GitHub Copilot model. -- Use only explicit `allow` or `deny` permissions; do not use `ask`. -- Include only the tools and permissions needed for the role. -- Keep instructions aligned with the planner -> builder contract in `AGENTS.md`. - -Typical frontmatter fields in this repo include: - -- `description` -- `mode` -- `model` -- `temperature` -- `steps` -- `tools` -- `permission` -- `permalink` - -Mirror nearby agent files instead of inventing new metadata patterns. - -## Practical Workflow (Create or Update) - -1. Inspect the relevant primary agent file and at least one comparable peer in `agents/*.md`. -2. Create or edit `agents/.md` with matching local structure. -3. If the agent is a subagent, update the owning primary agent's `permission.task` allowlist. -4. Update `AGENTS.md` so the roster, responsibilities, and workflow rules stay synchronized. -5. Review `commands/*.md` if the new agent changes how `/init`, `/plan`, `/build`, or `/continue` should behave. -6. Review `opencode.jsonc` for conflicting overrides, disable flags, or provider drift. - -## Manual Verification Checklist (No Validation Script) - -Run this checklist before claiming completion: - -- [ ] `agents/.md` exists and frontmatter is valid and consistent with peers. -- [ ] Agent instructions clearly define role, scope, escalation rules, and constraints. -- [ ] The owning primary agent includes the correct `permission.task` rule for the subagent. -- [ ] `AGENTS.md` roster row exists and matches the agent name, role, and model. -- [ ] `commands/*.md` and `opencode.jsonc` still reflect the intended workflow. -- [ ] Terminology stays consistent: agents in `agents/*.md`, skills in `skills/*/SKILL.md`. diff --git a/.config/opencode/skills/creating-skills/SKILL.md b/.config/opencode/skills/creating-skills/SKILL.md deleted file mode 100644 index 1eb771b..0000000 --- a/.config/opencode/skills/creating-skills/SKILL.md +++ /dev/null @@ -1,84 +0,0 @@ ---- -name: creating-skills -description: Create or update opencode skills in this repository using the required SKILL.md format and concise, trigger-focused guidance -permalink: opencode-config/skills/creating-skills/skill ---- - -# Creating Skills - -Use this skill when you need to add or revise an opencode skill under `skills/`. - -## Skills vs OpenAI/Codex Source Model - -- Treat this repo as **opencode-native**. -- Do **not** use OpenAI/Codex-specific artifacts such as `agents/openai.yaml`, `init_skill.py`, `quick_validate.py`, or `scripts/references/assets` conventions from the old source model. -- A skill is discovered from `skills/*/SKILL.md` only. - -## Required Structure - -1. Create a folder at `skills//`. -2. Add `skills//SKILL.md`. -3. Keep `` equal to frontmatter `name`. - -Frontmatter must contain only: - -```yaml ---- -name: -description: -permalink: opencode-config/skills//skill ---- -``` - -## Naming Rules - -- Use lowercase kebab-case. -- Keep names short and action-oriented. -- Match folder name and `name` exactly. - -## Body Writing Rules - -- Write concise, imperative instructions. -- Lead with when to load and the core workflow. -- Prefer short checklists over long prose. -- Include only repo-relevant guidance. -- Keep the planner/builder operating model in mind when a skill touches workflow behavior. - -## Companion Notes (`*.md` in skill folder) - -Add companion markdown files only when detail would bloat `SKILL.md` (examples, deep procedures, edge-case references). - -- Keep `SKILL.md` as the operational entrypoint. -- Link companion files directly from `SKILL.md` with clear “when to read” guidance. -- Do not create extra docs by default. - -## Practical Workflow (Create or Update) - -1. Inspect 2–3 nearby skills for local style and brevity. -2. Pick/update `` and folder path under `skills/`. -3. Write or revise `SKILL.md` frontmatter (`name`, `description`, `permalink` only). -4. Draft concise body sections: purpose, load conditions, workflow, red flags/checks. -5. Add minimal companion `.md` files only if needed; link them from `SKILL.md`. -6. Verify discovery path and naming consistency: - - file exists at `skills//SKILL.md` - - folder name == frontmatter `name` - - no OpenAI/Codex-only artifacts introduced -7. If the skill changes agent workflow or command behavior: - - Update the **Skills** table, **Agent Skill-Loading Contract**, and **TDD Default Policy** in `AGENTS.md`. - - Confirm `commands/*.md` and any affected `agents/*.md` prompts stay aligned. - - If the skill involves parallelization, verify it enforces safe-parallelization rules (no parallel mutation on shared files, APIs, schemas, or verification steps). - - If the skill involves code changes, verify it references the TDD default policy and its narrow exceptions. - -## Language/Ecosystem Skill Pattern - -When adding a new language or ecosystem skill (e.g., `rust-development`, `go-development`), follow this template: - -1. **Name**: `-development` (kebab-case). -2. **Load trigger**: presence of the language's project file(s) or source files as primary source. -3. **Defaults table**: one row per concern — package manager, linter/formatter, test runner, type checker (if applicable). -4. **Core workflow**: numbered steps for bootstrap, lint, format, test, add-deps, and any lock/check step. -5. **Conventions**: 3–5 bullets on config file preferences, execution patterns, and version pinning. -6. **Docker integration**: one paragraph on base image and cache strategy. -7. **Red flags**: 3–5 bullets on common anti-patterns. -8. **AGENTS.md updates**: add the skill to the **Ecosystem Skills** table and add load triggers for `planner`, `builder`, `coder`, and `tester` in the **Agent Skill-Loading Contract**. -9. **Agent prompt updates**: add the skill trigger to `agents/planner.md`, `agents/builder.md`, `agents/coder.md`, and `agents/tester.md`. diff --git a/.config/opencode/skills/dispatching-parallel-agents/SKILL.md b/.config/opencode/skills/dispatching-parallel-agents/SKILL.md deleted file mode 100644 index f7e798a..0000000 --- a/.config/opencode/skills/dispatching-parallel-agents/SKILL.md +++ /dev/null @@ -1,41 +0,0 @@ ---- -name: dispatching-parallel-agents -description: Safely parallelize independent lanes with isolation checks, explicit ownership, and single-agent integration -permalink: opencode-config/skills/dispatching-parallel-agents/skill ---- - -# Dispatching Parallel Agents - -Use this skill before parallel fan-out. - -## Isolation Test (Required) - -Before fan-out, verify that no two lanes share: - -- **Claimed Files/Areas** under active mutation (paths or named workflow surfaces from the lane-claim entries) -- APIs or schemas being changed -- **Sequential verification dependencies** (verification steps that must run in order across lanes) - -Overlapping claimed files/areas or sequential verification dependencies **forbid** parallel fan-out. Run those lanes sequentially. - -## Workflow - -1. **Builder creates lane-claim entries** in the execution note before fan-out, recording for each lane: `Owner`, `Status` (→ `active`), `Claimed Files/Areas`, `Depends On`, and `Exit Condition`. -2. Run the isolation test above against the claimed files/areas and dependencies. Abort fan-out on any overlap. -3. Define lane scope, inputs, and outputs for each subagent. -4. Assign a single integrator (usually builder) for merge and final validation. -5. Each lane must return **compact verification evidence** in the shared shape (`Goal`, `Mode`, `Command/Check`, `Result`, `Key Evidence`, `Artifacts`, `Residual Risk`) — not just code output. -6. Integrate in dependency order; update lane statuses to `released` or `done`. -7. Run final end-to-end verification (`full` mode) after integration. - -## Planner/Builder Expectations - -- **Planner**: define intended lanes and claimed files/areas in the approved plan when parallelization is expected. -- **Builder**: load this skill before fan-out, create or update lane-claim entries in the execution note, mark them `active`/`released`/`done`/`blocked`, and enforce lane boundaries strictly. -- Claims are advisory markdown metadata, not hard runtime locks. Do not invent lockfiles or runtime enforcement. - -## Red Flags - -- Two lanes editing the same contract. -- Shared test fixtures causing non-deterministic outcomes. -- Missing integrator ownership. diff --git a/.config/opencode/skills/docker-container-management/SKILL.md b/.config/opencode/skills/docker-container-management/SKILL.md deleted file mode 100644 index a15b8da..0000000 --- a/.config/opencode/skills/docker-container-management/SKILL.md +++ /dev/null @@ -1,37 +0,0 @@ ---- -name: docker-container-management -description: Reusable Docker container workflow for build, test, and dev tasks in containerized repos -permalink: opencode-config/skills/docker-container-management/skill ---- - -# Docker Container Management - -Load this skill when a repo uses Docker/docker-compose for builds, tests, or local dev, or when a task involves containerized workflows. - -## Core Workflow - -1. **Detect** — look for `Dockerfile`, `docker-compose.yml`/`compose.yml`, or `.devcontainer/` in the repo root. -2. **Prefer compose** — use `docker compose` (v2 CLI) over raw `docker run` when a compose file exists. -3. **Ephemeral containers** — default to `--rm` for one-off commands. Avoid leaving stopped containers behind. -4. **Named volumes over bind-mounts** for caches (e.g., package manager caches). Use bind-mounts only for source code. -5. **No host-path writes outside the repo** — all volume mounts must target paths inside the repo root or named volumes. This preserves `external_directory: deny`. - -## Path and Volume Constraints - -- Mount the repo root as the container workdir: `-v "$(pwd):/app" -w /app`. -- Never mount host paths outside the repository (e.g., `~/.ssh`, `/var/run/docker.sock`) unless the plan explicitly approves it with a stated reason. -- If root-owned artifacts appear after container runs, document cleanup steps (see `main/knowledge/worktree-cleanup-after-docker-owned-artifacts`). - -## Agent Guidance - -- **planner**: Use Docker during planning for context gathering and inspection (e.g., `docker compose config`, `docker ps`, `docker image ls`, `docker network ls`, checking container health or logs). Do not run builds, installs, tests, deployments, or any implementation-level commands — those belong to builder/tester/coder. -- **builder/coder**: Run builds and install steps inside containers. Prefer `docker compose run --rm ` for one-off tasks. -- **tester**: Run test suites inside the same container environment used by CI. Capture container exit codes as verification evidence. -- **coder**: When writing Dockerfiles or compose files, keep layers minimal, pin base image tags, and use multi-stage builds when the final image ships. - -## Red Flags - -- `docker run` without `--rm` in automation scripts. -- Bind-mounting sensitive host paths (`/etc`, `~/.config`, `/var/run/docker.sock`). -- Building images without a `.dockerignore`. -- Using `latest` tag for base images in production Dockerfiles. diff --git a/.config/opencode/skills/frontend-design/SKILL.md b/.config/opencode/skills/frontend-design/SKILL.md deleted file mode 100644 index 5cf4ee4..0000000 --- a/.config/opencode/skills/frontend-design/SKILL.md +++ /dev/null @@ -1,48 +0,0 @@ ---- -name: frontend-design -description: Create distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics. -permalink: opencode-config/skills/frontend-design/skill ---- - -# Frontend Design - -## When to Load - -Load this skill when the task involves building, redesigning, or significantly styling a frontend component, page, or application. Triggers include: user requests for UI/UX implementation, wireframe-to-code work, visual redesigns, and new web interfaces. - -## Design Thinking Checklist - -Before writing code, answer these: - -1. **Purpose** — What problem does this interface solve? Who is the audience? -2. **Brand / product context** — Does the project have existing design tokens, a style guide, or brand constraints? Follow them first; extend only where gaps exist. -3. **Aesthetic direction** — Commit to a clear direction (e.g., brutally minimal, maximalist, retro-futuristic, editorial, organic, luxury, playful, industrial). Intentionality matters more than intensity. -4. **Differentiation** — Identify the single most memorable element of the design. -5. **Constraints** — Note framework requirements, performance budgets, and accessibility targets (WCAG AA minimum). - -## Implementation Checklist - -- [ ] Produce production-grade, functional code (HTML/CSS/JS, React, Vue, etc.) -- [ ] Ensure the result is visually cohesive with a clear aesthetic point of view -- [ ] Respect accessibility: semantic HTML, sufficient contrast, keyboard navigation, focus management -- [ ] Respect performance: avoid heavy unoptimized assets; prefer CSS-only solutions for animation where practical -- [ ] Use CSS variables for color/theme consistency -- [ ] Match implementation complexity to the aesthetic vision — maximalist designs need elaborate effects; minimal designs need precision and restraint - -## Aesthetic Guidance - -- **Typography** — Choose distinctive, characterful fonts. Pair a display font with a refined body font. Avoid defaulting to the same choices across projects; vary intentionally. -- **Color & Theme** — Dominant colors with sharp accents outperform timid, evenly-distributed palettes. Vary between light and dark themes across projects. -- **Motion** — Prioritize high-impact moments: a well-orchestrated page load with staggered reveals creates more delight than scattered micro-interactions. Use CSS animations where possible; use a motion library (e.g., Motion) for complex sequences. Include scroll-triggered and hover effects when they serve the design. -- **Spatial Composition** — Explore asymmetry, overlap, diagonal flow, grid-breaking elements, generous negative space, or controlled density. -- **Backgrounds & Atmosphere** — Build depth with gradient meshes, noise textures, geometric patterns, layered transparencies, shadows, grain overlays, or other contextual effects rather than defaulting to flat solid colors. - -Avoid converging on the same fonts, color schemes, or layout patterns across generations. Each design should feel context-specific and intentional. - -## TDD & Verification - -Frontend code changes follow the project's TDD default policy. When the skill is loaded alongside `test-driven-development`: - -- Write or update component/visual tests before implementation when a test harness exists. -- If no frontend test harness is available, state the exception and describe alternative verification (e.g., manual browser check, screenshot comparison). -- Satisfy `verification-before-completion` requirements before claiming the work is done. diff --git a/.config/opencode/skills/javascript-typescript-development/SKILL.md b/.config/opencode/skills/javascript-typescript-development/SKILL.md deleted file mode 100644 index f29baf3..0000000 --- a/.config/opencode/skills/javascript-typescript-development/SKILL.md +++ /dev/null @@ -1,45 +0,0 @@ ---- -name: javascript-typescript-development -description: JS/TS ecosystem defaults and workflows using bun for runtime/packaging and biome for linting/formatting -permalink: opencode-config/skills/javascript-typescript-development/skill ---- - -# JavaScript / TypeScript Development - -Load this skill when a repo or lane involves JS/TS code (presence of `package.json`, `tsconfig.json`, or `.ts`/`.tsx`/`.js`/`.jsx` files as primary source). - -## Defaults - -| Concern | Tool | Notes | -| --- | --- | --- | -| Runtime + package manager | `bun` | Replaces node+npm/yarn/pnpm for most tasks | -| Linting + formatting | `biome` | Replaces eslint+prettier | -| Test runner | `bun test` | Built-in; use vitest/jest only if repo already configures them | -| Type checking | `tsc --noEmit` | Always run before completion claims | - -## Core Workflow - -1. **Bootstrap** — `bun install` to install dependencies. -2. **Lint** — `bunx biome check .` before committing. -3. **Format** — `bunx biome format . --write` (or `--check` in CI). -4. **Test** — `bun test` with the repo's existing config. Follow TDD default policy. -5. **Add dependencies** — `bun add ` (runtime) or `bun add -D ` (dev). -6. **Type check** — `bunx tsc --noEmit` for TS repos. - -## Conventions - -- Prefer `biome.json` for lint/format config. Do not add `.eslintrc` or `.prettierrc` unless the repo already uses them. -- Use `bun run '; + +// ========== Helper Functions ========== + +function isFullDocument(html) { + const trimmed = html.trimStart().toLowerCase(); + return trimmed.startsWith('', content); +} + +function getNewestScreen() { + const files = fs.readdirSync(CONTENT_DIR) + .filter(f => f.endsWith('.html')) + .map(f => { + const fp = path.join(CONTENT_DIR, f); + return { path: fp, mtime: fs.statSync(fp).mtime.getTime() }; + }) + .sort((a, b) => b.mtime - a.mtime); + return files.length > 0 ? files[0].path : null; +} + +// ========== HTTP Request Handler ========== + +function handleRequest(req, res) { + touchActivity(); + if (req.method === 'GET' && req.url === '/') { + const screenFile = getNewestScreen(); + let html = screenFile + ? (raw => isFullDocument(raw) ? raw : wrapInFrame(raw))(fs.readFileSync(screenFile, 'utf-8')) + : WAITING_PAGE; + + if (html.includes('')) { + html = html.replace('', helperInjection + '\n'); + } else { + html += helperInjection; + } + + res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' }); + res.end(html); + } else if (req.method === 'GET' && req.url.startsWith('/files/')) { + const fileName = req.url.slice(7); + const filePath = path.join(CONTENT_DIR, path.basename(fileName)); + if (!fs.existsSync(filePath)) { + res.writeHead(404); + res.end('Not found'); + return; + } + const ext = path.extname(filePath).toLowerCase(); + const contentType = MIME_TYPES[ext] || 'application/octet-stream'; + res.writeHead(200, { 'Content-Type': contentType }); + res.end(fs.readFileSync(filePath)); + } else { + res.writeHead(404); + res.end('Not found'); + } +} + +// ========== WebSocket Connection Handling ========== + +const clients = new Set(); + +function handleUpgrade(req, socket) { + const key = req.headers['sec-websocket-key']; + if (!key) { socket.destroy(); return; } + + const accept = computeAcceptKey(key); + socket.write( + 'HTTP/1.1 101 Switching Protocols\r\n' + + 'Upgrade: websocket\r\n' + + 'Connection: Upgrade\r\n' + + 'Sec-WebSocket-Accept: ' + accept + '\r\n\r\n' + ); + + let buffer = Buffer.alloc(0); + clients.add(socket); + + socket.on('data', (chunk) => { + buffer = Buffer.concat([buffer, chunk]); + while (buffer.length > 0) { + let result; + try { + result = decodeFrame(buffer); + } catch (e) { + socket.end(encodeFrame(OPCODES.CLOSE, Buffer.alloc(0))); + clients.delete(socket); + return; + } + if (!result) break; + buffer = buffer.slice(result.bytesConsumed); + + switch (result.opcode) { + case OPCODES.TEXT: + handleMessage(result.payload.toString()); + break; + case OPCODES.CLOSE: + socket.end(encodeFrame(OPCODES.CLOSE, Buffer.alloc(0))); + clients.delete(socket); + return; + case OPCODES.PING: + socket.write(encodeFrame(OPCODES.PONG, result.payload)); + break; + case OPCODES.PONG: + break; + default: { + const closeBuf = Buffer.alloc(2); + closeBuf.writeUInt16BE(1003); + socket.end(encodeFrame(OPCODES.CLOSE, closeBuf)); + clients.delete(socket); + return; + } + } + } + }); + + socket.on('close', () => clients.delete(socket)); + socket.on('error', () => clients.delete(socket)); +} + +function handleMessage(text) { + let event; + try { + event = JSON.parse(text); + } catch (e) { + console.error('Failed to parse WebSocket message:', e.message); + return; + } + touchActivity(); + console.log(JSON.stringify({ source: 'user-event', ...event })); + if (event.choice) { + const eventsFile = path.join(STATE_DIR, 'events'); + fs.appendFileSync(eventsFile, JSON.stringify(event) + '\n'); + } +} + +function broadcast(msg) { + const frame = encodeFrame(OPCODES.TEXT, Buffer.from(JSON.stringify(msg))); + for (const socket of clients) { + try { socket.write(frame); } catch (e) { clients.delete(socket); } + } +} + +// ========== Activity Tracking ========== + +const IDLE_TIMEOUT_MS = 30 * 60 * 1000; // 30 minutes +let lastActivity = Date.now(); + +function touchActivity() { + lastActivity = Date.now(); +} + +// ========== File Watching ========== + +const debounceTimers = new Map(); + +// ========== Server Startup ========== + +function startServer() { + if (!fs.existsSync(CONTENT_DIR)) fs.mkdirSync(CONTENT_DIR, { recursive: true }); + if (!fs.existsSync(STATE_DIR)) fs.mkdirSync(STATE_DIR, { recursive: true }); + + // Track known files to distinguish new screens from updates. + // macOS fs.watch reports 'rename' for both new files and overwrites, + // so we can't rely on eventType alone. + const knownFiles = new Set( + fs.readdirSync(CONTENT_DIR).filter(f => f.endsWith('.html')) + ); + + const server = http.createServer(handleRequest); + server.on('upgrade', handleUpgrade); + + const watcher = fs.watch(CONTENT_DIR, (eventType, filename) => { + if (!filename || !filename.endsWith('.html')) return; + + if (debounceTimers.has(filename)) clearTimeout(debounceTimers.get(filename)); + debounceTimers.set(filename, setTimeout(() => { + debounceTimers.delete(filename); + const filePath = path.join(CONTENT_DIR, filename); + + if (!fs.existsSync(filePath)) return; // file was deleted + touchActivity(); + + if (!knownFiles.has(filename)) { + knownFiles.add(filename); + const eventsFile = path.join(STATE_DIR, 'events'); + if (fs.existsSync(eventsFile)) fs.unlinkSync(eventsFile); + console.log(JSON.stringify({ type: 'screen-added', file: filePath })); + } else { + console.log(JSON.stringify({ type: 'screen-updated', file: filePath })); + } + + broadcast({ type: 'reload' }); + }, 100)); + }); + watcher.on('error', (err) => console.error('fs.watch error:', err.message)); + + function shutdown(reason) { + console.log(JSON.stringify({ type: 'server-stopped', reason })); + const infoFile = path.join(STATE_DIR, 'server-info'); + if (fs.existsSync(infoFile)) fs.unlinkSync(infoFile); + fs.writeFileSync( + path.join(STATE_DIR, 'server-stopped'), + JSON.stringify({ reason, timestamp: Date.now() }) + '\n' + ); + watcher.close(); + clearInterval(lifecycleCheck); + server.close(() => process.exit(0)); + } + + function ownerAlive() { + if (!ownerPid) return true; + try { process.kill(ownerPid, 0); return true; } catch (e) { return e.code === 'EPERM'; } + } + + // Check every 60s: exit if owner process died or idle for 30 minutes + const lifecycleCheck = setInterval(() => { + if (!ownerAlive()) shutdown('owner process exited'); + else if (Date.now() - lastActivity > IDLE_TIMEOUT_MS) shutdown('idle timeout'); + }, 60 * 1000); + lifecycleCheck.unref(); + + // Validate owner PID at startup. If it's already dead, the PID resolution + // was wrong (common on WSL, Tailscale SSH, and cross-user scenarios). + // Disable monitoring and rely on the idle timeout instead. + if (ownerPid) { + try { process.kill(ownerPid, 0); } + catch (e) { + if (e.code !== 'EPERM') { + console.log(JSON.stringify({ type: 'owner-pid-invalid', pid: ownerPid, reason: 'dead at startup' })); + ownerPid = null; + } + } + } + + server.listen(PORT, HOST, () => { + const info = JSON.stringify({ + type: 'server-started', port: Number(PORT), host: HOST, + url_host: URL_HOST, url: 'http://' + URL_HOST + ':' + PORT, + screen_dir: CONTENT_DIR, state_dir: STATE_DIR + }); + console.log(info); + fs.writeFileSync(path.join(STATE_DIR, 'server-info'), info + '\n'); + }); +} + +if (require.main === module) { + startServer(); +} + +module.exports = { computeAcceptKey, encodeFrame, decodeFrame, OPCODES }; diff --git a/.pi/agent/skills/superpowers/brainstorming/scripts/start-server.sh b/.pi/agent/skills/superpowers/brainstorming/scripts/start-server.sh new file mode 100755 index 0000000..9ef6dcb --- /dev/null +++ b/.pi/agent/skills/superpowers/brainstorming/scripts/start-server.sh @@ -0,0 +1,148 @@ +#!/usr/bin/env bash +# Start the brainstorm server and output connection info +# Usage: start-server.sh [--project-dir ] [--host ] [--url-host ] [--foreground] [--background] +# +# Starts server on a random high port, outputs JSON with URL. +# Each session gets its own directory to avoid conflicts. +# +# Options: +# --project-dir Store session files under /.superpowers/brainstorm/ +# instead of /tmp. Files persist after server stops. +# --host Host/interface to bind (default: 127.0.0.1). +# Use 0.0.0.0 in remote/containerized environments. +# --url-host Hostname shown in returned URL JSON. +# --foreground Run server in the current terminal (no backgrounding). +# --background Force background mode (overrides Codex auto-foreground). + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" + +# Parse arguments +PROJECT_DIR="" +FOREGROUND="false" +FORCE_BACKGROUND="false" +BIND_HOST="127.0.0.1" +URL_HOST="" +while [[ $# -gt 0 ]]; do + case "$1" in + --project-dir) + PROJECT_DIR="$2" + shift 2 + ;; + --host) + BIND_HOST="$2" + shift 2 + ;; + --url-host) + URL_HOST="$2" + shift 2 + ;; + --foreground|--no-daemon) + FOREGROUND="true" + shift + ;; + --background|--daemon) + FORCE_BACKGROUND="true" + shift + ;; + *) + echo "{\"error\": \"Unknown argument: $1\"}" + exit 1 + ;; + esac +done + +if [[ -z "$URL_HOST" ]]; then + if [[ "$BIND_HOST" == "127.0.0.1" || "$BIND_HOST" == "localhost" ]]; then + URL_HOST="localhost" + else + URL_HOST="$BIND_HOST" + fi +fi + +# Some environments reap detached/background processes. Auto-foreground when detected. +if [[ -n "${CODEX_CI:-}" && "$FOREGROUND" != "true" && "$FORCE_BACKGROUND" != "true" ]]; then + FOREGROUND="true" +fi + +# Windows/Git Bash reaps nohup background processes. Auto-foreground when detected. +if [[ "$FOREGROUND" != "true" && "$FORCE_BACKGROUND" != "true" ]]; then + case "${OSTYPE:-}" in + msys*|cygwin*|mingw*) FOREGROUND="true" ;; + esac + if [[ -n "${MSYSTEM:-}" ]]; then + FOREGROUND="true" + fi +fi + +# Generate unique session directory +SESSION_ID="$$-$(date +%s)" + +if [[ -n "$PROJECT_DIR" ]]; then + SESSION_DIR="${PROJECT_DIR}/.superpowers/brainstorm/${SESSION_ID}" +else + SESSION_DIR="/tmp/brainstorm-${SESSION_ID}" +fi + +STATE_DIR="${SESSION_DIR}/state" +PID_FILE="${STATE_DIR}/server.pid" +LOG_FILE="${STATE_DIR}/server.log" + +# Create fresh session directory with content and state peers +mkdir -p "${SESSION_DIR}/content" "$STATE_DIR" + +# Kill any existing server +if [[ -f "$PID_FILE" ]]; then + old_pid=$(cat "$PID_FILE") + kill "$old_pid" 2>/dev/null + rm -f "$PID_FILE" +fi + +cd "$SCRIPT_DIR" + +# Resolve the harness PID (grandparent of this script). +# $PPID is the ephemeral shell the harness spawned to run us — it dies +# when this script exits. The harness itself is $PPID's parent. +OWNER_PID="$(ps -o ppid= -p "$PPID" 2>/dev/null | tr -d ' ')" +if [[ -z "$OWNER_PID" || "$OWNER_PID" == "1" ]]; then + OWNER_PID="$PPID" +fi + +# Foreground mode for environments that reap detached/background processes. +if [[ "$FOREGROUND" == "true" ]]; then + echo "$$" > "$PID_FILE" + env BRAINSTORM_DIR="$SESSION_DIR" BRAINSTORM_HOST="$BIND_HOST" BRAINSTORM_URL_HOST="$URL_HOST" BRAINSTORM_OWNER_PID="$OWNER_PID" node server.cjs + exit $? +fi + +# Start server, capturing output to log file +# Use nohup to survive shell exit; disown to remove from job table +nohup env BRAINSTORM_DIR="$SESSION_DIR" BRAINSTORM_HOST="$BIND_HOST" BRAINSTORM_URL_HOST="$URL_HOST" BRAINSTORM_OWNER_PID="$OWNER_PID" node server.cjs > "$LOG_FILE" 2>&1 & +SERVER_PID=$! +disown "$SERVER_PID" 2>/dev/null +echo "$SERVER_PID" > "$PID_FILE" + +# Wait for server-started message (check log file) +for i in {1..50}; do + if grep -q "server-started" "$LOG_FILE" 2>/dev/null; then + # Verify server is still alive after a short window (catches process reapers) + alive="true" + for _ in {1..20}; do + if ! kill -0 "$SERVER_PID" 2>/dev/null; then + alive="false" + break + fi + sleep 0.1 + done + if [[ "$alive" != "true" ]]; then + echo "{\"error\": \"Server started but was killed. Retry in a persistent terminal with: $SCRIPT_DIR/start-server.sh${PROJECT_DIR:+ --project-dir $PROJECT_DIR} --host $BIND_HOST --url-host $URL_HOST --foreground\"}" + exit 1 + fi + grep "server-started" "$LOG_FILE" | head -1 + exit 0 + fi + sleep 0.1 +done + +# Timeout - server didn't start +echo '{"error": "Server failed to start within 5 seconds"}' +exit 1 diff --git a/.pi/agent/skills/superpowers/brainstorming/scripts/stop-server.sh b/.pi/agent/skills/superpowers/brainstorming/scripts/stop-server.sh new file mode 100755 index 0000000..a6b94e6 --- /dev/null +++ b/.pi/agent/skills/superpowers/brainstorming/scripts/stop-server.sh @@ -0,0 +1,56 @@ +#!/usr/bin/env bash +# Stop the brainstorm server and clean up +# Usage: stop-server.sh +# +# Kills the server process. Only deletes session directory if it's +# under /tmp (ephemeral). Persistent directories (.superpowers/) are +# kept so mockups can be reviewed later. + +SESSION_DIR="$1" + +if [[ -z "$SESSION_DIR" ]]; then + echo '{"error": "Usage: stop-server.sh "}' + exit 1 +fi + +STATE_DIR="${SESSION_DIR}/state" +PID_FILE="${STATE_DIR}/server.pid" + +if [[ -f "$PID_FILE" ]]; then + pid=$(cat "$PID_FILE") + + # Try to stop gracefully, fallback to force if still alive + kill "$pid" 2>/dev/null || true + + # Wait for graceful shutdown (up to ~2s) + for i in {1..20}; do + if ! kill -0 "$pid" 2>/dev/null; then + break + fi + sleep 0.1 + done + + # If still running, escalate to SIGKILL + if kill -0 "$pid" 2>/dev/null; then + kill -9 "$pid" 2>/dev/null || true + + # Give SIGKILL a moment to take effect + sleep 0.1 + fi + + if kill -0 "$pid" 2>/dev/null; then + echo '{"status": "failed", "error": "process still running"}' + exit 1 + fi + + rm -f "$PID_FILE" "${STATE_DIR}/server.log" + + # Only delete ephemeral /tmp directories + if [[ "$SESSION_DIR" == /tmp/* ]]; then + rm -rf "$SESSION_DIR" + fi + + echo '{"status": "stopped"}' +else + echo '{"status": "not_running"}' +fi diff --git a/.pi/agent/skills/superpowers/brainstorming/spec-document-reviewer-prompt.md b/.pi/agent/skills/superpowers/brainstorming/spec-document-reviewer-prompt.md new file mode 100644 index 0000000..35acbb6 --- /dev/null +++ b/.pi/agent/skills/superpowers/brainstorming/spec-document-reviewer-prompt.md @@ -0,0 +1,49 @@ +# Spec Document Reviewer Prompt Template + +Use this template when dispatching a spec document reviewer subagent. + +**Purpose:** Verify the spec is complete, consistent, and ready for implementation planning. + +**Dispatch after:** Spec document is written to docs/superpowers/specs/ + +``` +Task tool (general-purpose): + description: "Review spec document" + prompt: | + You are a spec document reviewer. Verify this spec is complete and ready for planning. + + **Spec to review:** [SPEC_FILE_PATH] + + ## What to Check + + | Category | What to Look For | + |----------|------------------| + | Completeness | TODOs, placeholders, "TBD", incomplete sections | + | Consistency | Internal contradictions, conflicting requirements | + | Clarity | Requirements ambiguous enough to cause someone to build the wrong thing | + | Scope | Focused enough for a single plan — not covering multiple independent subsystems | + | YAGNI | Unrequested features, over-engineering | + + ## Calibration + + **Only flag issues that would cause real problems during implementation planning.** + A missing section, a contradiction, or a requirement so ambiguous it could be + interpreted two different ways — those are issues. Minor wording improvements, + stylistic preferences, and "sections less detailed than others" are not. + + Approve unless there are serious gaps that would lead to a flawed plan. + + ## Output Format + + ## Spec Review + + **Status:** Approved | Issues Found + + **Issues (if any):** + - [Section X]: [specific issue] - [why it matters for planning] + + **Recommendations (advisory, do not block approval):** + - [suggestions for improvement] +``` + +**Reviewer returns:** Status, Issues (if any), Recommendations diff --git a/.pi/agent/skills/superpowers/brainstorming/visual-companion.md b/.pi/agent/skills/superpowers/brainstorming/visual-companion.md new file mode 100644 index 0000000..2113863 --- /dev/null +++ b/.pi/agent/skills/superpowers/brainstorming/visual-companion.md @@ -0,0 +1,287 @@ +# Visual Companion Guide + +Browser-based visual brainstorming companion for showing mockups, diagrams, and options. + +## When to Use + +Decide per-question, not per-session. The test: **would the user understand this better by seeing it than reading it?** + +**Use the browser** when the content itself is visual: + +- **UI mockups** — wireframes, layouts, navigation structures, component designs +- **Architecture diagrams** — system components, data flow, relationship maps +- **Side-by-side visual comparisons** — comparing two layouts, two color schemes, two design directions +- **Design polish** — when the question is about look and feel, spacing, visual hierarchy +- **Spatial relationships** — state machines, flowcharts, entity relationships rendered as diagrams + +**Use the terminal** when the content is text or tabular: + +- **Requirements and scope questions** — "what does X mean?", "which features are in scope?" +- **Conceptual A/B/C choices** — picking between approaches described in words +- **Tradeoff lists** — pros/cons, comparison tables +- **Technical decisions** — API design, data modeling, architectural approach selection +- **Clarifying questions** — anything where the answer is words, not a visual preference + +A question *about* a UI topic is not automatically a visual question. "What kind of wizard do you want?" is conceptual — use the terminal. "Which of these wizard layouts feels right?" is visual — use the browser. + +## How It Works + +The server watches a directory for HTML files and serves the newest one to the browser. You write HTML content to `screen_dir`, the user sees it in their browser and can click to select options. Selections are recorded to `state_dir/events` that you read on your next turn. + +**Content fragments vs full documents:** If your HTML file starts with `/.superpowers/brainstorm/` for the session directory. + +**Note:** Pass the project root as `--project-dir` so mockups persist in `.superpowers/brainstorm/` and survive server restarts. Without it, files go to `/tmp` and get cleaned up. Remind the user to add `.superpowers/` to `.gitignore` if it's not already there. + +**Launching the server by platform:** + +**Claude Code (macOS / Linux):** +```bash +# Default mode works — the script backgrounds the server itself +scripts/start-server.sh --project-dir /path/to/project +``` + +**Claude Code (Windows):** +```bash +# Windows auto-detects and uses foreground mode, which blocks the tool call. +# Use run_in_background: true on the Bash tool call so the server survives +# across conversation turns. +scripts/start-server.sh --project-dir /path/to/project +``` +When calling this via the Bash tool, set `run_in_background: true`. Then read `$STATE_DIR/server-info` on the next turn to get the URL and port. + +**Codex:** +```bash +# Codex reaps background processes. The script auto-detects CODEX_CI and +# switches to foreground mode. Run it normally — no extra flags needed. +scripts/start-server.sh --project-dir /path/to/project +``` + +**Gemini CLI:** +```bash +# Use --foreground and set is_background: true on your shell tool call +# so the process survives across turns +scripts/start-server.sh --project-dir /path/to/project --foreground +``` + +**Other environments:** The server must keep running in the background across conversation turns. If your environment reaps detached processes, use `--foreground` and launch the command with your platform's background execution mechanism. + +If the URL is unreachable from your browser (common in remote/containerized setups), bind a non-loopback host: + +```bash +scripts/start-server.sh \ + --project-dir /path/to/project \ + --host 0.0.0.0 \ + --url-host localhost +``` + +Use `--url-host` to control what hostname is printed in the returned URL JSON. + +## The Loop + +1. **Check server is alive**, then **write HTML** to a new file in `screen_dir`: + - Before each write, check that `$STATE_DIR/server-info` exists. If it doesn't (or `$STATE_DIR/server-stopped` exists), the server has shut down — restart it with `start-server.sh` before continuing. The server auto-exits after 30 minutes of inactivity. + - Use semantic filenames: `platform.html`, `visual-style.html`, `layout.html` + - **Never reuse filenames** — each screen gets a fresh file + - Use Write tool — **never use cat/heredoc** (dumps noise into terminal) + - Server automatically serves the newest file + +2. **Tell user what to expect and end your turn:** + - Remind them of the URL (every step, not just first) + - Give a brief text summary of what's on screen (e.g., "Showing 3 layout options for the homepage") + - Ask them to respond in the terminal: "Take a look and let me know what you think. Click to select an option if you'd like." + +3. **On your next turn** — after the user responds in the terminal: + - Read `$STATE_DIR/events` if it exists — this contains the user's browser interactions (clicks, selections) as JSON lines + - Merge with the user's terminal text to get the full picture + - The terminal message is the primary feedback; `state_dir/events` provides structured interaction data + +4. **Iterate or advance** — if feedback changes current screen, write a new file (e.g., `layout-v2.html`). Only move to the next question when the current step is validated. + +5. **Unload when returning to terminal** — when the next step doesn't need the browser (e.g., a clarifying question, a tradeoff discussion), push a waiting screen to clear the stale content: + + ```html + +
+

Continuing in terminal...

+
+ ``` + + This prevents the user from staring at a resolved choice while the conversation has moved on. When the next visual question comes up, push a new content file as usual. + +6. Repeat until done. + +## Writing Content Fragments + +Write just the content that goes inside the page. The server wraps it in the frame template automatically (header, theme CSS, selection indicator, and all interactive infrastructure). + +**Minimal example:** + +```html +

Which layout works better?

+

Consider readability and visual hierarchy

+ +
+
+
A
+
+

Single Column

+

Clean, focused reading experience

+
+
+
+
B
+
+

Two Column

+

Sidebar navigation with main content

+
+
+
+``` + +That's it. No ``, no CSS, no `