Invoke Copilot CLI Sub-Session
Use this skill when a main session (in Copilot CLI or VS Code) needs to spawn a fresh, isolated Copilot CLI sub-session with full control over its identity and runtime.
When to use
- Run a long or risky sub-workflow in a separate process that does not pollute the main session context.
- Pin a specific custom agent to the sub-session.
- Pin a specific BYOK provider / model for the sub-session (default:
opencode-go-deepseek-v4-flash, reasoning-efforthigh; per-model levels are grounded in thecopilot-byokskill'sreferences/reasoning-effort-lookup.md). - Self-generate a session name (
--name) and session UUID (--session-id) so the main session can send follow-up prompts to the same sub-session. - Capture structured output (text or JSONL) for programmatic parsing.
What it produces
- A PowerShell script:
scripts/Invoke-CopilotCliSubSession.ps1. - This skill guides the agent to call that script with the correct parameters. The agent should proactively assign a descriptive
-Namein kebab-case. - By default the sub-session inherits the main session's MCP servers and custom instructions (same working directory, same
~/.copilot/).
Quick start
# Minimal invocation — uses default BYOK profile (opencode-go-deepseek-v4-flash) at reasoning-effort high
.\scripts\Invoke-CopilotCliSubSession.ps1 `
-Name "analyze-async" `
-Prompt "Analyze the project structure and list all async methods."
# Specific agent, model override, named session, multi-line prompt
.\scripts\Invoke-CopilotCliSubSession.ps1 `
-Name "security-audit" `
-Agent "security-auditor" `
-Model "claude-opus-4.5" `
-SessionId "a1b2c3d4-e5f6-7890-abcd-ef1234567890" `
-Prompt @"
Review the codebase for security vulnerabilities:
1. Check for SQL injection in data access layer
2. Audit authentication middleware
3. Verify CSRF protection is active
4. Report findings with severity levels
"@
# Invoke a built-in command or skill via slash command
.\scripts\Invoke-CopilotCliSubSession.ps1 `
-SlashCommand "handoff" `
-Prompt "Describe the current session state" `
-Name "session-handoff"
# Invoke a skill without extra prompt
.\scripts\Invoke-CopilotCliSubSession.ps1 `
-SlashCommand "git-atomic-commit" `
-Name "auto-commit"
# Invoke with a custom agent
.\scripts\Invoke-CopilotCliSubSession.ps1 `
-Agent "dotnet-diag:optimizing-dotnet-performance" `
-Name "perf-analysis" `
-Prompt "Scan for async anti-patterns"
# Context handoff: list relevant file paths; sub-session reads them itself
.\scripts\Invoke-CopilotCliSubSession.ps1 `
-Name "exec-plan" `
-Prompt @"
Execute the implementation plan at:
c:/Workplace/my-repo/openspec/changes/auth-impl/plan.md
c:/Workplace/my-repo/openspec/changes/auth-impl/tasks.md
Reference specs:
c:/Workplace/my-repo/openspec/specs/auth/spec.md
Working directory: c:/Workplace/my-repo
Read each file before executing. Report progress after each step.
"@
# Chain two prompts on the same sub-session by reusing SessionId
$uuid = "b2c3d4e5-f6a7-8901-bcde-f12345678901"
$r1 = .\scripts\Invoke-CopilotCliSubSession.ps1 `
-Name "research-auth" `
-SessionId $uuid `
-Prompt "Research this repo's authentication approach." `
-JsonOutput
$r2 = .\scripts\Invoke-CopilotCliSubSession.ps1 `
-Name "research-auth" `
-SessionId $uuid `
-Prompt "Based on the research, propose three security improvements." `
-JsonOutput
Required vs optional parameters
| Parameter | Required | Default | Purpose |
|-----------|----------|---------|---------|
| -SlashCommand | No | — | Built-in command or skill name to invoke (e.g., handoff, git-atomic-commit, plan, review). Script prepends /. When given with -Prompt, the prompt becomes the command argument. At least one of -SlashCommand or -Prompt is required. |
| -Prompt | No* | — | The task prompt, or argument to -SlashCommand when both are given. Supports multi-line (here-strings, `n, literal newlines). *Required when -SlashCommand is not provided. |
| -Name | No | — | Human-readable session name (--name). Use kebab-case slugs (e.g. "analyze-async"). The agent should proactively generate one. |
| -SessionId | No | auto-generated UUID | Custom UUID for --session-id. Must be valid UUID format. When omitted, a UUID is auto-generated. Reuse the same value across calls to chain messages on the same session. |
| -Agent | No | — | Custom agent name. Qualify plugin agents as plugin:agent-name (colon, e.g. dotnet-diag:optimizing-dotnet-performance). Repo agents use bare name. |
| -Model | No | — | Model override. Takes precedence over the BYOK profile's model. |
| -ByokProfile | No | opencode-go-deepseek-v4-flash | BYOK profile name from ~/.copilot/byok-profiles.json. |
| -ByokAccount | No | — | Account override for account-grouped profiles (e.g., multiple OpenCode Go subscriptions). Takes precedence over the profile's account pin and the config-level activeAccount. When omitted, the profile pin or activeAccount is used. |
| -ReasoningEffort | No | high | none, minimal, low, medium, high, xhigh, max (per-model subset may vary; minimal is newer — verified in CLI 1.0.77). The default BYOK profile (opencode-go-deepseek-v4-flash) runs at high by default. For the grounded per-model lookup — which levels a model supports and whether to omit the flag — see the copilot-byok skill's references/reasoning-effort-lookup.md. |
| -WorkingDir | No | current location | Working directory for the sub-process. |
| -JsonOutput | Switch | off | Emit JSONL instead of plain text. |
| -NoAllowAll | Switch | off | Opt out of --allow-all --no-ask-user. By default the sub-session runs with full permissions. |
| -DisableBuiltInMcps | Switch | off | Isolate from main session's MCP servers. |
| -NoCustomInstructions | Switch | off | Skip project custom instructions. |
| -TimeoutSeconds | No | 600 | Kill the sub-process after N seconds. |
| -Passthrough | No | — | Extra arguments forwarded to copilot. |
Session naming (-Name)
The agent should always assign a meaningful -Name in kebab-case that describes the sub-session's purpose:
"research-csrf-patterns"— a research task"implement-oauth-middleware"— an implementation task"review-pr-142"— a review task
This name appears in copilot --resume listings and session logs. It is distinct from -SessionId (the UUID used for programmatic chaining). Pass both: -Name for human readability, -SessionId for script-level chaining.
Choosing a session ID
- Auto-generated: when
-SessionIdis omitted, a valid UUID is auto-generated usingNew-Guid. Every call gets a fresh session unless you reuse the same UUID. - Explicit UUID: pass a valid UUID (
xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx). Invalid UUIDs trigger a warning and are replaced with an auto-generated one. - Follow-up to the same sub-session: reuse the exact same
-SessionIdvalue; the prior session state is reloaded via--session-id. - Valid UUIDs only:
--session-idrequires standard format (xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx).
Multi-line prompts
-Prompt accepts multi-line strings natively. Use PowerShell here-strings for multi-paragraph task descriptions:
.\scripts\Invoke-CopilotCliSubSession.ps1 `
-Name "code-review" `
-Prompt @"
Review the following PR checklist:
1. Verify all edge cases are covered
2. Check for proper error handling
3. Ensure tests pass with >80% coverage
4. Validate API contract changes
Report findings in a markdown table.
"@
Inline newlines via `n also work: -Prompt "Line 1nLine 2nLine 3".
Slash command invocation (-SlashCommand)
-SlashCommand wraps Copilot CLI's interactive slash commands for non-interactive use. Pass just the command name (no leading /) — the script prepends / automatically.
Supported commands: Any built-in CLI command (help, model, init, diff, pr, review, plan, research, delegate, rewind, compact, share, allow-all, add-dir, skills) and any installed skill (git-atomic-commit, handoff, mermaid-creator, etc.).
# Slash command only
.\scripts\Invoke-CopilotCliSubSession.ps1 -SlashCommand "plan" -Name "planning-pass"
# Slash command with arguments (Prompt becomes the argument)
.\scripts\Invoke-CopilotCliSubSession.ps1 -SlashCommand "handoff" -Prompt "Describe session results" -Name "handoff-pass"
# Equivalent freeform prompt (also valid)
.\scripts\Invoke-CopilotCliSubSession.ps1 -Prompt "/handoff Describe session results" -Name "handoff-pass"
Multi-step orchestration pattern:
# Plan → Execute → Review with slash commands
.\scripts\Invoke-CopilotCliSubSession.ps1 -SlashCommand "plan" -Prompt "Implement user auth" -Name "plan-auth" -SessionId $uuid
.\scripts\Invoke-CopilotCliSubSession.ps1 -Prompt "Execute the plan above" -Name "exec-auth" -SessionId $uuid
.\scripts\Invoke-CopilotCliSubSession.ps1 -SlashCommand "review" -Name "review-auth" -SessionId $uuid
Custom agent invocation (-Agent)
Pin a specific agent to the sub-session. Plugin agents use colon: plugin:agent-name. Repo agents use bare name.
# Plugin agent
.\scripts\Invoke-CopilotCliSubSession.ps1 `
-Agent "dotnet-diag:optimizing-dotnet-performance" `
-Prompt "Analyze this project's performance" `
-Name "perf-analysis"
# Repo agent (discovered from .github/agents/)
.\scripts\Invoke-CopilotCliSubSession.ps1 `
-Agent "my-custom-agent" `
-Prompt "Execute the workflow" `
-Name "custom-workflow"
Agent discovery paths (in precedence order):
~/.copilot/agents/(user-level).github/agents/(repo-level)plugin:agent-name(qualified, from installed plugins)
The agent is invoked via the Copilot CLI --agent flag and inherits the sub-session's model, BYOK config, and all other parameters.
Context handoff convention
When delegating to a sub-session, always prioritize listing the full absolute paths of relevant files in -Prompt. The sub-session can read those files itself using its own tools (cat, grep, read). Only embed content inline when the context is short and simple enough to fit in a single message.
Why
- The sub-session starts with a blank context — it does not know what files the main session worked with, what decisions were made, or what artifacts exist.
- MCP and custom instructions inheritance provides environment (tools, config), not session memory.
- Listing file paths is cheaper, avoids duplication, and lets the sub-session choose what to read in depth.
Do this
# PREFERRED — list full paths; sub-session reads files itself
.\scripts\Invoke-CopilotCliSubSession.ps1 `
-Name "exec" `
-Prompt @"
Execute the implementation plan at:
c:/Workplace/my-repo/openspec/changes/auth-impl/plan.md
c:/Workplace/my-repo/openspec/changes/auth-impl/tasks.md
Reference specs:
c:/Workplace/my-repo/openspec/specs/auth/spec.md
Start from working directory: c:/Workplace/my-repo
After each step, report progress.
"@
# EXCEPTION — directly embed only when context is short and simple
.\scripts\Invoke-CopilotCliSubSession.ps1 `
-Name "quick-fix" `
-Prompt "Fix the typo in src/utils/helpers.ts line 42: change 'teh' to 'the'."
Practical workflow
- Identify the relevant files from the main session (plan, research, spec, ADR, design doc, task list).
- List their full absolute paths in the
-Promptargument, grouped by role. - Include the working directory and the final instruction — what the sub-session should produce.
- Only embed content inline (via here-string) when the context is trivially short (a few lines).
- Use the returned
SessionIdto chain follow-up messages if the task requires multiple turns.
What to reference
| Context type | Files to reference by path |
|--------------|----------------------------|
| Implementation plan | openspec/changes/*/plan.md, openspec/changes/*/tasks.md |
| Research findings | openspec/research/*.md, docs/design-docs/*.md |
| Specifications | openspec/specs/**/spec.md, requirements/*.md |
| Active task checklist | Current todo list, task breakdown |
| Configuration / conventions | .github/git-scope-constitution.md, relevant *.agent.md |
| Copilot CLI session state | ~/.copilot/session-state/<session-uuid>/ (see below) |
Copilot CLI session-state handoff
When the main session is itself a Copilot CLI session, its session state is persisted under ~/.copilot/session-state/<session-uuid>/. These files capture what the main session already worked on — plans, research, file changes, and checkpoints. Forward them to the sub-session so it does not start from scratch.
| File / Dir | Description |
|------------|-------------|
| plan.md | The implementation plan generated by /plan. The sub-session should read this to understand what to build and in what order. |
| research/ | Output from /research. Contains search results, analyzed code snippets, and external references the main session already gathered. |
| files/ | File snapshots or diffs touched during the session. Lets the sub-session see what was changed without re-reading the whole repo. |
| checkpoints/ | Session checkpoints. Useful for resuming work from a specific point if the sub-session needs to continue where the main session left off. |
How to discover the session UUID:
# List all session IDs
Get-ChildItem "$HOME\.copilot\session-state" -Directory | Select-Object Name
# Or get the latest session
Get-ChildItem "$HOME\.copilot\session-state" -Directory |
Sort-Object LastWriteTime -Descending |
Select-Object -First 1 -ExpandProperty Name
How to reference in -Prompt:
# PREFERRED — pass knowledge from previous session
.\scripts\Invoke-CopilotCliSubSession.ps1 `
-Name "continue-from-session" `
-Prompt @"
Continue the work from the previous Copilot CLI session.
Session state is at:
~/.copilot/session-state/a1b2c3d4-e5f6-7890-abcd-ef1234567890/
Review these files before executing:
~/.copilot/session-state/a1b2c3d4-e5f6-7890-abcd-ef1234567890/plan.md
~/.copilot/session-state/a1b2c3d4-e5f6-7890-abcd-ef1234567890/research/
~/.copilot/session-state/a1b2c3d4-e5f6-7890-abcd-ef1234567890/files/
Working directory: c:/Workplace/my-repo
Continue from where the plan left off.
"@
Note: The session-state directory is tied to the main session's UUID. The sub-session gets its own separate session-state (under its own --session-id). Forwarding the main session's state paths is what bridges the gap.
Path formatting
- Use absolute paths (
c:/Workplace/my-repo/...) so the sub-session can read them regardless of its working directory. - If the sub-session's
-WorkingDirmatches the repo root, relative paths rooted there also work. - Group paths by purpose with a short header line before each group.
MCP and custom instructions inheritance
By default the sub-session inherits the main session's MCP servers and custom instructions because:
- It runs in the same working directory (project-level
.mcp.json,.github/mcp.json,copilot-instructions.mdare picked up). - It uses the same
~/.copilot/directory (user-levelmcp-config.json, agents, skills).
To isolate the sub-session, pass -DisableBuiltInMcps and/or -NoCustomInstructions. To fully isolate, set -ConfigDir (mapped to $env:COPILOT_HOME for the sub-process) to a separate config tree.
BYOK profile handling
The script looks up the profile in ~/.copilot/byok-profiles.json (or $env:COPILOT_HOME/byok-profiles.json). The default profile is opencode-go-deepseek-v4-flash.
It maps profile fields to environment variables:
COPILOT_PROVIDER_BASE_URL
COPILOT_PROVIDER_TYPE
COPILOT_MODEL
COPILOT_PROVIDER_API_KEY
COPILOT_PROVIDER_WIRE_API
COPILOT_PROVIDER_MAX_PROMPT_TOKENS
COPILOT_PROVIDER_MAX_OUTPUT_TOKENS
COPILOT_OFFLINE
If the profile contains proxyPort, the script routes the request through the local Moonshot proxy (https://moonshot.local/v1) used by copilot-byok.
A -Model parameter, when provided, takes precedence over the profile's model.
Reasoning effort per model
The script forwards --reasoning-effort (default high) only when the resolved profile supports it. If the profile carries "reasoningEffortSupported": false (models whose API exposes no controllable levels — e.g., Kimi K2.x, GLM, MiMo, Qwen3.x, MiniMax), the argument is stripped with a warning, mirroring byok-profile.ps1 run. The authoritative per-model lookup — which levels a model supports and the recommended default — is the copilot-byok skill's references/reasoning-effort-lookup.md. For the default profile (deepseek-v4-flash), high is within the supported low/medium/high range.
Copilot SDK parity & keeping up
The CLI flag surface, COPILOT_* env vars, the .NET SDK (copilot-sdk-dotnet), and VS Code chatLanguageModels.json are four façades over the same Copilot CLI engine. The single source of truth for how they map is the capability parity matrix — update it whenever a new capability appears in any surface, and link it from new reference material instead of re-documenting equivalence.
To detect drift between this skill's documented surface and the installed CLI, run the parity gate before publishing:
.\scripts\Test-CopilotCliParity.ps1
The gate compares documented flags, env vars, and reasoning-effort levels against copilot --help / copilot help environment, exits non-zero on drift, and lists new capabilities the CLI gained that the skill does not document yet. After re-verifying, bump lastVerified / verifiedCliVersion in this skill's frontmatter and the Verified column of the matrix.
Historical (v1.0.77, resolved 2026-08-03): --config-dir is no longer listed in CLI help; -ConfigDir maps to COPILOT_HOME for the sub-process (the supported config-override mechanism).
Output
By default the script returns a plain-text block. With -JsonOutput it returns JSONL; the final result line contains exitCode and usage.
The script prints a structured result object (metadata only — StdOut is written to the console directly):
[PSCustomObject]@{
ExitCode = $proc.ExitCode
SlashCommand = $SlashCommand
Name = $Name
SessionId = $SessionId
Agent = $Agent
Model = $env:COPILOT_MODEL
ByokProfile = $ByokProfile
}
Safety rules
- Always assign a descriptive
-Namein kebab-case. -NoAllowAlllets you opt out of the default--allow-all --no-ask-userfor read-only or untrusted contexts.- The sub-session inherits MCP and custom instructions by default; use
-DisableBuiltInMcpsor-NoCustomInstructionsonly when isolation is intended. - The sub-process inherits the main session's environment except where the script overrides it.