- Preserved goal-mode tool injection for ordinary explicit tool lists.
- Kept plan-mode LSP and IRC unavailable under the host capability clamp.
- Added regressions for both capability boundaries.
- Added per-invocation task schemas with strict and permissive validation.
- Shared task and eval agent policy, artifacts, isolation, and lifecycle handling.
- Enabled host-restricted plan-mode eval agents and persisted their capability clamp.
Fixes#5279
- Added the `xd://` virtual device protocol (`internal-urls/xd-protocol.ts`, `tools/xdev.ts`): tools declaring `loadMode: "discoverable"` are unmounted from the request tools array and driven via `read xd://` (list/docs+schema) and `write xd://<tool>` (execute), gated by the `tools.xdev` setting (default on) and inlined into the system prompt.
- Merged the `irc`, `job`, and `launch` tools into a single `hub` tool (`tools/hub/`, `async/job-manager.ts`): messaging keeps `send`/`inbox`/`list`, job control maps to `wait`/`cancel`/`jobs`, process supervision keeps `start`/`logs`/`stop`/`restart`/`describe` with `ps`, and the unified `wait` races background jobs against peer messages; SDK `IrcTool`/`JobTool`/`LaunchTool` are replaced by `HubTool`.
- Removed the hidden `resolve` tool in favor of the `xd://resolve`/`xd://reject`/`xd://propose` resolution devices, auto-including `write` whenever a deferrable tool or plan mode is present.
- Removed the BM25 tool-discovery system: the `search_tool_bm25` tool, the `tool-discovery` module, the `tools.discoveryMode`/`mcp.discoveryMode`/`mcp.discoveryDefaultServers`/`tools.essentialOverride` settings, per-tool MCP selection, and the `mcp_tool_selection` message type.
- Unified tool presentation on `ToolLoadMode` (`essential`|`discoverable`), replacing the custom-tool `xdev?: boolean` opt-out; custom, extension, MCP, RPC host, image-generation, and TTS tools now default to `discoverable`, and added a `satisfies` predicate to `SoftToolRequirement`.
- Removed the standalone `ssh` command tool and `ssh/ssh-executor` (the `ssh://` read/write/search protocol stays), and made `--tools` address hidden built-ins.
- Updated collab-web to render `xd://` dispatches and `hub` op families, dropped the `search_tool_bm25`/`ssh`/`report-finding` renderers, refreshed tool docs and prompts, and migrated the affected tests and changelogs.
- Updated prewalk gating in `AgentSession` to key the todo gate on active tools instead of registry presence, so deactivated todo tools no longer block prewalk handoff.
- Changed subprocess tool filtering so `todo` is stripped for normal subagents but retained when prewalk is armed, and propagated the prewalk state through tool-session setup.
- Added regression tests for restricted active-tool slates and prewalk/non-prewalk subagent tool propagation to verify todo is handled correctly in each case.
- Added schema and type updates for task-agent fields and model resolver settings.
- Extended discovery helper logic to carry resolved task-agent metadata through execution setup.
- Updated task/agent registration and execution paths to use the new capability/field data.
- Expanded test coverage for agent-field parsing, model resolution, and executor prewalk behavior.
- Replaced legacy `pi/` role alias prefix with canonical `@` syntax across model resolution, documentation, and tests.
- Added support for bare `*` default alias and multiple alias prefix detection with custom role resolution in `resolveConfiguredRolePattern()`.
- Enhanced thinking suffix parsing to accept unambiguous abbreviations (minimum 2 characters) for effort and level selectors.
- Extended `resolveCliModel()` and `filterAvailableModelsByEnabledPatterns()` to accept settings parameter for role alias resolution from `--model` flag.
- Replaced silent budget-based termination with a graceful stop and forced-yield mechanism.
- Implemented resumable subagent states to preserve agent context upon budget exhaustion.
- Increased default soft request budget to 200 and updated IRC bus signaling to distinguish between active, resumable, and hard-aborted statuses.
- Added comprehensive status-aware prompts and unit tests to verify non-terminal abort behavior.
- Enabled granular task execution by allowing batches to interleave blocking items with non-blocking async background spawns.
- Updated task orchestration to support simultaneous inline result collection and persistent background job tracking.
- Improved agent visibility in the job tool by reporting running subagents even when not explicitly linked to a backing job ID.
- Enhanced terminal state handling to prevent premature tool block closures while async background operations remain active.
- Renamed task wire fields, replacing `assignment` and `description` with `task` and `name` while removing `role` references.
- Implemented automated task UI label generation using a tiny model to replace manual role descriptions.
- Updated task execution and rendering logic to support per-item agent resolution and dynamic badge display.
- Migrated schemas, prompts, and test suites to enforce the new flat task structure and agent-centric policy.
- Centralized task concurrency and delegation logic by moving instructions from individual tool descriptions to the system prompt.
- Introduced conditional system prompt logic to handle model-specific task policies, including support for GPT-5.6.
- Added infrastructure for task concurrency normalization and IRC steering state within the system prompt configuration.
- Refactored prompt inputs and session logic to enable dynamic system prompt updates based on model-specific policy cohorts.
Keep assistant yield tool calls pending until YieldTool.execute returns a successful tool result.
Prevent invalid pre-execution yield arguments from bypassing schema retry handling while still suppressing the soft budget abort during validation.
Fixes#5006
Persist yield tool-call arguments as soon as an assistant turn commits the yield call, before the soft request budget guard can abort the session.
Add a regression covering a yielding turn that crosses the budget threshold without a tool result event.
Fixes#5006
Capture a patch artifact from the live isolation worktree when branch-mode commit transfer fails, before cleanup can destroy the untransferred objects.
Fixes#4437
An intermediate commit whose net effect is already on HEAD (redundant
change, or 3-way merged to HEAD by "theirs == ours") stopped the
sequencer with "The previous cherry-pick is now empty" and was
treated as a hard conflict. mergeTaskBranches aborted the whole range,
marked the branch failed, and dropped every remaining non-overlapping
commit.
Add cherryPick.skip and cherryPick.isEmptyError to the git namespace,
then in mergeTaskBranches' catch classify the failure before aborting:
loop --skip while the error stderr matches the "now empty" phrase so
consecutive empties advance the sequencer; fall through to abort/fail
on the first non-empty error (genuine conflict with unmerged files).
Fixes#4438
- Introduced the `task.softRequestBudgetNotice` boolean setting to opt into budget steering notices.
- Disabled the wrap-up steering notice by default when a subagent crosses its soft request budget.
- Maintained the 1.5x graceful abort safety guard regardless of whether the steering notice option is enabled.
- Updated the settings schema to document the conditional steering notice behavior.
- Ensures in-memory overlay edits are durably written to the plan file before proceeding with approval.
- Avoids asynchronous write races by awaiting the final plan file serialization.
- Aligns synthetic approved-plan prompts with reference-only expectations.
- Implemented safe `releasePermit` helper to track whether a concurrency permit has been acquired before releasing.
- Guarded against double-releasing or releasing unacquired semaphore permits during queued job cancellation or abort events.
- Added comprehensive unit tests validating concurrency cap enforcement when queued jobs are cancelled.
Failed stash-pop cleanup now invokes git clean with literal pathspecs for
stash-derived untracked paths. Filenames such as `:(glob)*` are valid POSIX
filenames and valid Git pathspec magic; passing them as ordinary pathspecs with
`-x` could delete unrelated ignored artifacts that were never stashed and are
not recoverable from the preserved stash.
Extend the fallback regression with a literal `:(glob)*` stash file and an
ignored `build.log` that must survive cleanup.
Fixes#4175
When a task branch adds ignore rules for a path that was untracked in the
user's stashed WIP, a failed stash pop can restore the file and then leave it
hidden from normal status after reset. Default `git clean -fd -- <path>` does
not remove ignored files, so the partial restore could still leak into later
isolated task baselines.
Add an includeIgnored clean mode and use `git clean -fdx -- <stash path>` for
failed stash-pop cleanup. Extend the fallback regression so the task branch adds
.gitignore for the restored untracked path and verify both normal and ignored
status return clean.
Fixes#4175
A failed `git stash pop --index` can restore unrelated untracked files before
exiting on a tracked conflict while still preserving the stash entry. The
previous fallback only reset tracked/index state, leaving those untracked files
in the working tree for subsequent task baselines.
Record the top stash entry's untracked paths before popping and clean exactly
those paths if the pop fails after preflight. Add a regression that forces the
fallback branch and verifies the worktree returns clean with the stash preserved.
Fixes#4175
mergeTaskBranches and applyNestedPatches both stashed dirty WIP, cherry-picked
task branches, then called `git stash pop` in a finally block. On conflict git
left stage 1/2/3 unmerged entries in .git/index with no MERGE_HEAD to abort;
neither call cleaned up. The corrupted index persisted indefinitely, and every
subsequent overlay-isolated task inherited it through the lower layer —
captureRepoDeltaPatch then emitted `diff --cc` (combined merge format) that
git apply rejects with "No valid patches in input", failing every downstream
task merge with 'Branch merge failed before a task branch could be created'.
Fix at the git API level: git.stash.tryPop now runs `git apply --3way --check`
on `git stash show -p --binary stash@{0}` before popping (`--3way` matches
what git stash pop does internally, so context that drifted after cherry-pick
is still accepted). Preflight failure short-circuits — stash entry preserved,
index untouched. Preflight pass falls through to pop; if pop still leaves
unmerged entries (mode-only or delete/modify conflicts the preflight can miss),
a `reset --hard HEAD" fallback restores the merged HEAD without losing the
cherry-picked commits (stash is preserved by git on failed pop, so the user's
WIP stays recoverable).
Both call sites now share this contract via git.stash.tryPop.
Fixes#4175
Tracking raw agent-commit count meant an agent that committed only its
inherited baseline WIP (via `git add -A`) then left the real edit
uncommitted collapsed every filtered patch to empty, so tmpDir never
advanced past baselineSha yet the leftover path assumed it had.
replayFilteredAgentCommits now counts filtered commits actually applied
and, when zero landed, bypasses the finalFilteredTree/leftoverPatch
synthesis entirely — writeSyntheticTree(HEAD, [rootPatch]) fails hard
whenever rootPatch has HEAD+WIP context for a file missing from HEAD's
index (untracked / staged-new WIP). Instead, commit rootPatch directly
with WIP seed, matching the no-agent-commit path.
Added regression test covering the reviewer's scenario.
captureRepoDeltaPatch records the delta against `HEAD + WIP`, so the
patch's context lines and blob SHAs reference the WIP-modified files.
commitPatchToBranchWorktree then tried to apply that patch to a fresh
worktree pinned at HEAD, which failed hard whenever the WIP-side file
was missing from HEAD's index (untracked WIP files, staged-new WIP
files) or when --3way could not resolve an overlap.
commitPatchToBranchWorktree now tries plain apply first, then `--3way`
(which cleanly subtracts WIP via the shared ODB blob for tracked files),
and only when both fail replays baseline WIP into the temp worktree so
the delta's context lines up, rewinding WIP-only files afterward so
they never leak into the branch commit.
Added git.ls.tree helper for the WIP-only-file filter and a set of
regression tests covering the untracked, staged-new, and overlap
scenarios.
Fixes#4136
Reverse-check alone can theoretically succeed via git-apply fuzz when the file carries the postimage at another location, so treating it as sufficient risked silently dropping a task patch whose intended hunk still needed to run.
Required both `--reverse --check` to succeed AND forward `--check` to fail before declaring a no-op. When both check directions succeed (ambiguous), the merge falls through to a forward apply instead of skipping — mirroring the pre-idempotence behavior. Both checks are read-only, so no worktree writes on ambiguity.
Added a spy-based regression that forces the ambiguous case and asserts the merge applies forward instead of silently dropping the change.
git apply --3way --check exits 0 even when the real apply would write conflict markers and unmerged index stages, so the previous fix left the worktree dirty on conflicting patches while only flipping changesApplied to false.
Dropped --3way for patch-mode merge and used a --reverse --check probe instead: it succeeds only when the target state is already present (true no-op) and reads without touching the worktree. Conflicts fall through to the normal --check + apply path, which rejects them before writing anything.
Added regression coverage for the conflict scenario asserting the worktree stays clean, and for the fresh apply path.
Use git apply --3way for patch-mode isolated merge checks and applies so diff-tree patches that are already present are accepted as no-ops.
Added regression coverage for a clean already-applied binary/full-index patch.
Fixes#4135
When a batched task spawn is cancelled while still queued behind task.maxConcurrency the semaphore now rejects acquire(), but the previous patch let the abort throw past the aborted handler so progress.status and onSettled never fired and buildAsyncDetails kept reporting the batch as running. The wrapper now records whether the slot was held, funnels both acquire-time and post-acquire aborts through the same aborted branch (releasing only when held), and a batch regression test pins the contract.
Fixes#3930
discoverAgents sorted the listOmpExtensionRoots result by level, which
demoted CLI-injected roots (hard-coded level user) below any project
extensions: settings entry. The sibling skills/hooks/tools surface in
discovery/omp-plugins.ts consumes the returned order verbatim, so an
explicit --extension override could run a different agent than the rest
of its own plugin surface.
Drop the sort and append roots in returned order. Refresh the
discoverAgents doc comment to document the source-precedence chain (CLI
> project settings > user settings > installed plugins) and add a
regression test where a CLI-injected extension wins over a project
extensions: settings extension that defines the same agent name.
Fixes#3920
Gate the OMP extension-package agents/ scan on the omp-plugins provider so
disabledProviders suppresses plugin-shipped task agents consistently with
other extension-package surfaces.
Add a regression test covering an installed npm plugin with agents/ while
omp-plugins is disabled.
Fixes#3920