Skip to content

Releases: smykov/teamwright

teamwright 0.13.1

Choose a tag to compare

@smykov smykov released this 24 Oct 21:18
17429a7

Added

  • /teamwright:update — the plugin and the project's kit in one step. A plugin update alone changed nothing in the project: the hooks, roles, process docs and scripts there are the kit apply wrote, and the owner had to find the new copy and run the installer from it. tw-install.py update updates the marketplace and the plugin for the project's channel (teamwright@teamwright, or teamwright@teamwright-next when the project enables it) through claude plugin, finds the copy Claude Code installed for this project (installed_plugins.json: this project's install, else local, else the user's), and runs plan — or, with --apply, apply — from that copy, not from the one the session loaded; --no-fetch skips the plugin update. The command shows the plan, applies on the owner's yes, commits the kit files and says to restart Claude Code. Tests in tests/test-tw-update.sh.

Fixed

  • A worktree is no longer held by another task's IN_PROGRESS. The rule "one task IN_PROGRESS per working tree" counted every record on the branch, and a branch cut from main carries the other tasks' records as they were: one task IN_PROGRESS in the main tree made every tw/<ID> worktree whose task had finished its analysis wait for it (wip_waiting) and end idle - with /teamwright:parallel auto, every worktree at once. In a per-task worktree the rule, and the "uncommitted changes belong to one active task" check, now look at the worktree's own task only; the main tree is unchanged. Tests in tests/test-tw-worktrees.sh.

Security

  • /teamwright:parallel auto sessions may not push, merge or call gh: the default TEAMWRIGHT_CLAUDE_ARGS add --disallowedTools "Bash(git push:*) Bash(git merge:*) Bash(gh:*)"; merging stays with the main session.
  • /teamwright:parallel pre-approves git -C <path> rebase only, not any git -C or git rebase command.
  • SECURITY.md lists what runs without a prompt: the commands skills pre-approve, the project config that runs as code (config.yml, progress.json), headless parallel sessions, autonomous CI runs.
  • CI: actions pinned by commit SHA, the gitleaks download checked against its SHA-256, and a check that no name from the PRIVATE_NAMES_RE secret appears in the tree or recent commit messages. The autonomous-run example in docs/usage.md pins its actions too and warns that task records and issues are model input.

Changed

  • /teamwright:update and tw-parallel.py use one variable for the Claude Code binary, TW_CLAUDE.
  • Documentation brought up to date: the command and hook counts and lists (README, docs/README.md, CLAUDE.md, CONTRIBUTING.md), parallel auto in the commands table, the process settings in the glossary and docs/usage.md, requirements and /reload-plugins in the quickstart, stage-protocol.md in the reading order, the project status, the tw-parallel.py variables in docs/process/plugin.md; this changelog states its format.

Full changelog: CHANGELOG.md

teamwright 0.13.0

Choose a tag to compare

@smykov smykov released this 24 Oct 21:18
69871dc

Added

  • /teamwright:parallel auto: the orchestrator runs tasks in parallel itself. Until now parallel work meant the owner opened a session per worktree; the orchestrator could not even call /teamwright:parallel (it was owner-only), and red-tests or implement held one task IN_PROGRESS per tree while nine analysed tasks waited. Now parallel is open to the model, and auto analyses the next batch in the main tree, plans disjoint seams, starts the worktrees, prepares their index, launches their stages headless, watches, merges each approved task (rebase, gate in the worktree, fast-forward) and starts the next — owner decisions are collected, not asked. A stage session that leaves analysed tasks waiting with batch.parallel above 1 goes to parallel auto (stage-protocol.md §3).
  • tw-parallel.py prepare <ids> — the context tool's index per worktree: Serena's .serena/cache copied from the main tree, then serena project index refreshes what differs (TW_CONTEXT_INDEX_CMD overrides the command). A worktree that cannot index is reported and not launched.
  • tw-parallel.py launch <ids> / run <id> — in the worktree, ask the router; while headless.run, run claude -p <headless.prompt> (one stage per session, a fresh context) and ask again; stop at CODE_COMPLETE, an owner decision (escalate with the reason), TEAMWRIGHT_PAUSE, two stages that moved nothing (stuck) or TW_PARALLEL_MAX_STAGES (12). At most batch.parallel at once. State and log: .teamwright/parallel/<ID>.json, .log; status shows them. Command: TW_CLAUDE (default claude) with TEAMWRIGHT_CLAUDE_ARGS (default acceptEdits, the tools a stage needs, the autonomous-run note). Tests in tests/test-tw-parallel.sh.
  • .teamwright/parallel/, .serena/cache/ and .serena/logs/ are gitignored by the installer, so a worktree's copied index does not look like uncommitted work.

Full changelog: CHANGELOG.md

teamwright 0.12.2

Choose a tag to compare

@smykov smykov released this 24 Oct 21:18
ca8e8a8

Fixed

  • Stage sessions check the context tool before any role. The check that the configured context tool (Serena, a code graph, docs) is connected was step 0 of /teamwright:flow; when the lifecycle moved into the stage commands it was not carried over, so /teamwright:analyze, red-tests, implement, review, verify and /teamwright:router spawned roles without it, and the roles read code with grep. Now stage-protocol.md §0 (and every stage command and the router) checks that the provider from tools.context is in the session and answers one cheap call, re-indexes a stale index, and spawns no role until it does: interactive — the owner restarts the server or answers continue to use the built-in search; headless — the session ends with Outcome: escalate. /teamwright:flow does the same instead of falling back silently.
  • Every role is told which code search to use. Each role's spawn prompt starts with a code-search line taken from tools.context (Serena: find_symbol, find_referencing_symbols, get_symbols_overview, search_for_pattern; grep and reads only for non-code text or where the tool misses) — role files edited by hand keep their own tools section, and the prompt still carries it.
  • stages.<stage>.batch says what it is. /teamwright:settings now states that a stage's batch is taken one after another in one session, not at the same time (batch.parallel), and that red-tests and implement keep one task IN_PROGRESS per working tree.

Full changelog: CHANGELOG.md

teamwright 0.12.1

Choose a tag to compare

@smykov smykov released this 24 Oct 21:18
f46aefa

Fixed

  • /teamwright:settings offers every key. It offered only the keys whose default differs from the recommendation, in one question block of at most four questions with the five stage models first — so the stage batches, batch.parallel, test_guard and router.select were never offered, and most keys never fit. Now the skill shows the whole table, asks which groups to change, then asks up to four keys per call for each chosen group; the stage models are one question with ready sets.

Changed

  • Neutral examples in comments, tests and the changelog (T-12, task/T-12-run3). No behaviour changes.

Full changelog: CHANGELOG.md

teamwright 0.12.0

Choose a tag to compare

@smykov smykov released this 24 Oct 21:18
c6619fa

Added

  • Stages: the lifecycle runs one stage per session when you want it to. Until now /teamwright:flow drove a task through analysis, red tests, implementation, gate, review and verification in one session: an autonomous job that was cut lost the whole task, and the context grew with every role. The lifecycle is now five stages — analyze (ready TODO, ANALYSIS, VERIFY_FAIL → IN_PROGRESS), red-tests, implement (green tests, the test-writer's failure-branch bite and tw-mutants, tw-gate --for-task + tw-gate <area>, technical-writer, commit, IN_PROGRESS → NEEDS_REVIEW; a failed check is fixed in the same session), review, verify — and push (DRAIN) stays a separate owner decision. New commands: /teamwright:analyze, /teamwright:red-tests, /teamwright:implement, /teamwright:review, /teamwright:verify run a named stage and first ask the router, refusing with the right command when the task is at another stage (/teamwright:implement T-12 on a task without red tests → /teamwright:red-tests T-12); /teamwright:router asks the router and runs exactly one stage, then stops at the barrier. /teamwright:flow stays, as a loop of router steps in one session; its lifecycle text moved into the stage commands, and its resume heuristic into the router.
  • The stage: task field (red-tests | implement, the sub-stage of IN_PROGRESS), written by the stage that finished its work and committed with it. The router checks it against the evidence (## Tests filled = the red tests are written; analysis complete): a field behind the evidence wins (red-tests with the tests filled — a send-back to the tests), a field ahead of it loses (implement without tests → red-tests), with a warning; a task without the field (started by an older flow) is routed by the evidence. IN_PROGRESS may now cross a session boundary when its stage is recorded and the tree is clean (lifecycle.md, sessions.md, AGENTS.md). Task template: a stage: "" line.
  • Stage gate (analysis gate, check 4): entering IN_PROGRESS sets the stage in the same edit (red-tests from TODO, ANALYSIS, VERIFY_FAIL; a send-back may set implement), the field only moves red-tests → implement (back to red-tests from implement, or when review or verification return the task), is never removed from an IN_PROGRESS task, stage: implement needs ## Tests filled, and IN_PROGRESS → NEEDS_REVIEW needs stage: implement, the tests and — for a task that changes code (_task.code_changed: a commit naming the task, or a tracked uncommitted change, touches a code file) — the ### Failure branches table: only the implement stage hands a task to review. Shell rewrites of stage: in a record are refused like status:, recognised by the values too. Tests in tests/test-analysis-gate.sh.
  • Router: stages, per-stage batches and thresholds, candidates, models, headless output (scripts/tw-next.py). Every task-bound decision carries stage; the output adds batch (the router's default) and batch_cap, candidates for the chosen stage — every waiting task in router order with priority, effective priority, how many tasks it unblocks, depends_on, seam paths and the areas they fall in, size hints, the candidates it overlaps (tw-parallel.py's seam rule) and those it depends on — so a session picks its batch without reading task files; stages (per stage: waiting, due, why), work_available (the one predicate for "what runs" and "nothing to do"), model, command, select and headless (run, prompt, model, a note) for one stage per CI job. --stage S [--task IDS] answers a stage command (request: ok, batch, candidates, hint; an explicit stage ignores min). New settings, validated by the installer: process.stages.<stage>.batch (1–10, default 1), .min (1–10, default 1) and .max_wait_hours (0–168, default 0) — a stage that is not due (fewer than min waiting, no P0/P1 task, the oldest younger than max_wait_hours) moves behind the due work, and runs when nothing else is due; process.models.<stage> (opus, sonnet, haiku, fable or a claude-… id; unset = the role files' model:), passed as the agent tool's model on the stage's role spawns; process.router.select: script | agent (default script: the script selects and counts, the session picks the batch from the candidates; agent: the session reads the task records itself — more tokens, for records the script cannot read). Defaults behave as before stages. Tests in tests/test-tw-next.sh (stage field vs evidence, legacy tasks, resume rules, thresholds, batches, candidates, requests, models, headless) and tests/test-installer.sh.
  • The journal records the stage and the chosen batch: outcomes.jsonl gets stage (from a Stage: analyze|red-tests|implement|review|verify|flow line), batch and batch_reason (from Batch: T-3 T-7 - <why>). Tests in tests/test-journal.sh.
  • Tokens per stage. Stop and SubagentStop lines in outcomes.jsonl carry tokens: the model usage of the agent's transcript so far, per model (input, output, cache_read, cache_write) — the session's own lines from transcript_path (sidechains left out), a subagent's from agent_transcript_path; a message the transcript repeats per content block is counted once, and the transcript is read incrementally (offset under .teamwright/logs/.tokens/). teamwright-metrics adds per stage (journal.stages, a Per stage table in Markdown): sessions grouped by the stage they declared, duration, tool calls of every agent, outcomes, tasks taken, tokens (per session, per task, per model) and, with the new --prices <json> ($ per million tokens per model regex), a cost; a session that sent no tokens is no data, never 0. /teamwright:improve reads it as a signal (model or batch per stage). docs/process/metrics.md, gates.md (journal). Tests in tests/test-journal.sh, tests/test-metrics.sh.
  • Review gate check 7: one reviewed task spawns at most two new tasks (lifecycle.md §6 — until now only a line in the review skill). A new docs/tasks/<ID>.md created while the session's latest spawn by its main agent is a code-reviewer for task R counts toward R's review (the reviewer's rca task and the orchestrator's follow-up task alike; a later spawn of another role closes the window); the third is refused with the exit — add to an existing record, one umbrella task, or ask the owner. Gate-first warns. Limit TEAMWRIGHT_REVIEW_NEW_TASKS (2); ledger .teamwright/sessions/<R>.new-tasks.jsonl. gates.md, the review skill. Tests in tests/test-review-gate.sh.
  • The recommended models per stage and stage thresholds are offered. tw-next.py --json reports recommended (_config.PROCESS_RECOMMENDED, now with stages: batch 1, min 1, max_wait_hours 0 per stage, beside the models analyze/implement/review/verify opus, red-tests sonnet). adopt and init ask about the models and thresholds in their settings block, /teamwright:settings shows the recommended column from it and offers the keys still at a different default, /teamwright:status names them. Tests in tests/test-tw-next.sh.
  • tests/test-usage-example.sh: the autonomous-run workflow in docs/usage.md is parsed (PyYAML, or a subset parser where it is missing), its route step is run against a real project (tw-next.py --json, the headless and reason fields it reads, run=false with nothing to do), every steps.route.outputs.* another step reads is printed, the dispatched file is the one the docs name, and the claude flags exist when the CLI is installed. It found a real error: run: echo "router: …" is not valid YAML — the step now passes the reason through env (also no template expansion inside the shell).
  • Release channels: stable and experimental. The branch next is published as a second marketplace, teamwright-next (/plugin marketplace add smykov/teamwright#next, /plugin install teamwright@teamwright-next); it carries no version, so every pushed commit is an update. scripts/check-versions.py (in make lint, and make release-check) applies the rule by the marketplace name, not the branch: teamwright — the versions agree and have a changelog section (unchanged), teamwright-<channel> — no version anywhere. The installer records a channel kit's version as the 12-hex commit Claude Code computes (from the git checkout, or installed_plugins.json for an installed copy), and enables its channel in .claude/settings.json only when no other channel of teamwright is enabled there or in settings.local.json — two enabled copies with one name do not mix. README (Channels), CONTRIBUTING (Branches and channels), docs/usage.md. Tests: tests/test-release-check.sh, tests/test-installer.sh.

Changed

  • resume means unfinished work in the tree: tracked changes, or a session that ended interrupted. A current task on a clean tree no longer forces resume: its stage is recorded and committed, and it is routed to that stage (continue). In IN_PROGRESS the router's role follows the stage (test-writer at red-tests, developer at implement). tests/test-tw-next.sh updated.
  • docs/process/sessions.md §8 (stages, the stage field, selection, batches, thresholds, models, the stage-command protocol, autonomous runs), §5 (model per stage); lifecycle.md, gates.md, plugin.md, AGENTS.md, the flow, parallel, settings and status skills, design-decisions.md, docs/usage.md (an example workflow, one stage per job) and the README describe it.
  • tw-next.py no longer prints a BrokenPipeError when its reader stops early (| grep -q).

Fixed

  • Router: only a linked worktree is a per-task tree. An autonomous run checks out the whole project on a task branch (task/T-12-run3); the router took the branch name for a parallel worktree of T-12, refused verify for it ("merge it from the main tree") and d...
Read more

teamwright 0.11.0

Choose a tag to compare

@smykov smykov released this 24 Oct 21:18
e330c0d

Added

  • scripts/tw-gate <area> [--fresh], installed into projects: the full gate once per state of the code. In an autonomous run a small task took about 90 minutes, and its ten-minute area gate ran five times on the same code — twice by the developer (it cut the output with tail -8 and had to run it again to see the result), then by the flow's Gate step, the code-reviewer and the task-validator. tw-gate runs what the role files name as the gate (the area's generate_command, then its gate_command through scripts/tw-run, or the top-level gate_command as written), writes the whole output to .teamwright/logs/gate/<area>-<time>-<commit>.log ($TEAMWRIGHT_LOG_DIR respected), records the run in <area>.json and runs.jsonl (area, head, clean, tree, exit, duration, times, log, command), and prints PASS/FAIL, the exit code, the duration, the last 30 lines of a failure and the log path; its exit code is the gate's. A PASS is reused when the working tree has the same content (a git tree id of HEAD plus uncommitted and untracked changes, ignored files left out), root and command, and the tree did not change during the run: PASS (cached: same commit <sha>, <when>, log <path>). So the developer's PASS before the commit answers the flow, the reviewer and the validator once that content is committed. A FAIL is never reused; --fresh always runs. Tests: tests/test-tw-gate.sh (also under bash 3.2).

  • scripts/tw-mutants <area> <ID> --tree <copy>, installed into projects: the task's mutant catalog, in one runner start. Mutants are kept in the repository as docs/tasks/<ID>.mutants/: one <NN>-<slug>.mutant file each — guarantee: (the Acceptance/DoD line it breaks, - for none), file:, added_by:, optional test: and equivalent:, and the exact replacement between --- old / --- new / --- end — plus test-command, the command that runs only the task's tests. tw-mutants refuses the working tree, checks every entry against the throwaway copy (old text exactly once), and runs a baseline and every mutant in one scripts/tw-run <area> start with the copy as the project root (for runner: docker, the copy is what the container mounts). One line per mutant (killed, SURVIVED … breaks: <guarantee>, survived, follow-up, equivalent), a report in .teamwright/logs/mutants/; exit 0 when no survivor breaks a guarantee, 1 when one does, 2 for a stale or broken entry, 3 for a red baseline. Tests: tests/test-tw-mutants.sh (with a fake docker that counts starts and checks the mount).

  • tw-gate and tw-mutants outlive Claude Code's 10-minute Bash limit. In an autonomous run the gate was cut by the limit and started again; agents also killed the test container to restart, or polled the log in until grep …; sleep loops. Both scripts now start the real run detached — its own session and process group (scripts/hooks/_job.sh, Python's start_new_session, bash 3.2 and macOS included), output to the log, a job directory keyed like the cache under .teamwright/logs/{gate,mutants}/jobs/ — and wait in the foreground up to TW_WAIT_SECONDS (default 540). Done in time: the normal result and exit code. Not yet: RUNNING: gate <area> (pid N), started <when>, log <path> - run the same command again to keep waiting, exit 75. The same command again attaches to that run instead of starting another; a result that finished while nobody waited is printed by the next same call; a run of the same area (or task) on other content is waited for first; --fresh attaches to a running run rather than starting a second; a run killed without a result (pid gone) is reported, cleaned up and started again; a killed caller leaves the run going; scripts/tw-gate --stop <area> ends one. Role files, AGENTS.md and the flow: never wrap them in sleep loops or background calls — on RUNNING call the same command again; other long test commands run once through scripts/tw-run with output to a file. Tests: fake slow gates and catalogs with tiny wait budgets (attach, uncollected FAIL, --fresh, killed run, other content, killed caller, --stop).

  • scripts/tw-gate --for-task <ID> / --for-diff <base> and --top: gate the areas a task changed. In one project the validator ran the server suite for a CI-only change. The task's changed files (its own commits — on a branch, those since it left the default branch; everywhere, commits whose subject names the id first, so a commit that only mentions the task in its body does not count — plus uncommitted and untracked) map to the areas whose source_dirs, test_dirs or workdir hold them; a file outside every area means the top-level gate (--top, every area when there is none), except records, docs and Markdown, CI configuration and tool settings, which need no local gate ($TEAMWRIGHT_NO_GATE_RE). The flow's Gate step, the code-reviewer and the task-validator run exactly the listed gates.

  • Throwaway copies get generated code and a warm build cache. In one project every clean copy for mutants ran build_runner for ~5 minutes. New area keys: generated: [paths] (the outputs of generate_command) and optional generate_inputs: [paths] — tw-mutants copies the outputs from the working tree when the copy's inputs are unchanged, and otherwise runs generate_command in the copy inside the same runner start (exit 4 when it fails); copy_env: {VAR: value} — applied by scripts/tw-run under TW_RUN_COPY=1, {cache} = .teamwright/cache/<area>/copy of the main checkout (/tw-copy-cache in docker), e.g. CARGO_TARGET_DIR: "{cache}/target", so a copy neither builds from cold nor tramples the working tree's target dir; TW_CACHE_ROOT makes a copy's docker runs reuse the main checkout's package caches. scripts/tw-mutants <area> --tree <copy> --prepare does only this step for tests run by hand. The installer validates the keys. Tests in test-tw-mutants.sh and test-installer.sh.

  • scripts/tw-test <area> [tests ...] and the test guard: tests only through the wrapper. In one project's autonomous run the test-writer, after fixing one test, ran the same ~4-minute suite four times in a row: twice with the output cut by | grep … | tail -15 (the failures were lost), once with -p no:logging, which removed the caplog fixture and produced 25 false errors, once right — ~12 minutes, and with one worker instead of the configured PYTEST_WORKERS; the developer ran the gate script directly twice. The role files already said "never cut output"; agents ignored it, so the tooling enforces it. scripts/tw-test runs the area's new test_select_command ({tests} = the selectors, shell-quoted; workers stay in the config string, e.g. pytest -q -n ${PYTEST_WORKERS:-4} {tests}), else test_command with the selectors appended, through scripts/tw-run; the whole output goes to .teamwright/logs/test/, the screen gets PASS/FAIL, exit code, duration, the counts (pytest, cargo test, go test, flutter/dart test, jest, vitest), the failed tests with their first error line (at most 30) or the last 15 lines, and the log path. A repeat on the same area files (tw-gate's area-scoped key), command and selectors answers from the cache — a FAIL too: the answer to a failure is its log; --fresh reruns. Detached like tw-gate (RUNNING, exit 75, the same call attaches); --tree <copy> runs in a throwaway copy. The new PreToolUse hook scripts/hooks/test-guard.sh (Bash) refuses test runners and gates called directly — built-in patterns (pytest, python -m pytest, make test|check, flutter|dart|go|cargo test, npm|pnpm|yarn test, vitest, jest, phpunit, gradlew test, mvn test, …, also behind uv run/npx, sh -c, docker run and inside scripts/tw-run), every area's gate_command/test_command/test_select_command and the top-level gate_command (e.g. a project's tool/gate.sh), and the new top-level test_runner_patterns — and test or gate output piped into grep/tail/head/sed/awk, wrappers included; the message names the command to run instead (scripts/tw-test server tests/pipeline, scripts/tw-gate server) and says to read the log. It has its own switch, because gate-first only warns: process.test_guard: block | warn | off (default block, also in gate-first), TW_TEST_GUARD in the environment Claude Code starts with wins; the area's lint, codegen, API and UI test commands through scripts/tw-run stay allowed. The installer validates the new keys. Roles: developer, test-writer, code-reviewer and task-validator, AGENTS.md, gates.md (new section Test guard), tools.md, plugin.md, the settings, adopt and init skills and the README carry one rule — tests only via tw-test, gates via tw-gate, mutations via tw-mutants; the test-writer's wrong implementations and the validator's hand-run tests in a copy use tw-test --tree. Tests: tests/test-tw-test.sh, tests/test-test-guard.sh, tests/test-installer.sh. A config command whose head is a script that only wraps another one (tool/gate.sh sh -c '…') is not itself a signature — its inner command is checked, so lint, formatting and migrations through the same wrapper still run.

  • pre-push warns about a CI-skip marker on the pushed tip ([skip ci], [ci skip], [no ci], [skip actions], ***NO_CI***, skip-checks: true): CI decides by the tip's message, so the code under it and a pull request opened from it go unchecked — one project lost ~8 minutes on it. A warning, not a refusal. AGENTS.md, the flow's push step and docs/usage.md now say: never [skip ci] in a commit message, least of all on the last commit before a push; record-only pushes are skipped by the CI configuration (paths-ignore, scripts/tw-ci-changes).

Changed

  • process.batch.parallel up to 10 (was 1–4): an owner running more parallel worktree sessions (and per-worktree tool slots, e.g. Serena) on one project hit the cap. Default stays 1 (off).
  • **Roles run the gate ...
Read more

teamwright 0.10.0

Choose a tag to compare

@smykov smykov released this 24 Oct 21:18

Added

  • The router and the progress report read tasks from per-task worktrees (#12). Before, tw-next knew only /teamwright:parallel's tw/<ID> branches, and read even those from the branch; a task worked in a hand-made worktree on its own branch kept its main-tree record, so the main checkout showed it TODO, offered to start it again or resume a task already merged there, and tw-progress listed it as an unassigned area because its analysis existed only on the branch. Now a worktree whose branch names a task — tw/<ID> or task/<ID>, any suffix after a separator (task/T-12-parser), or $TEAMWRIGHT_TASK_BRANCH_RE with the id in group 1 — supplies that task's state from its own copy of the record (status, analysis, review, verify and validation rounds), marked in_worktree and branch. The main tree skips it, offers merge (naming the branch and path) once it is CODE_COMPLETE or later, the human output lists in worktrees:, and parallel.worktrees in the JSON gives path, branch and status. A session in such a worktree sees only its own task. Tests: tests/test-tw-worktrees.sh.

Full changelog: CHANGELOG.md

teamwright 0.9.0

Choose a tag to compare

@smykov smykov released this 24 Oct 21:18

Changed

  • The test-writer breaks each Acceptance failure branch before review (#11). Its first spawn runs before the implementation exists, so the end-to-end test of a failure branch was first mutated by the validator after deploy; in one project toothless-test was the most frequent blocking finding (14 of 59) and 4 of 5 VERIFY_FAILs were test gaps, each costing a merge, a deploy, a re-analysis and another review. Now /teamwright:flow spawns the test-writer a second time with mode: failure-branch bite once the developer's tests are green, before the gate: one mutation per failure branch on a throwaway copy that carries the uncommitted implementation, the test that guards it run there (for surface: api | both the end-to-end test verification will run; for a UI test, the state its wait reaches only after the branch ran), a surviving mutation means the test is rewritten. The result is a ### Failure branches table under ## Tests; the code-reviewer reads it (a missing row or a survivor is toothless-test) and does not re-run it, the task-validator re-runs it with its own mutations. Role files (test-writer, code-reviewer, task-validator), the task template, the flow skill (step 4 and resume), lifecycle.md, roles.md, gates.md and the README describe it. Projects pick it up after /plugin update: /teamwright:status reports the changed files, and tw-install.py apply (or /teamwright:adopt again) updates the ones the project did not edit.

Full changelog: CHANGELOG.md

teamwright 0.8.6

Choose a tag to compare

@smykov smykov released this 24 Oct 21:18

Fixed

  • tw-process counted no ratified tails on macOS. It finds the commits that set tail_code: ratified with git log -G, and the pattern used \s, a GNU extension that git on macOS (POSIX regex) does not know; the count was always 0 there. The pattern is [[:space:]]* now. Found by the macOS CI job once the bash 3.2 failures were out of the way.

Full changelog: CHANGELOG.md

teamwright 0.8.5

Choose a tag to compare

@smykov smykov released this 24 Oct 21:18

Fixed

  • pre-push refused every push on bash 3.2 (the macOS default). With no remote-tracking branches yet — a first push, or a new remote — the hook expanded an empty array under set -u, which bash before 4.4 treats as an unbound variable: delivered[@]: unbound variable, and the push was refused. The empty case now expands to nothing, as elsewhere in the hooks. The bash 3.2 CI job, which runs the existing pre-push tests in a bash:3.2 container, was failing on this.
  • The demo died on macOS (from→: unbound variable): bash 3.2 takes the bytes of a non-ASCII character after $name as part of the name. examples/demo.sh writes ${from}→${to}, and make lint now fails on $name before a non-ASCII character in any shell file (scripts/check-sh-names.py) — Linux CI could not see it otherwise.
  • Tests: ls | grep counts replaced with find (shellcheck SC2010); test-tw-ci-changes.sh imports importlib.machinery explicitly, which newer Python no longer pulls in through importlib.util.

Full changelog: CHANGELOG.md