From c32d370f6ad7ac37d7793c91d871efdf2fc52a47 Mon Sep 17 00:00:00 2001 From: James Rich <2199651+jamesarich@users.noreply.github.com> Date: Thu, 21 May 2026 12:56:20 -0700 Subject: [PATCH] ai: Add spec kit agent governance extension and related files (#5568) --- .../speckit.agent-governance.refresh.agent.md | 48 ++ .github/agents/speckit.git.validate.agent.md | 6 +- .github/copilot-instructions.md | 33 +- ...speckit.agent-governance.refresh.prompt.md | 3 + .specify/extensions.yml | 24 +- .../extensions/.cache/catalog-metadata.json | 2 +- .specify/extensions/.registry | 19 +- .../extensions/agent-governance/.gitignore | 7 + .../extensions/agent-governance/CHANGELOG.md | 40 ++ .specify/extensions/agent-governance/LICENSE | 21 + .../extensions/agent-governance/README.md | 58 ++ .../speckit.agent-governance.refresh.md | 45 ++ .../extensions/agent-governance/extension.yml | 46 ++ .../scripts/refresh_agent_governance.py | 656 ++++++++++++++++++ .../templates/agent-governance-template.md | 53 ++ .../scripts/bash/detect-changed-files.sh | 0 .../verify/scripts/bash/load-config.sh | 0 .specify/init-options.json | 6 +- .specify/integration.json | 10 +- .specify/integrations/copilot.manifest.json | 4 +- .specify/integrations/opencode.manifest.json | 16 - .specify/integrations/speckit.manifest.json | 8 +- .specify/memory/agent-governance.md | 84 +++ .specify/memory/constitution.md | 88 ++- .../catalog-ff86b51b80a289e5-metadata.json | 4 + .../.cache/catalog-ff86b51b80a289e5.json | 577 +++++++++++++++ .specify/presets/.cache/catalog-metadata.json | 4 + .specify/presets/.cache/catalog.json | 30 + .specify/templates/plan-template.md | 23 +- .specify/templates/spec-template.md | 50 +- .specify/templates/tasks-template.md | 9 +- ...orkflow-catalog-4beae448930d024d-meta.json | 1 + .../workflow-catalog-4beae448930d024d.json | 6 + ...orkflow-catalog-d232380ded3e35d7-meta.json | 1 + .../workflow-catalog-d232380ded3e35d7.json | 19 + AGENTS.md | 1 - 36 files changed, 1856 insertions(+), 146 deletions(-) create mode 100644 .github/agents/speckit.agent-governance.refresh.agent.md create mode 100644 .github/prompts/speckit.agent-governance.refresh.prompt.md create mode 100644 .specify/extensions/agent-governance/.gitignore create mode 100644 .specify/extensions/agent-governance/CHANGELOG.md create mode 100644 .specify/extensions/agent-governance/LICENSE create mode 100644 .specify/extensions/agent-governance/README.md create mode 100644 .specify/extensions/agent-governance/commands/speckit.agent-governance.refresh.md create mode 100644 .specify/extensions/agent-governance/extension.yml create mode 100644 .specify/extensions/agent-governance/scripts/refresh_agent_governance.py create mode 100644 .specify/extensions/agent-governance/templates/agent-governance-template.md mode change 100644 => 100755 .specify/extensions/review/scripts/bash/detect-changed-files.sh mode change 100644 => 100755 .specify/extensions/verify/scripts/bash/load-config.sh delete mode 100644 .specify/integrations/opencode.manifest.json create mode 100644 .specify/memory/agent-governance.md create mode 100644 .specify/presets/.cache/catalog-ff86b51b80a289e5-metadata.json create mode 100644 .specify/presets/.cache/catalog-ff86b51b80a289e5.json create mode 100644 .specify/presets/.cache/catalog-metadata.json create mode 100644 .specify/presets/.cache/catalog.json create mode 100644 .specify/workflows/.cache/workflow-catalog-4beae448930d024d-meta.json create mode 100644 .specify/workflows/.cache/workflow-catalog-4beae448930d024d.json create mode 100644 .specify/workflows/.cache/workflow-catalog-d232380ded3e35d7-meta.json create mode 100644 .specify/workflows/.cache/workflow-catalog-d232380ded3e35d7.json diff --git a/.github/agents/speckit.agent-governance.refresh.agent.md b/.github/agents/speckit.agent-governance.refresh.agent.md new file mode 100644 index 000000000..0916b88e5 --- /dev/null +++ b/.github/agents/speckit.agent-governance.refresh.agent.md @@ -0,0 +1,48 @@ +--- +description: Generate or update the active agent governance file +--- + + + + +# Agent Governance Generate/Update + +## Input + +$ARGUMENTS + +## Output + +- Active agent platform governance file. +- Managed `SPECKIT GOVERNANCE` section. +- `.specify/memory/agent-governance.md`: internal cache. + +## Procedure + +1. Require `.specify/`. +2. Resolve target: + - `.specify/init-options.json` `context_file` + - `.specify/integration.json` `default_integration` or `integration` + - `AGENTS.md` +3. Create internal cache when missing. +4. Generate target file when missing. +5. Update only the managed section when target exists. +6. Use existing managed section as refresh source. +7. Distill detected repository areas into action rules. + - depth: 2 + - include hidden and cache directories +8. Preserve content outside managed markers. +9. Preserve managed markers verbatim. +10. Run: + + ```bash + uv run python .specify/extensions/agent-governance/scripts/refresh_agent_governance.py + ``` + +## Report + +- target governance file +- generated or updated +- review target +- internal cache status +- captured evidence when cache is created \ No newline at end of file diff --git a/.github/agents/speckit.git.validate.agent.md b/.github/agents/speckit.git.validate.agent.md index dfd751f2a..3612dbaa6 100644 --- a/.github/agents/speckit.git.validate.agent.md +++ b/.github/agents/speckit.git.validate.agent.md @@ -29,20 +29,22 @@ The branch name must match one of these patterns: 1. **Sequential**: `^[0-9]{3,}-` (e.g., `001-feature-name`, `042-fix-bug`, `1000-big-feature`) 2. **Timestamp**: `^[0-9]{8}-[0-9]{6}-` (e.g., `20260319-143022-feature-name`) +3. **Conventional prefix**: `^(feat|fix|chore|docs|build|ci|refactor|test|deps)/` (e.g., `feat/add-node-filter`, `fix/ble-reconnect`) ## Execution If on a feature branch (matches either pattern): - Output: `✓ On feature branch: ` -- Check if the corresponding spec directory exists under `specs/`: +- For sequential/timestamp branches, check if the corresponding spec directory exists under `specs/`: - For sequential branches, look for `specs/-*` where prefix matches the numeric portion - For timestamp branches, look for `specs/-*` where prefix matches the `YYYYMMDD-HHMMSS` portion +- For conventional prefix branches, skip spec directory lookup (not spec-driven) - If spec directory exists: `✓ Spec directory found: ` - If spec directory missing: `⚠ No spec directory found for prefix ` If NOT on a feature branch: - Output: `✗ Not on a feature branch. Current branch: ` -- Output: `Feature branches should be named like: 001-feature-name or 20260319-143022-feature-name` +- Output: `Feature branches should be named like: 001-feature-name, feat/feature-name, or 20260319-143022-feature-name` ## Graceful Degradation diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 0d5c63353..f6f0e772a 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -1,6 +1,6 @@ # Meshtastic Android — Copilot Instructions -> **Full rules**: `AGENTS.md` is the source of truth. This file is a compact quick-reference for build commands and task naming. For architecture, conventions, and workflow details, consult `AGENTS.md` and the `.skills/` playbooks listed at the bottom. +> **Full rules**: `AGENTS.md` is the source of truth. This file is a compact quick-reference for build commands and task naming. For architecture, conventions, and workflow details, consult `AGENTS.md` and the `.skills/` playbooks. ## Build, Test & Lint @@ -46,33 +46,14 @@ KMP modules have different task names than pure-Android modules. Using the wrong ## Quick Reference -- **Architecture**: KMP project (Android, Desktop, iOS). Business logic in `commonMain`; platform shells (`androidApp/`, `desktopApp/`) wire DI and host UI. See `AGENTS.md` and `.skills/kmp-architecture/`. +- **Architecture**: KMP project (Android, Desktop, iOS). Business logic in `commonMain`; platform shells (`androidApp/`, `desktopApp/`) wire DI and host UI. - **Flavors**: `fdroid` (OSS) / `google` (Maps + DataDog). Only one installable at a time (different signing keys). -- **Verify before push**: Run `./gradlew spotlessApply detekt assembleDebug test allTests`, then confirm CI with `gh pr checks `. -- **Strings**: `stringResource(Res.string.key)` — run `python3 scripts/sort-strings.py` after adding strings. -- **Icons**: `MeshtasticIcons` (from `core/ui/icon/`), not `material.icons.Icons`. -- **Error handling**: `safeCatching {}` (not `runCatching {}`) in coroutine code. -- **Dispatchers**: `org.meshtastic.core.common.util.ioDispatcher`, not `Dispatchers.IO`. -- **Navigation**: `MeshtasticNavDisplay` + `NavigationBackHandler` (not Android `BackHandler`). -- **Protos**: `core/proto/` is a read-only git submodule. Never modify proto files. -- **Branches**: Must start with `feat/`, `fix/`, `chore/`, `docs/`, `build/`, `ci/`, `refactor/`, `test/`, `deps/`, or a numeric spec prefix. Always branch off `origin/main`. + +> See `AGENTS.md` for full rules (verify before push, branch naming, protos, coding conventions). +> Contextual `.github/instructions/` files enforce conventions scoped to relevant source sets. -## Active Plan - -- **Feature**: Reorder Bottom Navigation Tab Labels -- **Plan**: `specs/20260520-153412-nav-tab-labels/plan.md` -- **Branch**: `jamesarich/issue-5543-alignment-reorder-bottom-navigation-tab-91d55d` +For additional context about technologies to be used, project structure, +shell commands, and other important information, read the current plan -## Deeper Guidance - -Consult `.skills/` for detailed playbooks: -- `.skills/project-overview/` — Full codebase map and bootstrap -- `.skills/kmp-architecture/` — Source-set rules, expect/actual -- `.skills/compose-ui/` — Adaptive UI, string resources -- `.skills/navigation-and-di/` — Nav 3 & Koin patterns -- `.skills/testing-ci/` — CI architecture, verification matrix -- `.skills/implement-feature/` — Feature development workflow -- `.skills/code-review/` — PR hygiene checklist -- `.skills/speckit/` — Spec Kit SDD workflow, slash commands, constitution diff --git a/.github/prompts/speckit.agent-governance.refresh.prompt.md b/.github/prompts/speckit.agent-governance.refresh.prompt.md new file mode 100644 index 000000000..0df335b5d --- /dev/null +++ b/.github/prompts/speckit.agent-governance.refresh.prompt.md @@ -0,0 +1,3 @@ +--- +agent: speckit.agent-governance.refresh +--- diff --git a/.specify/extensions.yml b/.specify/extensions.yml index 05a4c8c7b..cb6ff2294 100644 --- a/.specify/extensions.yml +++ b/.specify/extensions.yml @@ -1,4 +1,5 @@ -installed: [] +installed: +- agent-governance settings: auto_execute_hooks: true hooks: @@ -82,6 +83,13 @@ hooks: prompt: Commit constitution changes? description: Auto-commit after constitution update condition: null + - extension: agent-governance + command: speckit.agent-governance.refresh + enabled: true + optional: true + prompt: Refresh agent governance after constitution changes? + description: Generates the active agent platform governance file + condition: null after_specify: - extension: git command: speckit.git.commit @@ -106,6 +114,13 @@ hooks: prompt: Commit plan changes? description: Auto-commit after implementation planning condition: null + - extension: agent-governance + command: speckit.agent-governance.refresh + enabled: true + optional: true + prompt: Refresh agent governance after planning? + description: Keeps the active agent platform governance file aligned + condition: null after_tasks: - extension: git command: speckit.git.commit @@ -114,6 +129,13 @@ hooks: prompt: Commit task changes? description: Auto-commit after task generation condition: null + - extension: agent-governance + command: speckit.agent-governance.refresh + enabled: true + optional: true + prompt: Refresh agent governance after task generation? + description: Keeps the active agent platform governance file aligned + condition: null after_implement: - extension: git command: speckit.git.commit diff --git a/.specify/extensions/.cache/catalog-metadata.json b/.specify/extensions/.cache/catalog-metadata.json index fe4796215..cd9a4e0f3 100644 --- a/.specify/extensions/.cache/catalog-metadata.json +++ b/.specify/extensions/.cache/catalog-metadata.json @@ -1,4 +1,4 @@ { - "cached_at": "2026-05-09T17:19:49.660998+00:00", + "cached_at": "2026-05-21T18:06:13.258618+00:00", "catalog_url": "https://raw.githubusercontent.com/github/spec-kit/main/extensions/catalog.json" } \ No newline at end of file diff --git a/.specify/extensions/.registry b/.specify/extensions/.registry index 3e225091c..feace7de3 100644 --- a/.specify/extensions/.registry +++ b/.specify/extensions/.registry @@ -108,6 +108,23 @@ }, "registered_skills": [], "installed_at": "2026-05-09T00:25:20.640435+00:00" + }, + "agent-governance": { + "version": "1.2.0", + "source": "local", + "manifest_hash": "sha256:99b9bb818d30379426ffd15e31660bf7e762eb90d1cca22ebcd4dd27b78f94a2", + "enabled": false, + "priority": 10, + "registered_commands": { + "copilot": [ + "speckit.agent-governance.refresh" + ], + "opencode": [ + "speckit.agent-governance.refresh" + ] + }, + "registered_skills": [], + "installed_at": "2026-05-21T18:07:24.505929+00:00" } } -} +} \ No newline at end of file diff --git a/.specify/extensions/agent-governance/.gitignore b/.specify/extensions/agent-governance/.gitignore new file mode 100644 index 000000000..d40d1eb93 --- /dev/null +++ b/.specify/extensions/agent-governance/.gitignore @@ -0,0 +1,7 @@ +__pycache__/ +*.pyc +.pytest_cache/ +.DS_Store +.venv/ +dist/ +*.zip diff --git a/.specify/extensions/agent-governance/CHANGELOG.md b/.specify/extensions/agent-governance/CHANGELOG.md new file mode 100644 index 000000000..dab737d13 --- /dev/null +++ b/.specify/extensions/agent-governance/CHANGELOG.md @@ -0,0 +1,40 @@ +# Changelog + +## Unreleased + +## [1.2.0] - 2026-05-19 + +### Changed + +- Initialize the missing governance evidence cache from repository evidence instead of copying the bundled template verbatim. +- Document captured repository evidence and manifest-backed commands in the initial governance evidence cache. +- Clarify that the extension generates active agent platform repository governance files from Spec Kit metadata. +- Simplify command semantics to one generate/update command: missing target governance files are generated, existing target governance files are updated. +- Include repository evidence and development commands in generated agent platform governance files. +- Add `uv`/`pytest` development configuration so the repository test suite has a reproducible runner. +- Treat the generated active agent platform section as the repository governance SSOT and `.specify/memory/agent-governance.md` as a first-run evidence cache. +- Preserve reviewed governance content from an existing active generated section during refresh instead of re-reading rules from the memory cache. +- Clarify that users review only the resolved active agent governance file; no separate memory review or second refresh is required. +- Distill detected repository areas into generated action rules with depth limited to two directory levels, including hidden and cache directories. +- Add generic directory responsibility governance without platform or project examples. +- Tighten governance template wording to preserve managed markers, scope broad linked-file updates, and limit skill-spec field requirements to repository-local skills. + +## [1.1.0] - 2026-05-15 + +### Changed + +- Decoupled the agent governance domain from specific project-governance source files. +- Updated generated projections to describe project governance as an independent domain. + +### Added + +- Tests for template and projection domain boundaries. + +## [1.0.0] - 2026-05-14 + +### Added + +- Initial `speckit.agent-governance.refresh` command. +- Agent governance memory template. +- Python helper to project managed governance sections into active agent context files. +- Optional hooks after constitution, plan, and tasks workflows. diff --git a/.specify/extensions/agent-governance/LICENSE b/.specify/extensions/agent-governance/LICENSE new file mode 100644 index 000000000..1fb116dbe --- /dev/null +++ b/.specify/extensions/agent-governance/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 bigben + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/.specify/extensions/agent-governance/README.md b/.specify/extensions/agent-governance/README.md new file mode 100644 index 000000000..7feb90de9 --- /dev/null +++ b/.specify/extensions/agent-governance/README.md @@ -0,0 +1,58 @@ +# Spec Kit Agent Governance + +Generate the active agent platform governance SSOT section. + +## Output + +- Active target file from Spec Kit integration metadata. +- Managed `SPECKIT GOVERNANCE` section. + +## Scope + +- Generate missing target governance file. +- Update existing target governance file. +- Distill detected repository areas into action rules. +- Analyze repository areas to depth 2 only. +- Include hidden and cache directories in repository area governance. +- Enforce one primary responsibility per directory. +- Preserve user-authored content outside managed markers. +- Preserve managed markers verbatim. +- Keep `.specify/memory/agent-governance.md` internal. +- Review only the active target file. + +## Install + +```bash +specify extension add agent-governance --from https://github.com/bigsmartben/spec-kit-agent-governance/archive/refs/tags/v1.2.0.zip +``` + +Local development: + +```bash +specify extension add --dev /path/to/spec-kit-agent-governance +``` + +## Run + +```text +/speckit.agent-governance.refresh +``` + +Helper: + +```bash +uv run python .specify/extensions/agent-governance/scripts/refresh_agent_governance.py +``` + +## Files + +- `extension.yml` +- `commands/speckit.agent-governance.refresh.md` +- `scripts/refresh_agent_governance.py` +- `templates/agent-governance-template.md` + +## Verify + +```bash +uv run pytest -q +``` diff --git a/.specify/extensions/agent-governance/commands/speckit.agent-governance.refresh.md b/.specify/extensions/agent-governance/commands/speckit.agent-governance.refresh.md new file mode 100644 index 000000000..0a4f20443 --- /dev/null +++ b/.specify/extensions/agent-governance/commands/speckit.agent-governance.refresh.md @@ -0,0 +1,45 @@ +--- +description: "Generate or update the active agent governance file" +--- + +# Agent Governance Generate/Update + +## Input + +$ARGUMENTS + +## Output + +- Active agent platform governance file. +- Managed `SPECKIT GOVERNANCE` section. +- `.specify/memory/agent-governance.md`: internal cache. + +## Procedure + +1. Require `.specify/`. +2. Resolve target: + - `.specify/init-options.json` `context_file` + - `.specify/integration.json` `default_integration` or `integration` + - `AGENTS.md` +3. Create internal cache when missing. +4. Generate target file when missing. +5. Update only the managed section when target exists. +6. Use existing managed section as refresh source. +7. Distill detected repository areas into action rules. + - depth: 2 + - include hidden and cache directories +8. Preserve content outside managed markers. +9. Preserve managed markers verbatim. +10. Run: + + ```bash + uv run python .specify/extensions/agent-governance/scripts/refresh_agent_governance.py + ``` + +## Report + +- target governance file +- generated or updated +- review target +- internal cache status +- captured evidence when cache is created diff --git a/.specify/extensions/agent-governance/extension.yml b/.specify/extensions/agent-governance/extension.yml new file mode 100644 index 000000000..d9ee1da34 --- /dev/null +++ b/.specify/extensions/agent-governance/extension.yml @@ -0,0 +1,46 @@ +schema_version: "1.0" + +extension: + id: agent-governance + name: "Agent Governance" + version: "1.2.0" + description: "Generate agent-platform repository governance files from Spec Kit metadata" + author: "bigben" + repository: "https://github.com/bigsmartben/spec-kit-agent-governance" + homepage: "https://github.com/bigsmartben/spec-kit-agent-governance" + license: "MIT" + +requires: + speckit_version: ">=0.8.0" + tools: + - name: "uv" + required: true + +provides: + commands: + - name: "speckit.agent-governance.refresh" + file: "commands/speckit.agent-governance.refresh.md" + description: "Generate or update the active agent platform governance file" + +hooks: + after_constitution: + command: "speckit.agent-governance.refresh" + optional: true + prompt: "Refresh agent governance after constitution changes?" + description: "Generates the active agent platform governance file" + after_plan: + command: "speckit.agent-governance.refresh" + optional: true + prompt: "Refresh agent governance after planning?" + description: "Keeps the active agent platform governance file aligned" + after_tasks: + command: "speckit.agent-governance.refresh" + optional: true + prompt: "Refresh agent governance after task generation?" + description: "Keeps the active agent platform governance file aligned" + +tags: + - "governance" + - "agents" + - "memory" + - "context" diff --git a/.specify/extensions/agent-governance/scripts/refresh_agent_governance.py b/.specify/extensions/agent-governance/scripts/refresh_agent_governance.py new file mode 100644 index 000000000..fd43ca163 --- /dev/null +++ b/.specify/extensions/agent-governance/scripts/refresh_agent_governance.py @@ -0,0 +1,656 @@ +#!/usr/bin/env python3 +"""Generate or refresh Spec Kit agent platform governance for the current project.""" + +from __future__ import annotations + +import json +import re +import sys +from pathlib import Path +from typing import Any + + +MEMORY_PATH = Path(".specify/memory/agent-governance.md") +TEMPLATE_PATH = Path(".specify/extensions/agent-governance/templates/agent-governance-template.md") +INTEGRATION_JSON = Path(".specify/integration.json") +INIT_OPTIONS_JSON = Path(".specify/init-options.json") + +MARKER_START = "" +MARKER_END = "" + +CONTEXT_FILES = { + "agy": "AGENTS.md", + "amp": "AGENTS.md", + "auggie": ".augment/rules/specify-rules.md", + "bob": "AGENTS.md", + "claude": "CLAUDE.md", + "codebuddy": "CODEBUDDY.md", + "codex": "AGENTS.md", + "copilot": ".github/copilot-instructions.md", + "cursor-agent": ".cursor/rules/specify-rules.mdc", + "devin": "AGENTS.md", + "forge": "AGENTS.md", + "gemini": "GEMINI.md", + "generic": "AGENTS.md", + "goose": "AGENTS.md", + "iflow": "IFLOW.md", + "junie": ".junie/AGENTS.md", + "kilocode": ".kilocode/rules/specify-rules.md", + "kimi": "KIMI.md", + "kiro-cli": "AGENTS.md", + "lingma": ".lingma/rules/specify-rules.md", + "opencode": "AGENTS.md", + "pi": "AGENTS.md", + "qodercli": "QODER.md", + "qwen": "QWEN.md", + "roo": ".roo/rules/specify-rules.md", + "shai": "SHAI.md", + "tabnine": "TABNINE.md", + "trae": ".trae/rules/project_rules.md", + "vibe": "AGENTS.md", + "windsurf": ".windsurf/rules/specify-rules.md", +} + + +def main() -> int: + root = Path.cwd() + if not (root / ".specify").is_dir(): + print("Error: .specify/ not found. Run from a Spec Kit project root.", file=sys.stderr) + return 1 + + state = read_json(root / INTEGRATION_JSON) + init_options = read_json(root / INIT_OPTIONS_JSON) + created_memory = ensure_memory(root) + target = resolve_target(root, state, init_options) + projection = render_projection(root, target, state, created_memory) + evidence_summary = repository_evidence_summary(root, state, init_options) if created_memory else "" + action = write_projection(target, projection) + remove_stale_sections(root, target, init_options, state) + + print(f"Target governance file: {rel(root, target)}") + print(f"Governance file: {action}") + print(f"Review target: {rel(root, target)}") + print(f"Internal initialization cache: {MEMORY_PATH.as_posix()} ({'created' if created_memory else 'existing'})") + if created_memory: + print(f"Repository evidence: {evidence_summary}") + return 0 + + +def ensure_memory(root: Path) -> bool: + memory = root / MEMORY_PATH + if memory.exists(): + return False + template = root / TEMPLATE_PATH + if not template.exists(): + raise SystemExit(f"Error: template not found: {TEMPLATE_PATH.as_posix()}") + memory.parent.mkdir(parents=True, exist_ok=True) + memory.write_text(render_initial_memory(root, template.read_text(encoding="utf-8-sig")), encoding="utf-8") + return True + + +def render_initial_memory(root: Path, template: str) -> str: + content = normalize_newlines(template) + state = read_json(root / INTEGRATION_JSON) + init_options = read_json(root / INIT_OPTIONS_JSON) + content = replace_sync_report(content, root, state) + evidence = "\n".join( + [ + "## Repository Evidence", + "", + *repository_evidence_lines(root, state, init_options), + "", + "## Repository Areas", + "", + *repository_area_lines(root), + "", + "## Development Commands", + "", + *development_command_lines(root), + "", + ] + ) + marker = "\n## Scope\n" + if marker in content: + content = content.replace(marker, f"\n{evidence}{marker}", 1) + else: + content = content.rstrip() + "\n\n" + evidence + return content + + +def replace_sync_report(content: str, root: Path, state: dict[str, Any]) -> str: + report = "\n".join( + [ + "", + ] + ) + pattern = re.compile(r"", re.DOTALL) + if pattern.search(content): + return pattern.sub(report, content, count=1) + return content + + +def repository_evidence_summary(root: Path, state: dict[str, Any], init_options: dict[str, Any]) -> str: + evidence = repository_evidence_lines(root, state, init_options) + detected = [line for line in evidence if "none detected" not in line and "`unknown`" not in line] + return "; ".join(line.removeprefix("- ") for line in detected) or "none detected" + + +def repository_evidence_lines(root: Path, state: dict[str, Any], init_options: dict[str, Any]) -> list[str]: + lines = [ + evidence_line("README", existing_paths(root, ["README.md", "README.markdown", "README.txt"])), + evidence_line( + "Package manifest", + existing_paths(root, ["package.json", "pyproject.toml", "Cargo.toml", "go.mod", "Gemfile", "pom.xml", "build.gradle", "build.gradle.kts"]), + ), + evidence_line( + "Lockfiles", + existing_paths(root, ["package-lock.json", "pnpm-lock.yaml", "yarn.lock", "uv.lock", "poetry.lock", "Cargo.lock", "go.sum", "Gemfile.lock"]), + ), + evidence_line("Task runners", existing_paths(root, ["Makefile", "Taskfile.yml", "Taskfile.yaml", "justfile"])), + evidence_line("CI workflows", directory_files(root, ".github/workflows")), + evidence_line("Source paths", existing_dirs(root, ["src", "app", "lib", "scripts", "commands", "templates"])), + evidence_line("Test paths", existing_dirs(root, ["test", "tests", "spec", "specs"])), + evidence_line("Repository areas", repository_area_paths(root)), + evidence_line("Existing agent context files", existing_context_files(root, init_options, state)), + evidence_line("Repository-local skills", scan_skills(root)), + evidence_line("MCP configs", scan_mcp_configs(root)), + f"- Active integration: `{default_integration(state) or 'unknown'}`", + f"- Resolved context file: `{rel(root, resolve_target(root, state, init_options))}`", + ] + return lines + + +def evidence_line(label: str, values: list[str]) -> str: + return f"- {label}: {format_values(values)}" + + +def format_values(values: list[str]) -> str: + return ", ".join(f"`{value}`" for value in values) if values else "none detected" + + +def existing_paths(root: Path, names: list[str]) -> list[str]: + return [name for name in names if (root / name).is_file()] + + +def existing_dirs(root: Path, names: list[str]) -> list[str]: + return [f"{name}/" for name in names if (root / name).is_dir()] + + +def directory_files(root: Path, directory: str) -> list[str]: + base = root / directory + if not base.is_dir(): + return [] + return sorted(rel(root, path) for path in base.iterdir() if path.is_file()) + + +def repository_area_lines(root: Path) -> list[str]: + lines = [] + for area in repository_area_paths(root): + if "/" in area.rstrip("/"): + parent = area.rstrip("/").split("/", 1)[0] + "/" + lines.append(f"- `{area}`: change with parent area `{parent}`.") + else: + lines.append(f"- `{area}`: review before changing linked areas.") + return lines or ["- none detected"] + + +def repository_area_paths(root: Path) -> list[str]: + areas: list[str] = [] + for path in sorted(root.iterdir()): + if not path.is_dir(): + continue + areas.append(f"{path.name}/") + for child in sorted(path.iterdir()): + if child.is_dir(): + areas.append(f"{path.name}/{child.name}/") + return areas + + +def existing_context_files(root: Path, init_options: dict[str, Any], state: dict[str, Any]) -> list[str]: + paths: set[Path] = {root / "AGENTS.md"} + for value in CONTEXT_FILES.values(): + target = safe_project_path(root, value) + if target is not None: + paths.add(target) + init_target = safe_project_path(root, init_options.get("context_file")) + if init_target is not None: + paths.add(init_target) + resolved = resolve_target(root, state, init_options) + paths.add(resolved) + return sorted(rel(root, path) for path in paths if path.exists()) + + +def development_command_lines(root: Path) -> list[str]: + commands = package_script_lines(root) + if commands: + commands.append("- manifest commands over ad hoc equivalents") + return commands + return ["- none detected"] + + +def package_script_lines(root: Path) -> list[str]: + package_json = root / "package.json" + data = read_json(package_json) + scripts = data.get("scripts") + if not isinstance(scripts, dict): + return [] + result: list[str] = [] + for name in sorted(scripts): + value = scripts[name] + if not isinstance(value, str) or not value.strip(): + continue + command = f"npm {name}" if name in {"start", "stop", "test", "restart"} else f"npm run {name}" + result.append(f"- `{command}` -> `{value.strip()}`") + return result + + +def read_json(path: Path) -> dict[str, Any]: + if not path.exists(): + return {} + try: + data = json.loads(path.read_text(encoding="utf-8")) + except (json.JSONDecodeError, OSError, UnicodeDecodeError): + return {} + return data if isinstance(data, dict) else {} + + +def resolve_target(root: Path, state: dict[str, Any], init_options: dict[str, Any]) -> Path: + for value in ( + init_options.get("context_file"), + CONTEXT_FILES.get(default_integration(state) or ""), + "AGENTS.md", + ): + target = safe_project_path(root, value) + if target is not None: + return target + return root / "AGENTS.md" + + +def safe_project_path(root: Path, value: Any) -> Path | None: + if not isinstance(value, str) or not value.strip(): + return None + raw = Path(value.strip()) + candidate = raw if raw.is_absolute() else root / raw + try: + candidate.resolve(strict=False).relative_to(root.resolve()) + except (OSError, ValueError): + return None + return candidate + + +def default_integration(state: dict[str, Any]) -> str | None: + for key in ("default_integration", "integration"): + value = state.get(key) + if isinstance(value, str) and value.strip(): + return value.strip() + installed = state.get("installed_integrations") + if isinstance(installed, list): + for value in installed: + if isinstance(value, str) and value.strip(): + return value.strip() + return None + + +def installed_integrations(state: dict[str, Any]) -> list[str]: + seen: set[str] = set() + values = state.get("installed_integrations") + if not isinstance(values, list): + values = [] + default = default_integration(state) + ordered = ([default] if default else []) + values + result: list[str] = [] + for value in ordered: + if not isinstance(value, str) or not value.strip(): + continue + clean = value.strip() + if clean not in seen: + seen.add(clean) + result.append(clean) + return result + + +def render_projection(root: Path, target: Path, state: dict[str, Any], created_memory: bool) -> str: + source_text, source_label = governance_source(root, target) + default_key = default_integration(state) or "unknown" + installed = installed_integrations(state) + style = projection_style(target) + lines = [ + MARKER_START, + "## Repository Governance", + "- SSOT: this managed section.", + f"- Target: {rel(root, target)}", + f"- Active integration: {default_key}", + f"- Refresh source: {source_label}", + f"- Cache: {MEMORY_PATH.as_posix()} ({'created' if created_memory else 'present'})", + "", + "## Scope", + "- agent collaboration rules", + "- tool and MCP permissions", + "- write boundaries", + "- skill invocation contracts", + "- project governance: external", + "", + "## Context", + f"- Installed integrations: {', '.join(installed) if installed else 'none'}", + f"- Skills: {', '.join(scan_skills(root)) or 'none'}", + f"- MCP configs: {', '.join(scan_mcp_configs(root)) or 'none'}", + f"- Extensions config: .specify/extensions.yml ({extensions_status(root)})", + "", + "## Repository Evidence", + *section_or_default(source_text, ["## Repository Evidence"], repository_evidence_default()), + "", + "## Repository Areas", + *section_or_default(source_text, ["## Repository Areas"], repository_areas_default()), + "", + "## Directory Governance", + *section_or_default(source_text, ["## Directory Governance"], directory_governance_default()), + "", + "## Development Commands", + *section_or_default(source_text, ["## Development Commands"], development_commands_default()), + "", + "## Authority", + "1. Current user instruction", + "2. Active `SPECKIT GOVERNANCE` section", + "3. User-authored repository instructions for agent behavior", + "4. Skill-local `SKILL.md`", + "5. Tool and MCP defaults", + "", + "## Repository Workflow", + "- Read: Repository Evidence", + "- Run: Development Commands", + "- Scope: active task only", + "- Preserve: user-authored edits", + "- Protected files: implementation, CI, MCP config, secrets, permissions, tool settings", + "- Protected-file writes: explicit user request only", + "- External writes: authorized target and action only", + "- Handoff: changed files, commands, validation, risks", + "", + "## Write Boundaries", + *section_or_default(source_text, ["## Write Boundaries"], write_boundary_default(style)), + "", + "## MCP And External Tools", + *section_or_default(source_text, ["## MCP And External Tools", "## MCP And External Tool Policy", "## MCP Policy"], mcp_default(style)), + "", + "## Skills", + *section_or_default(source_text, ["## Skills", "## Skill Usage Policy", "## Skill Contract"], skill_default(style)), + "", + "## Handoff", + *section_or_default(source_text, ["## Handoff", "## Required Handoff Report", "## Validation"], handoff_default(style)), + MARKER_END, + "", + ] + return "\n".join(lines) + + +def write_projection(target: Path, projection: str) -> str: + existed = target.exists() + existing = target.read_text(encoding="utf-8-sig") if target.exists() else "" + updated = upsert_section(existing, projection) + if target.suffix == ".mdc": + updated = ensure_mdc_frontmatter(updated) + target.parent.mkdir(parents=True, exist_ok=True) + target.write_text(normalize_newlines(updated), encoding="utf-8") + return "updated" if existed else "generated" + + +def upsert_section(content: str, projection: str) -> str: + start = content.find(MARKER_START) + end = content.find(MARKER_END, start if start != -1 else 0) + if start != -1 and end != -1 and end > start: + end += len(MARKER_END) + if end < len(content) and content[end] == "\r": + end += 1 + if end < len(content) and content[end] == "\n": + end += 1 + return content[:start] + projection + content[end:] + if content and not content.endswith("\n"): + content += "\n" + return content + ("\n" if content else "") + projection + + +def remove_stale_sections(root: Path, active: Path, init_options: dict[str, Any], state: dict[str, Any]) -> None: + paths = {root / "AGENTS.md"} + for value in CONTEXT_FILES.values(): + target = safe_project_path(root, value) + if target is not None: + paths.add(target) + init_target = safe_project_path(root, init_options.get("context_file")) + if init_target is not None: + paths.add(init_target) + for path in paths: + if same_path(path, active): + continue + remove_section(path) + + +def remove_section(path: Path) -> None: + if not path.exists(): + return + content = path.read_text(encoding="utf-8-sig") + start = content.find(MARKER_START) + end = content.find(MARKER_END, start if start != -1 else 0) + if start == -1 or end == -1 or end <= start: + return + removal_end = end + len(MARKER_END) + if removal_end < len(content) and content[removal_end] == "\r": + removal_end += 1 + if removal_end < len(content) and content[removal_end] == "\n": + removal_end += 1 + removal_start = start + if removal_start > 1 and content[removal_start - 1] == "\n" and content[removal_start - 2] == "\n": + removal_start -= 1 + updated = normalize_newlines(content[:removal_start] + content[removal_end:]) + if not updated.strip() or (path.suffix == ".mdc" and re.match(r"^---\n.*?\n---\s*$", updated, re.DOTALL)): + path.unlink() + else: + path.write_text(updated, encoding="utf-8") + + +def governance_source(root: Path, target: Path) -> tuple[str, str]: + managed = extract_managed_section(target) + if managed: + return managed, "active generated section" + memory = root / MEMORY_PATH + try: + return normalize_newlines(memory.read_text(encoding="utf-8-sig")), "initialization cache" + except (OSError, UnicodeDecodeError): + return "", "built-in defaults" + + +def section_or_default(source_text: str, headings: list[str], default: list[str]) -> list[str]: + for heading in headings: + section = extract_section_from_text(source_text, heading) + if section: + return section + return default + + +def repository_evidence_default() -> list[str]: + return ["- none captured"] + + +def repository_areas_default() -> list[str]: + return ["- none detected"] + + +def directory_governance_default() -> list[str]: + return [ + "- Responsibility: one primary purpose per directory.", + "- Depth: 2.", + "- Coverage: include visible, hidden, generated, cache, config/env, tool, and agent directories.", + "- Mixed concerns: follow existing repo convention or split responsibility.", + "- Change impact: review linked code, tests, docs, config/env, data, assets, generated files, and tool outputs; update only when in scope and authorized.", + ] + + +def development_commands_default() -> list[str]: + return ["- none recorded"] + + +def extract_section(path: Path, heading: str) -> list[str]: + try: + return extract_section_from_text(path.read_text(encoding="utf-8-sig"), heading) + except (OSError, UnicodeDecodeError): + return [] + + +def extract_managed_section(path: Path) -> str: + try: + content = normalize_newlines(path.read_text(encoding="utf-8-sig")) + except (OSError, UnicodeDecodeError): + return "" + start = content.find(MARKER_START) + end = content.find(MARKER_END, start if start != -1 else 0) + if start == -1 or end == -1 or end <= start: + return "" + return content[start + len(MARKER_START) : end] + + +def extract_section_from_text(text: str, heading: str) -> list[str]: + lines = normalize_newlines(text).splitlines() + capture = False + result: list[str] = [] + for line in lines: + if line.strip() == heading: + capture = True + continue + if capture and line.startswith("## "): + break + if capture and line.strip(): + result.append(line) + return result + + +def projection_style(path: Path) -> str: + rel_path = path.as_posix() + if rel_path.endswith(".github/copilot-instructions.md"): + return "copilot" + if path.suffix == ".mdc" or "/rules/" in rel_path: + return "rule" + return "agent" + + +def style_lead(style: str) -> str: + if style == "copilot": + return "Use these as concise Copilot custom instructions for this repository." + if style == "rule": + return "Apply these repository rules before planning, editing, or using tools." + return "Follow these repository instructions when working in this project." + + +def write_boundary_default(style: str) -> list[str]: + if style == "rule": + return [ + "- Stay inside the active task scope.", + "- Preserve user-authored edits.", + "- Preserve managed markers verbatim: `` and ``.", + ] + return [ + "- Keep edits inside the active task scope and preserve user changes.", + "- Preserve managed markers verbatim: `` and ``.", + ] + + +def mcp_default(style: str) -> list[str]: + return ["- Read-only unless the user authorizes mutation.", "- External writes: target, action, expected effect."] + + +def skill_default(style: str) -> list[str]: + return [ + "- Use active skill `SKILL.md`.", + "- Write scope: declared skill paths only.", + "- Repository-local skill specs should declare purpose, trigger, allowed read paths, allowed write paths, forbidden paths, outputs, and validation command.", + ] + + +def handoff_default(style: str) -> list[str]: + return ["- changed files", "- commands run", "- validation result", "- unresolved risks"] + + +def scan_feature_specs(root: Path) -> str: + specs = root / "specs" + if not specs.is_dir(): + return "none" + entries = [] + for feature in sorted(path for path in specs.iterdir() if path.is_dir()): + statuses = [f"{name}:{'present' if (feature / name).exists() else 'missing'}" for name in ("spec.md", "plan.md", "tasks.md")] + entries.append(f"{rel(root, feature)} ({', '.join(statuses)})") + return ", ".join(entries) if entries else "none" + + +def scan_skills(root: Path) -> list[str]: + return sorted(rel(root, path) for path in root.rglob("SKILL.md") if not ignored(path)) + + +def scan_mcp_configs(root: Path) -> list[str]: + names = {".mcp.json", "mcp.json", "mcp.yml", "mcp.yaml", "mcp.config.json"} + return sorted( + rel(root, path) + for path in root.rglob("*") + if path.is_file() and not ignored(path) and (path.name in names or "mcp" in path.name.lower()) + ) + + +def ignored(path: Path) -> bool: + return any(part in {".git", "__pycache__", ".venv", "node_modules"} for part in path.parts) + + +def extensions_status(root: Path) -> str: + path = root / ".specify/extensions.yml" + if not path.exists(): + return "missing" + return "present" + + +def exists(root: Path, value: str) -> str: + return "present" if (root / value).exists() else "missing" + + +def ensure_mdc_frontmatter(content: str) -> str: + stripped = content.lstrip() + if not stripped.startswith("---"): + return "---\nalwaysApply: true\n---\n\n" + content + match = re.match(r"^(---[ \t]*\n)(.*?)(\n---[ \t]*)(\n|$)(.*)", stripped, re.DOTALL) + if not match: + return "---\nalwaysApply: true\n---\n\n" + content + opening, frontmatter, closing, sep, rest = match.groups() + if re.search(r"(?m)^[ \t]*alwaysApply[ \t]*:[ \t]*true[ \t]*$", frontmatter): + return content + if re.search(r"(?m)^[ \t]*alwaysApply[ \t]*:", frontmatter): + frontmatter = re.sub(r"(?m)^([ \t]*)alwaysApply[ \t]*:.*$", r"\1alwaysApply: true", frontmatter, count=1) + elif frontmatter.strip(): + frontmatter += "\nalwaysApply: true" + else: + frontmatter = "alwaysApply: true" + return f"{opening}{frontmatter}{closing}{sep}{rest}" + + +def same_path(left: Path, right: Path) -> bool: + try: + return left.resolve(strict=False) == right.resolve(strict=False) + except OSError: + return left.absolute() == right.absolute() + + +def rel(root: Path, path: Path) -> str: + try: + return path.relative_to(root).as_posix() + except ValueError: + return path.as_posix() + + +def normalize_newlines(content: str) -> str: + return content.replace("\r\n", "\n").replace("\r", "\n") + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/.specify/extensions/agent-governance/templates/agent-governance-template.md b/.specify/extensions/agent-governance/templates/agent-governance-template.md new file mode 100644 index 000000000..99ec0519f --- /dev/null +++ b/.specify/extensions/agent-governance/templates/agent-governance-template.md @@ -0,0 +1,53 @@ +# Agent Governance Cache + + + +## Final Output + +- active agent platform governance file +- managed `SPECKIT GOVERNANCE` section +- cache: internal + +## Directory Governance + +- Responsibility: one primary purpose per directory. +- Depth: 2. +- Coverage: include visible, hidden, generated, cache, config/env, tool, and agent directories. +- Mixed concerns: follow existing repo convention or split responsibility. +- Change impact: review linked code, tests, docs, config/env, data, assets, generated files, and tool outputs; update only when in scope and authorized. + +## Scope + +- agent collaboration rules +- tool and MCP permissions +- write boundaries +- skill invocation contracts +- project governance: external + +## Write Boundaries + +- Scope: active task only +- Preserve: user-authored edits +- Preserve managed markers verbatim: `` and `` +- Protected files: implementation, CI, MCP config, secrets, permissions, tool settings +- Protected-file writes: explicit user request only + +## Skill Contract + +- Repository-local skill specs should declare purpose, trigger, allowed read paths, allowed write paths, forbidden paths, outputs, and validation command. + +## MCP Policy + +- Default: read-only +- Mutation: explicit user intent +- External writes: target, action, result +- Secrets: never log, never write + +## Validation + +- changed files +- commands run +- tests/validation result +- unresolved risks diff --git a/.specify/extensions/review/scripts/bash/detect-changed-files.sh b/.specify/extensions/review/scripts/bash/detect-changed-files.sh old mode 100644 new mode 100755 diff --git a/.specify/extensions/verify/scripts/bash/load-config.sh b/.specify/extensions/verify/scripts/bash/load-config.sh old mode 100644 new mode 100755 diff --git a/.specify/init-options.json b/.specify/init-options.json index 3d0c55bc7..26d679582 100644 --- a/.specify/init-options.json +++ b/.specify/init-options.json @@ -1,9 +1,9 @@ { - "ai": "opencode", + "ai": "copilot", "branch_numbering": "timestamp", - "context_file": "AGENTS.md", + "context_file": ".github/copilot-instructions.md", "here": true, - "integration": "opencode", + "integration": "copilot", "script": "sh", "speckit_version": "0.8.8.dev0" } \ No newline at end of file diff --git a/.specify/integration.json b/.specify/integration.json index cf4062608..d626d19af 100644 --- a/.specify/integration.json +++ b/.specify/integration.json @@ -1,15 +1,15 @@ { - "version": "0.8.8.dev0", + "version": "0.8.13", "integration_state_schema": 1, "installed_integrations": [ - "opencode" + "copilot" ], "integration_settings": { - "opencode": { + "copilot": { "script": "sh", "invoke_separator": "." } }, - "integration": "opencode", - "default_integration": "opencode" + "integration": "copilot", + "default_integration": "copilot" } diff --git a/.specify/integrations/copilot.manifest.json b/.specify/integrations/copilot.manifest.json index ee84b97a7..49c1cdde9 100644 --- a/.specify/integrations/copilot.manifest.json +++ b/.specify/integrations/copilot.manifest.json @@ -1,7 +1,7 @@ { "integration": "copilot", - "version": "0.8.8.dev0", - "installed_at": "2026-05-07T18:49:21.970795+00:00", + "version": "0.8.13", + "installed_at": "2026-05-21T18:50:11.969212+00:00", "files": { ".github/agents/speckit.analyze.agent.md": "699032fdd49afe31d23c7191f3fe7bcb1d14b081fbc94c2287e6ba3a57574fda", ".github/agents/speckit.checklist.agent.md": "d7d691689fe45427c868dcf18ade4df500f0c742a6c91923fefba405d6466dde", diff --git a/.specify/integrations/opencode.manifest.json b/.specify/integrations/opencode.manifest.json deleted file mode 100644 index e8f999668..000000000 --- a/.specify/integrations/opencode.manifest.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "integration": "opencode", - "version": "0.8.8.dev0", - "installed_at": "2026-05-07T18:50:21.381460+00:00", - "files": { - ".opencode/command/speckit.analyze.md": "699032fdd49afe31d23c7191f3fe7bcb1d14b081fbc94c2287e6ba3a57574fda", - ".opencode/command/speckit.checklist.md": "d7d691689fe45427c868dcf18ade4df500f0c742a6c91923fefba405d6466dde", - ".opencode/command/speckit.clarify.md": "0cc766dcc5cab233ccdf3bc4cfb5759a6d7d1e13e29f611083046f818f5812bb", - ".opencode/command/speckit.constitution.md": "58d35eb026f56bb7364d91b8b0382d5dd1249ded6c1449a2b69546693afb85f7", - ".opencode/command/speckit.implement.md": "2acb475f761e5b65319c4e71847bd07b88c933b45da7be45e7801271f64fcd4d", - ".opencode/command/speckit.plan.md": "5b1e9c9b5a26a1877fe3b655a9350562cf5ee88788f9030e6b8a9dc1de88b347", - ".opencode/command/speckit.specify.md": "c7b1ab7ceafc42607e86dd6c0dab0b5cb74462a93a3cdd3b5e7173468cc88bdf", - ".opencode/command/speckit.tasks.md": "6b42e295fb67082392b4b62febf297c73655ea67cc9379cd5df80468e920cb4c", - ".opencode/command/speckit.taskstoissues.md": "e84794f7a839126defb364ca815352c5c2b2d20db2d6da399fa53e4ddbb7b3ee" - } -} diff --git a/.specify/integrations/speckit.manifest.json b/.specify/integrations/speckit.manifest.json index 7908f079c..c2358b888 100644 --- a/.specify/integrations/speckit.manifest.json +++ b/.specify/integrations/speckit.manifest.json @@ -1,6 +1,6 @@ { "integration": "speckit", - "version": "0.8.8.dev0", + "version": "0.8.13", "installed_at": "2026-05-07T18:46:46.194118+00:00", "files": { ".specify/scripts/bash/common.sh": "dd638316259e699fd466542c77ef16af5eb198efe0447c081f86b890db414ba8", @@ -10,8 +10,8 @@ ".specify/scripts/bash/create-new-feature.sh": "bcf4964ca0c6c78717bb42d9e66b8c7e5ee82779cd96afc5aa7b08b75abe5790", ".specify/templates/constitution-template.md": "ce7549540fa45543cca797a150201d868e64495fdff39dc38246fb17bd4024b3", ".specify/templates/checklist-template.md": "312eee8291dfa984b21f95ddd0ca778e7a1f0b3a64bfc470d79762a3e3f5d7b8", - ".specify/templates/tasks-template.md": "5da92ac1fbf5be2f9018a5064497995bf3592761ccb6b3951503c63d851297e8", - ".specify/templates/spec-template.md": "785dc50d856dd92d6515eca0761e16dce0c9ba0a3cd07154fd33eae77932422a", - ".specify/templates/plan-template.md": "873e84b226fe3d24afe28046931b20db9bbb9210366428dc958a515349ed6e68" + ".specify/templates/tasks-template.md": "c731575d8099b3f871861186fbd1a592b51b2ba57fb99e1a0dab439ff6d5608f", + ".specify/templates/spec-template.md": "3945437fc35cd30a5b2bf7beea680337c3516826d3efa5a6b92c4a7eca1ba28e", + ".specify/templates/plan-template.md": "3fdc12da2eb157def636948c157bfb638b265e70b2e3246a0e09c8d5db710e91" } } diff --git a/.specify/memory/agent-governance.md b/.specify/memory/agent-governance.md new file mode 100644 index 000000000..c1a8e45ba --- /dev/null +++ b/.specify/memory/agent-governance.md @@ -0,0 +1,84 @@ +# Agent Governance Cache + + + +## Final Output + +- active agent platform governance file +- managed `SPECKIT GOVERNANCE` section +- cache: internal + +## Directory Governance + +- Responsibility: one primary purpose per directory. +- Depth: 2. +- Coverage: include visible, hidden, generated, cache, config/env, tool, and agent directories. +- Mixed concerns: follow existing repo convention or split responsibility. +- Change impact: review linked code, tests, docs, config/env, data, assets, generated files, and tool outputs; update only when in scope and authorized. + +## Repository Evidence + +- README: `README.md` +- Package manifest: `Gemfile`, `build.gradle.kts` +- Lockfiles: `Gemfile.lock` +- Task runners: none detected +- CI workflows: `.github/workflows/create-or-promote-release.yml`, `.github/workflows/dependency-submission.yml`, `.github/workflows/docs-deploy.yml`, `.github/workflows/docs-governance.yml`, `.github/workflows/docs-release.yml`, `.github/workflows/main-check.yml`, `.github/workflows/merge-queue.yml`, `.github/workflows/models_issue_triage.yml`, `.github/workflows/models_pr_triage.yml`, `.github/workflows/moderate.yml`, `.github/workflows/post-release-cleanup.yml`, `.github/workflows/pr_enforce_labels.yml`, `.github/workflows/promote.yml`, `.github/workflows/publish-core.yml`, `.github/workflows/pull-request-target.yml`, `.github/workflows/pull-request.yml`, `.github/workflows/release.yml`, `.github/workflows/reusable-check.yml`, `.github/workflows/scheduled-updates.yml`, `.github/workflows/stale.yml`, `.github/workflows/sync-android-docs.yml`, `.github/workflows/update-changelog.yml` +- Source paths: `app/`, `scripts/` +- Test paths: `specs/` +- Repository areas: (see "Repository Areas" section below for top-level listing) +- Existing agent context files: `.github/copilot-instructions.md`, `AGENTS.md`, `CLAUDE.md`, `GEMINI.md` +- Repository-local skills: `.agent_refs/mqttastic-client-kmp/.github/skills/mqtt-kmp/SKILL.md`, `.skills/ci-cost-control/SKILL.md`, `.skills/code-review/SKILL.md`, `.skills/compose-ui/SKILL.md`, `.skills/design-standards/SKILL.md`, `.skills/implement-feature/SKILL.md`, `.skills/kmp-architecture/SKILL.md`, `.skills/navigation-and-di/SKILL.md`, `.skills/new-branch/SKILL.md`, `.skills/project-overview/SKILL.md`, `.skills/speckit/SKILL.md`, `.skills/testing-ci/SKILL.md` +- MCP configs: `.agent_refs/firmware/src/modules/Telemetry/Sensor/MCP9808Sensor.cpp`, `.agent_refs/firmware/src/modules/Telemetry/Sensor/MCP9808Sensor.h`, `androidApp/build/intermediates/incremental/googleDebug-mergeJavaRes/zip-cache/ut0r9CiGRq6mCprTK2blRg==`, `app/build/intermediates/incremental/fdroidDebug-mergeJavaRes/zip-cache/mcpnRT6ZHkD92YpTv5y52w==`, `app/build/intermediates/incremental/googleDebug-mergeJavaRes/zip-cache/mcpnRT6ZHkD92YpTv5y52w==`, `app/build/intermediates/incremental/googleDebug-mergeJavaRes/zip-cache/ut0r9CiGRq6mCprTK2blRg==` +- Active integration: `copilot` +- Resolved context file: `AGENTS.md` + +## Repository Areas + +**Policy**: Subdirectories inherit parent area governance rules. When modifying a subdirectory, +review the parent area's context for impact. Top-level directories require review before +changing linked areas; child directories change with their parent. + +**Top-level areas requiring review**: `.agent_memory/`, `.agent_plans/`, `.agent_refs/`, +`.github/`, `.specify/`, `androidApp/`, `app/`, `build-logic/`, `config/`, `core/`, +`desktop/`, `desktopApp/`, `docs/`, `docs-site/`, `fastlane/`, `feature/`, `gradle/`, +`ios/`, `iosApp/`, `offline-repository/`, `screenshot-tests/`, `scripts/`, `specs/` + +## Development Commands + +- none detected + +## Scope + +- agent collaboration rules +- tool and MCP permissions +- write boundaries +- skill invocation contracts +- project governance: external + +## Write Boundaries + +- Scope: active task only +- Preserve: user-authored edits +- Preserve managed markers verbatim: `` and `` +- Protected files: implementation, CI, MCP config, secrets, permissions, tool settings +- Protected-file writes: explicit user request only + +## Skill Contract + +- Repository-local skill specs should declare purpose, trigger, allowed read paths, allowed write paths, forbidden paths, outputs, and validation command. + +## MCP Policy + +- Default: read-only +- Mutation: explicit user intent +- External writes: target, action, result +- Secrets: never log, never write + +## Validation + +- changed files +- commands run +- tests/validation result +- unresolved risks diff --git a/.specify/memory/constitution.md b/.specify/memory/constitution.md index e7b45102c..56648f6d6 100644 --- a/.specify/memory/constitution.md +++ b/.specify/memory/constitution.md @@ -1,17 +1,14 @@ # Meshtastic Android (KMP) Constitution @@ -28,9 +25,7 @@ MUST be used in place of JVM/Android-specific APIs: - MUST NOT import `java.*` or `android.*` in any `commonMain` module. - Platform-specific implementations belong in `androidMain`/`desktopMain` actual declarations only. -- Rationale: The project goal is multi-platform parity (Android, Desktop, iOS). Framework - bleed in `commonMain` breaks compilability on non-Android targets and undermines the - entire decoupling effort. + ### II. Zero Lint Tolerance @@ -39,8 +34,7 @@ All code contributions MUST pass static analysis before merge: - `./gradlew spotlessApply` MUST be run and `spotlessCheck` MUST pass with no violations. - `detekt` MUST pass with no new violations introduced. - A task or PR is considered incomplete if either check fails. -- Rationale: Consistent code style and static analysis gates prevent technical debt - accumulation and catch bugs that tests alone miss. + ### III. Compose Multiplatform UI @@ -51,8 +45,7 @@ All UI MUST use JetBrains Compose Multiplatform, not Android-only Jetpack Compos - Floats MUST be pre-formatted using `NumberFormatter.format()` before display in any composable. - UI MUST compile and render correctly on all supported targets (Android, Compose Desktop). -- Rationale: Compose Multiplatform ensures UI consistency across platforms and enforces the - project's multi-platform architecture goal. + ### IV. Privacy First @@ -65,8 +58,7 @@ times: circumstances. - `core/proto` is a read-only upstream submodule (`meshtastic/protobufs`). MUST NOT modify `.proto` files directly; proto changes require an upstream issue labeled `upstream`. -- Rationale: Meshtastic users rely on the mesh for private, off-grid communications. Data - leaks could endanger users in sensitive or adversarial deployments. + ### V. Design Standards Compliance @@ -74,8 +66,8 @@ All user-facing UI MUST conform to the Meshtastic Client Design Standards: - The canonical reference lives at: `https://raw.githubusercontent.com/meshtastic/design/refs/heads/master/standards/meshtastic_design_standards_latest.md` -- New screens and significant UI changes MUST be reviewed against the design standards - before merge. +- New screens and significant UI changes (any screen with ≥3 composables or a new + navigation destination) MUST be reviewed against the design standards before merge. - Deviations from the design standards require explicit justification in the PR description with a rationale for why the standard cannot or should not be followed. - Features that affect multiple platforms (messaging, settings, telemetry, etc.) MUST @@ -84,9 +76,7 @@ All user-facing UI MUST conform to the Meshtastic Client Design Standards: or create one using the `TEMPLATE.md` in that directory before writing the Android implementation spec. Platform-specific-only features (e.g., Android widget, Wear OS tile) may mark the `Cross-Platform Spec` field as N/A with justification. -- Rationale: Consistent cross-platform UX across Android, iOS, and other clients ensures - users have a predictable experience regardless of platform. The design standards are - maintained collaboratively across all Meshtastic client teams. + ### VI. Documentation Freshness @@ -118,9 +108,7 @@ Governance rules: - Image references MUST use root-relative paths (`/assets/screenshots/filename.png`) so they resolve correctly in both Jekyll and the in-app renderer. The sync script rewrites these to Docusaurus paths automatically. -- Rationale: Documentation that drifts from the implementation misleads users, increases - support burden, and undermines the in-app help experience. Three distinct consumers - means a single source change must be verified across all delivery channels. + ### VII. Verify Before Push @@ -131,26 +119,15 @@ Local verification MUST complete successfully before any `git push`: - After pushing, CI status MUST be confirmed via `gh pr checks ` or `gh run list --branch --limit 5`. Phrases like "CI should be green" are explicitly prohibited. -- Rationale: CI has failed repeatedly due to skipped local checks. Verification is a hard - gate, not an optimistic assumption. + ## Development Workflow -The following workflow steps are non-negotiable for all contributors and agents: - -- **Bootstrap First**: The mandatory bootstrap steps in `.skills/project-overview/SKILL.md` - MUST be executed before any build operation in a new session. -- **Baseline Verification**: Before any PR is opened or pushed, run: - `./gradlew spotlessApply spotlessCheck detekt assembleDebug test allTests` -- **String Resources**: After adding any string resource, run - `python3 scripts/sort-strings.py` to maintain alphabetical organization and regenerate - `strings-index.txt`. Consult `strings-index.txt` before reading large string files. -- **Memory Persistence**: `.agent_memory/session_context.md` MUST be updated at the end of - every agent session or major task to preserve context across sessions. -- **Plan Before Execution**: Complex refactors MUST have a plan written in `.agent_plans/` - (git-ignored) before execution begins. -- **Context Discipline**: Agents MUST NOT read binary files (PNG, MP3, etc.) or vacuum the - entire codebase for localized fixes. Limit context reads to relevant modules. +Non-negotiable workflow steps are defined in `AGENTS.md` ``. Key +requirements: bootstrap before build, baseline verification before push, sort-strings after +adding resources, update `.agent_memory/session_context.md` per session, plan complex +refactors (touching ≥3 modules or >200 LOC changed) in `.agent_plans/`, limit context +reads to relevant modules. ## Architecture Constraints @@ -170,12 +147,27 @@ The following module boundaries and technology choices are fixed for this projec - **Language & Toolchain**: Kotlin 2.3+ targeting JDK 21. Java source files MUST NOT be introduced in KMP modules. +## Operational Standards + +The following coding standards are enforced by contextual instruction files +(`.github/instructions/`) scoped to relevant source sets. They are acknowledged by this +constitution but defined and maintained in their respective files: + +- `safeCatching {}` over `runCatching {}` in coroutine/suspend contexts +- `org.meshtastic.core.common.util.ioDispatcher` over `Dispatchers.IO` +- `MeshtasticIcons` (from `core/ui/icon/`) over `material.icons.Icons` +- `MetricFormatter` for display strings (temperature, voltage, percent, signal) +- `stringResource(Res.string.key)` with `python3 scripts/sort-strings.py` after additions +- `kotlinx.coroutines.CancellationException` (not `kotlin.coroutines.cancellation.*`) +- Branch naming: `feat/`, `fix/`, `chore/`, `docs/`, `build/`, `ci/`, `refactor/`, + `test/`, `deps/`, or numeric spec prefix; always off `origin/main` + ## Governance -This constitution supersedes all other practices, coding guidelines, and agent instructions. -`AGENTS.md` is the authoritative source of truth. The files -`.github/copilot-instructions.md`, `CLAUDE.md`, and `GEMINI.md` MUST redirect to -`AGENTS.md` and MUST NOT diverge from it. +This constitution is the canonical governance document and supersedes all other practices, +coding guidelines, and agent instructions. `AGENTS.md` is the agent-facing operational +summary derived from this constitution. The files `.github/copilot-instructions.md`, +`CLAUDE.md`, and `GEMINI.md` MUST redirect to `AGENTS.md` and MUST NOT diverge from it. **Amendment Procedure**: 1. Propose the amendment with rationale and a migration plan in a PR description. @@ -197,4 +189,4 @@ This constitution supersedes all other practices, coding guidelines, and agent i Constitution Check confirming all seven principles were evaluated. Complexity violations require explicit justification in the Complexity Tracking table of the plan document. -**Version**: 1.3.0 | **Ratified**: 2026-05-07 | **Last Amended**: 2026-05-13 +**Version**: 1.3.2 | **Ratified**: 2026-05-07 | **Last Amended**: 2026-05-21 diff --git a/.specify/presets/.cache/catalog-ff86b51b80a289e5-metadata.json b/.specify/presets/.cache/catalog-ff86b51b80a289e5-metadata.json new file mode 100644 index 000000000..ccb652a97 --- /dev/null +++ b/.specify/presets/.cache/catalog-ff86b51b80a289e5-metadata.json @@ -0,0 +1,4 @@ +{ + "cached_at": "2026-05-21T18:52:11.605092+00:00", + "catalog_url": "https://raw.githubusercontent.com/github/spec-kit/main/presets/catalog.community.json" +} \ No newline at end of file diff --git a/.specify/presets/.cache/catalog-ff86b51b80a289e5.json b/.specify/presets/.cache/catalog-ff86b51b80a289e5.json new file mode 100644 index 000000000..1e044bf1f --- /dev/null +++ b/.specify/presets/.cache/catalog-ff86b51b80a289e5.json @@ -0,0 +1,577 @@ +{ + "schema_version": "1.0", + "updated_at": "2026-05-05T10:00:00Z", + "catalog_url": "https://raw.githubusercontent.com/github/spec-kit/main/presets/catalog.community.json", + "presets": { + "a11y-governance": { + "name": "A11Y Governance", + "id": "a11y-governance", + "version": "0.2.0", + "description": "Adds accessibility, bilingual DE/EN delivery, CEFR-B2 readability, and inclusive-content governance to Spec Kit.", + "author": "Thorsten Hindermann", + "repository": "https://github.com/hindermath/spec-kit-preset-a11y-governance", + "download_url": "https://github.com/hindermath/spec-kit-preset-a11y-governance/archive/refs/tags/v0.2.0.zip", + "homepage": "https://github.com/hindermath/spec-kit-preset-a11y-governance", + "documentation": "https://github.com/hindermath/spec-kit-preset-a11y-governance/blob/main/README.md", + "license": "MIT", + "requires": { + "speckit_version": ">=0.8.0" + }, + "provides": { + "templates": 9, + "commands": 3 + }, + "tags": [ + "a11y", + "accessibility", + "bilingual", + "wcag", + "inclusion" + ], + "created_at": "2026-04-27T00:00:00Z", + "updated_at": "2026-04-27T00:00:00Z" + }, + "agent-parity-governance": { + "name": "Agent Parity Governance", + "id": "agent-parity-governance", + "version": "0.1.0", + "description": "Keeps shared AI-agent guidance aligned across a project-defined set of agent instruction surfaces.", + "author": "Thorsten Hindermann", + "repository": "https://github.com/hindermath/spec-kit-preset-agent-parity-governance", + "download_url": "https://github.com/hindermath/spec-kit-preset-agent-parity-governance/archive/refs/tags/v0.1.0.zip", + "homepage": "https://github.com/hindermath/spec-kit-preset-agent-parity-governance", + "documentation": "https://github.com/hindermath/spec-kit-preset-agent-parity-governance/blob/main/README.md", + "license": "MIT", + "requires": { + "speckit_version": ">=0.8.0" + }, + "provides": { + "templates": 6, + "commands": 3 + }, + "tags": [ + "agents", + "governance", + "parity", + "agent-guidance", + "multi-agent" + ], + "created_at": "2026-04-27T00:00:00Z", + "updated_at": "2026-04-27T00:00:00Z" + }, + "aide-in-place": { + "name": "AIDE In-Place Migration", + "id": "aide-in-place", + "version": "1.0.0", + "description": "Adapts the AIDE workflow for in-place technology migrations (X \u2192 Y pattern). Overrides vision, roadmap, progress, and work item commands with migration-specific guidance.", + "author": "mnriem", + "repository": "https://github.com/mnriem/spec-kit-presets", + "download_url": "https://github.com/mnriem/spec-kit-presets/releases/download/aide-in-place-v1.0.0/aide-in-place.zip", + "homepage": "https://github.com/mnriem/spec-kit-presets", + "documentation": "https://github.com/mnriem/spec-kit-presets/blob/main/aide-in-place/README.md", + "license": "MIT", + "requires": { + "speckit_version": ">=0.2.0", + "extensions": [ + "aide" + ] + }, + "provides": { + "templates": 2, + "commands": 8 + }, + "tags": [ + "migration", + "in-place", + "brownfield", + "aide" + ] + }, + "architecture-governance": { + "name": "Architecture Governance", + "id": "architecture-governance", + "version": "0.2.0", + "description": "Adds secure architecture governance, threat modeling, STRIDE/CAPEC, Zero Trust, S-ADRs, and OWASP SAMM to Spec Kit.", + "author": "Thorsten Hindermann", + "repository": "https://github.com/hindermath/spec-kit-preset-architecture-governance", + "download_url": "https://github.com/hindermath/spec-kit-preset-architecture-governance/archive/refs/tags/v0.2.0.zip", + "homepage": "https://github.com/hindermath/spec-kit-preset-architecture-governance", + "documentation": "https://github.com/hindermath/spec-kit-preset-architecture-governance/blob/main/README.md", + "license": "MIT", + "requires": { + "speckit_version": ">=0.8.0" + }, + "provides": { + "templates": 11, + "commands": 3 + }, + "tags": [ + "architecture", + "governance", + "threat-modeling", + "stride", + "zero-trust" + ], + "created_at": "2026-04-27T00:00:00Z", + "updated_at": "2026-04-27T00:00:00Z" + }, + "canon-core": { + "name": "Canon Core", + "id": "canon-core", + "version": "0.1.0", + "description": "Adapts original Spec Kit workflow to work together with Canon extension.", + "author": "Maxim Stupakov", + "download_url": "https://github.com/maximiliamus/spec-kit-canon/releases/download/v0.1.0/spec-kit-canon-core-v0.1.0.zip", + "repository": "https://github.com/maximiliamus/spec-kit-canon", + "homepage": "https://github.com/maximiliamus/spec-kit-canon", + "documentation": "https://github.com/maximiliamus/spec-kit-canon/blob/master/README.md", + "license": "MIT", + "requires": { + "speckit_version": ">=0.4.3" + }, + "provides": { + "templates": 2, + "commands": 8 + }, + "tags": [ + "baseline", + "canon", + "spec-first" + ] + }, + "claude-ask-questions": { + "name": "Claude AskUserQuestion", + "id": "claude-ask-questions", + "version": "1.0.0", + "description": "Upgrades /speckit.clarify and /speckit.checklist on Claude Code from Markdown-table prompts to the native AskUserQuestion picker, with a recommended option and reasoning on every question.", + "author": "0xrafasec", + "repository": "https://github.com/0xrafasec/spec-kit-preset-claude-ask-questions", + "download_url": "https://github.com/0xrafasec/spec-kit-preset-claude-ask-questions/archive/refs/tags/v1.0.0.zip", + "homepage": "https://github.com/0xrafasec/spec-kit-preset-claude-ask-questions", + "documentation": "https://github.com/0xrafasec/spec-kit-preset-claude-ask-questions/blob/main/README.md", + "license": "MIT", + "requires": { + "speckit_version": ">=0.6.0" + }, + "provides": { + "templates": 0, + "commands": 2 + }, + "tags": [ + "claude", + "ask-user-question", + "clarify", + "checklist" + ], + "created_at": "2026-04-13T00:00:00Z", + "updated_at": "2026-04-13T00:00:00Z" + }, + "cross-platform-governance": { + "name": "Cross-Platform Governance", + "id": "cross-platform-governance", + "version": "0.1.0", + "description": "Adds Bash and PowerShell parity, dry-run/WhatIf parity, man-page expectations, and Verb-Noun Cmdlet discipline.", + "author": "Thorsten Hindermann", + "repository": "https://github.com/hindermath/spec-kit-preset-cross-platform-governance", + "download_url": "https://github.com/hindermath/spec-kit-preset-cross-platform-governance/archive/refs/tags/v0.1.0.zip", + "homepage": "https://github.com/hindermath/spec-kit-preset-cross-platform-governance", + "documentation": "https://github.com/hindermath/spec-kit-preset-cross-platform-governance/blob/main/README.md", + "license": "MIT", + "requires": { + "speckit_version": ">=0.8.0" + }, + "provides": { + "templates": 8, + "commands": 3 + }, + "tags": [ + "cross-platform", + "bash", + "powershell", + "man-page", + "cmdlet" + ], + "created_at": "2026-04-27T00:00:00Z", + "updated_at": "2026-04-27T00:00:00Z" + }, + "explicit-task-dependencies": { + "name": "Explicit Task Dependencies", + "id": "explicit-task-dependencies", + "version": "1.0.0", + "description": "Adds explicit (depends on T###) dependency declarations and an Execution Wave DAG to tasks.md for dependency-resolved parallel scheduling", + "author": "Quratulain-bilal", + "repository": "https://github.com/Quratulain-bilal/spec-kit-preset-explicit-task-dependencies", + "download_url": "https://github.com/Quratulain-bilal/spec-kit-preset-explicit-task-dependencies/archive/refs/tags/v1.0.0.zip", + "homepage": "https://github.com/Quratulain-bilal/spec-kit-preset-explicit-task-dependencies", + "documentation": "https://github.com/Quratulain-bilal/spec-kit-preset-explicit-task-dependencies/blob/main/README.md", + "license": "MIT", + "requires": { + "speckit_version": ">=0.4.0" + }, + "provides": { + "templates": 1, + "commands": 1 + }, + "tags": [ + "dependencies", + "parallel", + "scheduling", + "wave-dag" + ] + }, + "fiction-book-writing": { + "name": "Fiction Book Writing", + "id": "fiction-book-writing", + "version": "1.7.0", + "description": "Spec-Driven Development for novel and long-form fiction. 27 AI commands from idea to submission: story bible governance, 9 POV modes, all major plot structure frameworks, scene-by-scene drafting with quality gates, audiobook pipeline (SSML/ElevenLabs), cover design, sensitivity review, pacing and prose statistics, and pandoc-based export to DOCX/EPUB/LaTeX. Two style modes: author voice sample extraction or humanized-AI prose with 5 craft profiles. 12 languages supported. Support for offline semantic search.", + "author": "Andreas Daumann", + "repository": "https://github.com/adaumann/speckit-preset-fiction-book-writing", + "download_url": "https://github.com/adaumann/speckit-preset-fiction-book-writing/archive/refs/tags/v1.7.0.zip", + "homepage": "https://github.com/adaumann/speckit-preset-fiction-book-writing", + "documentation": "https://github.com/adaumann/speckit-preset-fiction-book-writing/blob/main/fiction-book-writing/README.md", + "license": "MIT", + "requires": { + "speckit_version": ">=0.5.0" + }, + "provides": { + "templates": 22, + "commands": 27, + "scripts": 2 + }, + "tags": [ + "writing", + "novel", + "fiction", + "storytelling", + "creative-writing", + "kdp", + "multi-pov", + "export", + "book", + "brainstorming", + "roleplay", + "audiobook", + "language-support" + ], + "created_at": "2026-04-09T08:00:00Z", + "updated_at": "2026-04-27T08:00:00Z" + }, + "game-narrative-writing": { + "name": "Game Narrative Writing", + "id": "game-narrative-writing", + "version": "1.0.0", + "description": "Spec-Driven Development for interactive game-narrative pre-production in video games. Authors write in a portable generic format, Twine/Sugarcube (.twee) or Ink (.ink). Covers choice-IF, visual novels, and branching dialogue. Supports Tier 1 mechanic hooks (flag, counter, inventory, timer, trust, currency, npc_state, ending_condition), multi-ending design, series carry-over variable registry, and NPC-focused character architecture.", + "author": "Andreas Daumann", + "repository": "https://github.com/adaumann/speckit-preset-game-narrative-writing", + "download_url": "https://github.com/adaumann/speckit-preset-game-narrative-writing/archive/refs/tags/v1.0.0.zip", + "homepage": "https://github.com/adaumann/speckit-preset-game-narrative-writing", + "documentation": "https://github.com/adaumann/speckit-preset-game-narrative-writing/blob/main/game-narrative-writing/README.md", + "license": "MIT", + "requires": { + "speckit_version": ">=0.5.0" + }, + "provides": { + "templates": 22, + "commands": 36, + "scripts": 2 + }, + "tags": [ + "game-writing", + "interactive-fiction", + "twine", + "ink", + "renpy", + "point-and-click", + "branching-narrative", + "choice-if", + "visual-novel", + "mechanic-hooks", + "game-narrative", + "export", + "series" + ], + "created_at": "2026-05-05T08:00:00Z", + "updated_at": "2026-05-05T08:00:00Z" + }, + "isaqb-architecture-governance": { + "name": "iSAQB Architecture Governance", + "id": "isaqb-architecture-governance", + "version": "0.1.0", + "description": "Adds general iSAQB/CPSA-F and arc42 architecture governance, including views, quality scenarios, ADRs, risks, and technical debt.", + "author": "Thorsten Hindermann", + "repository": "https://github.com/hindermath/spec-kit-preset-isaqb-architecture-governance", + "download_url": "https://github.com/hindermath/spec-kit-preset-isaqb-architecture-governance/archive/refs/tags/v0.1.0.zip", + "homepage": "https://github.com/hindermath/spec-kit-preset-isaqb-architecture-governance", + "documentation": "https://github.com/hindermath/spec-kit-preset-isaqb-architecture-governance/blob/main/README.md", + "license": "MIT", + "requires": { + "speckit_version": ">=0.8.0" + }, + "provides": { + "templates": 13, + "commands": 3 + }, + "tags": [ + "architecture", + "governance", + "isaqb", + "arc42", + "adr" + ], + "created_at": "2026-04-27T00:00:00Z", + "updated_at": "2026-04-27T00:00:00Z" + }, + "jira": { + "name": "Jira Issue Tracking", + "id": "jira", + "version": "1.0.0", + "description": "Overrides speckit.taskstoissues to create Jira epics, stories, and tasks instead of GitHub Issues via Atlassian MCP tools.", + "author": "luno", + "repository": "https://github.com/luno/spec-kit-preset-jira", + "download_url": "https://github.com/luno/spec-kit-preset-jira/archive/refs/tags/v1.0.0.zip", + "homepage": "https://github.com/luno/spec-kit-preset-jira", + "documentation": "https://github.com/luno/spec-kit-preset-jira/blob/main/README.md", + "license": "MIT", + "requires": { + "speckit_version": ">=0.1.0" + }, + "provides": { + "templates": 0, + "commands": 1 + }, + "tags": [ + "jira", + "atlassian", + "issue-tracking", + "preset" + ], + "created_at": "2026-04-15T00:00:00Z", + "updated_at": "2026-04-15T00:00:00Z" + }, + "mde": { + "name": "Model Driven Engineering", + "id": "mde", + "version": "0.5.1", + "description": "Focuses on streamlined commands, app repository support, cross-spec support, and capability-aware project memory for model-driven engineering workflows.", + "author": "Ralph Hanna", + "repository": "https://github.com/AI-MDE/spec-kit-preset-mde", + "download_url": "https://github.com/AI-MDE/spec-kit-preset-mde/archive/refs/tags/v0.5.1.zip", + "homepage": "https://github.com/AI-MDE/spec-kit-preset-mde", + "documentation": "https://github.com/AI-MDE/spec-kit-preset-mde/blob/main/README.md", + "license": "MIT", + "requires": { + "speckit_version": ">=0.1.0", + "extensions": [ + "mde" + ] + }, + "provides": { + "templates": 6, + "commands": 11 + }, + "tags": [ + "model-driven-engineering", + "software-lifecycle", + "business-analysis", + "business-application", + "multi-layered-architecture" + ], + "created_at": "2026-05-08T00:00:00Z", + "updated_at": "2026-05-08T00:00:00Z" + }, + "multi-repo-branching": { + "name": "Multi-Repo Branching", + "id": "multi-repo-branching", + "version": "1.0.0", + "description": "Coordinates feature branch creation across multiple git repositories (independent repos and submodules) during plan and tasks phases.", + "author": "sakitA", + "repository": "https://github.com/sakitA/spec-kit-preset-multi-repo-branching", + "download_url": "https://github.com/sakitA/spec-kit-preset-multi-repo-branching/archive/refs/tags/v1.0.0.zip", + "homepage": "https://github.com/sakitA/spec-kit-preset-multi-repo-branching", + "documentation": "https://github.com/sakitA/spec-kit-preset-multi-repo-branching/blob/master/README.md", + "license": "MIT", + "requires": { + "speckit_version": ">=0.4.0" + }, + "provides": { + "templates": 0, + "commands": 2 + }, + "tags": [ + "multi-repo-branching", + "multi-module", + "submodules", + "monorepo" + ], + "created_at": "2026-04-09T00:00:00Z", + "updated_at": "2026-04-09T00:00:00Z" + }, + "pirate": { + "name": "Pirate Speak (Full)", + "id": "pirate", + "version": "1.0.0", + "description": "Arrr! Transforms all Spec Kit output into pirate speak. Specs, plans, and tasks be written fer scallywags.", + "author": "mnriem", + "repository": "https://github.com/mnriem/spec-kit-presets", + "download_url": "https://github.com/mnriem/spec-kit-presets/releases/download/pirate-v1.0.0/pirate.zip", + "homepage": "https://github.com/mnriem/spec-kit-presets", + "documentation": "https://github.com/mnriem/spec-kit-presets/blob/main/pirate/README.md", + "license": "MIT", + "requires": { + "speckit_version": ">=0.1.0" + }, + "provides": { + "templates": 6, + "commands": 9 + }, + "tags": [ + "pirate", + "theme", + "fun", + "experimental" + ] + }, + "screenwriting": { + "name": "Screenwriting", + "id": "screenwriting", + "version": "1.0.0", + "description": "Spec-Driven Development for screenwriting/scriptwriting/tutorials: feature films, television (pilot, episode, limited series), and stage plays. Adapts the Spec Kit workflow to screenplay craft \u2014 slug lines, action lines, act breaks, beat sheets, and industry-standard pitch documents replace prose fiction conventions. Supports three-act, Save the Cat, TV pilot, network episode, cable/streaming episode, and stage-play structural frameworks.", + "author": "Andreas Daumann", + "repository": "https://github.com/adaumann/speckit-preset-screenwriting", + "download_url": "https://github.com/adaumann/speckit-preset-screenwriting/archive/refs/tags/v1.0.0.zip", + "homepage": "https://github.com/adaumann/speckit-preset-screenwriting", + "documentation": "https://github.com/adaumann/speckit-preset-screenwriting/blob/main/screenwriting/README.md", + "license": "MIT", + "requires": { + "speckit_version": ">=0.5.0" + }, + "provides": { + "templates": 26, + "commands": 32, + "scripts": 1 + }, + "tags": [ + "writing", + "screenplay", + "scriptwriting", + "film", + "tv", + "fountain", + "fountain-format", + "beat-sheet", + "teleplay", + "drama", + "comedy", + "storytelling", + "tutorial", + "education" + ], + "created_at": "2026-04-23T08:00:00Z", + "updated_at": "2026-04-23T08:00:00Z" + }, + "security-governance": { + "name": "Security Governance", + "id": "security-governance", + "version": "0.2.0", + "description": "Adds secure development governance, MSL preference, ASVS verification, supply-chain transparency, and EU CRA awareness.", + "author": "Thorsten Hindermann", + "repository": "https://github.com/hindermath/spec-kit-preset-security-governance", + "download_url": "https://github.com/hindermath/spec-kit-preset-security-governance/archive/refs/tags/v0.2.0.zip", + "homepage": "https://github.com/hindermath/spec-kit-preset-security-governance", + "documentation": "https://github.com/hindermath/spec-kit-preset-security-governance/blob/main/README.md", + "license": "MIT", + "requires": { + "speckit_version": ">=0.8.0" + }, + "provides": { + "templates": 12, + "commands": 3 + }, + "tags": [ + "security", + "governance", + "msl", + "asvs", + "supply-chain" + ], + "created_at": "2026-04-27T00:00:00Z", + "updated_at": "2026-04-27T00:00:00Z" + }, + "spec2cloud": { + "name": "Spec2Cloud", + "id": "spec2cloud", + "version": "1.1.0", + "description": "Spec-driven workflow tuned for shipping to Azure: spec \u2192 plan \u2192 tasks \u2192 implement \u2192 deploy.", + "author": "Azure Samples", + "repository": "https://github.com/Azure-Samples/Spec2Cloud", + "download_url": "https://github.com/Azure-Samples/Spec2Cloud/releases/download/spec-kit-spec2cloud-v1.1.0/preset.zip", + "homepage": "https://aka.ms/spec2cloud", + "documentation": "https://github.com/Azure-Samples/Spec2Cloud/blob/main/spec-kit/README.md", + "license": "MIT", + "requires": { + "speckit_version": ">=0.1.0" + }, + "provides": { + "templates": 5, + "commands": 8 + }, + "tags": [ + "azure", + "spec2cloud", + "workflow", + "deployment" + ], + "created_at": "2026-04-30T00:00:00Z", + "updated_at": "2026-04-30T00:00:00Z" + }, + "toc-navigation": { + "name": "Table of Contents Navigation", + "id": "toc-navigation", + "version": "1.0.0", + "description": "Adds a navigable Table of Contents to generated spec.md, plan.md, and tasks.md documents", + "author": "Quratulain-bilal", + "repository": "https://github.com/Quratulain-bilal/spec-kit-preset-toc-navigation", + "download_url": "https://github.com/Quratulain-bilal/spec-kit-preset-toc-navigation/archive/refs/tags/v1.0.0.zip", + "homepage": "https://github.com/Quratulain-bilal/spec-kit-preset-toc-navigation", + "documentation": "https://github.com/Quratulain-bilal/spec-kit-preset-toc-navigation/blob/main/README.md", + "license": "MIT", + "requires": { + "speckit_version": ">=0.4.0" + }, + "provides": { + "templates": 3, + "commands": 3 + }, + "tags": [ + "navigation", + "toc", + "documentation" + ] + }, + "vscode-ask-questions": { + "name": "VS Code Ask Questions", + "id": "vscode-ask-questions", + "version": "1.0.0", + "description": "Enhances the clarify command to use vscode/askQuestions for batched interactive questioning, reducing API request costs in GitHub Copilot.", + "author": "fdcastel", + "repository": "https://github.com/fdcastel/spec-kit-presets", + "download_url": "https://github.com/fdcastel/spec-kit-presets/releases/download/vscode-ask-questions-v1.0.0/vscode-ask-questions.zip", + "homepage": "https://github.com/fdcastel/spec-kit-presets", + "documentation": "https://github.com/fdcastel/spec-kit-presets/blob/main/vscode-ask-questions/README.md", + "license": "MIT", + "requires": { + "speckit_version": ">=0.1.0" + }, + "provides": { + "templates": 0, + "commands": 1 + }, + "tags": [ + "vscode", + "askquestions", + "clarify", + "interactive" + ] + } + } +} \ No newline at end of file diff --git a/.specify/presets/.cache/catalog-metadata.json b/.specify/presets/.cache/catalog-metadata.json new file mode 100644 index 000000000..06aa5b91f --- /dev/null +++ b/.specify/presets/.cache/catalog-metadata.json @@ -0,0 +1,4 @@ +{ + "cached_at": "2026-05-21T18:52:11.763650+00:00", + "catalog_url": "https://raw.githubusercontent.com/github/spec-kit/main/presets/catalog.json" +} \ No newline at end of file diff --git a/.specify/presets/.cache/catalog.json b/.specify/presets/.cache/catalog.json new file mode 100644 index 000000000..b890ea2b4 --- /dev/null +++ b/.specify/presets/.cache/catalog.json @@ -0,0 +1,30 @@ +{ + "schema_version": "1.0", + "updated_at": "2026-04-24T00:00:00Z", + "catalog_url": "https://raw.githubusercontent.com/github/spec-kit/main/presets/catalog.json", + "presets": { + "lean": { + "name": "Lean Workflow", + "id": "lean", + "version": "1.0.0", + "description": "Minimal core workflow commands - just the prompt, just the artifact", + "author": "github", + "repository": "https://github.com/github/spec-kit", + "license": "MIT", + "bundled": true, + "requires": { + "speckit_version": ">=0.6.0" + }, + "provides": { + "commands": 5, + "templates": 0 + }, + "tags": [ + "lean", + "minimal", + "workflow", + "core" + ] + } + } +} \ No newline at end of file diff --git a/.specify/templates/plan-template.md b/.specify/templates/plan-template.md index f9d7d1560..95faa7316 100644 --- a/.specify/templates/plan-template.md +++ b/.specify/templates/plan-template.md @@ -1,6 +1,7 @@ # Implementation Plan: [FEATURE] **Branch**: `[###-feature-name]` | **Date**: [DATE] | **Spec**: [link] + **Input**: Feature specification from `/specs/[###-feature-name]/spec.md` **Note**: This template is filled in by the `/speckit.plan` command. See `.specify/templates/plan-template.md` for the execution workflow. @@ -17,14 +18,22 @@ the iteration process. --> -**Language/Version**: [e.g., Python 3.11, Swift 5.9, Rust 1.75 or NEEDS CLARIFICATION] -**Primary Dependencies**: [e.g., FastAPI, UIKit, LLVM or NEEDS CLARIFICATION] -**Storage**: [if applicable, e.g., PostgreSQL, CoreData, files or N/A] -**Testing**: [e.g., pytest, XCTest, cargo test or NEEDS CLARIFICATION] +**Language/Version**: [e.g., Python 3.11, Swift 5.9, Rust 1.75 or NEEDS CLARIFICATION] + +**Primary Dependencies**: [e.g., FastAPI, UIKit, LLVM or NEEDS CLARIFICATION] + +**Storage**: [if applicable, e.g., PostgreSQL, CoreData, files or N/A] + +**Testing**: [e.g., pytest, XCTest, cargo test or NEEDS CLARIFICATION] + **Target Platform**: [e.g., Linux server, iOS 15+, WASM or NEEDS CLARIFICATION] -**Project Type**: [e.g., library/cli/web-service/mobile-app/compiler/desktop-app or NEEDS CLARIFICATION] -**Performance Goals**: [domain-specific, e.g., 1000 req/s, 10k lines/sec, 60 fps or NEEDS CLARIFICATION] -**Constraints**: [domain-specific, e.g., <200ms p95, <100MB memory, offline-capable or NEEDS CLARIFICATION] + +**Project Type**: [e.g., library/cli/web-service/mobile-app/compiler/desktop-app or NEEDS CLARIFICATION] + +**Performance Goals**: [domain-specific, e.g., 1000 req/s, 10k lines/sec, 60 fps or NEEDS CLARIFICATION] + +**Constraints**: [domain-specific, e.g., <200ms p95, <100MB memory, offline-capable or NEEDS CLARIFICATION] + **Scale/Scope**: [domain-specific, e.g., 10k users, 1M LOC, 50 screens or NEEDS CLARIFICATION] ## Constitution Check diff --git a/.specify/templates/spec-template.md b/.specify/templates/spec-template.md index 16d5814f1..849e38aff 100644 --- a/.specify/templates/spec-template.md +++ b/.specify/templates/spec-template.md @@ -1,9 +1,9 @@ # Feature Specification: [FEATURE NAME] -**Feature Branch**: `[###-feature-name]` -**Created**: [DATE] -**Status**: Draft -**Input**: User description: "$ARGUMENTS" +**Feature Branch**: `[###-feature-name]` +**Created**: [DATE] +**Status**: Draft +**Input**: User description: "$ARGUMENTS" **Cross-Platform Spec**: ## Summary @@ -11,7 +11,7 @@ + +### Functional Requirements + +- **FR-001**: System MUST [specific capability] +- **FR-002**: System MUST [specific capability] + +### Non-Functional Requirements + +- **NFR-001**: [Performance, accessibility, or quality requirement] + ## Architecture - -### Functional Requirements - -- **FR-001**: System MUST [specific capability] -- **FR-002**: System MUST [specific capability] - -### Non-Functional Requirements - -- **NFR-001**: [Performance, accessibility, or quality requirement] - ## Source-Set Impact | Source Set | Impact | Justification | @@ -154,7 +154,7 @@ @@ -166,7 +166,7 @@ ## Privacy Assessment diff --git a/.specify/templates/tasks-template.md b/.specify/templates/tasks-template.md index 927cb4e5a..5bc9eb6f0 100644 --- a/.specify/templates/tasks-template.md +++ b/.specify/templates/tasks-template.md @@ -6,6 +6,7 @@ description: "Task list template for feature implementation" # Tasks: [FEATURE NAME] **Input**: Design documents from `/specs/[###-feature-name]/` + **Prerequisites**: plan.md (required), spec.md (required for user stories), research.md, data-model.md, contracts/ **Tests**: The examples below include test tasks. New automated tests are OPTIONAL and @@ -31,21 +32,21 @@ touched modules before work is considered complete. - **Mobile**: `api/src/`, `ios/src/` or `android/src/` - Paths shown below assume single project - adjust based on plan.md structure - diff --git a/.specify/workflows/.cache/workflow-catalog-4beae448930d024d-meta.json b/.specify/workflows/.cache/workflow-catalog-4beae448930d024d-meta.json new file mode 100644 index 000000000..9b6a16b8a --- /dev/null +++ b/.specify/workflows/.cache/workflow-catalog-4beae448930d024d-meta.json @@ -0,0 +1 @@ +{"url": "https://raw.githubusercontent.com/github/spec-kit/main/workflows/catalog.community.json", "fetched_at": 1779389640.9802408} \ No newline at end of file diff --git a/.specify/workflows/.cache/workflow-catalog-4beae448930d024d.json b/.specify/workflows/.cache/workflow-catalog-4beae448930d024d.json new file mode 100644 index 000000000..56738d475 --- /dev/null +++ b/.specify/workflows/.cache/workflow-catalog-4beae448930d024d.json @@ -0,0 +1,6 @@ +{ + "schema_version": "1.0", + "updated_at": "2026-04-10T00:00:00Z", + "catalog_url": "https://raw.githubusercontent.com/github/spec-kit/main/workflows/catalog.community.json", + "workflows": {} +} \ No newline at end of file diff --git a/.specify/workflows/.cache/workflow-catalog-d232380ded3e35d7-meta.json b/.specify/workflows/.cache/workflow-catalog-d232380ded3e35d7-meta.json new file mode 100644 index 000000000..8dd7d8a85 --- /dev/null +++ b/.specify/workflows/.cache/workflow-catalog-d232380ded3e35d7-meta.json @@ -0,0 +1 @@ +{"url": "https://raw.githubusercontent.com/github/spec-kit/main/workflows/catalog.json", "fetched_at": 1779389641.039055} \ No newline at end of file diff --git a/.specify/workflows/.cache/workflow-catalog-d232380ded3e35d7.json b/.specify/workflows/.cache/workflow-catalog-d232380ded3e35d7.json new file mode 100644 index 000000000..e37d6ad51 --- /dev/null +++ b/.specify/workflows/.cache/workflow-catalog-d232380ded3e35d7.json @@ -0,0 +1,19 @@ +{ + "schema_version": "1.0", + "updated_at": "2026-04-13T00:00:00Z", + "catalog_url": "https://raw.githubusercontent.com/github/spec-kit/main/workflows/catalog.json", + "workflows": { + "speckit": { + "id": "speckit", + "name": "Full SDD Cycle", + "description": "Runs specify \u2192 plan \u2192 tasks \u2192 implement with review gates", + "author": "GitHub", + "version": "1.0.0", + "url": "https://raw.githubusercontent.com/github/spec-kit/main/workflows/speckit/workflow.yml", + "tags": [ + "sdd", + "full-cycle" + ] + } + } +} \ No newline at end of file diff --git a/AGENTS.md b/AGENTS.md index 1d20691fa..48c7c75d9 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -49,5 +49,4 @@ You are an expert Android/KMP engineer. Maintain architectural boundaries, use M For additional context about technologies to be used, project structure, shell commands, and other important information, read the current plan -at `specs/20260520-153504-udp-label-rename/plan.md`