baldart 3.30.0 → 3.31.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,25 @@ 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
+ ## [3.31.0] - 2026-05-30
9
+
10
+ Gives `/baldart-update` an **autonomous mode** so agents and scheduled routines can bring the framework up-to-date with **zero human interaction** — closing the gap that the skill, as shipped, was *purely* human-in-the-loop (it replicated every CLI decision point as a chat confirmation, which an unattended agent cannot answer). The new mode is **auto-detected** from a positive automation signal and keeps every one of the CLI's safety gates: it drives `npx baldart update --yes` and **stops hard** (never forces a merge or reset) the moment the CLI refuses on custom divergence or a conflict — exactly the calls a human should own. **No new `baldart.config.yml` keys** — `BALDART_AUTONOMOUS` is a runtime env var, not a config flag, so the schema-propagation rule does not apply.
11
+
12
+ ### Added — autonomous (unattended) mode for `/baldart-update`
13
+
14
+ - **[framework/.claude/skills/baldart-update/SKILL.md](framework/.claude/skills/baldart-update/SKILL.md)**: new **Mode detection** first step (`printenv | grep -qE '^(BALDART_AUTONOMOUS|CI|GITHUB_ACTIONS)='`) branches the skill into INTERACTIVE (a human is present → existing chat-confirmation flow, unchanged) or AUTONOMOUS (no human → new flow). Detection is **positive-signal-only**: absence of every signal defaults to INTERACTIVE so a human never silently loses control. Documents *why* the TTY test (`[ -t 0 ]`) cannot be used — Claude's Bash tool never has a TTY on stdin, even with a human present, so it can't tell the two situations apart.
15
+ - **`## Autonomous mode`** section: pre-flight (shared Step 0 + CLI version drift gate) → `npx baldart update --yes` (bare, `timeout: 600000`) → exit-code interpretation → shared post-flight assert → structured log-friendly report. **Hard guardrail**: on a non-zero exit (custom-overlay-able / real-custom divergence, subtree-pull conflict, stale-CLI halt) the skill STOPS and reports the exact flag a human would re-run with — it **never** retries with `--on-divergence pull|scaffold-overlays` or `--reset` to force past a refusal. A refusal is a *correct* outcome that needs a human.
16
+
17
+ ### Added — automation marker injected by the routine-adapters
18
+
19
+ - **[src/utils/routine-adapters/github-actions.js](src/utils/routine-adapters/github-actions.js)**: the generated workflow's run step now sets `BALDART_AUTONOMOUS: '1'` in its `env:` block (alongside `ANTHROPIC_API_KEY`), inherited by the `claude` process and every child Bash it spawns.
20
+ - **[src/utils/routine-adapters/cron.js](src/utils/routine-adapters/cron.js)**: the generated shell wrapper `export`s `BALDART_AUTONOMOUS=1` before invoking `claude`.
21
+ - **[src/utils/routine-adapters/claude-code-cloud.js](src/utils/routine-adapters/claude-code-cloud.js)**: the generated routine config now carries `env: { BALDART_AUTONOMOUS: '1' }` (best-effort — relies on the RemoteTrigger surfacing `env` into the run environment; github-actions / cron inject it directly).
22
+
23
+ ### Changed — drift-check counter + honest framing
24
+
25
+ - **[framework/.claude/skills/baldart-update/SKILL.md](framework/.claude/skills/baldart-update/SKILL.md)**: `last_verified` v3.26.0 → v3.31.0; added an **AUTONOMY NOTE** recording that `BALDART_AUTONOMOUS` is a runtime env var (not a config key) so the schema-propagation rule does not apply. Hard rules gain a rule #0 (run mode detection first; default-on-absence is INTERACTIVE); rule #2 now qualifies the chat-replication mandate as INTERACTIVE-only. The closing "both keep the user in the loop" claim is corrected to reflect that autonomous mode drops confirmations while keeping the safety gates.
26
+
8
27
  ## [3.30.0] - 2026-05-29
9
28
 
10
29
  Hardens the **overlay** system — the layer that turns generic framework skills into project-specific knowledge. An audit surfaced a structural asymmetry: agent/command overlays are *compile-time merged* (the overlay is materially fused into the generated file → guaranteed delivery), but skill overlays use *runtime concatenation* (a line of prose tells the agent to read `.baldart/overlays/<skill>.md` → best-effort, nothing verifies it loaded). The most important overlays for knowledge transfer had the weakest guarantee. This release ships the high-certainty authoring/DX fixes now and adds **observation-only telemetry** to gather real data on whether skill overlays actually load — before deciding whether a stronger enforcement mechanism is worth building. **No new `baldart.config.yml` keys** — the telemetry hook is always-on (like `framework-edit-gate` / `agent-discovery-gate`), so the schema-propagation rule does not apply.
package/VERSION CHANGED
@@ -1 +1 @@
1
- 3.30.0
1
+ 3.31.0
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: baldart-update
3
- description: "Guidance for updating BALDART framework to the latest version in a consumer repo. Use when the user says /baldart-update, 'aggiorna baldart', 'aggiorna framework', 'update del framework', 'pull baldart latest', or wants to bring the framework up-to-date. Replicates the native CLI's user-decision points (preview diff, working-tree stash) as chat-side confirmations, lets the CLI auto-resolve mechanical noise (hook backfill, subtree-merge commits, schema migration), and asserts post-flight that .framework/VERSION actually changed. For non-update drift, defers to `npx baldart` (smart doctor)."
3
+ description: "Guidance for updating BALDART framework to the latest version in a consumer repo. Use when the user says /baldart-update, 'aggiorna baldart', 'aggiorna framework', 'update del framework', 'pull baldart latest', or wants to bring the framework up-to-date. Two modes, auto-detected: INTERACTIVE (a human is present) replicates the native CLI's user-decision points (preview diff, working-tree stash) as chat-side confirmations; AUTONOMOUS (unattended — CI / scheduled routine, signalled by BALDART_AUTONOMOUS / CI / GITHUB_ACTIONS env) runs `npx baldart update --yes` with zero prompts and hard-STOP guardrails (never forces a merge or reset on custom divergence / conflicts). Both let the CLI auto-resolve mechanical noise (hook backfill, subtree-merge commits, schema migration) and assert post-flight that .framework/VERSION actually changed. For non-update drift, defers to `npx baldart` (smart doctor)."
4
4
  contamination_scan: skip
5
5
  ---
6
6
 
@@ -12,10 +12,20 @@ pull_request). When any of the numbers below changes against the actual
12
12
  sources, a warning is surfaced in the workflow run. The decision whether
13
13
  this skill needs an update is left to a human reviewer.
14
14
 
15
- update_js_prompts: 7
15
+ update_js_prompts: 6
16
16
  hook_registry_entries: 4
17
17
  config_template_top_level_keys: features,git,identity,lsp,paths,stack,tools,version
18
- last_verified: v3.26.0
18
+ last_verified: v3.31.0
19
+ -->
20
+
21
+ <!--
22
+ AUTONOMY NOTE (v3.31.0)
23
+ `BALDART_AUTONOMOUS` is a RUNTIME ENV VAR, not a baldart.config.yml key — the
24
+ schema-change propagation rule does NOT apply (no template/configure/update
25
+ detector change). It is injected by the routine-adapters (github-actions: env
26
+ block; cron: `export`; claude-code-cloud: best-effort `env` field in the run
27
+ config) so scheduled routines run unattended. Any orchestrator that wants a
28
+ child agent to update autonomously can set it the same way.
19
29
  -->
20
30
 
21
31
 
@@ -42,7 +52,31 @@ CLI would normally ask in the terminal — so the CLI can be driven with
42
52
  ╚══════════════════════════════════════════════════════════════════════╝
43
53
  ```
44
54
 
45
- ## Execution modelIMPORTANT
55
+ ## Mode detectionFIRST STEP, BLOCKING (v3.31.0+)
56
+
57
+ Before anything else, decide which of two modes you are in. This gates the
58
+ entire rest of the skill.
59
+
60
+ ```bash
61
+ # A single positive signal of automation means "no human is in the loop".
62
+ # Absence of ALL signals means "human present" → stay interactive.
63
+ printenv | grep -qE '^(BALDART_AUTONOMOUS|CI|GITHUB_ACTIONS)=' && echo AUTONOMOUS || echo INTERACTIVE
64
+ ```
65
+
66
+ - **`AUTONOMOUS`** → no human can answer chat prompts (scheduled routine, CI,
67
+ or an orchestrator that exported the marker). Follow **`## Autonomous mode`**
68
+ below. Do NOT ask any chat questions — there is no one to read them.
69
+ - **`INTERACTIVE`** → a human is present. Follow the interactive flow
70
+ (Execution model + Workflow steps), which replicates every CLI decision
71
+ point as a chat confirmation.
72
+
73
+ > **Why not `[ -t 0 ]`?** When Claude runs a command via the Bash tool, stdin
74
+ > is never a TTY — not even with a human present. The TTY test cannot tell the
75
+ > two situations apart. Only a *positive* automation signal (env var) is
76
+ > reliable, and we default to INTERACTIVE on its absence so a human never
77
+ > silently loses control.
78
+
79
+ ## Execution model (INTERACTIVE mode) — IMPORTANT
46
80
 
47
81
  This is an **agent-driven skill with full chat-side replication** of every
48
82
  decision point the CLI would pose interactively. The flow is:
@@ -64,6 +98,60 @@ pure-guidance (the user runs the CLI themselves). Here the user has asked
64
98
  for an agent that drives the update, so the skill drives it — but it
65
99
  replicates every confirmation so nothing is silently auto-accepted.
66
100
 
101
+ ## Autonomous mode (AUTONOMOUS) — unattended, zero prompts (v3.31.0+)
102
+
103
+ When mode detection returned `AUTONOMOUS`, there is no human to confirm
104
+ anything. The skill drives the update end-to-end with NO chat questions, and
105
+ leans entirely on the CLI's own safety gates — which already **refuse** to do
106
+ anything destructive under bare `--yes`.
107
+
108
+ **The contract: autonomy over mechanical work, hard STOP on anything that
109
+ touches the user's custom content.**
110
+
111
+ ### Autonomous workflow
112
+
113
+ 1. **Pre-flight (read-only)** — same as interactive Step 0: run
114
+ `npx baldart version`, parse the `Installed:` and `Remote:` lines with the
115
+ tolerant matcher. Apply the same **CLI version drift gate** (a too-old
116
+ global CLI crossing the v3.27.0 payload boundary → STOP and report; do not
117
+ launch).
118
+ - Aligned / already up-to-date → report "already current", exit success.
119
+ 2. **Launch directly — no preview/stash confirmation:**
120
+ ```bash
121
+ npx baldart update --yes
122
+ ```
123
+ Use the Bash tool with `timeout: 600000`. `--yes` implies `--auto-stash`,
124
+ so a dirty tree is handled (stashed + re-applied) without asking.
125
+ **Do NOT add `--on-divergence pull` or `--reset`.** Bare `--yes` is the
126
+ safe ceiling: the CLI auto-resolves only mechanical noise and *refuses*
127
+ (exits non-zero) on real custom divergence.
128
+ 3. **Interpret the exit code (the whole point of staying safe):**
129
+ - **Exit 0** → update applied (or already aligned). Go to post-flight.
130
+ - **Exit non-zero** → the CLI hit a wall it will not cross unattended:
131
+ custom-overlay-able / real-custom divergence, a subtree-pull conflict, or
132
+ a stale-CLI halt. **STOP. Do NOT retry with `--on-divergence` or
133
+ `--reset`.** Report loudly (see below) so the human who reads the routine
134
+ log knows exactly what needs a hands-on decision. Forcing a merge or a
135
+ reset unattended is precisely the silent destruction this mode forbids.
136
+ 4. **Post-flight assert (MANDATORY)** — identical to interactive Step 4:
137
+ `cat .framework/VERSION`, compare to the pre-update version. If the CLI
138
+ exited 0 but VERSION did not change (and stdout is not "Already up to
139
+ date"), **FAIL LOUD** — do not report success.
140
+ 5. **Report** — emit a structured, log-friendly summary (no questions):
141
+ version delta, backup tag + rollback command, any agent-layout migration
142
+ (v3.27.0+), and — on a non-zero exit — the verbatim CLI stderr plus the
143
+ exact flag a human would re-run with (`--on-divergence pull` /
144
+ `scaffold-overlays` / `--reset --yes --i-know`). The skill names the
145
+ options; it never picks one autonomously.
146
+
147
+ ### What autonomous mode must NEVER do
148
+
149
+ - Ask a chat question (no one is there; a blocked prompt hangs the routine).
150
+ - Pass `--on-divergence pull|scaffold-overlays` or `--reset` to "get past" a
151
+ refusal. A refusal is a *correct* outcome that needs a human.
152
+ - Report success when the post-flight assert fails.
153
+ - Auto-resolve a stash-pop or merge conflict with `--hard` / `--no-verify`.
154
+
67
155
  ## When to use
68
156
 
69
157
  - The user invokes `/baldart-update`.
@@ -100,13 +188,20 @@ for the protocol.
100
188
 
101
189
  ## Hard rules
102
190
 
191
+ 0. **MUST run mode detection FIRST** (the `printenv | grep` probe above) and
192
+ branch accordingly. Defaulting to AUTONOMOUS when no signal is present —
193
+ or to INTERACTIVE when a signal IS present — are both wrong. The default on
194
+ *absence of signal* is INTERACTIVE (human keeps control).
103
195
  1. **MUST NOT re-implement the logic of `update.js`.** Same rule as
104
196
  `/baldart-push`: the CLI is the source of truth. The skill only
105
197
  replicates prompts and parses output.
106
- 2. **MUST replicate in chat all 5 decision points** before passing `--yes`:
107
- preview, working-tree stash, hooks drift, schema config drift,
108
- auto-commit of BALDART-managed files. Silencing one is dishonestthe
109
- user thinks they confirmed everything, but they didn't see that prompt.
198
+ 2. **(INTERACTIVE mode) MUST replicate in chat the 2 remaining decision
199
+ points** before passing `--yes`: preview and working-tree stash (the other
200
+ three hooks drift, schema config drift, BALDART-managed auto-commit are
201
+ auto-resolved silently by the CLI since v3.26.0). Silencing a real prompt
202
+ is dishonest — the user thinks they confirmed everything, but they didn't
203
+ see that prompt. **(AUTONOMOUS mode) MUST NOT ask any chat question** — see
204
+ `## Autonomous mode`; a blocked prompt hangs the routine.
110
205
  3. **MUST pass `timeout: 600000` (10 minutes)** to the `Bash` call running
111
206
  `npx baldart update --yes`. The default 120s is not enough for subtree
112
207
  pull + symlink reconcile + post-update wizard + hooks register +
@@ -150,7 +245,11 @@ post-flight assert:
150
245
  > preview. The repo URL is exposed by `npx baldart version` in the
151
246
  > `Repository:` line.
152
247
 
153
- ## Workflow
248
+ ## Workflow (INTERACTIVE mode)
249
+
250
+ > In AUTONOMOUS mode follow `## Autonomous mode` instead. Step 0 (pre-flight
251
+ > probe + CLI version drift gate) and Step 4 (post-flight assert) are shared
252
+ > by both modes; Steps 1–3 (chat confirmations) are interactive-only.
154
253
 
155
254
  ### Step 0 — Pre-flight (read-only)
156
255
 
@@ -391,5 +490,9 @@ spine of BALDART maintenance:
391
490
  - `/baldart-update` — pull from upstream.
392
491
  - `/baldart-push` — push to upstream.
393
492
 
394
- Both wrap the CLI without re-implementing it; both keep the user in the
395
- loop. The CLI remains the source of truth.
493
+ Both wrap the CLI without re-implementing it; the CLI remains the source of
494
+ truth. `/baldart-push` always keeps the user in the loop. `/baldart-update`
495
+ does too **when a human is present** (interactive mode); when run unattended
496
+ (autonomous mode — CI / scheduled routine) it drops the confirmations but
497
+ keeps the CLI's safety gates, stopping hard rather than forcing any
498
+ destructive resolution a human would otherwise own.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "baldart",
3
- "version": "3.30.0",
3
+ "version": "3.31.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"
@@ -43,6 +43,13 @@ class ClaudeCodeCloudAdapter {
43
43
  prompt: spec.prompt,
44
44
  output: spec.output,
45
45
  backend: this.name,
46
+ // Marks this as an unattended (no-human) run. Autonomy-aware skills
47
+ // (e.g. /baldart-update) auto-detect this and drop their chat
48
+ // confirmations, with safe guardrails (STOP on custom divergence /
49
+ // conflicts, never forces a destructive merge). Best-effort for this
50
+ // backend: RemoteTrigger must surface `env` into the run environment for
51
+ // the runtime probe to see it; github-actions / cron inject it directly.
52
+ env: { BALDART_AUTONOMOUS: '1' },
46
53
  installed_at: new Date().toISOString()
47
54
  };
48
55
  fs.writeFileSync(this.configPath(spec.name), JSON.stringify(config, null, 2) + '\n');
@@ -101,6 +101,13 @@ if ! command -v claude >/dev/null 2>&1; then
101
101
  fi
102
102
  : "\${ANTHROPIC_API_KEY:?ANTHROPIC_API_KEY must be set (export it from the cron env or your shell profile)}"
103
103
 
104
+ # Marks this as an unattended (no-human) run. The /baldart-update skill (and
105
+ # any other autonomy-aware skill) auto-detects this and switches to
106
+ # non-interactive mode — no chat confirmations, safe guardrails (STOP on
107
+ # custom divergence / conflicts, never forces a destructive merge). Exported
108
+ # so the \`claude\` process and every child Bash it spawns inherit it.
109
+ export BALDART_AUTONOMOUS=1
110
+
104
111
  DATE=$(date -u +%Y%m%d)
105
112
  OUT_PATH="${outputPath}"
106
113
  OUT_PATH="\${OUT_PATH//\\{\\{YYYYMMDD\\}\\}/$DATE}"
@@ -105,6 +105,13 @@ jobs:
105
105
  - name: Run ${spec.name}
106
106
  env:
107
107
  ANTHROPIC_API_KEY: \${{ secrets.ANTHROPIC_API_KEY }}
108
+ # Marks this as an unattended (no-human) run. The /baldart-update
109
+ # skill (and any other autonomy-aware skill) auto-detects this and
110
+ # switches to non-interactive mode — no chat confirmations, safe
111
+ # guardrails (STOP on custom divergence / conflicts, never forces a
112
+ # destructive merge). Inherited by the \`claude\` process and every
113
+ # child Bash it spawns.
114
+ BALDART_AUTONOMOUS: '1'
108
115
  run: |
109
116
  DATE=$(date -u +%Y%m%d)
110
117
  OUT_PATH="${outputPath}"