wogiflow 2.32.0 → 2.33.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.
@@ -497,6 +497,57 @@ await cancelTask('wf-123', 'superseded', false);
497
497
 
498
498
  - **Experimental flag**: `CLAUDE_CODE_FORK_SUBAGENT=1` enables forked subagents on external builds. Not currently consumed by WogiFlow. Tracked as a future enhancement for faster IGR sub-agent spawning.
499
499
 
500
+ ### Features in 2.1.118+ → 2.1.139 (consolidated)
501
+
502
+ Catch-up pass covering everything between 2.1.118 and 2.1.139 with a WogiFlow-relevant surface. Grouped by topic since most users jump several patch versions at once.
503
+
504
+ #### Hooks
505
+ - **`PostToolUse` `continueOnBlock` config option (2.1.139)** — when a `PostToolUse` hook returns a blocking decision, set `continueOnBlock: true` on the hook entry to feed the rejection reason back to Claude and continue the turn instead of dead-ending it. **Impact on WogiFlow (acted on, wf-cb951e91)**: WogiFlow's `PostToolUse` hook (`post-tool-use.js` → `core/validation.js runValidation`, adapter emits `decision: 'block'` on lint/typecheck failure) now sets `continueOnBlock: true` in generated settings (`scripts/hooks/adapters/claude-code.js generateConfig()`). Effect: a lint/typecheck failure after an `Edit`/`Write` is surfaced to Claude so it fixes the error in-loop — exactly what CLAUDE.md's "validate after EVERY file edit, don't edit another file until it passes" rule needs. Unknown field on Claude Code < 2.1.139 → silently ignored (prior behavior), so emitting it unconditionally is safe.
506
+ - **Hook `args: string[]` exec form (2.1.139)** — spawns the command directly without a shell, so path placeholders never need quoting. **Impact on WogiFlow**: evaluated and **not adopted** — see `.claude/rules/alternative-hook-args-exec-form.md`. Short version: WogiFlow's generated hook commands already double-quote the absolute path (`command: \`node "${...}"\``, which handles spaces); `args` would *replace* `command` and is silently ignored on Claude Code < 2.1.139, breaking hooks for users on older CC; the robustness delta for real-world project paths is negligible. Revisit when WogiFlow's minimum supported Claude Code version reaches 2.1.139.
507
+ - **Hooks now run without terminal access (2.1.139)** — a hook writing to the terminal could corrupt an on-screen interactive prompt; that's now prevented. **Impact on WogiFlow**: none — WogiFlow hooks communicate via the stdout-JSON protocol and use `console.error` (stderr) for debug logging only; grep-verified no hook touches `/dev/tty` or does raw terminal I/O.
508
+ - **`PostToolUse` / `PostToolUseFailure` inputs include `duration_ms` (2.1.119)** — **Impact on WogiFlow**: `post-tool-use.js` already feeds `selectDuration(parsedInput, …)` into `captureObservation` — when Claude Code supplies `duration_ms` the observation log gets the real tool duration instead of the hook's own wall-clock estimate. Automatic improvement, no change.
509
+ - **Fixed async `PostToolUse` hooks writing empty transcript entries (2.1.119)** — WogiFlow's `PostToolUse` hook is async (`runHook('PostToolUse', async …)`); this fixes a stray empty-entry bug. Automatic.
510
+ - **Hooks receive active effort level via `effort.level` JSON field + `$CLAUDE_EFFORT` env var (2.1.133)**; **`PostToolUse` can replace tool output via `hookSpecificOutput.updatedToolOutput` for all tools (2.1.121)**; **hooks can invoke MCP tools via `type: "mcp_tool"` (2.1.118)** — not currently consumed by WogiFlow; tracked as possible future enhancements (e.g. effort-aware validation strictness).
511
+ - **Fixed a malformed hooks entry invalidating the entire `settings.json` (2.1.122)** — **Impact on WogiFlow (relevant)**: WogiFlow generates the `hooks` block via `generateConfig()`. Before this fix, one bad hook entry would nuke *all* settings (permissions, model, env). Post-fix it's isolated. Reinforces the value of `node --check` + JSON-validity gates after editing hook generators (already in `.claude/settings.local.json`'s allow-list as a test command).
512
+ - **Fixed plugin `Stop`/`UserPromptSubmit` hooks failing when cache cleanup deletes a version still in use (2.1.136)**; **`CLAUDE_ENV_FILE` SessionStart-hook env vars going stale after `/resume` or `/clear` (2.1.136)** — automatic; WogiFlow ships no plugin in this repo and doesn't use `CLAUDE_ENV_FILE`, but target-project users with plugins benefit.
513
+
514
+ #### Skills & slash commands (WogiFlow `/wogi-*`)
515
+ - **`claude_code.skill_activated` OTel event now fires for user-typed slash commands with an `invocation_trigger` attribute (2.1.126)** — every `/wogi-*` invocation now emits a telemetry event distinguishable as user-typed vs model-invoked. Useful for anyone running WogiFlow with OTel enabled; no code change.
516
+ - **`skillOverrides` setting now works: `off` hides a skill from the model and `/`, `user-invocable-only` hides it from the model only (2.1.129)** — relevant to skill management (`lib/skill-registry.js`, `/wogi-skills`): users can hard-disable a WogiFlow skill via settings without uninstalling it. No code change; worth a `/wogi-skills` docs mention eventually.
517
+ - **`--dangerously-skip-permissions` no longer prompts for `.claude/skills/`, `.claude/agents/`, `.claude/commands/` (2.1.121)** and **`.claude/` / `.git/` / `.vscode/` / shell-config writes (2.1.126)** — `flow hooks setup` / `flow bridge sync` writes under `.claude/` now go through cleanly in skip-permissions mode. Catastrophic deletes still prompt.
518
+ - **Fixed skills invoked before auto-compaction re-executing on the next message (2.1.119)**; **subagents not discovering project/user/plugin skills via the Skill tool (2.1.133)** — **Impact on WogiFlow (HIGH)**: the flow is skill-driven (`/wogi-start` → `/wogi-story` → …) and Explore/Architect/Adversary sub-agents may invoke skills. Pre-fix a skill could double-fire across a compaction boundary, or a sub-agent couldn't see project skills at all. Both fixed; reliability improvement, no code change.
519
+ - **`claude ultrareview [target]` non-interactive subcommand (2.1.120)** — CI/script equivalent of `/ultrareview`. WogiFlow's session guidance already says `/ultrareview` is user-triggered and billed; this adds a headless variant. No change.
520
+ - **Fixed `AskUserQuestion` discarding multi-select answers supplied as an array (2.1.136)** — WogiFlow uses `AskUserQuestion` in interactive flows (blocked only in workspace *worker* mode). Multi-select answers now round-trip correctly. Automatic.
521
+
522
+ #### Worktrees & sub-agents
523
+ - **`worktree.baseRef` setting (`fresh` | `head`, 2.1.133)** and **`EnterWorktree` now branches from local `HEAD` as documented (2.1.128)** — WogiFlow's own `flow-worktree.js` is independent of native worktrees (different location, branch naming, cleanup — see the comparison table below) but *detects* and reuses a native worktree when launched with `--worktree`. The new `baseRef: head` default aligns native worktrees with what WogiFlow already does (branch from current state). No change.
524
+ - **Fixed `Agent` tool with `isolation: "worktree"` reusing stale worktrees (2.1.119)** — complements the 2.1.97 subagent-worktree-cwd-leak fix. `/wogi-bulk` and parallel-explore spawn worktree-isolated sub-agents; stale-worktree reuse could run a sub-agent against the previous task's tree. Fixed. Automatic.
525
+ - **Sub-agent progress-summary prompt-cache fixes (2.1.128: ~3× `cache_creation` reduction; summaries no longer fire repeatedly while the transcript is static)** — WogiFlow spawns several sub-agents per L1+ task (Explore ×N, Architect, Adversary). Cheaper, quieter sub-agent runs. Automatic.
526
+
527
+ #### Context, caching, 1M models
528
+ - **Fixed the 1-hour prompt-cache TTL being silently downgraded to 5 minutes (2.1.129)** — **Impact on WogiFlow (HIGH)**: WogiFlow loads a large stable prefix every turn (CLAUDE.md ~300 lines + `decisions.md` + `ready.json` + phase files + pinned spec context). The `ENABLE_PROMPT_CACHING_1H` guidance in the 2.1.108 section assumed 1h TTL actually held; before this fix it could collapse back to 5min, re-billing the whole prefix after any short pause. Fixed in 2.1.129. **Action**: still `export ENABLE_PROMPT_CACHING_1H=1` for API-key/Bedrock/Vertex/Foundry users (subscribers get 1h by default) — just be on 2.1.129+.
529
+ - **Fixed Bedrock/Vertex 400 errors when `ENABLE_PROMPT_CACHING_1H` is set (2.1.132)** — **Impact on WogiFlow (HIGH)**: this is the caveat referenced from the 2.1.108 section. **Concrete version**: Bedrock/Vertex users who set `ENABLE_PROMPT_CACHING_1H=1` MUST be on Claude Code **2.1.132+** — older versions return 400 on every request. Direct-API and subscriber users are unaffected.
530
+ - **Fixed sessions on 1M-context models falsely blocked with "Prompt is too long" before the real API limit (2.1.128)** and **`/context` dumping its rendered ASCII grid into the conversation (~1.6k wasted tokens) (2.1.129)** — **Impact on WogiFlow (HIGH)**: WogiFlow runs on Opus 4.7 with the 1M window and loads heavy context; pre-2.1.128 a long-but-legal prompt could be rejected outright. `scripts/flow-context-estimator.js` works in CC-supplied percentages (audited 2026-04-22, see the 2.1.117 entry), so it consumes the corrected numbers correctly. No code change.
531
+ - **`/config` now persists to `~/.claude/settings.json` and participates in override precedence (2.1.119)** — settings the user changes via `/config` now interact with WogiFlow-generated `.claude/settings.json` / `.claude/settings.local.json` through the normal precedence chain. No conflict; just be aware `/config` writes are now durable.
532
+ - **`CLAUDE_CODE_SESSION_ID` env var in the Bash-tool subprocess environment (2.1.132)**; **`CLAUDE_CODE_DISABLE_ALTERNATE_SCREEN=1` (2.1.132)** — informational; not consumed by WogiFlow.
533
+ - **Statusline stdin JSON now includes `effort.level` and `thinking.enabled` (2.1.119)** — relevant to `/wogi-statusline-setup`: the WogiFlow statusline could surface the active effort level. Tracked as a future enhancement; the current statusline doesn't use it.
534
+
535
+ #### MCP
536
+ - **MCP stdio servers now receive `CLAUDE_PROJECT_DIR` in their environment, matching hooks (2.1.139)** — WogiFlow ships no in-repo MCP server; `scripts/flow-mcp-*` only *discover* capabilities Claude Code already exposes (`ToolSearch`, `ListMcpResourcesTool`). User-installed MCP servers (figma, atlassian, gmail, …) benefit automatically.
537
+ - **`/mcp` Reconnect picks up `.mcp.json` edits without restart and shows HTTP status/URL on failure (2.1.139)**; **remote-MCP transient-failure reconnect retry enabled for all users (2.1.139)**; **fixed MCP servers in `.mcp.json`/plugins/connectors silently disappearing after `/clear` (2.1.136)**; **fixed deferred tools unavailable to skills with `context: fork` and subagents on first turn (2.1.126)**; **fixed `ToolSearch` missing MCP tools that connect after session start in nonblocking mode (2.1.122)** — **Impact on WogiFlow**: WogiFlow uses deferred MCP tools (Atlassian/Figma/Gmail/Google Calendar surfaces) and `ToolSearch`; these fixes make deferred-tool availability reliable across `/clear`, forked-context skills, and late-connecting servers. Automatic.
538
+ - **Fixed unbounded memory growth when a stdio/HTTP-SSE MCP server writes non-protocol data (2.1.132; 2.1.139 caps SSE bodies at 16 MB/frame)** — automatic; benefits users with chatty MCP servers.
539
+
540
+ #### Misc / no WogiFlow surface (automatic after upgrade)
541
+ - `/goal` command (2.1.139): a per-session completion condition Claude works toward across turns. Conceptually overlaps WogiFlow's Autonomous Walk-Away Mode (`go until you finish`) and the `/loop` skill — no conflict; they operate at different layers (`/goal` is a Claude Code session feature; WogiFlow's autonomous mode is task-queue-driven). Not integrated.
542
+ - Agent view / `claude agents` (2.1.139), `/scroll-speed` (2.1.139), `claude plugin details <name>` with projected per-session token cost (2.1.139), transcript-view navigation (2.1.139), `/context all` tokenizer-accurate per-skill estimates (2.1.139): editor/TUI conveniences, no WogiFlow surface.
543
+ - Plugin/project tooling: `claude plugin install <name>@<marketplace>` auto-refresh + retry (2.1.139), `claude plugin prune` (2.1.121), `claude plugin tag` (2.1.118), `claude plugin validate` accepting top-level `$schema`/`version`/`description` (2.1.120), `claude project purge [path]` (2.1.126), `--plugin-url <url>` / `--plugin-dir` accepting `.zip` (2.1.128–2.1.129). `/wogi-register` and plugin-registry routing are unaffected; users authoring WogiFlow-adjacent plugins get nicer tooling.
544
+ - API requests from sub-agents now carry `x-claude-code-agent-id` / `x-claude-code-parent-agent-id` headers and `claude_code.llm_request` OTel spans include `agent_id` / `parent_agent_id` (2.1.139): WogiFlow's Explore/Architect/Adversary sub-agents now show parent-agent attribution in telemetry. No code change.
545
+ - Remote Control, `/schedule`, claude.ai MCP connectors, and notification preferences are disabled when `ANTHROPIC_API_KEY` / `apiKeyHelper` / `ANTHROPIC_AUTH_TOKEN` is set (2.1.139): API-key users lose those claude.ai-tied features (unset the key to use them). Orthogonal to WogiFlow.
546
+ - Compaction prompt now asks the model to preserve sensitive user instructions (2.1.139): complements WogiFlow's "Compact Instructions" block in CLAUDE.md — SYSTEM-side compaction is now likelier to retain critical project rules. No change.
547
+ - Auth/credential reliability: fixed login-loop / concurrent-credential-write / OAuth-refresh-race bugs across 2.1.118, 2.1.126, 2.1.129, 2.1.133, 2.1.136; fixed the `claude auth login/logout/status` deadlock with expired credentials + `forceRemoteSettingsRefresh` (2.1.139). Plus the usual TUI/scroll/Windows-terminal/render fixes (~30 in 2.1.139 alone). All automatic.
548
+ - `Skill(name *)` permission-rule wildcard now works as a prefix match like `Bash(ls *)` (2.1.139): WogiFlow's generated settings allow-list `Skill(wogi-*)` (e.g. `.claude/settings.local.json`). This fix makes that wildcard reliably match all `/wogi-*` skills as a prefix. No code change; confirms the existing form is correct.
549
+ - Permission-matching correctness fixes: `Bash(mkdir *)`/`Bash(touch *)` now honored for in-project paths (2.1.129); `Edit(...)` allow rules scoped to drive root or POSIX `/` no longer always prompt (2.1.133); plan mode now blocks file writes even when a matching `Edit(...)` allow rule exists (2.1.136); `--dangerously-skip-permissions` broadened (2.1.126). See also `.claude/rules/security/security-patterns.md` §6 on scoping destructive commands — WogiFlow's `generateSettings()` already scopes destructive git variants narrowly; no change.
550
+
500
551
  ### Simple Mode Naming Distinction
501
552
 
502
553
  Claude Code's `CLAUDE_CODE_SIMPLE` environment variable (which enables a simplified tool set) is **unrelated** to WogiFlow's `loops.simpleMode` (a lightweight task completion loop using string detection). They are separate features that happen to share the word "simple":
@@ -0,0 +1,213 @@
1
+ # Scheduled / Background Mode (Phase 1A)
2
+
3
+ Continuous, **read-only**, background-mode quality signal for WogiFlow projects.
4
+ Phase 1A of `epic-quality-loop` (task `wf-b211a076`).
5
+
6
+ WogiFlow's review/audit/regression skills produce high-quality signal *only*
7
+ when a developer is actively in a Claude Code session. Scheduled mode closes
8
+ that loop by running designated `/wogi-*` commands on a cadence and reporting
9
+ findings as GitHub Issues / PR-comments — **never auto-merges, never edits
10
+ rule files, never pushes commits**.
11
+
12
+ ## The four jobs
13
+
14
+ | Job | Schedule (UTC) | What it does | Posts to |
15
+ |-----|---------------|--------------|----------|
16
+ | `nightly-regression` | `0 3 * * *` (daily 03:00) | Wraps `scripts/flow-step-regression.js`. Skipped on empty 24h diff. | `wogi/scheduled-nightly-regression` labelled issue (silent on green) |
17
+ | `weekly-audit` | `0 9 * * 1` (Mon 09:00) | Headless `claude -p` running `/wogi-audit`. | `wogi/scheduled-weekly-audit` labelled issue |
18
+ | `weekly-digest` | `0 17 * * 5` (Fri 17:00) | Headless `claude -p` running `/wogi-debt` + `/wogi-gate-stats --since=7d`. | `wogi/scheduled-weekly-digest` labelled issue |
19
+ | `per-pr-review` | on every PR event | `claude ultrareview <PR>` headless variant. | PR comment via `gh pr comment` |
20
+
21
+ ## Setup
22
+
23
+ ### Option A — GitHub Actions (recommended)
24
+
25
+ The workflow lives at `.github/workflows/wogi-scheduled.yml`. To enable:
26
+
27
+ 1. Set `scheduledMode.enabled: true` in `.workflow/config.json`.
28
+ 2. Ensure your repo has these secrets:
29
+ - `ANTHROPIC_API_KEY` — for headless `claude -p` invocations
30
+ - `GITHUB_TOKEN` — auto-provided by Actions (no setup needed)
31
+ 3. The workflow runs automatically on its cron schedule and on every PR.
32
+
33
+ ### Option B — Local scheduler
34
+
35
+ For users who don't want GH Actions, `flow schedule install` writes
36
+ platform-native unit files:
37
+
38
+ ```bash
39
+ # macOS — LaunchAgent plists in ~/Library/LaunchAgents/
40
+ flow schedule install --target=launchd
41
+
42
+ # Linux — systemd --user units in ~/.config/systemd/user/
43
+ flow schedule install --target=systemd
44
+ # then activate:
45
+ systemctl --user enable --now wogi-scheduled-nightly-regression.timer
46
+ systemctl --user enable --now wogi-scheduled-weekly-audit.timer
47
+ systemctl --user enable --now wogi-scheduled-weekly-digest.timer
48
+
49
+ # Any Unix — crontab fragment
50
+ flow schedule install --target=cron
51
+ # then activate:
52
+ (crontab -l 2>/dev/null; cat ~/.config/wogi-flow/crontab-fragment) | crontab -
53
+
54
+ # Inspect what's installed
55
+ flow schedule status
56
+
57
+ # Remove
58
+ flow schedule remove --target=launchd|cron|systemd
59
+ ```
60
+
61
+ Use `--dry-run` on `install` to preview the unit files without writing them.
62
+
63
+ ## Cost projection (dry-run mode)
64
+
65
+ Before enabling, run a dry-run to see projected monthly USD spend:
66
+
67
+ ```bash
68
+ node scripts/flow-scheduled-runner.js weekly-audit --dry-run
69
+ ```
70
+
71
+ Output:
72
+
73
+ ```
74
+ scheduled-runner: DRY-RUN (job=weekly-audit, model=sonnet)
75
+ Projected monthly cost across all configured jobs: $XX.XX
76
+
77
+ Per-job:
78
+ nightly-regression haiku 30× 1,200,000 tok → $1.50
79
+ weekly-audit sonnet 4× 600,000 tok → $3.60
80
+ weekly-digest sonnet 4× 120,000 tok → $0.72
81
+ per-pr-review opus 20× 1,600,000 tok → $48.00
82
+ ```
83
+
84
+ (Numbers are conservative estimates for budgeting. Actual billing varies.)
85
+
86
+ ## Configuration
87
+
88
+ In `.workflow/config.json`:
89
+
90
+ ```json
91
+ {
92
+ "scheduledMode": {
93
+ "enabled": false,
94
+ "dailyTokenBudget": 5000000,
95
+ "perJobModel": {
96
+ "nightly-regression": "haiku",
97
+ "weekly-audit": "sonnet",
98
+ "weekly-digest": "sonnet",
99
+ "per-pr-review": "opus"
100
+ },
101
+ "dryRun": false,
102
+ "jobs": ["nightly-regression", "weekly-audit", "weekly-digest", "per-pr-review"]
103
+ }
104
+ }
105
+ ```
106
+
107
+ | Key | Meaning |
108
+ |-----|---------|
109
+ | `enabled` | Master switch. Default `false`. |
110
+ | `dailyTokenBudget` | Cap across all jobs for a single calendar day. When projected total would exceed, remaining same-day jobs no-op with a logged warning. |
111
+ | `perJobModel` | Model used per job. Allowlist: `haiku`, `sonnet`, `opus`. |
112
+ | `dryRun` | Force every invocation into dry-run mode. |
113
+ | `jobs` | Subset of jobs to include in cost projections. |
114
+
115
+ ## Read-only-by-default invariants
116
+
117
+ These are non-negotiable. Enforced both by the runner code and by static-grep
118
+ tests in `tests/flow-scheduled-runner.test.js`:
119
+
120
+ 1. **No `git push` to non-bot refs.** The runner never calls
121
+ `git push origin master`/`main`.
122
+ 2. **No `gh pr merge`.** The PR-review job posts comments only.
123
+ 3. **No edits to `.workflow/state/decisions.md`.** Rule files are sacrosanct.
124
+ 4. **Default-branch only.** The runner detects `origin/HEAD` and records the
125
+ current branch in the audit trail. The temp worktree (invariant #5) is
126
+ created on the default branch regardless, so accidental developer-branch
127
+ leakage cannot reach scheduled execution.
128
+ 5. **Temp worktree (real, hard-enforced).** All work happens in an isolated
129
+ worktree created via `scripts/flow-worktree.js → runInWorktree()`. If
130
+ worktree creation fails, the runner opens a `wogi/scheduled-failure` issue
131
+ and exits non-zero — it does NOT silently fall back to the user's working
132
+ dir. (Fixed in R-379 / F2; prior versions had the claim in the JSDoc only.)
133
+
134
+ ## Safeguards in detail
135
+
136
+ | Safeguard | Where |
137
+ |-----------|-------|
138
+ | 10-minute hard timeout per job | `lib/scheduled-mode.js → withTimeout()` + `AbortController` |
139
+ | Retry-1×-then-alert with 30s backoff | `scripts/flow-scheduled-runner.js → runJobWithRetry()` |
140
+ | Token-budget cap | `lib/scheduled-mode.js → enforceTokenBudget()` |
141
+ | Dedup labelled issue (no spam) | `lib/scheduled-mode.js → updateDedupIssue()` |
142
+ | Silence on green | `runNightlyRegression()` exits without posting if all pass |
143
+ | Skip on empty 24h diff | `hasDiffSinceYesterday()` uses `git log --since=24 hours ago` |
144
+ | Stale-marker clearing | `clearStaleMarkers()` removes `routing-pending.json` + `pending-question.json` before each invocation |
145
+ | Failure alerts | `openFailureIssue()` creates a `wogi/scheduled-failure` issue with captured stderr |
146
+
147
+ ## Kill-switch
148
+
149
+ ```json
150
+ { "scheduledMode": { "enabled": false } }
151
+ ```
152
+
153
+ Or, for the GH Actions path: disable the workflow in **Actions → Workflows →
154
+ "Wogi Scheduled Quality Loop" → Disable workflow**.
155
+
156
+ Local schedulers: `flow schedule remove --target=<target>`.
157
+
158
+ ## Troubleshooting
159
+
160
+ **Q: The nightly-regression job posts every night even though tests pass.**
161
+ A: Check the dedup label `wogi/scheduled-nightly-regression`. Silence-on-green
162
+ only suppresses posts when `result.passed === true`. Check the issue body
163
+ to see what failed.
164
+
165
+ **Q: My GH workflow is hitting the 10-min timeout.**
166
+ A: Per-job timeout is set in `lib/scheduled-mode.js` as
167
+ `DEFAULT_JOB_TIMEOUT_MS`. Either raise it (caveat: cost), or split the
168
+ job (e.g. run audit on a subset of files via `--scope=`).
169
+
170
+ **Q: How do I see what's currently scheduled locally?**
171
+ A: `flow schedule status` returns a JSON blob with all installed units across
172
+ launchd / cron / systemd.
173
+
174
+ **Q: How does `--dry-run` differ from `enabled: false`?**
175
+ A: `enabled: false` makes the runner exit 0 immediately without any output.
176
+ `--dry-run` runs the projection logic and prints `$/month` — useful for
177
+ previewing before flipping `enabled` to `true`.
178
+
179
+ **Q: What about non-GitHub repos (GitLab, Bitbucket)?**
180
+ A: Phase 1A is GitHub-specific (uses `gh` CLI for dedup issues). Multi-host
181
+ support is out-of-scope; can be added in a future phase if needed.
182
+
183
+ ## Architecture
184
+
185
+ ```
186
+ .github/workflows/wogi-scheduled.yml ← cron triggers + permissions matrix
187
+
188
+
189
+ scripts/flow-scheduled-runner.js ← entry point (timeout, retry, budget)
190
+
191
+
192
+ lib/scheduled-mode.js ← pure helpers (CLI-agnostic)
193
+
194
+
195
+ scripts/flow-step-regression.js ← existing nightly-regression target
196
+ │ (UNMODIFIED — runner wraps it)
197
+
198
+ claude -p --model=<X> /wogi-audit ← for weekly-audit / weekly-digest / PR-review
199
+ ```
200
+
201
+ The runner follows the hook three-layer pattern: business logic in
202
+ `lib/scheduled-mode.js` (CLI-agnostic, exhaustively unit-tested), thin entry
203
+ point in `scripts/flow-scheduled-runner.js`, no transformation needed for
204
+ its single consumer (CLI / GH workflow).
205
+
206
+ ## Out of scope (Phase 1A)
207
+
208
+ - **Auto-fix / auto-merge** — by design. Phase 1A is read-only.
209
+ - **Multi-repo aggregation** — single repo per workflow file.
210
+ - **Cross-runner state** — each job is independent. The usage log is the only
211
+ shared state and is keyed by day, not by run.
212
+ - **Custom job definitions** — the four jobs are fixed. Adding a fifth
213
+ requires code + a new entry in `JOB_NAMES`.
@@ -0,0 +1,190 @@
1
+ # Skill Portability — Export to agentskills.io / Claude Code plugin
2
+
3
+ Phase 1B of the Continuous Code-Quality Initiative (epic `epic-quality-loop`,
4
+ task `wf-0342fc33`) adds a portable export path for WogiFlow skills. This
5
+ document explains what "portable" means in this context, how the portability
6
+ checker works, how to publish to either supported format, and why **import is
7
+ deliberately deferred**.
8
+
9
+ ## What is a "portable" skill?
10
+
11
+ A WogiFlow skill is *portable* when its content runs unchanged in a Claude
12
+ Code (or agentskills.io–compatible) environment that does NOT have WogiFlow
13
+ installed. In practice that means:
14
+
15
+ - No references to `.workflow/` paths (state files, specs, dossiers, epics).
16
+ - No references to WogiFlow state files by name: `ready.json`,
17
+ `feedback-patterns.md`, `decisions.md`, `app-map.md`, `function-map.md`,
18
+ `api-map.md`.
19
+ - No mentions of WogiFlow-specific tooling: `flow-utils`, `./scripts/flow`,
20
+ WogiFlow-specific `flow <subcommand>` invocations.
21
+ - No `/wogi-*` slash-command invocations.
22
+ - No `wogiflow-cloud` references (paid tier is out of scope for the OSS
23
+ catalog).
24
+
25
+ Skills that legitimately depend on any of the above are **not** portable.
26
+ That's fine — they remain available in WogiFlow's own catalog (the
27
+ `Wogi-Git/wogi-flow-skills` registry), which is unaffected by this work.
28
+
29
+ ## The `portable` manifest field
30
+
31
+ Every skill manifest gains an optional `portable: true|false` field. Default
32
+ is `false` — exports refuse skills that haven't opted in.
33
+
34
+ ```yaml
35
+ ---
36
+ name: my-skill
37
+ version: 1.0.0
38
+ description: ...
39
+ license: MIT
40
+ portable: true # <-- new in Phase 1B
41
+ ---
42
+ ```
43
+
44
+ Setting `portable: true` only declares the intent. The portability checker
45
+ still runs and overrides the declaration if it finds WogiFlow-specific
46
+ references — fail-loud is the rule.
47
+
48
+ Setting `portable: false` explicitly short-circuits the checker and blocks
49
+ export. Use this when your skill has an implicit dependency on a project
50
+ convention the scanner can't detect.
51
+
52
+ ## How the portability checker works
53
+
54
+ `lib/skill-portability.js` walks the skill directory and scans every
55
+ text-y file (`.md`, `.txt`, `.json`, `.yaml`, `.js`, `.ts`, `.sh`, etc.)
56
+ line by line. Each line is matched against a fixed set of blocker patterns;
57
+ matches become citations of the form `file:line — "<offending substring>"`.
58
+
59
+ Run the checker via the export CLI — it always runs first:
60
+
61
+ ```bash
62
+ flow skill export my-skill
63
+ # → succeeds, or prints the citation list and exits 1.
64
+ ```
65
+
66
+ ## Two-catalog principle
67
+
68
+ WogiFlow maintains two parallel skill catalogs:
69
+
70
+ | Catalog | Holds | Distribution |
71
+ |---------|-------|--------------|
72
+ | **WogiFlow registry** (`Wogi-Git/wogi-flow-skills`) | All skills, portable or not | `flow skill add <name>` |
73
+ | **agentskills.io / Claude Code plugins** | *Portable subset only* | `flow skill export <name>` |
74
+
75
+ The WogiFlow registry stays canonical for non-portable skills that depend on
76
+ WogiFlow-specific paths or commands. Phase 1B adds export *alongside* the
77
+ existing registry — it never replaces it.
78
+
79
+ ## Publishing to agentskills.io
80
+
81
+ ```bash
82
+ flow skill export my-skill --format=agentskills@v1
83
+ ```
84
+
85
+ Output (default `dist/skills/my-skill/`):
86
+
87
+ ```
88
+ dist/skills/my-skill/
89
+ ├── manifest.json # agentskills@v1 manifest (schemaVersion pinned)
90
+ ├── skill.md # the skill itself
91
+ ├── knowledge/... # bundled aux files
92
+ └── templates/...
93
+ ```
94
+
95
+ Manifest shape (pinned to `schemaVersion: "agentskills@v1"`):
96
+
97
+ ```json
98
+ {
99
+ "schemaVersion": "agentskills@v1",
100
+ "name": "my-skill",
101
+ "version": "1.0.0",
102
+ "description": "...",
103
+ "license": "MIT",
104
+ "compatibility": "Claude Code 2.1+",
105
+ "instructions": "<post-frontmatter body of skill.md>",
106
+ "source": { "type": "wogiflow" },
107
+ "files": ["skill.md", "knowledge/learnings.md"],
108
+ "dependencies": []
109
+ }
110
+ ```
111
+
112
+ Note: this module operates offline. We do not fetch the agentskills.io v1
113
+ schema at export time. Our serializer pins `schemaVersion` to a known
114
+ identifier so a future CI contract test (Phase 1B acceptance criterion) can
115
+ catch drift once the network gate is built. Until then, this is our
116
+ authoritative interpretation of the v1 shape; see `lib/skill-export-agentskills.js`
117
+ header comment.
118
+
119
+ ## Publishing as a Claude Code plugin
120
+
121
+ ```bash
122
+ flow skill export my-skill --format=claude-plugin
123
+ ```
124
+
125
+ Output (default `dist/skills/my-skill/`):
126
+
127
+ ```
128
+ dist/skills/my-skill/
129
+ ├── .claude-plugin/
130
+ │ └── plugin.json # Claude Code plugin manifest
131
+ └── skills/
132
+ └── my-skill/
133
+ ├── SKILL.md # normalized from skill.md
134
+ └── knowledge/...
135
+ ```
136
+
137
+ This layout matches the convention used by shipping Claude Code plugins
138
+ (e.g., the official Figma plugin). It is ready for the
139
+ `claude plugin tag` distribution path (Claude Code 2.1.118+).
140
+
141
+ ## Why import is deferred
142
+
143
+ The Phase 1B spec explicitly defers `flow skill import <archive>` to a
144
+ follow-up. Reason: importing third-party skills means executing third-party
145
+ content under our existing tool-grant model. Even Markdown-only skills can
146
+ declare `allowed-tools` and ship templates that an agent will treat as
147
+ authoritative. Shipping import without a security model would mean either:
148
+
149
+ - Granting third-party skills our default tool surface (Read/Write/Edit/
150
+ Glob/Grep/Bash) on first install — unsafe by default, breaks our
151
+ no-surprise principle.
152
+ - Or stripping `allowed-tools` and re-prompting the user on every tool use
153
+ — degraded UX that defeats the point of skills.
154
+
155
+ The right design is **quarantine + content scanner + opt-in enable**:
156
+
157
+ 1. Imported skills land in `.claude/skills-quarantine/` (off the loader path).
158
+ 2. A content scanner flags `allowed-tools`, scripts, bash invocations,
159
+ and any reference to known sensitive paths for review.
160
+ 3. The user explicitly promotes a skill out of quarantine after review.
161
+
162
+ That work needs a dedicated security-model spec and is the obvious next
163
+ phase after the catalog is seeded with safe exports.
164
+
165
+ The import insertion point in `scripts/flow-skill-export.js` is marked
166
+ with the comment `[import would go here]` so a future task can locate it
167
+ without grep.
168
+
169
+ ## Which in-repo skills are portable?
170
+
171
+ At Phase 1B ship:
172
+
173
+ | Skill | Portable | Why |
174
+ |-------|----------|-----|
175
+ | `_template` | yes | No WogiFlow refs; a clean template by design. |
176
+ | `conventional-commit` | yes | Reusable across any git repo. |
177
+ | `figma-analyzer` | no | References `.workflow/state/`, `./scripts/flow figma`, `/wogi-flow`, and a WogiFlow MCP server (28 blockers). To make it portable, decouple from the WogiFlow component registry. |
178
+
179
+ The portability tag also shows up in `flow skill list` output as
180
+ `[portable]` for any installed skill whose local manifest carries
181
+ `portable: true`.
182
+
183
+ ## Roadmap
184
+
185
+ - Phase 1B (this work) — export only. Two catalog separation. Portability
186
+ checker is the single source of truth for "exportable".
187
+ - Follow-up (post-security-model) — `flow skill import` with quarantine.
188
+ - Phase 3 candidate — auto-flag drift when a portable skill picks up a
189
+ WogiFlow-specific reference in a later edit (the same scanner, run via
190
+ the registry-update gate).
@@ -0,0 +1,6 @@
1
+ # Alternative: Migrate generated hook registrations to the `args: string[]` exec form
2
+
3
+ **Rejected**: 2026-05-12
4
+ **Reason**: Claude Code 2.1.139 added an `args: string[]` field for hook entries that spawns the command directly without a shell, so path placeholders never need quoting. WogiFlow's generated hook registrations (`generateConfig()` in `scripts/hooks/adapters/claude-code.js`) already emit `command: \`node "${absolutePath}"\`` — the absolute script path is double-quoted, which already handles spaces in the project path. Switching to `args` would buy only marginal robustness (paths containing a literal `"` or shell metacharacters — vanishingly rare for real project directories) while introducing a real regression: `args` is silently ignored on Claude Code < 2.1.139, and since it *replaces* `command` rather than augmenting it, a hook entry that emits only `args` would do nothing on older Claude Code — breaking task gating, validation, routing enforcement, etc. for any user not yet on 2.1.139. WogiFlow does not currently require a minimum Claude Code version that high (`postinstall.js` version-gates individual hook *events*, but the base hook set must work on much older CC). The shell-chain commands that actually have gnarly quoting (the `&&`/`2>/dev/null`/`$(...)` one-liners) live in the **permissions allow-list**, not in hook registrations, and cannot use exec form at all (no shell = no `&&`).
5
+ **Chose instead**: Keep `command: \`node "${path}"\``. If WogiFlow's minimum supported Claude Code version ever reaches 2.1.139, revisit — at that point `buildHookEntry()` could emit `args: ["node", scriptPath]` for the `command` transport and drop the manual quoting. Until then, the double-quoted `command` form is correct and maximally compatible.
6
+ **Source**: wf-cb951e91 — "Respond to Claude Code v2.1.139 changelog" (AC2).
@@ -41,7 +41,8 @@
41
41
  {
42
42
  "type": "command",
43
43
  "command": "node scripts/hooks/entry/claude-code/post-tool-use.js",
44
- "timeout": 60
44
+ "timeout": 60,
45
+ "continueOnBlock": true
45
46
  }
46
47
  ]
47
48
  }
@@ -9,6 +9,7 @@ agent: developer
9
9
  memory: project
10
10
  license: MIT
11
11
  compatibility: Claude Code 2.1+
12
+ portable: true
12
13
  allowed-tools:
13
14
  - Read
14
15
  - Glob
@@ -0,0 +1,65 @@
1
+ # Conventional Commit Examples
2
+
3
+ Each example shows a diff summary on the left and the commit message that
4
+ fits it on the right. Use these as anchors when classifying ambiguous
5
+ changes.
6
+
7
+ ## feat
8
+
9
+ ```
10
+ + src/auth/oauth-callback.ts
11
+ + src/auth/oauth-callback.test.ts
12
+ ```
13
+
14
+ ```
15
+ feat(auth): add Google OAuth callback handler
16
+
17
+ Wires the OIDC callback to the existing session store. Falls back to
18
+ local password auth when the provider is unconfigured.
19
+ ```
20
+
21
+ ## fix
22
+
23
+ ```
24
+ ~ src/parser/json.ts (1 hunk)
25
+ + src/parser/json.test.ts (1 hunk)
26
+ ```
27
+
28
+ ```
29
+ fix(parser): handle UTF-8 BOM in JSON input
30
+
31
+ The parser silently truncated the first key when the file began with a
32
+ BOM. Strip the BOM before handing the buffer to JSON.parse.
33
+
34
+ Closes #142
35
+ ```
36
+
37
+ ## refactor
38
+
39
+ ```
40
+ ~ src/utils/path-helpers.ts
41
+ ~ src/cli/index.ts
42
+ ```
43
+
44
+ ```
45
+ refactor(utils): extract path-normalization into a shared helper
46
+
47
+ No functional change. Removes duplication between cli/index.ts and
48
+ worker/runner.ts.
49
+ ```
50
+
51
+ ## BREAKING CHANGE
52
+
53
+ ```
54
+ ~ src/api/client.ts
55
+ ~ README.md
56
+ ```
57
+
58
+ ```
59
+ feat(api)!: rename `client.send()` to `client.dispatch()`
60
+
61
+ The old name was ambiguous with WebSocket `send`. Update all callers.
62
+
63
+ BREAKING CHANGE: client.send() has been removed. Use client.dispatch()
64
+ instead. Codemod available at scripts/migrate-v2.js.
65
+ ```
@@ -0,0 +1,76 @@
1
+ ---
2
+ name: conventional-commit
3
+ version: 1.0.0
4
+ description: Format git commit messages following the Conventional Commits 1.0 specification
5
+ scope: project
6
+ user-invocable: true
7
+ context: inline
8
+ agent: developer
9
+ memory: project
10
+ license: MIT
11
+ compatibility: Claude Code 2.1+
12
+ portable: true
13
+ allowed-tools:
14
+ - Read
15
+ - Bash(git *)
16
+ lastUpdated: 2026-05-13
17
+ ---
18
+
19
+ # Conventional Commit Skill
20
+
21
+ A reusable, project-agnostic skill that helps an agent compose
22
+ [Conventional Commits 1.0](https://www.conventionalcommits.org/en/v1.0.0/)
23
+ messages from the staged diff.
24
+
25
+ ## When to Use
26
+
27
+ - The user asks to "commit" recent changes.
28
+ - An automated workflow wraps up and needs to record a commit.
29
+ - A patch series should be split into typed, scoped commits.
30
+
31
+ ## Format
32
+
33
+ ```
34
+ <type>(<scope>): <description>
35
+
36
+ [body]
37
+
38
+ [footer(s)]
39
+ ```
40
+
41
+ | Type | When to use |
42
+ |------------|-------------|
43
+ | `feat` | New feature or capability |
44
+ | `fix` | Bug fix |
45
+ | `docs` | Documentation only |
46
+ | `style` | Formatting, whitespace (no logic change) |
47
+ | `refactor` | Code change that neither fixes a bug nor adds a feature |
48
+ | `perf` | Performance improvement |
49
+ | `test` | Adding or updating tests |
50
+ | `chore` | Build process, tooling, dependencies |
51
+
52
+ The optional `BREAKING CHANGE:` footer escalates the commit to a major bump
53
+ for tools that consume Conventional Commits (semantic-release, changelog
54
+ generators, etc.).
55
+
56
+ ## Workflow
57
+
58
+ 1. Read the staged diff with `git diff --staged`.
59
+ 2. Classify the change against the type table above. If multiple types
60
+ apply, split into multiple commits rather than mixing.
61
+ 3. Choose a scope — usually a module name, directory, or feature area.
62
+ 4. Draft a one-line description in the imperative mood (50 chars max).
63
+ 5. If the change is non-obvious, add a body explaining the *why*.
64
+ 6. Run the commit. Don't push.
65
+
66
+ ## Output
67
+
68
+ The skill produces a commit message that an agent can pass to
69
+ `git commit -F -`. It does not run `git push`, does not edit code, and
70
+ does not touch the working tree.
71
+
72
+ ## Why this skill is portable
73
+
74
+ This skill references no project-specific paths, state files, or slash
75
+ commands. It works in any git repository regardless of which AI workflow
76
+ framework is in use. That makes it a clean Phase 1B export target.
package/bin/flow CHANGED
@@ -229,6 +229,22 @@ function main() {
229
229
  return;
230
230
  }
231
231
 
232
+ if (command === 'schedule') {
233
+ // Scheduled-mode unit installer (Phase 1A — wf-b211a076).
234
+ // Lightweight wrapper; the actual logic lives in scripts/flow-schedule.js
235
+ // so it can be unit-tested without spawning the CLI.
236
+ try {
237
+ const schedule = require('../scripts/flow-schedule');
238
+ const result = schedule.dispatch(args.slice(1));
239
+ if (result.output) console.log(result.output);
240
+ process.exit(result.ok ? 0 : 1);
241
+ } catch (err) {
242
+ console.error(`Schedule error: ${err.message}`);
243
+ process.exit(1);
244
+ }
245
+ return;
246
+ }
247
+
232
248
  // For all other commands, try to find project context
233
249
  const projectRoot = findProjectRoot();
234
250