Visitar URL original
feat(core): report subagent results to the parent every time a child goes idle by jlongster · Pull Request #63209 · anomalyco/opencode · GitHub
Skip to content

feat(core): report subagent results to the parent every time a child goes idle - #63209

Merged
jlongster merged 9 commits into
devfrom
subagent-idle-report
Nov 11, 2026
Merged

jlongster merged 9 commits into
devfrom
subagent-idle-report

Conversation

@jlongster

@jlongster jlongster commented Nov 10, 2026 •

Copy link
Copy Markdown
Contributor

A subagent now reports to its parent every time it goes idle, not only when the tool's job ends.
Today only the subagent tool's one-shot observer reports, once, when the job it started finishes. A child you type into directly, a child the parent prompts again, or a child woken by its own background shell finishes with nobody listening (#48826).

Explainer with interactive diagrams (playground, crash scrubber, race lab): https://jamesbox.exe.xyz/artifacts/report-on-idle/

❌ Before

  • One <subagent> message per tool job, from SubagentJob.notify.
  • Later busy periods of the child are never reported.
  • A background child that goes idle while its shell runs reports its partial answer, and the final answer is dropped.

✅ After

  • Session core reports at the end of every busy period of a child (coordinator.settled), whoever started it. The tool's observer is deleted, so there is one live sender.
  • If background work is still running, the report goes out now with a Background work still running: list; when that work wakes the child, its next idle reports again.
  • The reported answer is bounded to the busy period: the newest completed, error-free assistant message with seq > startedSeq (SessionStore.lastAssistantAfter). A busy period with no new answer (compaction, move, empty wake) sends nothing.
  • Foreground calls still return inline and get no duplicate message (Job.prepareSubagentReport classifies foreground / background / none atomically; a settling guard refuses a late Ctrl+B).
  • notify: false on the subagent tool silences a child. It is stored as the subagent.notify metadata key, is not inherited by children or forks, and follow-ups keep the current setting unless notify is passed.
- subagent tool job ends -> observer -> one <subagent> message
+ any busy period of a child ends -> settle hook -> one <subagent> message (+ still-running list)

🗄️ Durability, no migration: the report is written as a finished job table row (the outbox) inside the same BEGIN IMMEDIATE transaction that records the child going idle (Bus.publish commit hook), then delivered after commit: SessionInbox.admit → completeBackground → wake the parent. A crash after the commit replays the row on boot with no model turn. A crash before it leaves the child claimed; restart resumes it when it still has a running subagent job row (a busy period started by a direct prompt or a shell wake after the job was acknowledged is not resumed, same as on dev). Restart delivery errors are logged and skipped instead of orDie, and resumed children start only after suspended roots count their attempt.

🚩 Flag: none. We're shipping this as the new behavior.

📊 Proof

  • packages/core full suite (rebased on latest dev): 7093 pass, 354 skip, 3 fail (environmental only: ShellParse under root, util.flock ×2).
  • New subagent-idle-e2e.test.ts (real tool, shell, execution and restart over a shared SQLite file): shell wake → exactly 2 reports; direct prompts; background follow-ups; nested one level at a time; silent middle; crash after commit replays once with no model turn; crash mid-turn resumes and reports once; parent/child deletion mid-run. 3 consecutive clean runs.
  • subagent-report.test.ts, job.test.ts, session-execution.test.ts, tool-subagent.test.ts cover the outbox, guards, restart replay and tool wiring. packages/cli: 387 pass. packages/server: 125 pass (2 timeouts pass when rerun alone).

👀 Read: packages/core/src/session/execution/subagent-report.ts (the commit step must stay plain SQL: it runs inside BEGIN IMMEDIATE, and taking Job's SynchronizedRef there would deadlock against Job writes), then job.ts (prepareSubagentReport, settling / consumed / reported, recordSubagentReport) and execution/restart.ts.

Supersedes the reporting part of #61833. #62035's default flip lands separately as a stacked PR on top of this one.

Visual

<svg xmlns="http://www.w3.org/2000/svg" width="240" height="72" viewBox="0 0 240 72" fill="none" stroke="currentColor">
  <style>
    .p{animation:t 3s ease-in-out infinite}
    .p2{animation-delay:1.5s}
    @keyframes t{0%{transform:translateX(0);opacity:0}10%{opacity:1}55%{transform:translateX(-118px);opacity:1}65%,100%{transform:translateX(-118px);opacity:0}}
    @media (prefers-reduced-motion:reduce){.p{animation:none;opacity:0}}
  </style>
  <rect x="8" y="20" width="64" height="32" rx="6" stroke-width="1.5"/>
  <text x="40" y="40" fill="currentColor" stroke="none" font-size="11" text-anchor="middle" font-family="sans-serif">parent</text>
  <rect x="168" y="20" width="64" height="32" rx="6" stroke-width="1.5"/>
  <text x="200" y="40" fill="currentColor" stroke="none" font-size="11" text-anchor="middle" font-family="sans-serif">child</text>
  <line x1="72" y1="36" x2="168" y2="36" stroke-opacity=".3" stroke-dasharray="3 4"/>
  <circle class="p" cx="196" cy="36" r="5" fill="currentColor" stroke="none"/>
  <circle class="p p2" cx="196" cy="36" r="5" fill="currentColor" stroke="none" fill-opacity=".5"/>
</svg>

Added by the opencode bot (AI-generated).

Fixes #48826

Related: #62792, #36349, #59051

Public API: adds an optional notify input to the subagent tool and a reserved subagent.notify session metadata key; <subagent> reports are now sent every time the child goes idle (backwards compatible)

@opencodejr opencodejr Bot 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.

The design holds up: reporting from the settle hook, with an outbox row written in the same transaction, is a sound way to get the final answer to the parent. I ran the related core tests (128 pass) and typecheck:tsc (passes). I did not reproduce the issue by hand with the simulated model, because parent and child requests come off one shared response queue in no fixed order. The PR's e2e test is the main evidence.

Public API: the subagent tool gets a new optional notify input, and subagent.notify becomes a reserved session metadata key. The <subagent> message the parent sees is now sent every time the child goes idle, not once per job, and can include a Background work still running: list. Nothing is removed and existing callers keep working.

Concerns, inline:

  • The silence flag lives in user metadata that other writers replace wholesale.
  • Every child with a parent now reports, including plugin-created child sessions. A user pressing Esc in a child they are typing into wakes the parent with a "Subagent cancelled" turn.
  • The e2e eventually helper polls with no limit.

Fixes #48826
Related: #62792, #36349, #59051

import type { SessionSchema } from "./schema.js"

/** Per-link switch for reporting a subagent's idle transition to its parent. */
export const KEY = "subagent.notify"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

subagent.notify lives in ordinary session metadata, but setMetadata (the HTTP API and plugin session.update) replaces the whole map, as the MetadataUpdated projector shows. Any host or plugin that writes its own metadata to a silenced child quietly makes it report again. The key is also exposed to clients, who may copy it back or remove it. Could the link state live somewhere that isn't host metadata, such as a column or the job recovery, or could metadata updates preserve this key?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Keeping it in session metadata for now. A host that replaces the whole map resets the key, which we're accepting in this PR.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Sounds good, that's a fine tradeoff for this PR. If the map gets replaced, the key goes back to the loud default (notify() at lines 9–11 only treats an explicit false as silent). So the worst case is a silenced child that starts reporting to its parent again. Nothing is lost or blocked.

If this comes up later, there are two cheap fixes that don't need a schema change:

  • Keep subagent.notify when the MetadataUpdated projector replaces the map, or
  • Make the tool's follow-up path rewrite the key on every call through update().

I didn't change anything in the checkout.

mode: "background" | "none",
): Effect.fn.Return<{ readonly status: Exclude<Job.Status, "running">; readonly body: string } | undefined> {
if (outcome.type === "failed") return { status: "error", body: outcome.error.message }
if (outcome.type === "interrupted") return { status: "cancelled", body: "Subagent cancelled" }

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Every child with a parentID now reports, whoever started its busy period. That includes sessions plugins create with session.create({ parentID }), which don't go through the subagent tool. And when a user who is typing into a child directly presses Esc, the parent gets a Subagent cancelled report and is woken for a model turn. Is waking the parent on a user interrupt (and for plugin-created children) intended? If not, consider sending nothing for user interrupts when no background job promised a report (mode === "none").

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Intended: any child with a parent reports, whoever started its busy period, including plugin-created children. A user interrupt in a child also reports cancelled to the parent; we're keeping that.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Understood, I'll drop the suggestion. The code already does this: resolveBody (line 65) returns cancelled for a user interrupt in either mode, and nothing in the report path checks how the child was created, so plugin-created children with a parentID report too.

I read the tests but didn't run them. There are tests for a user interrupt reporting Subagent cancelled, but each one has a job attached:

  • with a background subagent job, including replay after a crash: session-execution.test.ts:194-249
  • with a background shell still running: subagent-report.test.ts:353-361
  • created, then cancelled at once: subagent-report.test.ts:394-401

No test covers the case you're keeping: a user prompts a child directly, with no subagent or shell job, presses Esc, and the parent gets a cancelled report and is woken. If you want that locked in, it would be a short addition next to subagent-report.test.ts:353: prompt/wake a child that has no jobs, interrupt it, then assert one state="cancelled" inbox item on the parent. I didn't change anything in repo/.

): Effect.Effect<A, E, R> =>
Effect.suspend(() => effect).pipe(
Effect.flatMap((value) =>
predicate(value) ? Effect.succeed(value) : Effect.sleep(20).pipe(Effect.andThen(eventually(effect, predicate))),

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

eventually retries every 20 ms with no limit, so a condition that never becomes true hangs until the runner's timeout instead of failing with a clear message. Please add a limit, or wait on the relevant event/deferred. More generally, this file (~760 lines) and subagent-report.test.ts (~890 lines) are large; cutting them down to the core cases would make them easier to maintain.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in fe120a1: the wait is bounded and the failure names the session and the expected vs actual report count.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Confirmed: fe120a1 fixes it. I tested the PR head in a separate worktree at /tmp/opencode/pr-head. The shared repo/ checkout is still on the older 3b092c0f6, so I didn't touch it.

  • Bounded wait: waitForReports (lines 300–314) now checks every 20 ms and gives up after 500 tries, about 10 s. In Effect, when repeat runs out of tries it returns the last value it got instead of failing, so the expect after it is what actually reports the failure. Each test still has its 30 s timeout, so a miss shows up well before that.
  • Failure message: I temporarily changed line 348 to expect 5 reports. The test failed after about 10.7 s with Session ses_…: expected at least 5 reports, got 2 (Expected: >= 5, Received: 2). I then reverted the change.
  • Removed eventually in the silent-middle test: this is fine. waitForReports(h, childID, 1) already ends with sessions.wait(childID), so the direct toContain check runs after the child is idle.
  • Runs: after a fresh bun install, bun test test/subagent-idle-e2e.test.ts passes all 9 tests in about 2 s. tsc --noEmit reports no errors in this file.

One small leftover: the sessions.wait(sessionID) at the end of the helper has no limit of its own, but the 30 s per-test timeout covers it.

readonly info: Info
readonly isBackgrounded: boolean
readonly consumed?: boolean
readonly settling?: boolean

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

@OpenCode what sets these?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

hey opencode answer me

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Nothing in list.ts sets them. Live is a read-only structural view of the in-memory Active entries in Job's SynchronizedRef. On Active (packages/core/src/job.ts:83-84) both fields are required booleans, and they start as false when a job is created (job.ts:385-386).

consumed has two writers in job.ts:

  • consume (job.ts:249): a finished, non-running job's result has been read by its caller. Finished entries that are consumed and have no notification are then trimmed to COMPLETED_LIMIT.
  • completeBackground (job.ts:616): the notification row was delivered and deleted, but the work is still running. The entry stays so the work can keep running, and the flag stops persistBackground from writing the deleted row back when the work finishes (job.ts:320-328).

settling has one writer, prepareSubagentReport (job.ts:649). It is set when a running generation is claimed for its idle report, alongside reported: true. From then on, that generation:

  • refuses a late Ctrl+B (job.ts:490, :510)
  • doesn't persist its own row, because the settle commit owns it (:328, :544)
  • counts as not running for currentGeneration (:627)
  • isn't reused when new work starts: a new generation is created instead (:356)

In list.ts, the only reader is line 113. It drops live entries that are consumed or settling from backgroundJobs, so a job already delivered or being reported doesn't show up as running background work. That includes the Background work still running: list. The fields are optional on Live only because it's a structural subset, not because anything sets them partially.

I found these with a grep over packages/core/src and read the call sites; I didn't run anything or make any changes.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

why do we need them in this pr

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

They keep Job.backgroundJobs (JobList.read) honest now that a report can go out while the job is still running. backgroundJobs builds the Background work still running: list (session/background.ts:113 → subagent-completion.ts:69) and the restart/wake checks. read() combines DB rows with the in-memory entries, and line 113 adds any live entry that no row covered. This PR adds two states where a live entry is no longer running work, and both would be listed as running without the filter:

  • consumed (already on Active in base; this PR adds a new writer): before this PR, a report was only sent once the job had finished. Now a background child can report on idle while it is still running, for example while its shell is still going. completeBackground then deletes the notification row but keeps the entry with consumed: true (job.ts:616). With the row gone, seen doesn't contain it, so without the filter the live loop would add it back. The parent would then see a job it has already been told about as "still running", and so could the child's next report.
  • settling (new in this PR): it's set in prepareSubagentReport (job.ts:649) while a running generation's idle report is being committed. Without the filter, the generation that is reporting could appear in its own "still running" list, or keep a wake/restart check waiting on it. The other settling checks in job.ts (late Ctrl+B, skipping persistBackground, currentGeneration) treat it the same way: it's no longer live work.

The fields are optional on Live only so that read()'s generic Entry extends Live accepts entries without them; Active always sets both.

I read the base and the diff to confirm that consumed already existed and that settling and the list.ts filter are new. I didn't change anything, and I didn't check whether a test fails if the filter is removed.

@opencodejr opencodejr Bot 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.

The fix works: I ran the #48826 reproduction from source with a simulated model.

  • Base: the parent only ever sees the subagent's early reply.
  • This PR: the child's final answer, written after its background shell finishes, reaches the parent as a second report.

The subagent tests (93) and the session-remove tests pass, and tsc -b is clean.

The new commit doesn't address the earlier threads (where subagent.notify is stored, parent wakes from plugin-created or user-interrupted children, and the e2e polling helper that never times out), so they stay open. The new commit doesn't change the public API, and the earlier assessment still applies.

One new concern, inline: the new Session.remove order can leave children whose parent no longer exists.

Before

After

yield* environments.clear(sessionID)
yield* bus.publish(SessionEvent.Deleted, { sessionID })
yield* bus.remove(sessionID)
yield* Effect.forEach(children, (child) => result.remove(child.id), { concurrency: 1, discard: 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.

With children now removed after the parent's Deleted event, a failure or shutdown partway through this loop (e.g. a child's awaitIdle interrupted, or a process exit) leaves the remaining children with a parent_id that points to a session that no longer exists. Calling remove(parent) again can't clean them up, because the parent's get now fails. With the old order, a partial failure left the parent in place so the call could be retried. Could the report path skip a parent that is being deleted (e.g. mark it before interrupting the children), so the children can still be removed first?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Leaving this as is: it needs remove itself to be interrupted between the parent's delete and the children's, which is rare enough to keep out of this PR.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

That's fine with me. Interruption mid-remove is the main way to get there, and the orphaned children only cost a few dangling rows. There's no foreign key on parent_id, so nothing cascades or breaks.

There is one non-interrupt case, which you can still skip. Each child's result.remove(child.id) starts with result.get, which can fail with NotFoundError (packages/core/src/session.ts, around line 395). If a child is deleted while its parent's delete is running, for example when a client deletes several sessions at once, that error stops the forEach at line 407. The remaining siblings are then left behind, and a retry can't reach them because the parent is already gone. If you ever want to cover it, it's a one-line change and doesn't need the "mark parent as deleting" redesign:

yield* Effect.forEach(
  children,
  (child) => result.remove(child.id).pipe(Effect.catchTag("NotFoundError", () => Effect.void)),
  { concurrency: 1, discard: true },
)

I only read the code; I didn't run anything or make any changes. bun.lock was already modified in the checkout when I looked, and I didn't touch it.

User decisions:
- Report to the parent whenever a subagent goes idle
- Keep a subagent's current notify setting on follow-up calls when notify is omitted
…nt tracking

User decisions:
- Report to the parent whenever a subagent goes idle
- List still-running background work on both background and foreground results
…running-work formatting

User decisions:
- Report to the parent whenever a subagent goes idle
- List still-running background work on both background and foreground results
…b outbox

User decisions:
- Report to the parent whenever a subagent goes idle
- List still-running background work on both background and foreground results
User decisions:
- Report to the parent whenever a subagent goes idle
- Don't resume a directly prompted child after a crash (deferred)
User decisions:
- Report to the parent whenever a subagent goes idle
- Keep a subagent's current notify setting on follow-up calls when notify is omitted
- List still-running background work on both background and foreground results
User decisions:
- Add the end-to-end suite as a new packages/core/test/subagent-idle-e2e.test.ts
- Cover the report-on-idle scenarios for shells, direct and tool follow-ups, nested and silent links, crash replay, mid-turn restart, and session deletion
- Skip opencode run quiescence, which is out of scope here
- Keep this change test-only; no source fixes
…ent helpers

User decisions:
- Delete the parent before its children so settling children don't wake a deleted parent
- Remove the unused SubagentJob.background method and the duplicated running-work type
User decisions:
- Rebase onto the latest dev
- Tell the model a silently launched subagent won't notify it
- Fix the remaining small review nits

@opencodejr opencodejr Bot 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.

The fix still works after the rebase. I re-ran the #48826 reproduction from source with a simulated model: on the base the parent never receives the child's final answer, and with this PR it arrives as a second report. The subagent, job and session-execution tests pass (122), and tsc -b is clean.

The e2e polling helper now stops after a bounded number of tries and fails with a clear message, so that thread is resolved. The subagent.notify storage, wakes from plugin-created or user-interrupted children, and the delete order in Session.remove are still open. The new commits raise no new concerns and don't change the public API; the earlier assessment still applies.

Before

After

@jlongster

jlongster commented Nov 11, 2026 •

Copy link
Copy Markdown
Contributor Author

Statecheck: all 159 traces matched on fe120a1a52. The first report carried the partial answer and the running shell; the follow-up carried the finished answer.

Two recorded parent admissions: Checking with a running shell, then Finished

What ran, replay scripts, and coverage
  • Notification settings: 125 three-action traces, 375 observations. Silencing a child suppressed its own link; a fork defaulted to reporting again. Unrelated annotations survived.
  • Report contents and delivery order: 32 traces, 96 actions. Given completed rows, the helper admitted each parent message before acknowledging it. A still-running row produced zero events. The fixture supplied report rows and shell state and recorded admission callbacks.
  • Answer selection: Two traces, 12 checks, on fresh SQLite databases. The sequence cutoff excluded the previous period’s answer. Selection skipped failed and unfinished rows, including a page of 20 unfinished messages. An eligible reasoning-only message produced the no-text fallback.
  • Coverage boundary: The host guard deferred the full shell-wake → child settlement → parent inbox run before setup. The diagram shows helper observations.

Download the property scripts · Explore this 159-trace run at fe120a1a52. The scripts use the Statecheck runTrace package and a prepared OpenCode PR checkout. With those installed, set OPENCODE_TREE to that checkout and run bash primary/leaf.sh for the report shown above.

@jlongster
jlongster merged commit 609ee05 into dev Nov 11, 2026
22 of 23 checks passed
@jlongster
jlongster deleted the subagent-idle-report branch November 11, 2026 18:09
cevr added a commit to cevr/opencode that referenced this pull request Nov 11, 2026
Upstream now always runs subagents in the background and reports a child's
result to its parent every time the child goes idle (anomalyco#63209, anomalyco#63382, anomalyco#63223).
That does what fork commit 80da76e did (a subagent waiting on its own
background work is not finished), so ours is dropped: Job's undelivered /
awaitDelivered notice tracking, SessionBackground.awaitQuiet, its hooks in
subagent-job.ts and execution/restart.ts, and
test/subagent-background-wake.test.ts. job.ts, restart.ts and subagent-job.ts
take upstream's.

Kept from the fork: Job.background's `running` option (shell handles,
c965f99) and its test. shell.ts keeps the fork's handles and end notice;
its notify takes upstream's narrowed `sessions` and drops `resume` as
upstream's did.
SirWellington added a commit to WellingtonHQ/opencode that referenced this pull request Nov 13, 2026
* chore(site): remove the unused arcade sound library from the media manifest (anomalyco#62611)

* fix(site): bring the latest site fixes from the new-website workshop (anomalyco#62613)

Co-authored-by: Adam <2363879+adamdotdevin@users.noreply.github.com>

* feat(data): switch the mono font to OpenTUI Mono (anomalyco#62623)

* feat(site): add the shared product and logo menus to every nav (anomalyco#62654)

Co-authored-by: Adam <2363879+adamdotdevin@users.noreply.github.com>

* fix(data): keep native light-dark() so the shared nav menus get their colours (anomalyco#62660)

* feat(core): wake sessions on Console event watches (anomalyco#62662)

* fix(site): match the product chevron to the docs chevron (anomalyco#62665)

Co-authored-by: Adam <2363879+adamdotdevin@users.noreply.github.com>

* fix(site): stop the page dimming when a product card opens (anomalyco#62622)

* perf(core): fetch Console instructions and skills concurrently (anomalyco#62672)

* docs: antivirus HTTPS scanning and W-9 tax form (anomalyco#62661)

* fix(site): stop server functions failing on the dev server behind a proxy (anomalyco#62677)

* fix(site): pin the Like letters? bar so Safari's toolbar turns blue with it (anomalyco#62674)

* fix(site): tidy the docs bars and search on phones and desktop (anomalyco#62669)

* fix(site): use one dark link blue across the sites (anomalyco#62676)

* feat(data): per-page Open Graph cards for model and lab pages (anomalyco#62692)

* fix(core): clearer shell exit and timeout status, pass unmatched zsh globs through (anomalyco#62141)

Co-authored-by: Aiden Cline <aidenpcline@gmail.com>

* docs(legal): cover integrations with third-party services (anomalyco#62700)

* fix(site): follow up anomalyco#62700 with dev's commit in the legal history and new legal bundle budgets (anomalyco#62701)

* fix(core): keep Console policies when its instructions or skills fail (anomalyco#62702)

* fix(core): don't fail MCP tool calls whose results break their output schema (anomalyco#61254)

* fix(site): tidy the phone nav, docs menus and icons (anomalyco#62707)

* chore(perf): bench with strobe 0.20.0 from github.com/anomalyco/strobe (anomalyco#62705)

* feat(core): watch workspace MCP servers' events through the Console plugin (anomalyco#62734)

* chore(perf): bench with strobe 0.21.0 (accuracy audit) (anomalyco#62747)

* feat(site): keep the page and current section stuck on phone docs (anomalyco#62751)

* fix(site): return Safari's toolbar to the page colour when the letters go back (anomalyco#62754)

* fix(site): make the phone sticky rows full width so their tap fill reaches both edges (anomalyco#62759)

* fix(core): keep Code Mode catalog updates small and stable (anomalyco#62176)

Co-authored-by: exe.dev user <exedev@anton.exe.xyz>

* fix(core): make build metadata a required service so flags can't silently fall back to release defaults (anomalyco#62686)

* chore(perf): bench with strobe 0.22.0; tabs' warm switches end on the frame after the answer (anomalyco#62764)

* fix(core): keep a v1 provider's baseURL when api is also set (anomalyco#62570)

* fix(desktop): show an error when opening a path in the default app fails (anomalyco#62572)

* Add Frantic Ferret Free (anomalyco#62770)

Co-authored-by: Daniel <daniel@anoma.ly>

* fix(app): slide the side panel shut when its last tab closes (anomalyco#62758)

* feat(core): frame Console channel follow-up wakes as maybe unrelated, and let watch take minutes (anomalyco#62774)

* Remove Frantic Ferret Free from docs (anomalyco#62780)

* fix(desktop): restore the review shortcut (anomalyco#62567)

* docs(legal): cover hosted agent sessions and their retention (anomalyco#62789)

* fix(site): point the legal history's hosted agents entry at dev's commit (anomalyco#62790)

* fix(core): tail reads from the end of a file and suggest close file names (anomalyco#62147)

Co-authored-by: Aiden Cline <aidenpcline@gmail.com>

* docs: strobe moved to github.com/anomalyco/strobe (anomalyco#62706)

* feat(core): say which credential changed in credential.updated (anomalyco#62762)

* chore(perf): bench with strobe 0.23.0 (anomalyco#62799)

* chore: let bun resolve strobe's Windows on Arm package (anomalyco#62804)

* feat(core): tag shell, tool and model-stream spans with session, agent and command (anomalyco#62806)

* fix(server): stop waiting for plugins in request handlers (anomalyco#62796)

* fix(core): refresh the Copilot API endpoint with the model list (anomalyco#62171)

Co-authored-by: exe.dev user <exedev@anton.exe.xyz>

* feat(ai): support predicate criteria in decisions (anomalyco#62819)

* fix(core): stop retrying ChatGPT workspace usage limits (anomalyco#62823)

* feat(acp): support _session/steering (anomalyco#54394)

Co-authored-by: Dan Smolsky <dannysmo@gmail.com>

* docs: document cache.ttl and per-model cache.warming (anomalyco#62829)

* fix(core): stop applying well-known remote config after logout (anomalyco#62760)

Co-authored-by: 2SinceJuly <202121119+2SinceJuly@users.noreply.github.com>

* fix(core): refresh MCP OAuth tokens under the shared credential lock (anomalyco#62827)

* refactor(core): run GitHub Copilot on native ai protocols (anomalyco#62034)

Co-authored-by: exe.dev user <exedev@anton.exe.xyz>

* fix(app): drop the dead plugin-boot retry on catalog syncs (anomalyco#62830)

* docs(go): add LongCat 2.5 Free to Free and Go (anomalyco#62878)

Co-authored-by: Jack <jack@anoma.ly>

* refactor(tui): remove the import cycle in plugin (anomalyco#62884)

* refactor(core): remove the import cycle in v1 migration (anomalyco#62885)

* refactor(codemode): remove the import cycle in interpreter (anomalyco#62886)

* docs(console): lower Claude Sonnet 5.5 cached read price to $0.10 (anomalyco#62887)

* feat(app): mark sessions read or unread from their menus (anomalyco#62889)

* fix(session-ui): show the picked question answer as a raised card (anomalyco#62896)

* chore(perf): bench with strobe 0.24.0 (anomalyco#62895)

* feat(core): return usage from session generate (anomalyco#62835)

* fix(tui): use keyboard-navigable buttons in update and confirm dialogs (anomalyco#62906)

* fix(ui): remove focus form borderless inline input while editing (anomalyco#62919)

* fix(ui): keep selects, menus, tooltips and toasts reachable from a dialog (anomalyco#62913)

* fix(ui): list types before import in packed exports and export select.css (anomalyco#62914)

* chore(infra): drop stripe and aws from deploy, move share to its own worker (anomalyco#62908)

* fix(site): align Copy as Markdown with the end of the docs page footer (anomalyco#62933)

* chore(infra): drop SiteDomain and retain zen buckets and trust dns before untracking (anomalyco#62938)

* docs(console): add Muse Ember 1.0 (anomalyco#62935)

Co-authored-by: Daniel <daniel@anoma.ly>

* fix(core): hold Console watch wakes after 5 in 10 minutes or 20 since the prompt (anomalyco#62924)

* fix(tui): use the base text color for the dialog search cursor (anomalyco#62939)

* chore(infra): untrack zen buckets and trust dns now that they are retained (anomalyco#62940)

* fix(tui): drop usage and the model detail line from the model picker (anomalyco#62927)

* fix(tui): remove dark gap between execute detail and its footer (anomalyco#62928)

* fix(tui): add a blank row under the OAuth dialog title (anomalyco#62929)

* fix(tui): give the shell output dialog new-design footer actions (anomalyco#62932)

* docs(console): add Claude Fable 5.2 (anomalyco#62949)

Co-authored-by: Daniel <daniel@anoma.ly>

* fix(core): time warming from the model's cache.ttl by default (anomalyco#62831)

Co-authored-by: Ryan Skidmore <4580448+ryanskidmore@users.noreply.github.com>

* chore(perf): bench with strobe 0.26.0 (anomalyco#62931)

* feat(app): close side panel tabs to the right and make ⌘W/⌘⇧T side-panel aware (anomalyco#62922)

* ci: read deploy and release secrets from aws secrets manager (anomalyco#62954)

* fix(perf): type navigation.bench.ts's setup key on its target (anomalyco#62952)

* fix(core): stop warming a session after a ping misses the cache (anomalyco#62926)

Co-authored-by: Ryan Skidmore <4580448+ryanskidmore@users.noreply.github.com>

* fix(core): count the warming interval from when the request was sent (anomalyco#62941)

* fix(site): keep open menus under the pinned header (anomalyco#62968)

* docs: match Gemini Flash intro pricing on Console models (anomalyco#62937)

Co-authored-by: Frank <frank@anoma.ly>

* docs(console): deprecate Crouton Alpha Free (anomalyco#62975)

Co-authored-by: Daniel <daniel@anoma.ly>

* fix(site): fetch the docs' status bars from a 79-byte endpoint when the footer comes near (anomalyco#62962)

* fix(site): stop idle polling and scroll layout thrashing (anomalyco#62966)

* fix(files): cache the site's media for a year (anomalyco#62980)

* fix(site): flatten masked logo SVGs so they render sharp (anomalyco#62946)

* refactor(site): keep dev-only code out of production pages and group small shared chunks (anomalyco#62964)

* fix(site): load the nav menus, console API and Hex pop-up on intent (anomalyco#62965)

* fix(site): serve AV1/HEVC card videos and load card media after the page (anomalyco#62971)

* refactor(core): give each warmed session one owned loop (anomalyco#62972)

* chore(perf): bench with strobe 0.27.0 (anomalyco#62985)

* refactor(site): parameterize src/docs for multiple docs sets (anomalyco#62950)

* feat(site): serve V1 docs in the new design at /v1/docs (anomalyco#62951)

* feat(site): translate the V1 docs' chrome and missing pages (anomalyco#62956)

* feat(app): keep assistant copy visible on dev builds (anomalyco#62992)

* chore(core): update MCP SDK to 2.4.0 (anomalyco#62982)

* refactor(site): prune component CSS variants and split shell from route stylesheets (anomalyco#62990)

* fix(stats): map crouton alpha to muse ember (anomalyco#62994)

* chore(infra): point docs.opencode.ai at the site worker (anomalyco#62999)

* docs(console): add MiniMax M3.1 Flash Free (anomalyco#63005)

Co-authored-by: MrMushrooooom <19261047+MrMushrooooom@users.noreply.github.com>

* fix(core): count session generate requests in the session's cost (anomalyco#63006)

* feat(ai): add embedding models with the OpenAI embeddings protocol (anomalyco#62832)

* refactor(ai): remove the ImageResponse.image shortcut (anomalyco#63011)

* fix(core): keep MCP OAuth credentials when a refresh fails temporarily (anomalyco#63012)

* feat(ai): add Google embedContent embeddings (anomalyco#62843)

* feat(core): add GitHub Copilot Auto and a model resolve hook (anomalyco#62997)

* refactor(plugin): edit the model in place in experimental.model.resolve (anomalyco#63015)

* feat(ai): add Vertex predict embeddings (anomalyco#62844)

* feat(ai): add Google and Vertex embedding entry points (anomalyco#63017)

* refactor(core): share OAuth credential refresh between provider logins and MCP (anomalyco#63022)

* fix(core): keep background compaction from stopping a running Claude Agent session (anomalyco#63025)

* fix(core): keep catalog capabilities when a v1 model override sets only some (anomalyco#62573)

* fix(site): build the Worker as one file so its chunks can't import each other (anomalyco#63031)

* feat(site): serve the reading pages as static HTML (anomalyco#63032)

* fix(core): send gatewayApiKey to Cloudflare AI Gateway (anomalyco#62574)

* fix(core): put Console event watches behind the console_watches flag (anomalyco#63036)

* fix(core): stop splitting an emoji when read truncates a long line (anomalyco#62575)

* fix(core): list Console's watch tool and say pull requests wake with their checks (anomalyco#63039)

* fix(core): stop interrupting Claude Agent tool calls when instructions or tools change (anomalyco#63033)

* ignore: wait for plugins again where managed policy applies  (anomalyco#63040)

* refactor(site): share the static pages' behaviour with their components (anomalyco#63041)

* chore(perf): bench with strobe 0.28.0 (anomalyco#63043)

* release: v2.2.6 (anomalyco#62450)

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* feat(site): serve the home and product pages as static HTML (anomalyco#63060)

* refactor(site): make every page static and stop shipping the app's JavaScript (anomalyco#63067)

* feat(app): make session IDs easier to find and copy (anomalyco#63083)

* release: v2.2.7 (anomalyco#63085)

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* feat(app): show tab shortcut numbers while holding the mod key (anomalyco#63089)

* fix(site): answer other methods on pages with a 405 (anomalyco#63102)

* fix(site): send every unhandled method a 405 listing what the address takes (anomalyco#63104)

* fix(app): tighten gap between titlebar search and first tab to 10px (anomalyco#63108)

* chore(release): mint short-lived cloudflare token for r2 uploads (anomalyco#63115)

* docs(console): list Muse Ember 1.0's over-200K price (anomalyco#63116)

* feat(app): queue a follow-up first with Alt+Enter (anomalyco#63109)

* feat(app): steer the next queued prompt with Mod+Enter (anomalyco#63111)

* fix(site): load the changelog's collapsed lists when opened (anomalyco#63122)

* chore(web): move the V1 docs into services/site and remove packages/web (anomalyco#63117)

* fix(release): publish platform packages before the cli package (anomalyco#63124)

* feat(app): link Console MCPs and skills in Extensions settings (anomalyco#63125)

* fix(site): serve 1344-wide hero videos to 1x screens and phones (anomalyco#63135)

* refactor(site): keep Solid off the static pages until an overlay opens (anomalyco#63140)

* refactor(site): drop code only the hydrated production pages used (anomalyco#63147)

* fix(core): retry failed streams cleanly and keep finished work on interrupt (anomalyco#60674)

* fix(core): send Copilot requests to the login's own endpoint until models load (anomalyco#63146)

* feat(core): background shell commands when their timeout expires (anomalyco#63024)

* docs(console): add Gemini 4 Carbon to Zen (anomalyco#63153)

Co-authored-by: Daniel <daniel@anoma.ly>

* refactor(core): remove the import cycle between provider and aisdk-native (anomalyco#62883)

Co-authored-by: Aiden Cline <63023139+rekram1-node@users.noreply.github.com>

* refactor(ai): remove the import cycles between media modules and their clients (anomalyco#62882)

Co-authored-by: Aiden Cline <63023139+rekram1-node@users.noreply.github.com>

* refactor(site): share the docs' and static pages' shell code (anomalyco#63161)

* fix(site): keep the Like letters? bar's look when the announcement banner is off (anomalyco#63157)

* docs(console): document paying for Go with credit (anomalyco#63162)

* fix(site): give the not-found page one stylesheet of what it renders (anomalyco#63169)

* feat(app): add an experimental customizable sessions sidebar (anomalyco#63143)

* feat(core): speak opencode-pty protocol v8 (anomalyco#62976)

* fix(app): slide the file tree sidebar open and shut again (anomalyco#62773)

* fix(core): keep a shell command's output when the user interrupts its call (anomalyco#62977)

* fix(app): name the main checkout by its branch instead of Local (anomalyco#63187)

* feat(core): run shell commands in the process daemon across handoffs (anomalyco#62978)

* feat(plugin): let promise tools stop cooperatively through their signal (anomalyco#63127)

* feat(core): use freeform tool input on models that support it (anomalyco#61703)

* fix(core): accept decision-type models from LM Studio (anomalyco#56214)

* fix(tui): draw paste chip text dark in dark mode and light in light mode (anomalyco#62930)

* fix(tui): open the right activity tab and make tabs clickable (anomalyco#60168)

* feat(app): add Recent sessions sidebar experiment and iOS-style recency (anomalyco#63177)

* feat(tui): default transcript verbosity to low (anomalyco#63207)

* fix(app): show Recent sidebar rows exactly like side tabs (anomalyco#63211)

* fix(desktop): stop freezing the main process during the login shell env probe (anomalyco#63208)

* v0.8.4 (anomalyco#63055)

* fix(core): accept null context length from LM Studio models (anomalyco#63198)

* fix(core): report a refused Console auto-watch (anomalyco#63217)

* fix(cli): update npm installs through their own prefix (anomalyco#63152)

* feat(codemode): rank tool search with name-weighted BM25 (anomalyco#62984)

* feat(core): run LM Studio decision models (anomalyco#63200)

* fix(core): describe the execute program as plain JavaScript for every tool shape (anomalyco#63226)

* chore(ci): keep the heavy test tier off pull requests

pull requests now run the affected unit tests on linux only. the windows unit
tests, the compiled builds and the four playwright suites still run on every
push to dev and beta, on nightly runs, and as a release.yml gate before a
stable release publishes.

* chore(skills): describe the test tiers as they now run

* chore(ci): gate a stable release on the linux browser suites

the windows playwright legs still fail on dev pushes often enough that a
release gate over them would stall shipping. unit tests and builds still cover
both OSes, and dev pushes and nightly runs still cover the windows browser
legs.

* feat(tui): open sessions from session IDs in messages (anomalyco#63224)

* chore: move the api worker into the legacy service

* fix(tui): only re-highlight blocks whose session link changed (anomalyco#63247)

* chore: move the data site off sst

the stats site, its og worker and the sync workflow deploy from services/data with cf as
opencode-data-<stage>, opencode-data-og-<stage> and opencode-data-sync-<stage>. the beta
web app and the whole sst setup (sst.config.ts, infra/, sst-env.d.ts, the sst dependency)
are gone, so nothing deploys through sst anymore (security finding anomalyco#920).

* chore: drop the sst-env.d.ts files sst regenerated

* fix(core): refresh MCP OAuth tokens before they expire (anomalyco#63028)

* fix(site): keep the bare host as a custom domain

* fix(ai): keep exhausted request rate limits retryable (anomalyco#59816)

* fix(codemode): return compact JSON results (anomalyco#63258)

* feat(core): support MCP events in the MCP client (anomalyco#63254)

Co-authored-by: Adam <2363879+adamdotdevin@users.noreply.github.com>

* ci(deploy): mint short-lived cloudflare tokens from the token issuer

* feat(core): wake a session on MCP events with a watch tool (anomalyco#63269)

Co-authored-by: Adam <2363879+adamdotdevin@users.noreply.github.com>

* fix(core): send saved keys during local model discovery (anomalyco#63266)

* refactor(data): strict dev/production stages and data naming

- services/data/stage.ts: stage(mode) throws on anything but dev or production, used by all three configs, build.ts and deploy.ts
- packages/stats -> packages/data (@opencode/data-app, -core, -server)
- StatsSyncWorkflow -> DataSyncWorkflow, instance ids data-hourly-/data-history-, Data* resource keys, data sync log lines
- worker, route, workflow and cron names unchanged

* feat(core): tell agents when they are in a fork (anomalyco#63235)

Co-authored-by: OpenCode Agent <opencode-agent[bot]@users.noreply.github.com>

* fix(deploy): run Cloudflare deploys from verified artifacts behind pinned targets

Repository code outside .github/ needs no review, but every deploy job held a
Cloudflare token strong enough to write any Worker on the account (the data
sync Workflow PUT has no per-Worker permission). A dev merge could therefore
overwrite production Workers.

Split each service into a build job with no environment, secrets, or OIDC token
that uploads a SHA256SUMS artifact, and a deploy job in dev|production that
checks out only .github/release/, verifies the artifact against the build job's
digest, installs the cf/wrangler CLI pinned here, and runs only deploy-*.sh.

The deploy scripts treat the artifact as data and refuse it unless its resolved
config equals the pinned target in .github/release/targets/ exactly: Worker
names, routes, custom domains, crons, Workflow names, and bindings. For cf
services the pinned config is what cf reads. That is what makes an account-wide
token safe, and it keeps production out of reach of a dev merge.

Adds the cf 1.0.0-beta.12 and wrangler 4.110.0 lockfiles the deploy jobs
install with npm ci --ignore-scripts.

* fix(core): fetch Console instructions and skills only when the config says the workspace has them (anomalyco#63259)

* fix(ci): treat require-digests=false as off in verify-artifacts

The download action always sets OPENCODE_REQUIRE_DIGESTS (false by default),
so testing for a non-empty value required digests for release artifacts that
legitimately have none and broke sign-macos, sign-windows and
publish-attestations. Compare the value to true instead.

* fix(site): show download and install menus again after closing them (anomalyco#63311)

* feat(app): add the New timeline experiment (anomalyco#63295)

* fix(app): snap vertical tab preview to its tab (anomalyco#63074)

* feat(app): limit Recent sidebar to 7 days and 30 rows, align its hover preview (anomalyco#63313)

* fix(tui): give plugins a live theme view (anomalyco#63306)

* fix(app): accept a pasted redirect URL for provider sign-in (anomalyco#63315)

Co-authored-by: Aiden Cline <aidenpcline@gmail.com>

* fix(session): measure tps from the first streamed token (anomalyco#63321)

* chore(protocol): refresh generated openapi for the first-token event (anomalyco#63324)

* fix(app): show only the branch in the new session row (anomalyco#63182)

* refactor(codemode): remove the legacy interpreter; the VM is the only engine (anomalyco#62642)

* fix(core): keep the truncated preview when tool output can't be saved (anomalyco#63334)

* fix(app): show the agent switcher by default (anomalyco#63337)

* feat(process-daemon): pipe mode on Windows (anomalyco#63196)

* fix(update): verify access identity on admin routes (anomalyco#63340)

* fix(app): remeasure the desktop drag area when direction changes (anomalyco#63347)

* chore: remove beta what's new and visual svgs (anomalyco#63325)

* feat(core): report subagent results to the parent every time a child goes idle (anomalyco#63209)

* chore(process-daemon): release 0.5.1 (anomalyco#63366)

* refactor(process-daemon): simplify Windows pipe mode (anomalyco#63346)

* chore(process-daemon): allow 60 minutes for Windows release builds (anomalyco#63378)

* feat(core): always run subagents in the background (anomalyco#63382)

* refactor(core): remove the unused foreground path from SubagentJob (anomalyco#63223)

* fix(core): defer restart wakes until parent attempts are counted (anomalyco#63367)

* chore(process-daemon): release 0.5.2 (anomalyco#63381)

* feat(ai): add Google Decisions (anomalyco#63369)

* fix(acp): stream the parent's reaction to background subagent reports (anomalyco#63395)

* chore(core): bump gitlab-ai-provider to 6.24.0 (anomalyco#63342)

* ci: deploy dev workers in anomaly-dev (anomalyco#63379)

* read dev data sync from the dev lake

* fix(core): show the start of tool output that exceeds the limit (anomalyco#63272)

* feat(site): simplify the docs header menu and move the V1 notice into the header (anomalyco#63399)

* chore(site): update OpenCode link cards (anomalyco#63401)

* refactor(core): remove leftover foreground subagent and reattach code (anomalyco#63392)

* refactor(app): remove leftover foreground subagent UI (anomalyco#63391)

* fix(tui): show the subagent card instead of launch instructions in mini scrollback (anomalyco#63389)

* chore(site): remove the /ide page (anomalyco#63386)

Co-authored-by: Adam <2363879+adamdotdevin@users.noreply.github.com>

* ci: run macos build jobs on blacksmith (anomalyco#63397)

* fix(storybook): provide settings context to stories

* fix(app): avoid transforms on scrolling composer suggestions

* fix(app): keep mobile tab menu open when closing tabs

* fix(desktop): update build-windows.bat to post-merge workflow

The merge adopted the upstream desktop workflow, which folded prebuild into build and removed package:win. Drop the stale prebuild step and package the Windows NSIS installer directly with electron-builder.

* chore: ignore Astro and Cloudflare build artifacts

Ignore the generated .astro content modules, .wrangler miniflare state, and the generated services/www/public/cli.json schema so local builds of the site packages no longer show up as untracked files.

* fix(core): keep ephemeral server credentials from wiping shared auth sessions

A stdio/ACP auxiliary server mints its own random password and shares the data directory (and database) with the canonical server. On startup, AuthSession.configure treated the verifier mismatch as a credential change: it deleted the whole auth_session table, wiping the canonical server's remembered logins, and adopted a random verifier. Thread an ephemeral flag from the CLI (set when the password was minted, not from env/config) down to configure, which now skips the reconcile for such a process. The canonical server's behavior, including invalidation on a real credential change, is unchanged.

* fix(desktop): update build-mac.sh to the post-merge build workflow

The script called bun run prebuild and bun run package:mac, neither of which exists in packages/desktop/package.json, so it aborted before producing a build. Mirror build-windows.bat: run bun run build, then bunx electron-builder --mac --publish never --config electron-builder.config.ts.

* feat(app): add sortable schedule list with persisted preference

The schedules panel gains a sort selector with three modes: name (alphabetical, the default), lastRun (most recent first, never-run tasks last), and status (enabled first, name order within each group). The choice is stored with the app's local preference storage (home.schedules.sort) and restored when the panel reopens.

A neutral review pass pinned the never-run ordering (second undefined fixture plus a numeric-aware name pair) and replaced the -Infinity comparator sentinel with -1, since lastRunAtMs is a NonNegativeInt, so the comparator always returns a finite number.

* feat(session-ui): show full input in expanded generic tool calls

---------

Co-authored-by: David Hill <1879069+iamdavidhill@users.noreply.github.com>
Co-authored-by: Adam <2363879+adamdotdevin@users.noreply.github.com>
Co-authored-by: Kit Langton <kit.langton@gmail.com>
Co-authored-by: vprdev <mail@alanrice.me>
Co-authored-by: Aiden Cline <aidenpcline@gmail.com>
Co-authored-by: Aiden Cline <63023139+rekram1-node@users.noreply.github.com>
Co-authored-by: Luke Parker <10430890+Hona@users.noreply.github.com>
Co-authored-by: exe.dev user <exedev@anton.exe.xyz>
Co-authored-by: James Long <longster@gmail.com>
Co-authored-by: Dan Smolsky <78942835+Tarquinen@users.noreply.github.com>
Co-authored-by: opencode-agent[bot] <219766164+opencode-agent[bot]@users.noreply.github.com>
Co-authored-by: Daniel <daniel@anoma.ly>
Co-authored-by: smagnuso <smagnuso@gmail.com>
Co-authored-by: Dan Smolsky <dannysmo@gmail.com>
Co-authored-by: 2SinceJuly <202121119+2SinceJuly@users.noreply.github.com>
Co-authored-by: Jack <jack@anoma.ly>
Co-authored-by: Stefan Avram <98915060+Slickstef11@users.noreply.github.com>
Co-authored-by: usrnk1 <7547651+usrnk1@users.noreply.github.com>
Co-authored-by: Ludvig Rask <74653458+ludvigrask@users.noreply.github.com>
Co-authored-by: Dax <mail@thdxr.com>
Co-authored-by: Ryan Skidmore <4580448+ryanskidmore@users.noreply.github.com>
Co-authored-by: Frank <frank@anoma.ly>
Co-authored-by: Jay <air@live.ca>
Co-authored-by: MrMushrooooom <19261047+MrMushrooooom@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Liyang Zhu <tomzhu1024@outlook.com>
Co-authored-by: OpeOginni <107570612+OpeOginni@users.noreply.github.com>
Co-authored-by: Simon Klee <hello@simonklee.dk>
Co-authored-by: Dax Raad <d@ironbay.co>
Co-authored-by: Kyle Bush <157062883+Kyle-j-bush@users.noreply.github.com>
Co-authored-by: Sebastian <hasta84@gmail.com>
Co-authored-by: OpenCode Agent <opencode-agent[bot]@users.noreply.github.com>
Co-authored-by: Aarav Sareen <96787824+arvsrn@users.noreply.github.com>
Co-authored-by: Swapnil Devesh <sid.swapnildevesh@gmail.com>
Co-authored-by: Filip <34747899+neriousy@users.noreply.github.com>
Co-authored-by: Vladimir Glafirov <vglafirov@gitlab.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] V2: subagent with pending background work (shell commands or subagents, background: true) marked completed early — results never collected

1 participant