Skip to content

Commit 636fffa

Browse files
committed
v1.0.6: Self-healing latest symlink, reliable script paths, hardened planner protocol
All skill scripts now self-heal the cache/tandemkit/latest symlink at the top of every run, so version updates never leave a stale pointer. Planner/generator/evaluator SKILL.md switched from the fragile CLAUDE_PLUGIN_ROOT/CLAUDE_SKILL_DIR fallback to an absolute path under $HOME/.claude/plugins/cache/FlineDev/tandemkit/latest — skills work whether loaded via plugin system or via ~/.agents/skills/ symlinks. Planner SKILL.md also tightened in three places: - Clickable file:// link to the latest Claude-NN.md draft is now a HARD REQUIREMENT at every approval step, never optional. - Last line before AskUserQuestion must be a brief plain-text prompt, so the AskUserQuestion overlay can never hide the spec link. - Codex launch now states explicitly that run_in_background on the Agent is the ONLY backgrounding mechanism — passing --background to the Codex CLI produces double-backgrounding with empty output. - Empty output / zero-byte Codex-NN.md is no longer treated as "Codex unavailable"; only EXPLICIT error messages trigger that branch, otherwise the planner flags a launch issue and asks.
1 parent bed3315 commit 636fffa

6 files changed

Lines changed: 34 additions & 17 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.5",
3+
"version": "1.0.6",
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",

scripts/create-mission.sh

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
#!/usr/bin/env bash
22
set -euo pipefail
33

4+
# Self-heal the 'latest' symlink so it always points at the newest installed version.
5+
_TC="$HOME/.claude/plugins/cache/FlineDev/tandemkit"
6+
_NV=$(ls "$_TC" 2>/dev/null | grep -v '^latest$' | sort -V | tail -1)
7+
[[ -n "$_NV" ]] && ln -sf "$_NV" "$_TC/latest" 2>/dev/null
8+
unset _TC _NV
9+
410
# TandemKit — create-mission
511
# Scaffolds a new mission folder with State.json and updates Config.json.
612
# Must be run from the project root (where TandemKit/ lives).

scripts/wait-for-state.sh

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
#!/usr/bin/env bash
22
set -euo pipefail
33

4+
# Self-heal the 'latest' symlink so it always points at the newest installed version.
5+
_TC="$HOME/.claude/plugins/cache/FlineDev/tandemkit"
6+
_NV=$(ls "$_TC" 2>/dev/null | grep -v '^latest$' | sort -V | tail -1)
7+
[[ -n "$_NV" ]] && ln -sf "$_NV" "$_TC/latest" 2>/dev/null
8+
unset _TC _NV
9+
410
# TandemKit — wait-for-state
511
# Blocks until a State.json field matches an expected value (or any change occurs).
612
#

skills/evaluator/SKILL.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ Both Claude and Codex write their per-round outputs as files in `Evaluator/Round
5555
> **If you are Codex:** Run the setup script before anything else. It verifies that your `~/.agents/skills/` symlinks resolve correctly and auto-repairs them if stale — handles plugin upgrades transparently with no user involvement.
5656
5757
```bash
58-
bash "${CLAUDE_PLUGIN_ROOT:-${CLAUDE_SKILL_DIR}/../..}/scripts/setup-codex-skills.sh"
58+
bash "$HOME/.claude/plugins/cache/FlineDev/tandemkit/latest/scripts/setup-codex-skills.sh"
5959
```
6060

6161
Silent if everything is up to date. Prints what changed if repairs were made. Exits with an error if the TandemKit plugin is not installed.
@@ -89,7 +89,7 @@ The user invokes this skill with `/tandemkit:evaluator NNN-MissionName`. First r
8989
- `"ready-for-eval"` → Proceed to Step 3 immediately.
9090
- Any other value → Wait:
9191
```bash
92-
bash "${CLAUDE_PLUGIN_ROOT:-${CLAUDE_SKILL_DIR}/../..}/scripts/wait-for-state.sh" "$(pwd)/TandemKit/NNN-MissionName" generatorStatus ready-for-eval
92+
bash "$HOME/.claude/plugins/cache/FlineDev/tandemkit/latest/scripts/wait-for-state.sh" "$(pwd)/TandemKit/NNN-MissionName" generatorStatus ready-for-eval
9393
```
9494
Run with `run_in_background: true`. When it prints "READY", proceed to Step 3.
9595

@@ -255,12 +255,12 @@ After writing your verdict, IMMEDIATELY start TWO background watchers:
255255
256256
1. **Next round watcher:**
257257
```bash
258-
bash "${CLAUDE_PLUGIN_ROOT:-${CLAUDE_SKILL_DIR}/../..}/scripts/wait-for-state.sh" "$(pwd)/TandemKit/NNN-MissionName" generatorStatus ready-for-eval --round N+1
258+
bash "$HOME/.claude/plugins/cache/FlineDev/tandemkit/latest/scripts/wait-for-state.sh" "$(pwd)/TandemKit/NNN-MissionName" generatorStatus ready-for-eval --round N+1
259259
```
260260
261261
2. **Completion watcher:**
262262
```bash
263-
bash "${CLAUDE_PLUGIN_ROOT:-${CLAUDE_SKILL_DIR}/../..}/scripts/wait-for-state.sh" "$(pwd)/TandemKit/NNN-MissionName" phase complete
263+
bash "$HOME/.claude/plugins/cache/FlineDev/tandemkit/latest/scripts/wait-for-state.sh" "$(pwd)/TandemKit/NNN-MissionName" phase complete
264264
```
265265
266266
Run both with `run_in_background: true`. When either returns:

skills/generator/SKILL.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ The user invokes this skill with `/tandemkit:generator NNN-MissionName`. First r
4848
b. If `evaluatorStatus` is `null` → the Evaluator is not ready yet. Update State.json: `generatorStatus: "researching"`. You may read files, investigate the codebase, and prepare — but do NOT create or modify implementation files.
4949
c. Wait for the Evaluator to signal readiness:
5050
```bash
51-
bash "${CLAUDE_PLUGIN_ROOT:-${CLAUDE_SKILL_DIR}/../..}/scripts/wait-for-state.sh" "$(pwd)/TandemKit/NNN-MissionName" evaluatorStatus watching
51+
bash "$HOME/.claude/plugins/cache/FlineDev/tandemkit/latest/scripts/wait-for-state.sh" "$(pwd)/TandemKit/NNN-MissionName" evaluatorStatus watching
5252
```
5353
Run with `run_in_background: true`. When it prints "READY", update State.json: `generatorStatus: "working"`, `phase: "generation"`. Proceed.
5454
6. Check for `UserFeedback/` files — if they exist, read the latest (this is a feedback iteration)
@@ -81,7 +81,7 @@ The user invokes this skill with `/tandemkit:generator NNN-MissionName`. First r
8181
6. **Signal the Evaluator**: Update State.json — `generatorStatus: "ready-for-eval"`, `evaluatorStatus: "pending"`, `phase: "evaluation"`, `round: N`. Read-modify-write only your fields.
8282
7. **Wait for evaluation**: Use `wait-for-state.sh`:
8383
```bash
84-
bash "${CLAUDE_PLUGIN_ROOT:-${CLAUDE_SKILL_DIR}/../..}/scripts/wait-for-state.sh" "$(pwd)/TandemKit/NNN-MissionName" evaluatorStatus done --round N
84+
bash "$HOME/.claude/plugins/cache/FlineDev/tandemkit/latest/scripts/wait-for-state.sh" "$(pwd)/TandemKit/NNN-MissionName" evaluatorStatus done --round N
8585
```
8686
Run with `run_in_background: true`. When `evaluatorStatus` is `"done"` and round matches, read `Evaluator/Round-NN.md`.
8787
@@ -213,7 +213,7 @@ If the user says "abort": confirm, set State.json `phase: "abandoned"`, Config.j
213213
Use `wait-for-state.sh` for ALL State.json watching. Do NOT use raw watchman-wait.
214214
215215
```bash
216-
bash "${CLAUDE_PLUGIN_ROOT:-${CLAUDE_SKILL_DIR}/../..}/scripts/wait-for-state.sh" "$(pwd)/TandemKit/NNN-MissionName" evaluatorStatus done --round N
216+
bash "$HOME/.claude/plugins/cache/FlineDev/tandemkit/latest/scripts/wait-for-state.sh" "$(pwd)/TandemKit/NNN-MissionName" evaluatorStatus done --round N
217217
```
218218
219219
Run with `run_in_background: true`. The script checks immediately, then enters a watch loop. When it prints "READY", re-read State.json. The `--round N` parameter ensures you don't match stale values from a previous round.

skills/planner/SKILL.md

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ You are the Planner. Your job is to investigate the codebase, ask the right ques
1414

1515
1. **Ask questions ONE AT A TIME** with 2-3 sentences of context before each AskUserQuestion call.
1616
2. **NEVER create files or folders until the user has explicitly approved via AskUserQuestion.** Do not infer approval from context.
17-
3. **Present a 5–10 line summary + a clickable file link to the latest `Claude-NN.md` draft.** Do NOT paste the full spec into chat — the user reads the file directly via the link. The same file becomes `Spec.md` byte-for-byte after approval (via `cp`), so what they read IS what they're approving. The clickable link must follow the `[name](file:///absolute/path)` format from the workspace AGENTS.md so it opens in the user's editor.
17+
3. **ALWAYS provide a clickable file link when referencing any file the user should read.** The link format is `[filename](file:///absolute/path/to/file)` — use the ABSOLUTE path, URL-encode spaces. This is a HARD REQUIREMENT for every `Claude-NN.md` draft, every `Spec.md`, and any other file you point the user to. If the user cannot click a link to open the file, you have failed this step. Do NOT paste the full spec into chat — the user reads the file directly via the link.
1818
4. **Use Variant 1 visual framing** for copyable content:
1919

2020
╔═══ UPPERCASE LABEL ══════════════════════════════════════════════════╗
@@ -72,7 +72,7 @@ Both Claude and Codex write their per-round outputs as files in `Planner-Discuss
7272
> **If you are Codex:** Run the setup script before anything else. It verifies that your `~/.agents/skills/` symlinks resolve correctly and auto-repairs them if stale — handles plugin upgrades transparently with no user involvement.
7373
7474
```bash
75-
bash "${CLAUDE_PLUGIN_ROOT:-${CLAUDE_SKILL_DIR}/../..}/scripts/setup-codex-skills.sh"
75+
bash "$HOME/.claude/plugins/cache/FlineDev/tandemkit/latest/scripts/setup-codex-skills.sh"
7676
```
7777

7878
Silent if everything is up to date. Prints what changed if repairs were made. Exits with an error if the TandemKit plugin is not installed.
@@ -104,10 +104,12 @@ Silent if everything is up to date. Prints what changed if repairs were made. Ex
104104

105105
Only AFTER that block is in the response do you run the scaffolding script. This creates the mission folder, `Planner-Discussion/` subfolder, and `State.json` in one shot:
106106
```bash
107-
bash "${CLAUDE_PLUGIN_ROOT:-${CLAUDE_SKILL_DIR}/../..}/scripts/create-mission.sh" "NNN-MissionName"
107+
bash "$HOME/.claude/plugins/cache/FlineDev/tandemkit/latest/scripts/create-mission.sh" "NNN-MissionName"
108108
```
109109
Also create the feature branch if configured.
110-
9. **Immediately launch Codex in background** using the Agent tool with `run_in_background: true`. Do NOT also use `--background` in the Codex CLI flags — that creates double-backgrounding where the Agent "completes" immediately but Codex is still running, and you never get the result notification.
110+
9. **Immediately launch Codex in background** using the Agent tool with `run_in_background: true`.
111+
112+
**CRITICAL — NO DOUBLE-BACKGROUNDING:** The Agent tool's `run_in_background: true` is the ONLY backgrounding mechanism. Do NOT EVER pass `--background` in the Codex CLI flags. If you use both, the Agent completes instantly with zero output (because Codex itself backgrounded), you get no result notification, Codex-01.md stays empty, and the whole round breaks. This has happened before. The correct pattern: `run_in_background: true` on the Agent call, NO `--background` anywhere in the prompt text.
111113

112114
The Codex prompt points at its template file plus the per-mission inputs. Substitute `NNN-MissionName`, the user's verbatim goal text, AND `{EFFORT}` (the `codex.effort` value you captured from `Config.json` in Step 0.5):
113115

@@ -124,11 +126,13 @@ Silent if everything is up to date. Prints what changed if repairs were made. Ex
124126
- User goal (verbatim): [paste the user's goal text here]
125127
```
126128

127-
**If Codex is unavailable**, distinguish two cases:
129+
**If Codex is unavailable** — only if you receive an EXPLICIT error message indicating unavailability. **Empty output or zero-byte Codex-01.md is NOT evidence of unavailability** — it almost always means you double-backgrounded (see rule above) or the prompt was malformed. If Codex-01.md is empty and you did NOT receive an explicit error, tell the user: "Codex produced empty output — this is likely a launch issue, not a Codex problem. Want me to retry?" Do NOT write a placeholder or proceed Claude-only.
130+
131+
Only treat Codex as unavailable when you see one of these EXPLICIT signals:
128132

129-
- **Permanent** (CLI not installed, auth expired/invalid, `/codex:rescue` itself errors out before Codex even starts): STOP. Tell the user: "Codex is unavailable. Please run `/codex:setup` to fix, then say 'continue'." Do NOT proceed with Claude-only planning — TandemKit's value comes from the dual-model approach and a permanent failure is something the user needs to fix.
133+
- **Permanent** (CLI not installed, auth expired/invalid, `/codex:rescue` itself errors out with a clear error message before Codex starts): STOP. Tell the user: "Codex is unavailable. Please run `/codex:setup` to fix, then say 'continue'." Do NOT proceed with Claude-only planning.
130134

131-
- **Temporary** (Codex returned a rate-limit / token-quota error like `"You've hit your usage limit. To get more access now... try again at <date>"`, or the `codex-companion` reported a quota/throttle error, or a network/timeout error): Do NOT keep retrying — token-limit errors won't clear within this session. Instead:
135+
- **Temporary** (Codex returned an EXPLICIT rate-limit / token-quota error like `"You've hit your usage limit. To get more access now... try again at <date>"`, or the `codex-companion` reported a quota/throttle error with a clear message): Do NOT keep retrying — token-limit errors won't clear within this session. Instead:
132136
1. Write a **placeholder `Codex-01.md`** to `Planner-Discussion/` containing exactly:
133137
```markdown
134138
# Codex-01 — Skipped (Codex Unavailable)
@@ -223,12 +227,13 @@ Codex is already running in background from Step 0.9. The `Planner-Discussion/`
223227
26. Present to the user, in chat:
224228
- **A 5–10 line summary** of what Claude and Codex converged on (mission goal in one sentence, key acceptance criteria, key decisions, anything noteworthy)
225229
- **Any remaining low-level differences** between Claude and Codex (one short bullet each)
226-
- **A clickable file link** to the final draft, in this exact format (substitute the absolute path):
230+
- **A clickable file link** to the final draft this is MANDATORY, not optional:
227231
```
228232
📄 [Claude-NN.md](file:///absolute/path/to/TandemKit/NNN-MissionName/Planner-Discussion/Claude-NN.md)
229233
```
230-
Use the absolute path (not a relative one) so the link opens in the user's editor regardless of their current directory. URL-encode any spaces or special characters per the workspace AGENTS.md conventions.
234+
Construct the absolute path from the current working directory + the relative path. URL-encode spaces. If you present the approval step WITHOUT this clickable link, the user cannot review the spec and the step is broken. NEVER skip the link.
231235
- **One sentence** explaining: "This file becomes `Spec.md` exactly as written once you approve. If you want editorial changes (typos, wording), say so and I'll apply them after the approval. If you want substantive changes (new criteria, changed scope), say so and Codex will review them in another convergence round."
236+
- **LAST LINE before AskUserQuestion** must be a brief plain-text prompt like: "Ready to finalize the spec?" — this acts as a buffer because AskUserQuestion can visually overlay the last line of chat output. The clickable file link MUST appear ABOVE this line, never as the last thing before AskUserQuestion.
232237
27. Ask for approval via AskUserQuestion. The options should be: **Approve as-is** / **Approve with editorial changes** / **Substantive changes needed**.
233238
28. Handle the response:
234239

0 commit comments

Comments
 (0)