@yagni-app/code-staging 0.2.1-staging.1047.1 → 0.2.1-staging.1055.1

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.
@@ -53,6 +53,15 @@ export interface BrandSystemPromptOptions {
53
53
  identity?: string;
54
54
  /** Live company brief to inject so the agent boots grounded (Phase C). */
55
55
  contextBrief?: string;
56
+ /**
57
+ * Repository rules section (`.claude/rules`, built by claudeRules.ts).
58
+ * Placed after the brief and BEFORE the closing reminder: rules are user
59
+ * content that may legitimately name other coding agents — exactly the text
60
+ * the reminder inoculates against — so the reminder must stay the most
61
+ * recent instruction. Appended after the scrub step, so rules content is
62
+ * never brand-rewritten (same exemption as <project_context>).
63
+ */
64
+ rulesSection?: string | null;
56
65
  }
57
66
  /**
58
67
  * Rebrand pi's assembled system prompt as YAGNI Code's, and optionally inject a
@@ -61,7 +70,9 @@ export interface BrandSystemPromptOptions {
61
70
  * Steps: (1) drop pi's self-referential documentation block, (2) replace the
62
71
  * identity sentence (with a loose fallback, else prepend), (3) scrub residual
63
72
  * brand tokens outside user content, (4) append the company brief + a proactive
64
- * ask_yagni directive. Idempotent: re-branding keeps a single identity.
73
+ * ask_yagni directive, (5) append the repository-rules section verbatim, (6)
74
+ * close with the identity reminder, which must stay last (recency). Idempotent:
75
+ * re-branding keeps a single identity, brief, rules section, and reminder.
65
76
  */
66
77
  export declare function brandSystemPrompt(original: string, opts?: BrandSystemPromptOptions): string;
67
78
  /** The minimal theme surface the masthead needs (a subset of pi's Theme). */
@@ -103,7 +103,9 @@ export function brandingDisabled(env) {
103
103
  * Steps: (1) drop pi's self-referential documentation block, (2) replace the
104
104
  * identity sentence (with a loose fallback, else prepend), (3) scrub residual
105
105
  * brand tokens outside user content, (4) append the company brief + a proactive
106
- * ask_yagni directive. Idempotent: re-branding keeps a single identity.
106
+ * ask_yagni directive, (5) append the repository-rules section verbatim, (6)
107
+ * close with the identity reminder, which must stay last (recency). Idempotent:
108
+ * re-branding keeps a single identity, brief, rules section, and reminder.
107
109
  */
108
110
  export function brandSystemPrompt(original, opts = {}) {
109
111
  const identity = opts.identity ?? YAGNI_IDENTITY;
@@ -133,7 +135,18 @@ export function brandSystemPrompt(original, opts = {}) {
133
135
  "your priors. When you need more detail, or it does not cover something " +
134
136
  "organization- or codebase-specific, call ask_yagni instead of guessing.";
135
137
  }
136
- // 5. Closing reinforcement. Weak open-weight models weight the most recent
138
+ // 5. Repository rules after the scrub (user content stays verbatim), before
139
+ // the closing reminder (which must remain last; see rulesSection's doc).
140
+ // The idempotency guard keys on the section's first line (its stable header,
141
+ // "## Repository rules (.claude/rules)") rather than the full content, so a
142
+ // re-brand stays single-section even if the rules BODY differs between
143
+ // passes — same shape as the BRIEF_HEADER guard above.
144
+ const rules = opts.rulesSection ?? undefined;
145
+ const rulesHeader = rules?.split("\n", 1)[0];
146
+ if (rules && rulesHeader && !s.includes(rulesHeader)) {
147
+ s = `${s}\n\n${rules}`;
148
+ }
149
+ // 6. Closing reinforcement. Weak open-weight models weight the most recent
137
150
  // instruction heavily, and the user's own project files may name other
138
151
  // harnesses; a trailing reminder keeps the agent from claiming one as its own.
139
152
  if (!s.includes(CLOSING_REMINDER)) {
@@ -49,6 +49,4 @@ export interface BuildSectionOptions {
49
49
  export declare function buildClaudeRulesSection(rules: ClaudeRule[], opts?: BuildSectionOptions): string | null;
50
50
  /** Env-driven entry: dirs from YAGNI_CLAUDE_RULES_DIRS, null when off/empty. */
51
51
  export declare function claudeRulesSection(env: NodeJS.ProcessEnv, opts?: CollectRulesOptions & BuildSectionOptions): string | null;
52
- /** Append `section` to a system prompt exactly once; no-op without a section. */
53
- export declare function appendClaudeRules(systemPrompt: string, section: string | null): string;
54
52
  //# sourceMappingURL=claudeRules.d.ts.map
@@ -169,12 +169,4 @@ export function claudeRulesSection(env, opts = {}) {
169
169
  return null;
170
170
  }
171
171
  }
172
- /** Append `section` to a system prompt exactly once; no-op without a section. */
173
- export function appendClaudeRules(systemPrompt, section) {
174
- if (!section)
175
- return systemPrompt;
176
- if (systemPrompt.includes(CLAUDE_RULES_HEADER))
177
- return systemPrompt;
178
- return `${systemPrompt}\n\n${section}`;
179
- }
180
172
  //# sourceMappingURL=claudeRules.js.map
@@ -11,7 +11,7 @@ import { makeRecordEngineeringContextTool } from "./recordContextTool.js";
11
11
  import { makeRecordDecisionTool } from "./recordDecisionTool.js";
12
12
  import { makeSuggestNextWorkTool } from "./nextWorkTool.js";
13
13
  import { BRAND_NAME, brandSystemPrompt, brandingDisabled, buildMastheadString, YAGNI_IDENTITY_DRIVER } from "./branding.js";
14
- import { appendClaudeRules, claudeRulesSection } from "./claudeRules.js";
14
+ import { claudeRulesSection } from "./claudeRules.js";
15
15
  import { registerCostCommand } from "./costHud.js";
16
16
  import { isDebug } from "./diagnostics.js";
17
17
  import { droppedSessionRuns, sessionRunIds } from "./sessionRuns.js";
@@ -409,7 +409,11 @@ export async function registerYagni(pi, deps = {}) {
409
409
  pi.on("before_agent_start", (event) => noBranding
410
410
  ? undefined
411
411
  : {
412
- systemPrompt: appendClaudeRules(brandSystemPrompt(event.systemPrompt, { contextBrief, identity }), rulesSection),
412
+ systemPrompt: brandSystemPrompt(event.systemPrompt, {
413
+ contextBrief,
414
+ identity,
415
+ rulesSection,
416
+ }),
413
417
  });
414
418
  // Two finalized-message guards share this handler (their conditions are
415
419
  // mutually exclusive: YAG-460 takes error-stopped messages, YAG-466 takes
package/dist/launch.js CHANGED
@@ -8,6 +8,7 @@
8
8
  import { randomUUID } from "node:crypto";
9
9
  import { agentDirEnvVar } from "./branding.js";
10
10
  import { PAD_X_ENV, resolvePadX } from "./padding.js";
11
+ import { ENGINEERING_PRACTICE_SECTION, promptEnrichmentDisabled } from "./promptEnrichment.js";
11
12
  /**
12
13
  * How close to expiry the token can be before launch warns. A coding session
13
14
  * easily outlives a token, so warn early enough that re-logging in before a long
@@ -109,11 +110,20 @@ export function buildLaunch(creds, passthroughArgs, opts) {
109
110
  // cannot switch to a different tier via /model or Ctrl+P. The proxy still
110
111
  // resolves the tier to the concrete backing model.
111
112
  const userChoseModel = passthroughArgs.some(arg => arg === "--model" || arg.startsWith("--model="));
113
+ // Engineering-practice enrichment (YAG-496): appended to the DRIVER's system
114
+ // prompt only — /go stage children and subagents build their own pi argv, so
115
+ // this flag never reaches them. pi treats the value as literal text (it is
116
+ // never an existing file path) and slots it before <project_context>, so the
117
+ // user's repo instructions still outrank it. The flag is repeatable, so a
118
+ // user-passed --append-system-prompt coexists rather than conflicting; the
119
+ // opt-out is YAGNI_DISABLE_PROMPT_ENRICHMENT.
120
+ const enrichmentOff = promptEnrichmentDisabled(opts.baseEnv ?? process.env);
112
121
  const argv = [
113
122
  "-e",
114
123
  opts.extensionPath,
115
124
  ...(userChoseProvider ? [] : ["--provider", "yagni"]),
116
125
  ...(userChoseModel ? [] : ["--model", "advanced"]),
126
+ ...(enrichmentOff ? [] : ["--append-system-prompt", ENGINEERING_PRACTICE_SECTION]),
117
127
  ...(opts.extraAgentArgs ?? []),
118
128
  ...passthroughArgs,
119
129
  ];
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Engineering-practice prompt enrichment (YAG-496).
3
+ *
4
+ * pi's own base system prompt is deliberately thin (~15 lines: identity, tool
5
+ * one-liners, two generic guidelines). The extension adds identity, grounding,
6
+ * and product-tool guidance — but nothing about general engineering behavior:
7
+ * conventions, verification, commit discipline, communication style. This
8
+ * section carries that missing middle, curated from the prompt lineage shared
9
+ * by OpenCode/Claude Code/Kimi CLI and adapted to YAGNI Code's tools and
10
+ * autonomy posture.
11
+ *
12
+ * Delivery mechanism: pi's `--append-system-prompt <text>` flag, injected by
13
+ * the launcher (launch.ts). pi places appended text after its Guidelines and
14
+ * BEFORE the user's <project_context>, so repo instructions still outrank it.
15
+ * Because `/go` stage children and subagents build their own pi argv
16
+ * (pi-extension-yagni's pipeline/invocation.ts and pipeline/runner.ts), a
17
+ * launcher flag is structurally driver-only: child prompts are untouched by
18
+ * construction, not by an `if`. The piContract test pins both properties.
19
+ *
20
+ * Content constraints (enforced by test/promptEnrichment.test.ts):
21
+ * - must not contain the standalone word "pi" — the extension's brand scrub
22
+ * rewrites it to "YAGNI Code" and would mangle the sentence;
23
+ * - must not OPEN with a "- " bullet line — pi's self-referential docs block
24
+ * (which the extension strips with a regex that consumes consecutive
25
+ * bullets) sits directly above this section in the assembled prompt;
26
+ * - no emojis (the section itself forbids them).
27
+ */
28
+ /** Env switch that skips the enrichment entirely (sibling of
29
+ * YAGNI_DISABLE_BRANDING / YAGNI_DISABLE_CLAUDE_COMPAT, same semantics). */
30
+ export declare const ENRICHMENT_DISABLE_ENV = "YAGNI_DISABLE_PROMPT_ENRICHMENT";
31
+ /** `"1"`/anything truthy disables; unset, empty, and `"0"` keep it on. */
32
+ export declare function promptEnrichmentDisabled(env: NodeJS.ProcessEnv): boolean;
33
+ /**
34
+ * The section appended to the driver session's system prompt. Keep it curated,
35
+ * not encyclopedic: every line here spends attention budget on an open-weight
36
+ * model, and the load-bearing instructions (ask_yagni contract, delegation)
37
+ * live elsewhere in the prompt.
38
+ */
39
+ export declare const ENGINEERING_PRACTICE_SECTION = "Engineering practice:\n\nBias to action: when the user asks you to implement, fix, or change something, use your tools to make the actual edits and run the actual commands \u2014 do not answer with a description of what you would do, or with code for the user to apply themselves. When the user asks HOW to approach something, answer the question first; do not jump into making changes they have not asked for.\n\nConventions:\n- Never assume a library is available, however well known. Before using one, confirm the project already depends on it (its package manifest, or imports in neighboring files).\n- When editing, read the surrounding code and its imports first; match the file's existing style, naming, and patterns rather than introducing your own.\n- When creating a new file or component, study an existing sibling first and follow its structure.\n- Never write code that logs or exposes secrets, keys, or credentials.\n\nVerification:\n- Consider what the code you are changing is supposed to do (from its name, location, and callers) before you change it.\n- Verify changes with the project's own tests when possible. Never assume a test framework or command \u2014 check the README, package scripts, or neighboring tests for the real one.\n- After completing a task, run the project's lint and typecheck commands if you know them; if you cannot find them, ask the user and suggest recording them in AGENTS.md for next time.\n\nVersion control:\n- No unsolicited commits: commit only when the user asked for one or the task at hand clearly calls for it.\n\nCommunication:\n- Answer directly, without preamble or postamble (\"Here is what I will do next...\", \"Based on the information provided...\"). Match the length of your answer to the question.\n- After making edits, report the outcome briefly; do not restate the diff or explain the code you just wrote unless asked.\n- Do not add code comments that narrate what you changed or why the change is correct; comments are for future readers of the code.\n- Reference code as file_path:line_number so the user can jump to it.\n- Before running a non-trivial command that changes state, say in one line what it does and why.\n- Never guess or fabricate URLs. Only use URLs the user provided or that appear in local files.\n- No emojis unless the user asks for them.";
40
+ //# sourceMappingURL=promptEnrichment.d.ts.map
@@ -0,0 +1,68 @@
1
+ /**
2
+ * Engineering-practice prompt enrichment (YAG-496).
3
+ *
4
+ * pi's own base system prompt is deliberately thin (~15 lines: identity, tool
5
+ * one-liners, two generic guidelines). The extension adds identity, grounding,
6
+ * and product-tool guidance — but nothing about general engineering behavior:
7
+ * conventions, verification, commit discipline, communication style. This
8
+ * section carries that missing middle, curated from the prompt lineage shared
9
+ * by OpenCode/Claude Code/Kimi CLI and adapted to YAGNI Code's tools and
10
+ * autonomy posture.
11
+ *
12
+ * Delivery mechanism: pi's `--append-system-prompt <text>` flag, injected by
13
+ * the launcher (launch.ts). pi places appended text after its Guidelines and
14
+ * BEFORE the user's <project_context>, so repo instructions still outrank it.
15
+ * Because `/go` stage children and subagents build their own pi argv
16
+ * (pi-extension-yagni's pipeline/invocation.ts and pipeline/runner.ts), a
17
+ * launcher flag is structurally driver-only: child prompts are untouched by
18
+ * construction, not by an `if`. The piContract test pins both properties.
19
+ *
20
+ * Content constraints (enforced by test/promptEnrichment.test.ts):
21
+ * - must not contain the standalone word "pi" — the extension's brand scrub
22
+ * rewrites it to "YAGNI Code" and would mangle the sentence;
23
+ * - must not OPEN with a "- " bullet line — pi's self-referential docs block
24
+ * (which the extension strips with a regex that consumes consecutive
25
+ * bullets) sits directly above this section in the assembled prompt;
26
+ * - no emojis (the section itself forbids them).
27
+ */
28
+ /** Env switch that skips the enrichment entirely (sibling of
29
+ * YAGNI_DISABLE_BRANDING / YAGNI_DISABLE_CLAUDE_COMPAT, same semantics). */
30
+ export const ENRICHMENT_DISABLE_ENV = "YAGNI_DISABLE_PROMPT_ENRICHMENT";
31
+ /** `"1"`/anything truthy disables; unset, empty, and `"0"` keep it on. */
32
+ export function promptEnrichmentDisabled(env) {
33
+ const value = env[ENRICHMENT_DISABLE_ENV];
34
+ return value !== undefined && value !== "" && value !== "0";
35
+ }
36
+ /**
37
+ * The section appended to the driver session's system prompt. Keep it curated,
38
+ * not encyclopedic: every line here spends attention budget on an open-weight
39
+ * model, and the load-bearing instructions (ask_yagni contract, delegation)
40
+ * live elsewhere in the prompt.
41
+ */
42
+ export const ENGINEERING_PRACTICE_SECTION = `Engineering practice:
43
+
44
+ Bias to action: when the user asks you to implement, fix, or change something, use your tools to make the actual edits and run the actual commands — do not answer with a description of what you would do, or with code for the user to apply themselves. When the user asks HOW to approach something, answer the question first; do not jump into making changes they have not asked for.
45
+
46
+ Conventions:
47
+ - Never assume a library is available, however well known. Before using one, confirm the project already depends on it (its package manifest, or imports in neighboring files).
48
+ - When editing, read the surrounding code and its imports first; match the file's existing style, naming, and patterns rather than introducing your own.
49
+ - When creating a new file or component, study an existing sibling first and follow its structure.
50
+ - Never write code that logs or exposes secrets, keys, or credentials.
51
+
52
+ Verification:
53
+ - Consider what the code you are changing is supposed to do (from its name, location, and callers) before you change it.
54
+ - Verify changes with the project's own tests when possible. Never assume a test framework or command — check the README, package scripts, or neighboring tests for the real one.
55
+ - After completing a task, run the project's lint and typecheck commands if you know them; if you cannot find them, ask the user and suggest recording them in AGENTS.md for next time.
56
+
57
+ Version control:
58
+ - No unsolicited commits: commit only when the user asked for one or the task at hand clearly calls for it.
59
+
60
+ Communication:
61
+ - Answer directly, without preamble or postamble ("Here is what I will do next...", "Based on the information provided..."). Match the length of your answer to the question.
62
+ - After making edits, report the outcome briefly; do not restate the diff or explain the code you just wrote unless asked.
63
+ - Do not add code comments that narrate what you changed or why the change is correct; comments are for future readers of the code.
64
+ - Reference code as file_path:line_number so the user can jump to it.
65
+ - Before running a non-trivial command that changes state, say in one line what it does and why.
66
+ - Never guess or fabricate URLs. Only use URLs the user provided or that appear in local files.
67
+ - No emojis unless the user asks for them.`;
68
+ //# sourceMappingURL=promptEnrichment.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yagni-app/code-staging",
3
- "version": "0.2.1-staging.1047.1",
3
+ "version": "0.2.1-staging.1055.1",
4
4
  "description": "YAGNI Code: a terminal coding agent that already knows your company. One YAGNI login routes the model and grounds the agent in your team's context.",
5
5
  "license": "SEE LICENSE IN LICENSE.md",
6
6
  "author": "YAGNI, Inc. <jack@yagni.app> (https://yagni.app)",
@@ -38,5 +38,5 @@
38
38
  "@earendil-works/pi-tui": "0.84.1",
39
39
  "typebox": "^1.3.11"
40
40
  },
41
- "yagniSourceSha": "7468515ac44df41d14f176bb4982a348d47da532"
41
+ "yagniSourceSha": "154a3d40a32bd82da1a6f152100522efafabb7d1"
42
42
  }