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 +20 -2
- package/package.json +1 -1
- package/prompts/base/actions.md +1 -1
- package/prompts/base/env.md +2 -2
- package/prompts/base/session-guidance.md +1 -1
- package/prompts/style/declaudified.md +16 -0
- package/src/args.ts +4 -1
- package/src/assemble.ts +9 -0
- package/src/build-info.ts +1 -1
- package/src/config-cli.ts +45 -0
- package/src/config.ts +30 -2
- package/src/embedded-prompts.ts +21 -4
- package/src/env.ts +4 -3
- package/src/inspect.ts +7 -0
- package/src/presets.ts +1 -0
- package/src/resolve.ts +55 -1
- package/src/types.ts +8 -0
- package/src/update.ts +5 -3
- package/src/usage.ts +6 -0
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.
|
|
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
package/prompts/base/actions.md
CHANGED
|
@@ -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.
|
package/prompts/base/env.md
CHANGED
|
@@ -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
|
|
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
|
|
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
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`
|
package/src/embedded-prompts.ts
CHANGED
|
@@ -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
|
|
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
|
|
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 = "
|
|
48
|
-
const MODEL_ID = "claude-
|
|
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
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
|
-
|
|
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 ${
|
|
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
|