mirror of
https://github.com/meshtastic/Meshtastic-Android.git
synced 2026-05-24 06:40:37 -04:00
ai: Add spec kit agent governance extension and related files (#5568)
This commit is contained in:
48
.github/agents/speckit.agent-governance.refresh.agent.md
vendored
Normal file
48
.github/agents/speckit.agent-governance.refresh.agent.md
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
---
|
||||
description: Generate or update the active agent governance file
|
||||
---
|
||||
|
||||
|
||||
<!-- Extension: agent-governance -->
|
||||
<!-- Config: .specify/extensions/agent-governance/ -->
|
||||
# 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
|
||||
6
.github/agents/speckit.git.validate.agent.md
vendored
6
.github/agents/speckit.git.validate.agent.md
vendored
@@ -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: <branch-name>`
|
||||
- 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/<prefix>-*` where prefix matches the numeric portion
|
||||
- For timestamp branches, look for `specs/<prefix>-*` 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: <path>`
|
||||
- If spec directory missing: `⚠ No spec directory found for prefix <prefix>`
|
||||
|
||||
If NOT on a feature branch:
|
||||
- Output: `✗ Not on a feature branch. Current branch: <branch-name>`
|
||||
- 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
|
||||
|
||||
|
||||
33
.github/copilot-instructions.md
vendored
33
.github/copilot-instructions.md
vendored
@@ -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 <PR>`.
|
||||
- **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.
|
||||
|
||||
<!-- SPECKIT START -->
|
||||
## 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
|
||||
<!-- SPECKIT END -->
|
||||
|
||||
## 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
|
||||
|
||||
3
.github/prompts/speckit.agent-governance.refresh.prompt.md
vendored
Normal file
3
.github/prompts/speckit.agent-governance.refresh.prompt.md
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
---
|
||||
agent: speckit.agent-governance.refresh
|
||||
---
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
7
.specify/extensions/agent-governance/.gitignore
vendored
Normal file
7
.specify/extensions/agent-governance/.gitignore
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
__pycache__/
|
||||
*.pyc
|
||||
.pytest_cache/
|
||||
.DS_Store
|
||||
.venv/
|
||||
dist/
|
||||
*.zip
|
||||
40
.specify/extensions/agent-governance/CHANGELOG.md
Normal file
40
.specify/extensions/agent-governance/CHANGELOG.md
Normal file
@@ -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.
|
||||
21
.specify/extensions/agent-governance/LICENSE
Normal file
21
.specify/extensions/agent-governance/LICENSE
Normal file
@@ -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.
|
||||
58
.specify/extensions/agent-governance/README.md
Normal file
58
.specify/extensions/agent-governance/README.md
Normal file
@@ -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
|
||||
```
|
||||
@@ -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
|
||||
46
.specify/extensions/agent-governance/extension.yml
Normal file
46
.specify/extensions/agent-governance/extension.yml
Normal file
@@ -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"
|
||||
@@ -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 = "<!-- SPECKIT GOVERNANCE START -->"
|
||||
MARKER_END = "<!-- SPECKIT GOVERNANCE 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(
|
||||
[
|
||||
"<!--",
|
||||
"Sync Impact Report",
|
||||
f"- Active Integration: {default_integration(state) or 'unknown'}",
|
||||
f"- Installed Integrations: {', '.join(installed_integrations(state)) or 'none'}",
|
||||
f"- Skills Scanned: {len(scan_skills(root))}",
|
||||
f"- MCP Config Files Scanned: {', '.join(scan_mcp_configs(root)) or 'none'}",
|
||||
f"- Extension Config Status: .specify/extensions.yml ({extensions_status(root)})",
|
||||
"- Sections Changed: initialized repository evidence and development commands",
|
||||
"- Flow: generate missing target governance files; update existing target governance files",
|
||||
"-->",
|
||||
]
|
||||
)
|
||||
pattern = re.compile(r"<!--\nSync Impact Report\n.*?\n-->", 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: `<!-- SPECKIT GOVERNANCE START -->` and `<!-- SPECKIT GOVERNANCE END -->`.",
|
||||
]
|
||||
return [
|
||||
"- Keep edits inside the active task scope and preserve user changes.",
|
||||
"- Preserve managed markers verbatim: `<!-- SPECKIT GOVERNANCE START -->` and `<!-- SPECKIT GOVERNANCE END -->`.",
|
||||
]
|
||||
|
||||
|
||||
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())
|
||||
@@ -0,0 +1,53 @@
|
||||
# Agent Governance Cache
|
||||
|
||||
<!--
|
||||
Sync Impact Report
|
||||
-->
|
||||
|
||||
## 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: `<!-- SPECKIT GOVERNANCE START -->` and `<!-- SPECKIT GOVERNANCE END -->`
|
||||
- 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
|
||||
0
.specify/extensions/review/scripts/bash/detect-changed-files.sh
Normal file → Executable file
0
.specify/extensions/review/scripts/bash/detect-changed-files.sh
Normal file → Executable file
0
.specify/extensions/verify/scripts/bash/load-config.sh
Normal file → Executable file
0
.specify/extensions/verify/scripts/bash/load-config.sh
Normal file → Executable file
@@ -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"
|
||||
}
|
||||
@@ -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"
|
||||
}
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
|
||||
84
.specify/memory/agent-governance.md
Normal file
84
.specify/memory/agent-governance.md
Normal file
@@ -0,0 +1,84 @@
|
||||
# Agent Governance Cache
|
||||
|
||||
<!--
|
||||
Sync Impact Report
|
||||
-->
|
||||
|
||||
## 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: `<!-- SPECKIT GOVERNANCE START -->` and `<!-- SPECKIT GOVERNANCE END -->`
|
||||
- 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
|
||||
@@ -1,17 +1,14 @@
|
||||
<!--
|
||||
SYNC IMPACT REPORT
|
||||
==================
|
||||
Version change: 1.2.0 → 1.3.0
|
||||
Version change: 1.3.1 → 1.3.2
|
||||
Modified principles:
|
||||
- VI. Verify Before Push → renumbered to VII.
|
||||
Added sections:
|
||||
- VI. Documentation Freshness (new principle requiring last_updated frontmatter,
|
||||
blocking staleness check, link validation, coverage checks, freshness warnings)
|
||||
- I–VII: Rationale blocks compressed into HTML comments (no semantic change)
|
||||
Modified sections: None.
|
||||
Added sections: None.
|
||||
Removed sections: None.
|
||||
Templates requiring updates:
|
||||
- .specify/templates/checklist-template.md — Add CHK006 for documentation freshness
|
||||
- .specify/templates/plan-template.md — Constitution Check VII for docs freshness
|
||||
Follow-up TODOs: Update AGENTS.md with docs governance reference.
|
||||
Templates requiring updates: None (no principle renumbering).
|
||||
Follow-up TODOs: None.
|
||||
-->
|
||||
|
||||
# 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.
|
||||
<!-- Rationale: Multi-platform parity (Android, Desktop, iOS). Framework bleed in commonMain breaks compilability on non-Android targets. -->
|
||||
|
||||
### 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.
|
||||
<!-- Rationale: Consistent code style and static analysis gates prevent technical debt accumulation. -->
|
||||
|
||||
### 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.
|
||||
<!-- Rationale: Compose Multiplatform ensures UI consistency across platforms. -->
|
||||
|
||||
### 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.
|
||||
<!-- Rationale: Meshtastic users rely on the mesh for private, off-grid communications. Data leaks could endanger users in sensitive 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.
|
||||
<!-- Rationale: Consistent cross-platform UX ensures users have a predictable experience regardless of platform. -->
|
||||
|
||||
### 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.
|
||||
<!-- Rationale: Documentation drift misleads users and increases support burden. Three distinct consumers means changes 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 <PR>` or
|
||||
`gh run list --branch <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.
|
||||
<!-- Rationale: Verification is a hard gate, not an optimistic assumption. Skipped local checks are the leading cause of CI failures. -->
|
||||
|
||||
## 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` `<process_essentials>`. 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
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
577
.specify/presets/.cache/catalog-ff86b51b80a289e5.json
Normal file
577
.specify/presets/.cache/catalog-ff86b51b80a289e5.json
Normal file
@@ -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"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
4
.specify/presets/.cache/catalog-metadata.json
Normal file
4
.specify/presets/.cache/catalog-metadata.json
Normal file
@@ -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"
|
||||
}
|
||||
30
.specify/presets/.cache/catalog.json
Normal file
30
.specify/presets/.cache/catalog.json
Normal file
@@ -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"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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**: <!-- Link to meshtastic/design/features/ spec, or "N/A — platform-specific only" with justification -->
|
||||
|
||||
## Summary
|
||||
@@ -11,7 +11,7 @@
|
||||
<!--
|
||||
Provide a brief (2-3 sentence) summary of the feature, its purpose, and what
|
||||
user problem it solves. Mention which modules are primarily affected.
|
||||
|
||||
|
||||
CROSS-PLATFORM CHECK: Before writing this spec, check meshtastic/design/features/
|
||||
for an existing cross-platform behavior spec. If one exists, this spec should describe
|
||||
the Android-specific scope and acceptance criteria — not redefine the cross-platform
|
||||
@@ -37,7 +37,7 @@
|
||||
IMPORTANT: User stories should be PRIORITIZED as user journeys ordered by importance.
|
||||
Each user story/journey must be INDEPENDENTLY TESTABLE - meaning if you implement just ONE of them,
|
||||
you should still have a viable MVP (Minimum Viable Product) that delivers value.
|
||||
|
||||
|
||||
Assign priorities (P1, P2, P3, etc.) to each story, where P1 is the most critical.
|
||||
Think of each story as a standalone slice of functionality that can be:
|
||||
- Developed independently
|
||||
@@ -101,6 +101,22 @@
|
||||
- What happens when [boundary condition]?
|
||||
- How does system handle [error scenario]?
|
||||
|
||||
## Requirements *(mandatory)*
|
||||
|
||||
<!--
|
||||
ACTION REQUIRED: The content in this section represents placeholders.
|
||||
Fill them out with the right functional requirements.
|
||||
-->
|
||||
|
||||
### 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
|
||||
|
||||
<!--
|
||||
@@ -121,27 +137,11 @@
|
||||
| [Component] | `feature/[name]/component/` | [Purpose] |
|
||||
| [Existing Component] | `core/ui/component/` | [Reuse purpose] |
|
||||
|
||||
## Requirements *(mandatory)*
|
||||
|
||||
<!--
|
||||
ACTION REQUIRED: The content in this section represents placeholders.
|
||||
Fill them out with the right functional requirements.
|
||||
-->
|
||||
|
||||
### 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
|
||||
|
||||
<!--
|
||||
ACTION REQUIRED: Identify which KMP source sets this feature affects.
|
||||
All business logic and UI MUST be in commonMain (Constitution §I, §III).
|
||||
All business logic and UI MUST be in commonMain (Constitution I, III).
|
||||
-->
|
||||
|
||||
| Source Set | Impact | Justification |
|
||||
@@ -154,7 +154,7 @@
|
||||
|
||||
<!--
|
||||
ACTION REQUIRED: Note any UI elements that must be reviewed against the
|
||||
Meshtastic Client Design Standards (Constitution §V). Flag intentional
|
||||
Meshtastic Client Design Standards (Constitution V). Flag intentional
|
||||
deviations with rationale.
|
||||
-->
|
||||
|
||||
@@ -166,7 +166,7 @@
|
||||
## Privacy Assessment
|
||||
|
||||
<!--
|
||||
ACTION REQUIRED: Confirm this feature does not violate Constitution §IV.
|
||||
ACTION REQUIRED: Confirm this feature does not violate Constitution IV.
|
||||
If the feature handles any sensitive data, document the safeguards.
|
||||
-->
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
<!--
|
||||
<!--
|
||||
============================================================================
|
||||
IMPORTANT: The tasks below are SAMPLE TASKS for illustration purposes only.
|
||||
|
||||
|
||||
The /speckit.tasks command MUST replace these with actual tasks based on:
|
||||
- User stories from spec.md (with their priorities P1, P2, P3...)
|
||||
- Feature requirements from plan.md
|
||||
- Entities from data-model.md
|
||||
- Endpoints from contracts/
|
||||
|
||||
|
||||
Tasks MUST be organized by user story so each story can be:
|
||||
- Implemented independently
|
||||
- Tested independently
|
||||
- Delivered as an MVP increment
|
||||
|
||||
|
||||
DO NOT keep these sample tasks in the generated tasks.md file.
|
||||
============================================================================
|
||||
-->
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
{"url": "https://raw.githubusercontent.com/github/spec-kit/main/workflows/catalog.community.json", "fetched_at": 1779389640.9802408}
|
||||
@@ -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": {}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
{"url": "https://raw.githubusercontent.com/github/spec-kit/main/workflows/catalog.json", "fetched_at": 1779389641.039055}
|
||||
@@ -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"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -49,5 +49,4 @@ You are an expert Android/KMP engineer. Maintain architectural boundaries, use M
|
||||
<!-- SPECKIT START -->
|
||||
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`
|
||||
<!-- SPECKIT END -->
|
||||
|
||||
Reference in New Issue
Block a user