Run tweaks generation in background agent jobs with shadow-workspace apply - #94
Open
jamesrochabrun wants to merge 1 commit into
Open
Run tweaks generation in background agent jobs with shadow-workspace apply#94jamesrochabrun wants to merge 1 commit into
jamesrochabrun wants to merge 1 commit into
Conversation
…apply The Tweaks popover's Ideas / describe-a-tweak actions no longer occupy the interactive chat session. They now run as headless one-shot agent jobs (claude runSinglePrompt / codex exec) against a shadow copy of the project under .easel/tweaks/<jobId>/, then auto-apply when safe: - BackgroundAgentJobService (EaselChat): FIFO pipeline with statuses queued -> preparing -> generating -> validating -> waitingToApply -> applying -> applied/conflict/failed, cancel anytime, undo after apply. - Shadow workspace + hash-manifest diff detects exactly what the agent changed; the apply engine backs up real files before atomic writes. - Drift safety: files edited concurrently (chat agent, knob writes) surface a conflict with Regenerate / Apply anyway / Discard; apply waits for in-flight chat turns and re-checks drift before writing. - Providers: Claude and Codex runners in ClaudeCodeCore mirror the interactive runtimes' configuration; the Local/API provider fails gracefully with a send-to-chat fallback until it gains a runner. - UI: floating status pill on the canvas (progress, elapsed, cancel, undo, conflict actions), badge on the Tweaks button, and status row in the popover (Canvas 62c3cce revision pin, 1.4.0 to follow). - Legacy chat path kept as fallback when no coordinator is wired or the preview URL can't be mapped into the project.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The Tweaks popover's Ideas and Describe a tweak… actions previously injected a prompt into the live interactive chat session, blocking the chat for the entire (slow) generation. They now run as background headless agent jobs — the chat stays fully interactive while tweaks generate, with progress, cancel, and undo surfaced on the canvas.
How it works
.easel/tweaks/<jobId>/shadow(ignored by the preview file observers) with a SHA-256 manifest of every file. The agent only ever edits the copy.ClaudeCodeSDK.runSinglePrompt/codex exec) executes against the shadow, configured identically to the interactive runtimes (binary resolution, model, sandbox/permissions, env).dc_set_propsschema (with a changed-files fallback scan for dev-server projects where a component gets instrumented instead ofindex.html).Architecture
BackgroundAgentJobCoordinating(UI surface),BackgroundAgentRunning(runner),BackgroundJobValidating,FileContentHasher, andProjectScanIgnoreList(hoisted from the preview observer so scan scope and apply scope stay in lockstep).ClaudeBackgroundAgentRunner,CodexBackgroundAgentRunner, andCodexClientFactory(extracted fromCodexChatRuntime.makeClient()with a parity test; the runtime now delegates to it).ShadowWorkspaceManager,BackgroundJobApplyEngine, and the@ObservableBackgroundAgentJobService(FIFO, one running job at a time);ChatService.isAnySessionBusy(workingDirectory:)+makeBackgroundJobService(validator:).TweaksSchemaJobValidator(Canvas parser),TweaksJobRequestFactory,BackgroundJobStatusPill, andWebInspectorPreviewViewwiring (badge on the Tweaks button, pill overlay, popover status).TweaksGenerationStatus+ host-driven status row and control-disabling inTweaksPanelView(additive, source-compatible API).Provider behavior
client.cancel();.bypassPermissionsmatching the interactive path.--sandbox workspace-write --full-auto --json, stdin prompt) pointed at the shadow root; cancellation is abandon-and-flag (CodexSDK has no process handle) with the job timeout as kill switch.The legacy chat path is kept as a silent fallback whenever no coordinator is wired or the preview URL can't be mapped into the project — the buttons never go dead.
Dependency note
EaselWebInspectorandEaselPreviewpin Canvas to revision62c3cce(thebackground-tweaks-statusbranch, Canvas repo). Once Canvas1.4.0is tagged, both pins should move toexact: "1.4.0".Validation
swift test), including the newTweaksGenerationStatussuite.CodexClientFactoryprecedence parity, both runners' option construction, activity-event parsing, and error normalization; existing Codex runtime/mapper tests unaffected by themakeClientextraction.xcodebuild -scheme EaselChat-Package) — real-filesystem suites for the shadow manager (ignore-list exclusion, manifest hashing, modified/created/deleted classification, stale sweep) and apply engine (drift, backup+atomic apply, undo, binary round-trip); 19 orchestrator tests with scripted mocks (FIFO, busy-wait→apply, drift→conflict, all three resolutions, cancel queued/running, timeout/failure mapping, retry, undo force semantics, terminal auto-dismiss); plus 3 end-to-end integration tests running the real pipeline on a temp project, including concurrent-edit → conflict → apply-anyway → undo.Easelapp scheme builds; branch is up to date withmain(883b8ff, agent-harness merge) and the new.apiprovider case is handled.62c3cceresolves and builds from GitHub.Remaining manual QA (needs the GUI)
.easel/tweaksswept🤖 Generated with Claude Code