Extract agent context updates into bundled agent-context extension#2546
Merged
Conversation
12 tasks
Copilot
AI
changed the title
[WIP] Add agent-context extension for managing context file updates
Extract agent context updates into bundled agent-context extension
May 13, 2026
Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com>
Contributor
There was a problem hiding this comment.
Pull request overview
This PR refactors agent-context-file management (the <!-- SPECKIT START --> / <!-- SPECKIT END --> block injected into files like CLAUDE.md) out of IntegrationBase and into a new bundled agent-context extension. Configuration now flows through .specify/init-options.json (context_file, context_markers), giving users opt-out (specify extension disable agent-context) and customizable markers, with parallel bash/PowerShell scripts that mirror the Python upsert logic.
Changes:
- Adds a bundled
agent-contextextension (manifest, README, command, bash + PowerShell scripts) and registers it inextensions/catalog.json. - Extends
IntegrationBasewith_resolve_context_markers()and_agent_context_extension_enabled(), gating bothupsert_context_section()andremove_context_section()on the registry, and seeds/clearscontext_markersininit-options.jsonfromspecify_cli.__init__. - Updates
AGENTS.mdand adds 25 tests covering layout, marker resolution, custom-marker upsert/remove, the disabled-gate, and init-options writers.
Show a summary per file
| File | Description |
|---|---|
src/specify_cli/integrations/base.py |
New marker-resolution + extension-enabled helpers; upsert/remove use them. |
src/specify_cli/__init__.py |
New tracker step that auto-installs bundled agent-context; seeds/clears context_markers. |
extensions/catalog.json |
Registers agent-context as bundled: true. |
extensions/agent-context/extension.yml |
Extension manifest with after_specify / after_plan hooks. |
extensions/agent-context/README.md |
User-facing docs for opt-out and configuration. |
extensions/agent-context/commands/speckit.agent-context.update.md |
Slash-command spec referencing the bash/ps1 scripts. |
extensions/agent-context/scripts/bash/update-agent-context.sh |
Bash hook that re-renders the managed section. |
extensions/agent-context/scripts/powershell/update-agent-context.ps1 |
PowerShell counterpart. |
AGENTS.md |
Removes wrapper-script guidance; documents the new init-options.json flow and opt-out. |
tests/extensions/test_extension_agent_context.py |
25 new tests for the extension and plumbing. |
Copilot's findings
Tip
Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Files reviewed: 10/10 changed files
- Comments generated: 7
Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com>
- bash: parse init-options.json with a single python3 invocation instead of three separate read_json_field calls, for parity with the PowerShell ConvertFrom-Json approach and to avoid divergent error semantics - bash: use parameter expansion to strip PROJECT_ROOT prefix from plan path instead of sed interpolation, avoiding special-character fragility - powershell: limit Get-ChildItem to -Depth 1 so plan.md discovery matches the bash glob specs/*/plan.md (one level deep) — fixes cross-platform inconsistency with nested plan.md files - powershell: replace Substring+Length relative-path with [System.IO.Path]::GetRelativePath for robustness across case/PSDrive differences - __init__.py: move agent-context extension install to after save_init_options so init-options.json is present when hooks run - __init__.py: seed context_markers in init-options only when context_file is truthy; avoids noise for integrations without a context file - integrations/base.py: narrow blanket except Exception in _resolve_context_markers to ImportError / (OSError, ValueError) so unexpected bugs surface instead of being silently swallowed
…context_file Apply the same gating logic used during `specify init`: only write context_markers to init-options.json when the integration actually has a context_file set. When switching to an integration without a context file the stale markers are removed, keeping the two init paths consistent.
- Move agent-context extension install after init-options.json is saved so skill registration can read ai_skills + integration key - Write extension config after install (avoids template overwriting context_file) - Fix test_defaults_when_markers_field_missing to truly test missing markers key - Update hermes tests to allow extension-installed agent-context skill
…AML key order - Move ensure_executable_scripts after agent-context extension install so extension scripts get execute bits set - Use preserve_markers=True on reinit to keep user-customized markers - Add Python 3 version check in PowerShell fallback (matching bash behavior) - Add sort_keys=False to yaml.safe_dump for stable config output
- Reject absolute paths and '..' segments in context_file in both bash and PowerShell scripts to prevent writes outside the project root - Fix docstring in _update_init_options_for_integration to accurately describe marker preservation behavior
…raversal - Use 'is not False' for enabled check so only literal False disables - Update upsert_context_section docstring to mention disabled-extension return - Fix path traversal guards to check actual path segments, not substrings (allows filenames like 'notes..md' while rejecting '../' traversal)
- Add UnicodeError to exception tuples in _load_agent_context_config and _resolve_context_markers so garbled UTF-8 config files fall back to defaults - Emit error (with reinstall command) instead of silent skip when bundled agent-context extension is not found during init
- Reject backslash separators and Windows drive-letter paths in bash context_file validation (prevents traversal on Git-Bash/Windows) - Add extensions/agent-context to pyproject.toml force-include so the bundled extension is included in wheel builds
- Reorder writes in _update_init_options_for_integration so the agent-context extension config is updated first; if it fails, init-options.json remains consistent with the previous state
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
New Feature
Coding agent context file management (
<!-- SPECKIT START -->/<!-- SPECKIT END -->injection intoCLAUDE.md,.github/copilot-instructions.md, etc.) was hardcoded intoIntegrationBase, with no way to opt out or customize markers. This change moves that behavior into a bundledagent-contextextension driven by.specify/extensions/agent-context/agent-context-config.yml.What does this feature do?
Adds
extensions/agent-context/(bundled: true, opt-out) that owns the lifecycle of the managed context section. Both the Python paths and the new shell/PowerShell scripts readcontext_fileandcontext_markersfrom.specify/extensions/agent-context/agent-context-config.yml— single source of truth, no per-agent logic, user-customizable markers.Implementation details
integrations/base.py_resolve_context_markers(project_root)— readscontext_markersfromagent-context-config.yml, falls back toCONTEXT_MARKER_START/CONTEXT_MARKER_ENDconstants per side._agent_context_extension_enabled(project_root)— reads.specify/extensions/.registry; returnsTruewhen registry/entry absent (backwards compat) orenabledis not literallyFalse.upsert_context_section()/remove_context_section()now use the resolved markers and short-circuit when the extension is disabled.upsert_context_section()emits a deprecation warning (v0.12.0) since inline context updates are being replaced by the extension.specify_cli/commands/init.pyspecify initwritescontext_fileto the agent-context extension config (notinit-options.json).agent-contextextension duringspecify init(afterinit-options.jsonis saved, so skill registration works).ensure_executable_scriptsruns after extension install so extension scripts get execute bits.specify_cli/__init__.py_update_init_options_for_integration()writescontext_fileto the extension config, preserving user-customized markers._clear_init_options_for_integration()clearscontext_filein the extension config and removes legacy keys frominit-options.json._load_agent_context_config()/_save_agent_context_config()— helpers for reading/writing the extension config.extensions/agent-context/—extension.yml(idagent-context, hooksafter_specify/after_plan),README.md,commands/speckit.agent-context.update.md, and bash + PowerShellupdate-agent-contextscripts. Both scripts parseagent-context-config.yml, resolve markers (with default fallback), auto-detect the most recentspecs/*/plan.mdwhen no plan path is supplied, and perform the same upsert algorithm as the Python path (CRLF normalization, BOM strip, marker-corruption recovery). Scripts include path traversal guards rejecting absolute paths and..segments.extensions/catalog.json—agent-contextregistered asbundled: true, alphabetized first.AGENTS.md— wrapper-script and dispatcher-script guidance removed; replaced with theagent-context-config.ymlflow and thespecify extension disable agent-contextopt-out.Command templates — All 8 non-constitution commands (
specify,clarify,plan,tasks,checklist,implement,analyze,taskstoissues) now include a directive to load/memory/constitution.mdfor project principles and governance constraints.tests/extensions/test_extension_agent_context.py— 34 tests covering extension layout, catalog entry, marker resolution (defaults / custom / partial / invalid / corrupt YAML), upsert+remove with custom markers, the disabled-extension gate (upsertreturnsNone,removereturnsFalseand leaves file untouched), deprecation warning output, and extension config writers.tests/integrations/test_integration_generic.py— Parametrized test verifying all 8 commands referenceconstitution.md.Backwards compatibility
agent-context-config.ymlor missingcontext_markers→ class-constant defaults, identical to current behavior.context_fileininit-options.json→agents.pyfalls back to reading it when extension config is absent.agent-contextentry → treated as enabled, so existing projects continue to receive context updates without re-init.IntegrationBase.