Skip to content

Configuration

CopilotTask configures a session; the task is passed separately to copilot_run. This page covers the common settings. The API reference contains the full signature.

Authentication

Supported authentication paths:

  • gh auth login --hostname github.com
  • GITHUB_TOKEN or GH_TOKEN in CI or automation

Task sessions select GITHUB_TOKEN first, then GH_TOKEN. If neither is set, the SDK uses its signed-in user. Tokens must authorize the intended GitHub account and Copilot access.

The framework uses GitHub Copilot. There is no separate provider configuration.

CopilotTask

from pytest_copilot.copilot import CopilotTask


agent = CopilotTask(
    name="my-task",
    model="gpt-5.6-sol",
    instructions="Use the supplied tools to complete the user's task.",
    timeout_s=120,
    max_tool_calls=10,
)

Common settings

Field Meaning
name Label identifying the configuration in saved evidence
model Copilot model name; None uses Copilot's default
instructions System prompt content; distinct from the user task
system_message_mode append by default; replace replaces the SDK system message content
response_schema Optional Pydantic model class defining the final JSON answer
working_directory Session workspace; not a security sandbox
mcp_servers Copilot SDK server config mapping
allowed_tools Optional global tool allow-list
excluded_tools Tool block-list
custom_agents Loaded .agent.md definitions
active_agent Custom agent to activate at session start
skill_directories Explicit individual skill directories or parents; enable loading and check SDK availability before sending
disabled_skills Skill names deliberately disabled, retained in discovery evidence
max_turns Advisory top-level turn budget; used for subagent turn caps
timeout_s Hard wall-clock limit for the run
max_tool_calls Optional hard tool-admission budget; nonnegative integer
auto_confirm Auto-approve permission requests by default
audit_requests Capture actual outgoing request metadata when enabled
client_mode copilot-cli by default; empty disables ambient configuration and persona injection
extra_config SDK settings not exposed as direct fields; overrides subject to validation

Limits and permissions

max_turns is not a hard top-level limit. Use timeout_s and, where appropriate, max_tool_calls to bound execution. Tool admission does not prove a tool completed or the application operation succeeded.

auto_confirm=True is convenient for deterministic tests, but it is not an isolation boundary. Restrict tools and use guarded adapters and an approved execution environment. A temporary working directory alone does not prevent filesystem or network access.

One attempt per call

Each copilot_run call makes one execution attempt. Startup, connection, and task failures are recorded without automatically starting another session. Rerun a selected pytest case explicitly when appropriate.

JSON answers with a required shape

Pass a Pydantic model class as response_schema to request a JSON answer with specific fields and types. The SDK checks the final answer against that model. An invalid answer fails the run; the framework does not retry or repair it.

from pydantic import BaseModel, ConfigDict

from pytest_copilot.copilot import CopilotTask


class Answer(BaseModel):
    model_config = ConfigDict(extra="forbid", strict=True)
    count: int


async def test_count(copilot_run):
    agent = CopilotTask(
        name="count",
        client_mode="empty",
        response_schema=Answer,
    )
    result = await copilot_run(agent, "What is 19 plus 23? Return the count.")
    assert result.success, result.error
    assert result.final_response is not None
    answer = Answer.model_validate_json(result.final_response)
    assert answer.count == 42

final_response stays the original answer text. The configuration snapshot and saved JSON contain the requested JSON schema, not the Python class. The setting applies only to the parent's final answer; framework-owned child sessions do not inherit it. Omit it for ordinary text answers.

A matching shape does not establish that the answer is correct. Keep ordinary assertions against the expected values or actual application output.

Explicit skills and empty mode

Nonempty skill_directories set the public SDK enable_skills=True by default. enable_config_discovery remains false. In empty mode, personal/project discovery, custom instructions, file hooks, managed settings, and persona injection stay disabled. Explicit tools and system prompt content remain supported.

Explicit directories combined with extra_config={"enable_skills": False} are rejected, not silently ignored. None leaves the explicit-skills default enabled. An empty directory list plus enable_skills=False is allowed. Use disabled_skills to deliberately disable named skills within an otherwise loaded set.

Every requested directory must contain a valid SKILL.md or immediate child skill directories. Relative paths use the Python caller's current directory. Validation and public SDK discovery run before the task is sent; setup failure is recorded as an execution error with no model send. SDK metadata and diagnostics are available as result.skill_discovery and in native JSON, separately from reads. See Skills for input and evidence details.

MCP server mappings

Attach servers directly to CopilotTask(mcp_servers={...}).

SDK configuration discovery is disabled by default. Personal or ambient MCP configuration is not automatically attached to task sessions. Supply servers, skills, and custom agents explicitly, or use the configuration loaders for the project under test.

To test SDK discovery deliberately, opt in:

agent = CopilotTask(
    name="configuration-discovery",
    extra_config={"enable_config_discovery": True},
)

This opt-in can expose machine-specific tools and configuration; avoid it in tests intended to be reproducible across developer machines and CI.

For example, attach the bundled Banking server over stdio:

import sys

BANKING_MCP = {
    "banking": {
        "command": sys.executable,
        "args": ["-m", "pytest_copilot.testing.banking_mcp"],
        "tools": ["*"],
    }
}

Remote transports use the same mapping:

REMOTE_MCP = {
    "crm": {
        "type": "http",
        "url": "https://mcp.example.com/mcp",
        "headers": {"Authorization": "Bearer ${CRM_TOKEN}"},
        "tools": ["*"],
    }
}

Command-line tools

Use create_command_tool from pytest_copilot.copilot for direct executable calls with separate arguments, including native help, setup, and supporting commands. Attach tools through extra_config={"tools": [tool]}; use client_mode="empty" and allowed_tools to expose only the intended tools. No shell or MCP wrapper is needed. Consumers still own application permissions and independent checks. See Test CLI tools for the shared helper's input, output, time limits, and shell-specific exceptions.

pytest configuration

[tool.pytest.ini_options]
asyncio_mode = "auto"
addopts = """
--aitest-json=aitest-reports/results.json
"""

pytest-copilot init adds these settings to an existing project. It reports conflicting values instead of replacing them.

Use CLI options for repetition and evidence flags, CopilotResult for returned fields, and assertions for independent output checks. Saved evidence requires the current schema exactly; loading it does not execute a model.