Skip to content

feat(desktop): add a dev-only harness for driving app state without live sessions - #650

Open
charleslpan wants to merge 1 commit into
mainfrom
conductor/dev-harness-for-driving-app-state-locally
Open

feat(desktop): add a dev-only harness for driving app state without live sessions#650
charleslpan wants to merge 1 commit into
mainfrom
conductor/dev-harness-for-driving-app-state-locally

Conversation

@charleslpan

@charleslpancharleslpan commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Adds DevHarness, a Unix-socket control channel constructed only for unpackaged live runs (same gate as AgentTraceWriter), so a packaged build carries nothing to switch off
  • Adds pnpm dev:emit CLI (scripts/dev-emit.mjs) that connects to the socket and sends one JSON command, then exits with ok or an error message
  • Wires the harness into desktop-app.ts after the agent-trace section; session commands feed a synthetic SessionProviderAdapter directly into sessionRegistry, which triggers the full notice/announcement path without any provider; capture commands call an injected callback (logged to stderr on this branch, wirable to CallQuietGate.setCapturing in one line when the call-quiet branch lands)
  • run.sh exports LUKE_DEV_HARNESS_SOCK by default (parallel to LUKE_TRACE_DIR); the CLI defaults to .build/dev-harness.sock relative to repo root so pnpm dev:emit works from any terminal in the repo without extra setup

Testing the call-quiet feature end to end

With the charleslpan/daegu branch merged, wire the capture override in desktop-app.ts:

- onCaptureCommand: (on) =>- process.stderr.write(`[dev-harness] capture override: ${on ? "on" : "off"}\n`),+ onCaptureCommand: (on) => callQuietGate.setCapturing(on),

Then, in one terminal:

./scripts/run.sh # start the app (signs in, enables voice)

In a second terminal:

# Simulate "another app grabbed the mic" — starts the 3 s onset timer
pnpm dev:emit capture on
# 3 s later the gate holds; now push a waiting session — announcement is queued
pnpm dev:emit session waiting
# Confirm it was held (not spoken yet), then release the mic hold
pnpm dev:emit capture off
# 15 s grace expires — announcement speaks; Luke names the waiting dev session

To test that a finished session still announces when the mic is clear:

pnpm dev:emit session finished # speaks immediately if no hold is active

Test plan

  • ./scripts/check.sh clean (lint, typecheck, 848 tests pass, build succeeds)
  • ./scripts/verify.sh — requires macOS; cannot run in this Linux cloud environment. The harness is gated to !app.isPackaged && runMode.sendsNetwork, so fixture and evidence runs are unaffected and visual evidence is unchanged.
  • Manual smoke: ./scripts/run.sh, pnpm dev:emit session waiting → session row appears, announcement fires (requires macOS + signed-in account)
  • Manual smoke: pnpm dev:emit capture on/off[dev-harness] capture override: on/off in stderr (main branch stub)

🤖 Generated with Claude Code


Open workspace in Conductor

Open in Alchemize

Automated visual evidence

Download the deterministic macOS evidence · workflow run

  • Commit: cff16836e36efed3e811b12997e6704bc52715e9
  • Scenario: smoke
  • Physical-notch check: not performed by CI

…ive sessions
A new control channel lets a developer push synthetic session state and
override the input-capture boolean from the command line, without waiting
for a real agent session to finish, error, or stop for permission.
The harness follows the same gate as AgentTraceWriter: it is constructed
only for an unpackaged live run (app.isPackaged false, sendsNetwork true,
LUKE_DEV_HARNESS_SOCK set), so a packaged build carries nothing to switch
off and fixture/evidence runs are unaffected. run.sh sets the socket path
by default, parallel to how it sets LUKE_TRACE_DIR.
pnpm dev:emit session waiting # push a waiting session
pnpm dev:emit session error # push an error session
pnpm dev:emit session finished # push a finished session
pnpm dev:emit capture on # override: another app holds the mic
pnpm dev:emit capture off # override: mic is free
Session commands feed into a synthetic SessionProviderAdapter registered
directly with sessionRegistry, which triggers the full notice/announcement
path — the same real voice call that a live session would. The capture
command calls an onCaptureCommand callback; on this branch it logs to
stderr, and a branch with the call-quiet gate wires it to
CallQuietGate.setCapturing in one line.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@vercel

vercelBot commented Sep 2, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

ProjectDeploymentActionsUpdated
luke-webReadyReadyPreviewSep 2, 2026 11:20pm UTC

Request Review

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@cursorcursorBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit cff1683. Configure here.

}
this.#options.onSessionChanged();
return { ok: true };
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Harness sessions never trigger announcements

High Severity

#applySession installs the requested status as the first observation, so SessionNoticeTracker seeds it silently and never emits a notice. A later waiting observation also has no activity or recap question, so sessionNoticeAnnouncement drops the NEEDS_INPUT path. Completions only speak through reviewSessionAttention, which the harness refresh never starts.

Additional Locations (1)
Fix in CursorFix in Web

Reviewed by Cursor Bugbot for commit cff1683. Configure here.

Sign up for freeto 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

@charleslpan