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 +11 -0
- package/README.md +2 -0
- package/VERSION +1 -1
- package/framework/.claude/output-styles/terse.md +27 -0
- package/package.json +1 -1
- package/src/commands/configure.js +51 -0
- package/src/commands/update.js +1 -0
- package/src/utils/symlinks.js +23 -8
- package/src/utils/tool-adapters/claude.js +4 -0
- package/src/utils/tool-adapters/codex.js +5 -0
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.
|
|
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
|
@@ -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
|
}
|
package/src/commands/update.js
CHANGED
|
@@ -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
|
package/src/utils/symlinks.js
CHANGED
|
@@ -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)
|
|
23
|
-
//
|
|
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:
|
|
27
|
-
command:
|
|
28
|
-
workflow:
|
|
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
|
|
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',
|
|
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
|
-
|
|
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; }
|