Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,15 @@ All notable changes to weft are documented here. Format follows [Keep a Changelo
## [Unreleased]

### Added
- **`weft doctor` (`/wf-doctor`) — template currency.** Reports whether a working copy (project-local or user-global) has drifted from the plugin-bundled canonical it was derived from — the one staleness git can't see, since the copies live in different trees. Compares by content hash (key-order/whitespace independent), so only real semantic drift is flagged. Also reports whether the plugin's own git clone is behind upstream (no network; HEAD vs the already-fetched `@{u}`). Read-only, no persisted state. `--json` for machine output.
- **`weft analyze` (`/wf-analyze`) — per-template run insight.** Reads the event log into a per-template rollup: step durations (median/p90 from paired `wf.step_changed` deltas), loop counts, guard-block counts, abandonment + stall counts, slowest step, plus a recurring-friction section joined from `workflow-qa.jsonl` (by `workflow_id`). Turns the event log from a record into a feedback loop.
- **`wf.guard_blocked` events.** The guard engine appends a `wf.guard_blocked` event (`workflow_id`, `step_id`, `step_name`, `pattern`, `command`, `tool`) when it blocks a tool call — previously blocks were silent, so "does this guard ever fire?" was unanswerable from the log. Matching logic unchanged.
- **`wf.stalled` annotation + real session-id capture.** SessionStart writes the live session id to a per-project `<weft_dir>/.session-id` (read by `cli.py` as a fallback), fixing events logged with `session_id="unknown"`; a running workflow idle longer than `WEFT_STALL_HOURS` (default 12) gets a pure-annotation `wf.stalled` event (state untouched).
- **Context surfacing in `context.md`.** `generate_context_md` renders the current step's `description`, a computed `Next action:` line (gated on `running`/`waiting`), and two optional per-step fields — `suggest` (commands that fit the step) and `insights` (💡 hard-won findings) — so the right command and the why-it-bites surface when a step goes active and survive compaction.
- **`wf.step_changed` paired start+end events.** `_advance_to_next` now emits a `wf.step_changed` event with `to_status="running"` when each step begins. Auto-skipped optional+requires_skill steps now also emit a `wf.step_changed` with `to_status="skipped"`. `step_loop_back` emits the target step's `wf.step_changed` (pending->running) alongside the existing `wf.loop_iteration` event. Dashboards reading events.jsonl can now compute true per-step duration (paired transition deltas) and per-iteration loop timing. Test updated: feature workflow expects 2 * step_count - 1 `wf.step_changed` events.
- **`wf.failed` terminal event.** When a step's `on_fail=block` policy lands the workflow in `failed` state, `step_fail` emits a `wf.failed` event with `workflow_id`, `blocked_at_step`, `reason`, `policy`. Previously, blocked workflows had no terminal marker so downstream aggregators couldn't compute duration or distinguish "running" from "blocked-and-abandoned".
- **`scripts/wf.py` — interactive TUI** over weft workflows. Curses-based: list view (running workflows + PR/CI status), detail view (per-workflow step + recent events), templates view (discovery). Falls back to the static `wf-monitor.py` table when stdout is not a TTY or invoked with `--list` / `--json` / `--templates`. Reads per-project `.claude/weft/state.json + workflow-context.json` and per-ticket subdirectories. Read-only.
- **`scripts/wf-monitor.py` — read-only viewer** producing a plain-text aligned table over workflows + GitHub PR status. Standalone for scripting (`wf-monitor.py --json | jq`) or as the data layer behind the TUI.
- `pyproject.toml` with `weft` console script entry point.
- `CONTRIBUTING.md` and GitHub issue templates.
- CI workflow running pytest on push and pull requests.
Expand All @@ -16,7 +25,11 @@ All notable changes to weft are documented here. Format follows [Keep a Changelo
- `docs/demo.md` — annotated end-to-end walkthrough captured from a real workflow run.
- `Makefile` with `install`, `test`, `lint`, `clean` targets for one-command contributor onboarding.

### Fixed
- **`insights` step field is now actually populated.** `generate_context_md` rendered per-step `insights` (💡 lines) and the field was documented, but `start_workflow`/`rebuild_from_events` never copied it from the template into step state — so it silently rendered nothing. Both build sites now carry `insights`, matching the existing `suggest`-style optional fields. (`suggest` has the same latent gap; wire it the same way if a template ever uses it.)

### Changed
- **Date-based `workflow_id` now carries second resolution** (`name-YYYYMMDD-HHMMSS`, was `name-YYYYMMDD`). Two same-day runs of one template in one project no longer share an id, so `/wf-analyze` counts them as distinct workflows instead of conflating their step timings. PR-scoped ids (`name-pr<N>`) are unchanged — they stay stable by design. `/wf-analyze` already groups by the `name` field in `wf.started`, not by parsing the id, so the format change is backward-compatible for analytics.
- README: corrected license, version, install instructions (was a fictional `claude plugin install` syntax — now uses real `/plugin marketplace add` flow), skill count (10→11, added `wf-compose`), and feature-workflow step count (12→11).
- `.claude-plugin/plugin.json` bumped to `0.3.0` to match shipped feature set.

Expand Down
30 changes: 27 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ The plugin auto-registers four hooks (`SessionStart`, `PreToolUse`, `PreCompact`
/wf-start generic # plan → implement → verify
/wf-status # show current state
/wf-step complete # advance to the next step
/wf-dashboard # open the live TUI
/wf-analyze # per-template timing + recurring friction across runs
```

Run `/wf-start` with no args for the guided template picker.
Expand Down Expand Up @@ -118,12 +118,12 @@ JSON

- **Event-sourced state machine** — append-only JSON log; rebuild state with `/wf-rebuild`
- **Template system** — `generic` (3 steps) and `feature-workflow` (11 steps) bundled; add your own under `templates/` (project), `~/.weft/templates/` (user-global), or `WEFT_USER_TEMPLATES_DIR`
- **Smart skills** — 11 slash commands (`wf-start`, `wf-step`, `wf-status`, `wf-abort`, `wf-preview`, `wf-rebuild`, `wf-dashboard`, `wf-new-template`, `wf-edit-template`, `wf-compose`, `ev-query`)
- **Smart skills** — 12 slash commands (`wf-start`, `wf-step`, `wf-status`, `wf-resume`, `wf-run-step`, `wf-abort`, `wf-preview`, `wf-rebuild`, `wf-analyze`, `wf-template`, `wf-compose`, `ev-query`)
- **Guard engine** — per-step `allowed-tools` and `blocked-commands` enforced via `PreToolUse` hook
- **Stop gate** — refuses session exit while steps are incomplete (configurable via `on_fail: block|retry|skip`)
- **Compaction-safe** — `PreCompact` hook writes a `context.md` projection so the next session resumes mid-workflow
- **Live dashboard** — auto-refreshing TUI for monitoring active workflows
- **Template management** — `/wf-new-template` and `/wf-edit-template` for creating and editing templates in-session
- **Template management** — `/wf-template` for creating and editing templates in-session

## Auditable by design

Expand All @@ -140,13 +140,37 @@ weft rebuild # reconstruct from events alone

Use `weft query --type wf.step_changed`, `--last 50`, or `--workflow <id>` to filter.

## Interactive TUI

For watching multiple workflows at once, `scripts/wf.py` is a curses-based TUI over the same state. Three views: list (every running workflow + PR/CI status), detail (per-workflow step + recent events), templates (discovery).

```bash
python3 $WEFT_ROOT/scripts/wf.py # interactive TUI
python3 $WEFT_ROOT/scripts/wf.py --list # plain-text table (auto when not TTY)
python3 $WEFT_ROOT/scripts/wf.py --json | jq # machine-readable
python3 $WEFT_ROOT/scripts/wf.py --templates # template catalog
```

Keys in the list view: `j`/`k` navigate, `enter` open detail, `t` templates, `r` refresh, `q` quit. Detail view: `esc`/`h` back, `r` refresh, `q` quit. Read-only — never mutates weft state.

The TUI scans the current directory by default; pass a path to scan elsewhere. It picks up both legacy single-workflow layouts (`<project>/.claude/weft/`) and per-ticket layouts (`<project>/.claude/weft/workflows/<id>/.claude/weft/`).

For scripting without curses, `scripts/wf-monitor.py` produces the same aligned-table output and supports `--json`, `--templates`, and an explicit project path argument.

Suggested shell alias:

```bash
alias wf='python3 ~/.claude/plugins/cache/local/weft/0.3.0/scripts/wf.py'
```

## Repository Layout

```
.claude-plugin/ plugin.json — Claude Code plugin manifest
core/ Python event store, state machine, projections, CLI, dashboard
hooks/ SessionStart / PreToolUse / PreCompact / Stop bash hooks + hooks.json
skills/ 11 SKILL.md files for the /wf-* and /ev-* slash commands
scripts/ wf.py (curses TUI) + wf-monitor.py (plain-text + JSON viewer)
templates/ generic.json, feature-workflow.json (workflow definitions)
tests/ pytest suite covering event store, state machine, hooks, CLI, behaviors
```
Expand Down
Loading
Loading