Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
4c34562
feat(providers): add GitHub Copilot provider configuration types
Apr 23, 2026
445b95e
feat(providers): add GitHub Copilot community provider integration
Apr 23, 2026
9ad8f89
feat(providers): add Copilot provider registration and exports
Apr 23, 2026
4aed492
test(e2e): add GitHub Copilot provider smoke and abort tests
Apr 23, 2026
93c89ab
feat(copilot): add reasoning effort alias and session timeout improve…
Apr 23, 2026
1c5e35f
feat(copilot): add environment variable override support and auto mod…
Apr 23, 2026
9ece4b5
docs(copilot): clarify session option handling comment
Apr 23, 2026
e1cbc80
feat(copilot): add MCP, skills, agents, and structured output support
Apr 23, 2026
d54102e
feat(copilot): respect useLoggedInUser to override env token
Apr 23, 2026
178ce73
refactor(copilot): remove isCopilotModelCompatible and model-ref
Apr 28, 2026
ac31d33
fix(struct-out): enforce object requirement for structured output par…
Apr 28, 2026
6e1f5c3
feat(copilot): add isExecutableFile check for Copilot binary
Apr 28, 2026
707f736
feat(copilot): add PATH lookup for copilot binary resolution
Apr 28, 2026
ca6468e
ci(workflows): migrate and add Copilot CI workflows
Apr 30, 2026
79c6c41
refactor(shared): centralize structured-output parsing and skills
Apr 30, 2026
8eb51ab
feat(registry): register Copilot community provider
Apr 30, 2026
74ad739
feat(copilot): defer session error warning and harden abort flow
Apr 30, 2026
5b4fb8d
ci(workflow): simplify output capture in e2e-copilot-smoke workflow
Apr 30, 2026
bb12b82
ci(workflows): restructure Copilot e2e workflows for clarity
Apr 30, 2026
c553437
ci(workflow): remove e2e-copilot-all-features workflow
Apr 30, 2026
e8e0f86
feat(workflows): add e2e-copilot-all-nodes-smoke workflow
Apr 30, 2026
8ebe7bd
refactor(config): remove envOverrides support and COPILOT_MODEL usage
Apr 30, 2026
41508f7
docs: update Copilot docs and env sample
Apr 30, 2026
ab00dd7
feat(copilot): implement token precedence for Copilot auth
Apr 30, 2026
9994da6
fe​at(copilot): improve binary resolution and skill dir validation
Apr 30, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions .archon/workflows/test-workflows/e2e-copilot-abort.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# E2E manual abort test — GitHub Copilot community provider
# Verifies: Ctrl-C propagates through the bridge to session.abort() and
# sendAndWait unwinds cleanly without dangling listeners.
# Manual: start, wait for streaming to begin, press Ctrl-C. Not for CI.
name: e2e-copilot-abort
description: 'Manual test: start, then Ctrl-C. Verifies abort wiring.'
provider: copilot
model: gpt-5-mini

nodes:
- id: long
prompt: 'Count slowly from 1 to 200, one number per line, with a brief phrase after each number explaining its mathematical significance. Do not skip any numbers.'
effort: low
idle_timeout: 120000
147 changes: 147 additions & 0 deletions .archon/workflows/test-workflows/e2e-copilot-all-nodes-smoke.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
# E2E smoke test — Copilot provider, every CI-compatible node type
# Covers: prompt, command, loop (AI node types) + bash, script bun/uv
# (deterministic node types) + depends_on / when / trigger_rule / $nodeId.output
# (DAG features) + Copilot-specific options: effort, allowed_tools,
# output_format (best-effort JSON via prompt augment + 2-tier parser).
# Skipped: `approval:` — pauses for human input, incompatible with CI.
# Auth: `gh auth login` OR `COPILOT_GITHUB_TOKEN`.
# To use `GH_TOKEN` / `GITHUB_TOKEN`, also set `assistantConfig.useLoggedInUser: false`.
# Requires an active GitHub Copilot subscription.
name: e2e-copilot-all-nodes-smoke
description: 'Copilot provider smoke across every CI-compatible node type plus Copilot-specific options.'
provider: copilot
model: gpt-5-mini

nodes:
# ─── AI node types ──────────────────────────────────────────────────────

# 1. prompt: inline prompt + effort + allowed_tools (no tool calls).
# Verifies reasoningEffort and availableTools=[] reach the SDK.
- id: prompt-node
prompt: "Reply with exactly the single word 'ok' and nothing else."
allowed_tools: []
effort: low
idle_timeout: 30000

# 2. command: named command file (.archon/commands/e2e-echo-command.md).
# The command echoes back $ARGUMENTS (the workflow invocation message).
- id: command-node
command: e2e-echo-command
allowed_tools: []
idle_timeout: 30000

# 3. loop: iterative AI prompt until completion signal.
# Bounded by max_iterations: 2 so a misbehaving model can't hang CI.
- id: loop-node
loop:
prompt: "Reply with exactly 'DONE' and nothing else."
until: 'DONE'
max_iterations: 2
allowed_tools: []
effort: low
idle_timeout: 60000

# 4. output_format: Copilot's best-effort structured output path
# (prompt augmented with schema + 2-tier JSON parser on result text).
# Unique to Copilot/Pi vs. Claude/Codex native JSON mode — only an
# E2E test catches "real model drifted around the schema".
- id: structured-node
prompt: |
Return a JSON object with two fields, no fences and no prose:
- "status": always "ok" (string)
- "value": always 42 (number)
allowed_tools: []
effort: low
idle_timeout: 30000
output_format:
type: object
properties:
status:
type: string
value:
type: number
required: [status, value]

# ─── Deterministic node types (no AI) ───────────────────────────────────

# 5. bash: shell script with JSON output (enables $nodeId.output.status
# dot-access downstream).
- id: bash-json-node
bash: 'echo ''{"status":"ok"}'''

# 6. script: bun (TypeScript/JavaScript runtime)
- id: script-bun-node
script: echo-args
runtime: bun
timeout: 30000

# 7. script: uv (Python runtime)
- id: script-python-node
script: echo-py
runtime: uv
timeout: 30000

# ─── DAG features ───────────────────────────────────────────────────────

# 8. depends_on + $nodeId.output substitution
- id: downstream
bash: "echo 'downstream got: $prompt-node.output'"
depends_on: [prompt-node]

# 9. when: conditional (JSON dot-access on bash JSON output)
- id: gated
bash: "echo 'gated-ok'"
depends_on: [bash-json-node]
when: "$bash-json-node.output.status == 'ok'"

# 10. when: conditional on AI structured output (proves output_format
# parsed and dot-access works on the resulting object).
- id: structured-check
bash: "echo \"structured.status=$structured-node.output.status\""
depends_on: [structured-node]
when: "$structured-node.output.status == 'ok'"

# 11. trigger_rule: merge multiple deps (all_success semantics)
- id: merge
bash: "echo 'merge-ok'"
depends_on:
[downstream, gated, structured-check, script-bun-node, script-python-node]
trigger_rule: all_success

# ─── Final assertion ────────────────────────────────────────────────────

# 12. Verify every upstream node produced non-empty output, including
# dot-access on the structured-output node (proves output_format
# parsed and downstream consumers can index into it).
# Note: value-equality on string fields is avoided on purpose —
# shellQuote() wraps strings in literal single quotes, so a literal
# `[ "$x" != "ok" ]` would always fail. Non-emptiness is the right
# bar for a smoke; the `when:` gate on structured-check already
# proved the value matched 'ok' to reach this node.
- id: assert
bash: |
fail=0
check() {
local name="$1"
local value="$2"
if [ -z "$value" ]; then
echo "FAIL: $name produced empty output"
fail=1
fi
}
check prompt-node "$prompt-node.output"
check command-node "$command-node.output"
check loop-node "$loop-node.output"
check bash-json-node "$bash-json-node.output"
check script-bun-node "$script-bun-node.output"
check script-python-node "$script-python-node.output"
check downstream "$downstream.output"
check gated "$gated.output"
check merge "$merge.output"
check structured.status "$structured-node.output.status"
check structured.value "$structured-node.output.value"

if [ "$fail" -eq 1 ]; then exit 1; fi
echo "PASS: all node types + structured output verified"
depends_on: [merge, loop-node, command-node]
trigger_rule: all_success
14 changes: 13 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,18 @@ CODEX_REFRESH_TOKEN=
CODEX_ACCOUNT_ID=
# CODEX_BIN_PATH= # Optional: path to Codex native binary (binary builds only)

# GitHub Copilot (community provider — @github/copilot-sdk)
# Requires an active GitHub Copilot subscription. By default, Archon uses
# the credentials you configured via the Copilot CLI (`copilot login`).
# Generic GH_TOKEN / GITHUB_TOKEN (declared below) are intentionally NOT
# picked up — classic PATs lack Copilot entitlement and would fail. To
# opt back into env-token auth, set `useLoggedInUser: false` in
# `.archon/config.yaml`. Setting COPILOT_GITHUB_TOKEN is treated as
# explicit Copilot intent and always wins.
#
# COPILOT_GITHUB_TOKEN= # Copilot-scoped PAT (always wins when set)
# COPILOT_BIN_PATH= # Optional: path to Copilot CLI binary (binary builds only)

# Pi (community provider — @mariozechner/pi-coding-agent)
# One adapter, ~20 LLM backends. Archon's Pi adapter picks up credentials
# you've already configured via the Pi CLI (`pi /login` writes to
Expand All @@ -57,7 +69,7 @@ CODEX_ACCOUNT_ID=
# OPENROUTER_API_KEY= # Pi provider id: openrouter
# HUGGINGFACE_API_KEY= # Pi provider id: huggingface

# Default AI Assistant (must match a registered provider, e.g. claude, codex, pi)
# Default AI Assistant (must match a registered provider, e.g. claude, codex, copilot, pi)
# Used for new conversations when no codebase specified — errors on unknown values
DEFAULT_AI_ASSISTANT=claude

Expand Down
23 changes: 22 additions & 1 deletion bun.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions packages/core/src/config/config-loader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ const SAFE_ASSISTANT_FIELDS: Record<string, readonly string[]> = {
// community providers — list each field we're confident is safe to
// show in the web UI. Unknown providers fall through with no fields.
pi: ['model'],
copilot: ['model'],
};

function toSafeAssistantDefaults(assistants: AssistantDefaults): SafeConfig['assistants'] {
Expand Down
2 changes: 2 additions & 0 deletions packages/core/src/config/config-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,15 @@
import type {
ClaudeProviderDefaults,
CodexProviderDefaults,
CopilotProviderDefaults,
PiProviderDefaults,
ProviderDefaultsMap,
} from '@archon/providers/types';

export type {
ClaudeProviderDefaults,
CodexProviderDefaults,
CopilotProviderDefaults,
PiProviderDefaults,
ProviderDefaultsMap,
};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
title: AI Assistants
description: Configure Claude Code, Codex, and Pi as AI assistants for Archon.
description: Configure Claude Code, Codex, GitHub Copilot, and Pi as AI assistants for Archon.
category: getting-started
area: clients
audience: [user]
Expand All @@ -9,7 +9,7 @@ sidebar:
order: 4
---

You must configure **at least one** AI assistant. All three can be configured and mixed within workflows.
You must configure **at least one** AI assistant. All four can be configured and mixed within workflows.

## Claude Code

Expand Down Expand Up @@ -389,6 +389,95 @@ Unsupported YAML fields trigger a visible warning from the dag-executor when the
- [Adding a Community Provider](../contributing/adding-a-community-provider/) — the contributor-facing guide for extending Archon with your own provider.
- [Pi on GitHub](https://github.com/badlogic/pi-mono) — upstream project.

## GitHub Copilot (Community Provider)

**Use a GitHub Copilot subscription inside Archon workflows.** Drives the Copilot CLI via `@github/copilot-sdk`, supporting OpenAI, Anthropic via BYOK, Gemini, and the other models Copilot exposes — switch between them with the `model` field.

Copilot is registered as `builtIn: false` — like Pi, a bundled community provider rather than a core built-in.

### Install

For source installs (`bun run`), the SDK + its bundled CLI dependency come along with `bun install` — nothing extra to do.

For compiled Archon binaries, install the Copilot CLI yourself and point Archon at it:

```bash
npm install -g @github/copilot
```

Then tell Archon where the binary lives (the resolver searches these in order):

```ini
# .env
COPILOT_BIN_PATH=/absolute/path/to/copilot
```

```yaml
# .archon/config.yaml
assistants:
copilot:
copilotCliPath: /absolute/path/to/copilot
```

Or place the binary at `~/.archon/vendor/copilot/copilot` (POSIX) / `~/.archon/vendor/copilot/copilot.exe` (Windows) and the resolver picks it up automatically.

### Authenticate

By default, Copilot uses the credentials from your local `copilot login`. Generic `GH_TOKEN` / `GITHUB_TOKEN` env vars are **not** picked up automatically — classic GitHub PATs lack Copilot entitlement and would fail with a misleading SDK error. Auth precedence (highest to lowest):

1. **`COPILOT_GITHUB_TOKEN`** (env) — always wins when set; treated as explicit Copilot intent
2. **`useLoggedInUser: false`** in `.archon/config.yaml` — opts into env-token auth, including generic `GH_TOKEN` / `GITHUB_TOKEN`
3. **`copilot login` credentials** — the default

An active GitHub Copilot subscription is required for any of these to work.

### Copilot Configuration Options

You can configure Copilot's behavior in `.archon/config.yaml`:

```yaml
assistants:
copilot:
model: gpt-5-mini # 'gpt-5', 'gpt-5-mini', 'claude-sonnet-4.5', 'auto', etc.
modelReasoningEffort: medium # 'low' | 'medium' | 'high' | 'xhigh' | 'max' (alias for xhigh)
# configDir: /absolute/path/to/copilot-config
# enableConfigDiscovery: false # only enable for trusted repos — bypasses Archon's workflow MCP/skill validation
# useLoggedInUser: false # opt into env-token auth (GH_TOKEN / GITHUB_TOKEN); default uses `copilot login`
# logLevel: error # 'none' | 'error' | 'warning' | 'info' | 'debug' | 'all'
```

Copilot accepts OpenAI models (`gpt-5`, `gpt-5-mini`), Anthropic via BYOK (`claude-sonnet-4.5`), Gemini, and more. When no model is configured, Archon passes `model: 'auto'` and Copilot picks.

### Supported Archon Features

| Feature | Support | Notes |
|---|---|---|
| Session resume | ✅ | Returns `sessionId`; reused on resume |
| Reasoning control | ✅ | `effort:` / string `thinking:` → Copilot `reasoningEffort`; `max` maps to SDK `xhigh` |
| System prompt override | ✅ | `systemPrompt:` |
| Codebase env vars | ✅ | merged into the spawned Copilot CLI environment |
| Tool restrictions | ✅ | `allowed_tools` → `availableTools`, `denied_tools` → `excludedTools` |
| MCP servers | ✅ | `mcp: path/to/servers.json` → `SessionConfig.mcpServers` (env vars `$FOO` expanded; missing vars warned) |
| Skills | ✅ | `skills: [name]` resolved from `.agents/skills/` or `.claude/skills/` (project or home) → `SessionConfig.skillDirectories` |
| Structured output | ✅ | best-effort via prompt augmentation; unparseable output degrades to dag-executor's missing-output warning |
| Sub-agents (`agents:`) | ✅ | `name`/`description`/`prompt`/`tools` → `SessionConfig.customAgents`; Claude-specific fields (`model`, `disallowedTools`, `skills`, `maxTurns`) warn per agent and are ignored |
| Fork-session retry | ⚠️ | Copilot SDK has no fork API — when Archon requests a fork (on retry), we create a fresh session and emit a system-chunk warning |
| Hooks | ❌ | Archon hooks ≠ Copilot's `SessionHooks` event vocabulary |
| Fallback model | ❌ | not wired |
| Cost control | ❌ | no cost-limit API |
| Sandbox | ❌ | Copilot permissions surface is separate from Archon's sandbox model |

### Set as Default (Optional)

```ini
DEFAULT_AI_ASSISTANT=copilot
```

### See also

- [Adding a Community Provider](../contributing/adding-a-community-provider/) — the contributor-facing guide for extending Archon with your own provider.
- [`@github/copilot-sdk`](https://www.npmjs.com/package/@github/copilot-sdk) — upstream SDK.

## How Assistant Selection Works

- Assistant type is set per codebase via the `assistant` field in `.archon/config.yaml` or the `DEFAULT_AI_ASSISTANT` env var
Expand Down
Loading