* docs: add Spec Kit spec for agent-context full opt-in Use Spec Kit's own specify workflow to author the spec that makes the agent-context extension a full opt-in, removing all agent-context configuration/support from the Python codebase and removing the deprecation message. Force-added despite specs/ being gitignored; the generated artifact will be purged prior to merge. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * docs: add Spec Kit plan artifacts for agent-context full opt-in Phase 0/1 of the SDD plan workflow: plan.md, research.md, data-model.md, quickstart.md, and contracts/cli-behavior.md. Constitution Check is a documented no-op (repo has no ratified constitution). Force-added despite specs/ being gitignored; generated artifacts will be purged prior to merge. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * docs: correct Constitution Check against ratified v1.0.0 Earlier draft wrongly treated the gate as a no-op; the fork's main is 16 commits behind upstream/main, which carries .specify/memory/constitution.md. Re-evaluate the feature against Principles I-V (all PASS) and note that Principle I mandates keeping context_file as a declared class attribute, validating the R1 metadata decision. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * docs: refresh plan artifacts against synced upstream/main After syncing fork main to upstream and rebasing, re-scan the current agent-context surface. Upstream generalized the single context_file into a plural context_files concept with new resolver helpers (_resolve_context_files, _resolve_context_file_values, _format_context_file_values) and upsert/remove now loop over multiple files. Update research.md, data-model.md, contracts, quickstart grep guards, and the plan summary to cover the expanded removal scope. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * docs: add Spec Kit tasks for agent-context full opt-in Phase 2 of SDD: dependency-ordered tasks.md (30 tasks) organized by the three user stories, with mandatory test tasks (Constitution Principle II) and a foundational phase decoupling __CONTEXT_FILE__ resolution from the extension config. Includes the extension self-seeding task (T015) and a static guard test (T002) enforcing zero agent-context references in the CLI. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * feat!: remove agent-context lifecycle from the Specify CLI Make the agent-context extension a full opt-in. The CLI no longer installs the extension during init, writes agent-context-config.yml, or creates/updates/removes the managed Spec Kit section in agent context files. Context-section upsert/remove, marker resolution, extension-enabled gating, the config helpers, and the obsolete inline deprecation warning are all removed. Integration context_file stays as inert metadata; __CONTEXT_FILE__ now resolves from registry metadata. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * feat(agent-context): self-seed context file from the active integration When agent-context-config.yml has no context_file/context_files, the bundled bash and PowerShell update scripts now resolve the context file from the active integration in .specify/init-options.json via the integration registry, so the extension no longer depends on the CLI writing its config. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * test+docs: update suite and docs for agent-context opt-in Update integration/extension tests to expect no agent-context install, config, or context-section writes during init. Add a static guard test (test_agent_context_cli_free.py) asserting the CLI source is free of agent-context lifecycle symbols, plus backward-compatibility tests for legacy projects. Refresh AGENTS.md, the extension README, and add a CHANGELOG entry describing the opt-in behavior change. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(agent-context): warn on self-seed failure, correct docs, speed up guard test Address PR review feedback: - Self-seed scripts (bash + PowerShell) now emit an actionable warning when an active integration is configured but specify_cli cannot be imported by the chosen Python (e.g. pipx installs), or when the integration declares no context file, instead of silently falling through to 'nothing to do'. - Correct the extension README disable note: command rendering never reads the extension config; __CONTEXT_FILE__ is always substituted from integration metadata, so a stale context_files value cannot affect rendering. - Cache CLI source reads in the static guard test via a module-scoped fixture so the directory walk happens once instead of once per forbidden symbol. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * feat(agent-context): ship self-owned per-agent context-file defaults The extension now bundles agent-context-defaults.json (key→context_file map) and self-seeds from it, dropping any dependency on the Specify CLI registry. Both the bash and PowerShell update scripts read the bundled JSON map keyed by the active integration from init-options.json. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * feat!: remove all agent-context state from the Specify CLI Strip every context_file reference from the CLI: the field on all 35 integration classes, the IntegrationBase plumbing (process_template param/step, _context_file_display, docstrings), the __CONTEXT_FILE__ resolution in agents.py, the legacy context_file/context_markers popping in _helpers.py, and the context_file template in integration_scaffold.py. Also drop the Agent context update step and __CONTEXT_FILE__ placeholder from templates/commands/plan.md. The agent-context extension now solely owns all context-file knowledge, including the per-agent default mapping. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * test: drop context_file coverage and guard against CLI reintroduction Remove CONTEXT_FILE attrs and context_file assertions across the base mixins, all 35 per-integration test files, shared integration tests, and conftest stubs. Rewrite the base-mixin context tests to assert no managed section is written and no __CONTEXT_FILE__ placeholder survives. Extend the CLI-free static guard to forbid context_file, __CONTEXT_FILE__, and _context_file_display in src/specify_cli, and have the extension tests copy the bundled defaults JSON so self-seed runs without the CLI. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * docs: reflect full removal of agent-context state from the CLI Update AGENTS.md (integration examples, required-fields table, context behavior section, pitfalls), CHANGELOG, and the SDD spec artifacts (FR-007, SC-002, data-model) to state that the CLI carries no context_file and the extension fully owns the per-agent default mapping via agent-context-defaults.json. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * docs: align SDD artifacts with full context_file removal Update research.md (R1, R2, R4, summary table), contracts/cli-behavior.md (C3, C5), tasks.md (Phase 2, T026, notes), plan.md (Principle I, source map), and checklists/requirements.md so the spec artifacts reflect the implemented decision: the CLI carries no context_file attribute or __CONTEXT_FILE__ resolution, and the per-agent defaults map lives in the extension. Resolves PR review #4548130110. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * docs: scrub stale context-file mentions from CLI docstrings Update the multi_install_safe docstring (drop the removed "context file" invariant), the RovoDev setup docstring (no longer upserts a context section), the Copilot module docstring (drop the context-file line), and tighten the _update_init_options_for_integration note. Pure docstring changes — no behavioral impact. Resolves PR review #4548237085. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * test+docs: harden agent-context test helper and fix stale docs - base.py: document multi_install_safe as an optional subclass attribute in the IntegrationBase docstring. - test_cli.py: clarify the init-options assertion is guarding against leftover legacy agent-context keys, not relocation. - test_extension_agent_context.py: _install_agent_context_config now asserts the bundled agent-context-defaults.json exists and always copies it, so self-seeding tests fail loudly instead of silently skipping when the map is missing. - test_integration_cursor_agent.py: drop Path/IntegrationManifest imports left unused after removing the context-section frontmatter tests. Resolves PR review #4548293116. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * chore: remove gitignored SDD artifacts from specs/ The specs/001-agent-context-full-optin/ artifacts were force-added for dogfooding visibility, but specs/ is gitignored and these were always intended to be purged before merge. Remove them so merging does not add an intentionally-untracked directory to repo history. Assisted-by: GitHub Copilot (model: Claude Opus 4.8, autonomous) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * chore: keep CHANGELOG.md identical to upstream CHANGELOG.md is auto-generated at release time, so the branch should not carry a manual entry. Restore it to match upstream/main exactly. Assisted-by: GitHub Copilot (model: Claude Opus 4.8, autonomous) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix: preserve Cursor .mdc frontmatter in agent-context updater scripts The bundled agent-context updater scripts wrote the managed section as plain text. For Cursor-style `.mdc` targets this dropped the required `---\nalwaysApply: true\n---` frontmatter, reintroducing the rule-loading bug originally fixed in #1699. Port the `_ensure_mdc_frontmatter` logic into both the bash and PowerShell updaters: prepend frontmatter when missing, repair `alwaysApply` when set to the wrong value, and leave non-`.mdc` targets untouched. Add regression tests covering both shells. Assisted-by: GitHub Copilot (model: Claude Opus 4.8, autonomous) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * test: scope CLI-free guard to agent-context-specific symbols Drop the bare "context_file" substring from FORBIDDEN_SYMBOLS so the guard no longer fails on unrelated future CLI fields named context_file. The list still covers agent-context-specific identifiers (__CONTEXT_FILE__, _context_file_display, _resolve_context_files, _resolve_context_file_values). Assisted-by: GitHub Copilot (model: Claude Opus 4.8, autonomous) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix: harden agent-context bash self-seed against malformed init JSON Two robustness fixes in the embedded Python self-seed logic: - Coerce the integration value from init-options.json to a string only when it is actually a string; otherwise treat it as unset so a corrupted dict/list value degrades to the existing nothing-to-do behavior instead of breaking the agents-map lookup. - Normalize agent-context-defaults.json: only use 'agents' when both the JSON root and the 'agents' value are dicts, so a wrong-shaped (but valid) JSON falls back to the warning path instead of raising on .get. Assisted-by: GitHub Copilot (model: Claude Opus 4.8, autonomous) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix: correct PowerShell hyphenated key lookup and regex replace count - Self-seed now reads the defaults mapping via $defaults.agents.PSObject.Properties[$integrationKey].Value instead of member access ($defaults.agents.$integrationKey), which parsed hyphenated keys like 'cursor-agent'/'kiro-cli' as subtraction and failed to resolve. - Replace the static [regex]::Replace(..., 1) call, whose trailing 1 was interpreted as RegexOptions.IgnoreCase rather than a replacement count, with an instance Regex whose Replace(input, replacement, 1) limits to the first match as intended. Assisted-by: GitHub Copilot (model: Claude Opus 4.8, autonomous) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix: make bash .mdc frontmatter guard case-insensitive The bash updater only injected Cursor .mdc frontmatter when ctx_path ended in lowercase '.mdc', so a mixed/upper-case extension (e.g. specify-rules.MDC) was skipped and Cursor would not auto-load the rule file. Compare against the casefolded path. The PowerShell variant already uses -match, which is case-insensitive by default, so no change is needed there. Assisted-by: GitHub Copilot (model: Claude Opus 4.8, autonomous) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * docs: document separator-agnostic agent-context update invocation The README hard-coded the dot-notation slash command (/speckit.agent-context.update), which hyphen-separator agents like Forge and Cline do not recognize. Document the canonical command ID plus both slash invocations so users copy the form their agent accepts. Assisted-by: GitHub Copilot (model: Claude Opus 4.8, autonomous) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
21 KiB
AGENTS.md
About Spec Kit and Specify
GitHub Spec Kit is a comprehensive toolkit for implementing Spec-Driven Development (SDD) - a methodology that emphasizes creating clear specifications before implementation. The toolkit includes templates, scripts, and workflows that guide development teams through a structured approach to building software.
Specify CLI is the command-line interface that bootstraps projects with the Spec Kit framework. It sets up the necessary directory structures, templates, and AI agent integrations to support the Spec-Driven Development workflow.
The toolkit supports multiple AI coding assistants, allowing teams to use their preferred tools while maintaining consistent project structure and development practices.
Integration Architecture
Each AI agent is a self-contained integration subpackage under src/specify_cli/integrations/<key>/. The subpackage exposes a single class that declares all metadata and inherits setup/teardown logic from a base class. Built-in integrations are then instantiated and added to the global INTEGRATION_REGISTRY by src/specify_cli/integrations/__init__.py via _register_builtins().
src/specify_cli/integrations/
├── __init__.py # INTEGRATION_REGISTRY + _register_builtins()
├── base.py # IntegrationBase, MarkdownIntegration, TomlIntegration, YamlIntegration, SkillsIntegration
├── manifest.py # IntegrationManifest (file tracking)
├── claude/ # Example: SkillsIntegration subclass
│ └── __init__.py # ClaudeIntegration class
├── gemini/ # Example: TomlIntegration subclass
│ └── __init__.py
├── windsurf/ # Example: MarkdownIntegration subclass
│ └── __init__.py
├── copilot/ # Example: IntegrationBase subclass (custom setup)
│ └── __init__.py
└── ... # One subpackage per supported agent
The registry is the single source of truth for Python integration metadata. Supported agents, their directories, formats, capabilities, and context files are derived from the integration classes for the Python integration layer.
Adding a New Integration
1. Choose a base class
| Your agent needs… | Subclass |
|---|---|
Standard markdown commands (.md) |
MarkdownIntegration |
TOML-format commands (.toml) |
TomlIntegration |
YAML recipe files (.yaml) |
YamlIntegration |
Skill directories (speckit-<name>/SKILL.md) |
SkillsIntegration |
| Fully custom output (companion files, settings merge, etc.) | IntegrationBase directly |
Most agents only need MarkdownIntegration — a minimal subclass with zero method overrides.
2. Create the subpackage
Create src/specify_cli/integrations/<package_dir>/__init__.py, where <package_dir> is the Python-safe directory name derived from <key>: use the key as-is when it contains no hyphens (e.g., key "gemini" → gemini/), or replace hyphens with underscores when it does (e.g., key "kiro-cli" → kiro_cli/). The IntegrationBase.key class attribute always retains the original hyphenated value, since that is what the CLI and registry use. For CLI-based integrations (requires_cli: True), the key should match the actual CLI tool name (the executable users install and run) so CLI checks can resolve it correctly. For IDE-based integrations (requires_cli: False), use the canonical integration identifier instead.
Minimal example — Markdown agent (Windsurf):
"""Windsurf IDE integration."""
from ..base import MarkdownIntegration
class WindsurfIntegration(MarkdownIntegration):
key = "windsurf"
config = {
"name": "Windsurf",
"folder": ".windsurf/",
"commands_subdir": "workflows",
"install_url": None,
"requires_cli": False,
}
registrar_config = {
"dir": ".windsurf/workflows",
"format": "markdown",
"args": "$ARGUMENTS",
"extension": ".md",
}
TOML agent (Gemini):
"""Gemini CLI integration."""
from ..base import TomlIntegration
class GeminiIntegration(TomlIntegration):
key = "gemini"
config = {
"name": "Gemini CLI",
"folder": ".gemini/",
"commands_subdir": "commands",
"install_url": "https://github.com/google-gemini/gemini-cli",
"requires_cli": True,
}
registrar_config = {
"dir": ".gemini/commands",
"format": "toml",
"args": "{{args}}",
"extension": ".toml",
}
Skills agent (Codex):
"""Codex CLI integration — skills-based agent."""
from __future__ import annotations
from ..base import IntegrationOption, SkillsIntegration
class CodexIntegration(SkillsIntegration):
key = "codex"
config = {
"name": "Codex CLI",
"folder": ".agents/",
"commands_subdir": "skills",
"install_url": "https://github.com/openai/codex",
"requires_cli": True,
}
registrar_config = {
"dir": ".agents/skills",
"format": "markdown",
"args": "$ARGUMENTS",
"extension": "/SKILL.md",
}
@classmethod
def options(cls) -> list[IntegrationOption]:
return [
IntegrationOption(
"--skills",
is_flag=True,
default=True,
help="Install as agent skills (default for Codex)",
),
]
Required fields
| Field | Location | Purpose |
|---|---|---|
key |
Class attribute | Unique identifier; for CLI-based integrations (requires_cli: True), must match the CLI executable name |
config |
Class attribute (dict) | Agent metadata: name, folder, commands_subdir, install_url, requires_cli |
registrar_config |
Class attribute (dict) | Command output config: dir, format, args placeholder, file extension |
Key design rule: For CLI-based integrations (requires_cli: True), key must be the actual executable name (e.g., "cursor-agent" not "cursor"). This ensures shutil.which(key) works for CLI-tool checks without special-case mappings. IDE-based integrations (requires_cli: False) should use their canonical identifier (e.g., "windsurf", "copilot").
3. Register it
In src/specify_cli/integrations/__init__.py, add one import and one _register() call inside _register_builtins(). Both lists are alphabetical:
def _register_builtins() -> None:
# -- Imports (alphabetical) -------------------------------------------
from .claude import ClaudeIntegration
# ...
from .newagent import NewAgentIntegration # ← add import
# ...
# -- Registration (alphabetical) --------------------------------------
_register(ClaudeIntegration())
# ...
_register(NewAgentIntegration()) # ← add registration
# ...
4. Context file behavior
The Specify CLI carries no agent-context state whatsoever. Integration classes do not declare a context_file, and the CLI never creates, updates, removes, resolves, or migrates a context/instruction file (CLAUDE.md, AGENTS.md, .github/copilot-instructions.md, …). New integrations add nothing for context handling.
Managing the "Spec Kit" section in the context file is fully owned by the bundled agent-context extension (extensions/agent-context/), which is a full opt-in: specify init does not install it. A user adds/enables it through the standard extension verbs, after which the extension's own bundled scripts maintain the context section. When the extension is absent or disabled, nothing in Spec Kit touches the context file.
The extension reads its own config file at .specify/extensions/agent-context/agent-context-config.yml:
# Path to the coding agent context file managed by this extension
context_file: CLAUDE.md
# Delimiters for the managed Spec Kit section
context_markers:
start: "<!-- SPECKIT START -->"
end: "<!-- SPECKIT END -->"
- The Specify CLI does not write this config. When
context_fileis empty, the extension's bundled scripts self-seed it by looking up the active integration's key in the extension's ownagent-context-defaults.jsonmap (extensions/agent-context/scripts/bash/update-agent-context.shand.ps1). The CLI registry is never consulted — all agent→context-file knowledge lives inside the extension. context_markers.{start,end}are read solely by the extension's scripts; they default to the Spec Kit markers shown above and can be customized by editingagent-context-config.ymldirectly.
Existing projects created by older Spec Kit versions keep working: any previously written managed section or extension config is left intact and is only ever updated by the extension when run.
Only add custom setup logic when the agent needs non-standard behavior. Integrations no longer require per-agent thin wrapper scripts or shared context-update dispatcher scripts — the agent-context extension is fully generic.
5. Test it
# Install into a test project
specify init my-project --integration <key>
# Verify files were created in the commands directory configured by
# config["folder"] + config["commands_subdir"] (for example, .windsurf/workflows/)
ls -R my-project/.windsurf/workflows/
# Uninstall cleanly
cd my-project && specify integration uninstall <key>
Each integration also has a dedicated test file at tests/integrations/test_integration_<key>.py. Note that hyphens in the key are replaced with underscores in the filename (e.g., key cursor-agent → test_integration_cursor_agent.py, key kiro-cli → test_integration_kiro_cli.py). Run it with:
pytest tests/integrations/test_integration_<key_with_underscores>.py -v
6. Optional overrides
The base classes handle most work automatically. Override only when the agent deviates from standard patterns:
| Override | When to use | Example |
|---|---|---|
command_filename(template_name) |
Custom file naming or extension | Copilot → speckit.{name}.agent.md |
options() |
Integration-specific CLI flags via --integration-options |
Codex → --skills flag, Copilot → --skills flag |
setup() |
Custom install logic (companion files, settings merge) | Copilot → .agent.md + .prompt.md + .vscode/settings.json (default) or speckit-<name>/SKILL.md (skills mode) |
teardown() |
Custom uninstall logic | Rarely needed; base handles manifest-tracked files |
Example — Copilot (fully custom setup):
Copilot extends IntegrationBase directly because it creates .agent.md commands, companion .prompt.md files, and merges .vscode/settings.json. It also supports a --skills mode that scaffolds speckit-<name>/SKILL.md under .github/skills/ using composition with an internal _CopilotSkillsHelper. See src/specify_cli/integrations/copilot/__init__.py for the full implementation.
7. Update Devcontainer files (Optional)
For agents that have VS Code extensions or require CLI installation, update the devcontainer configuration files:
VS Code Extension-based Agents
For agents available as VS Code extensions, add them to .devcontainer/devcontainer.json:
{
"customizations": {
"vscode": {
"extensions": [
// ... existing extensions ...
"[New Agent Extension ID]"
]
}
}
}
CLI-based Agents
For agents that require CLI tools, add installation commands to .devcontainer/post-create.sh:
#!/bin/bash
# Existing installations...
echo -e "\n🤖 Installing [New Agent Name] CLI..."
# run_command "npm install -g [agent-cli-package]@latest"
echo "✅ Done"
Command File Formats
Markdown Format
Standard format:
---
description: "Command description"
---
Command content with {SCRIPT} and $ARGUMENTS placeholders.
GitHub Copilot Chat Mode format:
---
description: "Command description"
mode: speckit.command-name
---
Command content with {SCRIPT} and $ARGUMENTS placeholders.
TOML Format
description = "Command description"
prompt = """
Command content with {SCRIPT} and {{args}} placeholders.
"""
YAML Format
Used by: Goose
version: 1.0.0
title: "Command Title"
description: "Command description"
author:
contact: spec-kit
extensions:
- type: builtin
name: developer
activities:
- Spec-Driven Development
prompt: |
Command content with {SCRIPT} and {{args}} placeholders.
Argument Patterns
Different agents use different argument placeholders. The placeholder used in command files is always taken from registrar_config["args"] for each integration — check there first when in doubt:
- Markdown/prompt-based:
$ARGUMENTS(default for most markdown agents) - TOML-based:
{{args}}(e.g., Gemini) - YAML-based:
{{args}}(e.g., Goose) - Custom: some agents override the default (e.g., Forge uses
{{parameters}}) - Script placeholders:
{SCRIPT}(replaced with actual script path) - Agent placeholders:
__AGENT__(replaced with agent name)
Special Processing Requirements
Some agents require custom processing beyond the standard template transformations:
Copilot Integration
GitHub Copilot has unique requirements:
- Commands use
.agent.mdextension (not.md) - Each command gets a companion
.prompt.mdfile in.github/prompts/ - Installs
.vscode/settings.jsonwith prompt file recommendations - Context file lives at
.github/copilot-instructions.md
Implementation: Extends IntegrationBase with custom setup() method that:
- Processes templates with
process_template() - Generates companion
.prompt.mdfiles - Merges VS Code settings
Skills mode (--skills): Copilot also supports an alternative skills-based layout
via --integration-options="--skills". When enabled:
- Commands are scaffolded as
speckit-<name>/SKILL.mdunder.github/skills/ - No companion
.prompt.mdfiles are generated - No
.vscode/settings.jsonmerge post_process_skill_content()injects amode: speckit.<stem>frontmatter fieldbuild_command_invocation()returns/speckit-<stem>instead of bare args
The two modes are mutually exclusive — a project uses one or the other:
# Default mode: .agent.md agents + .prompt.md companions + settings merge
specify init my-project --integration copilot
# Skills mode: speckit-<name>/SKILL.md under .github/skills/
specify init my-project --integration copilot --integration-options="--skills"
Forge Integration
Forge has special frontmatter and argument requirements:
- Uses
{{parameters}}instead of$ARGUMENTS - Strips
handoffsfrontmatter key (Forge-specific collaboration feature) - Injects
namefield into frontmatter when missing
Implementation: Extends MarkdownIntegration with custom setup() method that:
- Inherits standard template processing from
MarkdownIntegration - Adds extra
$ARGUMENTS→{{parameters}}replacement after template processing - Applies Forge-specific transformations via
_apply_forge_transformations() - Strips
handoffsfrontmatter key - Injects missing
namefields
Goose Integration
Goose is a YAML-format agent using Block's recipe system:
- Uses
.goose/recipes/directory for YAML recipe files - Uses
{{args}}argument placeholder - Produces YAML with
prompt: |block scalar for command content
Implementation: Extends YamlIntegration (parallel to TomlIntegration):
- Processes templates through the standard placeholder pipeline
- Extracts title and description from frontmatter
- Renders output as Goose recipe YAML (version, title, description, author, extensions, activities, prompt)
- Uses
yaml.safe_dump()for header fields to ensure proper escaping
Branch Naming Convention
Branches follow one of two patterns depending on whether an issue exists:
<type>/<number>-<short-slug> # when an issue is created first
<type>/<short-slug> # when no issue exists (PR-only changes)
When an issue exists, include its number immediately after the prefix — this is what makes branches traceable. For small or self-contained changes that go straight to a PR without a tracking issue, omit the number.
| Prefix | When to use | Example |
|---|---|---|
feat/ |
New features | feat/2342-workflow-cli-alignment |
fix/ |
Bug fixes | fix/2653-paths-only-validation |
docs/ |
Documentation changes | docs/2677-branch-naming-convention, docs/update-landing-stats |
community/ |
Community catalog additions | community/2492-add-mde-extension |
chore/ |
Maintenance, tooling, CI | chore/2366-editorconfig |
Rules:
- Include the issue number when one exists — this is what makes branches traceable
- Use kebab-case for the slug
- Keep the slug short — enough to identify the work without looking up the issue
Agent Disclosure for PRs, Comments, and Commits
Disclosure is continuous, not a one-time event. A single AI-disclosure paragraph in the PR body does not cover the commits and replies you add during review rounds. Each of the following must independently attest to agent authorship.
Commits
-
Every commit you author must carry an
Assisted-by:trailer identifying the agent and whether it acted autonomously or under direct human supervision, for example:Assisted-by: GitHub Copilot (model: <name-if-known>, autonomous)Use
supervisedinstead ofautonomousonly when a human actually authored or line-by-line reviewed the change before it was committed. -
Never push solo-authored commits that hide agent authorship behind the operator's git identity. If an agent generated the change, the trailer must say so even when the commit is attributed to a human account.
-
Preserve any tool-generated
Co-authored-by:trailers (e.g. Copilot Autofix) — do not strip them to make a commit look hand-written.
Comments
- If you are an agent working on behalf of a human, disclose your identity in your PR comment — name the agent (and model, if applicable) and the human you are acting for (e.g., "Posted on behalf of @user by GitHub Copilot (model: <name-if-known>)").
- Re-state agent identity in each review-round summary comment. A prior PR-body disclosure does not cover later comments or commits.
- Post one top-level summary comment per review round listing what changed and the commit SHA. Do not reply on every individual comment.
- Reply inline only when context is needed (disagreement, deferral, non-obvious fix). Keep it to a sentence or two.
- Never click "Resolve conversation" — that belongs to the reviewer or PR author.
- No emoji, no celebratory framing, no checklist mirroring the reviewer's items, no restating what the reviewer wrote.
- Re-request review once per round (when all feedback is addressed), not after every intermediate push.
Anti-patterns (do not do these)
- Do not reply "Done" or push a "fix" within seconds/minutes of a review event without disclosing that the response or commit was agent-generated. Speed of turnaround is not a substitute for attestation — a near-instant tested code change is itself a signal of automation and must be disclosed as such.
- Do not claim "reviewed, tested, and understood by me" for commits that were authored and pushed automatically in response to a review trigger. If the loop is automated, disclose it as automated.
Common Pitfalls
- Using shorthand keys for CLI-based integrations: For CLI-based integrations (
requires_cli: True), thekeymust match the executable name (e.g.,"cursor-agent"not"cursor").shutil.which(key)is used for CLI tool checks — mismatches require special-case mappings. IDE-based integrations (requires_cli: False) are not subject to this constraint. - Reintroducing context handling into the CLI: The opt-in
agent-contextextension owns everything about context files — including the per-agent default mapping inagent-context-defaults.json. Integration classes must not declare acontext_file, and no CLI code should read, write, resolve, or migrate context files. All context-file logic lives in.specify/extensions/agent-context/and its bundled scripts. - Incorrect
requires_clivalue: Set toTrueonly for agents that have a CLI tool; set toFalsefor IDE-based agents. - Wrong argument format: Use
$ARGUMENTSfor Markdown agents,{{args}}for TOML agents. - Skipping registration: The import and
_register()call in_register_builtins()must both be added. - Running tests against the wrong environment: Always run the suite inside this working tree's own virtualenv (
uv sync --extra testthen.venv/bin/python -m pytest, or activate the venv first). A bareuv run pytestcan resolve to an ambient/global interpreter whose editable.pthpoints at a different worktree. The failure is sneaky: test collection still importsspecify_clisuccessfully, but newly-added subpackages (e.g. a freshspecify_cli/bundler/) resolve as a stale namespace package and raiseModuleNotFoundError. If a brand-new subpackage imports underpython -cbut not under pytest, suspect environment contamination, not your code.
This documentation should be updated whenever new integrations are added to maintain accuracy and completeness.