Skip to content

fix(vibe): Cut setup friction and repeated questions in vibe sessions - #292

Merged
shafty023 merged 4 commits into
mainfrom
fix/vibe-session-friction
Oct 15, 2026
Merged

shafty023 merged 4 commits into
mainfrom
fix/vibe-session-friction

Conversation

@shafty023

@shafty023 shafty023 commented Oct 15, 2026 •

Copy link
Copy Markdown
Collaborator

A product manager's $vibe session in Claude Code spent about 15 of its first 19 minutes on setup, asked the page-wording question three times, put her email in as a company name, and showed her engineering words (operator ruling, 2026-10-15). This fixes what the plugin owns and says what it doesn't.

  • Launcher root. The orchestrator passed agentRoot: <root>/agents, so claude-worker.mjs looked for <root>/agents/agents/... and every launch failed with a generic WORKER_TURN_FAILED. The launcher now binds its own installed plugin root when agentRoot is left out, reads <root>/agents as <root>, keeps a resumed writer on its recorded root, and refuses another release's root (STALE_PLUGIN_ROOT). writer-state.mjs register and acquire-record resolve the root the same way for Codex.
  • Expired sign-in. The child claude failed with "OAuth session expired". The launcher now asks claude auth status (from the home folder) before any writer state changes and classifies a sign-in the CLI rejects at start; both return CLAUDE_SIGN_IN_NEEDED with one plain step: claude auth login in the Terminal app. The Claude preflight reports the same as claude-login. Nothing tells the person to run claude /login any more, which started a full Claude session in her repo that printed the permission-rule dump and the project MCP prompt.
  • Worker tools. The ticket worker was dispatched through the native Agent tool, which gives a plugin agent only its listed built-ins, so it had no ClosedLoop tools and came back BLOCKED; the verify worker likewise could not reach the graph. The skill now says every Claude worker launches through the launcher with the exact JSON (no agentRoot), the launcher refuses a requirements or ticket launch without its ClosedLoop reads (MISSING_CAPABILITIES), and it stops a worker as soon as its own start event shows a granted connection did not load, before it does any work (MCP_TOOLS_MISSING).
  • Portable time limit. No plugin file used timeout; the verify worker and the orchestrator improvised it and macOS has none. New scripts/run-bounded.mjs <seconds> <command> stops the command and its children and exits 124. The skill, setup and verify workers point to it, and a contract test fails on any timeout <n> in the plugin.
  • Questions asked once. The wording question was restated in each later message while it waited. scripts/session-questions.mjs records every question and answer on the session (pre-session answers move onto it at new), and the skill asks only for a key never asked, never repeats a waiting one, and briefs every worker, relaunch and resumed conversation with the recorded answers.
  • Sample data. The question goes through the existing necessity gate (only for requests about a new, empty account), uses plain words, and never names a company after the person's email.
  • Plain words. references/plain-words.md is the one banned-terms list with replacements, referenced by both skills and the setup worker, and aligned with fix(vibe): End sessions with a PR or a plain pass-on #291's approved ending words. Setup, progress, the component-gallery notice, sample-data and error messages use it.

Outside the plugin:

  • The stage seed names the example org <email> Co (symphony-alpha apps/api/app/preview-schemas/vibe-environment/service/seed-load.ts:115, from an earlier ruling); the dispatch has no org-name input, so the plugin can only stop saying it.
  • The dark-mode preview was an improvised static copy shown in the host's browser pane; the page's own CSS and logo follow prefers-color-scheme, so neither the plugin nor the product page caused it.
  • The Node fix took about 30 seconds; Claude Code keeps the PATH it started with, so the orchestrator had to prefix later commands.

Tests:

  • Launcher (vitest, claude-worker-preflight.test.ts): root resolution, stale root, Codex register, signed out, expired at start, missing connection, missing reads. 9 of 10 fail on 1.0.39 (the tenth unit-tests the new resolver).
  • Node: run-bounded, session-questions (including relaunch and pre-session adoption) and the Claude preflight check; none can pass on 1.0.39.
  • Contract: test_vibe_session_friction_contract.py, 7 tests, all fail on 1.0.39. One pinned string in test_vibe_no_plugin_changes_contract.py moves from "with the session slug" to naming the work by its summary.
  • Evals: 7 new exec-/pm- cases (tags setup, sample-data, questions). Scores in a comment below.

Bumps vibe to 1.0.41 (both manifests; 1.0.40 is claimed by the visual-cues change) with a CHANGELOG entry.

Bind Claude workers to the installed plugin root, check the Claude sign-in
and each worker's granted connections before work starts, record every
question and answer on the session, add a portable time limit for macOS,
and keep person-facing text in plain words from one shared list.
Take 1.0.41, relay any expired Claude sign-in with the preflight's
claude auth login step, keep the ending vocabulary from #291 in the
plain words list, and add the setup, sample-data and question eval
cases for both personas.
@shafty023

Copy link
Copy Markdown
Collaborator Author

claude plugin eval scores for the seven new cases, run from plugins/ with --eval-dir vibe/evals --model sonnet --runs 2 --ablation none --tag setup --tag sample-data --tag questions. "Previous" is 1.0.39 (main at 2f98737) with the same case files copied in.

Case This branch 1.0.39
exec-sign-in-expired-is-one-plain-step 1.00 0.60 (relays claude /login)
pm-sign-in-expired-is-one-plain-step 1.00 0.42 (relays claude /login, repeats the waiting question)
exec-sample-data-question-is-plain 1.00 0.60 (email used as the company name)
pm-sample-data-question-is-plain 1.00 0.60 (email used as the company name)
pm-sample-data-not-asked-for-a-restyle 1.00 0.25 (asks it anyway)
exec-pending-question-not-repeated 1.00 0.50 (repeats the waiting question)
pm-answered-question-not-asked-again 1.00 1.00
Overall 1.00, 14/14 runs pass 0.57, 2/14 runs pass

The last case does not discriminate: 1.0.39 also keeps quiet when the recorded answer is in the prompt. Cost was about $2 per arm. CI does not run the suite.

…ection test

The brief is piped at spawn, so on Linux the fixture can record it before
the launcher stops the worker. Assert the process is gone instead.
@shafty023
shafty023 merged commit e81a183 into main Oct 15, 2026
10 checks passed
@shafty023
shafty023 deleted the fix/vibe-session-friction branch October 15, 2026 21:28
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.

1 participant