github / github/app

Windows: completed scheduled workflows retain extension processes in a live pooled CLI

Open
#3,932 0 comments 2 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

triage
Dominant language
No language data
Stars
2.1k
Forks
157
PR merge metrics
No merged PRs in 30d

Description

Short summary

Completed scheduled workflow sessions retain their extension subprocesses inside a live pooled CLI on Windows. A workflow running every ten minutes accumulated a new batch of seven extension hosts per run. Six completed runs still held 42 extension hosts, approximately 3.1 GiB summed working set, with the oldest run complete for 57 minutes.

Affected version or release
  • GitHub Copilot App executable product/file version: 1.1.21
  • App-launched Copilot CLI executable/package: 1.0.84-5
  • OS: Windows 11 Enterprise, 10.0.26200, x64
  • Observed on 2026-09-15, approximately 21:27-22:31 UTC
Installation context

Windows desktop installation using local sessions and a scheduled automation configured with */10 * * * *. Each automation run creates a fresh workflow session in the same reused local branch workspace. The app reuses a pooled CLI for that working directory. This installation loads seven native extensions per workflow session.

There were other sessions in the app. The counts below isolate one pooled CLI and the extension batches corresponding to completed workflow runs; they are not a claim that every Copilot process on the machine was leaked.

What happened?

The observed sequence is:

  1. The scheduled run reuses the existing CLI pool entry.
  2. A fresh workflow session starts and the CLI logs seven native extensions installed for that session.
  3. The session records session.task_complete and assistant.turn_end.
  4. Its extension batch remains alive well after completion.
  5. The next scheduled run adds another seven hosts without removing the previous batches.

The CLI parent remains alive throughout, so these are retained children under a live parent, not parentless processes.

At approximately 22:28 UTC, pooled CLI PID 31228 had:

  • 49 direct copilot.exe children running extension_bootstrap.mjs.
  • 134 processes in its complete tree, approximately 6,668 MiB summed working set.

At 22:31 UTC, after the next scheduled run started at approximately 22:30:29:

  • The same CLI had 56 extension hosts, approximately 4,234 MiB summed working set for those hosts alone.
  • The older batches were still present.

The following six completed runs accounted for 42 hosts / 3,188.2 MiB at the read-only capture time, 2026-09-15T22:31:17.834Z:

Workflow start batch, UTC Task-complete event, UTC Minutes since completion Live extension hosts Summed working set, MiB
21:31 21:34:12.255 57.1 7 527.2
21:40 21:42:11.426 49.1 7 532.9
21:50 21:51:55.196 39.4 7 532.8
22:00 22:02:13.789 29.1 7 529.3
22:10 22:13:41.692 17.6 7 528.4
22:20 22:23:08.537 8.2 7 537.6

Working-set sums include shared pages. They are not measurements of unique physical memory or guaranteed reclaimable memory.

Steps to reproduce

This is the observed production usage pattern, not yet a clean-room minimal reproduction:

  1. On Windows, configure a local scheduled automation that starts a fresh session every ten minutes in the same workspace.
  2. Use a finite task that completes in less than ten minutes. Have several extensions installed; seven loaded per session in this observation.
  3. Leave the app running for several completed runs without restarting it. Confirm that the runs reuse the same pooled CLI.
  4. Record each session's terminal task-complete event and group extension-host processes by parent PID and creation time.
  5. Observe whether completed runs' batches disappear. Here, every observed scheduled run left seven hosts alive, including runs completed 29-57 minutes earlier.
  6. Observe the next scheduled run. Here it added seven more hosts while the previous batches remained.

Read-only process inspection, which avoids printing complete command lines:

$all = @(Get-CimInstance Win32_Process)
$byId = @{}
foreach ($p in $all) { $byId[[int]$p.ProcessId] = $p }

$all | Where-Object {
    $_.Name -eq 'copilot.exe' -and
    $_.CommandLine -match 'extension_bootstrap\.mjs'
} | ForEach-Object {
    $parent = $byId[[int]$_.ParentProcessId]
    [pscustomobject]@{
        Pid = $_.ProcessId
        ParentPid = $_.ParentProcessId
        Started = $_.CreationDate
        ParentAlive = (
            $null -ne $parent -and
            $parent.CreationDate -le $_.CreationDate
        )
        WorkingSetMiB = [math]::Round($_.WorkingSetSize / 1MB, 1)
    }
} | Sort-Object ParentPid, Started | Format-Table

Process counts alone do not establish a leak. In this observation, each batch was correlated with session-installation log timestamps, session ownership locks, and terminal session events. Parent creation times were checked to guard against PID reuse.

Expected behavior

Completed workflow sessions should release their runtime resources after an appropriate bounded idle period. Persisted history should remain accessible, but repeated finite workflow runs should not indefinitely accumulate runtime sessions, extension hosts, or MCP clients.

Cleanup must preserve unrelated active sessions sharing the same pooled CLI. Stopping the entire parent or trimming children by count is not a safe substitute for per-session cleanup.

Additional context

Evidence supporting session retention rather than a general failure to stop extension processes:

  • App logs show completed workflow sessions receiving subsequent live-session MCP refreshes, tens of minutes after task completion.
  • No corresponding session-destroy or SDK-event-loop-stop events were found for these six workflow sessions in the captured app log.
  • Other temporary sessions in this same CLI have explicit session.dispose events, and there were no surviving extension batches at those temporary sessions' creation timestamps.
  • The installed extension bootstrap has a parent-liveness guard. That does not address a completed session whose shared CLI parent remains alive.
  • A local missing-parent reaper was present. It does not select these live-parent extension trees, and its optional live-parent trimming was not enabled.

Selected timestamped lifecycle observations, with paths and session identifiers omitted:

22:00:27.167Z app: reusing warm CLI process from pool
22:00:27.169Z app: creating session, session_type=WorkflowWorkspace
22:00:30.496Z CLI: Installed 7 native extension(s) for session
22:02:13.789Z session events: session.task_complete
22:23:39.590Z app: extensibility live-session refresh completed
                     [same completed 22:00 workflow session]
22:30:29.225Z CLI: Installed 7 native extension(s) for session
                     [next scheduled run; earlier batches remain]

These are shortened field-level observations, not full raw log lines.

Confidence: high in the measured retention and recurring-workflow trigger. The exact source-code defect and ownership split between the desktop scheduler, CLI pool, and bundled CLI/SDK have not been established. The 20-minute threshold used in the local diagnostic was an observation threshold, not a claim about a documented eviction policy.

Suggested investigation: trace workflow completion and idle eviction through runtime session disposal and CLI-pool reference release. A useful regression test would run several finite workflows against one pooled CLI while another session remains active, then verify that completed workflows release their children without interrupting the active session. Include failure and cancellation paths.

Related reports:

No processes were terminated, app settings changed, or workflows disabled during capture. No restart-based recovery or code fix was tested.

Raw logs are not attached because they include private workspace information and conversation content. The report contains sanitized measurements and lifecycle observations only; the detailed process snapshots and correlation results have been retained locally.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by tracing workflow completion, runtime session disposal, idle eviction, and CLI-pool reference release. Build the suggested regression test with several finite workflows sharing one pooled CLI while another session remains active, including failure and cancellation paths. Done means completed workflows release their extension hosts without interrupting the active session.

Written by the indexing model from the issue text.

Assessment

Domain
cli, desktop, operating-systems
Issue type
Bug
Difficulty
5/5
Estimated time
Over a week
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
38/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.