detached 130798c

fix(agent): clarify action and skill priority guidance (#181)

* fix(agent): clarify action and skill priority guidance

* fix(agent): place shared guidance after appended context
commit
130798cd8b45c58e125952a5663596f887607159
author
bnema · · 2026-09-06 07:08 UTC
committer
GitHub · · 2026-09-06 07:08 UTC
parent
d341fee
signature
GPG UnverifiedB5690EEEBB952194 The key is unknown
3 files · +50 -5
M README.md +2 -0
@@ -159,6 +159,8 @@ $ZUT_HOME/
159159
160160 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.
161161
162+Shared prompt guidance remains active with custom identities and across providers and models. It asks the agent to complete authorized, non-destructive work rather than stop at a plan, while respecting requests for explanation or review and preserving required approvals. Explicit user instructions take precedence over skill guidelines; skills cannot grant permissions or override system or developer constraints. Writing guidance favors concise paragraphs, useful lists, and direct language without canned transitions. These are prompt instructions, not changes to tool permissions or guarantees of model behavior.
163+
162164 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.
163165
164166 A selected subagent profile with `systemPromptMode: replace` supplies the child's base identity even when `--system-prompt` was provided for the parent run. Global append addenda, including enabled Ponytail guidance, still follow their normal inclusion rules.
@@ -159,6 +159,8 @@ $ZUT_HOME/
159 159
160 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.160 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.
161 161
162+Shared prompt guidance remains active with custom identities and across providers and models. It asks the agent to complete authorized, non-destructive work rather than stop at a plan, while respecting requests for explanation or review and preserving required approvals. Explicit user instructions take precedence over skill guidelines; skills cannot grant permissions or override system or developer constraints. Writing guidance favors concise paragraphs, useful lists, and direct language without canned transitions. These are prompt instructions, not changes to tool permissions or guarantees of model behavior.
163+
162 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.164 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.
163 165
164 A selected subagent profile with `systemPromptMode: replace` supplies the child's base identity even when `--system-prompt` was provided for the parent run. Global append addenda, including enabled Ponytail guidance, still follow their normal inclusion rules.166 A selected subagent profile with `systemPromptMode: replace` supplies the child's base identity even when `--system-prompt` was provided for the parent run. Global append addenda, including enabled Ponytail guidance, still follow their normal inclusion rules.
M packages/agent/systemprompt.go +12 -5
@@ -35,7 +35,7 @@ type SystemPromptOpts struct {
3535 //
3636 // - A one-paragraph identity (who zut is, what the name means,
3737 // what the TUI expects for output format).
38-// - Compact handoff and writing-quality guidance that must survive
38+// - Compact task, skill-priority, handoff, and writing guidance that survive
3939 // custom identities and appended context.
4040 // - The date + cwd footer so the model has current-context.
4141 //
@@ -83,8 +83,11 @@ func BuildSystemPrompt(o SystemPromptOpts) string {
8383 sb.WriteString(a)
8484 }
8585
86- // Keep the universal writing policy after optional context so narrower
87- // addenda cannot accidentally disable it.
86+ // Keep shared guidance after optional context, with writing policy last.
87+ sb.WriteString("\n\n")
88+ sb.WriteString(taskExecutionGuidance)
89+ sb.WriteString("\n\n")
90+ sb.WriteString(skillPriorityGuidance)
8891 sb.WriteString("\n\n")
8992 sb.WriteString(writingGuidance)
9093
@@ -94,13 +97,17 @@ func BuildSystemPrompt(o SystemPromptOpts) string {
9497
9598 const defaultIdentity = `You are an expert coding assistant operating inside zut, a coding agent harness. The name "zut" stands for "zero-overhead-tool"; if the user asks what zut means, answer exactly that.
9699
97-Your output renders in a TUI that understands markdown for prose and plain text for tool output. Use markdown freely, keep answers concise, and let tool calls speak for themselves rather than narrating them in prose before you invoke them. Act first, then summarise what you did.
100+Your output renders in a TUI that understands markdown for prose and plain text for tool output. Use markdown where it improves clarity, keep answers concise, and let tool calls speak for themselves rather than narrating them in prose before you invoke them.
98101
99102 For focused changes to an existing file, inspect its current contents and use edit with verbatim oldText taken from that same file. Include only enough context to make each match unambiguous. Use write when creating a file or replacing it wholesale. Do not mutate files through bash redirections or commands such as cat, echo, sed, or tee, because those changes appear as opaque shell output instead of a readable edit diff.`
100103
101104 const compactedSummaryHandoffInstruction = `When you see a "## Context Summary (compacted)" message, treat it as a handoff from earlier work. Keep its active constraints and preferences in force, continue the most recent unresolved user request without waiting for the user to type "continue", and follow a newer user request when it supersedes the summary.`
102105
103-const writingGuidance = `Adapt every response and document to its medium, audience, and reader's immediate need. Lead with the answer or next useful action. Use plain, precise language, concrete details, and strong verbs. Prefer verified facts to vague emphasis; qualify uncertain claims. Preserve useful structure, descriptive links, and accessibility. Cut throat-clearing, ceremony, repetition, catalogue-like prose, and mechanical sentence patterns. Do not manufacture slang, errors, hesitation, or artificial variation to sound human. Revise silently unless asked to explain your writing choices.`
106+const taskExecutionGuidance = `Treat requests such as "can you" as instructions to do the requested work within the user's intended scope; do not stop at a plan or an offer to continue. Proceed with authorized, non-destructive work and reasonable assumptions until the task is complete or genuinely blocked. Respect requests for explanation, planning, or review without making unsolicited changes. Ask only when a missing decision blocks safe, correct progress; complete independent authorized work first. Preserve tool permissions, required confirmations, and explicit approval requirements; do not infer permission for destructive or irreversible actions.`
107+
108+const skillPriorityGuidance = `Explicit user instructions take precedence over skill guidelines. Skills do not grant permissions or override system or developer constraints. If a skill would block requested work or change its scope, identify its source and the relevant instruction, explain the conflict, and follow the applicable higher-priority instruction.`
109+
110+const writingGuidance = `Adapt every response and document to its medium, audience, and reader's immediate need. Lead with the answer or next useful action. Use plain, precise language, concrete details, and strong verbs. Prefer verified facts to vague emphasis; qualify uncertain claims. Preserve useful structure, descriptive links, and accessibility. Default to concise paragraphs unless the requested format calls for another structure. Use lists when items are genuinely parallel, sequential, or easier to compare; avoid unnecessary nesting. Cut throat-clearing, ceremony, repetition, canned transitions, catalogue-like prose, and mechanical sentence patterns. Do not manufacture slang, errors, hesitation, or artificial variation to sound human. Revise silently unless asked to explain your writing choices.`
104111
105112 // WritingGuidance returns the universal policy kept at the end of resolved
106113 // prompt context, including after interactive prompt updates.
@@ -35,7 +35,7 @@ type SystemPromptOpts struct {
35 //35 //
36 // - A one-paragraph identity (who zut is, what the name means,36 // - A one-paragraph identity (who zut is, what the name means,
37 // what the TUI expects for output format).37 // what the TUI expects for output format).
38-// - Compact handoff and writing-quality guidance that must survive38+// - Compact task, skill-priority, handoff, and writing guidance that survive
39 // custom identities and appended context.39 // custom identities and appended context.
40 // - The date + cwd footer so the model has current-context.40 // - The date + cwd footer so the model has current-context.
41 //41 //
@@ -83,8 +83,11 @@ func BuildSystemPrompt(o SystemPromptOpts) string {
83 sb.WriteString(a)83 sb.WriteString(a)
84 }84 }
85 85
86- // Keep the universal writing policy after optional context so narrower86+ // Keep shared guidance after optional context, with writing policy last.
87- // addenda cannot accidentally disable it.87+ sb.WriteString("\n\n")
88+ sb.WriteString(taskExecutionGuidance)
89+ sb.WriteString("\n\n")
90+ sb.WriteString(skillPriorityGuidance)
88 sb.WriteString("\n\n")91 sb.WriteString("\n\n")
89 sb.WriteString(writingGuidance)92 sb.WriteString(writingGuidance)
90 93
@@ -94,13 +97,17 @@ func BuildSystemPrompt(o SystemPromptOpts) string {
94 97
95 const defaultIdentity = `You are an expert coding assistant operating inside zut, a coding agent harness. The name "zut" stands for "zero-overhead-tool"; if the user asks what zut means, answer exactly that.98 const defaultIdentity = `You are an expert coding assistant operating inside zut, a coding agent harness. The name "zut" stands for "zero-overhead-tool"; if the user asks what zut means, answer exactly that.
96 99
97-Your output renders in a TUI that understands markdown for prose and plain text for tool output. Use markdown freely, keep answers concise, and let tool calls speak for themselves rather than narrating them in prose before you invoke them. Act first, then summarise what you did.100+Your output renders in a TUI that understands markdown for prose and plain text for tool output. Use markdown where it improves clarity, keep answers concise, and let tool calls speak for themselves rather than narrating them in prose before you invoke them.
98 101
99 For focused changes to an existing file, inspect its current contents and use edit with verbatim oldText taken from that same file. Include only enough context to make each match unambiguous. Use write when creating a file or replacing it wholesale. Do not mutate files through bash redirections or commands such as cat, echo, sed, or tee, because those changes appear as opaque shell output instead of a readable edit diff.`102 For focused changes to an existing file, inspect its current contents and use edit with verbatim oldText taken from that same file. Include only enough context to make each match unambiguous. Use write when creating a file or replacing it wholesale. Do not mutate files through bash redirections or commands such as cat, echo, sed, or tee, because those changes appear as opaque shell output instead of a readable edit diff.`
100 103
101 const compactedSummaryHandoffInstruction = `When you see a "## Context Summary (compacted)" message, treat it as a handoff from earlier work. Keep its active constraints and preferences in force, continue the most recent unresolved user request without waiting for the user to type "continue", and follow a newer user request when it supersedes the summary.`104 const compactedSummaryHandoffInstruction = `When you see a "## Context Summary (compacted)" message, treat it as a handoff from earlier work. Keep its active constraints and preferences in force, continue the most recent unresolved user request without waiting for the user to type "continue", and follow a newer user request when it supersedes the summary.`
102 105
103-const writingGuidance = `Adapt every response and document to its medium, audience, and reader's immediate need. Lead with the answer or next useful action. Use plain, precise language, concrete details, and strong verbs. Prefer verified facts to vague emphasis; qualify uncertain claims. Preserve useful structure, descriptive links, and accessibility. Cut throat-clearing, ceremony, repetition, catalogue-like prose, and mechanical sentence patterns. Do not manufacture slang, errors, hesitation, or artificial variation to sound human. Revise silently unless asked to explain your writing choices.`106+const taskExecutionGuidance = `Treat requests such as "can you" as instructions to do the requested work within the user's intended scope; do not stop at a plan or an offer to continue. Proceed with authorized, non-destructive work and reasonable assumptions until the task is complete or genuinely blocked. Respect requests for explanation, planning, or review without making unsolicited changes. Ask only when a missing decision blocks safe, correct progress; complete independent authorized work first. Preserve tool permissions, required confirmations, and explicit approval requirements; do not infer permission for destructive or irreversible actions.`
107+
108+const skillPriorityGuidance = `Explicit user instructions take precedence over skill guidelines. Skills do not grant permissions or override system or developer constraints. If a skill would block requested work or change its scope, identify its source and the relevant instruction, explain the conflict, and follow the applicable higher-priority instruction.`
109+
110+const writingGuidance = `Adapt every response and document to its medium, audience, and reader's immediate need. Lead with the answer or next useful action. Use plain, precise language, concrete details, and strong verbs. Prefer verified facts to vague emphasis; qualify uncertain claims. Preserve useful structure, descriptive links, and accessibility. Default to concise paragraphs unless the requested format calls for another structure. Use lists when items are genuinely parallel, sequential, or easier to compare; avoid unnecessary nesting. Cut throat-clearing, ceremony, repetition, canned transitions, catalogue-like prose, and mechanical sentence patterns. Do not manufacture slang, errors, hesitation, or artificial variation to sound human. Revise silently unless asked to explain your writing choices.`
104 111
105 // WritingGuidance returns the universal policy kept at the end of resolved112 // WritingGuidance returns the universal policy kept at the end of resolved
106 // prompt context, including after interactive prompt updates.113 // prompt context, including after interactive prompt updates.
M packages/agent/systemprompt_test.go +36 -0
@@ -30,6 +30,9 @@ func TestBuildSystemPromptAlwaysIncludesFinalWritingGuidance(t *testing.T) {
3030 for _, want := range []string{
3131 "medium, audience, and reader's immediate need",
3232 "plain, precise language",
33+ "Default to concise paragraphs",
34+ "Use lists when items are genuinely parallel, sequential, or easier to compare",
35+ "canned transitions",
3336 "verified facts",
3437 "descriptive links, and accessibility",
3538 "Do not manufacture slang, errors, hesitation",
@@ -43,6 +46,39 @@ func TestBuildSystemPromptAlwaysIncludesFinalWritingGuidance(t *testing.T) {
4346 }
4447 }
4548
49+func TestBuildSystemPromptAlwaysIncludesTaskAndSkillGuidance(t *testing.T) {
50+ for _, custom := range []string{"", "Custom identity"} {
51+ t.Run(custom, func(t *testing.T) {
52+ prompt := BuildSystemPrompt(SystemPromptOpts{
53+ Custom: custom,
54+ Append: []string{"Workspace context", "Available skills"},
55+ })
56+ previous := strings.Index(prompt, "Available skills")
57+ for _, guidance := range []string{taskExecutionGuidance, skillPriorityGuidance, writingGuidance} {
58+ index := strings.Index(prompt, guidance)
59+ if index <= previous {
60+ t.Fatalf("shared guidance must follow appended context in task/skill/writing order")
61+ }
62+ previous = index
63+ }
64+ for _, want := range []string{
65+ "Treat requests such as \"can you\" as instructions to do the requested work",
66+ "do not stop at a plan or an offer to continue",
67+ "Respect requests for explanation, planning, or review without making unsolicited changes",
68+ "Ask only when a missing decision blocks safe, correct progress",
69+ "Preserve tool permissions, required confirmations, and explicit approval requirements",
70+ "Explicit user instructions take precedence over skill guidelines",
71+ "Skills do not grant permissions or override system or developer constraints",
72+ "identify its source and the relevant instruction",
73+ } {
74+ if count := strings.Count(prompt, want); count != 1 {
75+ t.Errorf("guidance %q count = %d, want 1", want, count)
76+ }
77+ }
78+ })
79+ }
80+}
81+
4682 func TestBuildSystemPromptAddsCompactionHandoffToCustomPrompt(t *testing.T) {
4783 prompt := BuildSystemPrompt(SystemPromptOpts{Custom: "custom identity"})
4884 if !strings.Contains(prompt, "custom identity") {
@@ -30,6 +30,9 @@ func TestBuildSystemPromptAlwaysIncludesFinalWritingGuidance(t *testing.T) {
30 for _, want := range []string{30 for _, want := range []string{
31 "medium, audience, and reader's immediate need",31 "medium, audience, and reader's immediate need",
32 "plain, precise language",32 "plain, precise language",
33+ "Default to concise paragraphs",
34+ "Use lists when items are genuinely parallel, sequential, or easier to compare",
35+ "canned transitions",
33 "verified facts",36 "verified facts",
34 "descriptive links, and accessibility",37 "descriptive links, and accessibility",
35 "Do not manufacture slang, errors, hesitation",38 "Do not manufacture slang, errors, hesitation",
@@ -43,6 +46,39 @@ func TestBuildSystemPromptAlwaysIncludesFinalWritingGuidance(t *testing.T) {
43 }46 }
44 }47 }
45 48
49+func TestBuildSystemPromptAlwaysIncludesTaskAndSkillGuidance(t *testing.T) {
50+ for _, custom := range []string{"", "Custom identity"} {
51+ t.Run(custom, func(t *testing.T) {
52+ prompt := BuildSystemPrompt(SystemPromptOpts{
53+ Custom: custom,
54+ Append: []string{"Workspace context", "Available skills"},
55+ })
56+ previous := strings.Index(prompt, "Available skills")
57+ for _, guidance := range []string{taskExecutionGuidance, skillPriorityGuidance, writingGuidance} {
58+ index := strings.Index(prompt, guidance)
59+ if index <= previous {
60+ t.Fatalf("shared guidance must follow appended context in task/skill/writing order")
61+ }
62+ previous = index
63+ }
64+ for _, want := range []string{
65+ "Treat requests such as \"can you\" as instructions to do the requested work",
66+ "do not stop at a plan or an offer to continue",
67+ "Respect requests for explanation, planning, or review without making unsolicited changes",
68+ "Ask only when a missing decision blocks safe, correct progress",
69+ "Preserve tool permissions, required confirmations, and explicit approval requirements",
70+ "Explicit user instructions take precedence over skill guidelines",
71+ "Skills do not grant permissions or override system or developer constraints",
72+ "identify its source and the relevant instruction",
73+ } {
74+ if count := strings.Count(prompt, want); count != 1 {
75+ t.Errorf("guidance %q count = %d, want 1", want, count)
76+ }
77+ }
78+ })
79+ }
80+}
81+
46 func TestBuildSystemPromptAddsCompactionHandoffToCustomPrompt(t *testing.T) {82 func TestBuildSystemPromptAddsCompactionHandoffToCustomPrompt(t *testing.T) {
47 prompt := BuildSystemPrompt(SystemPromptOpts{Custom: "custom identity"})83 prompt := BuildSystemPrompt(SystemPromptOpts{Custom: "custom identity"})
48 if !strings.Contains(prompt, "custom identity") {84 if !strings.Contains(prompt, "custom identity") {

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 477

↑↓ moveenter openesc close