Skip to content

Support dirty state and cancellation confirmation in command wizards - #153

Draft
Oleg-Melnik wants to merge 8 commits into
masterfrom
wizard-dirty-state-and-cancellation
Draft

Support dirty state and cancellation confirmation in command wizards#153
Oleg-Melnik wants to merge 8 commits into
masterfrom
wizard-dirty-state-and-cancellation

Conversation

@Oleg-Melnik

@Oleg-Melnik Oleg-Melnik commented Jul 31, 2026

Copy link
Copy Markdown
Collaborator

Summary

CommandDialog exposes its form's dirty state and can guard cancellation,
but CommandWizard had no equivalent. Wizard.onCloseRequest also fired
both when the user cancelled and after a successful submission, so a wizard
host could not confirm discarding entered data without also prompting once
the command had posted.

This separates the two close paths rather than having onCloseRequest tell
them apart, and exposes the wizard's aggregate dirty state so a host can
implement discard confirmation without inspecting wizard internals.

Changes

  • Wizard gains onBeforeCancel, a suspending guard returning whether to
    proceed with closing, and cancel(), which the "Cancel" button now calls.
    The guard logic sits in requestCancel().
  • The submission path continues to call close() directly, so it never
    reaches the guard. close() and onCloseRequest are behaviourally
    unchanged, and existing hosts keep working.
  • Entered data survives a pending confirmation: the wizard stays in
    composition until the guard resolves.
  • CommandWizard gains dirty, backed by the single CommandMessageForm
    spanning every page, so the value covers pages the user has navigated away
    from.
  • client/README.md documents the host-side pattern.

Public API additions are additive only: Wizard.onBeforeCancel,
Wizard.cancel(), and CommandWizard.dirty. No existing signature, name, or
visibility changed.

Fixes #148

Oleg-Melnik and others added 8 commits July 31, 2026 19:20
Two agents work one GitHub issue through a shared Markdown document: one
plans and implements, the other reviews the plan before any code is written
and the resulting diff afterwards. The issue is the only accepted input, so
the reviewer checks the work against acceptance criteria that neither agent
wrote.

The driver invokes whichever agent owns the turn, keeps a transcript per
turn, and validates each transition against the protocol. Neither agent may
change Git state; the driver compares refs and the index after every turn and
aborts on any difference. Opening a pull request is opt-in, performed by the
driver after a finished run.

Both agent commands keep their CLI approval and sandbox boundaries by
default, and a command containing a known bypass flag is refused unless the
caller confirms an external isolation boundary.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Codex's `workspace-write` sandbox excludes gitignored paths from its
writable set, and `.agents/work/` is gitignored by design — the working
document is a scratch artifact that is never committed. `agent2` could
therefore read the document but not write its review into it, and every
run aborted with "agent2 did not modify ... plan.md".

Name the work root with `--add-dir` in the default `AGENT2_CMD`. This
widens the sandbox by exactly one directory inside the repository, and
`unsafe_agent_roles()` does not classify it as a bypass flag, so the
approval and sandbox boundaries are otherwise unchanged.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
`pair.sh` runs `agent1` with `--setting-sources project`, which loads
`.claude/settings.json` only. That file did not exist, so every Gradle and
`java` invocation was refused with "This command requires approval", and
the agent handed off an implementation it had never compiled. `agent2`
then had to spend its review round on that fact instead of on the code.

Allow the verification commands `AGENTS.md` prescribes — module `test`,
`check`, `compileKotlin`, `detekt`, the license-report tasks, the local
publishing tasks, and the JDK checks — plus the read-only `gh` commands
the agents use to inspect issues and pull requests.

Publishing tasks (`publish`, `publishCodegenPlugins`) are deliberately
absent: `AGENTS.md` reserves those for CI.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Four failures showed up in one run of issue #148, none of them in the
protocol itself. Each is addressed where it belongs.

The Git tripwire accused the agent. It compares two snapshots taken around
a turn and cannot see who moved between them, so a user switching branches
mid-run produced "agent2 wrote to Git". Report the movement, name the
innocent cause, and leave attribution to the reader. The skill and the run
guide now say the guard cannot attribute, and the guide asks the user not
to touch Git while a run is live.

A turn that died immediately said only that the agent exited non-zero. The
two things that actually fail first — a CLI on `PATH` but not signed in,
and a model identifier only the API rejects — are now named in that
message, and the run guide separates being on `PATH` from being
authenticated.

Verification could report green from cache. When every compile and test
task is `UP-TO-DATE`, `BUILD SUCCESSFUL` describes an earlier build, not
the change in the worktree. The tester skill now requires reading the task
list and forcing the work with `--rerun-tasks` before calling a result
green.

Finally, record why `--add-dir` and `.claude/settings.json` are
load-bearing, in the protocol and in the guide, so neither is dropped by
someone overriding an agent command.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Both fixes in this branch live in configuration rather than in the driver's
logic, so nothing failed when they were wrong until a turn was already
running — several minutes in, with a message about the symptom. These
assert them directly.

`--add-dir` is read out of the `AGENT2_CMD` assignment rather than from the
usage output, which describes the flag in prose: matching that text passed
even with the flag deleted from the default that actually runs. The
companion check asserts `.agents/work` really is gitignored, which is the
reason the flag is needed at all.

The `.claude/settings.json` checks cover the file agent1 loads under
`--setting-sources project` and the verification tasks it must allow.
Without them agent1 hands off an implementation it never compiled.

Each check was confirmed to fail when the thing it guards is removed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
`CommandDialog` exposes its form's dirty state and can guard cancellation,
but `CommandWizard` had no equivalent. `Wizard.onCloseRequest` also fired
both when the user cancelled and after a successful submission, so a host
could not confirm discarding entered data without also prompting once the
command had posted.

Separate the two paths instead of having `onCloseRequest` tell them apart.
`Wizard` gains `onBeforeCancel`, a suspending guard returning whether to
proceed, and `cancel()`, which the "Cancel" button now calls; the guard
logic sits in `requestCancel()` so a unit test can drive it outside
composition. The submission path still calls `close()` directly and never
reaches the guard, and `close()` and `onCloseRequest` are unchanged, so
existing hosts keep working. Entered data survives a pending confirmation
because the wizard stays in composition until the guard resolves.

`CommandWizard` gains `dirty`, backed by the single `CommandMessageForm`
spanning every page, so the value covers pages the user has left.

All additions are additive: no existing signature, name, or visibility
changed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@Oleg-Melnik Oleg-Melnik self-assigned this Jul 31, 2026
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.

Support dirty state and cancellation confirmation in command wizards

1 participant