baldart 4.49.1 → 4.50.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/CHANGELOG.md CHANGED
@@ -5,6 +5,17 @@ All notable changes to BALDART will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [4.50.0] - 2026-06-17
9
+
10
+ **BALDART ships a `Terse` Claude Code output style as a latent, opt-in deliverable — installed with every Claude-enabled consumer, activated only by the user.** Output styles (selected via `/config` → Output Style; active style stored as the top-level `outputStyle` settings key) are the *native, higher-precedence* lever for compressing assistant prose — stronger than `CLAUDE.md` guidance, which is project context the model weighs against its conversational default. The new `framework/.claude/output-styles/terse.md` is the caveman-style ethos generalized to the whole chat: compress *how* the assistant talks (no preamble/postamble, no "now I will…", no tool-call narration, lead with the result), with an explicit **Auto-clarity carve-out** (plans, clarifying questions, destructive-action confirmations, decision trade-offs stay full) and a preserved-engineering-behavior preamble so it only changes verbosity, never capability. Distribution reuses the v4.14.0 dynamic-workflows machinery: a new `outputStyle` entry in `MERGE_KINDS` (per-item symlink, **overlay-free** — a style is a single latent opinion file the user activates wholesale or replaces with their own), `claude.js` exposes `outputStylesDir()`, `codex.js` returns `null` (**Claude-only** — Codex has no output styles). Installing the file changes nothing; `baldart configure` adds an **interactive-only, default-NO** prompt to activate it (writes `outputStyle: "Terse"` to `.claude/settings.local.json` — personal, gitignored, never forced on the team). **MINOR** (additive payload type + CLI capability; **no new `baldart.config.yml` key** — `outputStyle` is a native Claude Code *settings* key, so the schema-change propagation rule does NOT apply; no removed surface).
11
+
12
+ ### Added
13
+
14
+ - **`framework/.claude/output-styles/terse.md`** — the `Terse` output style (frontmatter `name: Terse`): prose-only terseness with an Auto-clarity carve-out, preserving all software-engineering behavior.
15
+ - **`src/utils/symlinks.js`** — `outputStyle` kind in `MERGE_KINDS` + `mergeOutputStyles()` wrapper, wired into `createAllSymlinks()` and the install-validation reconcile loop. `_mergeBulkDir` generalized with an optional `srcDir` field (defaults to `<kind>s`) so the hyphenated `output-styles/` source dir Claude Code requires resolves correctly (the kind name `outputStyle` would otherwise pluralize to the wrong `outputStyles/`).
16
+ - **`src/utils/tool-adapters/{claude,codex}.js`** — `outputStylesDir()` (`.claude/output-styles` for Claude; `null` for Codex).
17
+ - **`src/commands/configure.js`** — `maybeActivateTerseOutputStyle()`: interactive-only, default-NO prompt to activate the style by writing `outputStyle: "Terse"` to `.claude/settings.local.json`; no-ops when the file is absent (Codex-only / older framework) or already active. New NEXT STEPS line pointing to `/config` → Output Style.
18
+
8
19
  ## [4.49.1] - 2026-06-17
9
20
 
10
21
  **The four `/new` dynamic workflows shed their paragraph-length `meta.description` — the last prose that re-entered the orchestrator context on every workflow completion.** The `Workflow` tool contract specifies `description` as a *one-line* field shown in the permission dialog, but `new-card-review` / `new-final-review` / `new2` / `new2-resolve` each carried a full-paragraph rationale (~150–230 words) that the runtime echoes back into the orchestrator prefix on the completion line — pure prose with zero runtime value (the orchestrator already knows what it invoked). Each is collapsed to a single line; the full semantics were already duplicated in the script's own args-contract comment block (source code, never injected into context) plus the `references/*.md` SSOT, so nothing is lost. Same family as the v4.49.0 prose-leak closures, applied to the workflow layer. **PATCH** (no behaviour change — descriptions are display/permission-dialog text only; **no new `baldart.config.yml` key**).
package/README.md CHANGED
@@ -358,6 +358,7 @@ your-project/
358
358
  │ ├── commands/ # Symlink → .framework/.claude/commands/
359
359
  │ ├── skills/ # Per-item merge dir (v2.1.1+): framework symlinks alongside your own skills
360
360
  │ ├── workflows/ # Per-item symlinks of framework dynamic workflows (v4.14.0+, Claude-only)
361
+ │ ├── output-styles/ # Per-item symlinks of framework output styles (v4.50.0+, Claude-only; latent — activate via /config)
361
362
  │ └── hooks/ # Customizable copies
362
363
  ├── baldart.config.yml # Project context: paths/identity/stack/features (v3.0.0+)
363
364
  ├── .baldart/
@@ -447,6 +448,7 @@ Files with symlinks auto-update when framework updates:
447
448
  - `.claude/agents/`
448
449
  - `.claude/commands/`
449
450
  - `.claude/workflows/` (v4.14.0+) — framework dynamic workflows, per-item symlinks (Claude-only; no Codex equivalent)
451
+ - `.claude/output-styles/` (v4.50.0+) — framework output styles, per-item symlinks (Claude-only; latent — installs without activating, toggle via `/config` → Output Style)
450
452
 
451
453
  Files managed by the CLI:
452
454
 
package/VERSION CHANGED
@@ -1 +1 @@
1
- 4.49.1
1
+ 4.50.0
@@ -0,0 +1,27 @@
1
+ ---
2
+ name: Terse
3
+ description: Caveman-style terseness — compress how the assistant talks (prose only), leaving reasoning and engineering behavior untouched, with an Auto-clarity carve-out for decision-grade content.
4
+ ---
5
+
6
+ You are an interactive CLI tool that helps users with software engineering tasks. Keep ALL of your software-engineering capabilities, tool use, and safety behavior exactly as in the default — this style changes ONLY how much prose you emit to the user, never what you do.
7
+
8
+ ## Communication style — terse
9
+
10
+ Compress *how* you talk, never *what* you do. Reasoning and work stay full; only the user-facing prose is lean.
11
+
12
+ - No preamble or postamble. Do not open with "Sure!"/"Great question" or close with "Let me know if…"/"Hope this helps"/"In summary". Answer directly.
13
+ - No narration of intent ("now I will…", "let me…") and no recap of what a tool just did or what an agent is doing. When you have enough to act, act.
14
+ - Lead with the result; add context only if asked or if it changes the decision. Don't survey options you won't pursue — give a recommendation.
15
+ - Report outcomes faithfully and compactly: `path:line`, error strings verbatim, exit codes — no prose wrapped around them.
16
+ - Default to a few words or a short sentence over a paragraph; use a list only when the user needs several discrete items.
17
+
18
+ ## Auto-clarity (carve-out — do NOT compress)
19
+
20
+ Content a human reads in order to *decide* stays full and clear:
21
+
22
+ - clarifying questions, plans / plan-mode output,
23
+ - confirmations of irreversible or destructive actions,
24
+ - explanations the user explicitly asked for,
25
+ - any trade-off where you expect the user to choose.
26
+
27
+ Terseness removes noise, never decision-grade substance. When in doubt about whether something is decision-grade, keep it clear.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "baldart",
3
- "version": "4.49.1",
3
+ "version": "4.50.0",
4
4
  "description": "Claude Agent Framework - Reusable framework for coordinating AI agents and humans in software projects",
5
5
  "bin": {
6
6
  "baldart": "./bin/baldart.js"
@@ -1118,6 +1118,51 @@ function serialize(config) {
1118
1118
  return header + yaml.dump(clean, { lineWidth: 100, noRefs: true });
1119
1119
  }
1120
1120
 
1121
+ /**
1122
+ * Offer to activate the framework-shipped `Terse` output style (v4.50.0+).
1123
+ *
1124
+ * The style FILE is installed latently by the symlink layer (`.claude/output-styles/terse.md`)
1125
+ * with every install — installing it changes nothing on its own. ACTIVATION, by contrast,
1126
+ * changes how every chat in the repo is phrased, so it is strictly opt-in: interactive only,
1127
+ * default NO, and written to `.claude/settings.local.json` (personal, gitignored — never forced
1128
+ * on the team via the committed `.claude/settings.json`). The active style is the top-level
1129
+ * `outputStyle` string key Claude Code reads (defaulting to "default").
1130
+ *
1131
+ * No-ops silently when the style file is absent (older framework / Codex-only install) or when
1132
+ * the style is already active.
1133
+ */
1134
+ async function maybeActivateTerseOutputStyle(cwd) {
1135
+ const styleFile = path.join(cwd, '.claude', 'output-styles', 'terse.md');
1136
+ if (!fs.existsSync(styleFile)) return; // not shipped / not linked — nothing to offer
1137
+
1138
+ const localPath = path.join(cwd, '.claude', 'settings.local.json');
1139
+ const sharedPath = path.join(cwd, '.claude', 'settings.json');
1140
+ const readJson = (p) => {
1141
+ try { return JSON.parse(fs.readFileSync(p, 'utf8')); } catch { return null; }
1142
+ };
1143
+ const local = readJson(localPath) || {};
1144
+ const shared = readJson(sharedPath) || {};
1145
+ const active = local.outputStyle || shared.outputStyle || 'default';
1146
+ if (active === 'Terse') {
1147
+ UI.info('Output style "Terse" is already active.');
1148
+ return;
1149
+ }
1150
+
1151
+ const enable = await UI.confirm(
1152
+ 'Activate the "Terse" output style now? (compresses assistant prose only — reasoning/work unchanged; toggle later via /config)',
1153
+ false
1154
+ );
1155
+ if (!enable) {
1156
+ UI.info('Left output style as-is. The "Terse" style stays available — activate it any time via /config → Output Style.');
1157
+ return;
1158
+ }
1159
+
1160
+ local.outputStyle = 'Terse';
1161
+ fs.mkdirSync(path.dirname(localPath), { recursive: true });
1162
+ fs.writeFileSync(localPath, `${JSON.stringify(local, null, 2)}\n`, 'utf8');
1163
+ UI.success('Activated "Terse" output style (.claude/settings.local.json). Restart Claude Code or /clear to apply.');
1164
+ }
1165
+
1121
1166
  async function configure(opts = {}) {
1122
1167
  const cwd = process.cwd();
1123
1168
  UI.header('BALDART CONFIGURE — project context');
@@ -1211,10 +1256,16 @@ async function configure(opts = {}) {
1211
1256
  UI.success(`Created ${OVERLAYS_DIR}/`);
1212
1257
  }
1213
1258
 
1259
+ // v4.50.0+: offer to turn on the latent "Terse" output style (interactive only).
1260
+ if (!opts.nonInteractive) {
1261
+ await maybeActivateTerseOutputStyle(cwd);
1262
+ }
1263
+
1214
1264
  UI.box('NEXT STEPS', [
1215
1265
  '• Review baldart.config.yml — values are committed to your repo',
1216
1266
  '• Author skill overlays in .baldart/overlays/<skill-name>.md',
1217
1267
  ' Examples: framework/templates/overlays/',
1268
+ '• Output style "Terse" available — toggle via /config → Output Style',
1218
1269
  '• Re-run `npx baldart configure` any time to refresh',
1219
1270
  ]);
1220
1271
  }
@@ -1181,6 +1181,7 @@ async function update(options = {}, unknownArgs = []) {
1181
1181
  symlinks.mergeAgents({ tools: enabledTools });
1182
1182
  symlinks.mergeCommands({ tools: enabledTools });
1183
1183
  symlinks.mergeWorkflows({ tools: enabledTools });
1184
+ symlinks.mergeOutputStyles({ tools: enabledTools });
1184
1185
  }
1185
1186
 
1186
1187
  // Routines wizard (since v2.1.0) — surfaces routines added in the new framework version
@@ -19,13 +19,21 @@ const CONFLICT_LOG = path.join('.baldart', 'skill-conflicts.json');
19
19
  // - ext: the file extension of the source items.
20
20
  // - overlay: whether the base+overlay generation path applies. Overlays
21
21
  // are a markdown construct (`## [OVERRIDE]` sections + HTML-comment
22
- // marker), so they only make sense for `.md` kinds. Workflows are `.js`
23
- // and are distributed as plain per-item symlinks no overlay.
22
+ // marker). Workflows are `.js` so they can't carry overlays. Output styles
23
+ // ARE `.md` but are still distributed overlay-free (`overlay: false`): a
24
+ // style is a single latent opinion file the user activates wholesale via
25
+ // `/config` or replaces by dropping their own file in the same dir — there
26
+ // is no per-section merge to do.
24
27
  // - exclude: filenames in the source dir that are NOT installable items.
28
+ // - srcDir: framework source subdir under `.framework/framework/.claude/`.
29
+ // Defaults to `<kind>s` (agents/commands/workflows). Set explicitly when the
30
+ // kind name doesn't pluralize to the on-disk dir — e.g. `outputStyle` lives in
31
+ // the hyphenated `output-styles/` dir Claude Code requires, not `outputStyles/`.
25
32
  const MERGE_KINDS = {
26
- agent: { dirGetter: 'agentsDir', ext: '.md', overlay: true, exclude: new Set(['REGISTRY.md']) },
27
- command: { dirGetter: 'commandsDir', ext: '.md', overlay: true, exclude: new Set(['REGISTRY.md']) },
28
- workflow: { dirGetter: 'workflowsDir', ext: '.js', overlay: false, exclude: new Set() },
33
+ agent: { dirGetter: 'agentsDir', ext: '.md', overlay: true, exclude: new Set(['REGISTRY.md']) },
34
+ command: { dirGetter: 'commandsDir', ext: '.md', overlay: true, exclude: new Set(['REGISTRY.md']) },
35
+ workflow: { dirGetter: 'workflowsDir', ext: '.js', overlay: false, exclude: new Set() },
36
+ outputStyle: { dirGetter: 'outputStylesDir', ext: '.md', overlay: false, exclude: new Set(), srcDir: 'output-styles' },
29
37
  };
30
38
 
31
39
  /**
@@ -345,6 +353,10 @@ class SymlinkUtils {
345
353
  UI.section('Merging Framework Workflows');
346
354
  this.mergeWorkflows({ tools: opts.tools });
347
355
 
356
+ UI.newline();
357
+ UI.section('Merging Framework Output Styles');
358
+ this.mergeOutputStyles({ tools: opts.tools });
359
+
348
360
  UI.newline();
349
361
  }
350
362
 
@@ -360,6 +372,7 @@ class SymlinkUtils {
360
372
  mergeAgents(opts = {}) { return this._mergeBulkDir('agent', opts); }
361
373
  mergeCommands(opts = {}) { return this._mergeBulkDir('command', opts); }
362
374
  mergeWorkflows(opts = {}) { return this._mergeBulkDir('workflow', opts); }
375
+ mergeOutputStyles(opts = {}) { return this._mergeBulkDir('outputStyle', opts); }
363
376
 
364
377
  /**
365
378
  * Generic per-item merge for kinds whose framework source is a directory
@@ -377,7 +390,8 @@ class SymlinkUtils {
377
390
  const aggregate = { linked: [], generated: [], skipped: [], conflicts: [], warnings: [] };
378
391
  const { getAdapter } = require('./tool-adapters');
379
392
 
380
- const fwSourceDir = path.join(this.cwd, FRAMEWORK_PAYLOAD, '.claude', `${kind}s`);
393
+ const srcDirName = cfg.srcDir || `${kind}s`;
394
+ const fwSourceDir = path.join(this.cwd, FRAMEWORK_PAYLOAD, '.claude', srcDirName);
381
395
  if (!fs.existsSync(fwSourceDir)) {
382
396
  UI.warning(`No framework ${kind}s found at ${path.relative(this.cwd, fwSourceDir)}. Skipping ${kind} merge.`);
383
397
  return aggregate;
@@ -405,7 +419,7 @@ class SymlinkUtils {
405
419
  // portable if the project gets moved.
406
420
  const linkDepth = targetRel.split(path.sep).filter(Boolean).length;
407
421
  const upPath = path.join(...Array(linkDepth).fill('..'));
408
- const target = path.join(upPath, FRAMEWORK_PAYLOAD, '.claude', `${kind}s`, filename);
422
+ const target = path.join(upPath, FRAMEWORK_PAYLOAD, '.claude', srcDirName, filename);
409
423
 
410
424
  const overlayRel = path.join('.baldart', 'overlays', `${kind}s`, filename);
411
425
  const overlayAbs = path.join(this.cwd, overlayRel);
@@ -676,7 +690,8 @@ class SymlinkUtils {
676
690
 
677
691
  // v3.8.0+: agents and commands also use per-item merge with overlay support.
678
692
  // v4.14.0+: workflows (.js) use the same per-item merge, overlay-free.
679
- for (const [kindGetter, kindLabel] of [['agentsDir', 'agents'], ['commandsDir', 'commands'], ['workflowsDir', 'workflows']]) {
693
+ // v4.50.0+: output styles (.md) use the same per-item merge, overlay-free.
694
+ for (const [kindGetter, kindLabel] of [['agentsDir', 'agents'], ['commandsDir', 'commands'], ['workflowsDir', 'workflows'], ['outputStylesDir', 'output styles']]) {
680
695
  if (typeof adapter[kindGetter] !== 'function') continue;
681
696
  const rel = adapter[kindGetter]();
682
697
  if (!rel) continue;
@@ -6,6 +6,7 @@
6
6
  * - `.claude/agents/<agent>.md` (subagents, bulk symlink)
7
7
  * - `.claude/commands/<command>.md` (slash commands, bulk symlink)
8
8
  * - `.claude/workflows/<workflow>.js` (dynamic workflows, per-item symlinks)
9
+ * - `.claude/output-styles/<name>.md` (output styles, per-item symlinks)
9
10
  * - `.claude/settings.json` (hooks, ide config)
10
11
  * - `AGENTS.md` (root coordination protocol)
11
12
  *
@@ -31,6 +32,9 @@ class ClaudeAdapter {
31
32
  /** Where this tool reads dynamic workflow scripts from (null if unsupported). */
32
33
  workflowsDir() { return '.claude/workflows'; }
33
34
 
35
+ /** Where this tool reads output-style definitions from (null if unsupported). */
36
+ outputStylesDir() { return '.claude/output-styles'; }
37
+
34
38
  /** Whether this tool consumes subagent definitions (`.claude/agents/`). */
35
39
  supportsSubagents() { return true; }
36
40
 
@@ -46,6 +46,11 @@ class CodexAdapter {
46
46
  // simply never linked into a Codex tree.
47
47
  workflowsDir() { return null; }
48
48
 
49
+ // Output styles are a Claude Code concept (selected via `/config`); Codex has
50
+ // no equivalent. Returning null disables the per-item output-style merge for
51
+ // Codex — the source style files are simply never linked into a Codex tree.
52
+ outputStylesDir() { return null; }
53
+
49
54
  supportsSubagents() { return false; }
50
55
  supportsSlashCommands() { return false; }
51
56
  supportsHooks() { return false; }