@sebastienrousseau/dotfiles 0.2.500 → 0.2.502

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (237) hide show
  1. package/CHANGELOG.md +154 -0
  2. package/README.md +113 -45
  3. package/docs/.vitepress/reports/localization-readability-audit.md +4 -0
  4. package/docs/AI.md +8 -2
  5. package/docs/CNAME +1 -0
  6. package/docs/COPYRIGHT +1 -1
  7. package/docs/NAMING_CONVENTIONS.md +7 -0
  8. package/docs/README.md +4 -0
  9. package/docs/_config.yml +59 -0
  10. package/docs/adr/ADR-001-ci-cd-pipeline.md +17 -0
  11. package/docs/adr/ADR-002-shell-performance.md +9 -0
  12. package/docs/adr/ADR-003-security-first.md +18 -0
  13. package/docs/adr/ADR-004-cli-architecture.md +14 -0
  14. package/docs/adr/ADR-005-chezmoi-choice.md +10 -0
  15. package/docs/adr/ADR-006-shell-selection.md +9 -0
  16. package/docs/adr/ADR-007-multi-shell-parity.md +10 -1
  17. package/docs/adr/ADR-008-alias-system-architecture.md +10 -0
  18. package/docs/adr/ADR-009-wallpaper-driven-theming.md +131 -0
  19. package/docs/adr/ADR-010-starship-transient-prompt.md +144 -0
  20. package/docs/adr/ADR-011-nushell-tier3-keep.md +144 -0
  21. package/docs/adr/README.md +7 -0
  22. package/docs/architecture/ARCHITECTURE.md +4 -0
  23. package/docs/architecture/INTEROP.md +8 -0
  24. package/docs/architecture/REPO_LAYOUT.md +5 -1
  25. package/docs/architecture/WALKTHROUGH.md +4 -0
  26. package/docs/architecture/fleet-deployment.md +4 -0
  27. package/docs/archive/EUXIS_2026_REVIEW.md +11 -3
  28. package/docs/archive/LEGACY_ROADMAP.md +45 -27
  29. package/docs/archive/MILESTONE_v0.2.493.md +4 -0
  30. package/docs/archive/PLAN.md +46 -8
  31. package/docs/archive/REPO_AUDIT.md +8 -0
  32. package/docs/guides/INSTALL.md +4 -0
  33. package/docs/guides/NEOVIM_IDE_GUIDE.md +9 -0
  34. package/docs/guides/THEMING.md +8 -0
  35. package/docs/guides/TROUBLESHOOTING.md +28 -0
  36. package/docs/guides/WSL2_NIX_TROUBLESHOOTING.md +70 -1
  37. package/docs/index.md +6 -2
  38. package/docs/interop/A2A.md +7 -0
  39. package/docs/interop/POWERSHELL.md +102 -0
  40. package/docs/manual/00-introduction.md +5 -1
  41. package/docs/manual/01-concepts/01-architecture.md +4 -0
  42. package/docs/manual/01-concepts/02-trust-model.md +6 -2
  43. package/docs/manual/01-concepts/03-theme-engine.md +4 -0
  44. package/docs/manual/01-concepts/04-fleet.md +7 -1
  45. package/docs/manual/01-concepts/05-self-healing.md +8 -1
  46. package/docs/manual/02-tutorials/01-first-install.md +5 -0
  47. package/docs/manual/02-tutorials/02-add-wallpaper.md +5 -0
  48. package/docs/manual/02-tutorials/03-create-profile.md +6 -0
  49. package/docs/manual/02-tutorials/04-encrypt-secret.md +6 -0
  50. package/docs/manual/02-tutorials/05-deploy-fleet.md +5 -1
  51. package/docs/manual/03-reference/01-dot-cli.md +67 -45
  52. package/docs/manual/03-reference/02-config-files.md +8 -2
  53. package/docs/manual/03-reference/03-environment.md +4 -0
  54. package/docs/manual/03-reference/04-templates.md +7 -1
  55. package/docs/manual/03-reference/05-feature-flags.md +72 -3
  56. package/docs/manual/04-cookbook/01-recipes.md +4 -0
  57. package/docs/manual/04-cookbook/02-troubleshooting.md +32 -0
  58. package/docs/manual/04-cookbook/03-faq.md +8 -0
  59. package/docs/manual/05-appendices/A-platform-matrix.md +4 -0
  60. package/docs/manual/05-appendices/B-security-checklist.md +6 -0
  61. package/docs/manual/05-appendices/C-glossary.md +4 -0
  62. package/docs/manual/05-appendices/D-bibliography.md +5 -1
  63. package/docs/manual/05-appendices/E-license.md +4 -0
  64. package/docs/manual/_toc.yml +1 -1
  65. package/docs/manual/command-index.md +16 -8
  66. package/docs/manual/concept-index.md +4 -0
  67. package/docs/manual/index.md +66 -0
  68. package/docs/operations/ATTESTATION.md +5 -0
  69. package/docs/operations/CI_CADENCE.md +107 -0
  70. package/docs/operations/CI_COMPOSITES.md +156 -0
  71. package/docs/operations/COMPLETIONS.md +123 -0
  72. package/docs/operations/COVERAGE.md +182 -0
  73. package/docs/operations/DRIFT.md +107 -0
  74. package/docs/operations/HARD_AUDIT_2026.md +631 -0
  75. package/docs/operations/MAINTENANCE.md +5 -1
  76. package/docs/operations/MIGRATION.md +14 -6
  77. package/docs/operations/OPERATIONS.md +24 -0
  78. package/docs/operations/PERFORMANCE.md +133 -0
  79. package/docs/operations/REGISTRY.md +89 -0
  80. package/docs/operations/RELIABILITY.md +6 -0
  81. package/docs/operations/ROADMAP.md +36 -18
  82. package/docs/operations/ROADMAP_2026.md +665 -0
  83. package/docs/operations/TESTING.md +4 -0
  84. package/docs/operations/TRACEABILITY.md +7 -0
  85. package/docs/operations/TRUSTED_AGENT_WORKSTATION.md +4 -0
  86. package/docs/operations/VERSION_SYNC.md +54 -5
  87. package/docs/reference/ALIASES.md +7 -0
  88. package/docs/reference/ALIASES_CHEATSHEET.md +5 -1
  89. package/docs/reference/ALIASES_DEPRECATIONS.md +5 -1
  90. package/docs/reference/FEATURES.md +4 -0
  91. package/docs/reference/FONTS.md +4 -0
  92. package/docs/reference/POWERSHELL_PARITY.md +80 -0
  93. package/docs/reference/PROFILES.md +4 -0
  94. package/docs/reference/SCREENSHOTS.md +4 -0
  95. package/docs/reference/SCRIPTS.md +4 -0
  96. package/docs/reference/SUPPORT_MATRIX.md +10 -4
  97. package/docs/reference/THEMES.md +4 -0
  98. package/docs/reference/TOOLS.md +4 -0
  99. package/docs/reference/UTILS.md +16 -12
  100. package/docs/registry.json +6 -0
  101. package/docs/security/AI_ACT_COMPLIANCE.md +4 -0
  102. package/docs/security/AUDIT_BYPASS.md +103 -0
  103. package/docs/security/AUTOMATION_SECRETS.md +4 -0
  104. package/docs/security/CI_EGRESS_ALLOWLIST.md +127 -0
  105. package/docs/security/CI_PINNING.md +113 -0
  106. package/docs/security/COMMIT_SIGNING.md +138 -0
  107. package/docs/security/COMPLIANCE.md +5 -0
  108. package/docs/security/DEPS_DEV_EXCEPTIONS.md +86 -0
  109. package/docs/security/DISCLOSURE.md +130 -0
  110. package/docs/security/ENCRYPTION.md +5 -0
  111. package/docs/security/FMEA.md +4 -0
  112. package/docs/security/HISTORY_FILTERING.md +132 -0
  113. package/docs/security/INCIDENT_RESPONSE.md +4 -0
  114. package/docs/security/INSTALL_VERIFICATION.md +122 -0
  115. package/docs/security/KEYS.md +4 -0
  116. package/docs/security/KEY_ROTATION.md +85 -1
  117. package/docs/security/MCP_POLICY.md +9 -0
  118. package/docs/security/POLICY_RELEASES.md +4 -0
  119. package/docs/security/README.md +4 -0
  120. package/docs/security/SCORECARD.md +140 -0
  121. package/docs/security/SECRETS.md +12 -0
  122. package/docs/security/SECURITY.md +4 -0
  123. package/docs/security/SECURITY_CHECKLIST.md +11 -0
  124. package/docs/security/SHELL_EXEMPTIONS.md +145 -0
  125. package/docs/security/SOUP_REGISTER.md +4 -0
  126. package/docs/security/THREAT_MODEL.md +10 -0
  127. package/docs/security/VERIFICATION_VALIDATION.md +5 -1
  128. package/docs/security/security-pubkey.asc +15 -0
  129. package/docs/themes/README.md +4 -0
  130. package/docs/themes/VISUAL_INTEGRITY_REPORT.md +4 -0
  131. package/dot_config/ai/identity.md +3 -0
  132. package/dot_config/ai/patterns/architect.md +2 -0
  133. package/dot_config/ai/patterns/hardener.md +2 -0
  134. package/dot_config/ai/patterns/refactor.md +2 -0
  135. package/dot_config/alacritty/alacritty.toml.tmpl +3 -3
  136. package/dot_config/atuin/config.toml.tmpl +47 -0
  137. package/dot_config/dotfiles/agent-card.json +1 -1
  138. package/dot_config/dotfiles/boot/README.md +2 -0
  139. package/dot_config/dotfiles/grub/README.md +2 -0
  140. package/dot_config/dotfiles/lock/README.md +2 -0
  141. package/dot_config/fish/conf.d/direnv.fish +4 -0
  142. package/dot_config/fish/conf.d/init.fish.tmpl +21 -0
  143. package/dot_config/fish/conf.d/mise-activate.fish +5 -0
  144. package/dot_config/fish/functions/_cached_eval.fish +84 -11
  145. package/dot_config/fish/functions/_cached_eval_clear.fish +17 -0
  146. package/dot_config/foot/foot.ini.tmpl +3 -3
  147. package/dot_config/fuzzel/fuzzel.ini.tmpl +2 -2
  148. package/dot_config/ghostty/config.tmpl +3 -3
  149. package/dot_config/git/hooks/executable_commit-msg +146 -0
  150. package/dot_config/goose/config.yaml +2 -2
  151. package/dot_config/gtk-3.0/gtk.css.tmpl +2 -2
  152. package/dot_config/gtk-3.0/settings.ini.tmpl +2 -2
  153. package/dot_config/gtk-4.0/gtk.css.tmpl +2 -2
  154. package/dot_config/gtk-4.0/settings.ini.tmpl +2 -2
  155. package/dot_config/kitty/kitty.conf.tmpl +3 -3
  156. package/dot_config/mise/config.toml +1 -1
  157. package/dot_config/niri/config.kdl.tmpl +2 -2
  158. package/dot_config/nushell/cached_eval.nu +80 -0
  159. package/dot_config/nushell/env.nu.tmpl +21 -13
  160. package/dot_config/shell/00-core-paths.sh.tmpl +9 -1
  161. package/dot_config/shell/05-core-safety.sh +1 -0
  162. package/dot_config/shell/10-secrets.sh +1 -0
  163. package/dot_config/shell/40-fzf-defaults.sh.tmpl +1 -0
  164. package/dot_config/shell/40-ls-colors.sh +1 -0
  165. package/dot_config/shell/50-logic-functions-core.sh.tmpl +1 -0
  166. package/dot_config/shell/50-logic-functions.sh.tmpl +1 -0
  167. package/dot_config/shell/51-logic-functions-extra.sh.tmpl +1 -0
  168. package/dot_config/shell/90-ux-aliases.sh.tmpl +1 -0
  169. package/dot_config/shell/91-ux-aliases-lazy.sh.tmpl +1 -0
  170. package/dot_config/shell/README.md +25 -8
  171. package/dot_config/starship.toml.tmpl +2 -2
  172. package/dot_config/tmux/tmux.conf.tmpl +3 -3
  173. package/dot_config/user-dirs.dirs +1 -0
  174. package/dot_config/vscode/settings.json.tmpl +2 -2
  175. package/dot_config/waybar/config.jsonc.tmpl +2 -2
  176. package/dot_config/waybar/style.css.tmpl +2 -2
  177. package/dot_config/wezterm/wezterm.lua.tmpl +3 -3
  178. package/dot_config/zsh/dot_zshrc.tmpl +207 -17
  179. package/dot_config/zsh/rc.d/00-alias-shims.zsh +28 -6
  180. package/dot_config/zsh/rc.d/30-options.zsh.tmpl +27 -7
  181. package/dot_local/bin/executable_bm +2 -0
  182. package/dot_local/bin/executable_dot +56 -9
  183. package/dot_local/bin/executable_dot-bootstrap +0 -1
  184. package/dot_local/bin/executable_dot-load-benchmark +1 -1
  185. package/dot_local/bin/executable_dot-theme-sync +8 -8
  186. package/dot_local/bin/executable_notify +2 -0
  187. package/dot_local/bin/executable_open +2 -0
  188. package/dot_local/bin/executable_tour +4 -2
  189. package/dot_local/bin/executable_up +3 -1
  190. package/dot_local/share/man/man1/dot.1 +1 -1
  191. package/dot_local/share/zsh/completions/_dot +4 -0
  192. package/install.sh +53 -38
  193. package/package.json +1 -1
  194. package/scripts/ci/check-dangerous-chmod.sh +19 -0
  195. package/scripts/ci/check-deps-dev.sh +236 -0
  196. package/scripts/ci/check-insecure-tls.sh +61 -0
  197. package/scripts/ci/check-regression-traceability.sh +67 -0
  198. package/scripts/ci/check-shell-preamble.sh +106 -0
  199. package/scripts/ci/dot-cli-startup-bench.sh +126 -0
  200. package/scripts/ci/install-chezmoi-verified.sh +4 -1
  201. package/scripts/ci/lint-reusable-pins.sh +78 -0
  202. package/scripts/ci/run-coverage.sh +451 -0
  203. package/scripts/ci/validate-chezmoidata.sh +25 -0
  204. package/scripts/ci/windows-smoke-test.ps1 +136 -0
  205. package/scripts/diagnostics/doctor.sh +203 -5
  206. package/scripts/diagnostics/drift-dashboard.sh +177 -13
  207. package/scripts/diagnostics/health.sh +21 -4
  208. package/scripts/diagnostics/perf.sh +304 -77
  209. package/scripts/diagnostics/workstation-attestation.sh +6 -1
  210. package/scripts/dot/commands/agent.sh +33 -27
  211. package/scripts/dot/commands/agents.sh +325 -0
  212. package/scripts/dot/commands/ai.sh +75 -10
  213. package/scripts/dot/commands/aliases.sh +10 -8
  214. package/scripts/dot/commands/core.sh +10 -4
  215. package/scripts/dot/commands/fleet.sh +278 -3
  216. package/scripts/dot/commands/init.sh +184 -0
  217. package/scripts/dot/commands/meta.sh +7 -4
  218. package/scripts/dot/commands/registry.sh +263 -0
  219. package/scripts/dot/commands/tools.sh +49 -1
  220. package/scripts/dot/lib/bento.sh +2 -1
  221. package/scripts/dot/lib/log.sh +6 -0
  222. package/scripts/dot/lib/platform.sh +22 -8
  223. package/scripts/dot/lib/ui.sh +145 -2
  224. package/scripts/dot/lib/utils.sh +6 -1
  225. package/scripts/git-hooks/pre-commit-audit.sh +1 -1
  226. package/scripts/git-hooks/pre-push +66 -3
  227. package/scripts/lib/secrets_provider.sh +32 -6
  228. package/scripts/ops/heal-chezmoi.sh +41 -6
  229. package/scripts/ops/rollback.sh +14 -0
  230. package/scripts/qa/powershell-contract.ps1 +95 -0
  231. package/scripts/security/check-disclosure-key-expiry.sh +110 -0
  232. package/scripts/security/lock-configs.sh +11 -2
  233. package/scripts/theme/merge-wallpaper.sh +4 -0
  234. package/scripts/theme/switch.sh +20 -10
  235. package/scripts/version-sync.sh +3 -0
  236. package/dot_config/atuin/config.toml +0 -40
  237. package/dot_local/bin/__pycache__/executable_dot-load-benchmark-ptycpython-312.pyc +0 -0
@@ -0,0 +1,325 @@
1
+ #!/usr/bin/env bash
2
+ # Copyright (c) 2015-2026 Dotfiles. All rights reserved.
3
+ # shellcheck shell=bash
4
+ #
5
+ # scripts/dot/commands/agents.sh
6
+ #
7
+ # `dot agents` — multi-harness AI agent configuration manager.
8
+ #
9
+ # Closes the #1 competitive gap identified in HARD_AUDIT_2026:
10
+ # every other dotfiles framework either targets one AI tool or
11
+ # requires hand-maintenance of N parallel config files. This command
12
+ # keeps CLAUDE.md (canonical) and AGENTS.md (cross-harness standard)
13
+ # in sync, plus stubs the Cursor/Codex tool-specific formats.
14
+ #
15
+ # Subcommands:
16
+ # render Regenerate AGENTS.md and tool-specific stubs from CLAUDE.md.
17
+ # check Verify AGENTS.md tracks CLAUDE.md (exit 0 in sync, 1 drifted).
18
+ # list Show which harnesses are recognised + their target paths.
19
+ #
20
+ # Reads: CLAUDE.md (repo root) — the canonical agent context.
21
+ # Writes: AGENTS.md, .cursor/rules/dotfiles.mdc, .codex/config.toml
22
+ # (only when invoked with `render`).
23
+
24
+ set -euo pipefail
25
+
26
+ # shellcheck disable=SC1091
27
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
28
+ source "$SCRIPT_DIR/../lib/ui.sh"
29
+ source "$SCRIPT_DIR/../lib/utils.sh"
30
+
31
+ _agents_repo_root() {
32
+ # Resolve the chezmoi source dir (where CLAUDE.md/AGENTS.md live).
33
+ # We REQUIRE the resolved dir to contain `.chezmoidata.toml` so a
34
+ # user running `dot agents render` from inside some other git
35
+ # checkout doesn't accidentally write CLAUDE.md/AGENTS.md/.cursor/
36
+ # /.codex/ into that repo. Round-2 audit C-finding.
37
+ #
38
+ # On a CI runner `chezmoi source-path` may return a default path
39
+ # like `$HOME/.local/share/chezmoi` that doesn't exist on disk —
40
+ # we treat that as "not a match" and fall through to git, rather
41
+ # than accepting the wrong candidate.
42
+ local candidate=""
43
+ if command -v chezmoi >/dev/null 2>&1; then
44
+ candidate="$(chezmoi source-path 2>/dev/null || true)"
45
+ if [[ -n "$candidate" && ! -f "$candidate/.chezmoidata.toml" ]]; then
46
+ candidate=""
47
+ fi
48
+ fi
49
+ if [[ -z "$candidate" ]]; then
50
+ candidate="$(git -C "$PWD" rev-parse --show-toplevel 2>/dev/null || true)"
51
+ fi
52
+ if [[ -z "$candidate" ]] || [[ ! -f "$candidate/.chezmoidata.toml" ]]; then
53
+ return 1
54
+ fi
55
+ printf '%s\n' "$candidate"
56
+ }
57
+
58
+ _agents_canonical() {
59
+ printf "%s/CLAUDE.md" "$(_agents_repo_root)"
60
+ }
61
+
62
+ _agents_targets() {
63
+ # printed one-per-line: <harness>\t<path-relative-to-repo-root>
64
+ # Closes the round-2 audit gap #3 — harness parity with
65
+ # TonyCasey/ai-dotfiles-manager (who covers 9 surfaces; we now
66
+ # cover 12 to maintain a margin).
67
+ local root
68
+ root="$(_agents_repo_root)"
69
+ cat <<EOF
70
+ agents-md $root/AGENTS.md
71
+ cursor $root/.cursor/rules/dotfiles.mdc
72
+ codex $root/.codex/config.toml
73
+ windsurf $root/.windsurf/rules.md
74
+ zed $root/.zed/agent-config.toml
75
+ roo $root/.roo/rules.md
76
+ cline $root/.clinerules
77
+ aider $root/.aider.conf.yml
78
+ continue $root/.continuerc.json
79
+ jules $root/.jules/system.md
80
+ gemini $root/.gemini/GEMINI.md
81
+ EOF
82
+ }
83
+
84
+ # Strip the leading HTML comment header (everything up to the first blank
85
+ # line after the `-->`), the H1 title line (which differs by design
86
+ # between CLAUDE.md / AGENTS.md), and the trailing cross-reference
87
+ # block. Leaves the comparable content body.
88
+ _agents_body() {
89
+ local file="$1"
90
+ awk '
91
+ BEGIN { in_header = 0; saw_close = 0; emit = 0 }
92
+ /^<!--/ && NR <= 5 { in_header = 1; next }
93
+ in_header && /-->/ { in_header = 0; saw_close = 1; next }
94
+ in_header { next }
95
+ saw_close && /^$/ && !emit { emit = 1; next }
96
+ saw_close && emit { print }
97
+ !saw_close { emit = 1; print }
98
+ ' "$file" |
99
+ # Drop the H1 (`# CLAUDE.md ...` or `# AGENTS.md ...`) and the
100
+ # trailing "Need richer context?" footer if present.
101
+ awk '
102
+ /^# (CLAUDE|AGENTS)\.md/ { next }
103
+ /^---$/ { trailer = 1; next }
104
+ trailer && /^\*\*Need richer context\?\*\*/ { next }
105
+ trailer && NF == 0 { next }
106
+ { trailer = 0; print }
107
+ '
108
+ }
109
+
110
+ cmd_agents() {
111
+ local subcommand="${1:-list}"
112
+ shift || true
113
+
114
+ case "$subcommand" in
115
+ list)
116
+ ui_header "Agent harness targets"
117
+ echo ""
118
+ ui_table_begin "Harness" "Target Path" "Status"
119
+ while IFS=$'\t' read -r harness path; do
120
+ if [[ -f "$path" ]]; then
121
+ ui_table_add "$harness" "$path" "rendered"
122
+ else
123
+ ui_table_add "$harness" "$path" "not yet rendered"
124
+ fi
125
+ done < <(_agents_targets)
126
+ ui_table_end
127
+ ;;
128
+ check)
129
+ local claude_md agents_md
130
+ claude_md="$(_agents_canonical)"
131
+ agents_md="$(_agents_repo_root)/AGENTS.md"
132
+ if [[ ! -f "$claude_md" ]]; then
133
+ ui_err "CLAUDE.md" "not found at $claude_md"
134
+ return 2
135
+ fi
136
+ if [[ ! -f "$agents_md" ]]; then
137
+ ui_warn "AGENTS.md" "missing — run 'dot agents render'"
138
+ return 1
139
+ fi
140
+ # Diff the bodies (header comments differ by design).
141
+ # `--ignore-blank-lines` so the trailing newline from the footer
142
+ # block doesn't false-positive as drift.
143
+ if diff -q --ignore-blank-lines <(_agents_body "$claude_md") <(_agents_body "$agents_md") >/dev/null 2>&1; then
144
+ ui_ok "AGENTS.md" "in sync with CLAUDE.md"
145
+ return 0
146
+ fi
147
+ ui_warn "AGENTS.md" "drifted from CLAUDE.md — run 'dot agents render'"
148
+ return 1
149
+ ;;
150
+ render)
151
+ local claude_md root
152
+ claude_md="$(_agents_canonical)"
153
+ root="$(_agents_repo_root)"
154
+ [[ -f "$claude_md" ]] || {
155
+ ui_err "CLAUDE.md" "not found at $claude_md"
156
+ return 2
157
+ }
158
+
159
+ # 1. AGENTS.md — body of CLAUDE.md + AGENTS.md cross-reference header.
160
+ local agents_md="$root/AGENTS.md"
161
+ {
162
+ cat <<'HEADER'
163
+ <!--
164
+ AGENTS.md — Cross-harness AI agent guidelines for this repository.
165
+
166
+ This file follows the AGENTS.md standard (originated by OpenAI in
167
+ August 2025, stewarded since December 2025 by the Linux Foundation
168
+ Agentic AI Foundation). Native readers: Codex CLI, GitHub Copilot,
169
+ Cursor, Windsurf, Amp, Devin, and a growing list of other agents.
170
+
171
+ Canonical source: CLAUDE.md (Claude Code uses CLAUDE.md natively).
172
+ This file is kept in sync via `dot agents render`. Edit CLAUDE.md
173
+ first; do not hand-edit AGENTS.md.
174
+ -->
175
+
176
+ HEADER
177
+ # Replace the title line so the rendered file declares its
178
+ # purpose, but pass everything else through unchanged.
179
+ _agents_body "$claude_md" | sed '1s/^# CLAUDE\.md.*/# AGENTS.md — AI Assistant Guidelines/'
180
+ cat <<'FOOTER'
181
+
182
+ ---
183
+
184
+ **Need richer context?** This file is the cross-harness summary. Claude Code reads the full canonical version from [`CLAUDE.md`](./CLAUDE.md). Both files are kept in sync via `dot agents render`.
185
+ FOOTER
186
+ } >"$agents_md"
187
+ chmod 0644 "$agents_md" 2>/dev/null || true
188
+ ui_ok "AGENTS.md" "rendered → $agents_md"
189
+
190
+ # 2. Cursor rules — MDC format, points at CLAUDE.md/AGENTS.md.
191
+ local cursor_dir="$root/.cursor/rules"
192
+ mkdir -p "$cursor_dir"
193
+ cat >"$cursor_dir/dotfiles.mdc" <<'MDC'
194
+ ---
195
+ description: Repo conventions for the dotfiles project (sourced from CLAUDE.md/AGENTS.md)
196
+ globs:
197
+ - "**/*"
198
+ alwaysApply: true
199
+ ---
200
+
201
+ See `AGENTS.md` and `CLAUDE.md` in the repository root for the full
202
+ project conventions, repository layout, testing, and CI policy. This
203
+ Cursor rule file exists so Cursor's rule engine picks up the same
204
+ context; do not duplicate content here — keep CLAUDE.md canonical.
205
+ MDC
206
+ chmod 0644 "$cursor_dir/dotfiles.mdc" 2>/dev/null || true
207
+ ui_ok "Cursor" "rendered → $cursor_dir/dotfiles.mdc"
208
+
209
+ # 3. Codex CLI config stub — declares the AGENTS.md path.
210
+ local codex_dir="$root/.codex"
211
+ mkdir -p "$codex_dir"
212
+ cat >"$codex_dir/config.toml" <<'TOML'
213
+ # Codex CLI config — points at the AGENTS.md cross-harness context.
214
+ # Codex reads AGENTS.md natively; this file is a project-scoped pin so
215
+ # the CLI prefers the in-repo guidance over any global default.
216
+ project_context = "AGENTS.md"
217
+ TOML
218
+ chmod 0644 "$codex_dir/config.toml" 2>/dev/null || true
219
+ ui_ok "Codex" "rendered → $codex_dir/config.toml"
220
+
221
+ # 4-11. Per-harness rules files. All eight emitters reuse the
222
+ # same body extracted from CLAUDE.md so a single edit propagates
223
+ # consistently. The header differs per harness so each tool sees
224
+ # syntax it expects (front-matter style, comment block, etc.).
225
+ _agents_render_markdown_with_header() {
226
+ local _path="$1" _harness="$2" _header="$3"
227
+ mkdir -p "$(dirname "$_path")"
228
+ {
229
+ printf '%s\n\n' "$_header"
230
+ _agents_body "$claude_md"
231
+ # Heredoc instead of printf — Codacy/shellcheck flags
232
+ # printf-with-backticks-in-single-quotes (SC2016) as
233
+ # ambiguous even when the backticks are literal Markdown.
234
+ cat <<'FOOTER'
235
+
236
+ ---
237
+
238
+ **Canonical source:** [`CLAUDE.md`](./CLAUDE.md) — keep in sync via `dot agents render`.
239
+ FOOTER
240
+ } >"$_path"
241
+ chmod 0644 "$_path" 2>/dev/null || true
242
+ ui_ok "$_harness" "rendered → $_path"
243
+ }
244
+
245
+ # 4. Windsurf — looks for `.windsurf/rules.md`.
246
+ _agents_render_markdown_with_header "$root/.windsurf/rules.md" \
247
+ "Windsurf" "# Windsurf project rules
248
+
249
+ These rules govern Cascade and the Windsurf agent inside this repository."
250
+
251
+ # 5. Roo — looks for `.roo/rules.md`.
252
+ _agents_render_markdown_with_header "$root/.roo/rules.md" \
253
+ "Roo" "# Roo project rules"
254
+
255
+ # 6. Cline — looks for `.clinerules` (no extension).
256
+ _agents_render_markdown_with_header "$root/.clinerules" \
257
+ "Cline" "# Cline workspace rules"
258
+
259
+ # 7. Jules — looks for `.jules/system.md`.
260
+ _agents_render_markdown_with_header "$root/.jules/system.md" \
261
+ "Jules" "# Jules system prompt"
262
+
263
+ # 8. Gemini — looks for `.gemini/GEMINI.md`.
264
+ _agents_render_markdown_with_header "$root/.gemini/GEMINI.md" \
265
+ "Gemini" "# Gemini agent rules"
266
+
267
+ # 9. Zed — config pointer (TOML).
268
+ local zed_dir="$root/.zed"
269
+ mkdir -p "$zed_dir"
270
+ cat >"$zed_dir/agent-config.toml" <<'TOML'
271
+ # Zed agent config — points at AGENTS.md for the cross-harness body.
272
+ # Zed reads this file when its agent mode is enabled; the actual rule
273
+ # body lives in AGENTS.md (which `dot agents render` keeps current).
274
+ agent_context = "AGENTS.md"
275
+ TOML
276
+ chmod 0644 "$zed_dir/agent-config.toml" 2>/dev/null || true
277
+ ui_ok "Zed" "rendered → $zed_dir/agent-config.toml"
278
+
279
+ # 10. Aider — YAML pointer to AGENTS.md / CLAUDE.md.
280
+ cat >"$root/.aider.conf.yml" <<'YML'
281
+ # Aider config — surfaces the cross-harness context bundle.
282
+ # Aider's `--read` flag pulls in AGENTS.md / CLAUDE.md per session.
283
+ read:
284
+ - AGENTS.md
285
+ - CLAUDE.md
286
+ YML
287
+ chmod 0644 "$root/.aider.conf.yml" 2>/dev/null || true
288
+ ui_ok "Aider" "rendered → $root/.aider.conf.yml"
289
+
290
+ # 11. Continue — JSON pointer used by VS Code / JetBrains plugin.
291
+ cat >"$root/.continuerc.json" <<'JSON'
292
+ {
293
+ "_comment": "Continue config pointer — see AGENTS.md for the full body.",
294
+ "systemMessage": "Apply the rules in AGENTS.md (canonical source: CLAUDE.md). Run `dot agents render` if the two drift."
295
+ }
296
+ JSON
297
+ chmod 0644 "$root/.continuerc.json" 2>/dev/null || true
298
+ ui_ok "Continue" "rendered → $root/.continuerc.json"
299
+
300
+ ui_info "Hint" "commit AGENTS.md alongside CLAUDE.md changes (or add to your pre-commit hook)"
301
+ ;;
302
+ --help | -h | help)
303
+ cat <<EOF
304
+ Usage: dot agents <subcommand>
305
+
306
+ Subcommands:
307
+ list Show which agent harnesses are recognised and their target paths
308
+ check Verify AGENTS.md tracks CLAUDE.md (exit 0 in sync, 1 drifted)
309
+ render Regenerate AGENTS.md + 10 harness-specific files from CLAUDE.md
310
+
311
+ CLAUDE.md is the canonical source. AGENTS.md follows the cross-harness
312
+ standard read by Codex, Copilot, Cursor, Windsurf, Amp, and Devin.
313
+
314
+ Harnesses covered by 'render':
315
+ agents-md, cursor, codex, windsurf, zed, roo, cline,
316
+ aider, continue, jules, gemini.
317
+ EOF
318
+ ;;
319
+ *)
320
+ ui_err "Unknown subcommand" "$subcommand"
321
+ echo "Run 'dot agents --help' for usage." >&2
322
+ return 1
323
+ ;;
324
+ esac
325
+ }
@@ -28,9 +28,10 @@ if [[ ! -d "$PATTERN_DIR" ]]; then
28
28
  fi
29
29
 
30
30
  _show_ai_bridge_usage() {
31
- echo "Usage: dot cl|copilot|gemini|kiro|autohand|vibe|qwen|zai --pattern [name] \"prompt\""
31
+ echo "Usage: dot cl|codex|copilot|gemini|goose|kiro|autohand|vibe|qwen|zai --pattern [name] \"prompt\""
32
32
  echo ""
33
33
  echo "Available Patterns:"
34
+ # shellcheck disable=SC2012
34
35
  ls -1 "$PATTERN_DIR" 2>/dev/null | sed 's/\.md$//' | sed 's/^/ - /' || echo " (none)"
35
36
  }
36
37
 
@@ -57,18 +58,72 @@ _ai_refresh_status_cache() {
57
58
  tmp_file="$(mktemp)"
58
59
  mkdir -p "$AI_CACHE_DIR"
59
60
 
60
- local entry category role name bin desc present version
61
+ local total=${#ai_entries[@]}
62
+
63
+ # Cold-cache refresh runs `$bin --version` for every tool — node-
64
+ # based ones are slow to start, so the total can hit 15-30s. Show a
65
+ # spinner so the user has feedback.
66
+ ui_spinner_start "Probing $total AI tools (cached for ${AI_STATUS_TTL}s)"
67
+
68
+ local jobs="${DOTFILES_AI_PROBE_JOBS:-$(nproc 2>/dev/null || sysctl -n hw.ncpu 2>/dev/null || echo 4)}"
69
+ local probe_dir
70
+ probe_dir="$(mktemp -d)"
71
+
72
+ # Probe via xargs -P. The probe logic lives INLINE in the bash -c
73
+ # string rather than as an exported function, because `export -f`
74
+ # doesn't always survive across bash invocations on every platform
75
+ # (notably macOS bash 3.2 needs the BASH_FUNC_*() env-var format,
76
+ # which subtly breaks for some shells in PATH). Inlining sidesteps
77
+ # the inheritance question entirely.
78
+ local i=0
79
+ local entry
80
+ local indexed=()
61
81
  for entry in "${ai_entries[@]}"; do
62
- IFS='|' read -r category role name bin desc <<<"$entry"
63
- if has_command "$bin"; then
64
- present=1
65
- version=$(_ai_extract_version "$bin")
82
+ indexed+=("$i|$entry")
83
+ i=$((i + 1))
84
+ done
85
+ # shellcheck disable=SC2016
86
+ local probe_script='
87
+ payload="$1"
88
+ out_dir="$2"
89
+ i="${payload%%|*}"
90
+ entry="${payload#*|}"
91
+ IFS="|" read -r category role name bin desc <<<"$entry"
92
+ if command -v "$bin" >/dev/null 2>&1; then
93
+ output=$("$bin" --version 2>/dev/null | head -1) || true
94
+ version=$(printf "%s" "$output" | sed "s/^[^0-9]*//" | sed "s/[[:space:]]*$//" | sed "s/\.$//")
95
+ printf "%s\t1\t%s\n" "$bin" "$version" >"$out_dir/$i"
66
96
  else
67
- present=0
68
- version=""
97
+ printf "%s\t0\t\n" "$bin" >"$out_dir/$i"
69
98
  fi
70
- printf '%s\t%s\t%s\n' "$bin" "$present" "$version" >>"$tmp_file"
99
+ '
100
+ # NOTE: `-I{}` already implies one input line per invocation. Adding
101
+ # `-n1` on top triggers a BSD-xargs quirk where the input line is
102
+ # word-split on whitespace ("0|Agents (autonomous)|..." → multiple
103
+ # entries). Use only `-I{}`.
104
+ #
105
+ # ALSO: feed null-delimited records (`-0`) so apostrophes and
106
+ # other quote-like characters in the descriptions ("Block's coding
107
+ # agent") don't trigger xargs's "unterminated quote" parser.
108
+ printf '%s\0' "${indexed[@]}" |
109
+ xargs -0 -I{} -P"$jobs" \
110
+ bash -c "$probe_script" _ {} "$probe_dir" \
111
+ 2>/dev/null || true
112
+
113
+ # Re-assemble in original entry order.
114
+ local n
115
+ for ((n = 0; n < i; n++)); do
116
+ [[ -f "$probe_dir/$n" ]] && cat "$probe_dir/$n" >>"$tmp_file"
71
117
  done
118
+ rm -rf "$probe_dir"
119
+
120
+ # Guard with `|| true` because ui_spinner_stop's last line evaluates
121
+ # to rc=1 when stdout is a TTY (the `[[ ! -t 1 ]] && printf` short-
122
+ # circuit). Under `set -euo pipefail` that rc would kill the script
123
+ # right before we get to write the cache, leaving the user with a
124
+ # silent broken cold-cache run. Defence in depth — the function
125
+ # now also has an explicit `return 0` upstream.
126
+ ui_spinner_stop || true
72
127
 
73
128
  mv "$tmp_file" "$AI_STATUS_CACHE_FILE"
74
129
  }
@@ -81,7 +136,9 @@ _ai_get_cached_status() {
81
136
  _ai_mise_pkg() {
82
137
  case "$1" in
83
138
  claude) echo "npm:@anthropic-ai/claude-code" ;;
139
+ codex) echo "npm:@openai/codex" ;;
84
140
  copilot) echo "npm:@github/copilot" ;;
141
+ goose) echo "pipx:goose-ai" ;;
85
142
  aider) echo "pipx:aider-chat" ;;
86
143
  opencode) echo "npm:opencode-ai" ;;
87
144
  sgpt) echo "pipx:shell-gpt" ;;
@@ -102,7 +159,9 @@ cmd_ai_status() {
102
159
  # category|role|name|binary|description
103
160
  local -a ai_clis=(
104
161
  "Agents (autonomous)|agent|Claude Code|claude|Anthropic CLI agent"
162
+ "Agents (autonomous)|agent|Codex CLI|codex|OpenAI Codex agent"
105
163
  "Agents (autonomous)|agent|Copilot CLI|copilot|GitHub Copilot CLI"
164
+ "Agents (autonomous)|agent|Goose|goose|Block's coding agent"
106
165
  "Coding (interactive)|coding|Aider|aider|AI pair programmer"
107
166
  "Coding (interactive)|coding|OpenCode|opencode|Terminal coding assistant"
108
167
  "Coding (interactive)|coding|Autohand Code|autohand|Autohand coding agent"
@@ -350,12 +409,18 @@ ${prompt}"
350
409
  cl | claude)
351
410
  printf "%s" "$full_prompt" | claude
352
411
  ;;
412
+ codex)
413
+ printf "%s" "$full_prompt" | codex
414
+ ;;
353
415
  copilot)
354
416
  copilot -sp "$full_prompt"
355
417
  ;;
356
418
  gemini)
357
419
  printf "%s" "$full_prompt" | gemini chat
358
420
  ;;
421
+ goose)
422
+ printf "%s" "$full_prompt" | goose session start
423
+ ;;
359
424
  kiro | kiro-cli)
360
425
  printf "%s" "$full_prompt" | kiro-cli chat
361
426
  ;;
@@ -404,7 +469,7 @@ case "${1:-}" in
404
469
  shift
405
470
  cmd_ai_query "$@"
406
471
  ;;
407
- cl | claude | copilot | gemini | kiro | sgpt | ollama | opencode | aider | autohand | vibe | qwen | zai)
472
+ cl | claude | codex | copilot | gemini | goose | kiro | sgpt | ollama | opencode | aider | autohand | vibe | qwen | zai)
408
473
  tool="$1"
409
474
  shift
410
475
  run_ai_with_context "$tool" "$@"
@@ -40,11 +40,11 @@ cmd_aliases() {
40
40
  list)
41
41
  ui_header "Aliases"
42
42
  echo ""
43
- printf " %-18s %-42s %s\n" "Name" "Value" "Source"
44
- echo " $(printf '%.18s' '------------------') $(printf '%.42s' '------------------------------------------') -------------------------"
45
- emit_alias_manifest | sort -t $'\t' -k1,1 | while IFS=$'\t' read -r name value file line; do
46
- printf " %-18s %-42s %s:%s\n" "$name" "${value:0:42}" "${file##*/}" "$line"
47
- done
43
+ ui_table_begin "Name" "Value" "Source"
44
+ while IFS=$'\t' read -r name value file line; do
45
+ ui_table_add "$name" "${value:0:60}" "${file##*/}:$line"
46
+ done < <(emit_alias_manifest | sort -t $'\t' -k1,1)
47
+ ui_table_end
48
48
  ;;
49
49
  search)
50
50
  local query="${1:-}"
@@ -60,9 +60,11 @@ cmd_aliases() {
60
60
  ui_warn "No matches" "$query"
61
61
  return 1
62
62
  fi
63
- printf "%s\n" "$results" | while IFS=$'\t' read -r name value file line; do
64
- printf " %-18s %-42s %s:%s\n" "$name" "${value:0:42}" "$file" "$line"
65
- done
63
+ ui_table_begin "Name" "Value" "Source"
64
+ while IFS=$'\t' read -r name value file line; do
65
+ ui_table_add "$name" "${value:0:60}" "$file:$line"
66
+ done <<<"$results"
67
+ ui_table_end
66
68
  ;;
67
69
  why)
68
70
  local alias_name="${1:-}"
@@ -77,13 +77,19 @@ cmd_diff() {
77
77
  }
78
78
 
79
79
  cmd_status() {
80
- local out
81
- out="$(chezmoi status "$@" || true)"
80
+ local out rc=0
81
+ # Capture chezmoi's stderr too so an actual tool failure surfaces
82
+ # to the user instead of being indistinguishable from a clean tree.
83
+ out="$(chezmoi status "$@" 2>&1)" || rc=$?
84
+ ui_header "Dotfiles Status"
85
+ if [[ "$rc" -ne 0 ]]; then
86
+ ui_err "chezmoi" "exited $rc"
87
+ [[ -n "$out" ]] && printf "%s\n" "$out"
88
+ return "$rc"
89
+ fi
82
90
  if [[ -z "$out" ]]; then
83
- ui_header "Dotfiles Status"
84
91
  ui_ok "Clean" "no local drift detected"
85
92
  else
86
- ui_header "Dotfiles Status"
87
93
  printf "%s\n" "$out"
88
94
  fi
89
95
  }