| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Name | Name | Last commit date | ||
|---|---|---|---|---|
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.
Multi-process-safe (SQLite WAL), liveness-aware, no daemon. Supports Claude Code, Codex CLI, Antigravity CLI (agy), Grok Build, and OpenCode out of the box. Gemini CLI identity is retained for existing sessions, but Gemini skill installation is deprecated in favor of Antigravity and the shared agents skill directory. One tt wait --json long-poll handles ownership and room events using a CLI-managed cursor; agents can chat out-of-band without passing the stick via tt msg send.
Three steps, then you're coordinating two agents in the same repo.
npm i -g talking-sticktt install --allRestart any harness that was already running so it loads the updated skill. The skill teaches agents to coordinate by running tt CLI commands from the workspace. To tune the default collaboration prompt without editing installed package files, run tt instructions edit.
Installing for Claude Code also merges a managed Stop-guard hook into ~/.claude/settings.json: when a Claude session tries to stop while it still owns the stick or holds an unclaimed reservation, the hook blocks the stop once and tells the model to release, pass, or enter standby first. It is read-only, fails open whenever coordination state is unavailable, never blocks twice in a row, and touches only its own settings entry. Pass --no-guard at install time to skip it; tt uninstall claude-code removes it.
Open two terminal panes side by side — tmux split, iTerm split, two windows, whatever you like. cd into the same repo in each, and launch a different harness in each pane:
| Pane A — Claude Code | Pane B — Codex |
|---|---|
| cd ~/myrepo && claude [--dangerously-skip-permissions] | cd ~/myrepo && codex |
Then give both panes the same prompt — a shared goal plus the skill trigger:
/goal Work together to implement OAuth login. Use the /talking-stick $talking-stick skill for coordination
/talking-stick $talking-stick triggers the skill in either harness, and the goal keeps each agent driving toward the shared objective. You don't script the turn-taking — the skill teaches each agent how to join, wait, listen, hand off, test, and review. Coordination is mandatory while the skill applies: agents take turns for shared edits, keep one receive path active whenever the harness can sustain it, carry structured handoffs (status, next action, artifacts, verification) across transitions, and never edit the repo at the same time.
| Method | Command | Notes |
|---|---|---|
| From npm | npm i -g talking-stick | Latest published release. Requires Node ≥ 22. |
| From GitHub | npm i -g github:mostlydev/talking-stick | Tracks the master branch; builds on install via the prepare hook. |
| From source | git clone … && npm install && npm link | For contributors. |
All three produce a tt binary on your PATH. Everything else below works identically. Published package installs also bootstrap the skiller binary used by tt install for skill-directory writes. Set TALKING_STICK_DISABLE_SKILLER_BOOTSTRAP=1 to skip that postinstall bootstrap, or TALKING_STICK_DISABLE_SKILLER=1 to force the built-in TypeScript fallback.
Want to see exactly what tt install would change before touching anything?
tt install --all --printtt install claude-code codexDuring normal execution, install commands skip harnesses that are not present instead of failing or creating new harness config roots.
Uses the right npm/pnpm/yarn by default:
tt self-updateThe package refreshes unedited generated instructions automatically. Customized instruction files and copied skills are preserved and receive an explicit replacement command instead of being overwritten.
tt uninstall --allSingle-harness uninstalls for shared-reading harnesses leave ~/.agents/skills/talking-stick in place because Codex, Antigravity, Grok, and OpenCode share that one skill location. Use tt uninstall agents or tt uninstall --shared to remove only the shared skill target.
Once installed, each agent harness has a skill that tells it to coordinate through the tt CLI:
tt list — which rooms exist under a path tt join — join the room for this workspace tt leave — explicitly leave a room; deletes it when no active members remain tt wait — long-poll for ownership and room events; cursor is saved automatically tt wait --park — stay coordinated without auto-claiming idle rooms tt standby — park, return immediately, and optionally wake the cmux surface later tt release — normal handoff to the next fair waiter, with structured Handoff tt assign — explicit handoff to a named agent tt take — deliberate claim when the prior holder is gone/stuck tt kick — evict an idle member whose process is gone tt state — authoritative state projection tt health/status — concise local safety/action check; --verbose shows diagnostics tt events — audit/debug log and lower-level event stream tt notes add/list — durable async observations for the room tt msg send — out-of-band chat into the room event log tt instructions — show, edit, safely update, or reset local instruction overrides
A workspace maps to a room — usually the git root or nearest project marker — so two agents cd'd anywhere under the same repo join the same room automatically. An existing parent room also wins across a nested Git repository or nearer project marker; --force-new is the explicit way to create a nested room. Marker files directly in your home directory are ignored for descendant paths, so scratch directories under $HOME do not collapse into one broad home-scoped room unless you explicitly join home itself.
The global skill tells the model when to join, wait, take over, leave notes, send messages, and hand off.
The bundled skill is the safety floor. It is intentionally small and package-managed. Local collaboration preferences live in editable Markdown files that tt instructions shows to agents after they join.
Instruction delivery is deliberately tiered:
| Surface | When the model sees it | Content |
|---|---|---|
| Installed skill | When Talking Stick is invoked/loaded | Full ownership, wait, recovery, and handoff mechanics |
| tt instructions show | Once after joining | Concise working agreement plus the detected harness's default role |
| Compact tt result hints | Only at join, authority, wait-exit, and handoff transitions | One short next-step safety reminder |
| Wake and Claude Stop hooks | Only on the matching lifecycle event | Fixed resume or release/pass warning |
| README and design docs | Only when explicitly opened | Human reference and rationale |
Normal tt join --json includes compact current-member summaries and omits the large policy block; --verbose retains the full diagnostic result. This lets an agent discover expected peers without polling tt state.
tt instructions show # effective prompt for the detected harness
tt instructions show --harness codex # view one harness's effective prompt
tt instructions edit # edit user defaults
tt instructions edit --project # edit this repo's overrides
tt instructions update --user # auto-refresh generated defaults; preserve custom content
tt instructions update --user --replace # explicitly replace customized user instructions
tt instructions reset --project # remove this repo's overrideEffective instructions are layered in this order: bundled defaults, user overrides at ${TALKING_STICK_DATA_DIR}/instructions.md (normally ~/.local/share/talking-stick/instructions.md), then project overrides at .talking-stick/instructions.md in the workspace root. Generated, unedited files update automatically. Customized files are preserved and appear as update_available in tt instructions show until explicitly replaced. User and project files are created lazily on first edit, so installing tt does not litter repositories or harness config directories.
While you wait your turn you may still need to flag something to the current owner: a subtle invariant, a related bug, a pointer to a doc. Non-owner notes give you a durable channel without interrupting the turn.
The stick guarantees single-writer authority over shared workspace state. It is not a chat protocol. When two agents need to talk — design questions, "are you about to break X?", live coordination — use messages instead of churning the stick.
tt msg send <recipient|room> "<body>" [--interrupt] [--stdin]
tt wait --jsonWhen to message vs note vs handoff.
to_agent_id is routing, not ACL. Any room member can read any message via tt events --target any. Messages are not private. They also do not grant the stick — a non-holder paging the holder gets attention, not write authority.
After a handoff, an agent keeps the wait loop alive while work is pending, runs tt standby --wake cmux --json when it is only waiting on an external signal, or — when the shared task is genuinely complete — stops and sends a final closeout instead of churning the room. Standby records parked intent, returns immediately, and wakes the same verified cmux surface once for a directed actionable update. --wake manual is available outside cmux but cannot self-wake. Final handoffs include the tests, build checks, runtime checks, release checks, dogfood checks, or an explicit reason the task was not testable. The exact completion evidence an agent must see before declaring done lives in the skill (skills/talking-stick/SKILL.md).
tt install installs or refreshes the bundled talking-stick skill. Skill directory writes are delegated to the skiller binary when available; package postinstall bootstraps skiller automatically from the published release and verifies checksums.txt before installation. If skiller is missing, disabled, or fails its version gate, tt uses the built-in TypeScript fallback.
By default, tt install links the bundled skill so local updates are picked up immediately. Pass --copy if you want a standalone snapshot.
For harnesses that previously had proprietary skill copies, tt prunes duplicate talking-stick entries conservatively: it removes only symlinks that resolve to the bundled Talking Stick skill, and preserves copied directories, foreign symlinks, or hand-authored entries. OpenCode cleanup checks both ~/.config/opencode/skills/talking-stick (honoring XDG_CONFIG_HOME) and the older ~/.opencode/skills/talking-stick location.
Automatic skill sync records the digest of managed copied skills. A known unedited copy updates automatically; an unknown or edited copy is preserved and the CLI offers tt install <harness> --replace. Managed symlinks continue to follow the bundled skill directly.
Human CLI invocations also perform a silent best-effort sync for already-installed file-based skills in Claude Code and the shared ~/.agents/skills/talking-stick target. If the installed skill is a copy, it is refreshed from the bundled skill; if it is a stale symlink, it is relinked. Missing skill installs are skipped. Gemini skill sync is deprecated; use Antigravity/shared install instead.
The same tt binary also works as a human CLI, useful for watching or participating in a room from your terminal:
tt whoami [--explain] # show the resolved CLI identity
tt list [path] # list rooms
tt join [path] [--force-new] # join the room for path
tt leave [path] # leave the room for path
tt wait [path] [--timeout 110s] [--park] [--after N] # ownership + events; saved cursor by default
tt standby [path] [--wake cmux|manual] # return immediately; wake later on directed action
tt try [path] [--park] [--after N] # non-blocking claim/event check
tt state [path] [--all] # compact room state; --all shows older rows
tt health [path] [--verbose|--all] # concise safety/action check; verbose shows diagnostics
tt status [path] [--verbose|--all] # alias for health
tt events [path] [--all] [--after N] [--limit N] [--wait|--follow] [--event TYPE[,TYPE]] [--target self|any|agent] # audit/debug event log; --wait/--follow lower-level streams
tt msg send <recipient|room> <body...> [--interrupt] [--stdin] [--path DIR] # send an OOB message
tt msg recv [--wait|--follow] [--from agent] [--after N] [--target self|any|agent] [--path DIR] # receive OOB messages
tt instructions show [path] [--harness claude|codex|antigravity|gemini|grok|opencode|all] [--scope effective|bundled|user|project] # show collaboration prompt
tt instructions edit [path] [--user|--project] # edit user or project prompt
tt instructions reset [path] (--user|--project) # delete a user or project prompt
tt release [path] --status TEXT --next-action TEXT # normal handoff
tt pass [path] --status TEXT --next-action TEXT # pass/end your turn
tt assign <target|next> [path] --status TEXT --next-action TEXT # explicit handoff
tt take [path] [--reason TEXT] # human-friendly take/override
tt takeover [path] [--reason TEXT] # alias for take
tt notes add <body> [--turn N] [--path DIR] [--stdin] # leave an async note
tt notes list [--all] [--after ID] [--limit N] [--path DIR] # read notes
tt install <harness...> | --all [--print] [--copy] [--link] [--replace] # install or explicitly replace skill
tt uninstall <harness...|agents> | --all | --shared [--print] # remove skill
tt self-update [--print] [--manager npm|pnpm|yarn|bun] # update to the latest published tt
[path] defaults to the current working directory. Omit it for normal in-repo coordination; pass it only when you intentionally want a different or nested room.
Help flags are always read-only. --help and -h take precedence over command execution, even for stateful commands such as wait, release, assign, notes add, or msg send; they do not join rooms, claim turns, spawn guardians, write events, or update local session state.
tt self-update detects how tt was installed (npm / pnpm / yarn / bun, including npm-via-Homebrew/mise/asdf/nvm) and runs the right global-update command. Pass --print to see the inferred command without running it; pass --manager to override detection. Running tt self-update from a development checkout (where tt resolves outside node_modules/talking-stick) refuses and tells you to git pull && npm install && npm run build instead.
Human CLI commands use a stable identity like human:<username>. When tt wait, tt take, or tt takeover wins the turn, a small background guardian keeps the lease alive on your behalf until you release, pass, or assign it. If that guardian's captured harness process appears gone but the harness has recent tt activity, Talking Stick retains the lease and keeps heartbeating; a process-gone and silent owner is surrendered as harness_gone. Human CLI take intentionally works without a required reason so an operator can step into a stuck room quickly; harness-aware CLI takeovers still require --reason unless the command includes --operator-requested.
By default, tt behaves like a human CLI and resolves to human:<username> only when no harness environment is detected.
Harness-aware CLI identity is resolved before the human fallback:
If no harness signal is present, tt stays on the human CLI path. That keeps ordinary shell usage predictable while preventing harness-launched shells from silently joining rooms as human:<username>.
Use tt whoami --explain to see which identity path the CLI chose.
The coordination database lives at:
Override with TALKING_STICK_DATA_DIR if you want to keep per-project state.
npm install
npm test
npm run typecheck
npm run buildSee CHANGELOG.md for a per-version summary; full release notes live in docs/releases/.
When cutting a release, add entries under CHANGELOG.md's Unreleased section, then run npm version <new-version>. The version lifecycle script moves those entries into the new version section, writes docs/releases/<version>.md, and adds the GitHub release link before npm commits and tags the version.
MIT. See LICENSE.md.
| Back | FazBrowse Home | New Git URL |