Skip to content

Commit 60ea6ba

Browse files
committed
1.0.8: Race-free state watchers, add contributor guide
Drops the `--round` / `--min-round` flags from wait-for-state.sh. The status-field resets both agents already perform at the start of each round make the round gate redundant, and the old exact-match semantic caused watchers to hang when the Generator raced past the expected round under never-stop mode. The invariant is now documented once in the script header and nowhere else. Also introduces AGENTS.md with the release process (bump plugin.json + tag + GitHub release, no `v` prefix), the per-type past-release-style check, and the no-mid-sentence-line-breaks rule for Markdown.
1 parent 67a412c commit 60ea6ba

5 files changed

Lines changed: 56 additions & 18 deletions

File tree

.claude-plugin/plugin.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "tandemkit",
3-
"version": "1.0.9",
3+
"version": "1.0.8",
44
"description": "Describe your goal, approve the spec, then step away — Claude and Codex loop together until it's right.",
55
"author": {
66
"name": "Cihat Gündüz",

AGENTS.md

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
# TandemKit — Agent Instructions
2+
3+
This file applies to AI agents working in the TandemKit plugin repo.
4+
5+
## Cutting a release
6+
7+
Releases of TandemKit are **three coupled actions**. Never do any of them in isolation — and in particular, do **not** bump `plugin.json` unless you are cutting a release in the same commit.
8+
9+
A release consists of:
10+
11+
1. **Bump `.claude-plugin/plugin.json` `version`** to the new release number.
12+
2. **Create a git tag** at that commit, named with the bare version — e.g. `1.0.8`. **No `v` prefix.** All historical tags follow this convention; do not introduce a `v` prefix.
13+
3. **Create a GitHub release** with the same name and tag (no `v` prefix in either).
14+
15+
If any of these three is missing or inconsistent, the release is broken. Regular commits between releases must leave `plugin.json` untouched.
16+
17+
### Picking the version
18+
19+
Standard SemVer:
20+
21+
- **Patch (X.Y.**Z**)** — bug fixes, doc polish, small DX tweaks that don't change how the plugin is used.
22+
- **Minor (X.**Y**.0)** — new features, new skills, new strategies, new flags. Existing workflows keep working.
23+
- **Major (**X**.0.0)** — breaking changes: removed skills, renamed commands, changed mission-folder schema, etc.
24+
25+
### Writing release notes — match the past
26+
27+
Before writing release notes, read the **most recent releases of the same type** to match tone, structure, and depth. `gh release view <tag> -R FlineDev/TandemKit` is the fastest way.
28+
29+
| Releasing | Read these past releases first |
30+
|---|---|
31+
| Patch | The last **three** patch releases |
32+
| Minor | The last **two or three** minor releases |
33+
| Major | **All** past major releases |
34+
35+
The goal is consistency across the changelog, not novelty. If you have a good reason to break style (e.g. a release that genuinely needs a different format — a security advisory, a big migration guide), that's fine, but the default is to match.
36+
37+
## Markdown style
38+
39+
**Never insert mid-sentence line breaks in Markdown.** One paragraph = one line. Do not hard-wrap prose at 72/80/any column.
40+
41+
Why: mid-sentence line breaks make edits painful (every word change shifts the wrapping), they render inconsistently across viewers, and the diff hides what actually changed. Let the editor or the viewer wrap.
42+
43+
This applies to every `.md` file in the repo — skills, strategies, templates, README, AGENTS.md itself. Code blocks and lists are not prose and follow their own layout; this rule is specifically about paragraph text.
44+
45+
If you see wrapped paragraphs in existing files, unwrap them when you touch that section.

scripts/wait-for-state.sh

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,12 @@ unset _TC _NV
1818
#
1919
# If no field/values given: blocks until State.json content changes (any field).
2020
#
21-
# NOTE: There is no round filter. Both agents reset the other side's status field
22-
# at the start of each round (Generator writes evaluatorStatus=pending when
23-
# signalling ready-for-eval; Evaluator's verdict write keeps generatorStatus=
24-
# ready-for-eval but the next round-start flips generatorStatus=working first),
25-
# so a field-value match can never fire on a stale value from a previous round.
26-
# Dropping the round filter removes an exact-match race condition that used to
27-
# hang watchers when the counterparty raced ahead past the expected round number.
21+
# INVARIANT (why no round filter): both agents reset the other side's status
22+
# field at the start of each round — Generator writes evaluatorStatus=pending
23+
# when signalling ready-for-eval; Evaluator's verdict leaves generatorStatus at
24+
# ready-for-eval, and the next Generator round-start flips it to working first.
25+
# So the next time a watched field matches its expected value is always the
26+
# current round's signal, never a stale match from a previous round.
2827
#
2928
# Exit 0 = condition met. Output includes current state summary.
3029
# Exit 1 = error (missing files, bad args).
@@ -39,7 +38,7 @@ while [[ $# -gt 0 ]]; do
3938
case "$1" in
4039
--quiet) QUIET=true; shift ;;
4140
--round|--min-round)
42-
echo "ERROR: $1 has been removed in TandemKit 1.0.9 — watchers now rely on status-field resets, not round numbers. Drop this flag." >&2
41+
echo "ERROR: $1 has been removed in TandemKit 1.0.8 — watchers now rely on status-field resets, not round numbers. Drop this flag." >&2
4342
exit 1
4443
;;
4544
*) _ARGS+=("$1"); shift ;;

skills/evaluator/SKILL.md

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -258,13 +258,7 @@ After writing your verdict, IMMEDIATELY start TWO background watchers:
258258
bash "$HOME/.claude/plugins/cache/FlineDev/tandemkit/latest/scripts/wait-for-state.sh" "$(pwd)/TandemKit/NNN-MissionName" generatorStatus ready-for-eval
259259
```
260260
261-
No round filter is needed. Your verdict write leaves `generatorStatus` at its
262-
value from the Generator's ready-for-eval signal; the Generator's next round-
263-
start flips it to `"working"` first (or sometimes straight to `"ready-for-eval"`
264-
again for the new round). Either way, the next time `generatorStatus ==
265-
ready-for-eval` is the next round's signal, regardless of how many rounds the
266-
Generator has burned through since your last wake. Read `round` from
267-
`State.json` at wake time to know which `Round-NN.md` to evaluate.
261+
Read `round` from `State.json` at wake time to know which `Round-NN.md` to evaluate.
268262
269263
2. **Completion watcher:**
270264
```bash

skills/generator/SKILL.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ The user invokes this skill with `/tandemkit:generator NNN-MissionName`. First r
8383
```bash
8484
bash "$HOME/.claude/plugins/cache/FlineDev/tandemkit/latest/scripts/wait-for-state.sh" "$(pwd)/TandemKit/NNN-MissionName" evaluatorStatus done
8585
```
86-
Run with `run_in_background: true`. When `evaluatorStatus` flips to `"done"`, read `Evaluator/Round-NN.md` where `N` is whatever `round` is in State.json at that moment. No round filter is needed — step 6 reset `evaluatorStatus` to `"pending"` when signalling, so the next `"done"` is always your round's verdict.
86+
Run with `run_in_background: true`. When `evaluatorStatus` flips to `"done"`, read `Evaluator/Round-NN.md` where `N` is whatever `round` is in State.json at that moment.
8787
8888
════════════════════════════════════════
8989
→ DONE — Waiting for Evaluator
@@ -216,7 +216,7 @@ Use `wait-for-state.sh` for ALL State.json watching. Do NOT use raw watchman-wai
216216
bash "$HOME/.claude/plugins/cache/FlineDev/tandemkit/latest/scripts/wait-for-state.sh" "$(pwd)/TandemKit/NNN-MissionName" evaluatorStatus done
217217
```
218218
219-
Run with `run_in_background: true`. The script checks immediately, then enters a watch loop. When it prints "READY", re-read State.json. No round filter — the status-field reset at step 6 guarantees the next `done` is your round's verdict.
219+
Run with `run_in_background: true`. The script checks immediately, then enters a watch loop. When it prints "READY", re-read State.json.
220220
221221
## File Reading Limits
222222

0 commit comments

Comments
 (0)