Files
Clay Good 73207a6f2c feat(copilot): make cloud coding-agent files opt-in (#1517)
* feat(copilot): make cloud coding-agent files opt-in

Selecting the `github-copilot` tool auto-generated a GitHub Actions
workflow (.github/workflows/copilot-setup-steps.yml) plus an agent file.
Writing into a user's CI on init/update is invasive, benefits only the
narrow set of Copilot *cloud* coding-agent users, and couples us to
GitHub's externally-owned custom-agent format.

Cloud files are now opt-in:
- `openspec init` prompts before generating them (default No) and records
  the choice in openspec/config.yaml (`githubCopilot.cloudAgent`).
- `--copilot-cloud` / `--no-copilot-cloud` decide non-interactively.
- `openspec update` never prompts; it only refreshes files for projects
  that opted in, or that already have generated cloud files (so existing
  setups keep working — the migration path).

The pre-existing content-matching guarantees are unchanged and now proven
by regression tests: a user-customized cloud file is never overwritten or
deleted. Opt-in state is persisted via the YAML document model so the
user's hand-authored config comments and formatting survive untouched.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* feat(copilot): polish the cloud opt-in — safety, UX, and docs

Follow-up hardening driven by a five-agent review swarm over the opt-in.

Correctness:
- persistCopilotCloudOptIn no longer throws on a scalar/`null` config file
  (reproduced crash); it starts a fresh map while preserving comment-only
  and empty files.
- Explicit opt-out (`--no-copilot-cloud` / `cloudAgent: false`) now removes
  OpenSpec-managed cloud files on both init and update, instead of orphaning
  them. Customized files are still never touched.
- `--copilot-cloud` / `--no-copilot-cloud` warns when github-copilot isn't
  among the selected tools, instead of silently no-opping.

UX / discoverability:
- init prints whether cloud files were written or, when skipped for want of
  a signal, how to enable them (`--copilot-cloud`).
- When the user opts in but already has their own copilot-setup-steps.yml or
  agent file, init/update say it was left untouched and that the OpenSpec
  install step must be added by hand — the direct answer to "will this affect
  my existing Copilot cloud agent?".
- Clearer interactive prompt (names both files; distinguishes the GitHub-hosted
  cloud agent from Copilot in the editor); a dim, interactive-only, decision-
  gated hint on `openspec update`; tightened flag help text.

Docs (the feature was undocumented): new "GitHub Copilot cloud coding agent"
section in supported-tools.md; init flags in cli.md; the githubCopilot.cloudAgent
key in customization.md.

Tests: interactive prompt (accept/decline), opt-out removal + customized-file
preservation, config.yml variant, scalar-config regression, collision
reporting, flag-ignored warning, re-init honoring persisted opt-in, and the
config parse/warn branches. 2763 tests pass; the only failures are pre-existing
and unrelated (completion mocks, adapters loader, one config-profile PATH case,
one experimental-alias case), verified identical on clean main.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix(copilot): make init cloud-file output honest; harden config guard

Final hardening pass (adversarial review of the opt-in polish).

- init's success line listed both cloud-file paths from the *decision* to
  write, not from what was written — so it claimed files that a write
  skipped (user already owns them) or that the alternate-agent path removed.
  It now lists only OpenSpec-managed files that actually exist after the
  write (listManagedCloudFiles), keeps the "left untouched" caveat for
  user-owned files, and reports opt-out removals in the normal output block.
- persistCopilotCloudOptIn's non-map guard used isCollection, which is also
  true for sequences, so a YAML list at the config root still made setIn
  throw. Gate on isMap so scalars AND sequences fall back to a fresh
  document; empty/comment-only files still round-trip with comments intact.
- Fixed a misleading catch comment on the opt-out removal path.

Tests: success-line accuracy over a user-owned file, sequence-root config
regression, and listManagedCloudFiles coverage. 318 tests pass across the
touched suites; build + lint clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix(copilot): replace a non-map githubCopilot node before setIn

Addresses alfred review on #1517. The prior guard only fixed a non-map
config *root*; a valid top-level map whose `githubCopilot` value is itself a
scalar/null/sequence (`githubCopilot: false`, `null`, or a list) still made
`setIn(['githubCopilot','cloudAgent'], ...)` throw, which init swallowed —
so the explicit opt-in/out was never saved. Now the intermediate node is
replaced with an empty map before descending, keeping the rest of the config
and its comments intact.

Regression covers all three reproduced cases (false/null/sequence). Full
suite: 2770 pass; only the pre-existing unrelated failures remain.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix(copilot): never throw persisting into an unparseable config

Deeper pass on persistCopilotCloudOptIn (the function alfred flagged), driven
by an exhaustive input-shape check. Two malformed inputs still threw at
toString(): a multi-document YAML stream and a tab-indented (syntactically
invalid) file. Such a file can't be edited without corrupting it, so persist
now detects parse errors and leaves it untouched (no throw, no clobber) — it
is already invalid, so readProjectConfig ignores it regardless.

With this the function is throw-free across every shape exercised: empty,
comment-only, scalar/sequence root, a non-map githubCopilot value, anchors,
CRLF, BOM, and the two malformed cases (now skipped byte-identical).

Regression added for the multi-document case. Touched suites: 314 pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-05 18:51:26 +00:00

15 KiB

Customization

OpenSpec provides three levels of customization:

Level What it does Best for
Project Config Set defaults, inject context/rules Most teams
Custom Schemas Define your own workflow artifacts Teams with unique processes
Global Overrides Share schemas across all projects Power users

Project Configuration

The openspec/config.yaml file is the easiest way to customize OpenSpec for your team. It lets you:

  • Set a default schema - Skip --schema on every command
  • Inject project context - AI sees your tech stack, conventions, etc.
  • Add per-artifact rules - Custom rules for specific artifacts
  • Add per-operation guidance - Advisory preferences for apply and archive work
  • Remember integration choices - e.g. the GitHub Copilot cloud coding agent opt-in

Quick Setup

openspec init

This walks you through creating a config interactively. Or create one manually:

# openspec/config.yaml
schema: spec-driven

context: |
  Tech stack: TypeScript, React, Node.js, PostgreSQL
  API style: RESTful, documented in docs/api.md
  Testing: Jest + React Testing Library
  We value backwards compatibility for all public APIs

rules:
  proposal:
    - Include rollback plan
    - Identify affected teams
  specs:
    - Use Given/When/Then format
    - Reference existing patterns before inventing new ones

operations:
  apply:
    guidance:
      - Run focused tests before the full suite
  archive:
    guidance:
      - Keep the completion summary concise

# Set by `openspec init` when you choose (or decline) the GitHub Copilot
# cloud coding agent; controls whether `init`/`update` generate its files.
githubCopilot:
  cloudAgent: false

How It Works

Default schema:

# Without config
openspec new change my-feature --schema spec-driven

# With config - schema is automatic
openspec new change my-feature

Context and rules injection:

When generating any artifact, your context and rules are injected into the AI prompt:

<context>
Tech stack: TypeScript, React, Node.js, PostgreSQL
...
</context>

<rules>
- Include rollback plan
- Identify affected teams
</rules>

<template>
[Schema's built-in template]
</template>
  • Context appears in ALL artifacts
  • Rules ONLY appear for the matching artifact

Operation guidance:

operations.apply.guidance and operations.archive.guidance are optional arrays of advisory instructions for how an agent should conduct those operations. They are separate from rules: operation guidance does not constrain artifact content, and artifact rules are never relabeled as operation guidance.

Apply and archive fetch these inputs at execution time:

openspec instructions apply --change my-feature --json
openspec instructions archive --change my-feature --json

Both surfaces return current project context and matching operationGuidance as separate optional fields. Each invocation reads a fresh snapshot from the resolved root. When --store <id> is selected, the change, context, and guidance all come from that store rather than the current repository. The archive instruction command is read-only: it does not inspect or merge delta specs, write main specs, move the change, or run the static archive workflow.

Project context is a required prompt-level input. Generated workflows read it and apply relevant project facts, conventions, and constraints. Operation guidance is optional additive advice: workflows consider every entry and follow entries that are applicable and compatible with the built-in workflow.

Both fields remain separate from CLI-controlled state, resolved paths, built-in steps, explicit user choices, and artifact rules. A workflow reports context conflicts while preserving the controlling value. It does not follow inapplicable or conflicting guidance and explains why. Neither field is an enforceable check, and workflows do not copy their text into implementation files, specs, change artifacts, or summaries unless the user separately requests that content.

Archive and spec-sync input safety:

Archive, bulk archive, and standalone sync use artifactPaths.specs.existingOutputPaths from openspec status --json as the only delta-spec source. A schema without a specs artifact, or a change whose concrete output list is empty, has nothing to sync; other artifacts are not used to infer delta specs.

Before a semantic merge writes a main spec, the workflow consumes current openspec instructions specs --change <name> --json output. The returned specs rules constrain only the main specs produced by that merge. Single archive passes that snapshot into inline sync, standalone sync fetches it directly, and bulk archive obtains every required snapshot before its first spec write. A non-zero or invalid JSON archive/specs instruction response is a lookup failure, not an empty input: the workflow stops before the affected spec write or change move (for bulk archive, before any batch write or move).

This configuration does not change archive execution phases, user prompts, filesystem operations, semantic merge ownership, the direct openspec archive command, or the structure and output of artifact rules.

Schema Resolution Order

When OpenSpec needs a schema, it checks in this order:

  1. CLI flag: --schema <name>
  2. Change metadata (.openspec.yaml in the change folder)
  3. Project config (openspec/config.yaml)
  4. Default (spec-driven)

Custom Schemas

When project config isn't enough, create your own schema with a completely custom workflow. Custom schemas live in your project's openspec/schemas/ directory and are version-controlled with your code.

your-project/
├── openspec/
│   ├── config.yaml        # Project config
│   ├── schemas/           # Custom schemas live here
│   │   └── my-workflow/
│   │       ├── schema.yaml
│   │       └── templates/
│   └── changes/           # Your changes
└── src/

Fork an Existing Schema

The fastest way to customize is to fork a built-in schema:

openspec schema fork spec-driven my-workflow

This copies the entire spec-driven schema to openspec/schemas/my-workflow/ where you can edit it freely.

What you get:

openspec/schemas/my-workflow/
├── schema.yaml           # Workflow definition
└── templates/
    ├── proposal.md       # Template for proposal artifact
    ├── spec.md           # Template for specs
    ├── design.md         # Template for design
    └── tasks.md          # Template for tasks

Now edit schema.yaml to change the workflow, or edit templates to change what AI generates.

Create a Schema from Scratch

For a completely fresh workflow:

# Interactive
openspec schema init research-first

# Non-interactive
openspec schema init rapid \
  --description "Rapid iteration workflow" \
  --artifacts "proposal,tasks" \
  --default

Schema Structure

A schema defines the artifacts in your workflow and how they depend on each other:

# openspec/schemas/my-workflow/schema.yaml
name: my-workflow
version: 1
description: My team's custom workflow

artifacts:
  - id: proposal
    generates: proposal.md
    description: Initial proposal document
    template: proposal.md
    instruction: |
      Create a proposal that explains WHY this change is needed.
      Focus on the problem, not the solution.
    requires: []

  - id: design
    generates: design.md
    description: Technical design
    template: design.md
    instruction: |
      Create a design document explaining HOW to implement.
    requires:
      - proposal    # Can't create design until proposal exists

  - id: tasks
    generates: tasks.md
    description: Implementation checklist
    template: tasks.md
    requires:
      - design

apply:
  requires: [tasks]
  tracks: tasks.md

Key fields:

Field Purpose
id Unique identifier, used in commands and rules
generates Output filename (supports globs like specs/**/*.md)
template Template file in templates/ directory
instruction AI instructions for creating this artifact
requires Dependencies - which artifacts must exist first

List artifacts in the order you want them written. requires decides what is possible; the order of the artifacts: list decides what comes first when several artifacts are ready at once.

Templates

Templates are markdown files that guide the AI. They're injected into the prompt when creating that artifact.

<!-- templates/proposal.md -->
## Why

<!-- Explain the motivation for this change. What problem does this solve? -->

## What Changes

<!-- Describe what will change. Be specific about new capabilities or modifications. -->

## Impact

<!-- Affected code, APIs, dependencies, systems -->

Templates can include:

  • Section headers the AI should fill in
  • HTML comments with guidance for the AI
  • Example formats showing expected structure

Validate Your Schema

Before using a custom schema, validate it:

openspec schema validate my-workflow

This checks:

  • schema.yaml syntax is correct
  • All referenced templates exist
  • No circular dependencies
  • Artifact IDs are valid

Use Your Custom Schema

Once created, use your schema with:

# Specify on command
openspec new change feature --schema my-workflow

# Or set as default in config.yaml
schema: my-workflow

Debug Schema Resolution

Not sure which schema is being used? Check with:

# See where a specific schema resolves from
openspec schema which my-workflow

# List all available schemas
openspec schema which --all

Output shows whether it's from your project, user directory, or the package:

Schema: my-workflow
Source: project
Path: /path/to/project/openspec/schemas/my-workflow

Note: OpenSpec also supports user-level schemas at ~/.local/share/openspec/schemas/ for sharing across projects, but project-level schemas in openspec/schemas/ are recommended since they're version-controlled with your code.


Examples

Rapid Iteration Workflow

A minimal workflow for quick iterations:

# openspec/schemas/rapid/schema.yaml
name: rapid
version: 1
description: Fast iteration with minimal overhead

artifacts:
  - id: proposal
    generates: proposal.md
    description: Quick proposal
    template: proposal.md
    instruction: |
      Create a brief proposal for this change.
      Focus on what and why, skip detailed specs.
    requires: []

  - id: tasks
    generates: tasks.md
    description: Implementation checklist
    template: tasks.md
    requires: [proposal]

apply:
  requires: [tasks]
  tracks: tasks.md

Adding a Review Artifact

Fork the default and add a review step:

openspec schema fork spec-driven with-review

Then edit schema.yaml to add:

  - id: review
    generates: review.md
    description: Pre-implementation review checklist
    template: review.md
    instruction: |
      Create a review checklist based on the design.
      Include security, performance, and testing considerations.
    requires:
      - design

  - id: tasks
    # ... existing tasks config ...
    requires:
      - specs
      - design
      - review    # Now tasks require review too

Community Schemas

OpenSpec also supports community-maintained schemas distributed via standalone repositories. These provide opinionated workflows that integrate OpenSpec with other tools or systems, similar to how github/spec-kit's community extension catalog works for spec-kit.

Community schemas are not vendored into OpenSpec core — they live in their own repositories with their own release cadence. To use one, copy the schema bundle into your project's openspec/schemas/<schema-name>/ directory (each repo's README has install instructions).

Schema Maintainer Repository Description
intent-driven @harikrishnan83 intent-driven-dev/openspec-schemas Captures change intent, observable behaviour, technical design, and durable architectural decisions before implementation. Adds a change-local ADR review manifest and writes qualifying long-lived decisions as immutable, supersedable ADRs.
superpowers-bridge @JiangWay JiangWay/openspec-schemas Integrates OpenSpec's artifact governance with obra/superpowers execution skills (brainstorming, writing-plans, TDD via subagents, code review, finishing). Adds an evidence-first retrospective artifact filling a gap Superpowers does not natively cover.
nanopm @nmrtn nmrtn/nanopm PM-first workflow. Runs nanopm's planning pipeline (audit → strategy → roadmap → PRD) upstream of implementation. Bridges product planning to OpenSpec's spec-driven engineering workflow. Artifacts read from .nanopm/ if present — proposal sources the audit, design sources the strategy, and tasks source the PRD breakdown.
e2e-runbooks @Lukk17 Lukk17/openspec-schemas Capability-level end-to-end test runbooks. Each capability gets an immutable spec, an immutable tasks-template, and one timestamped run record per execution. Assertions are observable behaviour only (HTTP status, response body, persisted state — never log substrings); each run records start/end UTC, duration, and best-estimate LLM token consumption.
anvil @jikkujoyce jikkujoyce/openspec-schemas Spec-driven workflow with TDD discipline and an adversarial review step. Flow: proposalspecsdesignreviewtest-plantasksapplyverify. review is written by a fresh-context, read-only reviewer (a second model when one is available) and emits a VERDICT: line telling the agent to gate test-plan, tasks, and apply; OpenSpec only checks that artifacts exist, so enforce the gate with your own CI or hook. test-plan maps every spec scenario to a named test and doubles as a red/green ledger that verify audits.

Want to contribute a community schema? Open an issue with a link to your repository, or submit a PR adding a row to this table.


See Also