github / github/copilot-cli

Custom agents missing from 'Environment loaded' startup message due to race condition

Open
#2,081 0 comments 1 reaction 0 assignees View on GitHub
area:agents
Dominant language
Shell
Stars
11.2k
Forks
1.9k
Avg merge
14h 16m
Merged PRs (30d)
6

Description

## Description

Custom agents defined in `.github/agents/` are properly detected and usable via `/agent`, but they do not appear in the "Environment loaded" startup message. The message shows instructions, skills, and MCP servers, but omits the agent count.

**Expected:** `Environment loaded: 4 custom instructions, 1 MCP server, 58 skills, 38 agents`
**Actual:** `Environment loaded: 4 custom instructions, 1 MCP server, 58 skills`

Agents are fully functional — `/agent` lists all 38 custom agents correctly.

## Root Cause Analysis

After analyzing `app.js` (v1.0.5), the startup reporter (`Ybt` class) fires its `onComplete` callback exactly once — the first time all **registered** participants are done. The issue is a registration timing race:

1. **Instructions** (`VIo`), **Skills** (`XIo`), and **Plugins** (`QIo`) register their reporter participants immediately via `useEffect`.
2. **Agents** (`FIo`) only registers its participant **after** the async `RAe` call completes (when `fI.loaded` becomes `true`).

```js
// Agents only register when loaded — too late if others already completed
(0,ke.useEffect)(()=>{
fI.loaded && FIo(YI, fI.available.length)
}, [YI, fI.available.length, fI.loaded]);
```

If instructions, skills, and plugins all complete before `fI.loaded` becomes `true`, the reporter sees all registered participants as done, fires `onComplete`, and the startup message is emitted **without agents**. When agents finally load and `FIo` registers a new participant, the completion callback has already been emitted (guarded by `_completionEmitted` flag).

The `RAe` function includes a remote API call (`/agents/swe/custom-agents/{owner}/{repo}`) which adds latency, making this race likely for repos with many agents or slower API responses.

## Suggested Fix

**Option A: Pre-register the agents participant before async loading starts**

Register the "agents" participant eagerly so the reporter waits for it:

```js
// Register immediately, report items later when loaded
(0,ke.useEffect)(() => {
let participant = YI.register("agents");
// Will be updated when agents load
return () => {}; // cleanup
}, [YI]);

(0,ke.useEffect)(() => {
if (fI.loaded) {
// Reporter already knows about "agents" participant, just update and mark done
FIo(YI, fI.available.length);
}
}, [YI, fI.available.length, fI.loaded]);
```

**Option B: Add a timeout/debounce to the reporter completion**

Delay the `onComplete` emission briefly (e.g., 500ms) to allow async participants to register, or use a known list of expected participants.

## Environment

- **CLI version:** 1.0.5
- **OS:** macOS (Darwin arm64)
- **Node.js:** v24.11.1
- **Custom agents:** 38 (in `.github/agents/`)
- **Reproduction:** Consistent across multiple CLI restarts

## Steps to Reproduce

1. Create a repository with 30+ custom agents in `.github/agents/`
2. Launch `copilot` in the repository
3. Observe the "Environment loaded" message — agents are missing
4. Run `/agent` — all agents are listed correctly

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.