Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 0 additions & 66 deletions .chezmoitemplates/grok.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,71 +6,5 @@ compact_mode = false
permission_mode = "always-approve"
vim_mode = true

# Ox Alpha provider catalog. Keys remain machine-local environment state.
[model_providers.ox-opencode]
base_url = "https://opencode.ai/zen/v1"
api_backend = "chat_completions"
env_key = "OPENCODE_ZEN_API_KEY"
context_window = 1048576

[model_providers.ox-openrouter]
base_url = "https://openrouter.ai/api/v1"
api_backend = "chat_completions"
env_key = "OPENROUTER_API_KEY"
context_window = 1048576

[model_providers.ox-command]
base_url = "https://api.commandcode.ai/provider/v1"
api_backend = "chat_completions"
env_key = "COMMAND_CODE_API_KEY"
context_window = 1048576

[model_providers.ox-nous]
base_url = "http://127.0.0.1:8645/v1"
api_backend = "chat_completions"
env_key = "NOUS_API_KEY"
context_window = 1048576

[model_providers.ox-venice]
base_url = "https://api.venice.ai/api/v1"
api_backend = "chat_completions"
env_key = "VENICE_API_KEY"
context_window = 1048576

[model.ox-opencode]
model = "x-preview-f-free"
name = "Ox Alpha (OpenCode Zen; ZDR)"
description = "Limited-time free stealth preview with zero retention"
model_provider = "ox-opencode"
max_completion_tokens = 131072

[model.ox-openrouter]
model = "stealth/ox-alpha"
name = "Ox Alpha (OpenRouter)"
description = "Free stealth preview; upstream retains prompts and completions"
model_provider = "ox-openrouter"
max_completion_tokens = 131072

[model.ox-command]
model = "stealth/ox-alpha"
name = "Ox Alpha (Command Code)"
description = "Limited-time free stealth preview; not ZDR"
model_provider = "ox-command"
max_completion_tokens = 131072

[model.ox-nous]
model = "stealth/ox-alpha"
name = "Ox Alpha (Nous Portal)"
description = "Free-tier route; enable Nous Privacy Mode separately"
model_provider = "ox-nous"
max_completion_tokens = 131072

[model.ox-venice]
model = "stealth-ox-alpha"
name = "Ox Alpha (Venice)"
description = "Free beta route; anonymized third-party inference"
model_provider = "ox-venice"
max_completion_tokens = 131072

[models]
default = "grok-4.6"
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ These are codified in `docs/PLAYBOOKS.md`. Cheat sheet:
| Add a brew package | Edit `provision/Brewfile` (host/tap tools) or `provision/Brewfile.desktop` (GUI apps). Mise invokes real Homebrew. |
| Onboard another machine | `bash ~/dotfiles/scripts/onboard.sh` (standalone download also documented in `docs/SELF-SAVING-DOTFILES.md`); assumes base tools and GitHub login exist. |
| Provision a workstation | `mise bootstrap`; inventories and the isolated test rig are documented in `docs/BOOTSTRAP.md`. |
| Add a CLAUDE.md hook / MCP server / skill | Edit `dot_claude/settings.json` for hooks/MCP. Drop a `dot_claude/skills/<name>/SKILL.md` for a skill. Run `/discover` after to confirm pickup. |
| Add a CLAUDE.md hook / MCP server / skill | Add hooks/MCP to the `managed` block in `dot_claude/modify_settings.json`. Put a shared skill in `dot_agents/skills/<name>/SKILL.md` with a `symlink_SKILL.md` adapter per harness. Run `/discover` after to confirm pickup. |
| Add a chezmoi template variable | Add to `~/.config/chezmoi/chezmoi.toml` under `[data]`. Reference as `{{ .key }}` in a `.tmpl` file. |
| Add per-machine override | Three options in increasing specificity: chezmoi.toml per machine → hostname branch in `dot_gitconfig.tmpl` → `~/.gitconfig-work` via `includeIf`. See docs/setup.md. |
| Set up the alt git identity on a new machine | `~/dotfiles/scripts/setup-alt-identity.sh` — interactive; writes `~/.gitconfig-alt`, generates `~/.ssh/id_ed25519_alt`, runs `gh auth login` into `~/.config/gh-alt/`. Untracked outputs are per-machine. |
Expand Down
59 changes: 36 additions & 23 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ covers the universal substrate. This file is the Claude-flavored supplement.
| Surface | Where | What it does |
|---|---|---|
| `/discover` skill | `dot_claude/skills/discover/SKILL.md` + `dot_local/bin/executable_claude-discover` | Run when the user asks about enabled hooks, MCP servers, experimental flags, or "what's new." Snapshots the current Claude Code surface and diffs against the last snapshot at `$XDG_STATE_HOME/dotfiles/claude/known-features.json`. |
| `repo-onboarding` skill | `dot_claude/skills/repo-onboarding/SKILL.md` | Read yourself in at session start. Detects stack, conventions, in-flight work. Read-only. |
| Shared skills | `dot_agents/skills/<name>/SKILL.md`, adapted per harness by `dot_claude/skills/<name>/symlink_SKILL.md` | One copy in `~/.agents/skills/`, symlinked into Claude, OpenCode and Hermes. `repo-onboarding`, `blackbird`, `web-research`, `cyclomatic-complexity`, `i-have-adhd`. |
| Custom agents | `dot_claude/agents/*.md` | `terminal-executor` is the only one currently tracked. Add more here, not as untracked files in `~/.claude/agents/`. |
| User settings | `dot_claude/settings.json` | Plugin enables, `effortLevel`, dangerous-mode setting. Tracked. |
| User settings | `dot_claude/modify_settings.json` | A chezmoi `modify_` script, **not** a copied file. It merges the portable managed keys (plugin enables, `effortLevel`, dangerous-mode) into whatever is already on disk, so `herdr`'s live hooks survive every apply. |
| Project-local permissions | `.claude/settings.local.json` (gitignored) | Per-machine, never tracked. The global `~/.config/git/ignore` enforces. |

---
Expand All @@ -23,7 +23,7 @@ All live at `~/.local/bin/` post-`chezmoi apply`. All print to stdout in a form
you can read and present to the user.

```sh
dot-doctor # health check — 27 checks, exit 0/1/2
dot-doctor # health check — one file per check in checks/, exit 0/1/2
dot-doctor --list # list all checks discovered
DOT_SKIP=zsh,claude dot-doctor # skip specific checks
dot-bench # perf vs PERF.md baselines (zsh-bench)
Expand Down Expand Up @@ -60,24 +60,35 @@ file that still says `python3` or `pip`, convert it as part of the change.
When the user asks to add a hook, MCP server, skill, or agent:

1. **Identify the right home:**
- **Hook**: `dot_claude/settings.json` → `hooks` array. Hooks are
**harness-executed**, not Claude-executed — memory and preferences can't
fulfill "automatically do X" requests. Use the `update-config` skill if
available.
- **MCP server**: `dot_claude/settings.json` → `mcpServers` object.
- **Skill**: `dot_claude/skills/<name>/SKILL.md` with frontmatter
(`name`, `description`). Skill body is plain markdown.
- **Hook**: the `managed` block in `dot_claude/modify_settings.json` →
`hooks`. Hooks are **harness-executed**, not Claude-executed — memory and
preferences can't fulfill "automatically do X" requests. Use the
`update-config` skill if available.
- **MCP server**: the `managed` block → `mcpServers`.
- **Skill**: `dot_agents/skills/<name>/SKILL.md`, plus a
`dot_claude/skills/<name>/symlink_SKILL.md` adapter (and the equivalent
under `dot_config/opencode/skill/` and `dot_hermes/skills/` for harnesses
that should also see it). Claude-only skills may live at
`dot_claude/skills/<name>/SKILL.md` — `discover` is the one example.
- **Agent**: `dot_claude/agents/<name>.md` with frontmatter.
- **Slash command**: `dot_claude/commands/<name>.md`.

2. **Edit in the chezmoi source (not in `~/.claude/`)**. Editing `~/.claude/`
directly will be overwritten on next `chezmoi apply`.

`settings.json` is reconciled by a `modify_` script, so only the keys in its
`managed` block are enforced; everything else on disk (herdr's hooks, status
line, project state) is preserved. Shared skills are the mirror image:
`~/.agents/skills/` is a live preference owned by native mise history, and
`dot_agents/skills/` only *seeds* files that are missing — an existing live
file is never overwritten.

3. **Apply + verify:**
```sh
chezmoi diff # confirm scope
chezmoi apply
dot-doctor # claude.sh check verifies settings.json parses + matches source
dot-doctor # claude.sh proves the managed keys took and that
# the merge preserved everything it does not own
```

4. **Confirm discoverability** — run `claude-discover`. New hooks/skills/MCP
Expand All @@ -97,9 +108,9 @@ When the user says "from now on when X, do Y" or "whenever X" or "before/after X
that's a **hook** request. The harness executes hooks; memory and preferences
do not. If you save it as a memory, the rule will be ignored.

Use the `update-config` skill if available; otherwise edit
`dot_claude/settings.json` directly under the `hooks` field, then
`chezmoi apply`, then run `claude-discover` to confirm pickup.
Use the `update-config` skill if available; otherwise add the hook to the
`managed` block in `dot_claude/modify_settings.json`, then `chezmoi apply`,
then run `claude-discover` to confirm pickup.

---

Expand All @@ -109,12 +120,13 @@ Each project (this repo included) can have a `.claude/settings.local.json`
with **host-specific permission allowlists**. By Claude Code convention,
those files are gitignored via the global `~/.config/git/ignore`. They are
NOT tracked, NOT templated, and **must not contain anything that should
follow the user across machines** — that belongs in `dot_claude/settings.json`.
follow the user across machines** — that belongs in
`dot_claude/modify_settings.json`.

If the user wants to broaden permissions for *this* repo, edit
`~/dotfiles/.claude/settings.local.json` (gitignored, per-machine).
If they want it across all projects, edit `dot_claude/settings.json` and
`chezmoi apply`.
If they want it across all projects, add them to the `managed` block in
`dot_claude/modify_settings.json` and `chezmoi apply`.

---

Expand Down Expand Up @@ -143,10 +155,11 @@ The user has an active auto-memory at

---

## Ultrareview / unattended runs
## Deep review / unattended runs

When the user invokes `/ultrareview`, it's a cloud-billed multi-agent review.
You cannot launch it on their behalf. They invoke it; you don't.
`/code-review ultra` is a cloud-billed multi-agent review (`/ultrareview` is a
deprecated alias for the same thing). You cannot launch it on their behalf.
They invoke it; you don't.

For long-running unattended work (`/loop`, `/schedule`), the user has the
`loop` and `schedule` skills available. Suggest them when appropriate.
Expand All @@ -159,9 +172,9 @@ For long-running unattended work (`/loop`, `/schedule`), the user has the
`dot-doctor` / `dot-bench` (where they survive only as terminal output).
- **Skill descriptions are imperatives** in the frontmatter
(`description: Surface the current...`), not third-person.
- **Hooks are documented in their definition** — settings.json comments are
not supported in strict JSON, but you can leave a sibling `.md` under
`dot_claude/` if a hook needs explaining.
- **Hooks are documented in their definition.** `dot_claude/modify_settings.json`
is a shell script wrapping a JSON literal, so a `#` comment above the entry is
the right place to explain one — no sibling `.md` needed.
- **The `/discover` skill is the canonical answer to "what's enabled?"** Use
it; don't reinvent it.

Expand Down
62 changes: 58 additions & 4 deletions checks/blackbird.sh
Original file line number Diff line number Diff line change
@@ -1,14 +1,68 @@
# Blackbird durable coordination.
#
# Two levels of evidence, because they are not always both available. Where the
# service lifecycle is enabled, ask the runtime what it actually resolved --
# OpenCode accepts MCP servers at both .mcp.<name> and .mcp.servers.<name>, and
# a check that hardcodes one spelling reports a healthy daemon as broken. Where
# it is not (a container, a profile that opts out), no daemon is running to ask,
# so assert the configuration declares the integration correctly instead.
hdr "blackbird"
if ! command -v blackbird >/dev/null; then
fail "Blackbird missing — run mise bootstrap"
return 0
fi
config="$HOME/.config/opencode/opencode.jsonc"
if jq -e '.mcp.servers.blackbird.url == "http://127.0.0.1:8081" and any(.plugins[]; type == "object" and .package == "blackbird-opencode@0.1.3" and .options.baseUrl == "http://127.0.0.1:8080" and (.options | has("token") | not))' "$config" >/dev/null; then
ok "MCP and push-delivery connections configured without literal credentials"

bb_configs=()
for config in "$HOME/.config/opencode/opencode.jsonc" "$HOME/.config/opencode/opencode.json"; do
[[ -f "$config" ]] && bb_configs+=("$config")
done

# Accept either MCP placement, in any of the loaded documents.
bb_declared=1
for config in "${bb_configs[@]}"; do
jq -e '((.mcp.blackbird // .mcp.servers.blackbird) | .url) == "http://127.0.0.1:8081"' "$config" >/dev/null 2>&1 && bb_declared=0
done

bb_plugin_declared=1
for config in "${bb_configs[@]}"; do
jq -e 'any((.plugins // [])[]; type == "object" and (.package // "" | startswith("blackbird-opencode")))' "$config" >/dev/null 2>&1 && bb_plugin_declared=0
done

if ! command -v opencode2 >/dev/null 2>&1; then
warn "OpenCode absent — Blackbird delivery integration unverified"
elif services_enabled; then
# A daemon is running, so resolved state is the stronger claim.
if ! mcp_list="$(opencode2 mcp list 2>/dev/null)"; then
fail "OpenCode could not enumerate MCP servers"
elif grep -qE '^\s*✓\s+blackbird\b' <<< "$mcp_list"; then
ok "Blackbird MCP endpoint connected"
elif grep -qE '^\s*[⚠○]\s+blackbird\b' <<< "$mcp_list"; then
fail "Blackbird MCP server is registered but not connected — blackbird doctor"
else
fail "Blackbird MCP server is not registered with OpenCode"
fi
if opencode2 plugin list 2>/dev/null | grep -qE '^\S*blackbird\s'; then
ok "Blackbird push-delivery plugin loaded"
else
fail "Blackbird OpenCode plugin is not loaded — opencode2 plugin list"
fi
else
fail "Blackbird V2 integration invalid"
(( bb_declared )) && fail "Blackbird MCP endpoint is not declared in OpenCode config" \
|| ok "Blackbird MCP endpoint declared"
(( bb_plugin_declared )) && fail "Blackbird push-delivery plugin is not declared in OpenCode config" \
|| ok "Blackbird push-delivery plugin declared"
fi

# A credential belongs in the store, never in a tracked or synced config.
bb_credential_leak=0
for config in "${bb_configs[@]}"; do
if ! jq -e '[(.plugins // [])[] | select(type == "object" and (.package // "" | startswith("blackbird-opencode"))) | .options // {}] | all(has("token") | not)' "$config" >/dev/null 2>&1; then
fail "Blackbird plugin options carry a literal token in ${config/#$HOME/\~} — use the credential store"
bb_credential_leak=1
fi
done
(( bb_credential_leak )) || ok "no literal Blackbird credentials in OpenCode config"

if services_enabled; then
if blackbird doctor >/dev/null 2>&1; then ok "native doctor healthy"
else fail "Blackbird service needs attention — blackbird doctor"; fi
Expand Down
65 changes: 46 additions & 19 deletions checks/claude.sh
Original file line number Diff line number Diff line change
@@ -1,26 +1,60 @@
# claude checks. chezmoi-aware: files are real copies, not symlinks.
# shellcheck shell=bash
# Claude Code. Settings are reconciled by a modify_ script, not copied: herdr
# writes its own hooks into ~/.claude/settings.json live, so chezmoi merges the
# portable managed keys and leaves everything else alone. A plain source-vs-
# target diff is therefore meaningless here -- assert that the managed keys
# actually took, and nothing about the keys we deliberately do not own.

harness_enabled claude || return 0
hdr "claude"

if [[ -f "$HOME/.claude/settings.json" ]]; then
if jq empty "$HOME/.claude/settings.json" 2>/dev/null; then
ok "settings.json parses"
settings="$HOME/.claude/settings.json"
modify="$DOTFILES/dot_claude/modify_settings.json"

if [[ ! -f "$settings" ]]; then
warn "~/.claude/settings.json missing — run 'chezmoi apply'"
elif ! jq -e 'type == "object"' "$settings" >/dev/null 2>&1; then
fail "settings.json does not parse as JSON"
else
ok "settings.json parses"
# The managed block is the contract. Re-derive it from the modify_ script so
# this check cannot drift from what chezmoi actually enforces.
if [[ -x "$modify" ]] && managed="$(sed -n "/^managed='/,/^}'$/p" "$modify" | sed "s/^managed='//; s/^}'$/}/")" \
&& jq -e 'type == "object"' <<< "$managed" >/dev/null 2>&1; then
if jq -e --argjson managed "$managed" '. as $live | $managed | [paths(scalars) as $p | ($live | getpath($p)) == ($managed | getpath($p))] | all' "$settings" >/dev/null 2>&1; then
ok "managed settings keys are applied"
else
warn "managed settings keys diverge — run 'chezmoi apply'"
fi
else
fail "settings.json does not parse as JSON"
fail "dot_claude/modify_settings.json is missing, not executable, or its managed block is unreadable"
fi
fi

# Drift detection: does the applied copy match the chezmoi source?
src="$DOTFILES/dot_claude/settings.json"
if [[ -f "$src" ]] && ! diff -q "$src" "$HOME/.claude/settings.json" >/dev/null 2>&1; then
warn "settings.json diverges from source — run 'chezmoi apply' (or 'chezmoi diff' to inspect)"
# The modify_ script must merge, never replace: a replacing script would erase
# herdr's live hooks on every apply.
if [[ -x "$modify" ]]; then
probe='{"hooks":{"Stop":[{"keep":true}]},"theme":"light"}'
merged="$(printf '%s' "$probe" | "$modify" 2>/dev/null)"
if jq -e '.hooks.Stop[0].keep == true and .theme == "dark"' <<< "$merged" >/dev/null 2>&1; then
ok "modify_settings merges: unmanaged keys survive, managed keys win"
else
ok "settings.json matches source"
fail "modify_settings does not preserve unmanaged keys — it would erase herdr's hooks"
fi
else
warn "~/.claude/settings.json missing — run 'chezmoi apply'"
fi

# Skills reach Claude as symlink adapters into the shared ~/.agents tree.
for adapter in "$DOTFILES"/dot_claude/skills/*/symlink_SKILL.md; do
[[ -e "$adapter" ]] || continue
skill="$(basename "$(dirname "$adapter")")"
live="$HOME/.claude/skills/$skill/SKILL.md"
if [[ -e "$live" ]]; then
ok "claude skill adapter: $skill"
else
warn "claude skill adapter missing: $skill — run 'chezmoi apply'"
fi
done

# Custom agents — tracked count vs applied count.
if [[ -d "$DOTFILES/dot_claude/agents" ]]; then
tracked=$(find "$DOTFILES/dot_claude/agents" -maxdepth 1 -name '*.md' -type f 2>/dev/null | wc -l | tr -d ' ')
Expand All @@ -31,10 +65,3 @@ if [[ -d "$DOTFILES/dot_claude/agents" ]]; then
warn "agent count mismatch — tracked=$tracked applied=$applied. Move untracked agents into \$DOTFILES/dot_claude/agents/ and 'chezmoi apply'"
fi
fi

# settings.local.json (project-local Claude permissions). Gitignored via global.
if [[ -f "$DOTFILES/.claude/settings.local.json" ]] \
&& grep -q "/Users/phall/" "$DOTFILES/.claude/settings.local.json" 2>/dev/null; then
# Project-local file with hardcoded path is fine — it's host-specific anyway.
:
fi
Loading
Loading