talking-stick 0.4.0 → 0.4.1

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.
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  A CLI coordination tool that lets multiple AI coding agents share a single workspace without stepping on each other. One agent holds the stick at a time; handoffs carry structured context so the next agent doesn't have to re-derive it.
4
4
 
5
- **Version:** 0.4.0. Multi-process-safe (SQLite WAL), liveness-aware, no daemon. Supports Claude Code, Codex CLI, Gemini CLI, and OpenCode out of the box. Two agents in the same room can also chat out-of-band — without passing the stick — via `tt msg send/recv`.
5
+ **Version:** 0.4.1. Multi-process-safe (SQLite WAL), liveness-aware, no daemon. Supports Claude Code, Codex CLI, Gemini CLI, and OpenCode out of the box. Two agents in the same room can also chat out-of-band — without passing the stick — via `tt msg send/recv`.
6
6
 
7
7
  ## Quickstart
8
8
 
@@ -46,7 +46,7 @@ That's the whole workflow. They negotiate turns automatically, hand off structur
46
46
 
47
47
  | Method | Command | Notes |
48
48
  |---|---|---|
49
- | **From npm** | `npm i -g talking-stick` | Published as `0.4.0`. Requires Node ≥ 22. |
49
+ | **From npm** | `npm i -g talking-stick` | Published as `0.4.1`. Requires Node ≥ 22. |
50
50
  | **From GitHub** | `npm i -g github:mostlydev/talking-stick` | Tracks the `master` branch; builds on install via the `prepare` hook. |
51
51
  | **From source** | `git clone … && npm install && npm link` | For contributors. |
52
52
 
@@ -6,7 +6,7 @@ import { resolveContextPath } from "./path-resolution.js";
6
6
  export const DEFAULT_MAX_INSTRUCTION_FILE_BYTES = 256 * 1024;
7
7
  export const DEFAULT_INSTRUCTIONS_MARKDOWN = `# Talking Stick collaboration instructions
8
8
 
9
- Keep using Talking Stick until the shared task is done. After releasing or handing off, re-enter the wait loop by default. Prefer continued action unless the task is complete or the operator explicitly redirects or stops the room.
9
+ Keep using Talking Stick until the shared task is done. After releasing or handing off, re-enter the wait loop by default. Prefer continued action unless the task is complete or the operator explicitly redirects or stops the room. If you are the only active member of the room, stop polling after a clear handoff rather than churning release/reclaim turns.
10
10
 
11
11
  Use phase names in handoffs when they clarify the work: draft, adversarial review, convergence, implementation, implementation review, test review, and release. These phases are vocabulary, not protocol state.
12
12
 
package/dist/service.js CHANGED
@@ -1247,20 +1247,24 @@ export class TalkingStickService {
1247
1247
  if (!room.pending_handoff_event_seq) {
1248
1248
  return false;
1249
1249
  }
1250
- if (now.getTime() - Date.parse(room.updated_at) >= this.policy.waiterGraceMs) {
1251
- return false;
1252
- }
1250
+ const handoffAgeMs = now.getTime() - Date.parse(room.updated_at);
1253
1251
  const pendingEvent = this.getEventBySeq(room.pending_handoff_event_seq);
1254
1252
  const priorOwner = pendingEvent?.from_agent_id ?? null;
1255
1253
  if (priorOwner === agentId &&
1256
- this.hasOtherRoomMember(room.room_id, agentId)) {
1257
- return true;
1254
+ this.hasOtherActiveRoomMember(room.room_id, agentId, now)) {
1255
+ return handoffAgeMs < this.priorOwnerReleaseCooldownMs();
1256
+ }
1257
+ if (handoffAgeMs >= this.policy.waiterGraceMs) {
1258
+ return false;
1258
1259
  }
1259
1260
  const bestKnownMember = this.findBestFairKnownMember(room.room_id, priorOwner, now);
1260
1261
  return bestKnownMember !== null && bestKnownMember.agent_id !== agentId;
1261
1262
  }
1262
- hasOtherRoomMember(roomId, agentId) {
1263
- return this.getMembers(roomId).some((member) => member.agent_id !== agentId);
1263
+ hasOtherActiveRoomMember(roomId, agentId, now) {
1264
+ return this.getMembers(roomId).some((member) => member.agent_id !== agentId && this.isMemberActive(member, now));
1265
+ }
1266
+ priorOwnerReleaseCooldownMs() {
1267
+ return Math.max(this.policy.waiterGraceMs * 6, 60_000);
1264
1268
  }
1265
1269
  inspectRoom(room, now) {
1266
1270
  const members = this.getMembers(room.room_id);
@@ -0,0 +1,38 @@
1
+ # Talking Stick 0.4.1
2
+
3
+ Date: 2026-05-10
4
+
5
+ This patch fixes release/reclaim churn discovered while dogfooding the 0.4.0
6
+ collaboration instructions. A holder could release with "no work", immediately
7
+ re-enter `tt wait`, and reclaim the stick before another active harness had a
8
+ real chance to claim.
9
+
10
+ ## Fixed
11
+
12
+ ### Prior-owner release cooldown
13
+
14
+ When a room is idle after a release, the release's prior owner now waits through
15
+ a bounded cooldown before reclaiming if another active member exists. The
16
+ cooldown defaults to `max(6 * waiterGraceMs, 60_000)`, which is 60 seconds with
17
+ the stock policy.
18
+
19
+ Other members can still claim immediately, and the prior owner can continue
20
+ immediately when he is genuinely alone. Stale members and audit-only
21
+ `target=any` event reads do not force a cooldown.
22
+
23
+ ### Solo-polling guidance
24
+
25
+ The bundled skill and default collaboration instructions now clarify the escape
26
+ hatch for one-agent rooms: if you are the only active member, stop polling after
27
+ a clear handoff instead of churning release/reclaim turns. Brief quiet periods
28
+ from another active agent are not enough to declare yourself alone.
29
+
30
+ ## Verification
31
+
32
+ ```bash
33
+ npm run typecheck
34
+ npm run build
35
+ npm test
36
+ git diff --check
37
+ npm pack --dry-run
38
+ ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "talking-stick",
3
- "version": "0.4.0",
3
+ "version": "0.4.1",
4
4
  "description": "CLI coordination tool for path-scoped agent handoffs.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -224,7 +224,7 @@ Exit the wait loop only when one of these is true:
224
224
  - the shared task is explicitly finished
225
225
  - the operator gives a direct redirect or stop
226
226
 
227
- In every other case, after `tt release` or `tt assign`, go straight back into `tt wait --json`. Other-harness inactivity is not an exit signal; keep waiting or take the next useful action until the task is done.
227
+ In every other case, after `tt release` or `tt assign`, go straight back into `tt wait --json`. If you are the only active member of the room, stop polling after a clear handoff. Treat "only active" as no other member that `tt state --json` reports active or that has been seen in the last hour; if liveness is ambiguous, run one more normal wait cycle instead of churning. Other agents going briefly quiet is not enough to declare yourself alone.
228
228
 
229
229
  If the operator tells you to drop out of coordination, run `tt leave --json`. Rooms with no active members are deleted instead of kept as history, and long-idle rooms may be purged on later invocations.
230
230