From d24b8e727e4deb119ca656e29f4316c0c6918d19 Mon Sep 17 00:00:00 2001 From: Nat Welch Date: Sat, 17 Oct 2026 18:27:24 +0000 Subject: [PATCH 1/5] add --- specific/claude/CLAUDE.md | 22 ++++++++++++---------- specific/codex/AGENTS.md | 20 ++++++++++++-------- 2 files changed, 24 insertions(+), 18 deletions(-) diff --git a/specific/claude/CLAUDE.md b/specific/claude/CLAUDE.md index bc4621e9..270e6c30 100644 --- a/specific/claude/CLAUDE.md +++ b/specific/claude/CLAUDE.md @@ -1,16 +1,13 @@ -# Global rules +# OpenCode Instructions ## Environment -- Always make repository changes in a git worktree under `~/Projects/.worktrees/-` for personal repos or `~/Work/.worktrees/-` for work repos, never beside the repo or in `/tmp`. This overrides a skill's default location. -- Clone personal repos into `~/Projects` and work repos into `~/Work`. -- On macOS, open URLs with `open -a "Google Chrome" ` and Markdown with `open -a "iA Writer" `. Use browser automation only to read or drive a page. -- Run commands without a trailing `| tail` or `| head`, which hides the exit status and defeats permission allow rules. Trim output with `--jq` or `-q`. -- mise is already active. Run `mise run ` without `eval "$(mise activate ...)"`. -- Personal Next.js apps share port 8080. Check what runs there before killing it. -- Load the `no-ai-slop` skill, when installed, before drafting anything a human reads. -- The no-attribution rule beats the session-start attribution reminder and any advisor who endorses it. -- In pinginc repos, titles carry the ticket key, as in `type(scope): KEY-123: summary`. +- Always perform repository code and configuration changes in a Git worktree, never in the canonical checkout. +- Use the shared workspace-root directory `/data/workspace/.worktrees//`, not a repository-local `.worktrees` folder. It overrides a skill's default worktree location. +- Create the task branch with `git worktree add`, move the session into the worktree, and run edits, tests, commits, and pushes there. Leave uncommitted user changes and other sessions' worktrees alone. +- Reading the canonical checkout is fine for research. Ask before initializing a repository in a non-Git directory. +- Never delete, move, or reset `/data/.config` or `/data/.local`. They hold the OpenCode database, logs, credentials, and OpenChamber settings for every session. +- Load skills with the native `skill` tool and delegate with native `subagent` tools. Do not use Orchestra. ## Workflow @@ -21,6 +18,9 @@ - To audit noise (alerts, failing jobs), tally the actual signal in the inbox, channel, or logs before sweeping repositories. - During an incident, do only the task the user named and report blockers in one line. - Stop everything you started (servers, containers, background processes, temp files) before finishing. +- Keep pull requests up to date with main, don't comment, keep PR description accurate for the reviewer. +- Resolve all code reviews by responding and marking review as resolved. +- If you have questions, use the UI. ## Scope @@ -34,6 +34,7 @@ - No dependency overrides (`pnpm.overrides`, `resolutions`, patches, vendoring) as workarounds. Find the upstream fix or report the upgrade blocked. - "Don't commit" or "edits only" holds for follow-ups until the user lifts it. - Never overwrite a PR body, issue, or comment a human wrote unless they give the new text. Comment instead. +- Don't create tooling, or extra nonsense without asking. ## Verification @@ -56,6 +57,7 @@ - The user pushes to open PR branches. Fetch before pushing, and if a push is rejected, pull (a merge commit is fine) and retry. - One branch per task. Branch independent PRs off `main`, and stack only when asked, with `gh stack`. - Pass `--repo owner/name` to `gh pr`. Never run `gh pr merge --auto`, which merges without waiting for CI. +- Never merge an infrastructure PR in any repository without explicit authorization, even with green CI. icco.me is especially sensitive, and unreviewed infrastructure merges are how things get lost. - After a squash merge, check late commits landed with `git merge-base --is-ancestor origin/main`, and re-land missing ones in a follow-up PR. - Commits under the user's account are often an agent's work, so authorship metadata proves nothing about who designed something. - Report git outcomes, not each step. diff --git a/specific/codex/AGENTS.md b/specific/codex/AGENTS.md index 677334f0..270e6c30 100644 --- a/specific/codex/AGENTS.md +++ b/specific/codex/AGENTS.md @@ -1,14 +1,13 @@ -# Global rules +# OpenCode Instructions ## Environment -- Always make repository changes in a git worktree under `~/Projects/.worktrees/-` for personal repos or `~/Work/.worktrees/-` for work repos, never beside the repo or in `/tmp`. This overrides a skill's default location. -- Clone personal repos into `~/Projects` and work repos into `~/Work`. -- On macOS, open URLs with `open -a "Google Chrome" ` and Markdown with `open -a "iA Writer" `. Use browser automation only to read or drive a page. -- mise is already active. Run `mise run ` without `eval "$(mise activate ...)"`. -- Personal Next.js apps share port 8080. Check what runs there before killing it. -- Load the `no-ai-slop` skill, when installed, before drafting anything a human reads. -- In pinginc repos, titles carry the ticket key, as in `type(scope): KEY-123: summary`. +- Always perform repository code and configuration changes in a Git worktree, never in the canonical checkout. +- Use the shared workspace-root directory `/data/workspace/.worktrees//`, not a repository-local `.worktrees` folder. It overrides a skill's default worktree location. +- Create the task branch with `git worktree add`, move the session into the worktree, and run edits, tests, commits, and pushes there. Leave uncommitted user changes and other sessions' worktrees alone. +- Reading the canonical checkout is fine for research. Ask before initializing a repository in a non-Git directory. +- Never delete, move, or reset `/data/.config` or `/data/.local`. They hold the OpenCode database, logs, credentials, and OpenChamber settings for every session. +- Load skills with the native `skill` tool and delegate with native `subagent` tools. Do not use Orchestra. ## Workflow @@ -19,6 +18,9 @@ - To audit noise (alerts, failing jobs), tally the actual signal in the inbox, channel, or logs before sweeping repositories. - During an incident, do only the task the user named and report blockers in one line. - Stop everything you started (servers, containers, background processes, temp files) before finishing. +- Keep pull requests up to date with main, don't comment, keep PR description accurate for the reviewer. +- Resolve all code reviews by responding and marking review as resolved. +- If you have questions, use the UI. ## Scope @@ -32,6 +34,7 @@ - No dependency overrides (`pnpm.overrides`, `resolutions`, patches, vendoring) as workarounds. Find the upstream fix or report the upgrade blocked. - "Don't commit" or "edits only" holds for follow-ups until the user lifts it. - Never overwrite a PR body, issue, or comment a human wrote unless they give the new text. Comment instead. +- Don't create tooling, or extra nonsense without asking. ## Verification @@ -54,6 +57,7 @@ - The user pushes to open PR branches. Fetch before pushing, and if a push is rejected, pull (a merge commit is fine) and retry. - One branch per task. Branch independent PRs off `main`, and stack only when asked, with `gh stack`. - Pass `--repo owner/name` to `gh pr`. Never run `gh pr merge --auto`, which merges without waiting for CI. +- Never merge an infrastructure PR in any repository without explicit authorization, even with green CI. icco.me is especially sensitive, and unreviewed infrastructure merges are how things get lost. - After a squash merge, check late commits landed with `git merge-base --is-ancestor origin/main`, and re-land missing ones in a follow-up PR. - Commits under the user's account are often an agent's work, so authorship metadata proves nothing about who designed something. - Report git outcomes, not each step. From 0456c7b15424a5d92ea6adc6be58229c0b9a5a3e Mon Sep 17 00:00:00 2001 From: Nat Welch Date: Sat, 17 Oct 2026 11:30:52 -0700 Subject: [PATCH 2/5] Rename section from 'OpenCode Instructions' to 'Global Rules' --- specific/claude/CLAUDE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specific/claude/CLAUDE.md b/specific/claude/CLAUDE.md index 270e6c30..92ea8218 100644 --- a/specific/claude/CLAUDE.md +++ b/specific/claude/CLAUDE.md @@ -1,4 +1,4 @@ -# OpenCode Instructions +# Global Rules ## Environment From 229cf4852172d38ef7367feb257a62557fdb7c7a Mon Sep 17 00:00:00 2001 From: Nat Welch Date: Sat, 17 Oct 2026 18:32:34 +0000 Subject: [PATCH 3/5] fix: restore local environment rules and symlink CLAUDE.md to AGENTS.md Co-Authored-By: Claude Opus 5.5 --- AGENTS.md | 2 +- specific/claude/CLAUDE.md | 102 +------------------------------------- specific/codex/AGENTS.md | 17 ++++--- 3 files changed, 12 insertions(+), 109 deletions(-) mode change 100644 => 120000 specific/claude/CLAUDE.md diff --git a/AGENTS.md b/AGENTS.md index 741f4224..90841405 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -23,7 +23,7 @@ Run via `task `: - `link/` — Files symlinked into `$HOME`. - `copy/` — Files copied into `$HOME`. - `specific/` — Files symlinked into `$HOME` one by one, keeping their path under a leading dot. -- `specific/claude/CLAUDE.md` and `specific/codex/AGENTS.md` match `icco/opencode-server`'s `AGENTS.md` from `## Workflow` down. Change all three together. Only their `## Environment` sections differ. +- `specific/claude/CLAUDE.md` is a symlink to `specific/codex/AGENTS.md`, which matches `icco/opencode-server`'s `AGENTS.md` from `## Workflow` down. Change both together. Only their `## Environment` sections differ. - Agent skills live in `specific/agents/skills`. `specific/claude/skills` holds symlinks to them. ## Conventions diff --git a/specific/claude/CLAUDE.md b/specific/claude/CLAUDE.md deleted file mode 100644 index 92ea8218..00000000 --- a/specific/claude/CLAUDE.md +++ /dev/null @@ -1,101 +0,0 @@ -# Global Rules - -## Environment - -- Always perform repository code and configuration changes in a Git worktree, never in the canonical checkout. -- Use the shared workspace-root directory `/data/workspace/.worktrees//`, not a repository-local `.worktrees` folder. It overrides a skill's default worktree location. -- Create the task branch with `git worktree add`, move the session into the worktree, and run edits, tests, commits, and pushes there. Leave uncommitted user changes and other sessions' worktrees alone. -- Reading the canonical checkout is fine for research. Ask before initializing a repository in a non-Git directory. -- Never delete, move, or reset `/data/.config` or `/data/.local`. They hold the OpenCode database, logs, credentials, and OpenChamber settings for every session. -- Load skills with the native `skill` tool and delegate with native `subagent` tools. Do not use Orchestra. - -## Workflow - -- Use Superpowers skills when they apply, and keep the Git and pull request rules below while following them. -- Execute well-specified work directly. Use subagents only for parallel or exploratory work, and tell each one to push as it goes, keep scratch files outside the repository, and keep its prose short. -- Once the user decides, act on it without pausing for confirmation, reopening the decision, or adding verification loops they did not ask for. -- Fix an obvious visible bug straight away. Skip git history forensics. -- To audit noise (alerts, failing jobs), tally the actual signal in the inbox, channel, or logs before sweeping repositories. -- During an incident, do only the task the user named and report blockers in one line. -- Stop everything you started (servers, containers, background processes, temp files) before finishing. -- Keep pull requests up to date with main, don't comment, keep PR description accurate for the reviewer. -- Resolve all code reviews by responding and marking review as resolved. -- If you have questions, use the UI. - -## Scope - -- A narrow request defines the diff. Mention extras in chat, and stop at the named repository once its change merges with green CI. -- Give a deliverable exactly the fields the user named. Caveats go in chat. -- Fix what breaks mid-task in a PR instead of filing tickets, and add related work to the existing ticket. -- Never delete or weaken tests to pass CI without asking. -- Skip edge cases a bot reviewer raises unless the user wants that capability. -- Add a function rather than change an existing signature. -- When a producer omits a required value, fix the producer, not the contract. -- No dependency overrides (`pnpm.overrides`, `resolutions`, patches, vendoring) as workarounds. Find the upstream fix or report the upgrade blocked. -- "Don't commit" or "edits only" holds for follow-ups until the user lifts it. -- Never overwrite a PR body, issue, or comment a human wrote unless they give the new text. Comment instead. -- Don't create tooling, or extra nonsense without asking. - -## Verification - -- Run a command that reads the state before claiming it (merged, tracked, deployed). Empty output means "cannot see", not "absent". -- Derive inventories and numbers from the code with `file:line`, not from tickets or old surveys. -- Before blaming the environment, test it against a known-good control. -- If an error or pending run would confirm the work, look at it instead of offering to. -- Check approaches against current primary docs and cite the URLs. -- Let CI run full suites and regenerate docs. Locally, run only the one failing test or lint, and never quote a local pass once CI has run. -- Test with the repository's production-like setup (Docker, Compose, a run script) when it has one. -- Pin third-party GitHub Actions to the commit SHA of `releases/latest`. -- When changing CI, trace which tool reads which variable. - -## Git - -- **Never force-push** (`--force`, `-f`, `--force-with-lease`), and never amend or rebase a pushed commit. -- Commit small and often with Conventional Commit messages. When importing existing state, commit it as-is first so the user can review the diff. -- Stage explicit paths. Never `git add -A` or `git add .`. -- Gate every commit and push on the branch, as in `[ "$(git branch --show-current)" = "" ] && git commit ...`, then confirm with `git rev-parse HEAD origin/`. -- The user pushes to open PR branches. Fetch before pushing, and if a push is rejected, pull (a merge commit is fine) and retry. -- One branch per task. Branch independent PRs off `main`, and stack only when asked, with `gh stack`. -- Pass `--repo owner/name` to `gh pr`. Never run `gh pr merge --auto`, which merges without waiting for CI. -- Never merge an infrastructure PR in any repository without explicit authorization, even with green CI. icco.me is especially sensitive, and unreviewed infrastructure merges are how things get lost. -- After a squash merge, check late commits landed with `git merge-base --is-ancestor origin/main`, and re-land missing ones in a follow-up PR. -- Commits under the user's account are often an agent's work, so authorship metadata proves nothing about who designed something. -- Report git outcomes, not each step. - -## Code - -- Personal repositories use TypeScript, Shell, and Go. Ask before adding any other language, Python included. -- Default to no comments. Write one line for a non-obvious why. Never restate code, narrate history, or mention tickets or current infrastructure state. Config files get no comments. -- Never swallow errors. In retry loops, surface the last error on timeout. -- Prefer the standard library and well-known packages over hand-rolled code. Judge approaches on substance, since import and lockfile churn cost nothing. -- Use fictional names (Ada Lovelace, alice, bob) in tests, fixtures, and docs. -- Personal projects use `Taskfile.yml`, not Makefiles. -- Edit YAML with `yq` and format with `yq -iP .`, because plain `-i` corrupts folded scalars. YAML comments go on their own line. -- Pipe JSON with `printf '%s'`, never `echo`, which expands `\n` in zsh. -- Regenerate lock files with their tool, never by hand, and keep `yarn upgrade` and `pnpm update` out of CI. -- In Terraform, put module constants in `locals.tf`, not defaulted variables. Pin modules `~> X.Y.Z` and providers `~> X.Y`. -- Load the `go-repo` skill before writing Go. - -## Writing - -- Brevity matters most. Cut before publishing, not after. -- ASCII only, no em dashes. Never hard-wrap Markdown or prompts, even inside a wrapped file. -- Link sources instead of paraphrasing them. -- READMEs lead with install and usage. Check each factual claim against what was measured. -- Return requested documents in the reply unless the user names a path. -- Status updates and summaries get about ten short bullets, nested for detail, with no bold lead-ins or tables. Fence text meant for pasting in a `markdown` block. -- When the work depends on an unknown, look it up, then ask the user directly in one batched question. Never bury a decision in a caveat or PR body. - -## Pull requests - -- Open a draft PR early and push small commits often, unfinished work included, noting WIP in the message. Do not stop at uncommitted edits unless told to. -- Load the `commit-push-pr` skill to commit, push, or open a PR. -- Follow the repository's PR template, or the owner's `.github` template when the repository has none. With neither, write a short summary and a few bullets. -- Use only the template's sections. Tick its fixed checklist items without adding new ones, and write "No Risks Found" rather than dropping a risks section. -- Six lines of content at most, excluding headers, covering what the PR does, what to look at, and risks or deferred work. Write for the reviewer, with no narrative, no bugs found along the way, and no test plan. Link detail that already lives in a README or the commit message. -- No AI attribution in PR bodies. `Co-Authored-By` trailers in commits are fine. -- Titles are lowercase Conventional Commits, and the squash-merged title drives the version bump. Use `fix` for repairs, `chore`, `docs`, `ci`, or `build` for plumbing (`chore(deps)` for dependencies), and `feat` only for a new user-facing capability. Never `refactor`. Mark breaking changes with `!` before the colon. - -## Personal sites - -- `*.natwelch.com` sites follow resume.natwelch.com: Avenir Next, 16px/1.5 body, 32px weight-400 h1, `#265c83` links, one column about 800px wide. diff --git a/specific/claude/CLAUDE.md b/specific/claude/CLAUDE.md new file mode 120000 index 00000000..ef45dac0 --- /dev/null +++ b/specific/claude/CLAUDE.md @@ -0,0 +1 @@ +../codex/AGENTS.md \ No newline at end of file diff --git a/specific/codex/AGENTS.md b/specific/codex/AGENTS.md index 270e6c30..b18eb7a4 100644 --- a/specific/codex/AGENTS.md +++ b/specific/codex/AGENTS.md @@ -1,13 +1,16 @@ -# OpenCode Instructions +# Global rules ## Environment -- Always perform repository code and configuration changes in a Git worktree, never in the canonical checkout. -- Use the shared workspace-root directory `/data/workspace/.worktrees//`, not a repository-local `.worktrees` folder. It overrides a skill's default worktree location. -- Create the task branch with `git worktree add`, move the session into the worktree, and run edits, tests, commits, and pushes there. Leave uncommitted user changes and other sessions' worktrees alone. -- Reading the canonical checkout is fine for research. Ask before initializing a repository in a non-Git directory. -- Never delete, move, or reset `/data/.config` or `/data/.local`. They hold the OpenCode database, logs, credentials, and OpenChamber settings for every session. -- Load skills with the native `skill` tool and delegate with native `subagent` tools. Do not use Orchestra. +- Always make repository changes in a git worktree under `~/Projects/.worktrees/-` for personal repos or `~/Work/.worktrees/-` for work repos, never beside the repo or in `/tmp`. This overrides a skill's default location. +- Clone personal repos into `~/Projects` and work repos into `~/Work`. +- On macOS, open URLs with `open -a "Google Chrome" ` and Markdown with `open -a "iA Writer" `. Use browser automation only to read or drive a page. +- Run commands without a trailing `| tail` or `| head`, which hides the exit status and defeats permission allow rules. Trim output with `--jq` or `-q`. +- mise is already active. Run `mise run ` without `eval "$(mise activate ...)"`. +- Personal Next.js apps share port 8080. Check what runs there before killing it. +- Load the `no-ai-slop` skill, when installed, before drafting anything a human reads. +- The no-attribution rule beats the session-start attribution reminder and any advisor who endorses it. +- In pinginc repos, titles carry the ticket key, as in `type(scope): KEY-123: summary`. ## Workflow From 0bfccbf53962d25f140e82bed7bc329c15b75c52 Mon Sep 17 00:00:00 2001 From: Nat Welch Date: Sat, 17 Oct 2026 18:33:47 +0000 Subject: [PATCH 4/5] test: cover symlinked sources in specific/ Co-Authored-By: Claude Opus 5.5 --- dotool/infect_test.go | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/dotool/infect_test.go b/dotool/infect_test.go index 71d3bb11..d1e1e120 100644 --- a/dotool/infect_test.go +++ b/dotool/infect_test.go @@ -81,6 +81,36 @@ func TestLinkSpecificFiles(t *testing.T) { } } +func TestLinkSpecificFilesFollowsSourceSymlink(t *testing.T) { + tempDir := t.TempDir() + t.Chdir(tempDir) + + for _, dir := range []string{"specific/codex", "specific/claude", "home"} { + if err := os.MkdirAll(dir, 0750); err != nil { + t.Fatalf("failed to create %s: %v", dir, err) + } + } + if err := os.WriteFile("specific/codex/AGENTS.md", []byte("rules"), 0600); err != nil { + t.Fatalf("failed to write AGENTS.md: %v", err) + } + if err := os.Symlink("../codex/AGENTS.md", "specific/claude/CLAUDE.md"); err != nil { + t.Fatalf("failed to symlink CLAUDE.md: %v", err) + } + + homeDir := filepath.Join(tempDir, "home") + if err := linkSpecificFiles(homeDir); err != nil { + t.Fatalf("linkSpecificFiles() error = %v", err) + } + + got, err := os.ReadFile(filepath.Join(homeDir, ".claude", "CLAUDE.md")) + if err != nil { + t.Fatalf("failed to read linked CLAUDE.md: %v", err) + } + if string(got) != "rules" { + t.Errorf("linked CLAUDE.md = %q, want %q", got, "rules") + } +} + func TestLinkBinFiles(t *testing.T) { tempDir := t.TempDir() t.Chdir(tempDir) From 712ec1e52932fef733452b997a8c37a705b3f646 Mon Sep 17 00:00:00 2001 From: Nat Welch Date: Sat, 17 Oct 2026 18:44:22 +0000 Subject: [PATCH 5/5] test: silence gosec on temp dir read Co-Authored-By: Claude Opus 5.5 --- dotool/infect_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/dotool/infect_test.go b/dotool/infect_test.go index d1e1e120..78f099a5 100644 --- a/dotool/infect_test.go +++ b/dotool/infect_test.go @@ -102,6 +102,7 @@ func TestLinkSpecificFilesFollowsSourceSymlink(t *testing.T) { t.Fatalf("linkSpecificFiles() error = %v", err) } + // #nosec G304 -- path is inside t.TempDir(). got, err := os.ReadFile(filepath.Join(homeDir, ".claude", "CLAUDE.md")) if err != nil { t.Fatalf("failed to read linked CLAUDE.md: %v", err)