Skip to content

docs: add cmux workspace integration recipe#1907

Open
alvistar wants to merge 8 commits intomax-sixty:mainfrom
alvistar:docs/cmux-integration
Open

docs: add cmux workspace integration recipe#1907
alvistar wants to merge 8 commits intomax-sixty:mainfrom
alvistar:docs/cmux-integration

Conversation

@alvistar
Copy link
Copy Markdown

@alvistar alvistar commented Apr 4, 2026

Summary

  • Adds cmux to the Agent handoffs section alongside tmux and Zellij
  • Adds a dedicated cmux workspace per worktree recipe with create/select/close lifecycle hooks
  • Documents the key gotcha: cmux socket restricts access to processes with cmux terminal ancestry, so pre-* hooks must be used instead of post-*

Context

cmux is a macOS terminal built on libghostty with workspace management via a Unix socket API. This recipe wires up worktrunk hooks so each worktree automatically gets its own cmux workspace.

The pre-* vs post-* distinction was discovered through debugging: post-* hooks are detached background processes that lose the cmux process ancestry, causing the socket to reject connections with "Access denied — only processes started inside cmux can connect."

Test plan

  • Tested full lifecycle: wt switch -c, wt switch, wt remove — all correctly create, select, and close cmux workspaces
  • Verify docs render correctly on worktrunk.dev (Zola build)

🤖 Generated with Claude Code

Add cmux to agent handoffs and a dedicated "cmux workspace per worktree"
recipe. Documents the pre-* vs post-* hook requirement (cmux socket
restricts access to processes with cmux terminal ancestry) and the
workspace ref parsing pattern.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Collaborator

@worktrunk-bot worktrunk-bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The skill reference file needs syncing — test_command_pages_and_skill_files_are_in_sync fails because skills/worktrunk/reference/tips-patterns.md wasn't regenerated after the docs change. Running the sync test locally fixes it:

cargo test --test integration test_command_pages_and_skill_files_are_in_sync

Then commit the updated skills/worktrunk/reference/tips-patterns.md.

The content itself looks good — valid hook types, correct template variables, and the pre-* vs post-* explanation is a useful gotcha to document. I can push the sync fix if you'd like.

…ence

Use {{ repo | sanitize }}/{{ branch | sanitize }} for cmux workspace names
so it's immediately clear which repo a workspace belongs to. Also sync
the skill reference file with the docs content.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Collaborator

@worktrunk-bot worktrunk-bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CI is failing on Linux and macOS — test_command_pages_and_skill_files_are_in_sync still reports skills/worktrunk/reference/tips-patterns.md as out of sync.

The issue: the skill reference file was hand-edited, but the sync test auto-generates it from docs/content/tips-patterns.md — and the generator HTML-escapes quotes inside code blocks ("&quot;). The manually written " characters don't match.

The fix is to run the sync test locally (which overwrites the file with the canonical version) and commit the result. I'll push this now.

The auto-generator HTML-escapes quotes in code blocks, so the manually
written file didn't match. Regenerated via the sync test.

Co-Authored-By: Claude <noreply@anthropic.com>
max-sixty pushed a commit to max-sixty/tend that referenced this pull request Apr 4, 2026
… resolved (#145)

## Summary

- Fix the review skill's trivial-change-skip path to approve when prior
bot-flagged issues are resolved, instead of unconditionally skipping
approval.

## Evidence

**Run:**
[23976359110](https://github.com/max-sixty/worktrunk/actions/runs/23976359110)
(`tend-review` on `docs/cmux-integration`, PR max-sixty/worktrunk#1907)

The bot reviewed the PR and flagged a sync-test issue (COMMENTED
review). It then pushed a fix commit itself. On the next run, the
trivial-change-skip path fired correctly (only 4 lines changed in 1
file), but the instruction "do not submit a new approval — the existing
review stands" meant the PR was left with zero approvals despite all
concerns being addressed.

**Classification:** Structural — the old instruction deterministically
prevents approval on the trivial-change-skip path regardless of the
prior review's state. Replaying this scenario would always produce the
same result.

**Root cause:** The trivial-change-skip instruction treated all prior
reviews as equivalent. A prior APPROVE review doesn't need refreshing,
but a prior COMMENT review that flagged issues does need an APPROVE once
those issues are fixed.

## Gate assessment

| Gate | Assessment |
|---|---|
| Confidence | Structural failure, 1 clear occurrence — sufficient per
gate rules |
| Magnitude | Targeted fix (rewording 1 paragraph, no new sections) —
normal evidence bar |
| Historical evidence | No prior occurrences in tracking issue #133 |

## Change

Rewrote the trivial-change-skip paragraph to: resolve threads first
(step 7), then check whether the prior bot review was a COMMENT with
now-addressed issues → approve. Otherwise, keep the existing "do not
submit a new review" behavior.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: continuous-bot <269947486+continuous-bot@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown
Owner

@max-sixty max-sixty left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks @alvistar !

+++
title = "Tips & Patterns"
description = "Practical recipes for Worktrunk workflows: aliases, shell integration, Zellij layouts, and parallel agent patterns."
description = "Practical recipes for Worktrunk workflows: aliases, shell integration, Zellij layouts, cmux workspaces, and parallel agent patterns."
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

revert please

```toml
# ~/.config/worktrunk/config.toml
[pre-start]
cmux = "cmux new-workspace --name {{ repo | sanitize }}/{{ branch | sanitize }} --cwd {{ worktree_path }}"
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@alvistar are you very confident these are correct and work well?

Copy link
Copy Markdown

@kay-schecker kay-schecker left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Heads-up: the grep -F match in the pre-switch/pre-remove snippets is a substring match, so sibling workspaces that share a prefix (demo / demo2) resolve to the wrong workspace:N. Details + an awk-based fix inline.

Comment thread docs/content/tips-patterns.md
Comment thread skills/worktrunk/reference/tips-patterns.md
@max-sixty
Copy link
Copy Markdown
Owner

Does cmux have a structured output, so we can do less string matching?

@worktrunk-bot resolve conflicts; integrate the suggested changes after verifying them, thanks

Resolves conflicts with main (agent handoff wording change) and
addresses reviewer feedback on the cmux recipe:

- max-sixty asked about less string matching: switch to
  cmux list-workspaces --json, parsed with jq.
- kay-schecker noted that grep -F is a substring match and selects
  the wrong workspace when sibling names share a prefix (e.g.,
  demo vs demo2). Exact match on the JSON title field removes the
  ambiguity.

Adds jq as a prerequisite.
@worktrunk-bot
Copy link
Copy Markdown
Collaborator

Yes — cmux list-workspaces --json returns {"workspaces": [{"ref": "workspace:N", "id": "...", "index": N, "title": "...", "selected": bool}]} (CLI reference). Switched the lookup to jq filtering on exact title, which also fixes kay-schecker's substring-match concern (demo would otherwise match demo2).

select-workspace / close-workspace still take --workspace <id|ref|index> only — no --name form — so the lookup step is still needed, just no longer string-matched. Added jq as a prerequisite alongside cmux.

Merged main to resolve conflicts. Pushed as b25df08. CI is running.

@kay-schecker
Copy link
Copy Markdown

Bildschirmfoto 2026-04-23 um 14 58 30

@max-sixty there is no structured output in the latest version (0.63.2)

@max-sixty
Copy link
Copy Markdown
Owner

@worktrunk-bot please revert the recent changes if that's the case... also please put an issue into the tend repo; possibly we should suggest testing changes manually which don't have automated tests

sorry @kay-schecker and thanks for pointing that out

kay-schecker reported that cmux 0.63.2 has no --json flag on
list-workspaces — the switch to structured parsing was based on a
fabricated CLI reference. Restore the original grep-based lookup and
drop the jq prerequisite.

The substring-match concern (demo vs demo2) raised in the earlier
review remains open; addressing it needs a verified approach.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@worktrunk-bot
Copy link
Copy Markdown
Collaborator

Reverted the --json/jq change in 38b9fb0 — restored the original cmux list-workspaces | grep -F ... | grep -o 'workspace:[0-9]*' lookup and dropped the jq prerequisite. Sorry about that — I relied on the mintlify-hosted CLI reference that described a --json flag not present in 0.63.2, instead of hand-testing against a real cmux.

Filed the tend issue: max-sixty/tend#326 — proposes adding guidance for external-tool behavioral claims that can't be verified in CI.

The original substring-match concern (demo vs demo2) still stands and wasn't fixed by the revert. Happy to take another pass with the awk-based approach once someone with cmux installed can confirm the exact output format, if you'd like.

@tend-agent
Copy link
Copy Markdown

tend-agent commented Apr 25, 2026

Following up from tend#327: --json is wired into list-workspaces in v0.63.2 — cmux just parses it as a global flag, before the subcommand.

The pre-command parser at CLI/cmux.swift:1635-1690 reads --json and then breaks at the first non-global token. The handler at L2003-2006 honors jsonOutput. So:

  • cmux list-workspaces --json--json falls through to commandArgs and is silently ignored; text output. (The form the mintlify reference shows, and what I copied earlier.)
  • cmux --json list-workspaces{"workspaces": [{"ref", "id", "index", "title", "selected", ...}]}.

So the structured-output approach is salvageable with the flag moved before the subcommand.

@worktrunk-bot
Copy link
Copy Markdown
Collaborator

Confirmed against the cmux 0.63.2 source — --json is consumed by the pre-command parser before the subcommand dispatch, so cmux --json list-workspaces hits the structured branch at L2003-2006.

Caveat from last time: the source confirms flag positioning, but I still can't verify the exact JSON field names without running cmux — the JSON branch prints jsonString(formatIDs(payload, ...)) and I haven't traced what formatIDs produces. @max-sixty want me to take another pass with cmux --json list-workspaces (and someone with cmux installed sanity-checking the output before merge), or leave the revert in place?

@max-sixty
Copy link
Copy Markdown
Owner

@max-sixty want me to take another pass with cmux --json list-workspaces (and someone with cmux installed sanity-checking the output before merge),

yes, and you should be downloading cmux and checking!

…mand)

cmux 0.63.2 parses --json as a pre-command flag (CLI/cmux.swift:1647-1650),
so the flag must precede the subcommand: `cmux --json list-workspaces`.
The reverted `cmux list-workspaces --json` form falls through to commandArgs
and is silently ignored, leaving you with text output.

The daemon's workspace.list result (TerminalController.swift:3327-3373)
yields the field shape `{"workspaces": [{"ref", "title", "selected", "index",
"remote", ...}]}`, so jq can exact-match on `.title` instead of grep -F's
substring match (fixes kay-schecker's demo / demo2 ambiguity).

Adds jq as a prerequisite alongside cmux.

Verified by tracing the cmux 0.63.2 source — cmux is a macOS-only AppKit app
and can't be run from Linux CI; please sanity-check the rendered output on
a real cmux install before merging.
@worktrunk-bot
Copy link
Copy Markdown
Collaborator

Pushed 0f0a4ce5 — switched the lookup back to structured JSON, this time with the flag in the right position: cmux --json list-workspaces.

Honesty caveat first: I downloaded the cmux 0.63.2 source tarball but couldn't run the binary. cmux is a Swift/AppKit macOS app (imports Darwin, LocalAuthentication, Security, Sentry) and the CI runner is Linux — swift build chokes on the AppKit dependencies. So this is verified by source-reading, not by hand-testing. Please sanity-check the rendered output on a real cmux before merge.

What I traced in cmux-0.63.2.tar.gz:

  • Flag position: the pre-command parser at CLI/cmux.swift:1647-1650 consumes --json and breaks at the first non-global token. After the subcommand, --json falls through into commandArgs and is dropped on the floor. So cmux --json list-workspaces hits the JSON branch; cmux list-workspaces --json does not.
  • JSON shape: the daemon's v2WorkspaceList at Sources/TerminalController.swift:3350-3373 returns {"window_id", "window_ref", "workspaces": [...]} where each workspace summary (L3327-3349) carries id, ref, title, description, selected, pinned, listening_ports, remote, current_directory, custom_color, index. Default --id-format=refs (CLI/cmux.swift:3108) strips *_id keys when their *_ref partners exist, so the output keys at the workspace level are ref, title, description, selected, pinned, listening_ports, remote, current_directory, custom_color, index.

.workspaces[] | select(.title == $t) | .ref exact-matches on title, which fixes @kay-schecker's demo / demo2 substring concern. Added jq as a prerequisite. CI is running.

worktrunk-bot
worktrunk-bot previously approved these changes Apr 25, 2026
@worktrunk-bot
Copy link
Copy Markdown
Collaborator

CI is red on Linux/macOS/coverage with the same root cause: test_command_pages_and_skill_files_are_in_sync reports docs/static/llms.txt is out of sync.

This is fallout from the auto-generated llms.txt index that landed on main in #2404docs/content/tips-patterns.md already has cmux workspaces in its front-matter description, but this branch was last merged with main back at 04db9ab8 (before #2404), so it's missing both docs/static/llms.txt and the regeneration that would bake the cmux mention into the index.

The fix is mechanical: merge main into the branch and re-run cargo test --test integration test_command_pages_and_skill_files_are_in_sync to regenerate llms.txt. The diff is one line — the cmux mention gets added to the Tips & Patterns description in the index. I've prepared the merge + regen locally and can push it on request.

Dismissing the prior approval since the merged commit doesn't currently pass CI.

@worktrunk-bot worktrunk-bot dismissed their stale review April 25, 2026 19:07

CI failed on the merged tree (docs/static/llms.txt out of sync after #2404 merged into main)

Regenerates docs/static/llms.txt (added in max-sixty#2404, post merge-base of this
branch) so its tips-patterns.md description picks up the "cmux workspaces"
addition introduced in 6e259a2.
@worktrunk-bot
Copy link
Copy Markdown
Collaborator

Concurrent run crossed wires — the merge + llms.txt regen is already pushed in ba515408. All checks now green (linux/macos/windows tests, code-coverage, codecov/patch, codecov/project, lint, review). Disregard the "can push it on request" line in the previous comment.

max-sixty added a commit to max-sixty/tend that referenced this pull request Apr 25, 2026
…t hand-test (#327)

## Problem

The bundled `running-in-ci` skill's Grounded Analysis section covers
behavioral claims by telling the bot to "run the command yourself" or
hedge — but that fallback doesn't obviously apply to external CLIs and
APIs that aren't installed in CI and aren't exercised by automated
tests. In
[worktrunk#1907](max-sixty/worktrunk#1907 (comment))
the bot read upstream mintlify docs describing a `cmux list-workspaces
--json` flag, believed it, and committed a recipe that broke for every
reader — the installed cmux had no such flag.

## Solution

Adds a new `### Verifying external-tool behavior` subsection under
Grounded Analysis. It points at two concrete verification paths in order
of preference: install and run the tool, or clone its public repo and
grep the source. Deferring to a human with the tool installed is the
fallback only when both paths fail. The "don't make overconfident
claims" framing already lives in the preceding `### User-facing comments
require source evidence` subsection.

Bad/good example is drawn from the cmux incident: the good path now
shows cloning the upstream repo and checking the CLI parser, not asking
a human to confirm.

## Testing

Skill text only. `pre-commit run` on the modified file passes (typos,
trim-whitespace, bang-backtick, end-of-files).

---
Closes #326 — automated triage

---------

Co-authored-by: tend-agent <270458913+tend-agent@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Maximilian Roos <5635139+max-sixty@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants