detached 2dc650c

fix(agent): omit docs from custom system prompts

commit
2dc650c30b415570e5e1ca35afde1aa3cbbf335e
author
brice · · 2026-08-10 13:52 UTC
committer
brice · · 2026-08-11 07:21 UTC
parent
da49ca5
signature
GPG VerifiedCD88F9E564E0102646FB6077A1A07C7C7C3E349D · arch-gpg Verified for the committer email
3 files · +42 -5
M README.md +3 -3
@@ -145,7 +145,7 @@ $ZUT_HOME/
145145 └── logs/ # app log files
146146 ```
147147
148-Drop a `SYSTEM.md` in `$ZUT_HOME` to replace the built-in identity for every run. Existing append addenda, including `AGENTS.md`, skills, and enabled Ponytail coding mode, remain layered on top. `--system-prompt` wins per invocation unless a selected replace-mode subagent profile supplies the child's identity. Delete the file to revert to the default identity.
148+Drop a `SYSTEM.md` in `$ZUT_HOME` to replace the built-in identity and docs guidance for every run. Existing append addenda, including `AGENTS.md`, skills, and enabled Ponytail coding mode, remain layered on top. `--system-prompt` wins per invocation unless a selected replace-mode subagent profile supplies the child's identity. Delete the file to revert to the default identity.
149149
150150 Ponytail coding mode is enabled by default, including when an existing `config.json` does not contain a `ponytail_enabled` field. When disabled, its compact guidance is omitted from resolved system prompts; when enabled, the guidance tells the model to apply itself only to engineering work. The setting persists its explicit on/off choice in `$ZUT_HOME/config.json` and can be changed from `/settings`. It is advisory guidance only: it does not change tool permissions, confirmations, jail behavior, or sandboxing.
151151
@@ -186,9 +186,9 @@ Treat questions and discussions as requests for explanation. Do not edit files o
186186 |---|---|---|
187187 | `$ZUT_HOME/AGENTS.md` | global, every run | appended to the default prompt |
188188 | `./AGENTS.md` (and parent dirs) | project | appended to the default prompt |
189-| `$ZUT_HOME/SYSTEM.md` | global, every run | replaces the built-in identity; append addenda remain |
189+| `$ZUT_HOME/SYSTEM.md` | global, every run | replaces the built-in identity and docs guidance; append addenda remain |
190190 | `--append-system-prompt <text>` | single run | appends for one invocation (repeatable) |
191-| `--system-prompt <text>` | single run | replaces the built-in identity for one invocation; append addenda remain |
191+| `--system-prompt <text>` | single run | replaces the built-in identity and docs guidance for one invocation; append addenda remain |
192192
193193 > **Note:** zut does not read a `CLAUDE.md` instruction file. The only Claude-compatible thing it picks up is skills under `.claude/skills/`. If you are migrating from Claude Code, move that content into `AGENTS.md` (global or per-project) and zut will use it.
194194
@@ -145,7 +145,7 @@ $ZUT_HOME/
145 └── logs/ # app log files145 └── logs/ # app log files
146 ```146 ```
147 147
148-Drop a `SYSTEM.md` in `$ZUT_HOME` to replace the built-in identity for every run. Existing append addenda, including `AGENTS.md`, skills, and enabled Ponytail coding mode, remain layered on top. `--system-prompt` wins per invocation unless a selected replace-mode subagent profile supplies the child's identity. Delete the file to revert to the default identity.148+Drop a `SYSTEM.md` in `$ZUT_HOME` to replace the built-in identity and docs guidance for every run. Existing append addenda, including `AGENTS.md`, skills, and enabled Ponytail coding mode, remain layered on top. `--system-prompt` wins per invocation unless a selected replace-mode subagent profile supplies the child's identity. Delete the file to revert to the default identity.
149 149
150 Ponytail coding mode is enabled by default, including when an existing `config.json` does not contain a `ponytail_enabled` field. When disabled, its compact guidance is omitted from resolved system prompts; when enabled, the guidance tells the model to apply itself only to engineering work. The setting persists its explicit on/off choice in `$ZUT_HOME/config.json` and can be changed from `/settings`. It is advisory guidance only: it does not change tool permissions, confirmations, jail behavior, or sandboxing.150 Ponytail coding mode is enabled by default, including when an existing `config.json` does not contain a `ponytail_enabled` field. When disabled, its compact guidance is omitted from resolved system prompts; when enabled, the guidance tells the model to apply itself only to engineering work. The setting persists its explicit on/off choice in `$ZUT_HOME/config.json` and can be changed from `/settings`. It is advisory guidance only: it does not change tool permissions, confirmations, jail behavior, or sandboxing.
151 151
@@ -186,9 +186,9 @@ Treat questions and discussions as requests for explanation. Do not edit files o
186 |---|---|---|186 |---|---|---|
187 | `$ZUT_HOME/AGENTS.md` | global, every run | appended to the default prompt |187 | `$ZUT_HOME/AGENTS.md` | global, every run | appended to the default prompt |
188 | `./AGENTS.md` (and parent dirs) | project | appended to the default prompt |188 | `./AGENTS.md` (and parent dirs) | project | appended to the default prompt |
189-| `$ZUT_HOME/SYSTEM.md` | global, every run | replaces the built-in identity; append addenda remain |189+| `$ZUT_HOME/SYSTEM.md` | global, every run | replaces the built-in identity and docs guidance; append addenda remain |
190 | `--append-system-prompt <text>` | single run | appends for one invocation (repeatable) |190 | `--append-system-prompt <text>` | single run | appends for one invocation (repeatable) |
191-| `--system-prompt <text>` | single run | replaces the built-in identity for one invocation; append addenda remain |191+| `--system-prompt <text>` | single run | replaces the built-in identity and docs guidance for one invocation; append addenda remain |
192 192
193 > **Note:** zut does not read a `CLAUDE.md` instruction file. The only Claude-compatible thing it picks up is skills under `.claude/skills/`. If you are migrating from Claude Code, move that content into `AGENTS.md` (global or per-project) and zut will use it.193 > **Note:** zut does not read a `CLAUDE.md` instruction file. The only Claude-compatible thing it picks up is skills under `.claude/skills/`. If you are migrating from Claude Code, move that content into `AGENTS.md` (global or per-project) and zut will use it.
194 194
M packages/agent/systemprompt.go +2 -2
@@ -21,7 +21,7 @@ type ToolSummary struct {
2121 type SystemPromptOpts struct {
2222 CWD string
2323 Tools []ToolSummary
24- Custom string // if set, replaces the default identity entirely
24+ Custom string // if set, replaces the built-in identity and docs guidance
2525 Append []string // extra text appended at the end
2626 Now time.Time
2727 ZutDocsDir string
@@ -67,7 +67,7 @@ func BuildSystemPrompt(o SystemPromptOpts) string {
6767 sb.WriteString("\n\n")
6868 sb.WriteString(compactedSummaryHandoffInstruction)
6969
70- if strings.TrimSpace(o.ZutDocsDir) != "" {
70+ if o.Custom == "" && strings.TrimSpace(o.ZutDocsDir) != "" {
7171 sb.WriteString("\n\nZut's own docs are installed under ")
7272 sb.WriteString(o.ZutDocsDir)
7373 sb.WriteString("; use the read tool there when you need details about zut RPC, extensions, skills, or built-in behaviour.")
@@ -21,7 +21,7 @@ type ToolSummary struct {
21 type SystemPromptOpts struct {21 type SystemPromptOpts struct {
22 CWD string22 CWD string
23 Tools []ToolSummary23 Tools []ToolSummary
24- Custom string // if set, replaces the default identity entirely24+ Custom string // if set, replaces the built-in identity and docs guidance
25 Append []string // extra text appended at the end25 Append []string // extra text appended at the end
26 Now time.Time26 Now time.Time
27 ZutDocsDir string27 ZutDocsDir string
@@ -67,7 +67,7 @@ func BuildSystemPrompt(o SystemPromptOpts) string {
67 sb.WriteString("\n\n")67 sb.WriteString("\n\n")
68 sb.WriteString(compactedSummaryHandoffInstruction)68 sb.WriteString(compactedSummaryHandoffInstruction)
69 69
70- if strings.TrimSpace(o.ZutDocsDir) != "" {70+ if o.Custom == "" && strings.TrimSpace(o.ZutDocsDir) != "" {
71 sb.WriteString("\n\nZut's own docs are installed under ")71 sb.WriteString("\n\nZut's own docs are installed under ")
72 sb.WriteString(o.ZutDocsDir)72 sb.WriteString(o.ZutDocsDir)
73 sb.WriteString("; use the read tool there when you need details about zut RPC, extensions, skills, or built-in behaviour.")73 sb.WriteString("; use the read tool there when you need details about zut RPC, extensions, skills, or built-in behaviour.")
M packages/agent/systemprompt_test.go +37 -0
@@ -3,6 +3,7 @@ package agent
33 import (
44 "strings"
55 "testing"
6+ "time"
67 )
78
89 func TestBuildSystemPromptAddsCompactionHandoffToCustomPrompt(t *testing.T) {
@@ -22,3 +23,39 @@ func TestBuildSystemPromptAddsCompactionHandoffToCustomPrompt(t *testing.T) {
2223 }
2324 }
2425 }
26+
27+func TestBuildSystemPromptCustomOmitsBuiltInDocs(t *testing.T) {
28+ got := BuildSystemPrompt(SystemPromptOpts{
29+ CWD: "/workspace",
30+ Custom: "Custom instructions",
31+ Append: []string{"Additional context"},
32+ Now: time.Date(2026, time.August, 6, 0, 0, 0, 0, time.UTC),
33+ ZutDocsDir: "/zut/docs",
34+ })
35+
36+ if strings.Contains(got, "Zut's own docs") || strings.Contains(got, "/zut/docs") {
37+ t.Fatalf("custom prompt includes built-in docs guidance:\n%s", got)
38+ }
39+ for _, want := range []string{
40+ "Custom instructions",
41+ "Additional context",
42+ "Current date: 2026-08-06",
43+ "Current working directory: /workspace",
44+ } {
45+ if !strings.Contains(got, want) {
46+ t.Errorf("custom prompt missing %q:\n%s", want, got)
47+ }
48+ }
49+}
50+
51+func TestBuildSystemPromptDefaultIncludesBuiltInDocs(t *testing.T) {
52+ got := BuildSystemPrompt(SystemPromptOpts{
53+ CWD: "/workspace",
54+ Now: time.Date(2026, time.August, 6, 0, 0, 0, 0, time.UTC),
55+ ZutDocsDir: "/zut/docs",
56+ })
57+
58+ if !strings.Contains(got, "Zut's own docs are installed under /zut/docs") {
59+ t.Fatalf("default prompt missing built-in docs guidance:\n%s", got)
60+ }
61+}
@@ -3,6 +3,7 @@ package agent
3 import (3 import (
4 "strings"4 "strings"
5 "testing"5 "testing"
6+ "time"
6 )7 )
7 8
8 func TestBuildSystemPromptAddsCompactionHandoffToCustomPrompt(t *testing.T) {9 func TestBuildSystemPromptAddsCompactionHandoffToCustomPrompt(t *testing.T) {
@@ -22,3 +23,39 @@ func TestBuildSystemPromptAddsCompactionHandoffToCustomPrompt(t *testing.T) {
22 }23 }
23 }24 }
24 }25 }
26+
27+func TestBuildSystemPromptCustomOmitsBuiltInDocs(t *testing.T) {
28+ got := BuildSystemPrompt(SystemPromptOpts{
29+ CWD: "/workspace",
30+ Custom: "Custom instructions",
31+ Append: []string{"Additional context"},
32+ Now: time.Date(2026, time.August, 6, 0, 0, 0, 0, time.UTC),
33+ ZutDocsDir: "/zut/docs",
34+ })
35+
36+ if strings.Contains(got, "Zut's own docs") || strings.Contains(got, "/zut/docs") {
37+ t.Fatalf("custom prompt includes built-in docs guidance:\n%s", got)
38+ }
39+ for _, want := range []string{
40+ "Custom instructions",
41+ "Additional context",
42+ "Current date: 2026-08-06",
43+ "Current working directory: /workspace",
44+ } {
45+ if !strings.Contains(got, want) {
46+ t.Errorf("custom prompt missing %q:\n%s", want, got)
47+ }
48+ }
49+}
50+
51+func TestBuildSystemPromptDefaultIncludesBuiltInDocs(t *testing.T) {
52+ got := BuildSystemPrompt(SystemPromptOpts{
53+ CWD: "/workspace",
54+ Now: time.Date(2026, time.August, 6, 0, 0, 0, 0, time.UTC),
55+ ZutDocsDir: "/zut/docs",
56+ })
57+
58+ if !strings.Contains(got, "Zut's own docs are installed under /zut/docs") {
59+ t.Fatalf("default prompt missing built-in docs guidance:\n%s", got)
60+ }
61+}

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 1

Tags 476

↑↓ moveenter openesc close