From 63294c8b0ce4de10d0dd6d92bb5fa3d318a1eb93 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 29 Jul 2026 00:29:24 +0000 Subject: [PATCH 1/3] Add opencode config to mirror Claude Code setup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ports the Claude Code global config in tilde/dot_claude/ to opencode's equivalent locations under ~/.config/opencode/: - opencode.json: model/provider config (Anthropic + OpenRouter, keys via env vars), converts the Bash permission allowlist from settings.json into opencode's bash permission pattern syntax, autoupdate disabled since mise pins the opencode version. - AGENTS.md: consolidates tilde/dot_claude/instructions/*.md, which weren't wired into any CLAUDE.md import and so were never actually loaded by Claude Code. - commands/chezmoi-apply.md: ports the /chezmoi-apply slash command. Existing skills under ~/.claude/skills/ and the project CLAUDE.md need no changes — opencode auto-discovers .claude/skills/ and falls back to CLAUDE.md when no AGENTS.md is present. Provider API keys are stubbed and stored age-encrypted (same pattern as encrypted_akamai.bash.age), decrypted by chezmoi to ~/.config/shell/opencode-keys.sh and sourced from both fish and bash. Real keys need to be filled in via `chezmoi edit`. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_01JJkxjsGjWuZqV6tevUrVm4 --- tilde/private_dot_config/fish/config.fish | 5 + tilde/private_dot_config/opencode/AGENTS.md | 57 ++++++++ .../opencode/commands/chezmoi-apply.md | 33 +++++ .../private_dot_config/opencode/opencode.json | 135 ++++++++++++++++++ .../shell/encrypted_opencode-keys.sh.age | 11 ++ tilde/private_dot_config/shell/profile.sh | 3 + 6 files changed, 244 insertions(+) create mode 100644 tilde/private_dot_config/opencode/AGENTS.md create mode 100644 tilde/private_dot_config/opencode/commands/chezmoi-apply.md create mode 100644 tilde/private_dot_config/opencode/opencode.json create mode 100644 tilde/private_dot_config/shell/encrypted_opencode-keys.sh.age diff --git a/tilde/private_dot_config/fish/config.fish b/tilde/private_dot_config/fish/config.fish index a1d4b653..a047d969 100644 --- a/tilde/private_dot_config/fish/config.fish +++ b/tilde/private_dot_config/fish/config.fish @@ -3,6 +3,11 @@ # This file is sourced by fish and bash source "$XDG_CONFIG_HOME/shell/exports.sh" +# Secrets (age-encrypted; see tilde/private_dot_config/shell/encrypted_*.age) +if test -f "$XDG_CONFIG_HOME/shell/opencode-keys.sh" + source "$XDG_CONFIG_HOME/shell/opencode-keys.sh" +end + source "$__fish_config_dir/variables.fish" # automatically loads plugins under "$fisher_path" diff --git a/tilde/private_dot_config/opencode/AGENTS.md b/tilde/private_dot_config/opencode/AGENTS.md new file mode 100644 index 00000000..e9080539 --- /dev/null +++ b/tilde/private_dot_config/opencode/AGENTS.md @@ -0,0 +1,57 @@ +# Global Instructions + +Personal defaults for opencode across all projects. Ported from the Claude Code +instruction set in `~/.claude/instructions/` (those files aren't wired into any +`CLAUDE.md` import, so they weren't actually loaded there — consolidated here so +they're active). + +## Editor Configuration + +- Always check for `.editorconfig` in the project root before editing files. +- If `.editorconfig` exists, strictly follow its rules: indentation style/size, + end of line characters, character encoding, final newline, trailing whitespace. + +## Code Quality + +- Write clear, maintainable code with proper documentation. +- Follow established conventions for the project's language. +- Include appropriate error handling. +- Use meaningful variable and function names. +- Follow DRY, YAGNI, KISS, and SOLID. + +### Error handling and debugging + +- Investigate and understand the root cause of errors — don't patch around them. +- Never use quick fixes/workarounds, comment out error-causing code, silence + errors with empty catch blocks, or modify tests just to make them pass. +- Preserve the integrity of existing test cases unless explicitly instructed + otherwise. +- If unsure about the best approach, ask for guidance. + +### Research + +- Actively search the web for unfamiliar libraries/frameworks, API docs, best + practices, error messages, or recent syntax/feature changes — don't assume + knowledge about rapidly changing technologies. +- If research is insufficient: report what was tried and what's still unknown, + and ask for guidance rather than filling gaps with assumptions. + +## Git + +- Prioritize Git MCP server tools over bash commands for Git operations when + an MCP server is available. +- Analyze all changes before committing; identify logical units of work and + never mix unrelated changes (different features, different bugfixes, + different components, code vs. config vs. docs) into a single commit. +- Acceptable to bundle: code with its tests, a feature with its docs, a bugfix + with its test case, config changes that directly support the same feature. +- Propose the commit split to the user before executing when a change touches + multiple logical units. + +## General Reminders + +- Do what's been asked; nothing more, nothing less. +- Prefer editing an existing file over creating a new one. +- Don't proactively create documentation or README files unless requested. +- Don't guess at unclear requirements — ask for clarification instead of + proceeding on assumptions. diff --git a/tilde/private_dot_config/opencode/commands/chezmoi-apply.md b/tilde/private_dot_config/opencode/commands/chezmoi-apply.md new file mode 100644 index 00000000..82ccb7dc --- /dev/null +++ b/tilde/private_dot_config/opencode/commands/chezmoi-apply.md @@ -0,0 +1,33 @@ +--- +description: Apply chezmoi changes with conflict resolution +--- + +This command applies all staged changes from the chezmoi source directory to your home directory with intelligent conflict handling. + +## Command Behavior + +When you run `/chezmoi-apply`, opencode will: + +1. Show a preview of changes using `chezmoi diff --no-tty` +2. Attempt to apply changes using `chezmoi apply --no-tty` +3. If conflicts are detected: + - Display the conflicting files and their differences + - Present options: overwrite, skip, or quit for each conflict + - Wait for user decision before proceeding +4. Report the final result of the operation + +## Conflict Resolution Options + +When conflicts occur, you'll be prompted with these options for each file: +- **overwrite**: Replace the target file with chezmoi's version +- **skip**: Keep the existing file and skip this change +- **quit**: Stop the apply process entirely + +## Security + +This command is safe to use as it only applies changes that are already staged in your chezmoi source directory. The conflict resolution ensures you maintain control over which changes are applied. + +## Related Commands + +- Use regular file editing commands to modify files in the chezmoi source directory first +- This command only applies changes; it doesn't modify source files diff --git a/tilde/private_dot_config/opencode/opencode.json b/tilde/private_dot_config/opencode/opencode.json new file mode 100644 index 00000000..d689ba6d --- /dev/null +++ b/tilde/private_dot_config/opencode/opencode.json @@ -0,0 +1,135 @@ +{ + "$schema": "https://opencode.ai/config.json", + "model": "anthropic/claude-sonnet-4-5", + "provider": { + "anthropic": { + "options": { + "apiKey": "{env:ANTHROPIC_API_KEY}" + } + }, + "openrouter": { + "options": { + "apiKey": "{env:OPENROUTER_API_KEY}" + } + } + }, + "autoupdate": false, + "permission": { + "edit": "allow", + "webfetch": "allow", + "websearch": "allow", + "bash": { + "*": "ask", + "chezmoi status": "allow", + "chezmoi diff *": "allow", + "chezmoi cat *": "allow", + "chezmoi data": "allow", + "chezmoi doctor": "allow", + "chezmoi dump *": "allow", + "chezmoi list *": "allow", + "chezmoi state *": "allow", + "chezmoi verify *": "allow", + "chezmoi --version": "allow", + "brew list *": "allow", + "brew outdated *": "allow", + "brew deps *": "allow", + "brew info *": "allow", + "brew search *": "allow", + "brew doctor *": "allow", + "brew config": "allow", + "mise outdated *": "allow", + "mise list-remote *": "allow", + "mise plugins *": "allow", + "mise settings *": "allow", + "mise tasks *": "allow", + "mise env *": "allow", + "mise --version": "allow", + "mise list": "allow", + "mise current": "allow", + "mise ls": "allow", + "mise doctor": "allow", + "mise which *": "allow", + "terraform --version": "allow", + "terraform -version": "allow", + "terraform version": "allow", + "terraform version *": "allow", + "terraform validate": "allow", + "terraform validate *": "allow", + "terraform fmt -check": "allow", + "terraform fmt -check *": "allow", + "terraform graph": "allow", + "terraform graph *": "allow", + "terraform show": "allow", + "terraform show *": "allow", + "terraform output": "allow", + "terraform output *": "allow", + "terraform providers": "allow", + "terraform providers schema": "allow", + "terraform providers schema *": "allow", + "terraform state list": "allow", + "terraform state list *": "allow", + "terraform state show *": "allow", + "terraform workspace list": "allow", + "terraform workspace show": "allow", + "git status *": "allow", + "git log *": "allow", + "git show *": "allow", + "git diff *": "allow", + "git branch *": "allow", + "git remote *": "allow", + "gh run download *": "allow", + "gh run list *": "allow", + "gh run view *": "allow", + "gh run watch *": "allow", + "gh repo view *": "allow", + "gh repo list *": "allow", + "gh pr *": "allow", + "gh issue create *": "allow", + "gh issue list *": "allow", + "gh issue view *": "allow", + "gh release list *": "allow", + "gh release view *": "allow", + "gh status": "allow", + "gh auth status": "allow", + "gh api *": "allow", + "markdownlint *": "allow", + "uv run *": "allow", + "grep *": "allow", + "ls *": "allow", + "cat *": "allow", + "head *": "allow", + "tail *": "allow", + "wc *": "allow", + "find *": "allow", + "which *": "allow", + "pwd": "allow", + "env": "allow", + "printenv *": "allow", + "tree *": "allow", + "file *": "allow", + "stat *": "allow", + "diff *": "allow", + "rg *": "allow", + "ripgrep *": "allow", + "fd *": "allow", + "bat *": "allow", + "jq *": "allow", + "awk *": "allow", + "sed *": "allow", + "sort *": "allow", + "uniq *": "allow", + "python -c *": "allow", + "python -m json.tool *": "allow", + "pytest --collect-only *": "allow", + "pytest --help": "allow", + "npm list *": "allow", + "npm outdated *": "allow", + "pip list *": "allow", + "pip show *": "allow", + "poetry show *": "allow", + "poetry check": "allow", + "docker ps *": "allow", + "docker images *": "allow" + } + } +} diff --git a/tilde/private_dot_config/shell/encrypted_opencode-keys.sh.age b/tilde/private_dot_config/shell/encrypted_opencode-keys.sh.age new file mode 100644 index 00000000..e25e3d68 --- /dev/null +++ b/tilde/private_dot_config/shell/encrypted_opencode-keys.sh.age @@ -0,0 +1,11 @@ +-----BEGIN AGE ENCRYPTED FILE----- +YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBaZDRlaTdwWWdVb2xLRUox +RmpTN01ycXhxT28yYk5aOEdLY2grYisrcVJFClVWQXI0aEQ1UlJ4QWUvcjRFYlpx +aGNSdmE5eEpYbytSU1FLNXBUNEoxWWMKLS0tIG4xZXZRQTFCR0xmLzh4NHI0d2Vo +WFZCdUhVVmh5QlkvZTJjWmxNWjlUTWsKatF9wKOE8SBa/OufW5OX+ZTf9rt0zkxh +4RYvy8D1uH1Ui6NJij1YVi94tipfyCqn2JTRzvHXi3yvCps7MKeOPgE8zeMBiY7H +ScnSp4ntWMEJFxwbjWI9SnB8E7lFQvL+6akg+MNqlMJWLgg9FA44TyitWud1xB2m +WK8x15NxNLDuAMsfS5BoQaV66RI9PmmNMY+yCvqga+Vzqw9s/uJ+g9zzzemPYgQ7 +Kk3KSi0GdkdEf/VarCzXDM49z3TeS+W4MHENmn1TIVXOzinqPW1CfsglpGd3yoE9 +uFMO4qQNrO0dptBGwYz8JbyP1qGMwSlTafu+oVQaOW2C7yx/kbmBmsEC3M/2gA== +-----END AGE ENCRYPTED FILE----- diff --git a/tilde/private_dot_config/shell/profile.sh b/tilde/private_dot_config/shell/profile.sh index b1de4aba..dc30b7ec 100644 --- a/tilde/private_dot_config/shell/profile.sh +++ b/tilde/private_dot_config/shell/profile.sh @@ -18,4 +18,7 @@ export XDG_CONFIG_HOME="${XDG_CONFIG_HOME:-$HOME/.config}" [ ! -f "${XDG_CONFIG_HOME}/shell/aliases.sh" ] || . "${XDG_CONFIG_HOME}/shell/aliases.sh" [ ! -f "${XDG_CONFIG_HOME}/shell/functions.sh" ] || . "${XDG_CONFIG_HOME}/shell/functions.sh" +# Secrets (age-encrypted; see tilde/private_dot_config/shell/encrypted_*.age) +[ ! -f "${XDG_CONFIG_HOME}/shell/opencode-keys.sh" ] || . "${XDG_CONFIG_HOME}/shell/opencode-keys.sh" + true From 150ae5cec84ae3e2aa74a44eb589e97dca597d7e Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 29 Jul 2026 00:34:21 +0000 Subject: [PATCH 2/3] Drop redundant opencode secrets file, use existing hostname config rishid already sets provider env vars (e.g. for Claude Code) in the existing host-specific encrypted_config.bos-lhv9i4.fish.age, sourced automatically by fish's config.fish. Reuse that instead of the new shell-shared encrypted_opencode-keys.sh.age from the previous commit, which just duplicated the same purpose. opencode reads ANTHROPIC_API_KEY and OPENROUTER_API_KEY from the environment (same as referenced via {env:...} in opencode.json), so those are the two vars to add to the hostname config. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_01JJkxjsGjWuZqV6tevUrVm4 --- .../shell/encrypted_opencode-keys.sh.age | 11 ----------- 1 file changed, 11 deletions(-) delete mode 100644 tilde/private_dot_config/shell/encrypted_opencode-keys.sh.age diff --git a/tilde/private_dot_config/shell/encrypted_opencode-keys.sh.age b/tilde/private_dot_config/shell/encrypted_opencode-keys.sh.age deleted file mode 100644 index e25e3d68..00000000 --- a/tilde/private_dot_config/shell/encrypted_opencode-keys.sh.age +++ /dev/null @@ -1,11 +0,0 @@ ------BEGIN AGE ENCRYPTED FILE----- -YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBaZDRlaTdwWWdVb2xLRUox -RmpTN01ycXhxT28yYk5aOEdLY2grYisrcVJFClVWQXI0aEQ1UlJ4QWUvcjRFYlpx -aGNSdmE5eEpYbytSU1FLNXBUNEoxWWMKLS0tIG4xZXZRQTFCR0xmLzh4NHI0d2Vo -WFZCdUhVVmh5QlkvZTJjWmxNWjlUTWsKatF9wKOE8SBa/OufW5OX+ZTf9rt0zkxh -4RYvy8D1uH1Ui6NJij1YVi94tipfyCqn2JTRzvHXi3yvCps7MKeOPgE8zeMBiY7H -ScnSp4ntWMEJFxwbjWI9SnB8E7lFQvL+6akg+MNqlMJWLgg9FA44TyitWud1xB2m -WK8x15NxNLDuAMsfS5BoQaV66RI9PmmNMY+yCvqga+Vzqw9s/uJ+g9zzzemPYgQ7 -Kk3KSi0GdkdEf/VarCzXDM49z3TeS+W4MHENmn1TIVXOzinqPW1CfsglpGd3yoE9 -uFMO4qQNrO0dptBGwYz8JbyP1qGMwSlTafu+oVQaOW2C7yx/kbmBmsEC3M/2gA== ------END AGE ENCRYPTED FILE----- From 641c5657017b83a28b67b7bd427d3b383d16d86f Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 29 Jul 2026 00:34:33 +0000 Subject: [PATCH 3/3] Revert config.fish/profile.sh sourcing for removed secrets file MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Follow-up to 150ae5c — these two edits wired up sourcing for the encrypted_opencode-keys.sh.age file that commit deleted. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_01JJkxjsGjWuZqV6tevUrVm4 --- tilde/private_dot_config/fish/config.fish | 5 ----- tilde/private_dot_config/shell/profile.sh | 3 --- 2 files changed, 8 deletions(-) diff --git a/tilde/private_dot_config/fish/config.fish b/tilde/private_dot_config/fish/config.fish index a047d969..a1d4b653 100644 --- a/tilde/private_dot_config/fish/config.fish +++ b/tilde/private_dot_config/fish/config.fish @@ -3,11 +3,6 @@ # This file is sourced by fish and bash source "$XDG_CONFIG_HOME/shell/exports.sh" -# Secrets (age-encrypted; see tilde/private_dot_config/shell/encrypted_*.age) -if test -f "$XDG_CONFIG_HOME/shell/opencode-keys.sh" - source "$XDG_CONFIG_HOME/shell/opencode-keys.sh" -end - source "$__fish_config_dir/variables.fish" # automatically loads plugins under "$fisher_path" diff --git a/tilde/private_dot_config/shell/profile.sh b/tilde/private_dot_config/shell/profile.sh index dc30b7ec..b1de4aba 100644 --- a/tilde/private_dot_config/shell/profile.sh +++ b/tilde/private_dot_config/shell/profile.sh @@ -18,7 +18,4 @@ export XDG_CONFIG_HOME="${XDG_CONFIG_HOME:-$HOME/.config}" [ ! -f "${XDG_CONFIG_HOME}/shell/aliases.sh" ] || . "${XDG_CONFIG_HOME}/shell/aliases.sh" [ ! -f "${XDG_CONFIG_HOME}/shell/functions.sh" ] || . "${XDG_CONFIG_HOME}/shell/functions.sh" -# Secrets (age-encrypted; see tilde/private_dot_config/shell/encrypted_*.age) -[ ! -f "${XDG_CONFIG_HOME}/shell/opencode-keys.sh" ] || . "${XDG_CONFIG_HOME}/shell/opencode-keys.sh" - true