From 428ad64f604de6f8305027acd29ba1cc53cad851 Mon Sep 17 00:00:00 2001 From: Noor-ul-ain001 Date: Sun, 26 Jul 2026 12:18:20 +0500 Subject: [PATCH 1/3] docs: layer contributor-onboarding sections onto AGENTS.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rebased onto current main and reworked so the additions match the current architecture rather than the stale base this branch was written against. The original revision documented the retired Windsurf integration and a CLI-managed `context_file` field that no longer exists (context files are now owned by the opt-in agent-context extension), and described the manifest at the wrong path with a non-existent API. This version keeps all current AGENTS.md content unchanged and adds four onboarding-focused sections, verified against the code: - Quickstart — Add a New Integration in 5 Steps (links into the existing step-by-step section; notes context files are extension-owned) - IntegrationManifest — File Tracking (correct path .specify/integrations/.manifest.json and real API: record_file / record_existing / hash-guarded uninstall) - Error Handling and Debugging (symptom/cause/fix table + debug tips) - Contribution Checklist Purely additive (+88 lines, no deletions); all internal anchors resolve. Assisted-by: Claude Opus 4.8 (model: claude-opus-4-8, autonomous) Co-Authored-By: Claude Opus 4.8 (1M context) --- AGENTS.md | 88 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) diff --git a/AGENTS.md b/AGENTS.md index 061b8b12b1..503ee1a01c 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -10,6 +10,20 @@ The toolkit supports multiple AI coding assistants, allowing teams to use their --- +## Quickstart — Add a New Integration in 5 Steps + +If you are new to the codebase and want to add support for a new AI agent, here is the shortest path from zero to a working integration: + +1. **Choose a base class** — most agents only need `MarkdownIntegration`. See [Choose a base class](#1-choose-a-base-class). +2. **Create a subpackage** — add `src/specify_cli/integrations//__init__.py` with the required `key`, `config`, and `registrar_config` fields. +3. **Register it** — add one import and one `_register()` call in `src/specify_cli/integrations/__init__.py` (both alphabetical). +4. **Write a test file** — create `tests/integrations/test_integration_.py` (hyphens in the key become underscores in the filename). +5. **Run and verify** — use `specify init --integration ` to exercise the full install/uninstall cycle. + +Each step is expanded under [Adding a New Integration](#adding-a-new-integration). Note that agent **context files** (`CLAUDE.md`, `AGENTS.md`, …) are **not** handled by the integration — that is owned by the opt-in `agent-context` extension; see [Context file behavior](#4-context-file-behavior). + +--- + ## Integration Architecture Each AI agent is a self-contained **integration subpackage** under `src/specify_cli/integrations//`. 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()`. @@ -34,6 +48,30 @@ The registry is the **single source of truth for Python integration metadata**. --- +## IntegrationManifest — File Tracking + +`manifest.py` provides the `IntegrationManifest` class, which records every file an integration installs. This record is what makes uninstall reliable and safe. + +### How it works + +`setup()` receives an `IntegrationManifest` and writes files through it rather than touching the filesystem directly: + +```python +# Produce a new file and record its hash for later verification. +manifest.record_file("commands/speckit.plan.md", processed_content) + +# Adopt a pre-existing file the integration is now responsible for. +manifest.record_existing(".vscode/settings.json") +``` + +The manifest is persisted at `.specify/integrations/.manifest.json` (one per integration, keyed by `key`) and stores a SHA-256 hash per file. When the user runs `specify integration uninstall `, `teardown()` delegates to `manifest.uninstall()`, which removes only files whose current hash still matches the recorded value — so files the user later edited by hand are skipped, not clobbered (pass `force=True` to remove them anyway). + +### Why this matters + +Without hash-tracked manifests, uninstall would either remove files it should not (destructive) or leave orphans behind (messy). If you write a custom `setup()`, route **every** file you create through `manifest.record_file(...)` (or `record_existing(...)` for files you adopt) so uninstall can reason about them. + +--- + ## Adding a New Integration ### 1. Choose a base class @@ -511,4 +549,54 @@ Disclosure is **continuous**, not a one-time event. A single AI-disclosure parag --- +## Error Handling and Debugging + +### Common Errors and Fixes + +| Symptom | Likely Cause | Fix | +|---|---|---| +| `Integration '' not found` | Missing `_register()` call | Add `_register(Integration())` inside `_register_builtins()` | +| `Integration '' not found` (still) | Missing import | Add `from . import Integration` inside `_register_builtins()` | +| CLI check fails for a `requires_cli: True` agent | `key` does not match the executable name | Set `key` to the exact name `shutil.which(key)` must resolve (e.g. `"cursor-agent"`, not `"cursor"`) | +| Command files have the wrong argument syntax | Wrong `args` value in `registrar_config` | Use `$ARGUMENTS` for Markdown agents, `{{args}}` for TOML/YAML agents, or the agent's custom placeholder | +| `ModuleNotFoundError` on a brand-new subpackage under pytest only | Ambient interpreter with a stale editable `.pth` | Run inside this tree's own venv (see Common Pitfall 6) | +| Uninstall leaves files behind, or skips files you expected removed | Files not recorded via the manifest, or their hash changed after install | Route every created file through `manifest.record_file(...)`; user-edited files are intentionally skipped unless `force=True` | +| Context file (`CLAUDE.md`, etc.) not updated | Expecting the CLI to manage it | Context files are owned by the opt-in `agent-context` extension, not the integration — see [Context file behavior](#4-context-file-behavior) | + +### Debugging Tips + +**Inspect the manifest** to see what an installed integration tracks: + +```bash +cat .specify/integrations/.manifest.json +``` + +**Verify a CLI tool is detected** before debugging a `requires_cli` agent: + +```bash +which # Should print the executable path if installed +``` + +**Verify the installed output structure** after `specify init`: + +```bash +find my-project/ -type f +``` + +--- + +## Contribution Checklist + +Before opening or merging an integration PR, confirm the following: + +- [ ] Added the integration subpackage under `src/specify_cli/integrations//`. +- [ ] Registered it (import **and** `_register()`) in `src/specify_cli/integrations/__init__.py`, both alphabetical. +- [ ] Added or updated tests in `tests/integrations/test_integration_.py`. +- [ ] Verified the install/uninstall flow with `specify init --integration `. +- [ ] Did **not** add `context_file` handling to the CLI (that belongs to the `agent-context` extension). +- [ ] Updated devcontainer files if the agent needs a VS Code extension or CLI install step. +- [ ] Updated this guide or other relevant docs if the integration has special setup or limitations. + +--- + *This documentation should be updated whenever new integrations are added to maintain accuracy and completeness.* From a1e9f11dc227a989dce02a2f7dc678307697c864 Mon Sep 17 00:00:00 2001 From: Noor ul ain Date: Mon, 27 Jul 2026 19:33:48 +0500 Subject: [PATCH 2/3] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- AGENTS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AGENTS.md b/AGENTS.md index 503ee1a01c..b30debb3fe 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -64,7 +64,7 @@ manifest.record_file("commands/speckit.plan.md", processed_content) manifest.record_existing(".vscode/settings.json") ``` -The manifest is persisted at `.specify/integrations/.manifest.json` (one per integration, keyed by `key`) and stores a SHA-256 hash per file. When the user runs `specify integration uninstall `, `teardown()` delegates to `manifest.uninstall()`, which removes only files whose current hash still matches the recorded value — so files the user later edited by hand are skipped, not clobbered (pass `force=True` to remove them anyway). +The manifest is persisted at `.specify/integrations/.manifest.json` (one per integration, keyed by `key`) and stores a SHA-256 hash per file. When the user runs `specify integration uninstall `, `teardown()` delegates to `manifest.uninstall()`, which removes only files whose current hash still matches the recorded value — so files the user later edited by hand are skipped, not clobbered (use `specify integration uninstall --force` to remove modified tracked files anyway). ### Why this matters From 00c35aa2e872851bd14b3f28235eb444cadffc50 Mon Sep 17 00:00:00 2001 From: Noor ul ain Date: Tue, 28 Jul 2026 00:43:52 +0500 Subject: [PATCH 3/3] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- AGENTS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AGENTS.md b/AGENTS.md index b30debb3fe..82fde69548 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -556,7 +556,7 @@ Disclosure is **continuous**, not a one-time event. A single AI-disclosure parag | Symptom | Likely Cause | Fix | |---|---|---| | `Integration '' not found` | Missing `_register()` call | Add `_register(Integration())` inside `_register_builtins()` | -| `Integration '' not found` (still) | Missing import | Add `from . import Integration` inside `_register_builtins()` | +| `NameError: name 'Integration' is not defined` at startup | Missing import | Add `from . import Integration` inside `_register_builtins()` | | CLI check fails for a `requires_cli: True` agent | `key` does not match the executable name | Set `key` to the exact name `shutil.which(key)` must resolve (e.g. `"cursor-agent"`, not `"cursor"`) | | Command files have the wrong argument syntax | Wrong `args` value in `registrar_config` | Use `$ARGUMENTS` for Markdown agents, `{{args}}` for TOML/YAML agents, or the agent's custom placeholder | | `ModuleNotFoundError` on a brand-new subpackage under pytest only | Ambient interpreter with a stale editable `.pth` | Run inside this tree's own venv (see Common Pitfall 6) |