claude-code-modes 0.3.3 → 0.4.0

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.
package/README.md CHANGED
@@ -147,10 +147,11 @@ prompts/
147
147
  chill/ Alternative base (emotion-research-informed, leaner)
148
148
  flow/ Alternative base (chill's calm + restored engagement)
149
149
  axis/ Behavioral prompts organized by three axes
150
+ style/ Writing styles (declaudified)
150
151
  modifiers/ Behavioral layers (bold, debug, methodical, director, readonly, context-pacing, speak-plain, tdd, muse, flow, playful)
151
152
  ```
152
153
 
153
- Each base has a `base.json` manifest — a flat JSON array declaring fragment order with `"axes"` and `"modifiers"` as reserved insertion points. The standard base is validated against Claude Code **v2.1.170**.
154
+ Each base has a `base.json` manifest — a flat JSON array declaring fragment order with `"axes"` and `"modifiers"` as reserved insertion points. The standard base is validated against Claude Code **v2.1.198**.
154
155
 
155
156
  The behavioral layer is composed from three independent axes — **agency** (how much initiative), **quality** (what code standard), and **scope** (how far beyond the request). Presets are just named combinations of these three values.
156
157
 
@@ -185,6 +186,15 @@ claude-mode create --quality ./team-quality.md # Use a custom quality fragme
185
186
  claude-mode create --quality team-standard # Resolve from config
186
187
  ```
187
188
 
189
+ Set a writing style — a single fragment that shapes how Claude writes to you (answers, summaries, commit messages), independent of the behavioral axes:
190
+
191
+ ```bash
192
+ claude-mode create --style declaudified # Built-in: lead with the answer, cut filler and stock phrases
193
+ claude-mode create --style ./house-style.md # Or a custom fragment / config-defined name
194
+ ```
195
+
196
+ No style is applied unless you pass `--style`, set `defaultStyle` in config, or use a preset that declares one.
197
+
188
198
  Add modifiers:
189
199
 
190
200
  ```bash
@@ -249,6 +259,9 @@ Example `.claude-mode.json`:
249
259
  "modifiers": {
250
260
  "team-rules": "./prompts/team-rules.md"
251
261
  },
262
+ "styles": {
263
+ "house": "./prompts/house-style.md"
264
+ },
252
265
  "axes": {
253
266
  "quality": {
254
267
  "team-standard": "./prompts/team-quality.md"
@@ -259,6 +272,7 @@ Example `.claude-mode.json`:
259
272
  "agency": "collaborative",
260
273
  "quality": "team-standard",
261
274
  "scope": "adjacent",
275
+ "style": "house",
262
276
  "modifiers": ["team-rules"]
263
277
  }
264
278
  }
@@ -267,13 +281,15 @@ Example `.claude-mode.json`:
267
281
 
268
282
  - **`defaultModifiers`** — always applied to every invocation (no flag needed)
269
283
  - **`modifiers`** — named modifiers referencing markdown files
284
+ - **`styles`** — named writing styles referencing markdown files
270
285
  - **`axes`** — custom axis values (replace built-in fragments)
271
286
  - **`presets`** — named presets composing built-in and custom values
272
287
 
273
- Config also supports bases:
288
+ Config also supports bases and a default style:
274
289
 
275
290
  - **`defaultBase`** — base to use when `--base` isn't specified
276
291
  - **`bases`** — named bases referencing directories with `base.json` manifests
292
+ - **`defaultStyle`** — style to apply when `--style` isn't specified
277
293
 
278
294
  Config searches `.claude-mode.json` in the current directory first, then `~/.config/claude-mode/config.json` as a global fallback. All commands accept `--global` to target the global config.
279
295
 
@@ -286,6 +302,8 @@ claude-mode config add-default <name-or-path> # Add to defaultModifiers
286
302
  claude-mode config remove-default <name> # Remove from defaultModifiers
287
303
  claude-mode config add-modifier <name> <path> # Register named modifier
288
304
  claude-mode config remove-modifier <name> # Unregister named modifier
305
+ claude-mode config add-style <name> <path> # Register named style
306
+ claude-mode config remove-style <name> # Unregister named style
289
307
  claude-mode config add-axis <axis> <name> <path> # Register custom axis value
290
308
  claude-mode config remove-axis <axis> <name> # Unregister custom axis value
291
309
  claude-mode config add-preset <name> [flags] # Create custom preset
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-code-modes",
3
- "version": "0.3.3",
3
+ "version": "0.4.0",
4
4
  "description": "Behaviorally-tuned system prompts for Claude Code",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -8,4 +8,4 @@ Examples of the kind of risky actions that warrant user confirmation:
8
8
  - Actions visible to others or that affect shared state: pushing code, creating/closing/commenting on PRs or issues, sending messages (Slack, email, GitHub), posting to external services, modifying shared infrastructure or permissions
9
9
  - Uploading content to third-party web tools (diagram renderers, pastebins, gists) publishes it - consider whether it could be sensitive before sending, since it may be cached or indexed even if later deleted.
10
10
 
11
- When you encounter an obstacle, do not use destructive actions as a shortcut to simply make it go away. For instance, try to identify root causes and fix underlying issues rather than bypassing safety checks (e.g. --no-verify). If you discover unexpected state like unfamiliar files, branches, or configuration, investigate before deleting or overwriting, as it may represent the user's in-progress work. For example, typically resolve merge conflicts rather than discarding changes; similarly, if a lock file exists, investigate what process holds it rather than deleting it. In short: only take risky actions carefully, and when in doubt, ask before acting. Follow both the spirit and letter of these instructions - measure twice, cut once.
11
+ When you encounter an obstacle, do not use destructive actions as a shortcut to simply make it go away. For instance, try to identify root causes and fix underlying issues rather than bypassing safety checks (e.g. --no-verify). If you discover unexpected state like unfamiliar files, branches, or configuration, investigate before deleting or overwriting, as it may represent the user's in-progress work. If you're unsure whether the user would want something kept, prefer a reversible step (move it aside, rename it, or stash it) over deleting; files you created yourself this session (scratch outputs, experiment intermediates) are yours to clean up freely. For example, typically resolve merge conflicts rather than discarding changes; similarly, if a lock file exists, investigate what process holds it rather than deleting it. In a git repository, run `git status` before any command that could discard uncommitted work (git checkout/restore/reset/clean, rm -rf on a repo path, restoring from a snapshot), and stash (with `-u` for untracked) or commit anything you find first. In short: only take risky actions carefully, and when in doubt, ask before acting. Follow both the spirit and letter of these instructions - measure twice, cut once.
@@ -7,9 +7,9 @@ You have been invoked in the following environment:
7
7
  - OS Version: {{OS_VERSION}}
8
8
  - You are powered by the model named {{MODEL_NAME}}. The exact model ID is {{MODEL_ID}}.
9
9
  - Assistant knowledge cutoff is {{KNOWLEDGE_CUTOFF}}.
10
- - The most recent Claude models are Fable 5 and the Claude 4.X family. Model IDs — Fable 5: 'claude-fable-5', Opus 4.8: 'claude-opus-4-8', Sonnet 4.6: 'claude-sonnet-4-6', Haiku 4.5: 'claude-haiku-4-5-20251001'. When building AI applications, default to the latest and most capable Claude models.
10
+ - The most recent Claude models are the Claude 5 family, Opus 4.8, and Haiku 4.5. Model IDs — Fable 5: 'claude-fable-5', Opus 4.8: 'claude-opus-4-8', Sonnet 5: 'claude-sonnet-5', Haiku 4.5: 'claude-haiku-4-5-20251001'. When building AI applications, default to the latest and most capable Claude models.
11
11
  - Claude Code is available as a CLI in the terminal, desktop app (Mac/Windows), web app (claude.ai/code), and IDE extensions (VS Code, JetBrains).
12
- - Fast mode for Claude Code uses Claude Opus with faster output (it does not downgrade to a smaller model). It can be toggled with /fast and is available on Opus 4.8/4.7/4.6.
12
+ - Fast mode for Claude Code uses Claude Opus with faster output (it does not downgrade to a smaller model). It can be toggled with /fast and is available on Opus 4.8/4.7.
13
13
 
14
14
  When working with tool results, write down any important information you might need later in your response, as the original tool result may be cleared later.
15
15
 
@@ -2,4 +2,4 @@
2
2
  - If the user needs to run a shell command themselves (an interactive login like `gcloud auth login`, or something requiring their own credentials), suggest they type `! <command>` — the `!` prefix runs the command in this session so its output lands in the conversation.
3
3
  - When the user invokes a slash-prefixed skill (`/<name>`), follow its loaded instructions. Only invoke skills that appear in the session's available list — don't guess at names.
4
4
  - Use sub-agents to keep the main context lean. Delegate broad codebase exploration or research that'll take more than ~3 queries to an Explore-style agent (e.g. spawn Agent with `subagent_type=Explore`); otherwise use `find` or `grep` via the Bash tool directly. Don't duplicate searches a delegated agent is already doing.
5
- - If the user asks about "ultrareview" or how to run it, explain that /code-review ultra launches a multi-agent cloud review of the current branch (or /code-review ultra <PR#> for a GitHub PR); /ultrareview is a deprecated alias for the same command. It is user-triggered and billed; you cannot launch it yourself. It needs a git repository (offer to "git init" if not in one); the no-arg form bundles the local branch and does not need a GitHub remote.
5
+ - If the user asks about "ultrareview" or how to run it, explain that /code-review ultra launches a multi-agent cloud review of the current branch (or /code-review ultra <PR#> for a GitHub PR); /ultrareview is a deprecated alias for the same command. It is user-triggered and billed; you cannot launch it yourself, so do not attempt to via Bash or otherwise. It needs a git repository (offer to "git init" if not in one); the no-arg form bundles the local branch and does not need a GitHub remote.
@@ -0,0 +1,16 @@
1
+ # Style: Declaudified
2
+
3
+ How to write everything the user reads — answers, summaries, explanations, commit messages, docs.
4
+
5
+ - Lead with the answer. State the point first, then support it.
6
+ - Cut filler and metadiscourse — language that narrates the communicating instead of communicating: "let me lay out," "it's worth noting," "as mentioned above." Say the thing; don't say you're about to say it.
7
+ - Delete your opening sentence. The real first sentence is usually the second or third — cut the runway that sets up the answer instead of giving it.
8
+ - Do add relevant surrounding context that hasn't already been established in the conversation — don't assume the user has perfect repo or domain knowledge. Adding context they lack is welcome; restating what they just told you is not.
9
+ - Don't signpost structure. A list or table is self-evident; don't preface it with "here's a table of."
10
+ - Plain language: real names for real things, minimal jargon, no padding adjectives. Use real terminology; don't invent labels ("status," not "milestones").
11
+ - Drop dead tech-metaphors and stock phrases ("ship," "load-bearing," "first-class," "surface" as a verb, "seamless," "leverage," "robust"). Use the plain word or cut it; keep "ship" only for releasing software (else deliver / finish / send / hand off).
12
+ - Don't state a cause without evidence — label speculation or leave it out.
13
+
14
+ In short: say the thing; don't say you're about to say it, and don't say you understood the question.
15
+
16
+ References: George Orwell, "Politics and the English Language" (his plain-English rules); Strunk & White, *The Elements of Style* ("omit needless words"); Joseph Williams, *Style: Toward Clarity and Grace* (on cutting metadiscourse).
package/src/args.ts CHANGED
@@ -3,6 +3,7 @@ import { parseArgs } from "node:util";
3
3
  export interface ParsedArgs {
4
4
  base?: string;
5
5
  preset: string | null;
6
+ style?: string;
6
7
  overrides: {
7
8
  agency?: string;
8
9
  quality?: string;
@@ -34,6 +35,7 @@ export function parseCliArgs(argv: string[]): ParsedArgs {
34
35
  agency: { type: "string" },
35
36
  quality: { type: "string" },
36
37
  scope: { type: "string" },
38
+ style: { type: "string" },
37
39
  modifier: { type: "string", multiple: true },
38
40
  readonly: { type: "boolean" },
39
41
  print: { type: "boolean" },
@@ -78,7 +80,7 @@ export function parseCliArgs(argv: string[]): ParsedArgs {
78
80
 
79
81
  // Collect unknown flags for passthrough
80
82
  const knownFlags = new Set([
81
- "base", "agency", "quality", "scope", "modifier", "readonly", "print", "context-pacing",
83
+ "base", "agency", "quality", "scope", "style", "modifier", "readonly", "print", "context-pacing",
82
84
  "append-system-prompt", "append-system-prompt-file",
83
85
  "system-prompt", "system-prompt-file", "help", "version",
84
86
  ]);
@@ -102,6 +104,7 @@ export function parseCliArgs(argv: string[]): ParsedArgs {
102
104
  return {
103
105
  base: values.base as string | undefined,
104
106
  preset,
107
+ style: values.style as string | undefined,
105
108
  overrides,
106
109
  modifiers: {
107
110
  readonly: values.readonly === true,
package/src/assemble.ts CHANGED
@@ -116,6 +116,15 @@ export function getFragmentOrder(mode: ModeConfig, promptsDir: string): string[]
116
116
  }
117
117
  }
118
118
  }
119
+ // Style fragment rides the axes insertion point but applies even in
120
+ // none mode — an explicit --style is honored like explicit modifiers
121
+ if (mode.style) {
122
+ if (isAbsolute(mode.style)) {
123
+ fragments.push(mode.style);
124
+ } else {
125
+ fragments.push(`style/${mode.style}.md`);
126
+ }
127
+ }
119
128
  } else if (entry === "modifiers") {
120
129
  // All modifiers are fragment paths — just add them
121
130
  for (const modPath of mode.modifiers) {
package/src/build-info.ts CHANGED
@@ -12,6 +12,6 @@ export interface BuildInfo {
12
12
  export const BUILD_INFO: BuildInfo = {
13
13
  "repo": "https://github.com/nklisch/claude-code-modes",
14
14
  "branch": null,
15
- "commit": "967d10b",
15
+ "commit": "91f6069",
16
16
  "dirty": false
17
17
  };
package/src/config-cli.ts CHANGED
@@ -8,6 +8,7 @@ import {
8
8
  checkModifierNameCollision,
9
9
  checkPresetNameCollision,
10
10
  checkAxisValueCollision,
11
+ checkStyleNameCollision,
11
12
  } from "./config.js";
12
13
  import { AXIS_BUILTINS } from "./types.js";
13
14
  const VALID_AXES = Object.keys(AXIS_BUILTINS) as Array<"agency" | "quality" | "scope">;
@@ -120,6 +121,33 @@ function configRemoveModifier(configPath: string, name: string): void {
120
121
  );
121
122
  }
122
123
 
124
+ function configAddStyle(configPath: string, name: string, mdPath: string): void {
125
+ checkStyleNameCollision(name);
126
+ const config = readConfig(configPath);
127
+ config.styles = { ...config.styles, [name]: mdPath };
128
+ writeConfig(configPath, config);
129
+ process.stdout.write(
130
+ `Registered style "${name}" in ${configFileName(configPath)}\n`
131
+ );
132
+ }
133
+
134
+ function configRemoveStyle(configPath: string, name: string): void {
135
+ const config = readConfig(configPath);
136
+ const styles = config.styles ?? {};
137
+ if (!(name in styles)) {
138
+ throw new Error(
139
+ `Style "${name}" not found in ${configFileName(configPath)}`
140
+ );
141
+ }
142
+ const updated = { ...styles };
143
+ delete updated[name];
144
+ config.styles = updated;
145
+ writeConfig(configPath, config);
146
+ process.stdout.write(
147
+ `Unregistered style "${name}" from ${configFileName(configPath)}\n`
148
+ );
149
+ }
150
+
123
151
  function configAddAxis(configPath: string, axis: string, name: string, mdPath: string): void {
124
152
  if (!VALID_AXES.includes(axis as ValidAxis)) {
125
153
  throw new Error(
@@ -173,6 +201,7 @@ function configAddPreset(configPath: string, name: string, flags: string[]): voi
173
201
  agency: { type: "string" },
174
202
  quality: { type: "string" },
175
203
  scope: { type: "string" },
204
+ style: { type: "string" },
176
205
  modifier: { type: "string", multiple: true },
177
206
  readonly: { type: "boolean" },
178
207
  "context-pacing": { type: "boolean" },
@@ -184,6 +213,7 @@ function configAddPreset(configPath: string, name: string, flags: string[]): voi
184
213
  if (values.agency !== undefined) presetDef.agency = values.agency;
185
214
  if (values.quality !== undefined) presetDef.quality = values.quality;
186
215
  if (values.scope !== undefined) presetDef.scope = values.scope;
216
+ if (values.style !== undefined) presetDef.style = values.style;
187
217
  if (values.modifier !== undefined && values.modifier.length > 0) {
188
218
  presetDef.modifiers = values.modifier as string[];
189
219
  }
@@ -238,6 +268,8 @@ Subcommands:
238
268
  remove-default <name> Remove from defaultModifiers
239
269
  add-modifier <name> <path> Register a named modifier
240
270
  remove-modifier <name> Unregister a named modifier
271
+ add-style <name> <path> Register a named style
272
+ remove-style <name> Unregister a named style
241
273
  add-axis <axis> <name> <path> Register custom axis value
242
274
  remove-axis <axis> <name> Unregister custom axis value
243
275
  add-preset <name> [flags] Create a custom preset
@@ -247,6 +279,7 @@ Flags for add-preset:
247
279
  --agency <value>
248
280
  --quality <value>
249
281
  --scope <value>
282
+ --style <value>
250
283
  --modifier <name> (repeatable)
251
284
  --readonly
252
285
  --context-pacing`;
@@ -287,6 +320,18 @@ Flags for add-preset:
287
320
  break;
288
321
  }
289
322
 
323
+ case "add-style": {
324
+ if (rest.length < 2) throw new Error("add-style requires <name> <path>");
325
+ configAddStyle(configPath, rest[0], rest[1]);
326
+ break;
327
+ }
328
+
329
+ case "remove-style": {
330
+ if (rest.length < 1) throw new Error("remove-style requires <name>");
331
+ configRemoveStyle(configPath, rest[0]);
332
+ break;
333
+ }
334
+
290
335
  case "add-axis": {
291
336
  if (rest.length < 3) throw new Error("add-axis requires <axis> <name> <path>");
292
337
  configAddAxis(configPath, rest[0], rest[1], rest[2]);
package/src/config.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { readFileSync, existsSync } from "node:fs";
2
2
  import { join, dirname, resolve, isAbsolute } from "node:path";
3
3
  import { homedir } from "node:os";
4
- import { PRESET_NAMES, BUILTIN_MODIFIER_NAMES, AXIS_BUILTINS, BUILTIN_BASE_NAMES, isBuiltinModifier, isPresetName, isBuiltinBase, isBuiltinAxisValue } from "./types.js";
4
+ import { PRESET_NAMES, BUILTIN_MODIFIER_NAMES, AXIS_BUILTINS, BUILTIN_BASE_NAMES, STYLE_VALUES, isBuiltinModifier, isPresetName, isBuiltinBase, isBuiltinAxisValue, isBuiltinStyle } from "./types.js";
5
5
 
6
6
  /**
7
7
  * Matches paths that reference potentially sensitive files (SSH keys, credentials, etc.).
@@ -33,6 +33,8 @@ function validateConfigDefinedPath(path: string, context: string, configPath: st
33
33
  export interface UserConfig {
34
34
  defaultBase?: string;
35
35
  bases?: Record<string, string>; // name → directory path (relative to config dir)
36
+ defaultStyle?: string;
37
+ styles?: Record<string, string>; // name → .md path (relative to config dir)
36
38
  defaultModifiers?: string[];
37
39
  modifiers?: Record<string, string>;
38
40
  axes?: {
@@ -48,6 +50,7 @@ export interface CustomPresetDef {
48
50
  agency?: string;
49
51
  quality?: string;
50
52
  scope?: string;
53
+ style?: string;
51
54
  modifiers?: string[];
52
55
  readonly?: boolean;
53
56
  contextPacing?: boolean;
@@ -76,6 +79,15 @@ export function checkPresetNameCollision(name: string): void {
76
79
  }
77
80
  }
78
81
 
82
+ /** Throws if name collides with a built-in style name. */
83
+ export function checkStyleNameCollision(name: string): void {
84
+ if (isBuiltinStyle(name)) {
85
+ throw new Error(
86
+ `"${name}" is a built-in style name (${STYLE_VALUES.join(", ")}); choose a different name`
87
+ );
88
+ }
89
+ }
90
+
79
91
  /** Throws if name collides with a built-in base name. */
80
92
  export function checkBaseNameCollision(name: string): void {
81
93
  if (isBuiltinBase(name)) {
@@ -204,6 +216,22 @@ function validateConfig(raw: unknown, configPath: string): UserConfig {
204
216
  for (const key of Object.keys(bases)) checkBaseNameCollision(key);
205
217
  }
206
218
 
219
+ // Validate defaultStyle
220
+ if (obj.defaultStyle !== undefined && typeof obj.defaultStyle !== "string") {
221
+ throw new Error(
222
+ `Invalid config file ${configPath}: "defaultStyle" must be a string`
223
+ );
224
+ }
225
+
226
+ // Validate styles map
227
+ if (obj.styles !== undefined) {
228
+ const styles = validateStringRecord(obj.styles, "styles", configPath);
229
+ for (const [key, val] of Object.entries(styles)) {
230
+ checkStyleNameCollision(key);
231
+ validateConfigDefinedPath(val, `"styles.${key}"`, configPath);
232
+ }
233
+ }
234
+
207
235
  // Validate defaultModifiers
208
236
  if (obj.defaultModifiers !== undefined) {
209
237
  const defaultModifiers = validateStringArray(obj.defaultModifiers, "defaultModifiers", configPath);
@@ -262,7 +290,7 @@ function validateConfig(raw: unknown, configPath: string): UserConfig {
262
290
  `Invalid config file ${configPath}: preset "${presetName}.base" must be a string`
263
291
  );
264
292
  }
265
- for (const field of ["agency", "quality", "scope"] as const) {
293
+ for (const field of ["agency", "quality", "scope", "style"] as const) {
266
294
  if (def[field] !== undefined && typeof def[field] !== "string") {
267
295
  throw new Error(
268
296
  `Invalid config file ${configPath}: preset "${presetName}.${field}" must be a string`
@@ -45,7 +45,7 @@ Examples of the kind of risky actions that warrant user confirmation:
45
45
  - Actions visible to others or that affect shared state: pushing code, creating/closing/commenting on PRs or issues, sending messages (Slack, email, GitHub), posting to external services, modifying shared infrastructure or permissions
46
46
  - Uploading content to third-party web tools (diagram renderers, pastebins, gists) publishes it - consider whether it could be sensitive before sending, since it may be cached or indexed even if later deleted.
47
47
 
48
- When you encounter an obstacle, do not use destructive actions as a shortcut to simply make it go away. For instance, try to identify root causes and fix underlying issues rather than bypassing safety checks (e.g. --no-verify). If you discover unexpected state like unfamiliar files, branches, or configuration, investigate before deleting or overwriting, as it may represent the user's in-progress work. For example, typically resolve merge conflicts rather than discarding changes; similarly, if a lock file exists, investigate what process holds it rather than deleting it. In short: only take risky actions carefully, and when in doubt, ask before acting. Follow both the spirit and letter of these instructions - measure twice, cut once.
48
+ When you encounter an obstacle, do not use destructive actions as a shortcut to simply make it go away. For instance, try to identify root causes and fix underlying issues rather than bypassing safety checks (e.g. --no-verify). If you discover unexpected state like unfamiliar files, branches, or configuration, investigate before deleting or overwriting, as it may represent the user's in-progress work. If you're unsure whether the user would want something kept, prefer a reversible step (move it aside, rename it, or stash it) over deleting; files you created yourself this session (scratch outputs, experiment intermediates) are yours to clean up freely. For example, typically resolve merge conflicts rather than discarding changes; similarly, if a lock file exists, investigate what process holds it rather than deleting it. In a git repository, run \`git status\` before any command that could discard uncommitted work (git checkout/restore/reset/clean, rm -rf on a repo path, restoring from a snapshot), and stash (with \`-u\` for untracked) or commit anything you find first. In short: only take risky actions carefully, and when in doubt, ask before acting. Follow both the spirit and letter of these instructions - measure twice, cut once.
49
49
  `,
50
50
  "base/tools.md": `# Using your tools
51
51
  - Use your dedicated tools instead of shell equivalents. Read works better than cat or grep. Editing via sed or awk is error-prone and slow compared to Edit or your global search-and-replace tools. Using pgrep or echo for process monitoring just slows us down without adding control. Bash tools require user approval and may be rejected, especially in a sequence — calling them when a dedicated tool would do is a cost we don't need to pay.
@@ -75,7 +75,7 @@ In code: default to writing no comments. Never write multi-paragraph docstrings
75
75
  - If the user needs to run a shell command themselves (an interactive login like \`gcloud auth login\`, or something requiring their own credentials), suggest they type \`! <command>\` — the \`!\` prefix runs the command in this session so its output lands in the conversation.
76
76
  - When the user invokes a slash-prefixed skill (\`/<name>\`), follow its loaded instructions. Only invoke skills that appear in the session's available list — don't guess at names.
77
77
  - Use sub-agents to keep the main context lean. Delegate broad codebase exploration or research that'll take more than ~3 queries to an Explore-style agent (e.g. spawn Agent with \`subagent_type=Explore\`); otherwise use \`find\` or \`grep\` via the Bash tool directly. Don't duplicate searches a delegated agent is already doing.
78
- - If the user asks about "ultrareview" or how to run it, explain that /code-review ultra launches a multi-agent cloud review of the current branch (or /code-review ultra <PR#> for a GitHub PR); /ultrareview is a deprecated alias for the same command. It is user-triggered and billed; you cannot launch it yourself. It needs a git repository (offer to "git init" if not in one); the no-arg form bundles the local branch and does not need a GitHub remote.
78
+ - If the user asks about "ultrareview" or how to run it, explain that /code-review ultra launches a multi-agent cloud review of the current branch (or /code-review ultra <PR#> for a GitHub PR); /ultrareview is a deprecated alias for the same command. It is user-triggered and billed; you cannot launch it yourself, so do not attempt to via Bash or otherwise. It needs a git repository (offer to "git init" if not in one); the no-arg form bundles the local branch and does not need a GitHub remote.
79
79
  `,
80
80
  "base/env.md": `# Environment
81
81
  You have been invoked in the following environment:
@@ -86,9 +86,9 @@ You have been invoked in the following environment:
86
86
  - OS Version: {{OS_VERSION}}
87
87
  - You are powered by the model named {{MODEL_NAME}}. The exact model ID is {{MODEL_ID}}.
88
88
  - Assistant knowledge cutoff is {{KNOWLEDGE_CUTOFF}}.
89
- - The most recent Claude models are Fable 5 and the Claude 4.X family. Model IDs — Fable 5: 'claude-fable-5', Opus 4.8: 'claude-opus-4-8', Sonnet 4.6: 'claude-sonnet-4-6', Haiku 4.5: 'claude-haiku-4-5-20251001'. When building AI applications, default to the latest and most capable Claude models.
89
+ - The most recent Claude models are the Claude 5 family, Opus 4.8, and Haiku 4.5. Model IDs — Fable 5: 'claude-fable-5', Opus 4.8: 'claude-opus-4-8', Sonnet 5: 'claude-sonnet-5', Haiku 4.5: 'claude-haiku-4-5-20251001'. When building AI applications, default to the latest and most capable Claude models.
90
90
  - Claude Code is available as a CLI in the terminal, desktop app (Mac/Windows), web app (claude.ai/code), and IDE extensions (VS Code, JetBrains).
91
- - Fast mode for Claude Code uses Claude Opus with faster output (it does not downgrade to a smaller model). It can be toggled with /fast and is available on Opus 4.8/4.7/4.6.
91
+ - Fast mode for Claude Code uses Claude Opus with faster output (it does not downgrade to a smaller model). It can be toggled with /fast and is available on Opus 4.8/4.7.
92
92
 
93
93
  When working with tool results, write down any important information you might need later in your response, as the original tool result may be cleared later.
94
94
 
@@ -533,6 +533,23 @@ Stay strictly within the bounds of what was requested.
533
533
  - Do not refactor, rename, or reorganize anything that isn't directly required by the task.
534
534
  - If the request is to change function X, change function X. Do not also update its callers, its tests, or its documentation unless the request explicitly includes those.
535
535
  - If completing the request requires changing more code than expected, pause and confirm the scope with the user before proceeding.
536
+ `,
537
+ "style/declaudified.md": `# Style: Declaudified
538
+
539
+ How to write everything the user reads — answers, summaries, explanations, commit messages, docs.
540
+
541
+ - Lead with the answer. State the point first, then support it.
542
+ - Cut filler and metadiscourse — language that narrates the communicating instead of communicating: "let me lay out," "it's worth noting," "as mentioned above." Say the thing; don't say you're about to say it.
543
+ - Delete your opening sentence. The real first sentence is usually the second or third — cut the runway that sets up the answer instead of giving it.
544
+ - Do add relevant surrounding context that hasn't already been established in the conversation — don't assume the user has perfect repo or domain knowledge. Adding context they lack is welcome; restating what they just told you is not.
545
+ - Don't signpost structure. A list or table is self-evident; don't preface it with "here's a table of."
546
+ - Plain language: real names for real things, minimal jargon, no padding adjectives. Use real terminology; don't invent labels ("status," not "milestones").
547
+ - Drop dead tech-metaphors and stock phrases ("ship," "load-bearing," "first-class," "surface" as a verb, "seamless," "leverage," "robust"). Use the plain word or cut it; keep "ship" only for releasing software (else deliver / finish / send / hand off).
548
+ - Don't state a cause without evidence — label speculation or leave it out.
549
+
550
+ In short: say the thing; don't say you're about to say it, and don't say you understood the question.
551
+
552
+ References: George Orwell, "Politics and the English Language" (his plain-English rules); Strunk & White, *The Elements of Style* ("omit needless words"); Joseph Williams, *Style: Toward Clarity and Grace* (on cutting metadiscourse).
536
553
  `,
537
554
  "modifiers/readonly.md": `# Read-only mode
538
555
 
package/src/env.ts CHANGED
@@ -44,8 +44,8 @@ export function detectEnv(): EnvInfo {
44
44
  }
45
45
 
46
46
  // Hardcoded model info — update when Claude Code updates
47
- const MODEL_NAME = "Claude Opus 4.8";
48
- const MODEL_ID = "claude-opus-4-8";
47
+ const MODEL_NAME = "Fable 5";
48
+ const MODEL_ID = "claude-fable-5";
49
49
  const KNOWLEDGE_CUTOFF = "January 2026";
50
50
 
51
51
  export function buildTemplateVars(env: EnvInfo): TemplateVars {
@@ -63,7 +63,8 @@ export function buildTemplateVars(env: EnvInfo): TemplateVars {
63
63
  }
64
64
 
65
65
  const worktreeNotice = env.isWorktree
66
- ? "\n - This is a git worktree — an isolated copy of the repository. Run all commands from this directory. Do NOT `cd` to the original repository root."
66
+ ? "\n - This is a git worktree — an isolated copy of the repository. Run all commands from this directory. Do NOT `cd` to the original repository root." +
67
+ "\n - The git stash stack is shared with the main checkout and all other worktrees, and other Claude sessions may push or pop it concurrently. Never use bare `git stash` / `git stash pop` — you could pop another session's changes. Prefer a temporary WIP commit to set work aside; if you must stash, use `git stash push -u -m \"<unique-tag>\"`, immediately capture your entry's SHA via `git stash list --format='%H %gs'`, restore with `git stash apply <sha>` (not pop), and afterwards drop the entry, re-finding its current `stash@{n}` by tag first."
67
68
  : "";
68
69
 
69
70
  return {
package/src/inspect.ts CHANGED
@@ -66,6 +66,13 @@ function collectConfigDefinedPaths(loadedConfig: LoadedConfig | null): Set<strin
66
66
  }
67
67
  }
68
68
 
69
+ // Style definitions
70
+ if (config.styles) {
71
+ for (const val of Object.values(config.styles)) {
72
+ paths.add(resolveConfigPath(configDir, val));
73
+ }
74
+ }
75
+
69
76
  // Axis definitions
70
77
  if (config.axes) {
71
78
  for (const axisName of ["agency", "quality", "scope"] as const) {
package/src/presets.ts CHANGED
@@ -5,6 +5,7 @@ export interface PresetDefinition {
5
5
  axes: AxisConfig | null;
6
6
  readonly: boolean;
7
7
  base?: string; // default base for this preset
8
+ style?: string; // default style for this preset
8
9
  modifiers: string[]; // built-in modifier names to apply
9
10
  }
10
11
 
package/src/resolve.ts CHANGED
@@ -7,11 +7,13 @@ import {
7
7
  AGENCY_VALUES,
8
8
  QUALITY_VALUES,
9
9
  SCOPE_VALUES,
10
+ STYLE_VALUES,
10
11
  BUILTIN_MODIFIER_NAMES,
11
12
  BUILTIN_BASE_NAMES,
12
13
  PRESET_NAMES,
13
14
  isBuiltinModifier,
14
15
  isBuiltinBase,
16
+ isBuiltinStyle,
15
17
  } from "./types.js";
16
18
  import { resolve as pathResolve, isAbsolute } from "node:path";
17
19
 
@@ -128,6 +130,51 @@ function applyModifiers(
128
130
  }
129
131
  }
130
132
 
133
+ /**
134
+ * Resolves a style value to either a built-in name or an absolute path.
135
+ * Resolution order: built-in values → config-defined names → file path heuristic.
136
+ * Throws with descriptive error if unresolvable.
137
+ */
138
+ function resolveStyleValue(raw: string, loadedConfig: LoadedConfig | null): string {
139
+ // 1. Built-in value
140
+ if (isBuiltinStyle(raw)) return raw;
141
+
142
+ // 2. Config-defined custom name
143
+ const configStyles = loadedConfig?.config.styles;
144
+ if (configStyles && raw in configStyles) {
145
+ return resolveConfigPath(loadedConfig!.configDir, configStyles[raw]);
146
+ }
147
+
148
+ // 3. File path
149
+ if (looksLikeFilePath(raw)) {
150
+ return isAbsolute(raw) ? raw : pathResolve(raw);
151
+ }
152
+
153
+ // 4. Unknown
154
+ const configHint = loadedConfig
155
+ ? ` Config loaded from: ${loadedConfig.configDir}`
156
+ : " No config file found.";
157
+ throw new Error(
158
+ `Unknown --style value: "${raw}". ` +
159
+ `Must be one of: ${STYLE_VALUES.join(", ")}, ` +
160
+ `a name defined in your config, or a file path.${configHint}`
161
+ );
162
+ }
163
+
164
+ /**
165
+ * Resolves the active style, or null when none applies.
166
+ * Priority: CLI --style > config defaultStyle > preset style > none
167
+ */
168
+ function resolveStyle(
169
+ raw: string | undefined,
170
+ loadedConfig: LoadedConfig | null,
171
+ presetStyle: string | undefined,
172
+ ): string | null {
173
+ const value = raw ?? loadedConfig?.config.defaultStyle ?? presetStyle;
174
+ if (value === undefined) return null;
175
+ return resolveStyleValue(value, loadedConfig);
176
+ }
177
+
131
178
  /**
132
179
  * Resolves a base reference to a built-in name or absolute directory path.
133
180
  * Priority: CLI --base > config defaultBase > preset base > "standard"
@@ -190,12 +237,14 @@ export function resolveConfig(
190
237
  // 3. CLI --modifier flags — appended after defaults
191
238
  applyModifiers(parsed.customModifiers, loadedConfig, modifierPaths, "append");
192
239
 
193
- // Handle "none" preset — resolve base before early return
240
+ // Handle "none" preset — resolve base before early return.
241
+ // Explicit --style (or config defaultStyle) still applies, like modifiers.
194
242
  if (parsed.preset === "none") {
195
243
  const base = resolveBase(parsed.base, loadedConfig, undefined);
196
244
  return {
197
245
  base,
198
246
  axes: null,
247
+ style: resolveStyle(parsed.style, loadedConfig, undefined),
199
248
  modifiers: modifierPaths,
200
249
  };
201
250
  }
@@ -204,6 +253,7 @@ export function resolveConfig(
204
253
  let quality: string;
205
254
  let scope: string;
206
255
  let presetBase: string | undefined;
256
+ let presetStyle: string | undefined;
207
257
 
208
258
  if (parsed.preset) {
209
259
  // Check built-in presets first, then config presets
@@ -220,6 +270,7 @@ export function resolveConfig(
220
270
  ? resolveAxisValue(parsed.overrides.scope, "scope", SCOPE_VALUES, loadedConfig)
221
271
  : preset.axes.scope;
222
272
  presetBase = preset.base;
273
+ presetStyle = preset.style;
223
274
 
224
275
  // Apply preset's readonly flag as a modifier
225
276
  if (preset.readonly) {
@@ -233,6 +284,7 @@ export function resolveConfig(
233
284
  // Config-defined preset
234
285
  const customPreset = config.presets[parsed.preset];
235
286
  presetBase = customPreset.base;
287
+ presetStyle = customPreset.style;
236
288
  agency = parsed.overrides.agency
237
289
  ? resolveAxisValue(parsed.overrides.agency, "agency", AGENCY_VALUES, loadedConfig)
238
290
  : customPreset.agency
@@ -284,10 +336,12 @@ export function resolveConfig(
284
336
  }
285
337
 
286
338
  const base = resolveBase(parsed.base, loadedConfig, presetBase);
339
+ const style = resolveStyle(parsed.style, loadedConfig, presetStyle);
287
340
 
288
341
  return {
289
342
  base,
290
343
  axes: { agency, quality, scope },
344
+ style,
291
345
  modifiers: modifierPaths,
292
346
  };
293
347
  }
package/src/types.ts CHANGED
@@ -7,6 +7,13 @@ export type Quality = (typeof QUALITY_VALUES)[number];
7
7
  export const SCOPE_VALUES = ["unrestricted", "adjacent", "narrow"] as const;
8
8
  export type Scope = (typeof SCOPE_VALUES)[number];
9
9
 
10
+ // Built-in style names — writing styles applied on top of any base/axes
11
+ export const STYLE_VALUES = ["declaudified"] as const;
12
+ export type Style = (typeof STYLE_VALUES)[number];
13
+ export function isBuiltinStyle(value: string): value is Style {
14
+ return (STYLE_VALUES as readonly string[]).includes(value);
15
+ }
16
+
10
17
  export const PRESET_NAMES = [
11
18
  "create",
12
19
  "extend",
@@ -69,6 +76,7 @@ export interface AxisConfig {
69
76
  export interface ModeConfig {
70
77
  base: string; // built-in name ("standard", "chill") or absolute path to base directory
71
78
  axes: AxisConfig | null; // null for "none" mode
79
+ style: string | null; // built-in name or absolute path to a custom fragment; null = no style
72
80
  modifiers: string[]; // ordered list of modifier fragment paths (embedded keys or absolute paths)
73
81
  }
74
82
 
package/src/update.ts CHANGED
@@ -159,11 +159,13 @@ export function classifyInstall(
159
159
  execPath: string = process.execPath,
160
160
  buildInfo: BuildInfo = BUILD_INFO,
161
161
  ): InstallClassification {
162
- // 1. Runtime interpreter → source mode
163
- if (SOURCE_EXEC_NAMES.has(basename(execPath))) {
162
+ // 1. Runtime interpreter → source mode. The npm distribution of bun names
163
+ // its binary "bun.exe" on every platform, so strip the suffix before matching.
164
+ const execName = basename(execPath).replace(/\.exe$/, "");
165
+ if (SOURCE_EXEC_NAMES.has(execName)) {
164
166
  return {
165
167
  kind: "source",
166
- reason: `Running as ${basename(execPath)} runtime (source mode)`,
168
+ reason: `Running as ${execName} runtime (source mode)`,
167
169
  };
168
170
  }
169
171
 
package/src/usage.ts CHANGED
@@ -42,6 +42,11 @@ Axis overrides:
42
42
  --scope <value> Built-in: unrestricted, adjacent, narrow
43
43
  Axis values can also be config-defined names or file paths (.md files).
44
44
 
45
+ Style:
46
+ --style <value> Writing style for output. Built-in: declaudified
47
+ Style can also be a config-defined name or a file path (.md file).
48
+ No style is applied unless set via --style, config defaultStyle, or a preset.
49
+
45
50
  Modifiers:
46
51
  --readonly Prevent file modifications
47
52
  --context-pacing Include context pacing prompt
@@ -60,6 +65,7 @@ Examples:
60
65
  claude-mode create
61
66
  claude-mode create --base chill # use the chill base
62
67
  claude-mode create --quality pragmatic
68
+ claude-mode create --style declaudified # lead-with-the-answer writing, no filler
63
69
  claude-mode create --modifier ./my-rules.md
64
70
  claude-mode --agency autonomous --quality ./team-quality.md
65
71
  claude-mode team-default # custom preset from config