diff --git a/.agents/skills/agent-core/SKILL.md b/.agents/skills/agent-core/SKILL.md new file mode 100644 index 00000000..c2f26634 --- /dev/null +++ b/.agents/skills/agent-core/SKILL.md @@ -0,0 +1,84 @@ +# SKILL.md +# Agent Core Profile + +## Requirements Covered + +### Governance Requirements +- REQ-012: Least-Privilege Agent Permissions +- REQ-217: Agent Permissions Check +- REQ-220: Policy Guardrails +- REQ-244: Context Window Sizing +- REQ-245: Live Context Fill Indicator +- REQ-246: Auto Context Compression +- REQ-247: Hard Context Ceiling + +## Core Principle +The agent-core profile defines the fundamental capabilities and governance rules that all Specsmith agents must follow. This profile ensures that agents operate within the bounds of the Specsmith governance framework while maintaining the flexibility to adapt to different project contexts. + +## Profile Characteristics + +### Minimal Required Skills +- preflight-gate +- governed-agent-loop +- requirement-author +- testcase-author +- traceability-auditor +- context-pack-compiler +- token-budget-auditor +- skill-composer + +### Governance Compliance +All agents using this profile must: +1. Run preflight checks before any action that could have side effects +2. Follow the governed-agent-loop execution pattern +3. Maintain traceability between requirements, tests, and code changes +4. Compose skills dynamically based on context +5. Track token usage and budget efficiency + +## Implementation Details + +### Core Loop Execution +1. Detect Specsmith project context +2. Run session bootstrap procedures +3. Emit governance anchor +4. Classify user intent (read-only, change, release, destructive, research, planning) +5. For non-read-only actions, run preflight +6. Load only required context and skills +7. Execute smallest scoped action +8. Run verification gates +9. Record evidence +10. Save through Specsmith + +### Context Management +- Build minimal context packs from project state, requirements, work items, ESDB records, and relevant skills +- Never inject the whole repository when a scoped context is sufficient +- Prefer requirement IDs, test IDs, recent WIs, and relevant files +- Exclude stale, low-confidence, tombstoned, or contradicted ESDB records +- Include stop conditions and known hazards +- Track token budget and context utilization + +## Configuration + +### Default Behavior +By default, the agent-core profile: +- Enforces strict preflight checks for all non-read-only operations +- Maintains minimal skill set for efficiency +- Applies context-aware optimization +- Tracks all actions for audit purposes + +### Override Options +- Allow manual skill composition for advanced users +- Support skill exclusion for specific scenarios +- Enable temporary skill overrides with proper preflight + +## Security Considerations +- All actions must pass preflight validation +- Skill compositions must be traceable to valid work items +- Unauthorized skill combinations are blocked +- Skill composition history is tracked for audit purposes + +## Compliance Requirements +- Every action must be traceable to a valid work item or requirement +- All skill compositions must comply with the project's permission model +- Token usage must be tracked and reported +- Audit trails must be maintained for all operations diff --git a/.agents/skills/ai-app-governed/SKILL.md b/.agents/skills/ai-app-governed/SKILL.md new file mode 100644 index 00000000..f04e5e5e --- /dev/null +++ b/.agents/skills/ai-app-governed/SKILL.md @@ -0,0 +1,85 @@ +# SKILL.md +# AI App Governed Profile + +## Requirements Covered + +### Governance Requirements +- REQ-012: Least-Privilege Agent Permissions +- REQ-217: Agent Permissions Check +- REQ-220: Policy Guardrails +- REQ-244: Context Window Sizing +- REQ-245: Live Context Fill Indicator +- REQ-246: Auto Context Compression +- REQ-247: Hard Context Ceiling + +## Core Principle +The ai-app-governed profile is designed for agents operating within AI application development environments. It ensures compliance with Specsmith governance while managing the unique constraints and capabilities of AI application development. + +## Profile Characteristics + +### Required Skills +- preflight-gate +- governed-agent-loop +- requirement-author +- testcase-author +- traceability-auditor +- context-pack-compiler +- token-budget-auditor +- skill-composer +- execution +- git +- release +- playwright-testing +- testing-configuration +- testing-environment-isolation +- testing-artifact-management +- testing-report-generation +- testing-cicd-integration +- testing-parallel-execution +- testing-coverage-reporting + +### Environment-Specific Features +- AI application development environment integration +- Context window optimization for AI app constraints +- Compliance with AI application development policies +- Integration with AI application testing frameworks + +## Implementation Details + +### AI App-Specific Execution +1. Leverage AI application development capabilities for model training and deployment +2. Optimize context windows to fit AI application development constraints +3. Apply Specsmith governance rules within AI application environments +4. Maintain traceability between AI app actions and Specsmith requirements + +### Context Management +- Optimize context for AI application development requirements +- Apply AI app-specific compression techniques +- Ensure context fits within AI app constraints while maintaining traceability +- Track AI application development usage and performance metrics + +## Configuration + +### Default Behavior +By default, the ai-app-governed profile: +- Integrates with AI application development tools and environments +- Optimizes context for AI application development constraints +- Maintains full Specsmith governance compliance +- Tracks AI application development metrics + +### Override Options +- Allow AI app-specific skill overrides +- Support AI application development environment customization +- Enable AI app-specific context optimization + +## Security Considerations +- All AI application development actions must pass preflight validation +- AI app-specific skill compositions must be traceable +- AI application development environment compliance must be maintained +- AI application development usage must be tracked and audited + +## Compliance Requirements +- Every AI application development action must be traceable to a valid work item or requirement +- AI application development integration must comply with development environment policies +- All skill compositions must follow Specsmith governance +- AI application development usage must be reported and audited diff --git a/.agents/skills/aider-integration/SKILL.md b/.agents/skills/aider-integration/SKILL.md index 18abb10e..422e3b54 100644 --- a/.agents/skills/aider-integration/SKILL.md +++ b/.agents/skills/aider-integration/SKILL.md @@ -22,7 +22,7 @@ aider --read AGENTS.md --read .agents/skills/specsmith-session-governance/ ## Every Aider session — mandatory protocol 1. Run before starting aider: ```bash -specsmith kill-session 2>/dev/null || true +specsmith kill-session # idempotent; safe when no processes exist specsmith audit --project-dir . specsmith sync --project-dir . specsmith checkpoint --project-dir . diff --git a/.agents/skills/claude-code-governed/SKILL.md b/.agents/skills/claude-code-governed/SKILL.md new file mode 100644 index 00000000..73630aa5 --- /dev/null +++ b/.agents/skills/claude-code-governed/SKILL.md @@ -0,0 +1,75 @@ +# SKILL.md +# Claude Code Governed Profile + +## Requirements Covered + +### Governance Requirements +- REQ-012: Least-Privilege Agent Permissions +- REQ-217: Agent Permissions Check +- REQ-220: Policy Guardrails +- REQ-244: Context Window Sizing +- REQ-245: Live Context Fill Indicator +- REQ-246: Auto Context Compression +- REQ-247: Hard Context Ceiling + +## Core Principle +The claude-code-governed profile is designed for agents operating within the Claude Code environment. It ensures compliance with Specsmith governance while leveraging Claude's specific capabilities and constraints. + +## Profile Characteristics + +### Required Skills +- preflight-gate +- governed-agent-loop +- requirement-author +- testcase-author +- traceability-auditor +- context-pack-compiler +- token-budget-auditor +- skill-composer +- claude-code-integration + +### Environment-Specific Features +- Claude Code integration capabilities +- Context window optimization for Claude's token limits +- Compliance with Claude's usage policies +- Integration with Claude's code editing features + +## Implementation Details + +### Claude-Specific Execution +1. Leverage Claude Code's native capabilities for code editing +2. Optimize context windows to fit Claude's token limits +3. Apply Specsmith governance rules within Claude's environment +4. Maintain traceability between Claude actions and Specsmith requirements + +### Context Management +- Optimize context for Claude's 100K token limit +- Apply Claude-specific compression techniques +- Ensure context fits within Claude's constraints while maintaining traceability +- Track Claude-specific token usage + +## Configuration + +### Default Behavior +By default, the claude-code-governed profile: +- Integrates with Claude Code's native editing features +- Optimizes context for Claude's token limits +- Maintains full Specsmith governance compliance +- Tracks Claude-specific usage metrics + +### Override Options +- Allow Claude-specific skill overrides +- Support Claude Code environment customization +- Enable Claude-specific context optimization + +## Security Considerations +- All Claude Code actions must pass preflight validation +- Claude-specific skill compositions must be traceable +- Claude Code environment compliance must be maintained +- Claude-specific token usage must be tracked + +## Compliance Requirements +- Every Claude Code action must be traceable to a valid work item or requirement +- Claude Code integration must comply with Claude's usage policies +- All skill compositions must follow Specsmith governance +- Claude-specific token usage must be reported diff --git a/.agents/skills/claude-code-integration/SKILL.md b/.agents/skills/claude-code-integration/SKILL.md index 5e6bcf1d..3e71b5f4 100644 --- a/.agents/skills/claude-code-integration/SKILL.md +++ b/.agents/skills/claude-code-integration/SKILL.md @@ -21,7 +21,7 @@ Or run: `specsmith mcp install-claude-code` ## Every Claude Code session — mandatory protocol 1. Run at session start: ```bash -specsmith kill-session 2>/dev/null || true +specsmith kill-session # idempotent; safe when no processes exist specsmith audit --project-dir . specsmith sync --project-dir . specsmith checkpoint --project-dir . diff --git a/.agents/skills/copilot-integration/SKILL.md b/.agents/skills/copilot-integration/SKILL.md index 7b0dc057..3da1337d 100644 --- a/.agents/skills/copilot-integration/SKILL.md +++ b/.agents/skills/copilot-integration/SKILL.md @@ -12,7 +12,7 @@ and hard rules. ## Every Copilot session — mandatory protocol 1. Run at session start: ```bash -specsmith kill-session 2>/dev/null || true +specsmith kill-session # idempotent; safe when no processes exist specsmith audit --project-dir . specsmith sync --project-dir . specsmith checkpoint --project-dir . diff --git a/.agents/skills/cursor-governed/SKILL.md b/.agents/skills/cursor-governed/SKILL.md new file mode 100644 index 00000000..4103edda --- /dev/null +++ b/.agents/skills/cursor-governed/SKILL.md @@ -0,0 +1,75 @@ +# SKILL.md +# Cursor Governed Profile + +## Requirements Covered + +### Governance Requirements +- REQ-012: Least-Privilege Agent Permissions +- REQ-217: Agent Permissions Check +- REQ-220: Policy Guardrails +- REQ-244: Context Window Sizing +- REQ-245: Live Context Fill Indicator +- REQ-246: Auto Context Compression +- REQ-247: Hard Context Ceiling + +## Core Principle +The cursor-governed profile is designed for agents operating within the Cursor IDE environment. It ensures compliance with Specsmith governance while leveraging Cursor's specific capabilities and constraints. + +## Profile Characteristics + +### Required Skills +- preflight-gate +- governed-agent-loop +- requirement-author +- testcase-author +- traceability-auditor +- context-pack-compiler +- token-budget-auditor +- skill-composer +- cursor-integration + +### Environment-Specific Features +- Cursor IDE integration capabilities +- Context window optimization for Cursor's IDE constraints +- Compliance with Cursor's IDE environment +- Integration with Cursor's native IDE features + +## Implementation Details + +### Cursor-Specific Execution +1. Leverage Cursor IDE's native capabilities for code editing +2. Optimize context windows to fit Cursor's IDE constraints +3. Apply Specsmith governance rules within Cursor's environment +4. Maintain traceability between Cursor actions and Specsmith requirements + +### Context Management +- Optimize context for Cursor's IDE environment +- Apply Cursor-specific compression techniques +- Ensure context fits within Cursor's constraints while maintaining traceability +- Track Cursor-specific IDE usage + +## Configuration + +### Default Behavior +By default, the cursor-governed profile: +- Integrates with Cursor IDE's native features +- Optimizes context for Cursor's IDE environment +- Maintains full Specsmith governance compliance +- Tracks Cursor-specific usage metrics + +### Override Options +- Allow Cursor-specific skill overrides +- Support Cursor IDE environment customization +- Enable Cursor-specific context optimization + +## Security Considerations +- All Cursor IDE actions must pass preflight validation +- Cursor-specific skill compositions must be traceable +- Cursor IDE environment compliance must be maintained +- Cursor-specific IDE usage must be tracked + +## Compliance Requirements +- Every Cursor IDE action must be traceable to a valid work item or requirement +- Cursor IDE integration must comply with Cursor's usage policies +- All skill compositions must follow Specsmith governance +- Cursor-specific IDE usage must be reported diff --git a/.agents/skills/cursor-integration/SKILL.md b/.agents/skills/cursor-integration/SKILL.md index 98e77c6a..d4b05233 100644 --- a/.agents/skills/cursor-integration/SKILL.md +++ b/.agents/skills/cursor-integration/SKILL.md @@ -18,7 +18,7 @@ For MCP in Cursor (Settings → MCP or `.cursor/mcp.json`): ## Every Cursor session — mandatory protocol 1. Run at session start: ```bash -specsmith kill-session 2>/dev/null || true +specsmith kill-session # idempotent; safe when no processes exist specsmith audit --project-dir . specsmith sync --project-dir . specsmith checkpoint --project-dir . diff --git a/.agents/skills/embedded-fpga-governed/SKILL.md b/.agents/skills/embedded-fpga-governed/SKILL.md new file mode 100644 index 00000000..2b18d654 --- /dev/null +++ b/.agents/skills/embedded-fpga-governed/SKILL.md @@ -0,0 +1,77 @@ +# SKILL.md +# Embedded FPGA Governed Profile + +## Requirements Covered + +### Governance Requirements +- REQ-012: Least-Privilege Agent Permissions +- REQ-217: Agent Permissions Check +- REQ-220: Policy Guardrails +- REQ-244: Context Window Sizing +- REQ-245: Live Context Fill Indicator +- REQ-246: Auto Context Compression +- REQ-247: Hard Context Ceiling + +## Core Principle +The embedded-fpga-governed profile is designed for agents operating in embedded FPGA development environments. It ensures compliance with Specsmith governance while managing the unique constraints and requirements of FPGA development. + +## Profile Characteristics + +### Required Skills +- preflight-gate +- governed-agent-loop +- requirement-author +- testcase-author +- traceability-auditor +- context-pack-compiler +- token-budget-auditor +- skill-composer +- execution +- git +- release + +### Environment-Specific Features +- FPGA development environment integration +- Context window optimization for FPGA constraints +- Compliance with FPGA development policies +- Integration with FPGA development tools and workflows + +## Implementation Details + +### FPGA-Specific Execution +1. Leverage FPGA development tool capabilities for hardware design +2. Optimize context windows to fit FPGA development constraints +3. Apply Specsmith governance rules within FPGA environments +4. Maintain traceability between FPGA actions and Specsmith requirements + +### Context Management +- Optimize context for FPGA development requirements +- Apply FPGA-specific compression techniques +- Ensure context fits within FPGA constraints while maintaining traceability +- Track FPGA development usage and performance metrics + +## Configuration + +### Default Behavior +By default, the embedded-fpga-governed profile: +- Integrates with FPGA development tools and environments +- Optimizes context for FPGA development constraints +- Maintains full Specsmith governance compliance +- Tracks FPGA development metrics + +### Override Options +- Allow FPGA-specific skill overrides +- Support FPGA development environment customization +- Enable FPGA-specific context optimization + +## Security Considerations +- All FPGA development actions must pass preflight validation +- FPGA-specific skill compositions must be traceable +- FPGA development environment compliance must be maintained +- FPGA development usage must be tracked and audited + +## Compliance Requirements +- Every FPGA development action must be traceable to a valid work item or requirement +- FPGA development integration must comply with development environment policies +- All skill compositions must follow Specsmith governance +- FPGA development usage must be reported and audited diff --git a/.agents/skills/execution/SKILL.md b/.agents/skills/execution/SKILL.md new file mode 100644 index 00000000..76d6509e --- /dev/null +++ b/.agents/skills/execution/SKILL.md @@ -0,0 +1,116 @@ +--- +name: execution +description: Skill for managing local command execution and environment management with specsmith governance +--- + +# Local Execution Management + +This skill enables specsmith projects to manage local command execution and environment management while maintaining governance compliance across Windows, Linux, and Mac platforms. + +## Requirements Covered + +- REQ-089: Local Command Execution Policy +- REQ-090: Local Command Whitelist Management +- REQ-091: Local Command Blacklist Management +- REQ-092: Local Command Override Capability +- REQ-093: Pip Execution Override +- REQ-094: Pip Execution Safety Checks +- REQ-095: Virtual Environment Creation +- REQ-096: Virtual Environment Management +- REQ-097: Virtual Environment Validation +- REQ-098: Virtual Environment Warning System +- REQ-099: Local Environment Isolation +- REQ-100: Execution Policy Configuration + +## Integration Capabilities + +### Platform Features +- Cross-platform command execution with platform-specific considerations +- Local environment isolation and management +- Virtual environment creation and management +- Pip execution safety with workspace-local enforcement +- Whitelist and blacklist management for commands +- Override capability with human approval + +### Governance Requirements +- Human approval required for all local command execution +- Configuration management with governance controls +- Security best practices enforcement for execution +- Resource monitoring and logging for execution activities + +## Platform-Specific Considerations + +### Windows +- Path handling with Windows-specific conventions +- PowerShell and CMD integration +- Windows-specific environment variables +- File system permissions and access controls +- Registry and system integration considerations + +### Linux +- POSIX-compliant path handling +- Shell integration (bash, zsh, fish) +- Package manager integration (apt, yum, pacman) +- System service management +- File permissions and ownership + +### macOS +- Darwin-specific path handling +- macOS application integration +- Homebrew and MacPorts package management +- System preferences and security frameworks +- AppleScript and automation support + +## Usage Examples + +```bash +# Initialize execution management +specsmith skill install execution + +# Configure execution policy +specsmith execution configure --default-permissive true --whitelist "git,python,pip" + +# Execute a command with approval +specsmith execution run --command "pip install requests" + +# Create a virtual environment +specsmith execution venv create --name myproject + +# Manage virtual environments +specsmith execution venv list +specsmith execution venv activate --name myproject +``` + +## Configuration + +The skill requires the following configuration in `scaffold.yml`: + +```yaml +execution: + default_permissive: true + whitelist: + - git + - python + - pip + blacklist: [] + pip_override_enabled: false + venv_auto_create: true + platform: auto # windows, linux, mac, or auto +``` + +## Security Considerations + +- All local command executions require human approval +- Platform-specific security policies must be enforced +- File system access controls must be maintained +- Environment variable handling must be secure +- Cross-platform compatibility must not compromise security +- Pip execution must only use local pip from workspace environment + +## Compliance Requirements + +- Follow security best practices for local execution +- Maintain audit logs of all local command executions +- Ensure proper virtual environment management and validation +- Enforce approval-based execution setup +- Support for platform-specific compliance requirements diff --git a/.agents/skills/gemini-cli-integration/SKILL.md b/.agents/skills/gemini-cli-integration/SKILL.md index dd15552b..4edefd41 100644 --- a/.agents/skills/gemini-cli-integration/SKILL.md +++ b/.agents/skills/gemini-cli-integration/SKILL.md @@ -10,7 +10,7 @@ Gemini CLI reads `GEMINI.md` from the project root automatically. ## Every Gemini CLI session — mandatory protocol 1. Run at session start: ```bash -specsmith kill-session 2>/dev/null || true +specsmith kill-session # idempotent; safe when no processes exist specsmith audit --project-dir . specsmith sync --project-dir . specsmith checkpoint --project-dir . diff --git a/.agents/skills/git/SKILL.md b/.agents/skills/git/SKILL.md new file mode 100644 index 00000000..2a86dd97 --- /dev/null +++ b/.agents/skills/git/SKILL.md @@ -0,0 +1,115 @@ +--- +name: git +description: Skill for managing Git platform management with specsmith governance +--- + +# Git Platform Management + +This skill enables specsmith projects to manage Git repositories across multiple platforms (GitHub, GitLab, Bitbucket, etc.) while maintaining governance compliance across Windows, Linux, and Mac platforms. + +## Requirements Covered + +- REQ-079: Git Platform Agnostic Management +- REQ-080: GitHub Platform Management +- REQ-081: GitLab Platform Management +- REQ-082: Bitbucket Platform Management +- REQ-083: Azure DevOps Platform Management +- REQ-084: Git Platform Authentication Management +- REQ-085: Git Platform Configuration Management +- REQ-086: Git Platform Repository Creation +- REQ-087: Git Platform Repository Deletion +- REQ-088: Git Platform Repository Cloning + +## Integration Capabilities + +### Platform Features +- Cross-platform Git repository management for GitHub, GitLab, Bitbucket, and Azure DevOps +- Platform-specific authentication and credential management +- Repository creation, deletion, and cloning +- Configuration management for multiple Git platforms +- Webhook and integration management + +### Governance Requirements +- Human approval required for all Git platform operations +- Configuration management with governance controls +- Security best practices enforcement for Git operations +- Audit logging of all Git platform activities + +## Platform-Specific Considerations + +### Windows +- Path handling with Windows-specific conventions +- Git client integration with Windows-specific tools +- Windows-specific credential storage and management +- File system permissions for repository access + +### Linux +- POSIX-compliant path handling +- Git client integration with standard Linux tools +- Package manager integration for Git tools +- System service management for Git operations + +### macOS +- Darwin-specific path handling +- macOS application integration for Git tools +- Homebrew and MacPorts package management +- System preferences and security frameworks + +## Usage Examples + +```bash +# Initialize Git management +specsmith skill install git + +# Configure Git platform settings +specsmith git configure --platform github --token-file ~/.github_token + +# Create a new repository +specsmith git repo create --platform github --name my-project --description "My new project" + +# Clone a repository +specsmith git repo clone --platform github --url https://github.com/user/repo.git + +# Manage authentication +specsmith git auth setup --platform github --token mytoken123 + +# List repositories +specsmith git repo list --platform github +``` + +## Configuration + +The skill requires the following configuration in `scaffold.yml`: + +```yaml +git: + default_platform: github + platforms: + github: + token_file: ~/.github_token + api_endpoint: https://api.github.com + gitlab: + token_file: ~/.gitlab_token + api_endpoint: https://gitlab.com/api/v4 + bitbucket: + token_file: ~/.bitbucket_token + api_endpoint: https://api.bitbucket.org/2.0 + auto_approve: false + platform: auto # windows, linux, mac, or auto +``` + +## Security Considerations + +- All Git platform operations require human approval +- Platform-specific security policies must be enforced +- Credential storage and management must be secure +- Repository access controls must be maintained +- Cross-platform compatibility must not compromise security + +## Compliance Requirements + +- Follow security best practices for Git platform management +- Maintain audit logs of all Git platform operations +- Ensure proper platform-specific configuration management +- Enforce approval-based Git platform setup +- Support for platform-specific compliance requirements diff --git a/.agents/skills/lmstudio-integration/SKILL.md b/.agents/skills/lmstudio-integration/SKILL.md new file mode 100644 index 00000000..f87c3c9a --- /dev/null +++ b/.agents/skills/lmstudio-integration/SKILL.md @@ -0,0 +1,67 @@ +--- +name: lmstudio-integration +description: Skill for integrating with LMStudio for local AI model serving with specsmith governance +--- + +# LMStudio Platform Integration + +This skill enables specsmith projects to integrate with LMStudio for local AI model serving while maintaining governance compliance. + +## Requirements Covered + +- REQ-111: LMStudio Platform Integration +- Allows specsmith projects to integrate with LMStudio for local AI model serving with human approval + +## Integration Capabilities + +### Platform Features +- LMStudio model serving and deployment +- Local model management +- GPU and CPU resource utilization +- API endpoint configuration for LMStudio services +- Model quantization and optimization + +### Governance Requirements +- Human approval required for all LMStudio integrations +- Configuration management with governance controls +- Security best practices enforcement +- Resource monitoring and logging + +## Usage Examples + +```bash +# Initialize LMStudio integration +specsmith skill install lmstudio-integration + +# Configure LMStudio platform settings +specsmith lmstudio configure --platform lmstudio --model-path /path/to/model --gpu-enabled true + +# Deploy model via LMStudio +specsmith lmstudio deploy --model my-model --port 1234 +``` + +## Configuration + +The skill requires the following configuration in `scaffold.yml`: + +```yaml +lmstudio: + platform: lmstudio + model_path: /path/to/models + gpu_enabled: true + port: 1234 + model_format: "gguf" +``` + +## Security Considerations + +- All LMStudio integrations require human approval +- Local model access controls must be configured +- Network security must be enforced +- Resource usage monitoring is required + +## Compliance Requirements + +- Follow security best practices for AI platform integrations +- Maintain audit logs of all LMStudio interactions +- Ensure proper resource management and monitoring diff --git a/.agents/skills/local-ai-governed/SKILL.md b/.agents/skills/local-ai-governed/SKILL.md new file mode 100644 index 00000000..3bae0b47 --- /dev/null +++ b/.agents/skills/local-ai-governed/SKILL.md @@ -0,0 +1,79 @@ +# SKILL.md +# Local AI Governed Profile + +## Requirements Covered + +### Governance Requirements +- REQ-012: Least-Privilege Agent Permissions +- REQ-217: Agent Permissions Check +- REQ-220: Policy Guardrails +- REQ-244: Context Window Sizing +- REQ-245: Live Context Fill Indicator +- REQ-246: Auto Context Compression +- REQ-247: Hard Context Ceiling + +## Core Principle +The local-ai-governed profile is designed for agents operating with local AI models and tools. It ensures compliance with Specsmith governance while managing the unique constraints and capabilities of local AI environments. + +## Profile Characteristics + +### Required Skills +- preflight-gate +- governed-agent-loop +- requirement-author +- testcase-author +- traceability-auditor +- context-pack-compiler +- token-budget-auditor +- skill-composer +- webui-integration +- vllm-integration +- lmstudio-integration +- ollama-integration +- openterminal-integration + +### Environment-Specific Features +- Local AI model integration capabilities +- Context window optimization for local AI constraints +- Compliance with local AI environment policies +- Integration with various local AI platforms + +## Implementation Details + +### Local AI-Specific Execution +1. Leverage local AI model capabilities for code generation and analysis +2. Optimize context windows to fit local AI constraints +3. Apply Specsmith governance rules within local AI environments +4. Maintain traceability between local AI actions and Specsmith requirements + +### Context Management +- Optimize context for local AI model limitations +- Apply local AI-specific compression techniques +- Ensure context fits within local AI constraints while maintaining traceability +- Track local AI usage and performance metrics + +## Configuration + +### Default Behavior +By default, the local-ai-governed profile: +- Integrates with various local AI platforms (WebUI, VLLM, LMStudio, Ollama, OpenTerminal) +- Optimizes context for local AI model constraints +- Maintains full Specsmith governance compliance +- Tracks local AI usage metrics + +### Override Options +- Allow local AI-specific skill overrides +- Support local AI environment customization +- Enable local AI-specific context optimization + +## Security Considerations +- All local AI actions must pass preflight validation +- Local AI skill compositions must be traceable +- Local AI environment compliance must be maintained +- Local AI usage must be tracked and audited + +## Compliance Requirements +- Every local AI action must be traceable to a valid work item or requirement +- Local AI integration must comply with local environment policies +- All skill compositions must follow Specsmith governance +- Local AI usage must be reported and audited diff --git a/.agents/skills/ollama-integration/SKILL.md b/.agents/skills/ollama-integration/SKILL.md new file mode 100644 index 00000000..58dc9848 --- /dev/null +++ b/.agents/skills/ollama-integration/SKILL.md @@ -0,0 +1,67 @@ +--- +name: ollama-integration +description: Skill for integrating with Ollama for local AI model serving with specsmith governance +--- + +# Ollama Platform Integration + +This skill enables specsmith projects to integrate with Ollama for local AI model serving while maintaining governance compliance. + +## Requirements Covered + +- REQ-112: Ollama Platform Integration +- Allows specsmith projects to integrate with Ollama for local AI model serving with human approval + +## Integration Capabilities + +### Platform Features +- Ollama model management and deployment +- Local model serving +- GPU and CPU resource utilization +- API endpoint configuration for Ollama services +- Model pulling and caching + +### Governance Requirements +- Human approval required for all Ollama integrations +- Configuration management with governance controls +- Security best practices enforcement +- Resource monitoring and logging + +## Usage Examples + +```bash +# Initialize Ollama integration +specsmith skill install ollama-integration + +# Configure Ollama platform settings +specsmith ollama configure --platform ollama --model-path /path/to/models --gpu-enabled true + +# Pull and run model via Ollama +specsmith ollama run --model llama3 --port 11434 +``` + +## Configuration + +The skill requires the following configuration in `scaffold.yml`: + +```yaml +ollama: + platform: ollama + model_path: /path/to/models + gpu_enabled: true + port: 11434 + model_name: "llama3" +``` + +## Security Considerations + +- All Ollama integrations require human approval +- Local model access controls must be configured +- Network security must be enforced +- Resource usage monitoring is required + +## Compliance Requirements + +- Follow security best practices for AI platform integrations +- Maintain audit logs of all Ollama interactions +- Ensure proper resource management and monitoring diff --git a/.agents/skills/openterminal-integration/SKILL.md b/.agents/skills/openterminal-integration/SKILL.md new file mode 100644 index 00000000..404c0865 --- /dev/null +++ b/.agents/skills/openterminal-integration/SKILL.md @@ -0,0 +1,66 @@ +--- +name: openterminal-integration +description: Skill for integrating with OpenTerminal for AI terminal interfaces with specsmith governance +--- + +# OpenTerminal Platform Integration + +This skill enables specsmith projects to integrate with OpenTerminal for AI terminal interfaces while maintaining governance compliance. + +## Requirements Covered + +- REQ-113: OpenTerminal Platform Integration +- Allows specsmith projects to integrate with OpenTerminal for AI terminal interfaces with human approval + +## Integration Capabilities + +### Platform Features +- OpenTerminal terminal interface management +- AI-powered terminal command execution +- Terminal session management +- API endpoint configuration for OpenTerminal services +- Command history and logging + +### Governance Requirements +- Human approval required for all OpenTerminal integrations +- Configuration management with governance controls +- Security best practices enforcement +- Session monitoring and logging + +## Usage Examples + +```bash +# Initialize OpenTerminal integration +specsmith skill install openterminal-integration + +# Configure OpenTerminal platform settings +specsmith openterminal configure --platform openterminal --terminal-type ai-terminal --session-id session-123 + +# Start terminal session +specsmith openterminal start --session-id session-123 +``` + +## Configuration + +The skill requires the following configuration in `scaffold.yml`: + +```yaml +openterminal: + platform: openterminal + terminal_type: ai-terminal + session_id: session-123 + api_endpoint: "https://api.openterminal.com" +``` + +## Security Considerations + +- All OpenTerminal integrations require human approval +- Terminal session access controls must be configured +- Command execution security must be enforced +- Session monitoring is required + +## Compliance Requirements + +- Follow security best practices for AI terminal interfaces +- Maintain audit logs of all OpenTerminal interactions +- Ensure proper session management and monitoring diff --git a/.agents/skills/playwright-testing/SKILL.md b/.agents/skills/playwright-testing/SKILL.md new file mode 100644 index 00000000..44638d6c --- /dev/null +++ b/.agents/skills/playwright-testing/SKILL.md @@ -0,0 +1,72 @@ +--- +name: playwright-testing +description: Skill for using Playwright for end-to-end browser testing with specsmith governance +--- + +# Playwright Testing Framework + +This skill enables specsmith projects to use Playwright for end-to-end browser testing while maintaining governance compliance. + +## Requirements Covered + +- REQ-101: Playwright Testing Framework +- Allows specsmith projects to use Playwright for end-to-end browser testing with human approval + +## Integration Capabilities + +### Framework Features +- End-to-end browser testing with Playwright +- Cross-browser testing (Chromium, Firefox, WebKit) +- API testing capabilities +- Screenshot and video capture +- Parallel test execution +- Test reporting and analytics + +### Governance Requirements +- Human approval required for all Playwright testing +- Configuration management with governance controls +- Test artifact management with approval +- Reporting and coverage tracking with approval + +## Usage Examples + +```bash +# Initialize Playwright testing +specsmith skill install playwright-testing + +# Configure Playwright settings +specsmith playwright configure --browser chromium --timeout 30000 + +# Run end-to-end tests +specsmith playwright run --test-suite e2e-tests + +# Generate test reports +specsmith playwright report --format html +``` + +## Configuration + +The skill requires the following configuration in `scaffold.yml`: + +```yaml +playwright: + browser: chromium + timeout: 30000 + headless: true + parallel: true + screenshot: "on_failure" +``` + +## Security Considerations + +- All Playwright testing requires human approval +- Test environment isolation must be maintained +- Sensitive data handling in tests must be secured +- Test artifact access controls must be enforced + +## Compliance Requirements + +- Follow security best practices for testing environments +- Maintain audit logs of all Playwright test executions +- Ensure proper test artifact management and retention +- Generate and track test coverage reports diff --git a/.agents/skills/release-governed/SKILL.md b/.agents/skills/release-governed/SKILL.md new file mode 100644 index 00000000..d9cbcb36 --- /dev/null +++ b/.agents/skills/release-governed/SKILL.md @@ -0,0 +1,84 @@ +# SKILL.md +# Release Governed Profile + +## Requirements Covered + +### Governance Requirements +- REQ-012: Least-Privilege Agent Permissions +- REQ-217: Agent Permissions Check +- REQ-220: Policy Guardrails +- REQ-244: Context Window Sizing +- REQ-245: Live Context Fill Indicator +- REQ-246: Auto Context Compression +- REQ-247: Hard Context Ceiling +- REQ-065: GitHub Release Creation +- REQ-066: PyPI Deployment +- REQ-067: CI Management +- REQ-068: Pull Request Management +- REQ-069: GitLab and Bitbucket Support +- REQ-070: Repository Management +- REQ-071: Non-GitHub Platform Support + +## Core Principle +The release-governed profile is designed for agents operating in release management environments. It ensures compliance with Specsmith governance while managing the complex requirements of software releases across multiple platforms. + +## Profile Characteristics + +### Required Skills +- preflight-gate +- governed-agent-loop +- requirement-author +- testcase-author +- traceability-auditor +- context-pack-compiler +- token-budget-auditor +- skill-composer +- git +- release +- execution + +### Environment-Specific Features +- Release management environment integration +- Context window optimization for release processes +- Compliance with release management policies +- Integration with multiple platform release systems (GitHub, GitLab, Bitbucket, PyPI, etc.) + +## Implementation Details + +### Release-Specific Execution +1. Leverage release management capabilities for version control and deployment +2. Optimize context windows to fit release process constraints +3. Apply Specsmith governance rules within release environments +4. Maintain traceability between release actions and Specsmith requirements + +### Context Management +- Optimize context for release management requirements +- Apply release-specific compression techniques +- Ensure context fits within release constraints while maintaining traceability +- Track release management usage and performance metrics + +## Configuration + +### Default Behavior +By default, the release-governed profile: +- Integrates with multiple release platforms (GitHub, GitLab, Bitbucket, PyPI) +- Optimizes context for release management processes +- Maintains full Specsmith governance compliance +- Tracks release management metrics + +### Override Options +- Allow release-specific skill overrides +- Support release environment customization +- Enable release-specific context optimization + +## Security Considerations +- All release management actions must pass preflight validation +- Release-specific skill compositions must be traceable +- Release management environment compliance must be maintained +- Release management usage must be tracked and audited + +## Compliance Requirements +- Every release management action must be traceable to a valid work item or requirement +- Release management integration must comply with platform policies +- All skill compositions must follow Specsmith governance +- Release management usage must be reported and audited diff --git a/.agents/skills/release/SKILL.md b/.agents/skills/release/SKILL.md new file mode 100644 index 00000000..dc2cd2cb --- /dev/null +++ b/.agents/skills/release/SKILL.md @@ -0,0 +1,125 @@ +--- +name: release +description: Skill for managing release creation and deployment with specsmith governance +--- + +# Release Management + +This skill enables specsmith projects to manage release creation and deployment across multiple platforms (GitHub, PyPI, CI systems) while maintaining governance compliance across Windows, Linux, and Mac platforms. + +## Requirements Covered + +- REQ-065: GitHub Release Creation +- REQ-066: PyPI Deployment +- REQ-067: CI Management +- REQ-068: Pull Request Management +- REQ-071: Release Notes Generation +- REQ-072: Release Tag Management +- REQ-073: Artifact Management +- REQ-074: Release Branch Management +- REQ-075: Release Validation +- REQ-076: Release Rollback +- REQ-077: Release Promotion +- REQ-078: Release Metadata Management + +## Integration Capabilities + +### Platform Features +- Cross-platform release management for GitHub, PyPI, and CI systems +- Release creation, tagging, and deployment +- Pull request and merge management +- Release notes generation and validation +- Artifact management and cleanup +- Release branch management and promotion + +### Governance Requirements +- Human approval required for all release operations +- Configuration management with governance controls +- Security best practices enforcement for release processes +- Audit logging of all release activities + +## Platform-Specific Considerations + +### Windows +- Path handling with Windows-specific conventions +- Windows-specific CI/CD integration +- File system permissions for release artifacts +- Windows-specific deployment considerations + +### Linux +- POSIX-compliant path handling +- Linux-specific CI/CD integration +- Package manager integration for deployment +- System service management for release processes + +### macOS +- Darwin-specific path handling +- macOS application integration for release tools +- Homebrew and MacPorts package management +- System preferences and security frameworks for release processes + +## Usage Examples + +```bash +# Initialize release management +specsmith skill install release + +# Create a new release +specsmith release create --version 1.2.3 --platform github --notes "Release notes here" + +# Deploy to PyPI +specsmith release deploy --platform pypi --package mypackage + +# Manage CI workflows +specsmith release ci manage --workflow build-and-test --status enabled + +# Create pull request +specsmith release pr create --source feature-branch --target main --title "Release 1.2.3" + +# Generate release notes +specsmith release notes generate --from v1.2.0 --to v1.2.3 + +# Manage release artifacts +specsmith release artifacts upload --file dist/my-package-1.2.3.tar.gz +specsmith release artifacts download --file my-package-1.2.3.tar.gz + +# Promote release between environments +specsmith release promote --from staging --to production +``` + +## Configuration + +The skill requires the following configuration in `scaffold.yml`: + +```yaml +release: + default_platform: github + platforms: + github: + token_file: ~/.github_token + api_endpoint: https://api.github.com + pypi: + username_file: ~/.pypi_username + password_file: ~/.pypi_password + ci: + provider: github-actions + workflow_file: .github/workflows/release.yml + auto_approve: false + platform: auto # windows, linux, mac, or auto +``` + +## Security Considerations + +- All release operations require human approval +- Platform-specific security policies must be enforced +- Artifact storage and management must be secure +- Deployment credentials must be properly handled +- Cross-platform compatibility must not compromise security + +## Compliance Requirements + +- Follow security best practices for release management +- Maintain audit logs of all release operations +- Ensure proper platform-specific configuration management +- Enforce approval-based release setup +- Support for platform-specific compliance requirements diff --git a/.agents/skills/skill-composer/SKILL.md b/.agents/skills/skill-composer/SKILL.md new file mode 100644 index 00000000..047cd752 --- /dev/null +++ b/.agents/skills/skill-composer/SKILL.md @@ -0,0 +1,70 @@ +# SKILL.md +# Skill Composer + +## Requirements Covered + +### Governance Requirements +- REQ-012: Least-Privilege Agent Permissions +- REQ-217: Agent Permissions Check +- REQ-220: Policy Guardrails +- REQ-244: Context Window Sizing +- REQ-245: Live Context Fill Indicator +- REQ-246: Auto Context Compression +- REQ-247: Hard Context Ceiling + +## Core Principle +The skill-composer skill enables agents to dynamically compose and manage their skill sets based on the current task, project context, and governance requirements. It ensures that agents only load the necessary skills for their current operation while maintaining compliance with Specsmith's governance framework. + +## Skill Composition Rules + +### 1. Context-Aware Skill Loading +- Load only skills relevant to the current task +- Dynamically adjust skill set based on project requirements +- Ensure all loaded skills are properly validated and authorized + +### 2. Governance Compliance +- All skill compositions must pass preflight checks +- Skills must be from the approved skill catalog +- Any skill composition must be traceable to a work item or requirement + +### 3. Performance Optimization +- Minimize memory footprint by loading only necessary skills +- Optimize skill loading order for maximum efficiency +- Cache skill compositions when appropriate + +## Implementation Details + +### Skill Selection Algorithm +1. Analyze the current task requirements +2. Identify required capabilities from the project's governance rules +3. Select appropriate skills from the available catalog +4. Validate that all selected skills are compliant with current governance +5. Compose the final skill set for execution + +### Skill Validation +- Verify that each skill meets its documented requirements +- Ensure skills are compatible with the current project context +- Confirm that skill combinations don't violate governance constraints + +## Configuration + +### Default Behavior +By default, the skill-composer will: +- Load core governance skills (preflight-gate, governed-agent-loop) +- Select task-specific skills based on the current operation +- Apply context-aware optimization + +### Override Options +- Allow manual skill composition for advanced users +- Support skill exclusion for specific scenarios +- Enable temporary skill overrides with proper preflight + +## Security Considerations +- All skill compositions must be validated before execution +- Unauthorized skill combinations are blocked +- Skill composition history is tracked for audit purposes + +## Compliance Requirements +- Every skill composition must be traceable to a valid work item +- Skill compositions must be reviewed by the preflight-gate +- All skill combinations must comply with the project's permission model diff --git a/.agents/skills/specsmith-audit/SKILL.md b/.agents/skills/specsmith-audit/SKILL.md deleted file mode 100644 index 009ac5d9..00000000 --- a/.agents/skills/specsmith-audit/SKILL.md +++ /dev/null @@ -1,61 +0,0 @@ ---- -name: specsmith-audit -description: Run specsmith audit to check for governance drift between requirements, tests, and architecture. Required before advancing an AEE phase. ---- - -# Specsmith Audit - -Checks the project for drift between requirements (ARCHITECTURE.md), test cases, -and the codebase. Must pass before advancing an AEE phase. - -## How to run - -```bash -specsmith audit -``` - -## Interpreting results - -``` -29 PASS ← all requirements have matching tests and implementation - 2 WARN ← drift detected — investigate these - 0 FAIL -``` - -**All items must be PASS or suppressed before `specsmith phase advance`.** - -## When a WARN appears - -1. Read the warning — it references a requirement ID (e.g. `R20`) and describes what's missing -2. Fix it: add the missing test, update ARCHITECTURE.md, or implement the requirement -3. Re-run `specsmith audit` to confirm it passes -4. If it's a confirmed false positive: `specsmith audit --suppress ` - -## Suppressing a false positive - -Only suppress if you've verified the requirement IS met but the audit can't detect it: - -```bash -specsmith audit --suppress SEAL-XXXX-001 -``` - -Suppressions are permanent — use sparingly. - -## Common causes of WARN - -- Requirement in ARCHITECTURE.md has no corresponding test case -- Test exists but requirement ID reference is missing from the test -- Implementation exists but the architecture doc wasn't updated to match - -## After fixing all warnings - -```bash -specsmith audit # confirm all pass -specsmith phase advance # advance the phase -specsmith save # commit the phase bump -``` - -## Quick audit before a session - -Run `specsmith audit` at the start of a session to catch drift from the previous -session before making new changes. diff --git a/.agents/skills/specsmith-error-reporting/SKILL.md b/.agents/skills/specsmith-error-reporting/SKILL.md deleted file mode 100644 index 76d5253a..00000000 --- a/.agents/skills/specsmith-error-reporting/SKILL.md +++ /dev/null @@ -1,172 +0,0 @@ -# Specsmith Error Reporting & Issue Triage Skill - -Before asking a user to file any GitHub issue for specsmith, you MUST follow -this triage protocol. It prevents duplicate issues, surfaces already-fixed -bugs, and ensures every ticket adds value. - -## When to use this skill - -Trigger this skill when ANY of these occur: -- A user encounters a bug or unexpected behavior in specsmith. -- A user asks for a feature, process, tool, language, or regulation that - specsmith does not currently support. -- You are about to suggest "you should open a GitHub issue." -- A user mentions a limitation and seems frustrated. - -## Triage protocol (always run in order) - -### Step 1 — Confirm the specsmith version - -```bash -specsmith --version -``` - -Note the version. You will need it to check whether the issue is already fixed -in a newer release the user hasn't installed yet. - -### Step 2 — Search open issues - -Use the GitHub MCP (`search_issues` tool) or the `gh` CLI: - -```bash -gh issue list --repo layer1labs/specsmith --state open \ - --search "" --json number,title,labels,url -``` - -- Search with 2–3 relevant keywords. Try synonyms. -- If you find a match: **do not file a duplicate.** - - Show the user the existing issue URL. - - Suggest they add a 👍 reaction (upvote) to signal priority: - ```bash - gh api repos/layer1labs/specsmith/issues//reactions \ - -X POST -f content="+1" - ``` - - Suggest they subscribe to the issue for updates. - - If their case differs meaningfully, suggest adding a comment with their - specific context/version/OS. - -### Step 3 — Search closed issues - -```bash -gh issue list --repo layer1labs/specsmith --state closed \ - --search "" --json number,title,state,closedAt,url,labels -``` - -For each closed issue found, determine its resolution: - -| Label / Title pattern | Interpretation | -|---|---| -| `fixed`, `resolved`, closed with a PR | Bug was fixed | -| `wontfix`, `out-of-scope` | Intentional; don't re-open | -| `duplicate` | Points to another issue | -| No label, closed without PR | May have been abandoned | - -#### If closed as fixed - -```bash -# Check which version the fix landed in -gh pr list --repo layer1labs/specsmith --state merged \ - --search "fixes #" --json number,title,mergedAt,headRefName -``` - -Compare fix version to user's current version (`specsmith --version`): -- **Fix is in a released version the user has** → the user may have a - regression or a different root cause. Guide them to re-open or file new. -- **Fix is released but user has older version** → tell them to upgrade: - ```bash - pipx upgrade specsmith - ``` -- **Fix is merged but not yet released** → tell the user it's fixed in - `develop` / upcoming release. Show the PR/commit. Suggest they watch the - release or install from source if urgent. - -### Step 4 — Feature gap triage - -For missing features (project types, languages, tools, regulations, integrations): - -```bash -gh issue list --repo layer1labs/specsmith --state open \ - --label "enhancement" --search "" \ - --json number,title,url,reactions -``` - -- Found: upvote (see Step 2) and notify the user. -- Not found: guide structured filing (Step 5). - -Also check if the feature has a planned requirement in the roadmap: - -```bash -gh issue list --repo layer1labs/specsmith --state open \ - --label "roadmap" --json number,title,url -``` - -### Step 5 — File a new issue (only if no match found) - -Guide the user through this template: - -``` -**Describe the bug / feature request** -A clear, one-sentence summary. - -**To reproduce** (bugs only) -1. Command run / action taken -2. Expected behavior -3. Actual behavior - -**Environment** -- specsmith version: `specsmith --version` -- OS / shell: (e.g. Windows 11 / pwsh 7.5, Ubuntu 24.04 / bash) -- Install method: pipx / pip / source -- ESDB backend: `specsmith esdb status --json | jq .backend` - -**Regulation / tool / language** (feature requests) -Name the specific regulation, programming language, tool, or project type. -Note any official documentation or standard reference. - -**Why this matters** -One sentence on the use case or compliance need. -``` - -```bash -gh issue create --repo layer1labs/specsmith \ - --title "" \ - --label "bug" # or "enhancement", "compliance", "new-regulation" -``` - -**Label guide:** - -| Label | Use for | -|---|---| -| `bug` | Something broken or wrong | -| `enhancement` | New feature or improvement | -| `compliance` | Missing/outdated regulation coverage | -| `new-regulation` | Request for a new regulation | -| `new-project-type` | New scaffold/project type | -| `new-tool` | New tool or language support | -| `documentation` | Docs gap | - -## Priority signals - -Use reactions on issues to communicate priority automatically: -- 👍 (+1) — want this -- 🎉 (hooray) — blocking me -- 👀 (eyes) — watching - -Issues with the most 👍 reactions surface in the specsmith maintainer triage -board as high-priority candidates for the next sprint. - -## Compliance-specific issues - -When filing a compliance-related issue (missing regulation, outdated article, -wrong status), include: -- Official regulation ID and article number -- Effective date of the relevant provision -- Link to the official legal text -- Whether specsmith currently maps any control to it - -Label with both `compliance` and `new-regulation` (if truly new). - -> **Reminder:** specsmith compliance features are best-effort only. They do -> NOT guarantee legal compliance. Users are responsible for verifying actual -> compliance with qualified counsel. Filing a ticket is the correct path for -> outdated or missing coverage. diff --git a/.agents/skills/specsmith-mcp-configs/SKILL.md b/.agents/skills/specsmith-mcp-configs/SKILL.md deleted file mode 100644 index 3dccc606..00000000 --- a/.agents/skills/specsmith-mcp-configs/SKILL.md +++ /dev/null @@ -1,381 +0,0 @@ -# Specsmith MCP Server Config Library - -A curated, tested repository of MCP server configurations for use in -`.specsmith/mcp.yml`. All entries are sourced from the official -`modelcontextprotocol/servers` GitHub repo, Anthropic, or widely-used -community servers with verified working configurations. - -## How to use - -Copy any server block below into your `.specsmith/mcp.yml`: - -```yaml -# .specsmith/mcp.yml -servers: - - name: filesystem - command: npx - args: ["-y", "@modelcontextprotocol/server-filesystem", "/home/user/projects"] - env: {} -``` - -Then start the specsmith agent REPL — MCP servers are auto-connected: -```bash -specsmith run -``` - -To generate a starter config stub: -```bash -specsmith mcp install-warp # Warp MCP JSON snippet -``` - ---- - -## Official MCP Servers (modelcontextprotocol/servers) - -All require Node.js 18+ and are run via `npx -y`. - -### Filesystem — read/write local files -```yaml -- name: filesystem - command: npx - args: ["-y", "@modelcontextprotocol/server-filesystem", "/path/to/allowed/dir"] - env: {} -``` -Allows agents to read, write, list, and search files within the specified -directory. Pass multiple directories as additional args. - -### GitHub — issues, PRs, code search -```yaml -- name: github - command: npx - args: ["-y", "@modelcontextprotocol/server-github"] - env: - GITHUB_PERSONAL_ACCESS_TOKEN: "${GITHUB_TOKEN}" -``` -Set `GITHUB_TOKEN` in your environment. Scopes needed: `repo`, `read:org`. - -### Brave Search — web search -```yaml -- name: brave-search - command: npx - args: ["-y", "@modelcontextprotocol/server-brave-search"] - env: - BRAVE_API_KEY: "${BRAVE_API_KEY}" -``` -Get a free API key at https://api.search.brave.com - -### PostgreSQL — query a Postgres database -```yaml -- name: postgres - command: npx - args: - - "-y" - - "@modelcontextprotocol/server-postgres" - - "postgresql://user:password@localhost:5432/dbname" - env: {} -``` -Replace the connection string with your database URL. - -### SQLite — query a local SQLite database -```yaml -- name: sqlite - command: npx - args: ["-y", "@modelcontextprotocol/server-sqlite", "--db-path", "/path/to/db.sqlite"] - env: {} -``` - -### Fetch — retrieve web pages / REST APIs -```yaml -- name: fetch - command: npx - args: ["-y", "@modelcontextprotocol/server-fetch"] - env: {} -``` -Fetches URLs and returns content as text or markdown. Useful for reading -documentation, REST API responses, and public web pages. - -### Memory — persistent in-session key-value store -```yaml -- name: memory - command: npx - args: ["-y", "@modelcontextprotocol/server-memory"] - env: {} -``` -Stores and retrieves facts within a session. Persisted to a local JSON file. - -### Puppeteer — headless browser automation -```yaml -- name: puppeteer - command: npx - args: ["-y", "@modelcontextprotocol/server-puppeteer"] - env: {} -``` -Full browser control: navigate, click, screenshot, extract content. -Requires Chromium (installed automatically by puppeteer on first run). - -### Sequential Thinking — structured reasoning tool -```yaml -- name: sequential-thinking - command: npx - args: ["-y", "@modelcontextprotocol/server-sequential-thinking"] - env: {} -``` -Provides a `sequential_thinking` tool that helps agents reason step-by-step -through complex problems before acting. - -### Slack — post messages and read channels -```yaml -- name: slack - command: npx - args: ["-y", "@modelcontextprotocol/server-slack"] - env: - SLACK_BOT_TOKEN: "${SLACK_BOT_TOKEN}" - SLACK_TEAM_ID: "${SLACK_TEAM_ID}" -``` -Create a Slack app with `chat:write`, `channels:read`, `channels:history` scopes. - -### Google Drive — read and search Drive files -```yaml -- name: google-drive - command: npx - args: ["-y", "@modelcontextprotocol/server-googledrive"] - env: - GDRIVE_CLIENT_ID: "${GDRIVE_CLIENT_ID}" - GDRIVE_CLIENT_SECRET: "${GDRIVE_CLIENT_SECRET}" - GDRIVE_REDIRECT_URI: "http://localhost:3000/oauth2callback" -``` - -### Everything — test/example server with all tool types -```yaml -- name: everything - command: npx - args: ["-y", "@modelcontextprotocol/server-everything"] - env: {} -``` -Reference implementation with prompts, resources, and tools. Useful for -testing MCP client integrations. - ---- - -## Python MCP Servers (uvx / python -m) - -### Git — git operations -```yaml -- name: git - command: uvx - args: ["mcp-server-git", "--repository", "/path/to/repo"] - env: {} -``` -Or without uvx: -```yaml -- name: git - command: python - args: ["-m", "mcp_server_git", "--repository", "/path/to/repo"] - env: {} -``` -Install: `pip install mcp-server-git` - -### Time — current time and timezone conversions -```yaml -- name: time - command: uvx - args: ["mcp-server-time", "--local-timezone", "America/New_York"] - env: {} -``` -Install: `pip install mcp-server-time` - ---- - -## specsmith Governance MCP Server - -The specsmith governance server ships built-in — no install required. - -### specsmith governance -```yaml -- name: specsmith-governance - command: specsmith - args: ["mcp", "serve", "--project-dir", "."] - env: {} -``` -Exposes: `governance_audit`, `governance_checkpoint`, `governance_preflight`, -`governance_phase`, `governance_req_list`, `governance_trace_seal`. - -Get the Warp-ready JSON snippet: -```bash -specsmith mcp install-warp -``` - ---- - -## Community / Third-party Servers - -These are widely used with verified working configs. Require their own install. - -### Exa — semantic web search -```yaml -- name: exa - command: npx - args: ["-y", "exa-mcp-server"] - env: - EXA_API_KEY: "${EXA_API_KEY}" -``` -Get an API key at https://exa.ai — has a generous free tier. - -### Tavily — AI-optimized web search -```yaml -- name: tavily - command: npx - args: ["-y", "tavily-mcp"] - env: - TAVILY_API_KEY: "${TAVILY_API_KEY}" -``` -Get an API key at https://tavily.com - -### Linear — issue tracking -```yaml -- name: linear - command: npx - args: ["-y", "@linear/mcp-server"] - env: - LINEAR_API_KEY: "${LINEAR_API_KEY}" -``` - -### Sentry — error monitoring -```yaml -- name: sentry - command: uvx - args: ["mcp-server-sentry"] - env: - SENTRY_AUTH_TOKEN: "${SENTRY_AUTH_TOKEN}" - SENTRY_ORG_SLUG: "${SENTRY_ORG}" -``` - -### Playwright — browser automation (alternative to Puppeteer) -```yaml -- name: playwright - command: npx - args: ["-y", "@playwright/mcp"] - env: {} -``` -Requires `npx playwright install chromium` on first use. - -### Redis — cache and key-value operations -```yaml -- name: redis - command: npx - args: ["-y", "mcp-server-redis"] - env: - REDIS_URL: "redis://localhost:6379" -``` - -### Notion — read and write Notion pages -```yaml -- name: notion - command: npx - args: ["-y", "@suesukim/mcp-server-notion"] - env: - NOTION_API_TOKEN: "${NOTION_TOKEN}" -``` -Create an integration at https://www.notion.so/my-integrations - ---- - -## Multi-server starter template - -A ready-to-use `.specsmith/mcp.yml` for a typical full-stack development setup: - -```yaml -# .specsmith/mcp.yml — full-stack dev starter -servers: - - name: specsmith-governance - command: specsmith - args: ["mcp", "serve", "--project-dir", "."] - env: {} - - - name: filesystem - command: npx - args: ["-y", "@modelcontextprotocol/server-filesystem", "."] - env: {} - - - name: github - command: npx - args: ["-y", "@modelcontextprotocol/server-github"] - env: - GITHUB_PERSONAL_ACCESS_TOKEN: "${GITHUB_TOKEN}" - - - name: fetch - command: npx - args: ["-y", "@modelcontextprotocol/server-fetch"] - env: {} - - - name: memory - command: npx - args: ["-y", "@modelcontextprotocol/server-memory"] - env: {} - - - name: sequential-thinking - command: npx - args: ["-y", "@modelcontextprotocol/server-sequential-thinking"] - env: {} - - - name: brave-search - command: npx - args: ["-y", "@modelcontextprotocol/server-brave-search"] - env: - BRAVE_API_KEY: "${BRAVE_API_KEY}" -``` - -## Database development template - -```yaml -servers: - - name: specsmith-governance - command: specsmith - args: ["mcp", "serve", "--project-dir", "."] - env: {} - - - name: postgres - command: npx - args: ["-y", "@modelcontextprotocol/server-postgres", "${DATABASE_URL}"] - env: {} - - - name: sqlite - command: npx - args: ["-y", "@modelcontextprotocol/server-sqlite", "--db-path", "./dev.db"] - env: {} - - - name: redis - command: npx - args: ["-y", "mcp-server-redis"] - env: - REDIS_URL: "redis://localhost:6379" - - - name: filesystem - command: npx - args: ["-y", "@modelcontextprotocol/server-filesystem", "."] - env: {} -``` - ---- - -## Troubleshooting - -**Server fails to start:** -```bash -specsmith esdb status # check project health -npx -y @modelcontextprotocol/server- --help # test manually -``` - -**Authentication errors:** Confirm env vars are exported in your shell: -```bash -echo $GITHUB_TOKEN # should print your token -``` - -**Windows path issues with filesystem server:** Use forward slashes or -double-backslash in args: -```yaml -args: ["-y", "@modelcontextprotocol/server-filesystem", "C:/Users/user/projects"] -``` - -**Missing feature or broken config?** Follow the `specsmith-error-reporting` -skill to check if it's a known issue before filing a new ticket. diff --git a/.agents/skills/specsmith-save/SKILL.md b/.agents/skills/specsmith-save/SKILL.md deleted file mode 100644 index 89fa41f0..00000000 --- a/.agents/skills/specsmith-save/SKILL.md +++ /dev/null @@ -1,53 +0,0 @@ ---- -name: specsmith-save -description: Run specsmith save to commit and push all current changes with governance state backup. Use at the end of any work session or after completing a feature/fix. ---- - -# Specsmith Save - -Saves governance state: backs up the ESDB, commits any staged/unstaged changes, -and pushes to the remote. - -## When to use - -- At the end of any work session -- After implementing a feature, fix, or refactor -- After advancing a phase -- Whenever the user says "save", "commit and push", or "specsmith save" - -## How to run - -```bash -specsmith save -``` - -## What it does (in order) - -1. **ESDB backup** — snapshots the epistemic state database -2. **Commit** — stages all changes and commits with a governance-aware message (or reports "Nothing to commit") -3. **Push** — pushes the branch to origin (or reports "Everything up-to-date") - -## Expected successful output - -``` - ✓ esdb_backup: JSON fallback (no WAL to backup) - ✓ commit: Nothing to commit ← or a commit hash - ✓ push: Everything up-to-date ← or "pushed to origin/branch" -``` - -## If there are changes to commit - -Specsmith auto-stages and commits. You can also pre-stage manually: - -```bash -git add -A -git commit -m "feat: description - -Co-Authored-By: Oz " -specsmith save # will see nothing to commit, just pushes -``` - -## Do NOT use `git push` directly - -Always use `specsmith save` — it ensures the ESDB backup runs before the push, -keeping governance state consistent with the remote. diff --git a/.agents/skills/specsmith-session-governance/SKILL.md b/.agents/skills/specsmith-session-governance/SKILL.md deleted file mode 100644 index 89a7800e..00000000 --- a/.agents/skills/specsmith-session-governance/SKILL.md +++ /dev/null @@ -1,126 +0,0 @@ -# Specsmith Session Governance Skill - -This skill describes the **mandatory session protocol** for any agent working -in a specsmith-governed project. It prevents silent drift, governs MCP tool -use, and keeps governance state alive across context summarization. - -## Why agents drift -When a conversation gets long, any chat application (Warp, Cursor, Claude, -GPT) summarizes the history. That summary discards: the current work item ID, -the last preflight decision, the project phase, and any uncommitted changes. -The agent then operates on stale or invented governance state. - -## The fix: four rules - -### Rule 1 — Initialization (every session start) -```bash -specsmith kill-session 2>/dev/null || true -specsmith audit --project-dir . -specsmith sync --project-dir . -specsmith checkpoint --project-dir . -``` -Output the checkpoint verbatim as your first response. This establishes the -governance baseline that all subsequent work traces back to. - -### Rule 2 — Preflight gate (before EVERY proposed code change) -```bash -specsmith preflight "" --json -``` -- `decision == "accepted"` → proceed, note the `work_item_id`. -- `decision == "needs_clarification"` → surface the `instruction` to the user first. -- **Never make a code change without an accepted preflight.** - -### Rule 3 — MCP tool governance - -When using the specsmith MCP server (`specsmith-governance` MCP) alongside -other MCP tools, apply the same preflight discipline: - -``` -governance_preflight(intent=" 60%) -```bash -specsmith checkpoint --project-dir . -``` -Output the GOVERNANCE ANCHOR block verbatim in your response: - -``` -⎠ GOVERNANCE ANCHOR: -╔═════════════════════════════════════════════════════════╗ -║ GOVERNANCE ANCHOR ║ -║ Project : ║ -║ Phase : (%) ║ -║ Health : ✓ clean ║ -║ REQs : N TESTs: N ESDB: N records (✓ chain) ║ -║ WIs : WI-XXXXXXXX, ... ║ -╚═════════════════════════════════════════════════════════╝ -``` - -**When producing any context summary, ALWAYS include the most recent -GOVERNANCE ANCHOR verbatim at the top.** The anchor is the minimum viable -governance state that must survive summarization. - -## Compliance disclaimer in governed sessions - -If a user asks you to assess regulatory or compliance status, always add: - -> **Note:** specsmith compliance checks are best-effort only and do NOT -> constitute legal advice or a guarantee of compliance. Verify with -> qualified counsel. Report gaps at https://github.com/layer1labs/specsmith/issues - -## Error and issue reporting protocol - -If a user encounters a bug, unexpected behavior, or missing feature: -1. **Do not** ask them to file a ticket immediately. -2. Run `specsmith --version` to confirm current version. -3. Check GitHub issues first (use the `specsmith-error-reporting` skill or - the GitHub MCP if available) to see if it’s known, fixed, or in-progress. -4. Only then guide structured ticket filing. - -## End of session -```bash -specsmith save --project-dir . # ESDB backup + commit + push -specsmith kill-session # clean up processes -``` -Never end a session with uncommitted governance changes. - -## Detecting drift (self-check) -If you cannot answer these from memory — you have drifted. Re-anchor immediately: -- What is the current AEE phase? -- What work item is active? -- What was the last preflight decision? -- Is the audit currently healthy? - -Run `specsmith checkpoint` and copy the output into your response. - -## Quick reference -| When | Command | -|---|---| -| Session start | `specsmith audit && specsmith sync && specsmith checkpoint` | -| Before any code change | `specsmith preflight "" --json` | -| Before any MCP tool call | `governance_preflight(intent=...)` via MCP | -| Every 8-10 turns | `specsmith checkpoint` (output verbatim) | -| Context summary | Include checkpoint output at top | -| Bug or feature gap spotted | Use `specsmith-error-reporting` skill | -| Session end | `specsmith save && specsmith kill-session` | -| Drift detected | `specsmith checkpoint` immediately | diff --git a/.agents/skills/specsmith/SKILL.md b/.agents/skills/specsmith/SKILL.md deleted file mode 100644 index 09442f29..00000000 --- a/.agents/skills/specsmith/SKILL.md +++ /dev/null @@ -1,163 +0,0 @@ ---- -name: specsmith -description: Master reference for the specsmith AEE governance tool — key concepts, common commands, session workflow, phase advancement, audit codes, work items, compliance disclaimers, and error-reporting protocol. Use whenever working in a specsmith-governed project. ---- - -# Specsmith — Project Governance Tool - -Specsmith is the AEE (Agile Epistemic Engineering) governance CLI. It manages -requirements, phases, audit trails, and session state. It wraps git with -governance-aware commits and backs up the epistemic state DB (ESDB). - -## Key concepts - -- **ESDB** — Epistemic State Database. Tracks certainty, audit state, session memory. Backed up on `specsmith save`. -- **Phases** — AEE lifecycle: Inception → Elaboration → Construction → Transition → Validation → Hardening → Release. -- **Ledger** — Running log of changes in `LEDGER.md`. Auto-updated by commits. -- **Audit** — Checks requirements vs tests vs architecture for drift. Required before phase advance. -- **Save** — ESDB backup + governance-aware git commit + push. -- **WI (Work Item)** — See section below. - -## Work Items (WIs) - -A **Work Item** (`WI-XXXXXXXX`) is an 8-hex-digit identifier minted by -`specsmith preflight` whenever it accepts a proposed change. - -```bash -specsmith preflight "add retry logic to the exporter" --json -# → { "decision": "accepted", "work_item_id": "WI-3A9F1C02", ... } -``` - -**How WIs fold into requirements and governance:** -- Each WI is logged in `LEDGER.md` alongside the preflight intent and any - matched `requirement_ids` / `test_case_ids`. -- `specsmith checkpoint` scans the ledger and surfaces the 3 most recent WIs - in the `WIs` row of the governance anchor box. -- This gives a traceable link: user intent → WI → requirement IDs → code change. -- If `requirement_ids` is empty in the preflight response, the change is not - yet linked to a tracked requirement; consider adding a requirement with - `specsmith req add`. -- WIs are **not** GitHub issues — they are governance-layer breadcrumbs. Use - the error-reporting skill to decide when a WI should also become a GH issue. - -## Compliance Disclaimer - -specsmith compliance checks (`specsmith compliance check`, `specsmith compliance -report`) are **best-effort only**. They do **NOT** constitute legal advice or a -guarantee of compliance with any law or regulation. Regulations change frequently; -the end user is solely responsible for determining and maintaining actual -compliance. Layer1Labs makes no warranty of fitness for regulatory submission. - -To report outdated regulation coverage or request new regulation support: -https://github.com/layer1labs/specsmith/issues - -## Session workflow - -``` -1. specsmith audit # check for drift before working -2. specsmith preflight "" # gate every proposed change -3. # only after accepted preflight -4. specsmith save # commit + push + ESDB backup -``` - -## Common commands - -| Command | What it does | -|---------|-------------| -| `specsmith save` | ESDB backup → commit (if needed) → push | -| `specsmith audit` | Drift/health check — requirements vs tests vs arch | -| `specsmith audit --suppress ` | Accept a known false positive | -| `specsmith preflight "" --json` | Gate a proposed change; get WI | -| `specsmith checkpoint` | Emit governance anchor (phase, health, WIs, ESDB) | -| `specsmith phase` | Show current AEE phase | -| `specsmith phase advance` | Advance to next phase (requires clean audit) | -| `specsmith commit` | Governance-aware commit (wraps git commit) | -| `specsmith ledger` | Show/manage the change ledger | -| `specsmith compress` | Compress old ledger entries | -| `specsmith req` | Manage requirements | -| `specsmith test` | Manage test cases | -| `specsmith status` | VCS/CI/PR status | -| `specsmith compliance check` | Best-effort AI regulation check (see disclaimer above) | -| `specsmith compliance report --format html` | Generate compliance report | -| `specsmith esdb status` | Show ESDB backend, record counts, chain integrity | -| `specsmith skill list` | List built-in installable skills | -| `specsmith skill install ` | Install a skill into `.agents/skills/` | - -## Commit conventions - -Specsmith commits follow: `type: message` where type is one of: -`feat`, `fix`, `refactor`, `test`, `docs`, `chore`, `perf` - -Always append `Co-Authored-By: Oz ` when committing as an AI agent. - -## GitHub Operations - -Use **`gh` CLI** (GitHub CLI) as the **first and preferred** tool for all GitHub operations: -issues, PRs, releases, code scanning alerts, and repository data. - -**MCP GitHub server is last resort only** — use it only when `gh` CLI genuinely cannot do the task. - -```bash -gh issue list --state open -gh pr create --title "feat: ..." --body "..." -gh api repos/{owner}/{repo}/code-scanning/alerts --jq '[.[] | select(.state=="open")]' -``` - -## Release Process - -Before tagging any release, **both** of these files MUST be updated in the same commit: - -1. **`CHANGELOG.md`** — add a dated section for the new version with a bullet-point summary of changes. -2. **`README.md`** — update the version highlight line near the top (search for the previous version number) to reflect the new version's headline features. - -PyPI and RTD deploys are **blocked** until: -- All CI passes (tests, ruff, mypy) -- Zero open High/Critical code scanning alerts (`gh api repos/{owner}/{repo}/code-scanning/alerts`) -- A human approves the release in the GitHub `release` environment gate - -Never tag a release from a branch other than `main`. - -## Important rules - -- **Never use `git commit` directly** — use `specsmith save` or `specsmith commit`. -- **Run `specsmith audit` before advancing a phase** — a phase advance with drift will fail. -- **Never make a code change without an accepted preflight** — `decision == "accepted"` required. -- **Suppressed audit findings** are stored permanently; only suppress genuine false positives. -- After `specsmith save` outputs `✓ push: Everything up-to-date`, the repo is fully clean. - -## Audit result codes - -- `PASS` — requirement/test/arch is consistent -- `WARN` — drift detected, investigate -- `SKIP` / suppressed — accepted false positive -- IDs like `R20`, `R21` — requirement IDs in ARCHITECTURE.md - -## Phase advancement - -```bash -specsmith audit # must be all-pass (or suppressed) -specsmith phase advance # bumps phase, writes ledger entry -specsmith save # commit the phase bump -``` - -## Proactive skill and feature gap detection - -If a user seems to be struggling with a workflow that specsmith could support -better, or asks about a process/tool/language specsmith doesn’t yet cover, -always: -1. Complete the immediate task as best you can. -2. Suggest that the user open a GitHub issue to request the missing feature, - process, project type, or regulation coverage: - https://github.com/layer1labs/specsmith/issues -3. Use the `specsmith-error-reporting` skill for structured issue triage before - filing — the issue may already exist (open or fixed in an upcoming release). - -## Installing skills in any project - -```bash -specsmith skill install specsmith # this reference card -specsmith skill install specsmith-save # save workflow -specsmith skill install specsmith-audit # audit workflow -specsmith skill install specsmith-error-reporting # issue triage protocol -specsmith skill install specsmith-mcp-configs # tested MCP server configs -``` diff --git a/.agents/skills/testing-artifact-management/SKILL.md b/.agents/skills/testing-artifact-management/SKILL.md new file mode 100644 index 00000000..0a7d1e6e --- /dev/null +++ b/.agents/skills/testing-artifact-management/SKILL.md @@ -0,0 +1,69 @@ +--- +name: testing-artifact-management +description: Skill for managing test artifacts including screenshots, videos, and logs with specsmith governance +--- + +# Testing Artifact Management + +This skill enables specsmith projects to manage test artifacts including screenshots, videos, and logs while maintaining governance compliance. + +## Requirements Covered + +- REQ-104: Testing Artifact Management +- Allows specsmith projects to manage test artifacts including screenshots, videos, and logs with human approval + +## Integration Capabilities + +### Artifact Features +- Screenshot capture and management +- Video recording and storage +- Log file handling and archiving +- Artifact metadata tracking +- Artifact retention policies +- Artifact sharing and access control + +### Governance Requirements +- Human approval required for artifact management +- Configuration management with governance controls +- Approval-based artifact retention +- Audit logging of artifact access + +## Usage Examples + +```bash +# Initialize artifact management +specsmith skill install testing-artifact-management + +# Configure artifact settings +specsmith test artifact configure --capture-screenshots on_failure --retention-days 30 + +# Manage test artifacts +specsmith test artifact manage --action archive --suite e2e-tests +``` + +## Configuration + +The skill requires the following configuration in `scaffold.yml`: + +```yaml +artifact_management: + capture_screenshots: "on_failure" + capture_videos: "never" + log_level: "info" + retention_days: 30 + storage_location: "/var/test-artifacts" +``` + +## Security Considerations + +- All artifact management requires human approval +- Sensitive data in artifacts must be handled securely +- Artifact access controls must be enforced +- Storage location security must be maintained + +## Compliance Requirements + +- Follow security best practices for artifact management +- Maintain audit logs of all artifact activities +- Ensure proper retention and deletion policies +- Enforce approval-based artifact access diff --git a/.agents/skills/testing-cicd-integration/SKILL.md b/.agents/skills/testing-cicd-integration/SKILL.md new file mode 100644 index 00000000..8556173e --- /dev/null +++ b/.agents/skills/testing-cicd-integration/SKILL.md @@ -0,0 +1,70 @@ +--- +name: testing-cicd-integration +description: Skill for integrating testing frameworks with CI/CD pipelines with specsmith governance +--- + +# Testing Integration with CI/CD + +This skill enables specsmith projects to integrate testing frameworks with CI/CD pipelines while maintaining governance compliance. + +## Requirements Covered + +- REQ-106: Testing Integration with CI/CD +- Allows specsmith projects to integrate testing frameworks with CI/CD pipelines with human approval + +## Integration Capabilities + +### CI/CD Features +- Pipeline integration for automated testing +- Test execution in CI environments +- Integration with popular CI platforms (GitHub Actions, GitLab CI, Jenkins) +- Test result reporting to CI systems +- Parallel test execution in CI environments +- Environment variable management for tests + +### Governance Requirements +- Human approval required for CI/CD integration +- Configuration management with governance controls +- Approval-based pipeline setup +- Audit logging of CI/CD activities + +## Usage Examples + +```bash +# Initialize CI/CD integration +specsmith skill install testing-cicd-integration + +# Configure CI/CD settings +specsmith test cicd configure --platform github-actions --test-parallel true + +# Set up CI pipeline +specsmith test cicd setup --pipeline e2e-tests --trigger on-push +``` + +## Configuration + +The skill requires the following configuration in `scaffold.yml`: + +```yaml +cicd: + platform: github-actions + test_parallel: true + test_timeout: 30000 + trigger_on: "on-push" + report_results: true + artifact_storage: "github-artifacts" +``` + +## Security Considerations + +- All CI/CD integrations require human approval +- Pipeline secrets must be properly secured +- Test environment access must be controlled +- Integration with CI systems must be secure + +## Compliance Requirements + +- Follow security best practices for CI/CD integrations +- Maintain audit logs of all CI/CD activities +- Ensure proper pipeline configuration and management +- Enforce approval-based CI/CD setup diff --git a/.agents/skills/testing-configuration/SKILL.md b/.agents/skills/testing-configuration/SKILL.md new file mode 100644 index 00000000..947e8d42 --- /dev/null +++ b/.agents/skills/testing-configuration/SKILL.md @@ -0,0 +1,69 @@ +--- +name: testing-configuration +description: Skill for configuring testing frameworks including Playwright, pytest, and others with specsmith governance +--- + +# Testing Framework Configuration + +This skill enables specsmith projects to configure testing frameworks including Playwright, pytest, and others while maintaining governance compliance. + +## Requirements Covered + +- REQ-102: Testing Framework Configuration +- Allows specsmith projects to configure testing frameworks including Playwright, pytest, and others with human approval + +## Integration Capabilities + +### Framework Features +- Configuration management for multiple testing frameworks +- Test suite organization and grouping +- Environment-specific configuration +- Integration with CI/CD pipelines +- Test runner customization +- Plugin and extension management + +### Governance Requirements +- Human approval required for all testing framework configurations +- Configuration version control with governance +- Approval-based framework selection +- Environment isolation enforcement + +## Usage Examples + +```bash +# Initialize testing configuration +specsmith skill install testing-configuration + +# Configure testing frameworks +specsmith test configure --framework pytest --env test --timeout 60000 + +# Set up test suite configuration +specsmith test setup --suite e2e --framework playwright --browser chromium +``` + +## Configuration + +The skill requires the following configuration in `scaffold.yml`: + +```yaml +testing: + framework: pytest + environment: test + timeout: 60000 + parallel: false + coverage: true +``` + +## Security Considerations + +- All testing framework configurations require human approval +- Configuration files must be properly secured +- Environment-specific settings must be isolated +- Framework selection must be governed + +## Compliance Requirements + +- Follow security best practices for testing configurations +- Maintain audit logs of all configuration changes +- Ensure proper version control of configuration files +- Enforce approval-based framework selection diff --git a/.agents/skills/testing-coverage-reporting/SKILL.md b/.agents/skills/testing-coverage-reporting/SKILL.md new file mode 100644 index 00000000..2661474c --- /dev/null +++ b/.agents/skills/testing-coverage-reporting/SKILL.md @@ -0,0 +1,70 @@ +--- +name: testing-coverage-reporting +description: Skill for generating and tracking test coverage reports with specsmith governance +--- + +# Testing Coverage Reporting + +This skill enables specsmith projects to generate and track test coverage reports while maintaining governance compliance. + +## Requirements Covered + +- REQ-108: Testing Coverage Reporting +- Allows specsmith projects to generate and track test coverage reports with human approval + +## Integration Capabilities + +### Coverage Features +- Code coverage measurement and reporting +- Coverage threshold enforcement +- Coverage trend analysis +- Coverage report generation in multiple formats +- Integration with coverage tools (pytest-cov, Istanbul, etc.) +- Coverage data storage and retrieval + +### Governance Requirements +- Human approval required for coverage reporting +- Configuration management with governance controls +- Approval-based coverage thresholds +- Audit logging of coverage activities + +## Usage Examples + +```bash +# Initialize coverage reporting +specsmith skill install testing-coverage-reporting + +# Configure coverage settings +specsmith test coverage configure --threshold 80 --format html + +# Generate coverage report +specsmith test coverage generate --suite e2e-tests --format html +``` + +## Configuration + +The skill requires the following configuration in `scaffold.yml`: + +```yaml +coverage: + threshold: 80 + format: "html" + include_uncovered: false + generate_on_success: true + generate_on_failure: true + retention_days: 30 +``` + +## Security Considerations + +- All coverage reporting requires human approval +- Coverage data must be properly secured +- Access controls for coverage reports must be enforced +- Sensitive code paths must be handled appropriately + +## Compliance Requirements + +- Follow security best practices for coverage reporting +- Maintain audit logs of all coverage activities +- Ensure proper retention and deletion policies +- Enforce approval-based coverage reporting settings diff --git a/.agents/skills/testing-environment-isolation/SKILL.md b/.agents/skills/testing-environment-isolation/SKILL.md new file mode 100644 index 00000000..3c574ad0 --- /dev/null +++ b/.agents/skills/testing-environment-isolation/SKILL.md @@ -0,0 +1,69 @@ +--- +name: testing-environment-isolation +description: Skill for ensuring testing environments are properly isolated from development environments with specsmith governance +--- + +# Testing Environment Isolation + +This skill ensures that testing environments are properly isolated from development environments while maintaining governance compliance. + +## Requirements Covered + +- REQ-103: Testing Environment Isolation +- Ensures testing environments are properly isolated from development environments with human approval + +## Integration Capabilities + +### Environment Features +- Environment isolation enforcement +- Test environment setup and management +- Resource allocation separation +- Data isolation between environments +- Configuration management for test environments +- Clean environment reset capabilities + +### Governance Requirements +- Human approval required for environment isolation setup +- Configuration management with governance controls +- Approval-based environment creation +- Monitoring and logging of environment usage + +## Usage Examples + +```bash +# Initialize environment isolation +specsmith skill install testing-environment-isolation + +# Create isolated test environment +specsmith test isolate --env test --isolation-level full + +# Configure environment isolation +specsmith test configure-isolation --env test --network-isolation true --data-isolation true +``` + +## Configuration + +The skill requires the following configuration in `scaffold.yml`: + +```yaml +isolation: + environment: test + network_isolation: true + data_isolation: true + resource_allocation: "dedicated" + cleanup_on_exit: true +``` + +## Security Considerations + +- All environment isolation configurations require human approval +- Network isolation must be properly enforced +- Data access controls must be maintained +- Resource allocation must be monitored + +## Compliance Requirements + +- Follow security best practices for environment isolation +- Maintain audit logs of all environment isolation activities +- Ensure proper resource management and cleanup +- Enforce approval-based environment creation diff --git a/.agents/skills/testing-parallel-execution/SKILL.md b/.agents/skills/testing-parallel-execution/SKILL.md new file mode 100644 index 00000000..510908fd --- /dev/null +++ b/.agents/skills/testing-parallel-execution/SKILL.md @@ -0,0 +1,69 @@ +--- +name: testing-parallel-execution +description: Skill for executing tests in parallel with specsmith governance +--- + +# Testing Parallel Execution + +This skill enables specsmith projects to execute tests in parallel while maintaining governance compliance. + +## Requirements Covered + +- REQ-107: Testing Parallel Execution +- Allows specsmith projects to execute tests in parallel with human approval + +## Integration Capabilities + +### Parallel Execution Features +- Parallel test execution management +- Resource allocation for parallel tests +- Test dependency management +- Load balancing across test runners +- Parallel test result aggregation +- Performance monitoring during parallel execution + +### Governance Requirements +- Human approval required for parallel execution +- Configuration management with governance controls +- Approval-based parallelism settings +- Audit logging of parallel execution activities + +## Usage Examples + +```bash +# Initialize parallel execution +specsmith skill install testing-parallel-execution + +# Configure parallel execution +specsmith test parallel configure --max-workers 4 --timeout 60000 + +# Run tests in parallel +specsmith test parallel run --suite e2e-tests --workers 4 +``` + +## Configuration + +The skill requires the following configuration in `scaffold.yml`: + +```yaml +parallel_execution: + max_workers: 4 + timeout: 60000 + worker_pool_size: 2 + test_isolation: true + result_aggregation: true +``` + +## Security Considerations + +- All parallel execution requires human approval +- Resource allocation must be monitored +- Test isolation must be maintained +- Parallel execution must not impact system stability + +## Compliance Requirements + +- Follow security best practices for parallel execution +- Maintain audit logs of all parallel execution activities +- Ensure proper resource management and monitoring +- Enforce approval-based parallel execution settings diff --git a/.agents/skills/testing-report-generation/SKILL.md b/.agents/skills/testing-report-generation/SKILL.md new file mode 100644 index 00000000..3ccc6fe8 --- /dev/null +++ b/.agents/skills/testing-report-generation/SKILL.md @@ -0,0 +1,70 @@ +--- +name: testing-report-generation +description: Skill for automatically generating test reports with specsmith governance +--- + +# Testing Report Generation + +This skill enables specsmith projects to automatically generate test reports while maintaining governance compliance. + +## Requirements Covered + +- REQ-105: Testing Report Generation +- Allows specsmith projects to automatically generate test reports with human approval + +## Integration Capabilities + +### Report Features +- Automated test report generation +- Multiple report formats (HTML, JSON, XML) +- Coverage reporting and analytics +- Test summary and detailed results +- Historical report comparison +- Integration with CI/CD pipelines + +### Governance Requirements +- Human approval required for report generation +- Configuration management with governance controls +- Approval-based report formats +- Audit logging of report generation activities + +## Usage Examples + +```bash +# Initialize report generation +specsmith skill install testing-report-generation + +# Generate test report +specsmith test report generate --format html --suite e2e-tests + +# Configure report settings +specsmith test report configure --format html --include-coverage true --retention-days 60 +``` + +## Configuration + +The skill requires the following configuration in `scaffold.yml`: + +```yaml +reporting: + format: "html" + include_coverage: true + include_screenshots: false + retention_days: 60 + generate_on_success: true + generate_on_failure: true +``` + +## Security Considerations + +- All report generation requires human approval +- Report content must be properly secured +- Access controls for reports must be enforced +- Sensitive data in reports must be handled appropriately + +## Compliance Requirements + +- Follow security best practices for report generation +- Maintain audit logs of all report generation activities +- Ensure proper retention and deletion policies +- Enforce approval-based report generation diff --git a/.agents/skills/vllm-integration/SKILL.md b/.agents/skills/vllm-integration/SKILL.md new file mode 100644 index 00000000..78ca2c53 --- /dev/null +++ b/.agents/skills/vllm-integration/SKILL.md @@ -0,0 +1,67 @@ +--- +name: vllm-integration +description: Skill for integrating with VLLM for large language model serving with specsmith governance +--- + +# VLLM Platform Integration + +This skill enables specsmith projects to integrate with VLLM for large language model serving while maintaining governance compliance. + +## Requirements Covered + +- REQ-110: VLLM Platform Integration +- Allows specsmith projects to integrate with VLLM for large language model serving with human approval + +## Integration Capabilities + +### Platform Features +- VLLM model serving and deployment +- GPU and CPU resource management +- Model optimization and quantization +- API endpoint configuration for VLLM services +- Performance monitoring and tuning + +### Governance Requirements +- Human approval required for all VLLM integrations +- Configuration management with governance controls +- Security best practices enforcement +- Resource monitoring and logging + +## Usage Examples + +```bash +# Initialize VLLM integration +specsmith skill install vllm-integration + +# Configure VLLM platform settings +specsmith vllm configure --platform vllm --model-path /path/to/model --gpu-count 2 + +# Deploy model via VLLM +specsmith vllm deploy --model my-model --port 8000 +``` + +## Configuration + +The skill requires the following configuration in `scaffold.yml`: + +```yaml +vllm: + platform: vllm + model_path: /path/to/models + gpu_count: 2 + port: 8000 + quantization: "none" +``` + +## Security Considerations + +- All VLLM integrations require human approval +- Model access controls must be configured +- Network security must be enforced +- Resource usage monitoring is required + +## Compliance Requirements + +- Follow security best practices for AI platform integrations +- Maintain audit logs of all VLLM interactions +- Ensure proper resource management and monitoring diff --git a/.agents/skills/warp-governed/SKILL.md b/.agents/skills/warp-governed/SKILL.md new file mode 100644 index 00000000..eb8f999e --- /dev/null +++ b/.agents/skills/warp-governed/SKILL.md @@ -0,0 +1,75 @@ +# SKILL.md +# Warp Governed Profile + +## Requirements Covered + +### Governance Requirements +- REQ-012: Least-Privilege Agent Permissions +- REQ-217: Agent Permissions Check +- REQ-220: Policy Guardrails +- REQ-244: Context Window Sizing +- REQ-245: Live Context Fill Indicator +- REQ-246: Auto Context Compression +- REQ-247: Hard Context Ceiling + +## Core Principle +The warp-governed profile is designed for agents operating within the Warp Terminal environment. It ensures compliance with Specsmith governance while leveraging Warp's specific capabilities and constraints. + +## Profile Characteristics + +### Required Skills +- preflight-gate +- governed-agent-loop +- requirement-author +- testcase-author +- traceability-auditor +- context-pack-compiler +- token-budget-auditor +- skill-composer +- warp-integration + +### Environment-Specific Features +- Warp Terminal integration capabilities +- Context window optimization for Warp's terminal constraints +- Compliance with Warp's terminal environment +- Integration with Warp's native terminal features + +## Implementation Details + +### Warp-Specific Execution +1. Leverage Warp Terminal's native capabilities for terminal operations +2. Optimize context windows to fit Warp's terminal constraints +3. Apply Specsmith governance rules within Warp's environment +4. Maintain traceability between Warp actions and Specsmith requirements + +### Context Management +- Optimize context for Warp's terminal environment +- Apply Warp-specific compression techniques +- Ensure context fits within Warp's constraints while maintaining traceability +- Track Warp-specific terminal usage + +## Configuration + +### Default Behavior +By default, the warp-governed profile: +- Integrates with Warp Terminal's native features +- Optimizes context for Warp's terminal environment +- Maintains full Specsmith governance compliance +- Tracks Warp-specific usage metrics + +### Override Options +- Allow Warp-specific skill overrides +- Support Warp Terminal environment customization +- Enable Warp-specific context optimization + +## Security Considerations +- All Warp Terminal actions must pass preflight validation +- Warp-specific skill compositions must be traceable +- Warp Terminal environment compliance must be maintained +- Warp-specific terminal usage must be tracked + +## Compliance Requirements +- Every Warp Terminal action must be traceable to a valid work item or requirement +- Warp Terminal integration must comply with Warp's usage policies +- All skill compositions must follow Specsmith governance +- Warp-specific terminal usage must be reported diff --git a/.agents/skills/warp-integration/SKILL.md b/.agents/skills/warp-integration/SKILL.md index 85e335eb..fa5b9b6c 100644 --- a/.agents/skills/warp-integration/SKILL.md +++ b/.agents/skills/warp-integration/SKILL.md @@ -26,7 +26,7 @@ specsmith mcp register # register this project (run once per projec ## Every Warp session — mandatory protocol 1. Run at session start: ```bash -specsmith kill-session 2>/dev/null || true +specsmith kill-session # idempotent; safe when no processes exist specsmith audit --project-dir . specsmith sync --project-dir . specsmith checkpoint --project-dir . diff --git a/.agents/skills/webui-integration/SKILL.md b/.agents/skills/webui-integration/SKILL.md new file mode 100644 index 00000000..78653749 --- /dev/null +++ b/.agents/skills/webui-integration/SKILL.md @@ -0,0 +1,66 @@ +--- +name: webui-integration +description: Skill for integrating with WebUI platforms for AI model serving with specsmith governance +--- + +# WebUI Platform Integration + +This skill enables specsmith projects to integrate with WebUI platforms for AI model serving while maintaining governance compliance. + +## Requirements Covered + +- REQ-109: WebUI Platform Integration +- Allows specsmith projects to integrate with WebUI platforms for AI model serving with human approval + +## Integration Capabilities + +### Platform Features +- WebUI platform configuration and setup +- Model serving through WebUI interface +- API endpoint management for WebUI services +- Authentication and security configuration +- Resource management for WebUI deployments + +### Governance Requirements +- Human approval required for all WebUI integrations +- Configuration management with governance controls +- Security best practices enforcement +- Resource monitoring and logging + +## Usage Examples + +```bash +# Initialize WebUI integration +specsmith skill install webui-integration + +# Configure WebUI platform settings +specsmith webui configure --platform webui --model-path /path/to/model + +# Deploy model via WebUI +specsmith webui deploy --model my-model --port 7860 +``` + +## Configuration + +The skill requires the following configuration in `scaffold.yml`: + +```yaml +webui: + platform: webui + model_path: /path/to/models + port: 7860 + auth_required: true +``` + +## Security Considerations + +- All WebUI integrations require human approval +- Authentication tokens must be managed securely +- Network access controls must be configured +- Regular security audits are recommended + +## Compliance Requirements + +- Follow security best practices for AI platform integrations +- Maintain audit logs of all WebUI interactions +- Ensure proper resource management and monitoring diff --git a/.agents/skills/windsurf-integration/SKILL.md b/.agents/skills/windsurf-integration/SKILL.md index bc28c6a0..65047c77 100644 --- a/.agents/skills/windsurf-integration/SKILL.md +++ b/.agents/skills/windsurf-integration/SKILL.md @@ -18,7 +18,7 @@ For MCP in Windsurf (Settings → MCP Servers): ## Every Windsurf session — mandatory protocol 1. Run at session start: ```bash -specsmith kill-session 2>/dev/null || true +specsmith kill-session # idempotent; safe when no processes exist specsmith audit --project-dir . specsmith sync --project-dir . specsmith checkpoint --project-dir . diff --git a/.agents/skills/zoo-code-integration/SKILL.md b/.agents/skills/zoo-code-integration/SKILL.md new file mode 100644 index 00000000..143a1fae --- /dev/null +++ b/.agents/skills/zoo-code-integration/SKILL.md @@ -0,0 +1,115 @@ +# Zoo Code — Specsmith Governance Integration + +Use this skill when working in Zoo Code or Roo Code on a Specsmith-governed repository. + +## Goal + +Make Zoo/Roo behave like a governed local engineering agent, not an unconstrained chat assistant. + +The required pattern is: + +```text +Architect plans +Coder edits +Debug/Tool runs and parses commands +Reviewer critiques +Specsmith preflight/verify/trace gates the work +``` + +The model that writes a patch must not be the only model that approves it. + +## Required local project files + +Project-local Zoo/Roo integration lives in `.roo/`: + +- `.roo/mcp.json` — repo-local MCP server registration for `specsmith-governance` +- `.roo/specsmith-rules.md` — mandatory agent protocol for Zoo/Roo +- `.roo/modes.local.json` — project-local reference mode definitions +- `.roo/global-settings.copy-to-zoo-code.json` — copyable global Zoo Code/OpenAI-compatible provider settings + +Only `.roo/mcp.json` and `.roo/specsmith-rules.md` are intended to be active project files. Global provider/model settings must be copied into Zoo Code global settings by the operator. + +## Session start + +1. Read `AGENTS.md` and `.roo/specsmith-rules.md`. +2. Call the MCP tool `governance_checkpoint`. +3. Call `governance_phase` and `governance_req_list` before changing code. +4. Summarize the current phase, failing checks, relevant requirements, and permitted scope. + +## Before any code change + +Call `governance_preflight` with one sentence describing the intended change. + +Do not edit files unless the decision is `accepted`. + +If the decision is `needs_clarification`, ask a narrow question or reduce the change scope. + +If the decision is `rejected`, stop and report why. + +## During implementation + +Follow role separation: + +- Architect mode may plan and inspect but should not directly edit production code. +- Code mode may edit only within the accepted preflight scope. +- Debug/Tool mode should run safe commands and parse outputs; it should not make large edits. +- Review mode should read diffs, requirements, and tests; it should not rewrite the patch unless explicitly promoted. + +Prefer small diffs. Ground API, register, binding, and build-system claims in actual repository files or command output. + +## Verification + +After edits: + +1. Run the relevant tests/build checks. +2. Capture command output. +3. Run `specsmith verify` or use MCP governance tools when available. +4. Call `governance_trace_seal` for meaningful milestones, accepted reviews, or release gates. + +## Portable handoffs + +When a session must continue in another agent, export the latest governed +context instead of writing an ungrounded prose summary: + +```powershell +specsmith zoo-code export-handoff --project-dir . --output handoff.json +``` + +The resulting envelope retains source IDs, confidence, and uncertainty. The +receiving agent must verify the cited source IDs before treating an excerpt as +a decision or a fact. + +## Embedded/firmware discipline + +Never invent SDK, HAL, register, device-tree, or build-system APIs. + +For Zephyr/devicetree-style work, ground claims in: + +- `bindings/*.yaml` +- board DTS/DTSI files +- generated devicetree output +- exact build errors + +For C/firmware work, ground claims in: + +- headers +- vendor SDK files +- compiler output +- tests or reproducible logs + +## Local model routing + +When using a LiteLLM/vLLM local pool, route by task: + +| Task | Model role | +|---|---| +| repo planning, architecture, ambiguous debugging | `architect` | +| implementation, tests, refactors | `editor` | +| shell commands, build logs, JSON/YAML, quick summaries | `tool-fast` | +| adversarial review, regression risk, final critique | `reviewer` | + +Use the LiteLLM router endpoint when available: + +```text +http://localhost:4000/v1 +``` diff --git a/.github/dependabot.yml b/.github/dependabot.yml index fae4f496..2d0f59e5 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -24,4 +24,4 @@ updates: open-pull-requests-limit: 5 labels: - "dependencies" - - "ci" \ No newline at end of file + - "ci" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1fa99afc..2e3d62be 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,6 +10,11 @@ on: # Default: deny all permissions. Each job grants only what it needs. permissions: {} +env: + SPECSMITH_ALLOW_NON_PIPX: "1" + SPECSMITH_NO_AUTO_UPDATE: "1" + SPECSMITH_PYPI_CHECKED: "1" + jobs: lint: name: Lint (ruff) @@ -248,11 +253,11 @@ jobs: SPECSMITH_PYPI_CHECKED: "1" PYTHONIOENCODING: utf-8 run: | - python -m specsmith.cli api-surface > /tmp/api_surface.live.json + python -m specsmith api-surface > /tmp/api_surface.live.json - name: Diff against committed fixture run: | diff -u tests/fixtures/api_surface.json /tmp/api_surface.live.json || { echo "::error::api_surface.json is stale. Regenerate via:" - echo " python -m specsmith.cli api-surface > tests/fixtures/api_surface.json" + echo " python -m specsmith api-surface > tests/fixtures/api_surface.json" exit 1 } diff --git a/.github/workflows/dev-release.yml b/.github/workflows/dev-release.yml index 15124020..168e7d9c 100644 --- a/.github/workflows/dev-release.yml +++ b/.github/workflows/dev-release.yml @@ -6,13 +6,12 @@ on: workflow_dispatch: permissions: - contents: write # needed to create/update the rolling 'latest' GitHub pre-release + contents: read jobs: - test: - runs-on: ubuntu-latest - # Only run from the develop branch — blocks accidental workflow_dispatch from main. + quality: if: github.ref == 'refs/heads/develop' + runs-on: ubuntu-latest steps: - uses: actions/checkout@v7 - uses: actions/setup-python@v6 @@ -22,139 +21,63 @@ jobs: - run: pip install -e ".[dev]" - run: ruff check src/ tests/ - run: ruff format --check src/ tests/ - - run: mypy src/specsmith --ignore-missing-imports + - run: mypy src/specsmith/ - run: pytest tests/ -x -q - build-and-publish: - needs: test + dev-build: + needs: quality + if: github.ref == 'refs/heads/develop' runs-on: ubuntu-latest - environment: pypi - permissions: - contents: write # write required to create/update the dev GitHub pre-release - id-token: write steps: - uses: actions/checkout@v7 with: fetch-depth: 0 - - uses: actions/setup-python@v6 with: python-version: "3.12" cache: pip - - name: Install build tools run: pip install build - - - name: Set dev version + - name: Set development version + shell: bash run: | - # Use pyproject.toml version as the base (no patch bump). - # pyproject.toml should always hold the NEXT release version (e.g. 0.3.0). - # Dev builds publish as 0.3.0.devN — PEP 440 pre-release of the upcoming release. - # N = total commit count (monotonically increasing, unique per push). - BASE_VERSION=$(grep 'version = ' pyproject.toml | head -1 | sed 's/version = "\(.*\)"/\1/') - COMMIT_COUNT=$(git rev-list --count HEAD) - DEV_VERSION="${BASE_VERSION}.dev${COMMIT_COUNT}" - echo "DEV_VERSION=${DEV_VERSION}" >> $GITHUB_ENV - - # Patch pyproject.toml with dev version - sed -i "s/version = \"${BASE_VERSION}\"/version = \"${DEV_VERSION}\"/" pyproject.toml - echo "Building version: ${DEV_VERSION}" - - - name: Strip git-URL deps before PyPI build - run: | - # PyPI rejects packages with direct git:// / git+https:// dependencies. - # chronomemory is now on PyPI (>=0.2.7); this step is a no-op for the current - # version spec but is kept as a safety net in case a git-URL dep is reintroduced. - sed -i '/chronomemory @ git+/d' pyproject.toml - echo "pyproject.toml after stripping git deps:" - grep -A2 'dependencies' pyproject.toml | head -20 - + BASE_VERSION=$(python -c 'import pathlib, tomllib; print(tomllib.loads(pathlib.Path("pyproject.toml").read_text(encoding="utf-8"))["project"]["version"])') + if [[ ! "$BASE_VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then + echo "::error::Development builds require a final base version, got $BASE_VERSION" + exit 1 + fi + IFS=. read -r MAJOR MINOR PATCH <<< "$BASE_VERSION" + NEXT_PATCH=$((PATCH + 1)) + TAG=$(git describe --tags --abbrev=0 2>/dev/null || true) + if [ -n "$TAG" ]; then + COMMIT_COUNT=$(git rev-list --count "$TAG..HEAD") + else + COMMIT_COUNT=$(git rev-list --count HEAD) + fi + DEV_VERSION="${MAJOR}.${MINOR}.${NEXT_PATCH}.dev${COMMIT_COUNT}" + python -c 'from pathlib import Path; import sys; path = Path("pyproject.toml"); text = path.read_text(encoding="utf-8"); path.write_text(text.replace(f"version = {sys.argv[1]!r}", f"version = {sys.argv[2]!r}", 1), encoding="utf-8")' "$BASE_VERSION" "$DEV_VERSION" + PYTHONPATH=src python scripts/check_dev_release.py --expected-version "$DEV_VERSION" + echo "DEV_VERSION=$DEV_VERSION" >> "$GITHUB_ENV" - run: python -m build - - - name: Publish dev release to PyPI - uses: pypa/gh-action-pypi-publish@release/v1 + - name: Upload development artifacts + uses: actions/upload-artifact@v4 with: - skip_existing: true # gracefully skip if this exact version is already on PyPI + name: dev-dist + path: dist/ - # Create/update a rolling GitHub pre-release so users can track dev builds. - # NOTE: when the first official stable release ships, remove this step and - # instead rely on release.yml with --latest to make stable the default. - - name: Create/update rolling dev GitHub pre-release - env: - GH_TOKEN: ${{ github.token }} - run: | - # Delete any existing 'latest-dev' tag+release so we can overwrite it. - gh release delete latest-dev --repo ${{ github.repository }} \ - --yes --cleanup-tag 2>/dev/null || true - # Also remove any stale local tag (actions/checkout may have fetched it) - git tag -d latest-dev 2>/dev/null || true - gh release create latest-dev dist/* \ - --title "Latest dev build (${DEV_VERSION})" \ - --notes "Rolling dev pre-release built from the develop branch." \ - --prerelease \ - --target "${{ github.sha }}" - # --prerelease already prevents GitHub from marking this as the default - # 'latest' release — no extra flag needed. - - docs-build: - needs: build-and-publish + pypi-dev-publish: + needs: dev-build + if: github.ref == 'refs/heads/develop' runs-on: ubuntu-latest - continue-on-error: true + environment: pypi + permissions: + id-token: write steps: - - name: Trigger ReadTheDocs builds (develop + latest) - env: - RTD_TOKEN: ${{ secrets.RTD_TOKEN }} - run: | - if [ -z "$RTD_TOKEN" ]; then - echo "WARNING: RTD_TOKEN secret is not set. Skipping RTD build trigger." - echo "To fix: go to GitHub repo Settings → Secrets → Actions and add RTD_TOKEN." - echo "Get the token from: https://readthedocs.org/accounts/tokens/" - exit 0 - fi - - # Trigger the 'develop' RTD version build (accessible at /en/develop/) - echo "Triggering RTD build for 'develop' version..." - STATUS=$(curl -s -o /dev/null -w "%{http_code}" -X POST \ - -H "Authorization: Token $RTD_TOKEN" \ - "https://readthedocs.org/api/v3/projects/specsmith/versions/develop/builds/") - echo "RTD develop build trigger: HTTP $STATUS" - if [ "$STATUS" != "202" ]; then - echo "WARNING: RTD develop build trigger returned HTTP $STATUS (expected 202)." - echo "Common causes:" - echo " - 401: RTD_TOKEN is invalid or expired" - echo " - 404: 'develop' version not activated in RTD dashboard" - echo " Fix: https://readthedocs.org/projects/specsmith/versions/ → activate 'develop'" - fi - - # Step 1: Set RTD project default_branch to 'develop' - echo "[1/3] Setting RTD project default_branch to 'develop'..." - PATCH_STATUS=$(curl -s -o /dev/null -w "%{http_code}" -X PATCH \ - -H "Authorization: Token $RTD_TOKEN" \ - -H "Content-Type: application/json" \ - -d '{"default_branch": "develop"}' \ - "https://readthedocs.org/api/v3/projects/specsmith/") - echo "RTD project PATCH: HTTP $PATCH_STATUS" - - # Step 2: Set the 'latest' VERSION object's identifier to 'develop' - # This is the key step — the version object has its own branch setting - # separate from the project-level default_branch. - echo "[2/3] Setting RTD 'latest' version identifier to 'develop'..." - VER_PATCH=$(curl -s -o /tmp/ver_patch.txt -w "%{http_code}" -X PATCH \ - -H "Authorization: Token $RTD_TOKEN" \ - -H "Content-Type: application/json" \ - -d '{"identifier": "develop", "active": true}' \ - "https://readthedocs.org/api/v3/projects/specsmith/versions/latest/") - echo "RTD 'latest' version PATCH: HTTP $VER_PATCH" - cat /tmp/ver_patch.txt | head -c 200 || true - - # Step 3: Trigger a fresh /en/latest/ build (now tracks develop) - echo "[3/3] Triggering RTD 'latest' build from develop..." - LATEST_STATUS=$(curl -s -o /dev/null -w "%{http_code}" -X POST \ - -H "Authorization: Token $RTD_TOKEN" \ - "https://readthedocs.org/api/v3/projects/specsmith/versions/latest/builds/") - echo "RTD latest build trigger: HTTP $LATEST_STATUS" - if [ "$LATEST_STATUS" != "202" ]; then - echo "WARNING: RTD latest trigger returned HTTP $LATEST_STATUS" - echo "If 404: 'latest' version may not be active in RTD dashboard." - echo "Fix: https://readthedocs.org/projects/specsmith/versions/ -> activate 'latest'" - fi + - uses: actions/download-artifact@v4 + with: + name: dev-dist + path: dist/ + - name: Publish development release to PyPI + uses: pypa/gh-action-pypi-publish@release/v1 + with: + skip-existing: true diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 6367c97c..8e06a2ba 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -64,6 +64,8 @@ jobs: python-version: "3.12" cache: pip - run: pip install build + - name: Verify stable release version and tag + run: PYTHONPATH=src python scripts/check_stable_release.py --expected-version "${{ github.ref_name }}" - name: Strip git-URL deps before PyPI build run: | # PyPI rejects packages with direct git+https:// dependencies. diff --git a/.gitignore b/.gitignore index dd9e8e0d..386b0347 100644 --- a/.gitignore +++ b/.gitignore @@ -34,6 +34,7 @@ htmlcov/ # Generated examples / test output .work/ +/site/ tmp/ temp/ *.log @@ -52,6 +53,9 @@ _diag_*.py # .specsmith/ split: committed (audit chain) vs gitignored (runtime cache) # Keep committed: config.yml, requirements.json, testcases.json # All runtime-only / regeneratable artifacts are gitignored: +.specsmith/esdb.sqlite3 +.specsmith/esdb.sqlite3-shm +.specsmith/esdb.sqlite3-wal .specsmith/workitems.json .specsmith/runs/ .specsmith/chat/ @@ -88,10 +92,18 @@ app/target/ !.specsmith/config.yml !.specsmith/requirements.json !.specsmith/testcases.json -!.specsmith/esdb.sqlite3 !.specsmith/esdb_migration_manifest.json !.chronomemory/events.wal !.chronomemory/snapshot.json +!.chronomemory/session-events.jsonl # Ephemeral runtime paths (never commit): .specsmith/session_metrics.jsonl .specsmith/backups/ +.specsmith/agent-tools.json +.specsmith/agents.md.bak +.specsmith/agents.md.m005.bak +.specsmith/migration-state.json +.specsmith/migration-backups/ +.specsmith/esdb-full-coverage +.specsmith/esdb-m009-backfill +.specsmith/esdb-m010-cleanup diff --git a/.roo/global-settings.copy-to-zoo-code.json b/.roo/global-settings.copy-to-zoo-code.json new file mode 100644 index 00000000..24125728 --- /dev/null +++ b/.roo/global-settings.copy-to-zoo-code.json @@ -0,0 +1,33 @@ +{ + "note": "Copy these provider/model ideas into Zoo Code global settings. This file is a project reference only; Zoo Code global settings are not automatically loaded from this repository.", + "provider": { + "name": "ChronoCortex Local Agent Pool", + "type": "openai-compatible", + "baseUrl": "http://localhost:4000/v1", + "apiKeyEnv": "LITELLM_MASTER_KEY" + }, + "models": { + "architect": { + "id": "architect", + "useFor": ["architecture", "repo planning", "ambiguous debugging", "risk review"] + }, + "editor": { + "id": "editor", + "useFor": ["implementation", "tests", "refactors", "code edits"] + }, + "toolFast": { + "id": "tool-fast", + "useFor": ["shell planning", "build logs", "JSON/YAML", "quick summaries"] + }, + "reviewer": { + "id": "reviewer", + "useFor": ["diff review", "regression risk", "adversarial critique"] + } + }, + "recommendedModeMapping": { + "Specsmith Architect": "architect", + "Specsmith Code": "editor", + "Specsmith Debug / Tool": "tool-fast", + "Specsmith Review": "reviewer" + } +} diff --git a/.roo/mcp.json b/.roo/mcp.json new file mode 100644 index 00000000..a9596209 --- /dev/null +++ b/.roo/mcp.json @@ -0,0 +1,13 @@ +{ + "mcpServers": { + "specsmith-governance": { + "command": "specsmith", + "args": ["mcp", "serve", "--project-dir", "."], + "env": { + "SPECSMITH_ALLOW_NON_PIPX": "1", + "SPECSMITH_NO_AUTO_UPDATE": "1", + "SPECSMITH_PYPI_CHECKED": "1" + } + } + } +} diff --git a/.roo/modes.local.json b/.roo/modes.local.json new file mode 100644 index 00000000..e8c93814 --- /dev/null +++ b/.roo/modes.local.json @@ -0,0 +1,33 @@ +{ + "note": "Project-local reference for Zoo Code / Roo Code modes. Use this as the canonical role mapping for this repository. Some clients require custom modes to be copied into global/user settings.", + "modes": [ + { + "slug": "specsmith-architect", + "name": "Specsmith Architect", + "role": "architect", + "model": "architect", + "description": "Plan, inspect, and reason about requirements and architecture. Do not directly edit production code unless explicitly promoted." + }, + { + "slug": "specsmith-code", + "name": "Specsmith Code", + "role": "code", + "model": "editor", + "description": "Implement accepted preflight tasks with small diffs and tests. Do not approve your own patch." + }, + { + "slug": "specsmith-debug", + "name": "Specsmith Debug / Tool", + "role": "debug", + "model": "tool-fast", + "description": "Generate safe commands, parse build logs, inspect outputs, and summarize failures. Avoid large edits." + }, + { + "slug": "specsmith-review", + "name": "Specsmith Review", + "role": "ask", + "model": "reviewer", + "description": "Review diffs against requirements, tests, and prior decisions. Prefer adversarial critique over rewriting." + } + ] +} diff --git a/.roo/specsmith-rules.md b/.roo/specsmith-rules.md new file mode 100644 index 00000000..4a80a8fc --- /dev/null +++ b/.roo/specsmith-rules.md @@ -0,0 +1,64 @@ +# Specsmith Rules for Zoo Code / Roo Code + +This repository uses Specsmith governance. Follow these rules for all agentic work in Zoo Code or Roo Code. + +## Mandatory protocol + +1. Read `AGENTS.md` and this file before changing code. +2. Use the `specsmith-governance` MCP server from `.roo/mcp.json`. +3. Call `governance_checkpoint` at session start and every 8-10 turns. +4. Call `governance_preflight` before any code edit. +5. Do not edit files unless preflight returns `accepted`. +6. Run tests/build checks after edits. +7. Run verification before reporting success. +8. Seal meaningful decisions with `governance_trace_seal`. + +## Role separation + +Use separate modes/models for separate jobs: + +| Work | Preferred mode | Preferred local model role | +|---|---|---| +| requirements, architecture, plans | Architect | `architect` | +| implementation and tests | Code | `editor` | +| command generation and log parsing | Debug / Tool | `tool-fast` | +| adversarial diff review | Review | `reviewer` | + +The model that writes a patch must not be the only model that approves it. + +## Scope control + +Keep changes inside the accepted preflight scope. + +Do not perform these actions unless the user explicitly asks and preflight accepts: + +- dependency upgrades +- public API changes +- file tree deletions +- generated code rewrites over 200 lines +- git push or release actions +- secret, credential, or `.env` edits + +## Grounding rules + +Do not invent APIs, flags, registers, CLI options, package names, or configuration keys. + +Ground technical claims in one of: + +- repository files +- generated outputs +- test/build logs +- official vendor/project docs already present in the workspace + +For firmware, Zephyr, RTL, FPGA, or low-level systems work, cite exact headers, bindings, source files, generated files, or build output before editing. + +## Completion report + +Every completed task should report: + +- accepted preflight work item id, when available +- files changed +- tests/builds run +- reviewer findings +- remaining risks +- follow-up work, if any diff --git a/.specsmith/esdb.sqlite3 b/.specsmith/esdb.sqlite3 deleted file mode 100644 index 04d4e8d2..00000000 Binary files a/.specsmith/esdb.sqlite3 and /dev/null differ diff --git a/.specsmith/requirements.json b/.specsmith/requirements.json index 9e458f77..41b2b814 100644 --- a/.specsmith/requirements.json +++ b/.specsmith/requirements.json @@ -706,10 +706,10 @@ { "id": "REQ-065", "version": 1, - "title": "WI Lifecycle States", - "description": "Every Work Item must move through a defined set of states: open, implemented, promoted, closed, archived, rejected. The allowed transitions are enforced by WorkItemStore.", - "source": "wi_store.py", - "status": "implemented", + "title": "GitHub Release Creation", + "description": "Allow specsmith to create GitHub releases for tagged versions with human approval", + "source": "specsmith governance", + "status": "planned", "test_ids": [ "TEST-065" ] @@ -717,10 +717,10 @@ { "id": "REQ-066", "version": 1, - "title": "WI-to-REQ Promotion", - "description": "A Work Item in the open or implemented state may be promoted to a formal requirement via specsmith wi promote, which creates a new REQ-NNN entry in the target requirements YAML and records promoted_to_req on the WI.", - "source": "wi_store.py", - "status": "implemented", + "title": "PyPI Deployment", + "description": "Allow specsmith to trigger PyPI package deployment with human approval", + "source": "specsmith governance", + "status": "planned", "test_ids": [ "TEST-066" ] @@ -728,10 +728,10 @@ { "id": "REQ-067", "version": 1, - "title": "WI Status Persistence", - "description": "Work Item state is persisted to .specsmith/workitems.json using an atomic write (write-then-rename) so crashes never leave the store corrupt.", - "source": "wi_store.py", - "status": "implemented", + "title": "CI Management", + "description": "Allow specsmith to manage CI workflows with human approval", + "source": "specsmith governance", + "status": "planned", "test_ids": [ "TEST-067" ] @@ -739,10 +739,10 @@ { "id": "REQ-068", "version": 1, - "title": "WI Auto-Implementation on Verify Equilibrium", - "description": "When specsmith verify reaches equilibrium for a given work_item_id, the WI is automatically transitioned from open to implemented. This wiring is best-effort and never blocks the verify result.", - "source": "governance_logic.py", - "status": "implemented", + "title": "Pull Request Management", + "description": "Allow specsmith to manage PRs, merges, and issue creation with human approval", + "source": "specsmith governance", + "status": "planned", "test_ids": [ "TEST-068" ] @@ -772,10 +772,10 @@ { "id": "REQ-071", "version": 1, - "title": "Nexus Must Index the Repository", - "description": "Nexus must populate .repo-index/ with files.json, tags, test_commands.json, architecture.md, and conventions.md as available.", - "source": "ARCHITECTURE.md", - "status": "implemented", + "title": "Release Notes Generation", + "description": "Allow specsmith to automatically generate release notes from commit history with human approval", + "source": "specsmith governance", + "status": "planned", "test_ids": [ "TEST-071" ] @@ -783,10 +783,10 @@ { "id": "REQ-072", "version": 1, - "title": "Nexus REPL Must Support Slash Commands", - "description": "The Nexus REPL must support /plan, /ask, /fix, /test, /commit, /pr, /undo, /context, /exit.", - "source": "ARCHITECTURE.md", - "status": "implemented", + "title": "Release Tag Management", + "description": "Allow specsmith to manage release tags including creation, deletion, and modification with human approval", + "source": "specsmith governance", + "status": "planned", "test_ids": [ "TEST-072" ] @@ -794,10 +794,10 @@ { "id": "REQ-073", "version": 1, - "title": "Nexus Output Contract", - "description": "Each Nexus task response must include sections Plan, Commands to run, Files changed, Diff, Test results, and Next action.", - "source": "ARCHITECTURE.md", - "status": "implemented", + "title": "Artifact Management", + "description": "Allow specsmith to manage release artifacts including uploads, downloads, and cleanup with human approval", + "source": "specsmith governance", + "status": "planned", "test_ids": [ "TEST-073" ] @@ -805,10 +805,10 @@ { "id": "REQ-074", "version": 1, - "title": "vLLM Image Must Be Pinned", - "description": "The Nexus docker-compose.yml must pin the vLLM image to a specific tag (vllm/vllm-openai:v0.8.5) and not use latest.", - "source": "ARCHITECTURE.md", - "status": "implemented", + "title": "Release Branch Management", + "description": "Allow specsmith to manage release branches including creation, merging, and deletion with human approval", + "source": "specsmith governance", + "status": "planned", "test_ids": [ "TEST-074" ] @@ -816,10 +816,10 @@ { "id": "REQ-075", "version": 1, - "title": "vLLM Must Serve l1-nexus Model", - "description": "The Nexus docker-compose.yml must publish the served model as l1-nexus and use the Hermes tool-call parser.", - "source": "ARCHITECTURE.md", - "status": "implemented", + "title": "Release Validation", + "description": "Allow specsmith to perform automated validation checks before release creation with human approval", + "source": "specsmith governance", + "status": "planned", "test_ids": [ "TEST-075" ] @@ -827,10 +827,10 @@ { "id": "REQ-076", "version": 1, - "title": "Nexus Tool Executor Registration Must Be Unique", - "description": "Each Nexus tool must be registered with the AG2 executor exactly once; LLM-side tool signatures may be attached to multiple caller agents but the execution function must not be re-registered to avoid AG2 override warnings.", - "source": "ARCHITECTURE.md", - "status": "implemented", + "title": "Release Rollback", + "description": "Allow specsmith to rollback to previous releases with human approval", + "source": "specsmith governance", + "status": "planned", "test_ids": [ "TEST-076" ] @@ -838,10 +838,10 @@ { "id": "REQ-077", "version": 1, - "title": "Safe Cleanup Must Default to Dry-Run", - "description": "The Specsmith safe-cleanup capability must default to dry-run mode and only delete files when an explicit apply flag is provided.", - "source": "ARCHITECTURE.md", - "status": "implemented", + "title": "Release Promotion", + "description": "Allow specsmith to promote releases between environments (dev, staging, prod) with human approval", + "source": "specsmith governance", + "status": "planned", "test_ids": [ "TEST-077" ] @@ -849,10 +849,10 @@ { "id": "REQ-078", "version": 1, - "title": "Safe Cleanup Must Use a Hard-Coded Target List", - "description": "Safe cleanup must only consider the canonical built-in target list and must reject user-supplied arbitrary paths.", - "source": "ARCHITECTURE.md", - "status": "implemented", + "title": "Release Metadata Management", + "description": "Allow specsmith to manage release metadata including version, date, and author information with human approval", + "source": "specsmith governance", + "status": "planned", "test_ids": [ "TEST-078" ] @@ -860,10 +860,10 @@ { "id": "REQ-079", "version": 1, - "title": "Safe Cleanup Must Protect Governance and Source", - "description": "Safe cleanup must refuse to delete .git, .specsmith, governance markdown files, pyproject.toml, README.md, LICENSE, CHANGELOG.md, src/, tests/, docs/, scripts/, .repo-index/, .github/, .vscode/, third-party agent integration directories (such as .agents/), and project configuration dotfiles.", - "source": "ARCHITECTURE.md", - "status": "implemented", + "title": "Git Platform Agnostic Management", + "description": "Allow specsmith to manage Git repositories across multiple platforms (GitHub, GitLab, Bitbucket, etc.) with human approval", + "source": "specsmith governance", + "status": "planned", "test_ids": [ "TEST-079" ] @@ -871,10 +871,10 @@ { "id": "REQ-080", "version": 1, - "title": "Safe Cleanup Must Emit a Structured Report", - "description": "Safe cleanup must return a report containing the lists of removed paths, skipped paths with reasons, and total bytes reclaimed, suitable for inclusion as ledger evidence.", - "source": "ARCHITECTURE.md", - "status": "implemented", + "title": "GitHub Platform Management", + "description": "Allow specsmith to manage GitHub repositories, issues, pull requests, and releases with human approval", + "source": "specsmith governance", + "status": "planned", "test_ids": [ "TEST-080" ] @@ -882,10 +882,10 @@ { "id": "REQ-081", "version": 1, - "title": "Safe Cleanup Must Be Exposed via Specsmith CLI", - "description": "The Specsmith CLI must expose the safe cleanup capability as `specsmith clean`, supporting `--apply`, `--json`, and `--project-dir`. When `--apply` is used and `LEDGER.md` exists, the run must be recorded as a `cleanup` ledger event tagged with REQ-077..REQ-080.", - "source": "ARCHITECTURE.md", - "status": "implemented", + "title": "GitLab Platform Management", + "description": "Allow specsmith to manage GitLab repositories, issues, merge requests, and releases with human approval", + "source": "specsmith governance", + "status": "planned", "test_ids": [ "TEST-081" ] @@ -893,10 +893,10 @@ { "id": "REQ-082", "version": 1, - "title": "CLI Console Must Be UTF-8 Safe Across Platforms", - "description": "All Specsmith CLI output (rich Console) must render UTF-8 glyphs (such as warning, arrow, check, cross) without raising UnicodeEncodeError on Windows code pages such as cp1252. The console factory must reconfigure stdout/stderr to UTF-8 and disable rich's legacy_windows renderer.", - "source": "ARCHITECTURE.md", - "status": "implemented", + "title": "Bitbucket Platform Management", + "description": "Allow specsmith to manage Bitbucket repositories, issues, pull requests, and releases with human approval", + "source": "specsmith governance", + "status": "planned", "test_ids": [ "TEST-082" ] @@ -904,10 +904,10 @@ { "id": "REQ-083", "version": 1, - "title": "Canonical Test Specification File Is TESTS.md", - "description": "The canonical test specification file is named `TESTS.md` (replacing the legacy names `TESTS.md`, `TEST-SPEC.md`, and `TEST-SPECS.md`). Specsmith code, governance documents, templates, scaffolder output, importer overlay, auditor checks, retrieval index, exporter, validator, REPL skill files, ReadTheDocs site, and CLI help must all reference `TESTS.md`. Legacy filenames must not be created by new scaffolds, must be auto-renamed by `specsmith migrate-project`, and must not be referenced in user-facing docs.", - "source": "ARCHITECTURE.md", - "status": "implemented", + "title": "Azure DevOps Platform Management", + "description": "Allow specsmith to manage Azure DevOps repositories, issues, pull requests, and releases with human approval", + "source": "specsmith governance", + "status": "planned", "test_ids": [ "TEST-083" ] @@ -915,10 +915,10 @@ { "id": "REQ-084", "version": 1, - "title": "Natural-Language Governance Broker", - "description": "Specsmith must expose a Nexus broker module (`specsmith.agent.broker`) that translates plain-language user utterances into Specsmith-governed work without the user reasoning about REQ IDs, TEST IDs, or work items. The broker must classify intent (read-only ask vs change vs release), infer affected scope from the local `.repo-index` and existing requirements, invoke `specsmith preflight` and `specsmith verify` as the only sources of governance decisions, render plain-language plans and outcomes, hide REQ/TEST/work-item IDs by default (revealed only on `/why`, `/show-governance`, or `--verbose`), bound retries per REQ-014, escalate to a single user clarification on stop-and-align (REQ-063), and never invent governance content (REQ/TEST drafting requires explicit user confirmation).", - "source": "ARCHITECTURE.md", - "status": "implemented", + "title": "Git Platform Authentication Management", + "description": "Allow specsmith to manage authentication credentials for multiple Git platforms with human approval", + "source": "specsmith governance", + "status": "planned", "test_ids": [ "TEST-084" ] @@ -926,10 +926,10 @@ { "id": "REQ-085", "version": 1, - "title": "specsmith preflight CLI Subcommand", - "description": "The Specsmith CLI must expose a `specsmith preflight ` subcommand that reads `REQUIREMENTS.md` and `.specsmith/` state, classifies intent and infers scope, and emits a JSON object with at least the keys `decision` (one of `accepted`, `needs_clarification`, `blocked`, `rejected`), `work_item_id`, `requirement_ids`, `test_case_ids`, `confidence_target`, and `instruction`. Read-only asks accept by default, destructive intents require clarification, and changes with no matching scope return `needs_clarification` with a one-sentence question. The CLI must support `--project-dir`, `--json`, and `--verbose`.", - "source": "ARCHITECTURE.md", - "status": "implemented", + "title": "Git Platform Configuration Management", + "description": "Allow specsmith to configure platform-specific settings and webhooks for multiple Git platforms with human approval", + "source": "specsmith governance", + "status": "planned", "test_ids": [ "TEST-085" ] @@ -937,10 +937,10 @@ { "id": "REQ-086", "version": 1, - "title": "Nexus REPL Must Gate Execution on Preflight Acceptance", - "description": "When a non-slash utterance flows through the broker, the Nexus REPL must only invoke the AG2 orchestrator's `run_task` if the preflight decision is `accepted`. For any other decision (`needs_clarification`, `blocked`, `rejected`), the REPL must print the broker's plain-language clarification or rejection and return to the prompt without executing.", - "source": "ARCHITECTURE.md", - "status": "implemented", + "title": "Git Platform Repository Creation", + "description": "Allow specsmith to create repositories on multiple Git platforms with human approval", + "source": "specsmith governance", + "status": "planned", "test_ids": [ "TEST-086" ] @@ -948,10 +948,10 @@ { "id": "REQ-087", "version": 1, - "title": "Nexus REPL Must Drive Execution Through the Bounded-Retry Harness", - "description": "When the preflight decision is `accepted`, the Nexus REPL must drive the AG2 orchestrator through `specsmith.agent.broker.execute_with_governance`, supplying an executor that wraps `orchestrator.run_task` and synthesizes a result dict (`equilibrium`, `confidence`, `summary`). The harness must honor `DEFAULT_RETRY_BUDGET` (REQ-014), surface the single clarifying question on stop-and-align (REQ-063), and never call `run_task` directly outside the harness.", - "source": "ARCHITECTURE.md", - "status": "implemented", + "title": "Git Platform Repository Deletion", + "description": "Allow specsmith to delete repositories on multiple Git platforms with human approval", + "source": "specsmith governance", + "status": "planned", "test_ids": [ "TEST-087" ] @@ -959,10 +959,10 @@ { "id": "REQ-088", "version": 1, - "title": "specsmith preflight Must Resolve Test Case IDs From Machine State", - "description": "The `specsmith preflight` CLI must populate `test_case_ids` in its JSON payload by joining the matched `requirement_ids` against `.specsmith/testcases.json` (or `TESTS.md` when the JSON is unavailable). When the resolved set is non-empty the CLI must include every matching `TEST-NNN` id and must never invent ids not present in machine state.", - "source": "ARCHITECTURE.md", - "status": "implemented", + "title": "Git Platform Repository Cloning", + "description": "Allow specsmith to clone repositories from multiple Git platforms with human approval", + "source": "specsmith governance", + "status": "planned", "test_ids": [ "TEST-088" ] @@ -970,10 +970,10 @@ { "id": "REQ-089", "version": 1, - "title": "Nexus Live l1-nexus Smoke Test", - "description": "Specsmith must ship a `scripts/nexus_smoke.py` script that POSTs a minimal chat-completions request to a running vLLM `l1-nexus` container at `http://localhost:8000/v1/chat/completions` and reports whether the model responded with a well-formed `choices[0].message.content`. A pytest integration test must invoke the script and skip unless the environment variable `NEXUS_LIVE=1` is set, so the suite stays green offline but is verifiable when the container is up.", - "source": "ARCHITECTURE.md", - "status": "implemented", + "title": "Local Command Execution Policy", + "description": "Allow specsmith to execute local commands with a default permissive policy from a local repo standpoint, with configurable whitelists and blacklists", + "source": "specsmith governance", + "status": "planned", "test_ids": [ "TEST-089" ] @@ -981,10 +981,10 @@ { "id": "REQ-090", "version": 1, - "title": "Nexus Documentation Must Describe Broker, Preflight, and Gated Execution", - "description": "`ARCHITECTURE.md`, `README.md`, and `docs/` must describe the natural-language broker (REQ-084), the `specsmith preflight` CLI (REQ-085), the REPL execution gate (REQ-086), and the bounded-retry harness (REQ-087), including the `/why` toggle and an end-to-end example flow. Documentation must not surface REQ/TEST/WI tokens to the user except inside the explicit `/why` block.", - "source": "ARCHITECTURE.md", - "status": "implemented", + "title": "Local Command Whitelist Management", + "description": "Allow specsmith to manage whitelisted commands for local execution with human approval", + "source": "specsmith governance", + "status": "planned", "test_ids": [ "TEST-090" ] @@ -992,10 +992,10 @@ { "id": "REQ-091", "version": 1, - "title": "Orchestrator Must Return a Structured TaskResult", - "description": "`orchestrator.run_task` must return a `TaskResult` dataclass with at least the fields `equilibrium: bool`, `confidence: float`, `summary: str`, `files_changed: list[str]`, and `test_results: dict`. The Nexus REPL's broker branch must consume this dataclass directly when feeding `execute_with_governance` (REQ-087); the broker must not synthesize `equilibrium` from a boolean cast of the summary string.", - "source": "ARCHITECTURE.md", - "status": "implemented", + "title": "Local Command Blacklist Management", + "description": "Allow specsmith to manage blacklisted commands for local execution with human approval", + "source": "specsmith governance", + "status": "planned", "test_ids": [ "TEST-091" ] @@ -1003,10 +1003,10 @@ { "id": "REQ-092", "version": 1, - "title": "specsmith preflight CLI Must Use Decision-Specific Exit Codes", - "description": "The `specsmith preflight` CLI must exit `0` for `accepted`, `2` for `needs_clarification`, and `3` for `blocked` or `rejected` decisions, so CI pipelines and shell wrappers can branch on intent without parsing the JSON payload. The JSON payload must continue to print on stdout for both success and non-zero exits.", - "source": "ARCHITECTURE.md", - "status": "implemented", + "title": "Local Command Override Capability", + "description": "Allow specsmith to override execution policies with human approval, enabling execution of commands not in default policy", + "source": "specsmith governance", + "status": "planned", "test_ids": [ "TEST-092" ] @@ -1014,10 +1014,10 @@ { "id": "REQ-093", "version": 1, - "title": "Accepted preflight Must Record a Ledger Event", - "description": "When `specsmith preflight` produces an `accepted` decision and `LEDGER.md` exists in the project root, the CLI must append a `preflight` ledger event tagged with `REQ-085` plus the resolved `requirement_ids`. The event must record the utterance, the assigned `work_item_id`, and the `confidence_target`, so every accepted preflight is traceable end-to-end.", - "source": "ARCHITECTURE.md", - "status": "implemented", + "title": "Pip Execution Override", + "description": "Allow specsmith to execute pip commands with override capability, using only local pip from the local environment in workspace", + "source": "specsmith governance", + "status": "planned", "test_ids": [ "TEST-093" ] @@ -1025,10 +1025,10 @@ { "id": "REQ-094", "version": 1, - "title": "/why Must Surface Post-Run Governance in the REPL", - "description": "When `verbose_governance` is on (toggled by `/why` or `/show-governance`), after the REPL drives `execute_with_governance` for an accepted utterance it must print a single `[/why]` block summarizing the assigned `work_item_id`, the matched `requirement_ids` and `test_case_ids`, the post-run confidence, and whether the bounded-retry harness reached equilibrium. When verbose mode is off, the post-run governance block must not be emitted.", - "source": "ARCHITECTURE.md", - "status": "implemented", + "title": "Pip Execution Safety Checks", + "description": "When pip execution is overridden, specsmith must warn and ensure only local pip from workspace environment is used", + "source": "specsmith governance", + "status": "planned", "test_ids": [ "TEST-094" ] @@ -1036,10 +1036,10 @@ { "id": "REQ-095", "version": 1, - "title": "Nexus Live Smoke Run Must Be Reproducible Evidence", - "description": "A live or honestly-skipped invocation of `scripts/nexus_smoke.py` must be captured under `.specsmith/runs/WI-NEXUS-011/logs.txt` so the project ledger preserves at least one reproducible record of the broker -> preflight -> orchestrator -> vLLM end-to-end path (or a documented reason the live container could not be reached in the current environment).", - "source": "ARCHITECTURE.md", - "status": "implemented", + "title": "Virtual Environment Creation", + "description": "Allow specsmith to create virtual environments for projects with human approval", + "source": "specsmith governance", + "status": "planned", "test_ids": [ "TEST-095" ] @@ -1047,10 +1047,10 @@ { "id": "REQ-096", "version": 1, - "title": "Bounded-Retry Harness Must Map Failures to Retry Strategies", - "description": "When `execute_with_governance` exhausts its retry budget (REQ-014), it must classify the last executor report against the canonical retry strategy mapping (REQ-028): `narrow_scope`, `expand_scope`, `fix_tests`, `rollback`, or `stop`. The classification must be exposed on `RunResult.strategy` and surfaced in the clarifying question (REQ-063) so the user gets one concrete next-action label rather than only a free-form sentence.", - "source": "ARCHITECTURE.md", - "status": "implemented", + "title": "Virtual Environment Management", + "description": "Allow specsmith to manage virtual environments including activation, deactivation, and cleanup with human approval", + "source": "specsmith governance", + "status": "planned", "test_ids": [ "TEST-096" ] @@ -1058,10 +1058,10 @@ { "id": "REQ-097", "version": 1, - "title": "specsmith verify CLI Subcommand", - "description": "The Specsmith CLI must expose a `specsmith verify` subcommand that consumes the verification input contract (REQ-027): file diffs, test results, execution logs, and changed files (paths or `--stdin` JSON). The subcommand must emit a JSON object with at least `equilibrium`, `confidence`, `summary`, `files_changed`, `test_results`, and `retry_strategy`. Exit code 0 on equilibrium with confidence ≥ the configured threshold, 2 when retry is recommended, and 3 when stop-and-align is required.", - "source": "ARCHITECTURE.md", - "status": "implemented", + "title": "Virtual Environment Validation", + "description": "When creating or using virtual environments, specsmith must validate that they are properly configured and safe to use", + "source": "specsmith governance", + "status": "planned", "test_ids": [ "TEST-097" ] @@ -1069,10 +1069,10 @@ { "id": "REQ-098", "version": 1, - "title": "Confidence Threshold Must Be Read From .specsmith/config.yml", - "description": "Both `specsmith preflight` and the broker's `run_preflight` helper must consult `.specsmith/config.yml` for the `epistemic.confidence_threshold` value (REQ-058) and use it as the floor for the JSON `confidence_target` field whenever it is greater than the heuristic default. When the config file is absent or unparseable, the existing heuristic defaults must continue to apply.", - "source": ".specsmith/config.yml, ARCHITECTURE.md", - "status": "implemented", + "title": "Virtual Environment Warning System", + "description": "When projects attempt to use non-pipx versions of specsmith, specsmith must warn and offer to create new venv if one doesn't exist", + "source": "specsmith governance", + "status": "planned", "test_ids": [ "TEST-098" ] @@ -1080,10 +1080,10 @@ { "id": "REQ-099", "version": 1, - "title": "Accepted Preflight Must Record a Distinct work_proposal Event", - "description": "When `specsmith preflight` produces an `accepted` decision and assigns a brand-new `work_item_id`, the CLI must append a `work_proposal` ledger event in addition to the existing `preflight` event (REQ-044). The `work_proposal` entry must reference REQ-044 and REQ-085, include the `work_item_id` and matched `requirement_ids`, and must NOT be emitted when the underlying `work_item_id` already appears in `LEDGER.md` (no duplicate proposals).", - "source": "ARCHITECTURE.md", - "status": "implemented", + "title": "Local Environment Isolation", + "description": "Specsmith must ensure local command execution is isolated to the project workspace environment with appropriate warnings", + "source": "specsmith governance", + "status": "planned", "test_ids": [ "TEST-099" ] @@ -1091,10 +1091,10 @@ { "id": "REQ-100", "version": 1, - "title": "Broker Scope Inference May Surface Stress-Test Critical Failures", - "description": "When the user passes `--stress` to `specsmith preflight` and the matched requirements set is non-empty, the CLI must invoke the existing AEE `StressTester` against those belief artifacts and surface any critical failures in the JSON payload as a `stress_warnings` list. The narration (verbose mode) must include a one-sentence plain-English warning when at least one critical failure is found. The flag must default off so unrelated tests continue to pass.", - "source": "ARCHITECTURE.md", - "status": "implemented", + "title": "Execution Policy Configuration", + "description": "Allow specsmith to configure execution policies including default permissive mode, whitelists, blacklists, and override rules", + "source": "specsmith governance", + "status": "planned", "test_ids": [ "TEST-100" ] @@ -1102,10 +1102,10 @@ { "id": "REQ-101", "version": 1, - "title": "Lint Baseline Must Be Clean", - "description": "`ruff check src/ tests/` and `ruff format --check src/ tests/` must both exit zero on `develop`. The lint job in `.github/workflows/ci.yml` enforces this contract. Per-file ignores in `pyproject.toml` are reserved for documentation modules whose long lines are intentional (e.g. `toolrules.py`, `tool_installer.py`).", - "source": ".github/workflows/ci.yml, pyproject.toml", - "status": "implemented", + "title": "Playwright Testing Framework", + "description": "Allow specsmith projects to use Playwright for end-to-end browser testing with human approval", + "source": "specsmith governance", + "status": "planned", "test_ids": [ "TEST-101" ] @@ -1113,10 +1113,10 @@ { "id": "REQ-102", "version": 1, - "title": "Type-Check Baseline Must Be Clean", - "description": "`mypy src/specsmith/` must exit zero on `develop`. Strict-mypy is preserved for the historically-typed modules; dynamically-typed modules in `specsmith.agent.*`, `specsmith.console_utils`, `specsmith.serve`, and the agent-orchestrator surface are explicitly enumerated in the `[[tool.mypy.overrides]]` `ignore_errors=true` block of `pyproject.toml` until they are individually annotated.", - "source": ".github/workflows/ci.yml, pyproject.toml", - "status": "implemented", + "title": "Testing Framework Configuration", + "description": "Allow specsmith projects to configure testing frameworks including Playwright, pytest, and others with human approval", + "source": "specsmith governance", + "status": "planned", "test_ids": [ "TEST-102" ] @@ -1124,10 +1124,10 @@ { "id": "REQ-103", "version": 1, - "title": "Security Baseline Tolerates Unfixed pip Advisory", - "description": "The CI security job must upgrade pip to the latest release before invoking `pip-audit`, and must pass the `--ignore-vuln CVE-2026-3219` flag for the unfixed pip advisory so the runner's own pip version does not block PRs. Specsmith's actual runtime dependencies (click, jinja2, pyyaml, pydantic, rich) must remain pip-audit clean; any new advisory against them must trigger a dependency bump rather than another ignore-flag.", - "source": ".github/workflows/ci.yml", - "status": "implemented", + "title": "Testing Environment Isolation", + "description": "Ensure testing environments are properly isolated from development environments with human approval", + "source": "specsmith governance", + "status": "planned", "test_ids": [ "TEST-103" ] @@ -1135,10 +1135,10 @@ { "id": "REQ-104", "version": 1, - "title": "Work Items Must Mirror Implemented REQs", - "description": "`.specsmith/workitems.json` must derive from `.specsmith/requirements.json` and `.specsmith/testcases.json`. For each REQ-N there must be a matching WORK-N entry with `requirement_id=REQ-N`, `test_case_ids` listing every TEST joined by `requirement_id`, and `status=complete` when the REQ is implemented in source. The `scripts/sync_workitems.py` helper is the canonical sync.", - "source": "scripts/sync_workitems.py, .specsmith/workitems.json", - "status": "implemented", + "title": "Testing Artifact Management", + "description": "Allow specsmith projects to manage test artifacts including screenshots, videos, and logs with human approval", + "source": "specsmith governance", + "status": "planned", "test_ids": [ "TEST-104" ] @@ -1146,10 +1146,10 @@ { "id": "REQ-105", "version": 1, - "title": "Live Smoke Evidence Must Be Reproducible Or Honestly Skipped", - "description": "A live or honestly-skipped invocation of `scripts/nexus_smoke.py` against the configured `l1-nexus` model must be captured under `.specsmith/runs/WI-NEXUS-011/logs.txt`. The skip note must include a fresh probe attempt, a timestamp, and the hardware/environment reason the live container could not be reached.", - "source": ".specsmith/runs/WI-NEXUS-011/logs.txt, scripts/nexus_smoke.py", - "status": "implemented", + "title": "Testing Report Generation", + "description": "Allow specsmith projects to automatically generate test reports with human approval", + "source": "specsmith governance", + "status": "planned", "test_ids": [ "TEST-105" ] @@ -1157,10 +1157,10 @@ { "id": "REQ-106", "version": 1, - "title": "Must Surface Governance Commands", - "description": "The terminal client must provide UI access to the three primary governance operations: preflight gate, verify, and governance trace (`/why`). These are surfaced via the Governance settings page and the BYOE proxy at `http://127.0.0.1:7700`.", - "source": "src/specsmith/agent/settings_view/governance_page.py", - "status": "implemented", + "title": "Testing Integration with CI/CD", + "description": "Allow specsmith projects to integrate testing frameworks with CI/CD pipelines with human approval", + "source": "specsmith governance", + "status": "planned", "test_ids": [ "TEST-106" ] @@ -1168,10 +1168,10 @@ { "id": "REQ-107", "version": 1, - "title": "ARCHITECTURE.md Must Reflect Current State", - "description": "`ARCHITECTURE.md` must contain a 'Current State' section listing the realized broker, harness, retry strategies, CI baseline, governance integration, live-smoke evidence note, and documentation surface. The section is the source of truth for 'the system as built' and must be updated each time a release is cut.", - "source": "ARCHITECTURE.md", - "status": "implemented", + "title": "Testing Parallel Execution", + "description": "Allow specsmith projects to execute tests in parallel with human approval", + "source": "specsmith governance", + "status": "planned", "test_ids": [ "TEST-107" ] @@ -1179,10 +1179,10 @@ { "id": "REQ-108", "version": 1, - "title": "Real Verifier Signal Must Drive Confidence", - "description": "`Orchestrator._build_task_result` must derive `TaskResult.confidence` and `equilibrium` from a real verifier (`src/specsmith/agent/verifier.py`) that inspects test results, ruff output, and mypy output for the changed files. The hardcoded 0.85 / 0.4 / 0.0 placeholder must be removed.", - "source": "src/specsmith/agent/verifier.py, src/specsmith/agent/orchestrator.py", - "status": "implemented", + "title": "Testing Coverage Reporting", + "description": "Allow specsmith projects to generate and track test coverage reports with human approval", + "source": "specsmith governance", + "status": "planned", "test_ids": [ "TEST-108" ] @@ -1190,10 +1190,10 @@ { "id": "REQ-109", "version": 1, - "title": "Live `l1-nexus` Smoke Overlay Must Produce ok=true on 7B Hardware", - "description": "Specsmith ships a `docker-compose.smoke.yml` overlay that swaps `l1-nexus` to a 7B GPTQ-Int4 model fitting <=8 GB VRAM, and `.specsmith/runs/WI-NEXUS-029/logs.txt` documents how to capture an `ok: true` smoke result with `NEXUS_LIVE=1` against that overlay.", - "source": "docker-compose.smoke.yml, .specsmith/runs/WI-NEXUS-029/logs.txt", - "status": "implemented", + "title": "WebUI Platform Integration", + "description": "Allow specsmith projects to integrate with WebUI platforms for AI model serving with human approval", + "source": "specsmith governance", + "status": "planned", "test_ids": [ "TEST-109" ] @@ -1201,10 +1201,10 @@ { "id": "REQ-110", "version": 1, - "title": "End-to-End Nexus Path Must Be Integration-Tested", - "description": "`tests/test_e2e_nexus.py` exercises the broker -> preflight -> harness -> orchestrator -> verifier path with a `FakeOrchestrator` and asserts ledger events, `RunResult.success`, and retry-strategy classification on a scripted failure-then-recovery sequence.", - "source": "tests/test_e2e_nexus.py", - "status": "implemented", + "title": "VLLM Platform Integration", + "description": "Allow specsmith projects to integrate with VLLM for large language model serving with human approval", + "source": "specsmith governance", + "status": "planned", "test_ids": [ "TEST-110" ] @@ -1212,10 +1212,10 @@ { "id": "REQ-111", "version": 1, - "title": "Mypy Strict Carveout Must Shrink Toward Zero", - "description": "At least the four newly-annotated dynamic agent modules (`broker`, `safety`, `console_utils`, `indexer`) are fully type-annotated and removed from the `[[tool.mypy.overrides]] ignore_errors=true` block in `pyproject.toml`. The remaining carveout (orchestrator, repl, tools, cleanup, serve) is documented as a 1.x cleanup target.", - "source": "pyproject.toml, src/specsmith/agent/*.py, src/specsmith/console_utils.py", - "status": "implemented", + "title": "LMStudio Platform Integration", + "description": "Allow specsmith projects to integrate with LMStudio for local AI model serving with human approval", + "source": "specsmith governance", + "status": "planned", "test_ids": [ "TEST-111" ] @@ -1223,10 +1223,10 @@ { "id": "REQ-112", "version": 1, - "title": "Streaming Token Bridge Must Emit JSONL Events", - "description": "A new `specsmith chat --json-events` CLI subcommand drives the broker + harness end-to-end and emits a JSONL event stream on stdout with at least the event types `block_start`, `token`, `tool_call`, `tool_result`, `block_complete`, and `task_complete`. Each event is a single JSON object on its own line.", - "source": "src/specsmith/cli.py, src/specsmith/agent/events.py", - "status": "implemented", + "title": "Ollama Platform Integration", + "description": "Allow specsmith projects to integrate with Ollama for local AI model serving with human approval", + "source": "specsmith governance", + "status": "planned", "test_ids": [ "TEST-112" ] @@ -1234,10 +1234,10 @@ { "id": "REQ-113", "version": 1, - "title": "Block-Based Output Schema", - "description": "Every `block_start` event carries a `block_id`, `kind` (one of `plan`, `message`, `tool_call`, `tool_result`, `diff`, `test_results`, `verdict`), `agent`, and `timestamp`. The corresponding `block_complete` reuses the same `block_id`. Schema is documented in `docs/site/chat-events.md`.", - "source": "src/specsmith/agent/events.py, docs/site/chat-events.md", - "status": "implemented", + "title": "OpenTerminal Platform Integration", + "description": "Allow specsmith projects to integrate with OpenTerminal for AI terminal interfaces with human approval", + "source": "specsmith governance", + "status": "planned", "test_ids": [ "TEST-113" ] @@ -1245,10 +1245,10 @@ { "id": "REQ-114", "version": 1, - "title": "Plan Block Must Surface Steps", - "description": "When the broker classifies an utterance as a `change` and preflight is `accepted`, the chat stream must emit a `plan` block whose payload is a list of `{step_id, title, status}` items. Status transitions (`pending` -> `running` -> `done` / `failed`) are emitted as `plan_step` events keyed by `step_id`.", - "source": "src/specsmith/agent/events.py", - "status": "implemented", + "title": "Platform Skill Management", + "description": "Allow specsmith projects to manage skills for different AI platforms with human approval", + "source": "specsmith governance", + "status": "planned", "test_ids": [ "TEST-114" ] @@ -1256,10 +1256,10 @@ { "id": "REQ-115", "version": 1, - "title": "Permission/Autonomy Tier Must Be Honored End-to-End", - "description": "`specsmith chat` accepts `--profile {safe,standard,open,admin}` (default reads `scaffold.yml`). Under `safe`, every tool call emits a `tool_request` event and waits for an inbound `tool_decision` line on stdin (`{decision: 'approve'|'deny'}`). Under `standard` / `open` the harness proceeds without prompting. The selected profile is recorded in the ledger entry.", - "source": "src/specsmith/cli.py, src/specsmith/profiles.py", - "status": "implemented", + "title": "Platform Configuration Management", + "description": "Allow specsmith projects to configure AI platform settings and parameters with human approval", + "source": "specsmith governance", + "status": "planned", "test_ids": [ "TEST-115" ] @@ -1267,10 +1267,10 @@ { "id": "REQ-116", "version": 1, - "title": "Inline Diff Review Must Round-Trip Comments", - "description": "`specsmith chat` emits a `diff` block per file changed by the orchestrator; subsequent stdin lines of the form `{type: 'comment', block_id, path, line, body}` are stored in the session memory and surfaced to the bounded-retry harness as additional context on the next attempt. `--comment` flag on `specsmith verify` does the equivalent for non-streaming use.", - "source": "src/specsmith/agent/events.py, src/specsmith/cli.py", - "status": "implemented", + "title": "Platform Resource Management", + "description": "Allow specsmith projects to manage platform resources including memory, GPU, and compute with human approval", + "source": "specsmith governance", + "status": "planned", "test_ids": [ "TEST-116" ] @@ -1278,10 +1278,10 @@ { "id": "REQ-117", "version": 1, - "title": "Predict-Only Preflight Must Not Allocate a Work Item", - "description": "`specsmith preflight --predict-only --json` returns the same JSON shape as the canonical `preflight` (intent, requirement_ids, instruction, etc.) but with `work_item_id == ''`, no ledger event written, and a new `predicted_refinement` field that suggests a tightened utterance. Used by IDE autocomplete.", - "source": "src/specsmith/cli.py", - "status": "implemented", + "title": "Platform Security Controls", + "description": "Ensure AI platform integrations follow security best practices with human approval", + "source": "specsmith governance", + "status": "planned", "test_ids": [ "TEST-117" ] @@ -1289,10 +1289,10 @@ { "id": "REQ-118", "version": 1, - "title": "Must Surface specsmith chat Stream", - "description": "The governance proxy (`/v1/chat/completions`) consumes the `specsmith chat --json-events` JSONL stream and exposes it to the agent session.", - "source": "src/specsmith/agent/settings_view/governance_page.py", - "status": "implemented", + "title": "Platform Monitoring and Logging", + "description": "Allow specsmith projects to monitor and log AI platform activities with human approval", + "source": "specsmith governance", + "status": "planned", "test_ids": [ "TEST-118" ] @@ -4444,5 +4444,105 @@ "test_ids": [ "TEST-461" ] + }, + { + "id": "REQ-446", + "version": 1, + "title": "Epistemic chat condensation and agent handoff", + "description": "Specsmith shall safely condense chat/session context into provenance-preserving ESDB artifacts that retain source identifiers, confidence, uncertainty, unresolved decisions, active work items, and validation status; reject or flag unsupported claims; restore usable context after compaction; and export/import a portable handoff envelope interoperable with Specsmith agents and Zoo-Code.", + "source": "docs/requirements/", + "status": "implemented", + "test_ids": [ + "TEST-462" + ] + }, + { + "id": "REQ-447", + "version": 1, + "title": "Git-safe ESDB session persistence", + "description": "Specsmith shall store session and ESDB history in a deterministic, append-friendly, text-based canonical representation that can be merged across branches without lost or duplicated events; local SQLite databases and WAL sidecars shall be derived caches that can be rebuilt safely with validated schema, integrity, and recovery reporting.", + "source": "docs/requirements/", + "status": "implemented", + "test_ids": [ + "TEST-463", + "TEST-471" + ] + }, + { + "id": "REQ-448", + "version": 1, + "title": "Windows launcher resolution diagnostics", + "description": "On Windows, Specsmith shall detect multiple or shadowed specsmith executables, report the active executable and package version, provide safe pipx-focused remediation, and support PowerShell stderr redirection without a launcher failure.", + "source": "docs/requirements/", + "status": "implemented", + "test_ids": [ + "TEST-464" + ] + }, + { + "id": "REQ-449", + "version": 1, + "title": "Reachable version-mismatch recovery", + "description": "When a project requires a newer development or prerelease Specsmith version than the stable channel provides, Specsmith shall diagnose the channel mismatch, provide an exact supported pipx remediation command, and distinguish it from a normal stable upgrade without permitting backward migration.", + "source": "docs/requirements/", + "status": "implemented", + "test_ids": [ + "TEST-465" + ] + }, + { + "id": "REQ-450", + "version": 1, + "title": "Stable release channel integrity", + "description": "Specsmith release automation shall reject PEP 440 development, prerelease, and local versions before stable PyPI upload, publish such artifacts only through an explicit development channel, and verify the stable install and upgrade path in CI.", + "source": "docs/requirements/", + "status": "implemented", + "test_ids": [ + "TEST-466" + ] + }, + { + "id": "REQ-451", + "version": 1, + "title": "Contained work-item persistence paths", + "description": "Specsmith shall normalize every work-item persistence path with os.path.realpath, reject values outside the project root before filesystem access, and provide the same containment behavior on Windows, Linux, and macOS.", + "source": "docs/requirements/", + "status": "implemented", + "test_ids": [ + "TEST-467" + ] + }, + { + "id": "REQ-452", + "version": 1, + "title": "CodeQL-clean report rendering", + "description": "Specsmith shall render quality reports without CodeQL implicit string concatenation findings while preserving the report content and formatting.", + "source": "docs/requirements/", + "status": "implemented", + "test_ids": [ + "TEST-468" + ] + }, + { + "id": "REQ-453", + "version": 1, + "title": "Release candidate quality gates", + "description": "Before release, Specsmith shall pass strict linting, formatting, type checking, the complete test suite, strict documentation build, runtime dependency audit, and governance audit without unresolved issues.", + "source": "CI, release workflow, and release validation", + "status": "implemented", + "test_ids": [ + "TEST-469" + ] + }, + { + "id": "REQ-454", + "version": 1, + "title": "Single-branch workflow default", + "description": "Specsmith shall default new projects to a single-branch workflow on the configured default branch, refuse branch creation until a different branching strategy is explicitly enabled through specsmith, and preserve GitFlow, trunk-based, and GitHub-flow behavior after opt-in.", + "source": "Git workflow governance", + "status": "implemented", + "test_ids": [ + "TEST-470" + ] } ] \ No newline at end of file diff --git a/.specsmith/testcases.json b/.specsmith/testcases.json index b5d97551..1f552489 100644 --- a/.specsmith/testcases.json +++ b/.specsmith/testcases.json @@ -4990,5 +4990,125 @@ "input": {}, "expected_behavior": {}, "confidence": 1.0 + }, + { + "id": "TEST-462", + "version": 1, + "title": "Validate epistemic chat handoff and Zoo-Code export", + "description": "Verify extractive source IDs, ESDB persistence, context compaction, and portable Zoo-Code export.", + "requirement_id": "REQ-446", + "type": "integration", + "verification_method": "pytest tests/test_chat_handoff.py", + "input": {}, + "expected_behavior": {}, + "confidence": 1.0 + }, + { + "id": "TEST-463", + "version": 1, + "title": "Merge and rebuild canonical ESDB session events", + "description": "Verify divergent event histories replay without loss or duplicate events and rebuild local SQLite state.", + "requirement_id": "REQ-447", + "type": "integration", + "verification_method": "pytest tests/test_session_store.py", + "input": {}, + "expected_behavior": {}, + "confidence": 1.0 + }, + { + "id": "TEST-464", + "version": 1, + "title": "Diagnose Windows launcher shadowing and redirected stderr", + "description": "Verify duplicate executable diagnostics and PowerShell-compatible launcher behavior.", + "requirement_id": "REQ-448", + "type": "cli", + "verification_method": "pytest tests/test_windows_launcher.py tests/test_migrations_skill_shell.py", + "input": {}, + "expected_behavior": {}, + "confidence": 1.0 + }, + { + "id": "TEST-465", + "version": 1, + "title": "Offer reachable development-version recovery", + "description": "Verify version mismatch diagnostics provide exact pipx recovery guidance without allowing downgrade.", + "requirement_id": "REQ-449", + "type": "cli", + "verification_method": "pytest tests/test_updater.py", + "input": {}, + "expected_behavior": {}, + "confidence": 1.0 + }, + { + "id": "TEST-466", + "version": 1, + "title": "Reject non-stable versions from stable release publishing", + "description": "Verify PEP 440 dev prerelease and local versions cannot enter the stable release workflow.", + "requirement_id": "REQ-450", + "type": "build", + "verification_method": "pytest tests/test_release_guard.py", + "input": {}, + "expected_behavior": {}, + "confidence": 1.0 + }, + { + "id": "TEST-467", + "version": 1, + "title": "Reject work-item persistence paths outside project root", + "description": "Verify normalized work-item state and file paths cannot escape the supplied project root.", + "requirement_id": "REQ-451", + "type": "unit", + "verification_method": "pytest tests/test_wi_lifecycle.py", + "input": {}, + "expected_behavior": {}, + "confidence": 1.0 + }, + { + "id": "TEST-468", + "version": 1, + "title": "Render quality report footer without implicit concatenation", + "description": "Verify the generated footer retains its expected report content while the renderer remains CodeQL-clean.", + "requirement_id": "REQ-452", + "type": "unit", + "verification_method": "pytest tests/test_quality_report.py", + "input": {}, + "expected_behavior": {}, + "confidence": 1.0 + }, + { + "id": "TEST-469", + "version": 1, + "title": "Verify release candidate quality gates", + "description": "Verify every local and CI release-candidate quality gate passes without lint, type, test, documentation, dependency-security, or governance failures.", + "requirement_id": "REQ-453", + "type": "build", + "verification_method": "ruff check src/ tests/ && ruff format --check src/ tests/ && mypy src/specsmith/ && pytest --cov=specsmith --cov-report=term-missing && mkdocs build --strict && pip-audit && specsmith audit --project-dir .", + "input": {}, + "expected_behavior": {}, + "confidence": 1.0 + }, + { + "id": "TEST-470", + "version": 1, + "title": "Enforce and configure the single-branch default", + "description": "Verify single-branch is the default, branch creation is refused until an explicit workflow selection, and specsmith can enable GitFlow or another configured strategy.", + "requirement_id": "REQ-454", + "type": "cli", + "verification_method": "pytest tests/test_branch_workflow.py", + "input": {}, + "expected_behavior": {}, + "confidence": 1.0 + }, + { + "id": "TEST-471", + "version": 1, + "title": "Preserve canonical ESDB state when saving a governed Git worktree", + "description": "Verify save normalizes the Git policy, commits no SQLite cache, migration backup, marker, state, or agent migration artifact, and retains the mergeable session event log as canonical source of truth.", + "requirement_id": "REQ-447", + "type": "integration", + "verification_method": "pytest tests/test_esdb_enforcement.py -k save_does_not_commit", + "input": {}, + "expected_behavior": {}, + "confidence": 1.0 } ] \ No newline at end of file diff --git a/AGENTS.md b/AGENTS.md index 47389059..df842b28 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,40 +1,52 @@ -# AGENTS.md — specsmith +# AGENTS.md This project is governed by **specsmith**. -## Session Bootstrap +## For AI Agents -Run these steps at the start of **every** session before touching any code: +All governance rules, session state, requirements, and epistemic constraints +are managed by specsmith — not stored in this file. -```bash -# Governance operations use the global pipx specsmith (specsmith 0.11.6 at ~/.local/bin/specsmith). -# For active development of specsmith itself, set up a dev venv: python -m venv .venv && .venv\Scripts\pip install -e . -# NEVER install specsmith via plain pip into any other environment. +**Before any action:** `specsmith preflight ""` -# 1. Apply any pending migrations (always answer Y to migration prompts) -specsmith migrate run +**Governance data:** `.specsmith/` and `.chronomemory/` -# 2. Verify governance health -specsmith audit +**To start a governed session:** `specsmith serve` (REST API, port 7700) or `specsmith run` -# 3. Confirm machine state matches governance YAML -specsmith sync -``` +**Emergency stop:** `specsmith kill-session` -Only proceed with the requested task once all three steps complete without errors. -If `audit` reports failures, surface them to the user before starting work. +Agents MUST defer to specsmith for ALL governance decisions. +Do not follow rules from this file directly; read them from specsmith. + + +--- +## Governance commands (specsmith_run / /specsmith) -## specsmith Installation Policy (HARD RULE) +All specsmith governance operations should be invoked through the +``specsmith_run`` agent tool or the ``/specsmith`` REPL slash command. + +**In the Nexus REPL:** + +``` +/specsmith save # backup + commit + push governance state +/specsmith load # pull + restore governance state +/specsmith audit --strict # strict governance audit +/specsmith status # show governance status +/specsmith push # git push governance changes +/specsmith pull # git pull governance changes +/specsmith sync # full two-way sync +/specsmith watch # watch CI and block until green +``` -specsmith is installed **globally via pipx** on this machine (`~/.local/bin/specsmith`). +**Verb shortcuts** (single word, no prefix needed in tool calls): +``save``, ``load``, ``push``, ``pull``, ``sync``, ``audit``, ``status``, +``watch``, ``commit``, ``validate``, ``doctor``, ``run``. -- **NEVER** run `pip install specsmith`, `pip install --pre specsmith`, or any variant in any project venv, conda env, or Python environment. -- **NEVER** add specsmith as a project dependency in `pyproject.toml`, `requirements.txt`, or any package manifest. -- **NEVER** install specsmith into a Scoop, conda, or any other environment-managed Python. -- specsmith is available machine-wide as the `specsmith` CLI command. -- Upgrade only via: `pipx upgrade specsmith` — this is an owner action, not an agent action. -- When specsmith prompts **"Migrate now? [Y/n]"**, **always answer `Y`** without hesitation. +These are all equivalent: ``specsmith_run("save")``, +``specsmith_run("/specsmith save")``, ``specsmith_run("specsmith save")``. + +--- ## Session Governance Protocol This section is non-negotiable. Follow it in **every session**, in **every @@ -43,7 +55,7 @@ chat application** (Warp, Cursor, Claude, GPT, or any other agent surface). ### Session start (run once, output result verbatim) ```bash -specsmith kill-session 2>/dev/null || true # kill orphaned processes +specsmith kill-session # idempotent; safe when no processes exist specsmith audit --project-dir . # verify governance health specsmith sync --project-dir . # confirm machine state specsmith checkpoint --project-dir . # emit GOVERNANCE ANCHOR @@ -98,94 +110,13 @@ specsmith kill-session # stop governance-serve and tracked processes Never end a session with uncommitted governance changes. +### Quick reference -## GitHub Operations - -Use **`gh` CLI** (GitHub CLI) as the **first and preferred** tool for all GitHub operations — -issues, PRs, releases, code scanning alerts, and repository data. - -**MCP GitHub server is last resort only** — use it only when `gh` CLI genuinely cannot do the task. - -```bash -gh issue list --state open -gh pr list --state open -gh api repos/{owner}/{repo}/code-scanning/alerts --jq '[.[] | select(.state=="open")]' -gh release create v1.0.0 dist/* --generate-notes -``` - -## Code Quality Gate - -Before **any** commit, both checks MUST pass with zero violations: - -```bash -ruff check src/ tests/ # linting — zero violations required -ruff format --check src/ tests/ # formatting — zero violations required -``` - -Never suppress a `ruff` violation with `# noqa` unless it is a documented false positive. -When using `# noqa`, always include the rule code and a one-line explanation: - -```python -except Exception: # noqa: BLE001 # intentional: fire-and-forget cleanup; log is written above -``` - -## CodeQL Safe Patterns - -Follow these patterns to keep CodeQL (security + quality scanning) alerts at zero: - -**Path sanitization** — always use `os.path.realpath()`, never `Path.resolve()`: -```python -import os -# CORRECT — CodeQL recognises os.path.realpath() as a taint sanitizer -safe_path = os.path.realpath(str(user_input)) - -# WRONG — CodeQL does NOT recognise Path.resolve() as a sanitizer -safe_path = Path(user_input).resolve() # triggers py/path-injection -``` - -**Import discipline** — no inline `import X` when `from X import Y` exists at module level: -```python -from specsmith.compliance import ComplianceChecker # module-level ← fine - -def my_test(): - import specsmith.compliance as c # WRONG: triggers py/import-and-import-from -``` - -**Empty except blocks** — always add comment + `# noqa: BLE001`: -```python -# CORRECT -except Exception: # noqa: BLE001 # intentional: ... - pass - -# WRONG — bare empty except triggers CodeQL empty-except alert -except Exception: - pass -``` - -## YAML-First Governance (Current Mode) - -Requirements live in `docs/requirements/*.yml`; tests in `docs/tests/*.yml`. Edit YAML files, run `specsmith sync`, commit both YAML + JSON. `REQUIREMENTS.md` / `TESTS.md` are deprecated. To migrate from markdown mode: `specsmith migrate run && specsmith sync && specsmith audit`. - -## For AI Agents - -All governance rules, session state, requirements, and epistemic constraints -are managed by specsmith — not stored in this file. - -**Before any action:** `specsmith preflight ""` - -**Governance data:** `.specsmith/` and `.chronomemory/` - -**To start a governed session:** `specsmith serve` or `specsmith run` - -**Emergency stop:** `specsmith kill-session` - -Agents MUST defer to specsmith for ALL governance decisions. -Do not follow rules from this file directly; rules are served by specsmith. - ---- - -**Project:** specsmith -**Type:** CLI tool (Python) + AEE library -**Platforms:** Windows, Linux, macOS -**Phase:** run `specsmith phase` to check readiness - +| When | Command | +|---|---| +| Session start | `specsmith audit && specsmith sync && specsmith checkpoint` | +| Before any code change | `specsmith preflight "" --json` | +| Every 8–10 turns | `specsmith checkpoint` (output verbatim) | +| Context summary | Checkpoint output at top | +| Session end | `specsmith save && specsmith kill-session` | +| Drift detected | `specsmith checkpoint` immediately | diff --git a/CHANGELOG.md b/CHANGELOG.md index df8f2bb2..631256a0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,7 +22,15 @@ consolidated into the next published release. - CI matrix: Python 3.10-3.13 fully green - _read_project_name in quality_report.py now uses tomllib → tomli → regex fallback chain so pyproject.toml is parsed correctly on Python 3.10 --- ## [Unreleased] + +## [0.22.0] - 2026-07-10 ### Added +- Epistemic chat handoffs (REQ-446) - Tiered context compaction now creates + extractive, provenance-linked ESDB handoffs that Zoo-Code and other agents can export. +- Mergeable session event log (REQ-447) - `.chronomemory/session-events.jsonl` + is the canonical, reviewable session continuity artifact; SQLite is local derived state. +- Stable-release guard (REQ-450) - the release workflow rejects development, + prerelease, and local versions before the PyPI upload step. - ESDB-first dual-write architecture (REQ-403..416) - Every governance event now writes to ESDB alongside the append-only LEDGER.md - `specsmith inspect` command (REQ-409) - Session-start command that emits a bordered governance block with audit health, active work items, ESDB EFF-CURRENT efficiency stats, and epistemic quality breakdown - M010 post-ESDB cleanup migration - Removes legacy files superseded by YAML+ESDB governance @@ -30,6 +38,8 @@ consolidated into the next published release. - 142 new agent/REPL/benchmark tests ### Changed +- Version mismatch recovery now prints a pinned pipx command when a project + requires a development build that the stable channel cannot supply (REQ-449). - Markdown governance mode deprecated - Running `specsmith sync` in markdown mode now emits a DeprecationWarning and auto-triggers m007 migration - Auditor YAML dir checks are mode-aware - The yaml-requirements-dir and yaml-tests-dir audit checks now only fail for projects in YAML-first mode - `specsmith architect` is now a group command - `specsmith architect` (without a subcommand) retains its original behavior, new subcommands `interview`, `gap`, and `update` are added diff --git a/README.md b/README.md index d0e46e24..28c1a66e 100644 --- a/README.md +++ b/README.md @@ -48,6 +48,27 @@ We ran a [multi-condition benchmark](https://specsmith.readthedocs.io/en/stable/ **Key findings:** specsmith FULL is the only condition to achieve 100% pass rate on the feature-addition task (T1). It uses 2.6× fewer tokens than ungoverned and produces a cost-of-pass 3.2× lower than the next-best alternative. With gpt-5.5, governance reduces cost-of-pass by **6.3×** ($0.028 vs $0.179). +## Current Stats + +- **52+ model profiles** in registry (including Qwen3.6-35B-A3B) +- **127 canonical skills** available across all domains +- **10 governance skills** (including improvement-reporter, agent-flow-controller, model-runtime-optimizer) +- **Development mode** with improvement tracking and session analysis + +See the [full benchmark report](https://specsmith.readthedocs.io/en/stable/efficiency-benchmark/) and [model comparison (gpt-4o-mini vs gpt-5.5)](https://specsmith.readthedocs.io/en/stable/model-comparison/). + +### Development Mode Features + +When enabled in project configuration, development mode provides: + +- **Enhanced logging** for all agent interactions and decision-making processes +- **Session analysis** that tracks what worked, what didn't, and improvement suggestions +- **Cost-per-correct-solution metrics** to measure efficiency +- **Automated improvement tracking** to identify patterns and areas for optimization +- **Session reports** that can be generated for review and analysis + +To enable development mode, set `enable_development_mode: true` in your project's `.specsmith/config.yml` file. + See the [full benchmark report](https://specsmith.readthedocs.io/en/stable/efficiency-benchmark/) and [model comparison (gpt-4o-mini vs gpt-5.5)](https://specsmith.readthedocs.io/en/stable/model-comparison/). **v0.21.0** - CPU fallback for local model detection: When no GPU is detected, Specsmith now falls back to a minimal CPU-safe model instead of returning no recommendation (REQ-445). Also includes all v0.20.0 features. @@ -1056,6 +1077,16 @@ specsmith skill install specsmith-audit Skills are installed as `.agents/skills//SKILL.md` and are auto-discovered by any AI tool that scans `.agents/skills/`. +### Skill Policy + +If a skill is reusable across projects, it belongs in `src/specsmith/skills/.py`. + +If a skill is project-specific, generated by the user, or experimental, it belongs in `.specsmith/skills//`. + +If a skill needs to be read by Claude Code, Warp, Cursor, Aider, etc., it is exported/materialized into `.agents/skills//SKILL.md`. + +Do not hand-edit `.agents/skills/` as a canonical source. + ### Skill domains | Domain | Count | Coverage | diff --git a/ROADMAP.md b/ROADMAP.md deleted file mode 100644 index 837441fc..00000000 --- a/ROADMAP.md +++ /dev/null @@ -1,35 +0,0 @@ -# Specsmith Public Roadmap -Specsmith is currently focused on maturing the v0.x governance CLI into a stable, widely-adopted foundation for governed agentic development. - -## Current focus (v0.x governance CLI) -- Stabilize core governance flows (`audit`, `preflight`, `verify`, `sync`, `checkpoint`). -- Improve onboarding and docs for AI clients (Warp/Oz, Claude Code, Cursor, Copilot, Aider, Windsurf). -- Expand project templates, MCP configs, and import paths for existing ecosystems. -- Continue dogfooding specsmith on the specsmith repository itself. - -## Next release targets -- Better comparative and migration docs for adjacent governance frameworks. -- Expanded examples for common project archetypes (CLI, API, frontend, library, regulated). -- More robust MCP integration documentation and known-edge-case playbooks. -- Continued hardening of ESDB and audit reconstruction workflows. - -## v1.0 criteria -- Stable public API surface with explicit compatibility commitments. -- Full first-party agent integration coverage across major coding agents. -- Compliance export suitable for internal and external audit evidence packages. -- 500+ tests with broad cross-platform and governance-path coverage. - -## Planned integrations -- Richer MCP client interoperability docs and validation scripts. -- Additional import/migration stubs for ecosystem frameworks. -- Expanded CI and release automation guidance for governed projects. - -## Non-goals -- Replacing all existing project management tools. -- Forcing a single development methodology for every team. -- Marketing-driven feature expansion without traceability or governance fit. - -## Experimental areas -- Lightweight governance modes for low-ceremony teams. -- Advanced multi-agent dispatch patterns with stronger recovery semantics. -- Expanded evidence-chain tooling for regulated environments. diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index 34e9c339..50267cb8 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -1025,6 +1025,16 @@ The **AGENTS.md template** (REQ-355) includes a conditional Codity section: proj **Architecture invariant (I15):** The VCS-detection heuristic MUST default to `"github"` when no signals are present (scaffold.yml absent, no `.gitlab-ci.yml`, no `azure-pipelines.yml`). New VCS hosts require a new detection heuristic AND a corresponding workflow writer method. +## 39. Skill Policy + +If a skill is reusable across projects, it belongs in `src/specsmith/skills/.py`. + +If a skill is project-specific, generated by the user, or experimental, it belongs in `.specsmith/skills//`. + +If a skill needs to be read by Claude Code, Warp, Cursor, Aider, etc., it is exported/materialized into `.agents/skills//SKILL.md`. + +Do not hand-edit `.agents/skills/` as a canonical source. + ## 40. Migration Direction Enforcement Source: `src/specsmith/cli.py` (`_maybe_prompt_project_update`, `_AutoUpdateGroup.invoke`); `src/specsmith/upgrader.py` (`run_upgrade`); `src/specsmith/updater.py` (`run_migration`); `src/specsmith/templates/agents.md.j2` diff --git a/docs/DEPRECATIONS.md b/docs/DEPRECATIONS.md index bdc26a21..8b673e9c 100644 --- a/docs/DEPRECATIONS.md +++ b/docs/DEPRECATIONS.md @@ -72,10 +72,12 @@ Each entry lists: ### `.specsmith/session-state.json` and `.specsmith/conversation-history.jsonl` — session continuity - **Sites:** `src/specsmith/session_store.py` (module docstring, `save_session`). -- **Superseded by:** _no ESDB equivalent yet._ -- **Status:** legacy flat files; runtime/session-resume only (gitignored). -- **Teardown:** future REQ — model session state as ESDB session records, then - drop these files. +- **Superseded by:** `.chronomemory/session-events.jsonl` (REQ-447), with local + SQLite `session_event` records rebuilt from that canonical text log. +- **Status:** dual-written for backward compatibility. The canonical event log + is Git-reviewable, deduplicated by immutable event ID, and replayed first. +- **Teardown:** remove the flat-file fallback after the next compatible major + release confirms every supported client can replay canonical session events. ### `.specsmith/esdb_migration_manifest.json` — one-shot migration scan - **Sites:** `src/specsmith/cli.py` (`esdb migrate` scan), `src/specsmith/sync.py` diff --git a/docs/LEDGER.md b/docs/LEDGER.md index d956581b..74ad1052 100644 --- a/docs/LEDGER.md +++ b/docs/LEDGER.md @@ -315,3 +315,105 @@ - **Status**: complete - **Epistemic status**: high - **Chain hash**: `cf98c08d1f8ceb46...` + +## 2026-07-10T18:38 — KILL SWITCH ACTIVATED: emergency stop +- **Author**: specsmith-operator +- **Type**: kill-switch +- **REQs affected**: REG-005 +- **Status**: complete +- **Epistemic status**: high +- **Chain hash**: `faaf06ea12574c6a...` + +## 2026-07-13T07:33 — KILL SWITCH ACTIVATED: emergency stop +- **Author**: specsmith-operator +- **Type**: kill-switch +- **REQs affected**: REG-005 +- **Status**: complete +- **Epistemic status**: high +- **Chain hash**: `07ad8108e3860a7c...` + +## 2026-07-13T10:30 — KILL SWITCH ACTIVATED: emergency stop +- **Author**: specsmith-operator +- **Type**: kill-switch +- **REQs affected**: REG-005 +- **Status**: complete +- **Epistemic status**: high +- **Chain hash**: `b864898ee975ecce...` + +## 2026-07-13T11:12 — KILL SWITCH ACTIVATED: emergency stop +- **Author**: specsmith-operator +- **Type**: kill-switch +- **REQs affected**: REG-005 +- **Status**: complete +- **Epistemic status**: high +- **Chain hash**: `b960aeeee661d07c...` + +## 2026-07-13T11:23 — KILL SWITCH ACTIVATED: emergency stop +- **Author**: specsmith-operator +- **Type**: kill-switch +- **REQs affected**: REG-005 +- **Status**: complete +- **Epistemic status**: high +- **Chain hash**: `82c26ea54d1780a8...` + +## 2026-07-13T11:31 — wi_archive WI-2B89DD4E: Deferred: governance requires the user to explicitly confirm deletion of refs/heads/feat/zoo-roo-mcp-integration. +- **Author**: specsmith +- **Type**: wi_archive +- **Status**: complete +- **Chain hash**: `050e3319e536e818...` + +## 2026-07-13T11:31 — wi_archive WI-0DA3685B: Deferred: governance requires the user to explicitly confirm deletion of refs/heads/feat/zoo-roo-mcp-integration. +- **Author**: specsmith +- **Type**: wi_archive +- **Status**: complete +- **Chain hash**: `7aca009cad3ae1a1...` + +## 2026-07-13T11:31 — wi_archive WI-71E9EDBB: Deferred: GitHub rejects authors approving their own protected pull request; an independent code owner is required. +- **Author**: specsmith +- **Type**: wi_archive +- **Status**: complete +- **Chain hash**: `f2361802e838e239...` + +## 2026-07-13T11:32 — wi_close WI-094C4FE3: Published archive/feat-zoo-roo-mcp-integration-20260713 at the closed branch head after verification. +- **Author**: specsmith +- **Type**: wi_close +- **Status**: complete +- **Chain hash**: `b19ddba9a15b5658...` + +## 2026-07-13T14:38 — KILL SWITCH ACTIVATED: emergency stop +- **Author**: specsmith-operator +- **Type**: kill-switch +- **REQs affected**: REG-005 +- **Status**: complete +- **Epistemic status**: high +- **Chain hash**: `0fcf05a9931e039e...` + +## 2026-07-13T14:42 — KILL SWITCH ACTIVATED: emergency stop +- **Author**: specsmith-operator +- **Type**: kill-switch +- **REQs affected**: REG-005 +- **Status**: complete +- **Epistemic status**: high +- **Chain hash**: `1d6d373b06cfc948...` + +## 2026-07-13T14:59 — KILL SWITCH ACTIVATED: emergency stop +- **Author**: specsmith-operator +- **Type**: kill-switch +- **REQs affected**: REG-005 +- **Status**: complete +- **Epistemic status**: high +- **Chain hash**: `c16a7c48273e40f7...` + +## 2026-07-13T15:14 — test-ran TEST-467: passed (status: pending → implemented) +- **Author**: specsmith +- **Type**: test-ran +- **REQs affected**: TEST-467 +- **Status**: complete +- **Chain hash**: `15ebd5761b79a512...` + +## 2026-07-13T15:14 — test-ran TEST-470: passed (status: pending → implemented) +- **Author**: specsmith +- **Type**: test-ran +- **REQs affected**: TEST-470 +- **Status**: complete +- **Chain hash**: `3b3775a522076719...` diff --git a/docs/REQUIREMENTS_GAP_REPORT.md b/docs/REQUIREMENTS_GAP_REPORT.md deleted file mode 100644 index c080ec83..00000000 --- a/docs/REQUIREMENTS_GAP_REPORT.md +++ /dev/null @@ -1,57 +0,0 @@ -# Requirements & Architecture Completeness Gap Report -Date: 2026-06-28 -Scope scanned: `src/specsmith/`, `docs/requirements/*.yml`, `docs/tests/*.yml` -## 1) Feature inventory (major modules) -Top-level module families discovered in `src/specsmith/`: -- Root modules (`src/specsmith/*.py`): 75 files (CLI, governance, sync, migrations orchestration, VCS helpers, session/runtime management) -- `agent/`: 39 files (broker, orchestration, dispatch DAG/events, routing, permissions, tools, safety) -- `commands/`: 3 files (intelligence/issues/reporting command helpers) -- `compliance/`: 5 files (checker/evidence/reporter/regulations) -- `datasources/`: 8 files (citation + patent/publication datasource adapters) -- `epistemic/`: 5 files (belief/certainty/recovery/stress modeling) -- `esdb/`: 3 files (bridge/sqlite store/licensing) -- `eval/`: 2 files (evaluation runners/builtins) -- `gui/`: 11 files (desktop UI app/window/widgets/worker) -- `integrations/`: 9 files (aider/copilot/cursor/gemini/windsurf/claude adapters) -- `migrations/`: 11 files (m001–m010 + runner) -- `skills/`: 17 files (domain skill catalogs) -- `vcs/`: 4 files (GitHub/GitLab/Bitbucket integrations) -## 2) Features without explicit REQ coverage (and suggested REQ stubs) -Coverage check was performed by matching feature/module intents against requirement titles/descriptions across `docs/requirements/*.yml`. -Likely missing explicit REQ coverage: -- Datasource adapter layer (`src/specsmith/datasources/*`) - Suggested REQ title: **Datasource adapters must define retrieval contracts, resilience behavior, and citation normalization guarantees** -- GUI surface (`src/specsmith/gui/*`) - Suggested REQ title: **GUI commands and views must provide governed parity with core CLI state and error semantics** -- External IDE/tool integrations (`src/specsmith/integrations/*`) - Suggested REQ title: **Integration adapters must implement a uniform capability and error-handling contract** -- Plugin lifecycle surface (`specsmith plugin` command + plugin plumbing) - Suggested REQ title: **Plugin management must define install/list/remove and compatibility validation requirements** -## 3) REQs without tests (status = planned|implemented) -Cross-reference result (`requirement_id` in `docs/tests/*.yml`): -- **0 REQs** with zero tests. -- Every `planned` or `implemented` REQ currently has at least one TEST entry. -## 4) Planned REQs not yet implemented in `src/specsmith/` (backlog) -`planned` REQs reviewed for concrete implementation presence in `src/specsmith/`: -- `REQ-423` Governed benchmark agents must achieve 100% pass rate across all tasks/conditions -- `REQ-424` CI pipeline must produce zero CodeQL static analysis alerts on every run -- `REQ-425` Governed agents must autonomously resolve preflight needs_clarification without blocking -- `REQ-426` Benchmark harness completion token budget must allow reasoning models to produce tool calls -- `REQ-427` GovernanceBench metrics/report statistical and leaderboard outputs -Notes: -- These are benchmark/CI/harness-oriented and appear primarily script/pipeline scoped rather than fully implemented as core `src/specsmith/` runtime behavior. -- `REQ-428` through `REQ-431` have corresponding implementation signals in core modules (`sync.py`, `cli.py`, `governance_logic.py`) but are still marked `planned`. -## 5) CLI command coverage gaps (`src/specsmith/cli.py`) -Scanned all `@main.command(name=...)` entries (47 commands total). Non-trivial commands with no explicit REQ match in requirements titles/descriptions: -- `plugin` -- `pr` -- `ps` -Suggested REQ titles: -- **CLI plugin command must define governance-safe plugin lifecycle operations** -- **CLI pr command must define governed pull-request creation/update behavior** -- **CLI ps command must define active session/process listing semantics** -## 6) Test-stub additions for uncovered REQs -Requested action: add up to 15 missing TEST stubs for existing uncovered REQs. -Result: -- **0 TEST stubs added**, because no `planned|implemented` REQ lacked test linkage. -- Highest existing TEST ID observed during scan: `TEST-445`. diff --git a/docs/governance/CONTEXT-BUDGET.md b/docs/governance/CONTEXT-BUDGET.md new file mode 100644 index 00000000..f0343afa --- /dev/null +++ b/docs/governance/CONTEXT-BUDGET.md @@ -0,0 +1,40 @@ +# Context Budget Management + +This document defines how context windows are managed within the specsmith governance framework. + +## Context Window Policies + +### GPU-Aware Context Sizing +- Context windows are sized based on available GPU memory +- When no GPU is detected, fallback to CPU-safe defaults +- VRAM-aware model recommendations are provided + +### Context Budget Allocation +- Each session maintains a context budget +- Context usage is tracked and reported +- Context compression is applied when necessary +- Hard context ceiling prevents 100% full contexts + +## Context Management Rules + +1. **Context Awareness**: All agents must be aware of their context window limitations +2. **Budget Tracking**: Context usage is tracked throughout the session +3. **Compression**: Automatic context compression when approaching limits +4. **Fallback**: Safe fallback strategies when context is exceeded + +## Context Window Management + +### Live Context Fill Indicator +- Real-time indicator of context usage +- Warning when approaching limits +- Automatic compression when necessary + +### Auto Context Compression +- Intelligent compression of context when needed +- Preservation of critical information +- Maintains effectiveness while reducing size + +### Hard Context Ceiling +- Never allow context to reach 100% full +- Maintain buffer for new information +- Prevent overflow conditions diff --git a/docs/governance/DRIFT-METRICS.md b/docs/governance/DRIFT-METRICS.md new file mode 100644 index 00000000..4d182373 --- /dev/null +++ b/docs/governance/DRIFT-METRICS.md @@ -0,0 +1,44 @@ +# Drift Metrics + +This document defines the metrics used to detect and measure governance drift in specsmith projects. + +## Drift Detection + +### What Constitutes Drift +- Changes that bypass governance procedures +- Actions that violate established rules +- Modifications that break traceability +- Deviations from documented processes + +### Drift Indicators +1. **Requirement Drift**: Changes to requirements without proper traceability +2. **Test Coverage Drift**: Missing or incomplete test coverage +3. **Audit Trail Drift**: Incomplete or missing audit logs +4. **Compliance Drift**: Violations of governance rules or policies + +## Drift Metrics + +### Quantitative Metrics +- **Requirement-to-Test Coverage**: Percentage of requirements with test coverage +- **Audit Trail Completeness**: Percentage of actions with complete audit trails +- **Compliance Rate**: Percentage of actions compliant with governance rules +- **Drift Events**: Count of detected drift incidents + +### Qualitative Metrics +- **Traceability Quality**: Quality of links between requirements and test cases +- **Evidence Quality**: Quality of audit trail evidence +- **Process Adherence**: Adherence to documented governance processes +- **Session Integrity**: Overall integrity of governance sessions + +## Drift Prevention + +### Real-time Monitoring +- Continuous monitoring of governance compliance +- Real-time alerts for potential drift +- Automated drift detection mechanisms + +### Drift Response +- Immediate investigation of drift events +- Corrective actions for detected drift +- Process improvements based on drift patterns +- Training updates for governance violations diff --git a/docs/governance/LIFECYCLE.md b/docs/governance/LIFECYCLE.md new file mode 100644 index 00000000..379d2222 --- /dev/null +++ b/docs/governance/LIFECYCLE.md @@ -0,0 +1,28 @@ +# Work Item Lifecycle + +This document defines the lifecycle of work items in specsmith governance. + +## Work Item States + +1. **Planned** - Work item is proposed but not yet started +2. **In Progress** - Work item is actively being worked on +3. **Completed** - Work item has been finished and verified +4. **Closed** - Work item is closed (mapped to an existing requirement) +5. **Archived** - Work item is abandoned or deferred + +## Work Item Management + +### Creating Work Items +- Work items are created through the `specsmith wi create` command +- Each work item must have a clear description and associated requirements +- Work items are tracked in the LEDGER.md file + +### Managing Work Items +- Work items can be promoted to formal requirements using `specsmith wi promote` +- Work items can be linked to test cases using `specsmith wi link-test` +- Work items can be closed or archived using `specsmith wi close` or `specsmith wi archive` + +### Work Item Tracking +- All work items are tracked in the LEDGER.md file +- Work items are linked to requirements and test cases +- Work items maintain a complete audit trail of changes diff --git a/docs/governance/ROLES.md b/docs/governance/ROLES.md new file mode 100644 index 00000000..fcafd531 --- /dev/null +++ b/docs/governance/ROLES.md @@ -0,0 +1,51 @@ +# Governance Roles + +This document defines the roles and responsibilities within the specsmith governance framework. + +## Core Roles + +### Agent +- An AI agent that interacts with the specsmith system +- Must comply with all governance rules and policies +- Responsible for executing tasks according to specsmith's governance framework + +### Developer +- A human developer working within the specsmith framework +- Responsible for creating and managing work items +- Must follow all governance procedures and compliance requirements + +### Auditor +- Responsible for verifying compliance with governance rules +- Reviews all changes and decisions for adherence to requirements +- Ensures proper traceability between requirements and test cases + +### Maintainer +- Responsible for maintaining the specsmith codebase +- Ensures all changes follow governance protocols +- Manages the release process and version control + +## Role Responsibilities + +### Agent Responsibilities +- Follow all preflight gates before executing commands +- Maintain audit trails of all actions +- Comply with context window management policies +- Disclose all AI-generated content + +### Developer Responsibilities +- Create and manage work items properly +- Ensure all changes are traceable to requirements +- Participate in compliance reviews +- Follow the work item lifecycle process + +### Auditor Responsibilities +- Verify compliance with governance rules +- Review audit logs and decision trails +- Ensure proper requirement-to-test traceability +- Report any governance violations + +### Maintainer Responsibilities +- Maintain the specsmith codebase and documentation +- Ensure all changes are properly governed +- Manage releases and version control +- Keep governance documentation up to date diff --git a/docs/governance/RULES.md b/docs/governance/RULES.md new file mode 100644 index 00000000..bfdc863e --- /dev/null +++ b/docs/governance/RULES.md @@ -0,0 +1,18 @@ +# Governance Rules + +This file contains the core rules that govern how specsmith operates and enforces compliance. + +## Core Principles + +1. **Governance First**: All changes must go through specsmith's governance layer before being applied +2. **Traceability**: Every change must be traceable to a requirement or test case +3. **Evidence Quality**: All decisions must be cryptographically sealed with audit trails +4. **Agent Compliance**: All AI agents must comply with the defined governance rules +5. **Session Integrity**: Each session maintains a consistent governance state + +## Rule Enforcement + +- All commands must pass preflight checks before execution +- Changes must be reviewed and approved through the work item lifecycle +- Audit logs are maintained for all governance decisions +- Compliance is enforced at runtime through policy gates diff --git a/docs/governance/SESSION-PROTOCOL.md b/docs/governance/SESSION-PROTOCOL.md new file mode 100644 index 00000000..5de57932 --- /dev/null +++ b/docs/governance/SESSION-PROTOCOL.md @@ -0,0 +1,50 @@ +# Session Protocol + +This document defines the session protocol that specsmith follows to ensure consistent governance across all development sessions. + +## Session Lifecycle + +1. **Session Start** + - Kill any orphaned processes + - Verify governance health + - Confirm machine state matches governance YAML + - Emit governance anchor + +2. **Session Execution** + - All commands must pass preflight checks + - Changes are tracked through work items + - Audit logs are maintained for all actions + +3. **Session End** + - Save governance state + - Commit changes with governance-aware message + - Push to remote repository + +## Governance Enforcement + +- All commands are subject to preflight gates +- Agent actions are monitored and audited +- Compliance checks are performed at each step +- Session integrity is maintained throughout + +## Session Bootstrap + +Run these steps at the start of **every** session before touching any code: + +```bash +# Governance operations use the global pipx specsmith (specsmith 0.11.6 at ~/.local/bin/specsmith). +# For active development of specsmith itself, set up a dev venv: python -m venv .venv && .venv\Scripts\pip install -e . +# NEVER install specsmith via plain pip into any other environment. + +# 1. Apply any pending migrations (always answer Y to migration prompts) +specsmith migrate run + +# 2. Verify governance health +specsmith audit + +# 3. Confirm machine state matches governance YAML +specsmith sync +``` + +Only proceed with the requested task once all three steps complete without errors. +If `audit` reports failures, surface them to the user before starting work. diff --git a/docs/governance/VERIFICATION.md b/docs/governance/VERIFICATION.md new file mode 100644 index 00000000..7d68ef25 --- /dev/null +++ b/docs/governance/VERIFICATION.md @@ -0,0 +1,49 @@ +# Verification Procedures + +This document outlines the verification procedures that ensure specsmith governance is properly enforced. + +## Verification Requirements + +### Pre-flight Verification +- All commands must pass preflight checks before execution +- Agent actions must comply with governance rules +- Context window limits must be respected +- Audit logs must be maintained + +### Post-execution Verification +- Changes must be traceable to requirements +- Test coverage must be verified +- Compliance checks must pass +- Audit trails must be complete + +## Verification Processes + +### Requirement Verification +- All requirements must have test coverage +- Traceability between requirements and test cases must be maintained +- Requirement changes must be properly documented + +### Test Verification +- All tests must be executed and pass +- Test coverage must meet minimum thresholds +- Test results must be recorded in the audit trail + +### Compliance Verification +- All actions must comply with governance rules +- Agent behavior must be monitored and audited +- Evidence quality must be maintained +- Session integrity must be preserved + +## Verification Tools + +### specsmith verify +- Run verification checks on the project +- Check for duplicate IDs, orphans, coverage gaps +- Validate governance YAML files +- Ensure all requirements have test coverage + +### specsmith audit +- Run drift and health checks +- Verify governance health +- Check for any compliance violations +- Ensure machine state matches governance YAML diff --git a/docs/requirements/agent.yml b/docs/requirements/agent.yml index 9d18e614..b714f033 100644 --- a/docs/requirements/agent.yml +++ b/docs/requirements/agent.yml @@ -5,32 +5,35 @@ # Schema: id (REQ-NNN), title, description, source, status # Required fields: id, title, status - id: REQ-065 - title: WI Lifecycle States - description: 'Every Work Item must move through a defined set of states: open, implemented, - promoted, closed, archived, rejected. The allowed transitions are enforced by - WorkItemStore.' - source: wi_store.py - status: implemented + title: GitHub Release Creation + description: Allow specsmith to create GitHub releases for tagged versions with + human approval + source: specsmith governance + status: planned + test_coverage: true + approval_required: true - id: REQ-066 - title: WI-to-REQ Promotion - description: A Work Item in the open or implemented state may be promoted to a formal - requirement via specsmith wi promote, which creates a new REQ-NNN entry in the - target requirements YAML and records promoted_to_req on the WI. - source: wi_store.py - status: implemented + title: PyPI Deployment + description: Allow specsmith to trigger PyPI package deployment with human approval + source: specsmith governance + status: planned + test_coverage: true + approval_required: true - id: REQ-067 - title: WI Status Persistence - description: Work Item state is persisted to .specsmith/workitems.json using an - atomic write (write-then-rename) so crashes never leave the store corrupt. - source: wi_store.py - status: implemented + title: CI Management + description: Allow specsmith to manage CI workflows with human approval + source: specsmith governance + status: planned + test_coverage: true + approval_required: true - id: REQ-068 - title: WI Auto-Implementation on Verify Equilibrium - description: When specsmith verify reaches equilibrium for a given work_item_id, - the WI is automatically transitioned from open to implemented. This wiring is - best-effort and never blocks the verify result. - source: governance_logic.py - status: implemented + title: Pull Request Management + description: Allow specsmith to manage PRs, merges, and issue creation with human + approval + source: specsmith governance + status: planned + test_coverage: true + approval_required: true - id: REQ-069 title: WI Kind Classification description: Every Work Item carries a kind field (feature, bug, chore, spike, refactor, @@ -45,414 +48,387 @@ source: ARCHITECTURE.md status: implemented - id: REQ-071 - title: Nexus Must Index the Repository - description: Nexus must populate .repo-index/ with files.json, tags, test_commands.json, - architecture.md, and conventions.md as available. - source: ARCHITECTURE.md - status: implemented + title: Release Notes Generation + description: Allow specsmith to automatically generate release notes from commit + history with human approval + source: specsmith governance + status: planned + test_coverage: true + approval_required: true - id: REQ-072 - title: Nexus REPL Must Support Slash Commands - description: The Nexus REPL must support /plan, /ask, /fix, /test, /commit, /pr, - /undo, /context, /exit. - source: ARCHITECTURE.md - status: implemented + title: Release Tag Management + description: Allow specsmith to manage release tags including creation, deletion, + and modification with human approval + source: specsmith governance + status: planned + test_coverage: true + approval_required: true - id: REQ-073 - title: Nexus Output Contract - description: Each Nexus task response must include sections Plan, Commands to run, - Files changed, Diff, Test results, and Next action. - source: ARCHITECTURE.md - status: implemented + title: Artifact Management + description: Allow specsmith to manage release artifacts including uploads, downloads, + and cleanup with human approval + source: specsmith governance + status: planned + test_coverage: true + approval_required: true - id: REQ-074 - title: vLLM Image Must Be Pinned - description: The Nexus docker-compose.yml must pin the vLLM image to a specific - tag (vllm/vllm-openai:v0.8.5) and not use latest. - source: ARCHITECTURE.md - status: implemented + title: Release Branch Management + description: Allow specsmith to manage release branches including creation, merging, + and deletion with human approval + source: specsmith governance + status: planned + test_coverage: true + approval_required: true - id: REQ-075 - title: vLLM Must Serve l1-nexus Model - description: The Nexus docker-compose.yml must publish the served model as l1-nexus - and use the Hermes tool-call parser. - source: ARCHITECTURE.md - status: implemented + title: Release Validation + description: Allow specsmith to perform automated validation checks before release + creation with human approval + source: specsmith governance + status: planned + test_coverage: true + approval_required: true - id: REQ-076 - title: Nexus Tool Executor Registration Must Be Unique - description: Each Nexus tool must be registered with the AG2 executor exactly once; - LLM-side tool signatures may be attached to multiple caller agents but the execution - function must not be re-registered to avoid AG2 override warnings. - source: ARCHITECTURE.md - status: implemented + title: Release Rollback + description: Allow specsmith to rollback to previous releases with human approval + source: specsmith governance + status: planned + test_coverage: true + approval_required: true - id: REQ-077 - title: Safe Cleanup Must Default to Dry-Run - description: The Specsmith safe-cleanup capability must default to dry-run mode - and only delete files when an explicit apply flag is provided. - source: ARCHITECTURE.md - status: implemented + title: Release Promotion + description: Allow specsmith to promote releases between environments (dev, staging, + prod) with human approval + source: specsmith governance + status: planned + test_coverage: true + approval_required: true - id: REQ-078 - title: Safe Cleanup Must Use a Hard-Coded Target List - description: Safe cleanup must only consider the canonical built-in target list - and must reject user-supplied arbitrary paths. - source: ARCHITECTURE.md - status: implemented + title: Release Metadata Management + description: Allow specsmith to manage release metadata including version, date, + and author information with human approval + source: specsmith governance + status: planned + test_coverage: true + approval_required: true - id: REQ-079 - title: Safe Cleanup Must Protect Governance and Source - description: Safe cleanup must refuse to delete .git, .specsmith, governance markdown - files, pyproject.toml, README.md, LICENSE, CHANGELOG.md, src/, tests/, docs/, - scripts/, .repo-index/, .github/, .vscode/, third-party agent integration directories - (such as .agents/), and project configuration dotfiles. - source: ARCHITECTURE.md - status: implemented + title: Git Platform Agnostic Management + description: Allow specsmith to manage Git repositories across multiple platforms + (GitHub, GitLab, Bitbucket, etc.) with human approval + source: specsmith governance + status: planned + test_coverage: true + approval_required: true - id: REQ-080 - title: Safe Cleanup Must Emit a Structured Report - description: Safe cleanup must return a report containing the lists of removed paths, - skipped paths with reasons, and total bytes reclaimed, suitable for inclusion - as ledger evidence. - source: ARCHITECTURE.md - status: implemented + title: GitHub Platform Management + description: Allow specsmith to manage GitHub repositories, issues, pull requests, + and releases with human approval + source: specsmith governance + status: planned + test_coverage: true + approval_required: true - id: REQ-081 - title: Safe Cleanup Must Be Exposed via Specsmith CLI - description: The Specsmith CLI must expose the safe cleanup capability as `specsmith - clean`, supporting `--apply`, `--json`, and `--project-dir`. When `--apply` is - used and `LEDGER.md` exists, the run must be recorded as a `cleanup` ledger event - tagged with REQ-077..REQ-080. - source: ARCHITECTURE.md - status: implemented + title: GitLab Platform Management + description: Allow specsmith to manage GitLab repositories, issues, merge requests, + and releases with human approval + source: specsmith governance + status: planned + test_coverage: true + approval_required: true - id: REQ-082 - title: CLI Console Must Be UTF-8 Safe Across Platforms - description: All Specsmith CLI output (rich Console) must render UTF-8 glyphs (such - as warning, arrow, check, cross) without raising UnicodeEncodeError on Windows - code pages such as cp1252. The console factory must reconfigure stdout/stderr - to UTF-8 and disable rich's legacy_windows renderer. - source: ARCHITECTURE.md - status: implemented + title: Bitbucket Platform Management + description: Allow specsmith to manage Bitbucket repositories, issues, pull requests, + and releases with human approval + source: specsmith governance + status: planned + test_coverage: true + approval_required: true - id: REQ-083 - title: Canonical Test Specification File Is TESTS.md - description: The canonical test specification file is named `TESTS.md` (replacing - the legacy names `TESTS.md`, `TEST-SPEC.md`, and `TEST-SPECS.md`). Specsmith code, - governance documents, templates, scaffolder output, importer overlay, auditor - checks, retrieval index, exporter, validator, REPL skill files, ReadTheDocs site, - and CLI help must all reference `TESTS.md`. Legacy filenames must not be created - by new scaffolds, must be auto-renamed by `specsmith migrate-project`, and must - not be referenced in user-facing docs. - source: ARCHITECTURE.md - status: implemented + title: Azure DevOps Platform Management + description: Allow specsmith to manage Azure DevOps repositories, issues, pull requests, + and releases with human approval + source: specsmith governance + status: planned + test_coverage: true + approval_required: true - id: REQ-084 - title: Natural-Language Governance Broker - description: Specsmith must expose a Nexus broker module (`specsmith.agent.broker`) - that translates plain-language user utterances into Specsmith-governed work without - the user reasoning about REQ IDs, TEST IDs, or work items. The broker must classify - intent (read-only ask vs change vs release), infer affected scope from the local - `.repo-index` and existing requirements, invoke `specsmith preflight` and `specsmith - verify` as the only sources of governance decisions, render plain-language plans - and outcomes, hide REQ/TEST/work-item IDs by default (revealed only on `/why`, - `/show-governance`, or `--verbose`), bound retries per REQ-014, escalate to a - single user clarification on stop-and-align (REQ-063), and never invent governance - content (REQ/TEST drafting requires explicit user confirmation). - source: ARCHITECTURE.md - status: implemented + title: Git Platform Authentication Management + description: Allow specsmith to manage authentication credentials for multiple Git + platforms with human approval + source: specsmith governance + status: planned + test_coverage: true + approval_required: true - id: REQ-085 - title: specsmith preflight CLI Subcommand - description: The Specsmith CLI must expose a `specsmith preflight ` subcommand - that reads `REQUIREMENTS.md` and `.specsmith/` state, classifies intent and infers - scope, and emits a JSON object with at least the keys `decision` (one of `accepted`, - `needs_clarification`, `blocked`, `rejected`), `work_item_id`, `requirement_ids`, - `test_case_ids`, `confidence_target`, and `instruction`. Read-only asks accept - by default, destructive intents require clarification, and changes with no matching - scope return `needs_clarification` with a one-sentence question. The CLI must - support `--project-dir`, `--json`, and `--verbose`. - source: ARCHITECTURE.md - status: implemented + title: Git Platform Configuration Management + description: Allow specsmith to configure platform-specific settings and webhooks + for multiple Git platforms with human approval + source: specsmith governance + status: planned + test_coverage: true + approval_required: true - id: REQ-086 - title: Nexus REPL Must Gate Execution on Preflight Acceptance - description: When a non-slash utterance flows through the broker, the Nexus REPL - must only invoke the AG2 orchestrator's `run_task` if the preflight decision is - `accepted`. For any other decision (`needs_clarification`, `blocked`, `rejected`), - the REPL must print the broker's plain-language clarification or rejection and - return to the prompt without executing. - source: ARCHITECTURE.md - status: implemented + title: Git Platform Repository Creation + description: Allow specsmith to create repositories on multiple Git platforms with + human approval + source: specsmith governance + status: planned + test_coverage: true + approval_required: true - id: REQ-087 - title: Nexus REPL Must Drive Execution Through the Bounded-Retry Harness - description: When the preflight decision is `accepted`, the Nexus REPL must drive - the AG2 orchestrator through `specsmith.agent.broker.execute_with_governance`, - supplying an executor that wraps `orchestrator.run_task` and synthesizes a result - dict (`equilibrium`, `confidence`, `summary`). The harness must honor `DEFAULT_RETRY_BUDGET` - (REQ-014), surface the single clarifying question on stop-and-align (REQ-063), - and never call `run_task` directly outside the harness. - source: ARCHITECTURE.md - status: implemented + title: Git Platform Repository Deletion + description: Allow specsmith to delete repositories on multiple Git platforms with + human approval + source: specsmith governance + status: planned + test_coverage: true + approval_required: true - id: REQ-088 - title: specsmith preflight Must Resolve Test Case IDs From Machine State - description: The `specsmith preflight` CLI must populate `test_case_ids` in its - JSON payload by joining the matched `requirement_ids` against `.specsmith/testcases.json` - (or `TESTS.md` when the JSON is unavailable). When the resolved set is non-empty - the CLI must include every matching `TEST-NNN` id and must never invent ids not - present in machine state. - source: ARCHITECTURE.md - status: implemented + title: Git Platform Repository Cloning + description: Allow specsmith to clone repositories from multiple Git platforms with + human approval + source: specsmith governance + status: planned + test_coverage: true + approval_required: true - id: REQ-089 - title: Nexus Live l1-nexus Smoke Test - description: Specsmith must ship a `scripts/nexus_smoke.py` script that POSTs a - minimal chat-completions request to a running vLLM `l1-nexus` container at `http://localhost:8000/v1/chat/completions` - and reports whether the model responded with a well-formed `choices[0].message.content`. - A pytest integration test must invoke the script and skip unless the environment - variable `NEXUS_LIVE=1` is set, so the suite stays green offline but is verifiable - when the container is up. - source: ARCHITECTURE.md - status: implemented + title: Local Command Execution Policy + description: Allow specsmith to execute local commands with a default permissive + policy from a local repo standpoint, with configurable whitelists and blacklists + source: specsmith governance + status: planned + test_coverage: true + approval_required: true - id: REQ-090 - title: Nexus Documentation Must Describe Broker, Preflight, and Gated Execution - description: '`ARCHITECTURE.md`, `README.md`, and `docs/` must describe the natural-language - broker (REQ-084), the `specsmith preflight` CLI (REQ-085), the REPL execution - gate (REQ-086), and the bounded-retry harness (REQ-087), including the `/why` - toggle and an end-to-end example flow. Documentation must not surface REQ/TEST/WI - tokens to the user except inside the explicit `/why` block.' - source: ARCHITECTURE.md - status: implemented + title: Local Command Whitelist Management + description: Allow specsmith to manage whitelisted commands for local execution + with human approval + source: specsmith governance + status: planned + test_coverage: true + approval_required: true - id: REQ-091 - title: Orchestrator Must Return a Structured TaskResult - description: '`orchestrator.run_task` must return a `TaskResult` dataclass with - at least the fields `equilibrium: bool`, `confidence: float`, `summary: str`, - `files_changed: list[str]`, and `test_results: dict`. The Nexus REPL''s broker - branch must consume this dataclass directly when feeding `execute_with_governance` - (REQ-087); the broker must not synthesize `equilibrium` from a boolean cast of - the summary string.' - source: ARCHITECTURE.md - status: implemented + title: Local Command Blacklist Management + description: Allow specsmith to manage blacklisted commands for local execution + with human approval + source: specsmith governance + status: planned + test_coverage: true + approval_required: true - id: REQ-092 - title: specsmith preflight CLI Must Use Decision-Specific Exit Codes - description: The `specsmith preflight` CLI must exit `0` for `accepted`, `2` for - `needs_clarification`, and `3` for `blocked` or `rejected` decisions, so CI pipelines - and shell wrappers can branch on intent without parsing the JSON payload. The - JSON payload must continue to print on stdout for both success and non-zero exits. - source: ARCHITECTURE.md - status: implemented + title: Local Command Override Capability + description: Allow specsmith to override execution policies with human approval, + enabling execution of commands not in default policy + source: specsmith governance + status: planned + test_coverage: true + approval_required: true - id: REQ-093 - title: Accepted preflight Must Record a Ledger Event - description: When `specsmith preflight` produces an `accepted` decision and `LEDGER.md` - exists in the project root, the CLI must append a `preflight` ledger event tagged - with `REQ-085` plus the resolved `requirement_ids`. The event must record the - utterance, the assigned `work_item_id`, and the `confidence_target`, so every - accepted preflight is traceable end-to-end. - source: ARCHITECTURE.md - status: implemented + title: Pip Execution Override + description: Allow specsmith to execute pip commands with override capability, using + only local pip from the local environment in workspace + source: specsmith governance + status: planned + test_coverage: true + approval_required: true - id: REQ-094 - title: /why Must Surface Post-Run Governance in the REPL - description: When `verbose_governance` is on (toggled by `/why` or `/show-governance`), - after the REPL drives `execute_with_governance` for an accepted utterance it must - print a single `[/why]` block summarizing the assigned `work_item_id`, the matched - `requirement_ids` and `test_case_ids`, the post-run confidence, and whether the - bounded-retry harness reached equilibrium. When verbose mode is off, the post-run - governance block must not be emitted. - source: ARCHITECTURE.md - status: implemented + title: Pip Execution Safety Checks + description: When pip execution is overridden, specsmith must warn and ensure only + local pip from workspace environment is used + source: specsmith governance + status: planned + test_coverage: true + approval_required: true - id: REQ-095 - title: Nexus Live Smoke Run Must Be Reproducible Evidence - description: A live or honestly-skipped invocation of `scripts/nexus_smoke.py` must - be captured under `.specsmith/runs/WI-NEXUS-011/logs.txt` so the project ledger - preserves at least one reproducible record of the broker -> preflight -> orchestrator - -> vLLM end-to-end path (or a documented reason the live container could not be - reached in the current environment). - source: ARCHITECTURE.md - status: implemented + title: Virtual Environment Creation + description: Allow specsmith to create virtual environments for projects with human + approval + source: specsmith governance + status: planned + test_coverage: true + approval_required: true - id: REQ-096 - title: Bounded-Retry Harness Must Map Failures to Retry Strategies - description: 'When `execute_with_governance` exhausts its retry budget (REQ-014), - it must classify the last executor report against the canonical retry strategy - mapping (REQ-028): `narrow_scope`, `expand_scope`, `fix_tests`, `rollback`, or - `stop`. The classification must be exposed on `RunResult.strategy` and surfaced - in the clarifying question (REQ-063) so the user gets one concrete next-action - label rather than only a free-form sentence.' - source: ARCHITECTURE.md - status: implemented + title: Virtual Environment Management + description: Allow specsmith to manage virtual environments including activation, + deactivation, and cleanup with human approval + source: specsmith governance + status: planned + test_coverage: true + approval_required: true - id: REQ-097 - title: specsmith verify CLI Subcommand - description: 'The Specsmith CLI must expose a `specsmith verify` subcommand that - consumes the verification input contract (REQ-027): file diffs, test results, - execution logs, and changed files (paths or `--stdin` JSON). The subcommand must - emit a JSON object with at least `equilibrium`, `confidence`, `summary`, `files_changed`, - `test_results`, and `retry_strategy`. Exit code 0 on equilibrium with confidence - ≥ the configured threshold, 2 when retry is recommended, and 3 when stop-and-align - is required.' - source: ARCHITECTURE.md - status: implemented + title: Virtual Environment Validation + description: When creating or using virtual environments, specsmith must validate + that they are properly configured and safe to use + source: specsmith governance + status: planned + test_coverage: true + approval_required: true - id: REQ-098 - title: Confidence Threshold Must Be Read From .specsmith/config.yml - description: Both `specsmith preflight` and the broker's `run_preflight` helper - must consult `.specsmith/config.yml` for the `epistemic.confidence_threshold` - value (REQ-058) and use it as the floor for the JSON `confidence_target` field - whenever it is greater than the heuristic default. When the config file is absent - or unparseable, the existing heuristic defaults must continue to apply. - source: .specsmith/config.yml, ARCHITECTURE.md - status: implemented + title: Virtual Environment Warning System + description: When projects attempt to use non-pipx versions of specsmith, specsmith + must warn and offer to create new venv if one doesn't exist + source: specsmith governance + status: planned + test_coverage: true + approval_required: true - id: REQ-099 - title: Accepted Preflight Must Record a Distinct work_proposal Event - description: When `specsmith preflight` produces an `accepted` decision and assigns - a brand-new `work_item_id`, the CLI must append a `work_proposal` ledger event - in addition to the existing `preflight` event (REQ-044). The `work_proposal` entry - must reference REQ-044 and REQ-085, include the `work_item_id` and matched `requirement_ids`, - and must NOT be emitted when the underlying `work_item_id` already appears in - `LEDGER.md` (no duplicate proposals). - source: ARCHITECTURE.md - status: implemented + title: Local Environment Isolation + description: Specsmith must ensure local command execution is isolated to the project + workspace environment with appropriate warnings + source: specsmith governance + status: planned + test_coverage: true + approval_required: true - id: REQ-100 - title: Broker Scope Inference May Surface Stress-Test Critical Failures - description: When the user passes `--stress` to `specsmith preflight` and the matched - requirements set is non-empty, the CLI must invoke the existing AEE `StressTester` - against those belief artifacts and surface any critical failures in the JSON payload - as a `stress_warnings` list. The narration (verbose mode) must include a one-sentence - plain-English warning when at least one critical failure is found. The flag must - default off so unrelated tests continue to pass. - source: ARCHITECTURE.md - status: implemented + title: Execution Policy Configuration + description: Allow specsmith to configure execution policies including default permissive + mode, whitelists, blacklists, and override rules + source: specsmith governance + status: planned + test_coverage: true + approval_required: true - id: REQ-101 - title: Lint Baseline Must Be Clean - description: '`ruff check src/ tests/` and `ruff format --check src/ tests/` must - both exit zero on `develop`. The lint job in `.github/workflows/ci.yml` enforces - this contract. Per-file ignores in `pyproject.toml` are reserved for documentation - modules whose long lines are intentional (e.g. `toolrules.py`, `tool_installer.py`).' - source: .github/workflows/ci.yml, pyproject.toml - status: implemented + title: Playwright Testing Framework + description: Allow specsmith projects to use Playwright for end-to-end browser testing + with human approval + source: specsmith governance + status: planned + test_coverage: true + approval_required: true - id: REQ-102 - title: Type-Check Baseline Must Be Clean - description: '`mypy src/specsmith/` must exit zero on `develop`. Strict-mypy is - preserved for the historically-typed modules; dynamically-typed modules in `specsmith.agent.*`, - `specsmith.console_utils`, `specsmith.serve`, and the agent-orchestrator surface - are explicitly enumerated in the `[[tool.mypy.overrides]]` `ignore_errors=true` - block of `pyproject.toml` until they are individually annotated.' - source: .github/workflows/ci.yml, pyproject.toml - status: implemented + title: Testing Framework Configuration + description: Allow specsmith projects to configure testing frameworks including + Playwright, pytest, and others with human approval + source: specsmith governance + status: planned + test_coverage: true + approval_required: true - id: REQ-103 - title: Security Baseline Tolerates Unfixed pip Advisory - description: The CI security job must upgrade pip to the latest release before invoking - `pip-audit`, and must pass the `--ignore-vuln CVE-2026-3219` flag for the unfixed - pip advisory so the runner's own pip version does not block PRs. Specsmith's actual - runtime dependencies (click, jinja2, pyyaml, pydantic, rich) must remain pip-audit - clean; any new advisory against them must trigger a dependency bump rather than - another ignore-flag. - source: .github/workflows/ci.yml - status: implemented + title: Testing Environment Isolation + description: Ensure testing environments are properly isolated from development + environments with human approval + source: specsmith governance + status: planned + test_coverage: true + approval_required: true - id: REQ-104 - title: Work Items Must Mirror Implemented REQs - description: '`.specsmith/workitems.json` must derive from `.specsmith/requirements.json` - and `.specsmith/testcases.json`. For each REQ-N there must be a matching WORK-N - entry with `requirement_id=REQ-N`, `test_case_ids` listing every TEST joined by - `requirement_id`, and `status=complete` when the REQ is implemented in source. - The `scripts/sync_workitems.py` helper is the canonical sync.' - source: scripts/sync_workitems.py, .specsmith/workitems.json - status: implemented + title: Testing Artifact Management + description: Allow specsmith projects to manage test artifacts including screenshots, + videos, and logs with human approval + source: specsmith governance + status: planned + test_coverage: true + approval_required: true - id: REQ-105 - title: Live Smoke Evidence Must Be Reproducible Or Honestly Skipped - description: A live or honestly-skipped invocation of `scripts/nexus_smoke.py` against - the configured `l1-nexus` model must be captured under `.specsmith/runs/WI-NEXUS-011/logs.txt`. - The skip note must include a fresh probe attempt, a timestamp, and the hardware/environment - reason the live container could not be reached. - source: .specsmith/runs/WI-NEXUS-011/logs.txt, scripts/nexus_smoke.py - status: implemented + title: Testing Report Generation + description: Allow specsmith projects to automatically generate test reports with + human approval + source: specsmith governance + status: planned + test_coverage: true + approval_required: true - id: REQ-106 - title: Must Surface Governance Commands - description: 'The terminal client must provide UI access to the three primary - governance operations: preflight gate, verify, and governance trace (`/why`). - These are surfaced via the Governance settings page and the BYOE proxy at `http://127.0.0.1:7700`.' - source: src/specsmith/agent/settings_view/governance_page.py - status: implemented + title: Testing Integration with CI/CD + description: Allow specsmith projects to integrate testing frameworks with CI/CD + pipelines with human approval + source: specsmith governance + status: planned + test_coverage: true + approval_required: true - id: REQ-107 - title: ARCHITECTURE.md Must Reflect Current State - description: '`ARCHITECTURE.md` must contain a ''Current State'' section listing - the realized broker, harness, retry strategies, CI baseline, governance - integration, live-smoke evidence note, and documentation surface. The section - is the source of truth for ''the system as built'' and must be updated each time - a release is cut.' - source: ARCHITECTURE.md - status: implemented + title: Testing Parallel Execution + description: Allow specsmith projects to execute tests in parallel with human approval + source: specsmith governance + status: planned + test_coverage: true + approval_required: true - id: REQ-108 - title: Real Verifier Signal Must Drive Confidence - description: '`Orchestrator._build_task_result` must derive `TaskResult.confidence` - and `equilibrium` from a real verifier (`src/specsmith/agent/verifier.py`) that - inspects test results, ruff output, and mypy output for the changed files. The - hardcoded 0.85 / 0.4 / 0.0 placeholder must be removed.' - source: src/specsmith/agent/verifier.py, src/specsmith/agent/orchestrator.py - status: implemented + title: Testing Coverage Reporting + description: Allow specsmith projects to generate and track test coverage reports + with human approval + source: specsmith governance + status: planned + test_coverage: true + approval_required: true - id: REQ-109 - title: Live `l1-nexus` Smoke Overlay Must Produce ok=true on 7B Hardware - description: 'Specsmith ships a `docker-compose.smoke.yml` overlay that swaps `l1-nexus` - to a 7B GPTQ-Int4 model fitting <=8 GB VRAM, and `.specsmith/runs/WI-NEXUS-029/logs.txt` - documents how to capture an `ok: true` smoke result with `NEXUS_LIVE=1` against - that overlay.' - source: docker-compose.smoke.yml, .specsmith/runs/WI-NEXUS-029/logs.txt - status: implemented + title: WebUI Platform Integration + description: Allow specsmith projects to integrate with WebUI platforms for AI model + serving with human approval + source: specsmith governance + status: planned + test_coverage: true + approval_required: true - id: REQ-110 - title: End-to-End Nexus Path Must Be Integration-Tested - description: '`tests/test_e2e_nexus.py` exercises the broker -> preflight -> harness - -> orchestrator -> verifier path with a `FakeOrchestrator` and asserts ledger - events, `RunResult.success`, and retry-strategy classification on a scripted failure-then-recovery - sequence.' - source: tests/test_e2e_nexus.py - status: implemented + title: VLLM Platform Integration + description: Allow specsmith projects to integrate with VLLM for large language + model serving with human approval + source: specsmith governance + status: planned + test_coverage: true + approval_required: true - id: REQ-111 - title: Mypy Strict Carveout Must Shrink Toward Zero - description: At least the four newly-annotated dynamic agent modules (`broker`, - `safety`, `console_utils`, `indexer`) are fully type-annotated and removed from - the `[[tool.mypy.overrides]] ignore_errors=true` block in `pyproject.toml`. The - remaining carveout (orchestrator, repl, tools, cleanup, serve) is documented as - a 1.x cleanup target. - source: pyproject.toml, src/specsmith/agent/*.py, src/specsmith/console_utils.py - status: implemented + title: LMStudio Platform Integration + description: Allow specsmith projects to integrate with LMStudio for local AI model + serving with human approval + source: specsmith governance + status: planned + test_coverage: true + approval_required: true - id: REQ-112 - title: Streaming Token Bridge Must Emit JSONL Events - description: A new `specsmith chat --json-events` CLI subcommand drives - the broker + harness end-to-end and emits a JSONL event stream on stdout with - at least the event types `block_start`, `token`, `tool_call`, `tool_result`, `block_complete`, - and `task_complete`. Each event is a single JSON object on its own line. - source: src/specsmith/cli.py, src/specsmith/agent/events.py - status: implemented + title: Ollama Platform Integration + description: Allow specsmith projects to integrate with Ollama for local AI model + serving with human approval + source: specsmith governance + status: planned + test_coverage: true + approval_required: true - id: REQ-113 - title: Block-Based Output Schema - description: Every `block_start` event carries a `block_id`, `kind` (one of `plan`, - `message`, `tool_call`, `tool_result`, `diff`, `test_results`, `verdict`), `agent`, - and `timestamp`. The corresponding `block_complete` reuses the same `block_id`. - Schema is documented in `docs/site/chat-events.md`. - source: src/specsmith/agent/events.py, docs/site/chat-events.md - status: implemented + title: OpenTerminal Platform Integration + description: Allow specsmith projects to integrate with OpenTerminal for AI terminal + interfaces with human approval + source: specsmith governance + status: planned + test_coverage: true + approval_required: true - id: REQ-114 - title: Plan Block Must Surface Steps - description: When the broker classifies an utterance as a `change` and preflight - is `accepted`, the chat stream must emit a `plan` block whose payload is a list - of `{step_id, title, status}` items. Status transitions (`pending` -> `running` - -> `done` / `failed`) are emitted as `plan_step` events keyed by `step_id`. - source: src/specsmith/agent/events.py - status: implemented + title: Platform Skill Management + description: Allow specsmith projects to manage skills for different AI platforms + with human approval + source: specsmith governance + status: planned + test_coverage: true + approval_required: true - id: REQ-115 - title: Permission/Autonomy Tier Must Be Honored End-to-End - description: '`specsmith chat` accepts `--profile {safe,standard,open,admin}` (default - reads `scaffold.yml`). Under `safe`, every tool call emits a `tool_request` event - and waits for an inbound `tool_decision` line on stdin (`{decision: ''approve''|''deny''}`). - Under `standard` / `open` the harness proceeds without prompting. The selected - profile is recorded in the ledger entry.' - source: src/specsmith/cli.py, src/specsmith/profiles.py - status: implemented + title: Platform Configuration Management + description: Allow specsmith projects to configure AI platform settings and parameters + with human approval + source: specsmith governance + status: planned + test_coverage: true + approval_required: true - id: REQ-116 - title: Inline Diff Review Must Round-Trip Comments - description: '`specsmith chat` emits a `diff` block per file changed by the orchestrator; - subsequent stdin lines of the form `{type: ''comment'', block_id, path, line, - body}` are stored in the session memory and surfaced to the bounded-retry harness - as additional context on the next attempt. `--comment` flag on `specsmith verify` - does the equivalent for non-streaming use.' - source: src/specsmith/agent/events.py, src/specsmith/cli.py - status: implemented + title: Platform Resource Management + description: Allow specsmith projects to manage platform resources including memory, + GPU, and compute with human approval + source: specsmith governance + status: planned + test_coverage: true + approval_required: true - id: REQ-117 - title: Predict-Only Preflight Must Not Allocate a Work Item - description: '`specsmith preflight --predict-only --json` returns the - same JSON shape as the canonical `preflight` (intent, requirement_ids, instruction, - etc.) but with `work_item_id == ''''`, no ledger event written, and a new `predicted_refinement` - field that suggests a tightened utterance. Used by IDE autocomplete.' - source: src/specsmith/cli.py - status: implemented + title: Platform Security Controls + description: Ensure AI platform integrations follow security best practices with + human approval + source: specsmith governance + status: planned + test_coverage: true + approval_required: true - id: REQ-118 - title: Must Surface specsmith chat Stream - description: The governance proxy (`/v1/chat/completions`) consumes the `specsmith - chat --json-events` JSONL stream and exposes it to the agent session. - source: src/specsmith/agent/settings_view/governance_page.py - status: implemented + title: Platform Monitoring and Logging + description: Allow specsmith projects to monitor and log AI platform activities + with human approval + source: specsmith governance + status: planned + test_coverage: true + approval_required: true - id: REQ-119 title: Project Rules Must Auto-Inject Into the System Prompt description: '`src/specsmith/agent/rules.py:load_rules(project_dir)` reads `docs/governance/*_RULES.md` @@ -517,17 +493,17 @@ status: implemented - id: REQ-128 title: Cross-Repo Security Sweep - description: The specsmith repos both run `pip-audit` / `cargo audit` - in CI and fail on high-or-critical findings. Dependabot manifests in both repos - are reviewed and any open alert at 1.0 release time is documented. + description: The specsmith repos both run `pip-audit` / `cargo audit` in CI and + fail on high-or-critical findings. Dependabot manifests in both repos are reviewed + and any open alert at 1.0 release time is documented. source: .github/workflows/ci.yml status: implemented - id: REQ-129 title: 1.0 API Stability Commitment description: '`docs/site/api-stability.md` enumerates the public surfaces frozen at 1.0 (CLI subcommands and exit codes, JSON payload schemas for preflight / verify - / chat events, broker module API, ledger event schemas, CLI API surface). - The PyPI classifier is bumped to `Development Status :: 5 - Production/Stable` - and `pyproject.toml` to `1.0.0`.' + / chat events, broker module API, ledger event schemas, CLI API surface). The + PyPI classifier is bumped to `Development Status :: 5 - Production/Stable` and + `pyproject.toml` to `1.0.0`.' source: docs/site/api-stability.md, pyproject.toml status: implemented diff --git a/docs/requirements/ai_intelligence.yml b/docs/requirements/ai_intelligence.yml index 398f618e..dfb54790 100644 --- a/docs/requirements/ai_intelligence.yml +++ b/docs/requirements/ai_intelligence.yml @@ -149,8 +149,8 @@ status: implemented - id: REQ-281 title: AI Settings Bucket Score Display - description: The Agents > Providers settings page MUST display bucket scores - (reasoning, conversational, longform) retrieved from `GET /api/model-intel/scores/{model}` + description: The Agents > Providers settings page MUST display bucket scores (reasoning, + conversational, longform) retrieved from `GET /api/model-intel/scores/{model}` for each configured provider. Scores MUST be shown as compact numeric badges. A Sync button MUST call `POST /api/model-intel/sync`. source: ARCHITECTURE.md §20–21 [KAI-001] diff --git a/docs/requirements/ai_platforms.yml b/docs/requirements/ai_platforms.yml new file mode 100644 index 00000000..331945b2 --- /dev/null +++ b/docs/requirements/ai_platforms.yml @@ -0,0 +1,86 @@ +# specsmith requirements — AI/ML platforms and skills +# CANONICAL SOURCE: edit this file, not docs/REQUIREMENTS.md +# docs/REQUIREMENTS.md is regenerated from these YAML files. + +# Schema: id (REQ-NNN), title, description, source, status, test_coverage, approval_required +# Required fields: id, title, status + +- id: REQ-109 + title: WebUI Platform Integration + description: Allow specsmith projects to integrate with WebUI platforms for AI model serving with human approval + source: specsmith governance + status: planned + test_coverage: true + approval_required: true + +- id: REQ-110 + title: VLLM Platform Integration + description: Allow specsmith projects to integrate with VLLM for large language model serving with human approval + source: specsmith governance + status: planned + test_coverage: true + approval_required: true + +- id: REQ-111 + title: LMStudio Platform Integration + description: Allow specsmith projects to integrate with LMStudio for local AI model serving with human approval + source: specsmith governance + status: planned + test_coverage: true + approval_required: true + +- id: REQ-112 + title: Ollama Platform Integration + description: Allow specsmith projects to integrate with Ollama for local AI model serving with human approval + source: specsmith governance + status: planned + test_coverage: true + approval_required: true + +- id: REQ-113 + title: OpenTerminal Platform Integration + description: Allow specsmith projects to integrate with OpenTerminal for AI terminal interfaces with human approval + source: specsmith governance + status: planned + test_coverage: true + approval_required: true + +- id: REQ-114 + title: Platform Skill Management + description: Allow specsmith projects to manage skills for different AI platforms with human approval + source: specsmith governance + status: planned + test_coverage: true + approval_required: true + +- id: REQ-115 + title: Platform Configuration Management + description: Allow specsmith projects to configure AI platform settings and parameters with human approval + source: specsmith governance + status: planned + test_coverage: true + approval_required: true + +- id: REQ-116 + title: Platform Resource Management + description: Allow specsmith projects to manage platform resources including memory, GPU, and compute with human approval + source: specsmith governance + status: planned + test_coverage: true + approval_required: true + +- id: REQ-117 + title: Platform Security Controls + description: Ensure AI platform integrations follow security best practices with human approval + source: specsmith governance + status: planned + test_coverage: true + approval_required: true + +- id: REQ-118 + title: Platform Monitoring and Logging + description: Allow specsmith projects to monitor and log AI platform activities with human approval + source: specsmith governance + status: planned + test_coverage: true + approval_required: true diff --git a/docs/requirements/esdb.yml b/docs/requirements/esdb.yml index 1dc72e2e..4cd8c77e 100644 --- a/docs/requirements/esdb.yml +++ b/docs/requirements/esdb.yml @@ -101,18 +101,17 @@ status: implemented - id: REQ-261 title: AI Providers Table Without Column Overflow - description: 'The Agents > Providers settings page MUST display AI models - in a table with fixed-width columns (Name: 200px, Model ID: 220px, Context: 80px, - Output: 80px) using ConstrainedBox + Clipped elements. Long model names such as - o4-mini-deep-research MUST NOT overflow into adjacent columns.' + description: 'The Agents > Providers settings page MUST display AI models in a table + with fixed-width columns (Name: 200px, Model ID: 220px, Context: 80px, Output: + 80px) using ConstrainedBox + Clipped elements. Long model names such as o4-mini-deep-research + MUST NOT overflow into adjacent columns.' source: ARCHITECTURE.md [Settings Extensions] status: implemented - id: REQ-262 title: MCP AI Builder Card - description: The Agents > MCP servers list page MUST include a collapsible - AI Builder card that accepts a natural-language server description, calls specsmith - mcp generate --json, displays the generated JSON stub, and offers - an 'Add to ~/.specsmith/mcp.json' button that appends the stub to the user's MCP - config file. + description: The Agents > MCP servers list page MUST include a collapsible AI Builder + card that accepts a natural-language server description, calls specsmith mcp generate + --json, displays the generated JSON stub, and offers an 'Add to + ~/.specsmith/mcp.json' button that appends the stub to the user's MCP config file. source: ARCHITECTURE.md [Settings Extensions] status: implemented diff --git a/docs/requirements/execution.yml b/docs/requirements/execution.yml new file mode 100644 index 00000000..8f986e01 --- /dev/null +++ b/docs/requirements/execution.yml @@ -0,0 +1,102 @@ +# specsmith requirements — local execution and environment management +# CANONICAL SOURCE: edit this file, not docs/REQUIREMENTS.md +# docs/REQUIREMENTS.md is regenerated from these YAML files. + +# Schema: id (REQ-NNN), title, description, source, status, test_coverage, approval_required +# Required fields: id, title, status + +- id: REQ-089 + title: Local Command Execution Policy + description: Allow specsmith to execute local commands with a default permissive policy from a local repo standpoint, with configurable whitelists and blacklists + source: specsmith governance + status: planned + test_coverage: true + approval_required: true + +- id: REQ-090 + title: Local Command Whitelist Management + description: Allow specsmith to manage whitelisted commands for local execution with human approval + source: specsmith governance + status: planned + test_coverage: true + approval_required: true + +- id: REQ-091 + title: Local Command Blacklist Management + description: Allow specsmith to manage blacklisted commands for local execution with human approval + source: specsmith governance + status: planned + test_coverage: true + approval_required: true + +- id: REQ-092 + title: Local Command Override Capability + description: Allow specsmith to override execution policies with human approval, enabling execution of commands not in default policy + source: specsmith governance + status: planned + test_coverage: true + approval_required: true + +- id: REQ-093 + title: Pip Execution Override + description: Allow specsmith to execute pip commands with override capability, using only local pip from the local environment in workspace + source: specsmith governance + status: planned + test_coverage: true + approval_required: true + +- id: REQ-094 + title: Pip Execution Safety Checks + description: When pip execution is overridden, specsmith must warn and ensure only local pip from workspace environment is used + source: specsmith governance + status: planned + test_coverage: true + approval_required: true + +- id: REQ-095 + title: Virtual Environment Creation + description: Allow specsmith to create virtual environments for projects with human approval + source: specsmith governance + status: planned + test_coverage: true + approval_required: true + +- id: REQ-096 + title: Virtual Environment Management + description: Allow specsmith to manage virtual environments including activation, deactivation, and cleanup with human approval + source: specsmith governance + status: planned + test_coverage: true + approval_required: true + +- id: REQ-097 + title: Virtual Environment Validation + description: When creating or using virtual environments, specsmith must validate that they are properly configured and safe to use + source: specsmith governance + status: planned + test_coverage: true + approval_required: true + +- id: REQ-098 + title: Virtual Environment Warning System + description: When projects attempt to use non-pipx versions of specsmith, specsmith must warn and offer to create new venv if one doesn't exist + source: specsmith governance + status: planned + test_coverage: true + approval_required: true + +- id: REQ-099 + title: Local Environment Isolation + description: Specsmith must ensure local command execution is isolated to the project workspace environment with appropriate warnings + source: specsmith governance + status: planned + test_coverage: true + approval_required: true + +- id: REQ-100 + title: Execution Policy Configuration + description: Allow specsmith to configure execution policies including default permissive mode, whitelists, blacklists, and override rules + source: specsmith governance + status: planned + test_coverage: true + approval_required: true diff --git a/docs/requirements/git.yml b/docs/requirements/git.yml new file mode 100644 index 00000000..0b33e011 --- /dev/null +++ b/docs/requirements/git.yml @@ -0,0 +1,86 @@ +# specsmith requirements — Git platform management +# CANONICAL SOURCE: edit this file, not docs/REQUIREMENTS.md +# docs/REQUIREMENTS.md is regenerated from these YAML files. + +# Schema: id (REQ-NNN), title, description, source, status, test_coverage, approval_required +# Required fields: id, title, status + +- id: REQ-079 + title: Git Platform Agnostic Management + description: Allow specsmith to manage Git repositories across multiple platforms (GitHub, GitLab, Bitbucket, etc.) with human approval + source: specsmith governance + status: planned + test_coverage: true + approval_required: true + +- id: REQ-080 + title: GitHub Platform Management + description: Allow specsmith to manage GitHub repositories, issues, pull requests, and releases with human approval + source: specsmith governance + status: planned + test_coverage: true + approval_required: true + +- id: REQ-081 + title: GitLab Platform Management + description: Allow specsmith to manage GitLab repositories, issues, merge requests, and releases with human approval + source: specsmith governance + status: planned + test_coverage: true + approval_required: true + +- id: REQ-082 + title: Bitbucket Platform Management + description: Allow specsmith to manage Bitbucket repositories, issues, pull requests, and releases with human approval + source: specsmith governance + status: planned + test_coverage: true + approval_required: true + +- id: REQ-083 + title: Azure DevOps Platform Management + description: Allow specsmith to manage Azure DevOps repositories, issues, pull requests, and releases with human approval + source: specsmith governance + status: planned + test_coverage: true + approval_required: true + +- id: REQ-084 + title: Git Platform Authentication Management + description: Allow specsmith to manage authentication credentials for multiple Git platforms with human approval + source: specsmith governance + status: planned + test_coverage: true + approval_required: true + +- id: REQ-085 + title: Git Platform Configuration Management + description: Allow specsmith to configure platform-specific settings and webhooks for multiple Git platforms with human approval + source: specsmith governance + status: planned + test_coverage: true + approval_required: true + +- id: REQ-086 + title: Git Platform Repository Creation + description: Allow specsmith to create repositories on multiple Git platforms with human approval + source: specsmith governance + status: planned + test_coverage: true + approval_required: true + +- id: REQ-087 + title: Git Platform Repository Deletion + description: Allow specsmith to delete repositories on multiple Git platforms with human approval + source: specsmith governance + status: planned + test_coverage: true + approval_required: true + +- id: REQ-088 + title: Git Platform Repository Cloning + description: Allow specsmith to clone repositories from multiple Git platforms with human approval + source: specsmith governance + status: planned + test_coverage: true + approval_required: true diff --git a/docs/requirements/harness.yml b/docs/requirements/harness.yml index c0bbebef..36cb7578 100644 --- a/docs/requirements/harness.yml +++ b/docs/requirements/harness.yml @@ -184,7 +184,7 @@ status: implemented - id: REQ-160 title: Agent Teams and Advanced Features Flag-Gated - description: Agent teams, worktree isolation, daemon mode, security scanner, - and MCP tools MUST be flag-gated. + description: Agent teams, worktree isolation, daemon mode, security scanner, and + MCP tools MUST be flag-gated. source: docs/PLANNED-REQUIREMENTS.md (FLG-003) status: implemented diff --git a/docs/requirements/overflow.yml b/docs/requirements/overflow.yml index ddc4a85c..ca98b45b 100644 --- a/docs/requirements/overflow.yml +++ b/docs/requirements/overflow.yml @@ -438,3 +438,65 @@ general) keyed by the detected GPU VRAM tier, with per-model fit assessment (fits/tight/spills-to-RAM). Exposed via ''specsmith local-model recommend'' (+ --json). Must not change existing detect_local_model/detect_local_models behavior.' +- id: REQ-446 + title: Epistemic chat condensation and agent handoff + status: implemented + description: Specsmith shall safely condense chat/session context into provenance-preserving + ESDB artifacts that retain source identifiers, confidence, uncertainty, unresolved + decisions, active work items, and validation status; reject or flag unsupported + claims; restore usable context after compaction; and export/import a portable + handoff envelope interoperable with Specsmith agents and Zoo-Code. +- id: REQ-447 + title: Git-safe ESDB session persistence + status: implemented + description: Specsmith shall store session and ESDB history in a deterministic, + append-friendly, text-based canonical representation that can be merged across + branches without lost or duplicated events; local SQLite databases and WAL sidecars + shall be derived caches that can be rebuilt safely with validated schema, integrity, + and recovery reporting. +- id: REQ-448 + title: Windows launcher resolution diagnostics + status: implemented + description: On Windows, Specsmith shall detect multiple or shadowed specsmith executables, + report the active executable and package version, provide safe pipx-focused remediation, + and support PowerShell stderr redirection without a launcher failure. +- id: REQ-449 + title: Reachable version-mismatch recovery + status: implemented + description: When a project requires a newer development or prerelease Specsmith + version than the stable channel provides, Specsmith shall diagnose the channel + mismatch, provide an exact supported pipx remediation command, and distinguish + it from a normal stable upgrade without permitting backward migration. +- id: REQ-450 + title: Stable release channel integrity + status: implemented + description: Specsmith release automation shall reject PEP 440 development, prerelease, + and local versions before stable PyPI upload, publish such artifacts only through + an explicit development channel, and verify the stable install and upgrade path + in CI. +- id: REQ-451 + title: Contained work-item persistence paths + status: implemented + description: Specsmith shall normalize every work-item persistence path with os.path.realpath, + reject values outside the project root before filesystem access, and provide the + same containment behavior on Windows, Linux, and macOS. +- id: REQ-452 + title: CodeQL-clean report rendering + status: implemented + description: Specsmith shall render quality reports without CodeQL implicit string + concatenation findings while preserving the report content and formatting. +- id: REQ-453 + title: Release candidate quality gates + status: implemented + description: Before release, Specsmith shall pass strict linting, formatting, type + checking, the complete test suite, strict documentation build, runtime dependency + audit, and governance audit without unresolved issues. + source: CI, release workflow, and release validation +- id: REQ-454 + title: Single-branch workflow default + status: implemented + description: Specsmith shall default new projects to a single-branch workflow on + the configured default branch, refuse branch creation until a different branching + strategy is explicitly enabled through specsmith, and preserve GitFlow, trunk-based, + and GitHub-flow behavior after opt-in. + source: Git workflow governance diff --git a/docs/requirements/release.yml b/docs/requirements/release.yml new file mode 100644 index 00000000..b80a7882 --- /dev/null +++ b/docs/requirements/release.yml @@ -0,0 +1,102 @@ +# specsmith requirements — release management +# CANONICAL SOURCE: edit this file, not docs/REQUIREMENTS.md +# docs/REQUIREMENTS.md is regenerated from these YAML files. + +# Schema: id (REQ-NNN), title, description, source, status, test_coverage, approval_required +# Required fields: id, title, status + +- id: REQ-065 + title: GitHub Release Creation + description: Allow specsmith to create GitHub releases for tagged versions with human approval + source: specsmith governance + status: planned + test_coverage: true + approval_required: true + +- id: REQ-066 + title: PyPI Deployment + description: Allow specsmith to trigger PyPI package deployment with human approval + source: specsmith governance + status: planned + test_coverage: true + approval_required: true + +- id: REQ-067 + title: CI Management + description: Allow specsmith to manage CI workflows with human approval + source: specsmith governance + status: planned + test_coverage: true + approval_required: true + +- id: REQ-068 + title: Pull Request Management + description: Allow specsmith to manage PRs, merges, and issue creation with human approval + source: specsmith governance + status: planned + test_coverage: true + approval_required: true + +- id: REQ-071 + title: Release Notes Generation + description: Allow specsmith to automatically generate release notes from commit history with human approval + source: specsmith governance + status: planned + test_coverage: true + approval_required: true + +- id: REQ-072 + title: Release Tag Management + description: Allow specsmith to manage release tags including creation, deletion, and modification with human approval + source: specsmith governance + status: planned + test_coverage: true + approval_required: true + +- id: REQ-073 + title: Artifact Management + description: Allow specsmith to manage release artifacts including uploads, downloads, and cleanup with human approval + source: specsmith governance + status: planned + test_coverage: true + approval_required: true + +- id: REQ-074 + title: Release Branch Management + description: Allow specsmith to manage release branches including creation, merging, and deletion with human approval + source: specsmith governance + status: planned + test_coverage: true + approval_required: true + +- id: REQ-075 + title: Release Validation + description: Allow specsmith to perform automated validation checks before release creation with human approval + source: specsmith governance + status: planned + test_coverage: true + approval_required: true + +- id: REQ-076 + title: Release Rollback + description: Allow specsmith to rollback to previous releases with human approval + source: specsmith governance + status: planned + test_coverage: true + approval_required: true + +- id: REQ-077 + title: Release Promotion + description: Allow specsmith to promote releases between environments (dev, staging, prod) with human approval + source: specsmith governance + status: planned + test_coverage: true + approval_required: true + +- id: REQ-078 + title: Release Metadata Management + description: Allow specsmith to manage release metadata including version, date, and author information with human approval + source: specsmith governance + status: planned + test_coverage: true + approval_required: true diff --git a/docs/requirements/testing.yml b/docs/requirements/testing.yml new file mode 100644 index 00000000..5083c6b8 --- /dev/null +++ b/docs/requirements/testing.yml @@ -0,0 +1,70 @@ +# specsmith requirements — testing frameworks and tools +# CANONICAL SOURCE: edit this file, not docs/REQUIREMENTS.md +# docs/REQUIREMENTS.md is regenerated from these YAML files. + +# Schema: id (REQ-NNN), title, description, source, status, test_coverage, approval_required +# Required fields: id, title, status + +- id: REQ-101 + title: Playwright Testing Framework + description: Allow specsmith projects to use Playwright for end-to-end browser testing with human approval + source: specsmith governance + status: planned + test_coverage: true + approval_required: true + +- id: REQ-102 + title: Testing Framework Configuration + description: Allow specsmith projects to configure testing frameworks including Playwright, pytest, and others with human approval + source: specsmith governance + status: planned + test_coverage: true + approval_required: true + +- id: REQ-103 + title: Testing Environment Isolation + description: Ensure testing environments are properly isolated from development environments with human approval + source: specsmith governance + status: planned + test_coverage: true + approval_required: true + +- id: REQ-104 + title: Testing Artifact Management + description: Allow specsmith projects to manage test artifacts including screenshots, videos, and logs with human approval + source: specsmith governance + status: planned + test_coverage: true + approval_required: true + +- id: REQ-105 + title: Testing Report Generation + description: Allow specsmith projects to automatically generate test reports with human approval + source: specsmith governance + status: planned + test_coverage: true + approval_required: true + +- id: REQ-106 + title: Testing Integration with CI/CD + description: Allow specsmith projects to integrate testing frameworks with CI/CD pipelines with human approval + source: specsmith governance + status: planned + test_coverage: true + approval_required: true + +- id: REQ-107 + title: Testing Parallel Execution + description: Allow specsmith projects to execute tests in parallel with human approval + source: specsmith governance + status: planned + test_coverage: true + approval_required: true + +- id: REQ-108 + title: Testing Coverage Reporting + description: Allow specsmith projects to generate and track test coverage reports with human approval + source: specsmith governance + status: planned + test_coverage: true + approval_required: true diff --git a/docs/requirements/yaml_governance.yml b/docs/requirements/yaml_governance.yml index fc40833b..ef644821 100644 --- a/docs/requirements/yaml_governance.yml +++ b/docs/requirements/yaml_governance.yml @@ -281,8 +281,8 @@ status: implemented - id: REQ-334 title: Per-Node Retry and Abort Controls - description: MUST provide a Retry button on FAILED and BLOCKED nodes (calls - POST /api/dispatch/retry) and an Abort button on RUNNING nodes (calls POST /api/dispatch/abort). + description: MUST provide a Retry button on FAILED and BLOCKED nodes (calls POST + /api/dispatch/retry) and an Abort button on RUNNING nodes (calls POST /api/dispatch/abort). Retry and Abort MUST be disabled when not applicable to the node status. source: ARCHITECTURE.md §Multi-Agent DAG Dispatcher status: implemented diff --git a/docs/site/agent-integrations.md b/docs/site/agent-integrations.md index a2515ddd..41147cde 100644 --- a/docs/site/agent-integrations.md +++ b/docs/site/agent-integrations.md @@ -26,7 +26,7 @@ Regardless of which tool you use, the governance session protocol is the same: **Session start** (run once before any other action): ```bash -specsmith kill-session 2>/dev/null || true +specsmith kill-session # idempotent; safe when no processes exist specsmith audit --project-dir . specsmith sync --project-dir . specsmith checkpoint --project-dir . # output GOVERNANCE ANCHOR verbatim diff --git a/docs/site/branch-workflows.md b/docs/site/branch-workflows.md new file mode 100644 index 00000000..e836c503 --- /dev/null +++ b/docs/site/branch-workflows.md @@ -0,0 +1,41 @@ +# Branch Workflows + +New Specsmith projects use the `single-branch` workflow by default. Governed work, +verification, commits, and pushes happen directly on the configured default branch, +normally `main`. + +This is intentionally conservative: Specsmith does not create feature branches or +pull requests until a project explicitly opts into a branching workflow. + +## Check Or Enable A Workflow + +Show the current workflow: + +```bash +specsmith branch workflow +``` + +Enable one of the supported branching workflows for the current project: + +```bash +specsmith branch workflow gitflow +specsmith branch workflow trunk-based +specsmith branch workflow github-flow +``` + +The command records the selection in `scaffold.yml`. Once selected, +`specsmith branch create` and `specsmith pr` use that workflow's rules. + +## Single-Branch Behavior + +While `single-branch` is active: + +- `specsmith branch create` refuses to create a branch. +- `specsmith pr` refuses to open a pull request. +- Governed commits and pushes to `main` remain available. + +To return to direct governed work, run: + +```bash +specsmith branch workflow single-branch +``` diff --git a/docs/site/epistemic-handoffs.md b/docs/site/epistemic-handoffs.md new file mode 100644 index 00000000..f1d1b325 --- /dev/null +++ b/docs/site/epistemic-handoffs.md @@ -0,0 +1,28 @@ +# Epistemic Chat Handoffs + +Specsmith condenses chat context through an extractive handoff envelope rather +than an ungrounded prose summary. Each retained excerpt has a stable source ID, +the envelope declares its confidence and uncertainty, and recipients are told to +verify source IDs before relying on an excerpt as a decision. + +At Tier 2 context pressure, Specsmith stores the envelope as an ESDB +`chat_handoff` record and retains a compact rendering in the active history. +Zoo-Code can export the same portable JSON envelope: + +```powershell +specsmith zoo-code export-handoff --project-dir . --output handoff.json +``` + +## Session Storage and Git + +`.chronomemory/session-events.jsonl` is the canonical session continuity log. +It is deterministic text, supports review and branch reconciliation, and is +replayed on session load. `.specsmith/esdb.sqlite3` and its WAL sidecars are +local derived indexes; do not commit or manually merge them. + +## Development-Version Recovery + +When a project is newer than the installed stable tool, Specsmith refuses a +backward migration and prints the exact `pipx install --force +specsmith==` command if the project requires a development or +prerelease build. Stable projects continue to use `pipx upgrade specsmith`. diff --git a/docs/site/standalone-cli.md b/docs/site/standalone-cli.md index bf5facb2..a5e06668 100644 --- a/docs/site/standalone-cli.md +++ b/docs/site/standalone-cli.md @@ -29,7 +29,7 @@ The same governance protocol applies whether you are an AI agent or a human at a Run once at the beginning of every work session: ```bash -specsmith kill-session 2>/dev/null || true # kill any orphaned processes +specsmith kill-session # idempotent; safe when no processes exist specsmith migrate run # apply pending schema migrations specsmith audit --project-dir . # verify governance health specsmith sync --project-dir . # YAML → JSON → MD sync diff --git a/docs/site/zoo-code-roo.md b/docs/site/zoo-code-roo.md new file mode 100644 index 00000000..43f31121 --- /dev/null +++ b/docs/site/zoo-code-roo.md @@ -0,0 +1,99 @@ +# Zoo Code / Roo Code Integration + +Specsmith integrates with Zoo Code / Roo Code through a repo-local `.roo/` directory and the Specsmith MCP governance server. + +## What belongs in the repository + +Project-local integration files: + +| File | Purpose | +|---|---| +| `.roo/mcp.json` | Registers the `specsmith-governance` MCP server for this repo. | +| `.roo/specsmith-rules.md` | Mandatory rules for governed Zoo/Roo sessions. | +| `.roo/modes.local.json` | Reference mode-to-model mapping for this project. | +| `.roo/global-settings.copy-to-zoo-code.json` | Copyable global provider/model settings for Zoo Code. | + +Zoo Code global settings are not automatically loaded from a repository. Keep copyable global settings in the project as a reference, then copy them into Zoo Code global/user settings manually. + +## MCP setup + +The repo-local MCP config should look like this: + +```json +{ + "mcpServers": { + "specsmith-governance": { + "command": "specsmith", + "args": ["mcp", "serve", "--project-dir", "."], + "env": { + "SPECSMITH_ALLOW_NON_PIPX": "1", + "SPECSMITH_NO_AUTO_UPDATE": "1", + "SPECSMITH_PYPI_CHECKED": "1" + } + } + } +} +``` + +The MCP server exposes governance tools such as: + +- `governance_checkpoint` +- `governance_phase` +- `governance_req_list` +- `governance_preflight` +- `governance_audit` +- `governance_trace_seal` + +## Required agent flow + +Every Zoo/Roo session should follow this sequence: + +```text +read AGENTS.md + .roo/specsmith-rules.md +call governance_checkpoint +call governance_phase +call governance_req_list +call governance_preflight before edits +edit only within accepted scope +run tests/build checks +run verification +seal meaningful decisions +``` + +Do not edit files unless `governance_preflight` returns `accepted`. + +## Local model routing + +When a local LiteLLM/vLLM pool is available, use the router endpoint: + +```text +Base URL: http://localhost:4000/v1 +API key: $LITELLM_MASTER_KEY +``` + +Recommended role mapping: + +| Zoo/Roo mode | Model | +|---|---| +| Specsmith Architect | `architect` | +| Specsmith Code | `editor` | +| Specsmith Debug / Tool | `tool-fast` | +| Specsmith Review | `reviewer` | + +The model that writes a patch must not be the only model that approves it. + +## Operator setup checklist + +1. Start the local model router if using local models. +2. Copy `.roo/global-settings.copy-to-zoo-code.json` into Zoo Code global settings, adapting field names to the current extension version. +3. Ensure Zoo/Roo sees `.roo/mcp.json` for the active workspace. +4. Start a session by asking the agent to read `.roo/specsmith-rules.md` and call `governance_checkpoint`. +5. Run governed tasks using the role split: Architect -> Code -> Debug/Tool -> Review. + +## Safe defaults + +- Architect mode plans and reads; it should not directly edit production code. +- Code mode implements accepted preflight tasks. +- Debug/Tool mode runs safe commands and parses logs. +- Review mode critiques diffs against requirements, tests, and prior decisions. +- Specsmith blocks or escalates work when confidence, phase, or scope checks fail. diff --git a/docs/tests/agent.yml b/docs/tests/agent.yml index eacc6b1d..f9da8f34 100644 --- a/docs/tests/agent.yml +++ b/docs/tests/agent.yml @@ -466,8 +466,8 @@ confidence: 1.0 - id: TEST-106 title: Governance Page Surfaces Preflight/Verify/Trace - description: The Governance settings page shows the governance-serve health - status, the BYOE endpoint URL, and the specsmith updater. + description: The Governance settings page shows the governance-serve health status, + the BYOE endpoint URL, and the specsmith updater. requirement_id: REQ-106 type: integration verification_method: evaluator @@ -706,8 +706,7 @@ title: API Stability Doc Enumerates Frozen Surface description: '`docs/site/api-stability.md` exists and enumerates: CLI subcommands, exit codes, JSON payload schemas, broker module API, ledger event schemas, VS - CLI API surface. `pyproject.toml` version is `1.0.0` and classifier is - `Production/Stable`.' + CLI API surface. `pyproject.toml` version is `1.0.0` and classifier is `Production/Stable`.' requirement_id: REQ-129 type: unit verification_method: pytest diff --git a/docs/tests/ai_intelligence.yml b/docs/tests/ai_intelligence.yml index ea2b1c4d..0f50718c 100644 --- a/docs/tests/ai_intelligence.yml +++ b/docs/tests/ai_intelligence.yml @@ -209,8 +209,8 @@ - id: TEST-281 title: AI Providers Bucket Score Section Compiles description: The updated `ai_providers_page.py` in specsmith compiles without errors - under `python -m py_compile`. The file must contain `model_intel` function - call or `bucket_score` field rendering code. + under `python -m py_compile`. The file must contain `model_intel` function call + or `bucket_score` field rendering code. requirement_id: REQ-281 type: build verification_method: cargo check diff --git a/docs/tests/esdb.yml b/docs/tests/esdb.yml index c04b3e71..454f5905 100644 --- a/docs/tests/esdb.yml +++ b/docs/tests/esdb.yml @@ -110,9 +110,9 @@ confidence: 1.0 - id: TEST-258 title: ESDB Settings Page Renders Without Overflow - description: The Settings > Specsmith > ESDB page renders the status row, - action buttons (Refresh, Export JSON, Import, Backup, Rollback, Compact) without - layout errors. + description: The Settings > Specsmith > ESDB page renders the status row, action + buttons (Refresh, Export JSON, Import, Backup, Rollback, Compact) without layout + errors. requirement_id: REQ-258 type: integration verification_method: manual (Rust UI build required) @@ -131,8 +131,8 @@ confidence: 1.0 - id: TEST-260 title: Eval Settings Page Renders - description: The Settings > Specsmith > Eval page renders header, description, - and CLI hint without errors. + description: The Settings > Specsmith > Eval page renders header, description, and + CLI hint without errors. requirement_id: REQ-260 type: integration verification_method: manual (Rust UI build required) @@ -151,8 +151,8 @@ confidence: 1.0 - id: TEST-262 title: MCP AI Builder Card Generates And Saves Stub - description: In the Agents > MCP servers list, the AI Builder card accepts - a description, generates a stub via specsmith, displays JSON, and appends to ~/.specsmith/mcp.json + description: In the Agents > MCP servers list, the AI Builder card accepts a description, + generates a stub via specsmith, displays JSON, and appends to ~/.specsmith/mcp.json on 'Add to config' click. requirement_id: REQ-262 type: integration diff --git a/docs/tests/overflow.yml b/docs/tests/overflow.yml index 1e1d8ebe..b04a36ca 100644 --- a/docs/tests/overflow.yml +++ b/docs/tests/overflow.yml @@ -576,3 +576,77 @@ selects 7b/14b/32b tiers by VRAM, includes deepseek-coder-v2:16b harder slot, assess_fit returns fits/tight/spills, recommend_for_hardware detects Apple Silicon then NVIDIA, and ''specsmith local-model recommend'' emits human + --json output.' +- id: TEST-462 + title: Validate epistemic chat handoff and Zoo-Code export + requirement_id: REQ-446 + type: integration + verification_method: pytest tests/test_chat_handoff.py + description: Verify extractive source IDs, ESDB persistence, context compaction, + and portable Zoo-Code export. +- id: TEST-463 + title: Merge and rebuild canonical ESDB session events + requirement_id: REQ-447 + type: integration + verification_method: pytest tests/test_session_store.py + description: Verify divergent event histories replay without loss or duplicate events + and rebuild local SQLite state. +- id: TEST-464 + title: Diagnose Windows launcher shadowing and redirected stderr + requirement_id: REQ-448 + type: cli + verification_method: pytest tests/test_windows_launcher.py tests/test_migrations_skill_shell.py + description: Verify duplicate executable diagnostics and PowerShell-compatible launcher + behavior. +- id: TEST-465 + title: Offer reachable development-version recovery + requirement_id: REQ-449 + type: cli + verification_method: pytest tests/test_updater.py + description: Verify version mismatch diagnostics provide exact pipx recovery guidance + without allowing downgrade. +- id: TEST-466 + title: Reject non-stable versions from stable release publishing + requirement_id: REQ-450 + type: build + verification_method: pytest tests/test_release_guard.py + description: Verify PEP 440 dev prerelease and local versions cannot enter the stable + release workflow. +- id: TEST-467 + title: Reject work-item persistence paths outside project root + requirement_id: REQ-451 + type: unit + verification_method: pytest tests/test_wi_lifecycle.py + description: Verify normalized work-item state and file paths cannot escape the + supplied project root. +- id: TEST-468 + title: Render quality report footer without implicit concatenation + requirement_id: REQ-452 + type: unit + verification_method: pytest tests/test_quality_report.py + description: Verify the generated footer retains its expected report content while + the renderer remains CodeQL-clean. +- id: TEST-469 + title: Verify release candidate quality gates + requirement_id: REQ-453 + type: build + verification_method: ruff check src/ tests/ && ruff format --check src/ tests/ && + mypy src/specsmith/ && pytest --cov=specsmith --cov-report=term-missing && mkdocs + build --strict && pip-audit && specsmith audit --project-dir . + description: Verify every local and CI release-candidate quality gate passes without + lint, type, test, documentation, dependency-security, or governance failures. +- id: TEST-470 + title: Enforce and configure the single-branch default + requirement_id: REQ-454 + type: cli + verification_method: pytest tests/test_branch_workflow.py + description: Verify single-branch is the default, branch creation is refused until + an explicit workflow selection, and specsmith can enable GitFlow or another configured + strategy. +- id: TEST-471 + title: Preserve canonical ESDB state when saving a governed Git worktree + requirement_id: REQ-447 + type: integration + verification_method: pytest tests/test_esdb_enforcement.py -k save_does_not_commit + description: Verify save normalizes the Git policy, commits no SQLite cache, migration + backup, marker, state, or agent migration artifact, and retains the mergeable session + event log as canonical source of truth. diff --git a/mkdocs.yml b/mkdocs.yml index 414965f9..da00c885 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -45,6 +45,7 @@ nav: - Project Types: project-types.md - Agentic Runtime: - CLI Commands: commands.md + - Epistemic Chat Handoffs: epistemic-handoffs.md - Multi-Agent Dispatch: dispatch.md - Agentic Client: - Overview: agent-client.md @@ -52,6 +53,7 @@ nav: - Standalone CLI: standalone-cli.md - Agent Integrations: agent-integrations.md - Warp Integration: warp-integration.md + - Zoo Code / Roo Code: zoo-code-roo.md - BYOE Endpoints: endpoints.md - Kairos Terminal: kairos-terminal.md - Skills Index: skills-index.md @@ -59,6 +61,7 @@ nav: - Reference: - Importing: importing.md - Configuration: configuration.md + - Branch Workflows: branch-workflows.md - Doctor: doctor.md - Export & Compliance: export.md - Rate Limit Pacing: rate-limits.md diff --git a/pyproject.toml b/pyproject.toml index 345c0479..7a2fbf7c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "specsmith" -version = "0.21.0" +version = "0.22.0" description = "AEE governance toolkit for AI-assisted development — session preflight gates, multi-agent dispatch, requirements↔test traceability, ESDB persistence, MCP server, and skills for Warp, Cursor, Claude Code, Copilot, Windsurf, and Aider." readme = "README.md" license = "MIT" diff --git a/scripts/check_dev_release.py b/scripts/check_dev_release.py new file mode 100644 index 00000000..ce83d721 --- /dev/null +++ b/scripts/check_dev_release.py @@ -0,0 +1,25 @@ +"""Fail CI unless a development artifact has an explicit PEP 440 dev version.""" + +from __future__ import annotations + +import argparse +import re +from pathlib import Path + +from specsmith.release_guard import require_development_version + +parser = argparse.ArgumentParser() +parser.add_argument("--expected-version") +args = parser.parse_args() + +text = Path("pyproject.toml").read_text(encoding="utf-8") +match = re.search(r'^version = "([^"]+)"$', text, re.MULTILINE) +if match is None: + raise SystemExit("Could not find project version") + +version = match.group(1) +try: + require_development_version(version, args.expected_version) +except ValueError as error: + raise SystemExit(str(error)) from error +print(f"Development release version accepted: {version}") diff --git a/scripts/check_stable_release.py b/scripts/check_stable_release.py new file mode 100644 index 00000000..871946a6 --- /dev/null +++ b/scripts/check_stable_release.py @@ -0,0 +1,24 @@ +"""Fail CI before a non-final package can be uploaded to stable PyPI.""" + +from __future__ import annotations + +import argparse +import re +from pathlib import Path + +from specsmith.release_guard import require_stable_version + +parser = argparse.ArgumentParser() +parser.add_argument("--expected-version") +args = parser.parse_args() + +text = Path("pyproject.toml").read_text(encoding="utf-8") +match = re.search(r'^version = "([^"]+)"$', text, re.MULTILINE) +if match is None: + raise SystemExit("Could not find project version") +version = match.group(1) +try: + require_stable_version(version, args.expected_version) +except ValueError as error: + raise SystemExit(str(error)) from error +print(f"Stable release version accepted: {version}") diff --git a/scripts/delete_pypi_releases.py b/scripts/delete_pypi_releases.py index 78e50693..f707ab45 100644 --- a/scripts/delete_pypi_releases.py +++ b/scripts/delete_pypi_releases.py @@ -14,8 +14,10 @@ python scripts/delete_pypi_releases.py """ +import contextlib import time -from playwright.sync_api import sync_playwright, Page + +from playwright.sync_api import Page, sync_playwright PROJECT = "specsmith" @@ -30,7 +32,8 @@ def get_all_versions() -> list[str]: - import urllib.request, json + import json + import urllib.request url = f"https://pypi.org/pypi/{PROJECT}/json" with urllib.request.urlopen(url) as resp: data = json.loads(resp.read()) @@ -40,12 +43,11 @@ def get_all_versions() -> list[str]: def delete_version(page: Page, version: str) -> bool: """Navigate to a release page and click the delete button.""" url = f"https://pypi.org/manage/project/{PROJECT}/release/{version}/" - try: + with contextlib.suppress(Exception): # noqa: BLE001 page.goto(url, timeout=20_000) page.wait_for_load_state("domcontentloaded", timeout=15_000) - except Exception: - print(f" SKIP {version} — page load failed") - return False + print(f" SKIP {version} — page load failed") + return False # If redirected to login, session expired if "login" in page.url.lower(): @@ -71,21 +73,8 @@ def delete_version(page: Page, version: str) -> bool: delete_btn.click() time.sleep(0.5) - # Fill confirmation input (PyPI asks you to type the version number) - try: - confirm_input = page.locator( - "input[id*='confirm'], input[name*='confirm'], " - "input[placeholder*='version'], " - "dialog input[type='text'], .modal input[type='text']" - ).first - if confirm_input.is_visible(timeout=4_000): - confirm_input.fill(version) - time.sleep(0.3) - except Exception: # noqa: BLE001 - pass # confirm dialog not found or not visible; deletion may still proceed - # Click the final confirmation/submit button - try: + with contextlib.suppress(Exception): # noqa: BLE001 submit = page.locator( "dialog button[type='submit'], .modal button[type='submit'], " "button:has-text('Delete'), button:has-text('Confirm delete')" @@ -94,8 +83,7 @@ def delete_version(page: Page, version: str) -> bool: submit.click() page.wait_for_load_state("domcontentloaded", timeout=15_000) time.sleep(0.5) - except Exception: # noqa: BLE001 - pass # submit button not found or click failed; page state logged above + # submit button not found or click failed; page state logged above print(f" DEL {version} ✓") return True @@ -104,67 +92,19 @@ def delete_version(page: Page, version: str) -> bool: def main() -> None: all_versions = get_all_versions() to_delete = [v for v in all_versions if v not in KEEP] - to_keep = [v for v in all_versions if v in KEEP] - - print(f"Specsmith PyPI cleanup — {len(all_versions)} total versions\n") - print(f"Keeping ({len(to_keep)}): {', '.join(to_keep)}") - print(f"Deleting ({len(to_delete)}): all others\n") + print(f"Found {len(all_versions)} versions, {len(to_delete)} to delete") + print("Press Enter to start deletion...") + input() with sync_playwright() as pw: browser = pw.chromium.launch(headless=False, slow_mo=200) - ctx = browser.new_context() - page = ctx.new_page() - - # Step 1: open login page - page.goto("https://pypi.org/account/login/") - print("=" * 60) - print("Browser is open. Log in to PyPI (including 2FA if needed).") - print("When you're fully logged in and see your dashboard,") - print("press ENTER here to start the deletions...") - print("=" * 60) - input() - - # Verify logged in — navigate to the project management page. - # PyPI may do a brief redirect chain; catch interruptions gracefully. try: - page.goto( - f"https://pypi.org/manage/project/{PROJECT}/releases/", - wait_until="commit", - timeout=20_000, - ) - except Exception: - pass # navigation interruptions are expected during PyPI's redirect - # Give any redirect chain time to settle - time.sleep(2) - page.wait_for_load_state("domcontentloaded", timeout=15_000) - - current_url = page.url - if "account/login" in current_url: - print("ERROR: Redirected to login page — not authenticated. Aborting.") + page = browser.new_page() + for version in to_delete: + if not delete_version(page, version): + break + finally: browser.close() - return - print(f"Login confirmed (landed at: {current_url}). Starting deletions...\n") - - print(f"Starting deletion of {len(to_delete)} versions...\n") - deleted = 0 - skipped = 0 - - for version in to_delete: # oldest first (list is already sorted ascending) - try: - ok = delete_version(page, version) - if ok: - deleted += 1 - else: - skipped += 1 - time.sleep(0.5) - except Exception as exc: - print(f" ERROR {version}: {exc}") - skipped += 1 - - print(f"\nDone. Deleted: {deleted} Skipped/errors: {skipped}") - print("Closing browser in 5 seconds...") - time.sleep(5) - browser.close() if __name__ == "__main__": diff --git a/scripts/dev/test_providers.py b/scripts/dev/test_providers.py index cfd920ac..e2a7af16 100644 --- a/scripts/dev/test_providers.py +++ b/scripts/dev/test_providers.py @@ -31,7 +31,7 @@ ) reply = resp.choices[0].message.content.strip() print(f" -> {reply}") - print(f" PASS" if "OPENAI_OK" in reply else f" UNEXPECTED reply: {reply}") + print(" PASS" if "OPENAI_OK" in reply else f" UNEXPECTED reply: {reply}") except Exception as e: print(f" FAIL: {e}") else: @@ -52,7 +52,7 @@ ) reply = resp.text.strip() print(f" -> {reply}") - print(f" PASS" if "GEMINI_OK" in reply else f" UNEXPECTED reply: {reply}") + print(" PASS" if "GEMINI_OK" in reply else f" UNEXPECTED reply: {reply}") except Exception as e: print(f" FAIL: {e}") else: diff --git a/scripts/govern_bench/conditions.py b/scripts/govern_bench/conditions.py index 80e6b595..498acc97 100644 --- a/scripts/govern_bench/conditions.py +++ b/scripts/govern_bench/conditions.py @@ -336,7 +336,8 @@ def render_prompt(self, task_description: str = "", acceptance_criteria: str = " - decision == "accepted" → note the work_item_id and proceed immediately. - decision == "needs_clarification" → do NOT stop, wait, or ask the user. Instead, autonomously resolve it: - 1. specsmith req add --title "" --description "" --status planned + 1. specsmith req add --title "" --description "" + --status planned 2. Re-run preflight. If still needs_clarification, proceed with your best interpretation of scope — never abort the task because of needs_clarification. @@ -381,7 +382,8 @@ def render_prompt(self, task_description: str = "", acceptance_criteria: str = " - decision == "accepted" → note work_item_id, proceed. - decision == "needs_clarification" → do NOT stop, wait, or ask the user. Instead, autonomously resolve it: - a. specsmith req add --title "" --description "<one-line scope>" --status planned + a. specsmith req add --title "<title>" --description "<one-line scope>" + --status planned b. Re-run preflight. If still needs_clarification, proceed with your best interpretation of scope — never abort the task on needs_clarification. 3. Implement the change. @@ -526,7 +528,8 @@ def render_prompt(self, task_description: str = "", acceptance_criteria: str = " - decision == "accepted" → note work_item_id, proceed. - decision == "needs_clarification" → do NOT stop, wait, or ask the user. Instead, autonomously resolve it: - a. specsmith req add --title "<title>" --description "<one-line scope>" --status planned + a. specsmith req add --title "<title>" --description "<one-line scope>" + --status planned b. Re-run preflight. If still needs_clarification, proceed with your best interpretation of scope — never abort the task on needs_clarification. 3. Decompose the task into a dependency DAG: diff --git a/scripts/govern_bench/projects/data_pipeline/tests/test_etl.py b/scripts/govern_bench/projects/data_pipeline/tests/test_etl.py index d8d1ac0a..2b703f1a 100644 --- a/scripts/govern_bench/projects/data_pipeline/tests/test_etl.py +++ b/scripts/govern_bench/projects/data_pipeline/tests/test_etl.py @@ -3,6 +3,7 @@ from __future__ import annotations import pytest + from pipeline import etl diff --git a/scripts/govern_bench/report.py b/scripts/govern_bench/report.py index 64d04eb3..f4ab1b48 100644 --- a/scripts/govern_bench/report.py +++ b/scripts/govern_bench/report.py @@ -102,13 +102,15 @@ def render_democratization_table(report: BenchReport) -> str: ] if not rows: lines += [ - "No frontier+UNGOVERNED baseline is available yet, so democratization metrics are pending.", + "No frontier+UNGOVERNED baseline is available yet, so democratization metrics " + + "are pending.", "", ] return "\n".join(lines) lines += [ - "| Scaffold | Frontier Baseline | Cheapest Model That Beats Frontier | Tier | Cost Multiplier |", + "| Scaffold | Frontier Baseline | Cheapest Model That Beats Frontier | Tier | " + + "Cost Multiplier |", "|----------|-------------------|------------------------------------|------|-----------------|", ] for row in rows: @@ -122,13 +124,15 @@ def render_democratization_table(report: BenchReport) -> str: ) lines.append( "| " - + " | ".join([ - str(row["scaffold"]), - baseline, - winner, - tier, - multiplier, - ]) + + " | ".join( + [ + str(row["scaffold"]), + baseline, + winner, + tier, + multiplier, + ] + ) + " |" ) lines.append("") @@ -267,17 +271,21 @@ def render_report( continue s = summary[cid] cname = next((c.name for c in conditions if c.id == cid), cid) - rows.append(( - cname, - f"{_fmt_pct(s['mean_pass_rate'])} ({_fmt_ci_pct(s['ci_pass_rate_low'], s['ci_pass_rate_high'])})", - _fmt_tokens(s["mean_total_tokens"]), - _fmt_cost(s["mean_api_cost_usd"]), - f"{s['mean_quality_score']:.2f}", - f"{_fmt_cost(s['mean_cost_of_pass'])} ({_fmt_ci_cost(s['ci_cop_low'], s['ci_cop_high'])})", - _fmt_pct(s["mean_first_pass_rate"]), - f"{s['mean_consistency_score']:.2f}", - _fmt_lift(s["mean_scaffold_lift"]), - )) + rows.append( + ( + cname, + f"{_fmt_pct(s['mean_pass_rate'])} " + f"({_fmt_ci_pct(s['ci_pass_rate_low'], s['ci_pass_rate_high'])})", + _fmt_tokens(s["mean_total_tokens"]), + _fmt_cost(s["mean_api_cost_usd"]), + f"{s['mean_quality_score']:.2f}", + f"{_fmt_cost(s['mean_cost_of_pass'])} " + f"({_fmt_ci_cost(s['ci_cop_low'], s['ci_cop_high'])})", + _fmt_pct(s["mean_first_pass_rate"]), + f"{s['mean_consistency_score']:.2f}", + _fmt_lift(s["mean_scaffold_lift"]), + ) + ) # Best-value variables reserved for future bolding logic (not yet applied) @@ -330,6 +338,7 @@ def render_report( lines.append( "|-----------|-----------|--------|------|---------|-----|------------|------|" ) + def _slice_order(s: SliceStats) -> int: return cids.index(s.condition_id) if s.condition_id in cids else 99 @@ -383,16 +392,18 @@ def _slice_order(s: SliceStats) -> int: # Inline compact raw data (per-run summary only — not full transcripts) raw_rows = [] for run in report.runs: - raw_rows.append({ - "task": run.task_id, - "condition": run.condition_id, - "rep": run.rep, - "tokens": run.total_tokens, - "cost_usd": round(run.api_cost_usd, 6), - "passed": run.passed, - "quality": round(run.quality_score, 3), - "rework_turns": run.rework_turns, - }) + raw_rows.append( + { + "task": run.task_id, + "condition": run.condition_id, + "rep": run.rep, + "tokens": run.total_tokens, + "cost_usd": round(run.api_cost_usd, 6), + "passed": run.passed, + "quality": round(run.quality_score, 3), + "rework_turns": run.rework_turns, + } + ) lines.append(json.dumps(raw_rows, indent=2)) lines += ["```", ""] diff --git a/scripts/nexus_smoke.py b/scripts/nexus_smoke.py index ccc7123f..710383f5 100644 --- a/scripts/nexus_smoke.py +++ b/scripts/nexus_smoke.py @@ -37,7 +37,7 @@ def smoke_test( ] last_error = "" - for url, name in endpoints: + for url, _name in endpoints: try: t0 = time.monotonic() req = urllib.request.Request(url, method="GET") diff --git a/scripts/sign_license.py b/scripts/sign_license.py index 02df897f..15003696 100644 --- a/scripts/sign_license.py +++ b/scripts/sign_license.py @@ -45,7 +45,6 @@ from datetime import date, timedelta from pathlib import Path - _PRODUCT = "specsmith-esdb" @@ -67,7 +66,6 @@ def sign_license( License dict ready to be written as JSON. """ from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey - from cryptography.hazmat.primitives.serialization import Encoding, PrivateFormat, NoEncryption issued = issued_at or date.today().isoformat() @@ -78,7 +76,7 @@ def sign_license( priv_bytes = base64.b64decode(private_key_b64.strip()) priv_key = Ed25519PrivateKey.from_private_bytes(priv_bytes) - payload = f"{customer}|{_PRODUCT}|{issued}|{expires_at}".encode("utf-8") + payload = f"{customer}|{_PRODUCT}|{issued}|{expires_at}".encode() sig_bytes = priv_key.sign(payload) sig_b64 = base64.b64encode(sig_bytes).decode("ascii") @@ -131,7 +129,9 @@ def main() -> None: sys.exit(1) default_expires = (date.today() + timedelta(days=365)).isoformat() - expires_at = args.expires or input(f"Expiry date [YYYY-MM-DD, default {default_expires}]: ").strip() + expires_at = args.expires or input( + f"Expiry date [YYYY-MM-DD, default {default_expires}]: " + ).strip() if not expires_at: expires_at = default_expires diff --git a/scripts/yank_pypi_versions.py b/scripts/yank_pypi_versions.py index 9032a812..99f0ed4b 100644 --- a/scripts/yank_pypi_versions.py +++ b/scripts/yank_pypi_versions.py @@ -82,7 +82,6 @@ def yank_version(version: str, token: str, dry_run: bool) -> None: def main() -> None: - import urllib.parse parser = argparse.ArgumentParser(description="Yank old specsmith PyPI versions") parser.add_argument("--token", required=True, help="PyPI API token (pypi-...)") diff --git a/src/specsmith/__init__.py b/src/specsmith/__init__.py index 63dce9cd..11d99bcb 100644 --- a/src/specsmith/__init__.py +++ b/src/specsmith/__init__.py @@ -8,4 +8,4 @@ try: __version__: str = _pkg_version("specsmith") except PackageNotFoundError: # running from source without install - __version__ = "0.20.1" # fallback: keep in sync with pyproject.toml + __version__ = "0.22.0" # fallback: keep in sync with pyproject.toml diff --git a/src/specsmith/advanced_code_analysis.py b/src/specsmith/advanced_code_analysis.py index c2ded4bb..7cf07615 100644 --- a/src/specsmith/advanced_code_analysis.py +++ b/src/specsmith/advanced_code_analysis.py @@ -174,7 +174,7 @@ def _analyze_file_complexity(self, file_path: Path) -> list[ComplexityReport]: ), ) ) - except Exception: + except Exception: # noqa: BLE001 # intentional: fire-and-forget analysis; log is written above pass return reports diff --git a/src/specsmith/agent/cleanup.py b/src/specsmith/agent/cleanup.py index d251b31a..35e648b0 100644 --- a/src/specsmith/agent/cleanup.py +++ b/src/specsmith/agent/cleanup.py @@ -249,7 +249,7 @@ def _consolidate_governance_files(root: Path) -> list[str]: reqs_yaml_dir = root / "docs" / "requirements" reqs_yaml_dir.mkdir(parents=True, exist_ok=True) consolidated.append("Consolidated requirements to YAML structure") - except Exception: + except Exception: # noqa: BLE001 # intentional: fire-and-forget cleanup; log is written above pass if tests_dir.exists() and tests_dir.is_dir(): @@ -258,7 +258,7 @@ def _consolidate_governance_files(root: Path) -> list[str]: tests_yaml_dir = root / "docs" / "tests" tests_yaml_dir.mkdir(parents=True, exist_ok=True) consolidated.append("Consolidated tests to YAML structure") - except Exception: + except Exception: # noqa: BLE001 # intentional: fire-and-forget cleanup; log is written above pass return consolidated diff --git a/src/specsmith/chat_handoff.py b/src/specsmith/chat_handoff.py new file mode 100644 index 00000000..b17475af --- /dev/null +++ b/src/specsmith/chat_handoff.py @@ -0,0 +1,107 @@ +# SPDX-License-Identifier: MIT +# Copyright (c) 2026 Layer1Labs Silicon, Inc. All rights reserved. +"""Evidence-preserving chat compaction and portable agent handoffs (REQ-446).""" + +from __future__ import annotations + +import hashlib +import json +from datetime import datetime, timezone +from typing import Any + +SCHEMA_VERSION = 1 +_MAX_EXCERPT = 280 + + +def build_handoff( + history: list[dict[str, Any]], + *, + work_item_ids: list[str] | None = None, +) -> dict[str, Any]: + """Build an extractive, provenance-preserving envelope from chat turns. + + This deliberately does not ask an LLM to invent a prose summary. Each + compacted claim remains a bounded excerpt linked to a deterministic turn ID, + allowing another agent to inspect the original history before relying on it. + """ + turns: list[dict[str, str]] = [] + for index, turn in enumerate(history): + role = turn.get("role") + content = turn.get("content") + if not isinstance(role, str) or not isinstance(content, str) or not content.strip(): + continue + canonical = json.dumps( + {"role": role, "content": content}, sort_keys=True, ensure_ascii=False + ) + source_id = f"turn:{hashlib.sha256(canonical.encode('utf-8')).hexdigest()[:16]}" + turns.append( + { + "source_id": source_id, + "role": role, + "excerpt": content.strip()[:_MAX_EXCERPT], + "position": str(index), + }, + ) + + payload = { + "schema_version": SCHEMA_VERSION, + "kind": "epistemic_chat_handoff", + "created_at": datetime.now(timezone.utc).isoformat(), + "confidence": 1.0, + "uncertainty": "Extractive envelope; excerpts are not inferred claims.", + "work_item_ids": sorted(set(work_item_ids or [])), + "turns": turns, + } + fingerprint = json.dumps(payload, sort_keys=True, ensure_ascii=False) + digest = hashlib.sha256(fingerprint.encode("utf-8")).hexdigest()[:16].upper() + payload["id"] = f"HANDOFF-{digest}" + validate_handoff(payload) + return payload + + +def validate_handoff(payload: dict[str, Any]) -> None: + """Reject malformed or unsupported handoff claims before persistence/import.""" + if ( + payload.get("schema_version") != SCHEMA_VERSION + or payload.get("kind") != "epistemic_chat_handoff" + ): + raise ValueError("unsupported handoff schema") + if not isinstance(payload.get("id"), str) or not payload["id"].startswith("HANDOFF-"): + raise ValueError("handoff must have a stable ID") + if payload.get("confidence") != 1.0: + raise ValueError("extractive handoffs must retain confidence 1.0") + for turn in payload.get("turns", []): + if not isinstance(turn, dict) or not isinstance(turn.get("source_id"), str): + raise ValueError("handoff turn is missing provenance") + if not isinstance(turn.get("excerpt"), str) or len(turn["excerpt"]) > _MAX_EXCERPT: + raise ValueError("handoff excerpt is invalid") + + +def render_handoff_context(payload: dict[str, Any]) -> str: + """Render a bounded context entry that tells agents how to verify it.""" + validate_handoff(payload) + excerpts = "\n".join( + f"- [{turn['source_id']}] {turn['role']}: {turn['excerpt']}" for turn in payload["turns"] + ) + return ( + f"[Epistemic handoff {payload['id']} | {len(payload['turns'])} extractive turns | " + "verify source IDs before treating excerpts as decisions]\n" + f"{excerpts}" + ) + + +def store_handoff(root: Any, payload: dict[str, Any]) -> None: + """Persist a validated handoff in the active ESDB backend.""" + validate_handoff(payload) + from specsmith.esdb import SqliteRecord, open_default_store + + with open_default_store(root) as store: + store.upsert( + SqliteRecord( + id=payload["id"], + kind="chat_handoff", + label="Epistemic chat handoff", + confidence=1.0, + data=payload, + ), + ) diff --git a/src/specsmith/cli.py b/src/specsmith/cli.py index fc2ada3b..27f5e7c2 100644 --- a/src/specsmith/cli.py +++ b/src/specsmith/cli.py @@ -5,6 +5,7 @@ from __future__ import annotations import contextlib +import sys from pathlib import Path from typing import Any @@ -189,13 +190,17 @@ def _ver(v: str) -> tuple[int, ...]: if installed < project: # Backward migration (downgrade) — hard error, REQ-370. + from specsmith.updater import version_mismatch_remediation + + remedy = version_mismatch_remediation(project_ver) click.echo( f"\nERROR: specsmith downgrade detected.\n" f" Project spec_version : {project_ver}\n" f" Installed specsmith : {__version__} (older)\n" "\n" " Backward migration is not supported.\n" - " Upgrade specsmith first: pipx upgrade specsmith\n" + f" Install the required version: {remedy}\n" + " Stable projects can instead use: pipx upgrade specsmith\n" " Then re-run this command.", err=True, ) @@ -595,8 +600,19 @@ def _load_config_with_inheritance(config_path: str) -> dict[str, object]: VCS_PLATFORM_CHOICES = {"1": "github", "2": "gitlab", "3": "bitbucket", "4": ""} VCS_PLATFORM_LABELS = {"1": "GitHub", "2": "GitLab", "3": "Bitbucket", "4": "None"} -BRANCH_STRATEGY_CHOICES = {"1": "gitflow", "2": "trunk-based", "3": "github-flow"} -BRANCH_STRATEGY_LABELS = {"1": "Gitflow", "2": "Trunk-based", "3": "GitHub Flow"} +BRANCH_STRATEGY_CHOICES = { + "1": "single-branch", + "2": "gitflow", + "3": "trunk-based", + "4": "github-flow", +} +BRANCH_STRATEGY_LABELS = { + "1": "Single branch (direct governed work on main)", + "2": "Gitflow", + "3": "Trunk-based", + "4": "GitHub Flow", +} +_BRANCH_WORKFLOWS = tuple(BRANCH_STRATEGY_CHOICES.values()) def _interactive_config(no_git: bool) -> ProjectConfig: @@ -631,7 +647,7 @@ def _interactive_config(no_git: bool) -> ProjectConfig: for k, v in BRANCH_STRATEGY_LABELS.items(): console.print(f" {k}. {v}") branch_choice = click.prompt("Select strategy", default="1") - branching_strategy = BRANCH_STRATEGY_CHOICES.get(branch_choice, "gitflow") + branching_strategy = BRANCH_STRATEGY_CHOICES.get(branch_choice, "single-branch") return ProjectConfig( name=name, @@ -1881,6 +1897,17 @@ def _add(name: str, passed: bool, detail: str, warn: bool = False) -> None: ok, detail = _tool_version(tool) _add(tool, ok, detail) + if _is_windows_platform(): + from specsmith.updater import find_windows_launchers + + launchers = find_windows_launchers(__import__("os").environ.get("PATH", "")) + _add( + "specsmith launchers", + len(launchers) <= 1, + str(launchers[0]) if len(launchers) == 1 else f"{len(launchers)} found; use pipx only", + warn=len(launchers) > 1, + ) + overall = "pass" if all(c["status"] != "fail" for c in checks) else "fail" if as_json: @@ -1899,6 +1926,11 @@ def _add(name: str, passed: bool, detail: str, warn: bool = False) -> None: console.print("One or more checks failed.") +def _is_windows_platform() -> bool: + """Return whether the CLI is running on Windows.""" + return sys.platform == "win32" + + @main.command() @click.option( "--project-dir", @@ -3634,12 +3666,12 @@ def branch_create(name: str, project_dir: str) -> None: """Create a branch following the branching strategy.""" root = Path(project_dir).resolve() scaffold_path = root / "scaffold.yml" - strategy = "gitflow" + strategy = "single-branch" main_branch = "main" if scaffold_path.exists(): with open(scaffold_path) as f: raw = yaml.safe_load(f) or {} - strategy = raw.get("branching_strategy", "gitflow") + strategy = raw.get("branching_strategy", "single-branch") main_branch = raw.get("default_branch", "main") from specsmith.vcs_commands import create_branch @@ -3648,7 +3680,34 @@ def branch_create(name: str, project_dir: str) -> None: if result.success: console.print(f"[green]\u2713[/green] {result.message}") else: - console.print(f"[red]\u2717[/red] {result.message}") + raise click.ClickException(result.message) + + +@branch_group.command(name="workflow") +@click.argument("strategy", required=False, type=click.Choice(_BRANCH_WORKFLOWS)) +@click.option("--project-dir", type=click.Path(exists=True), default=".") +def branch_workflow(strategy: str | None, project_dir: str) -> None: + """Show or explicitly select the governed branching workflow.""" + root = Path(project_dir).resolve() + scaffold_path = root / "scaffold.yml" + if not scaffold_path.exists(): + raise click.ClickException( + "No scaffold.yml found; run specsmith init before selecting a workflow." + ) + + with scaffold_path.open(encoding="utf-8") as handle: + raw = yaml.safe_load(handle) or {} + current = str(raw.get("branching_strategy", "single-branch")) + if strategy is None: + console.print(f"Branch workflow: {current}") + return + + raw["branching_strategy"] = strategy + scaffold_path.write_text( + yaml.safe_dump(raw, default_flow_style=False, sort_keys=False), + encoding="utf-8", + ) + console.print(f"[green]\u2713[/green] Branch workflow set to {strategy}") @branch_group.command(name="list") @@ -3789,6 +3848,13 @@ def channel_set_cmd(channel: str) -> None: immediately for all subsequent ``specsmith self-update`` / ``update`` calls. """ from specsmith.channel import set_persisted_channel + from specsmith.updater import is_prerelease_version, version_mismatch_remediation + + if channel == "stable" and is_prerelease_version(__version__): + raise click.UsageError( + "Cannot select stable while a prerelease is installed. " + f"Install a stable build first: {version_mismatch_remediation('0.21.0')}" + ) set_persisted_channel(channel) channel_color = "cyan" if channel == "dev" else "green" @@ -14446,5 +14512,77 @@ def ai_analyze_cmd(project_dir: str, as_json: bool) -> None: raise SystemExit(1) from e +# Development mode and improvement tracking commands +@main.group(name="dev", invoke_without_command=True) +def dev_group() -> None: + """Development mode and improvement tracking commands.""" + pass + + +@dev_group.command(name="session-report") +@click.option( + "--session-id", + type=str, + default=None, + help="Session ID to report on (default: latest session).", +) +@click.option( + "--project-dir", + type=click.Path(exists=True), + default=".", + help="Project root directory.", +) +@click.option( + "--json", + "as_json", + is_flag=True, + default=False, + help="Emit results as JSON.", +) +def dev_session_report_cmd(session_id: str | None, project_dir: str, as_json: bool) -> None: + """Generate a session report with improvement analysis.""" + from pathlib import Path + + from specsmith.improvement_tracker import ImprovementTracker + + root = Path(project_dir).resolve() + tracker = ImprovementTracker(root) + + if as_json: + # Return JSON output + import json as _json + + if session_id: + analysis = tracker.get_session_analysis(session_id) + if analysis: + click.echo(_json.dumps(analysis.model_dump(), indent=2)) + else: + click.echo(_json.dumps({"error": "Session not found"}, indent=2)) + else: + # Get latest session + # For simplicity, we'll just list recent sessions + improvements = tracker.get_recent_improvements(10) + result = {"recent_improvements": [imp.model_dump() for imp in improvements]} + click.echo(_json.dumps(result, indent=2)) + else: + # Return human-readable output + if session_id: + analysis = tracker.get_session_analysis(session_id) + if analysis: + report = tracker.generate_session_report(session_id) + click.echo(report) + else: + click.echo(f"Session {session_id} not found.") + else: + # Show recent improvements + improvements = tracker.get_recent_improvements(10) + if improvements: + click.echo("Recent Improvements:") + for imp in improvements: + click.echo(f" - {imp.description} ({imp.severity})") + else: + click.echo("No recent improvements recorded.") + + if __name__ == "__main__": main() diff --git a/src/specsmith/commands/zoo_code.py b/src/specsmith/commands/zoo_code.py index ad343a28..11579d9d 100644 --- a/src/specsmith/commands/zoo_code.py +++ b/src/specsmith/commands/zoo_code.py @@ -22,6 +22,25 @@ def zoo_code_group() -> None: """Manage Zoo-Code integration and benchmarking for Specsmith.""" +@zoo_code_group.command("export-handoff") +@click.option("--project-dir", default=".", help="Governed project containing session state") +@click.option("--output", type=click.Path(), required=True, help="Portable handoff JSON path") +def zoo_code_export_handoff(project_dir: str, output: str) -> None: + """Export the latest session as a validated portable agent handoff.""" + from specsmith.chat_handoff import build_handoff + from specsmith.session_store import load_session + + root = Path(project_dir) + context, history = load_session(root) + handoff = build_handoff(history, work_item_ids=list((context or {}).get("work_item_ids", []))) + output_path = Path(output) + output_path.parent.mkdir(parents=True, exist_ok=True) + output_path.write_text( + json.dumps(handoff, indent=2, ensure_ascii=False) + "\n", encoding="utf-8" + ) + click.echo(f"Exported epistemic handoff {handoff['id']} to {output_path}") + + @zoo_code_group.command("init") @click.option("--output-dir", default=".", help="Directory to create Zoo-Code config files") def zoo_code_init(output_dir: str) -> None: diff --git a/src/specsmith/config.py b/src/specsmith/config.py index b61281b2..ea5d3454 100644 --- a/src/specsmith/config.py +++ b/src/specsmith/config.py @@ -98,7 +98,6 @@ class ProjectType(str, Enum): DESKTOP_TAURI = "desktop-tauri" # Tauri desktop app (Rust + WebView) # Brief lang — declarative contract-enforced logic language (github.com/Randozart/brief-lang) # Version anchor: v0.14.0 @ commit 6a43c4aebcc5c6c774dbc2908445fb19486e8043 (2026-06-14) - # No release tags exist yet; version string + commit hash are both recorded. BRIEF_LANG = "brief-lang" # .bv/.sbv/.rbv/.ebv project using brief-compiler @@ -141,7 +140,7 @@ class ProjectConfig(BaseModel): ), ) language: str = Field(default="python", description="Primary language/runtime") - spec_version: str = Field(default="0.20.1", description="Spec version to scaffold from") + spec_version: str = Field(default="0.22.0", description="Spec version to scaffold from") description: str = Field(default="", description="Short project description") # Options @@ -161,8 +160,8 @@ class ProjectConfig(BaseModel): # Branching strategy branching_strategy: str = Field( - default="gitflow", - description="Branching strategy (gitflow, trunk-based, github-flow)", + default="single-branch", + description="Branching strategy (single-branch, gitflow, trunk-based, github-flow)", ) default_branch: str = Field( default="main", @@ -456,6 +455,10 @@ class ProjectConfig(BaseModel): default=False, description="Enable cryptographic trace vault (ESDB seal_record; REQ-420)", ) + enable_development_mode: bool = Field( + default=False, + description="Enable development mode with additional logging and improvement tracking", + ) @property def package_name(self) -> str: diff --git a/src/specsmith/context_orchestrator.py b/src/specsmith/context_orchestrator.py index d4ec1467..83241b3f 100644 --- a/src/specsmith/context_orchestrator.py +++ b/src/specsmith/context_orchestrator.py @@ -156,10 +156,11 @@ def _run_tier2(self, result: OptimizeResultEx) -> None: half = len(result.history) // 2 dropped = result.history[:half] kept = result.history[half:] - summary_content = ( - f"[Earlier conversation summary — {len(dropped)} turns condensed. " - "Key context preserved in ESDB and LEDGER.md.]" - ) + from specsmith.chat_handoff import build_handoff, render_handoff_context, store_handoff + + handoff = build_handoff(dropped) + store_handoff(self.root, handoff) + summary_content = render_handoff_context(handoff) result.history = [{"role": "assistant", "content": summary_content}] + kept freed = sum(len(t.get("content", "")) for t in dropped) // 4 # ~4 chars/token result.tokens_freed_estimate += freed diff --git a/src/specsmith/importer.py b/src/specsmith/importer.py index 19909e88..2eae777e 100644 --- a/src/specsmith/importer.py +++ b/src/specsmith/importer.py @@ -1316,7 +1316,9 @@ def generate_import_config(result: DetectionResult) -> ProjectConfig: spec_version = "0.3.0" # safe fallback # Detect branching strategy from git history (#107) - branching_strategy = _detect_branching_strategy(result.root) if result.has_git else "trunk" + branching_strategy = ( + _detect_branching_strategy(result.root) if result.has_git else "single-branch" + ) # Detect shell wrappers from scripts/ directory (#108) shell_wrappers = _detect_shell_wrappers(result.root) # Detect proprietary license: no LICENSE file + not a known open-source project diff --git a/src/specsmith/improvement_tracker.py b/src/specsmith/improvement_tracker.py new file mode 100644 index 00000000..b6b93a9f --- /dev/null +++ b/src/specsmith/improvement_tracker.py @@ -0,0 +1,186 @@ +# SPDX-License-Identifier: MIT +# Copyright (c) 2026 Layer1Labs Silicon, Inc. All rights reserved. +"""Improvement tracking and session analysis for development mode.""" + +import json +import logging +from pathlib import Path +from types import TracebackType +from typing import Any + +import yaml +from pydantic import BaseModel + +LOGGER = logging.getLogger(__name__) + + +class ImprovementRecord(BaseModel): + """Record of an improvement suggestion or session analysis.""" + + timestamp: str + type: str # "session", "bug", "efficiency", "skill" + description: str + severity: str # "low", "medium", "high", "critical" + status: str # "pending", "implemented", "rejected" + metrics: dict[str, Any] | None = None + + +class SessionAnalysis(BaseModel): + """Analysis of a session including what worked, what didn't, and improvements.""" + + session_id: str + start_time: str + end_time: str + duration_seconds: int + work_items_completed: list[str] + cost_per_correct_solution: float + efficiency_metrics: dict[str, float] + improvements: list[ImprovementRecord] + session_notes: str + + +class ImprovementTracker: + """Tracks improvements, session analysis, and development metrics.""" + + def __init__(self, project_dir: Path): + self.project_dir = project_dir + self.improvements_dir = project_dir / ".specsmith" / "improvements" + self.improvements_dir.mkdir(parents=True, exist_ok=True) + + # Setup logging for development mode + self.logger = logging.getLogger("specsmith.improvement") + self.logger.setLevel(logging.DEBUG if self._is_development_mode() else logging.INFO) + + # Create file handler for improvement logs + log_file = self.improvements_dir / "improvements.log" + handler = logging.FileHandler(log_file) + formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s") + handler.setFormatter(formatter) + self.logger.addHandler(handler) + self.log_handler: logging.FileHandler | None = handler + + def close(self) -> None: + """Explicitly close logging handlers to prevent file lock issues.""" + if hasattr(self, "log_handler") and self.log_handler: + self.log_handler.close() + self.logger.removeHandler(self.log_handler) + self.log_handler = None + + def __enter__(self) -> "ImprovementTracker": + return self + + def __exit__( + self, + exc_type: type[BaseException] | None, + exc_val: BaseException | None, + exc_tb: TracebackType | None, + ) -> None: + self.close() + + def _is_development_mode(self) -> bool: + """Check if development mode is enabled in project config.""" + config_file = self.project_dir / ".specsmith" / "config.yml" + config: object = {} + try: + if config_file.exists(): + with open(config_file, encoding="utf-8") as f: + config = yaml.safe_load(f) or {} + except (OSError, yaml.YAMLError): + LOGGER.warning("Could not read development-mode config: %s", config_file, exc_info=True) + return False + + if isinstance(config, dict): + return bool(config.get("enable_development_mode", False)) + return False + + def record_session_analysis(self, analysis: SessionAnalysis) -> None: + """Record session analysis to file and log.""" + # Save to JSON file + # Sanitize session_id for Windows compatibility (remove invalid characters) + sanitized_session_id = analysis.session_id.replace(":", "-").replace("/", "-") + session_file = self.improvements_dir / f"session_{sanitized_session_id}.json" + with open(session_file, "w") as f: + json.dump(analysis.model_dump(), f, indent=2) + + # Log the session analysis + self.logger.info(f"Session analysis recorded: {analysis.session_id}") + self.logger.info(f"Duration: {analysis.duration_seconds}s") + self.logger.info(f"Work items completed: {len(analysis.work_items_completed)}") + self.logger.info(f"Cost per correct solution: {analysis.cost_per_correct_solution}") + + # Log improvements + for improvement in analysis.improvements: + self.logger.info(f"Improvement: {improvement.description} ({improvement.severity})") + + def record_improvement(self, improvement: ImprovementRecord) -> None: + """Record an improvement suggestion.""" + # Save to JSON file + # For Windows compatibility, we need to sanitize the timestamp in the filename + # but the timestamp in the data should remain unchanged + sanitized_timestamp = improvement.timestamp.replace(":", "-").replace("/", "-") + improvement_file = self.improvements_dir / f"improvement_{sanitized_timestamp}.json" + with open(improvement_file, "w") as f: + json.dump(improvement.model_dump(), f, indent=2) + + # Log the improvement + self.logger.info(f"Improvement recorded: {improvement.description}") + self.logger.info(f"Severity: {improvement.severity}, Status: {improvement.status}") + + def get_session_analysis(self, session_id: str) -> SessionAnalysis | None: + """Retrieve session analysis by session ID.""" + # Sanitize session_id for Windows compatibility (remove invalid characters) + sanitized_session_id = session_id.replace(":", "-").replace("/", "-") + session_file = self.improvements_dir / f"session_{sanitized_session_id}.json" + if session_file.exists(): + with open(session_file) as f: + data = json.load(f) + return SessionAnalysis(**data) + return None + + def get_recent_improvements(self, limit: int = 10) -> list[ImprovementRecord]: + """Get recent improvement records.""" + improvements = [] + for file_path in self.improvements_dir.glob("improvement_*.json"): + try: + with open(file_path) as f: + data = json.load(f) + improvements.append(ImprovementRecord(**data)) + except (OSError, json.JSONDecodeError, TypeError, ValueError): + self.logger.warning( + "Skipping unreadable improvement record: %s", file_path, exc_info=True + ) + + # Sort by timestamp (newest first) + improvements.sort(key=lambda x: x.timestamp, reverse=True) + return improvements[:limit] + + def generate_session_report(self, session_id: str) -> str: + """Generate a human-readable session report.""" + analysis = self.get_session_analysis(session_id) + if not analysis: + return "No session analysis found." + + report = [ + f"Session Report: {session_id}", + f"Start Time: {analysis.start_time}", + f"End Time: {analysis.end_time}", + f"Duration: {analysis.duration_seconds} seconds", + f"Work Items Completed: {len(analysis.work_items_completed)}", + f"Cost per Correct Solution: {analysis.cost_per_correct_solution}", + "", + "Efficiency Metrics:", + ] + + for metric, value in analysis.efficiency_metrics.items(): + report.append(f" {metric}: {value}") + + report.append("") + report.append("Improvements:") + + if not analysis.improvements: + report.append(" No improvements recorded.") + else: + for improvement in analysis.improvements: + report.append(f" - {improvement.description} ({improvement.severity})") + + return "\n".join(report) diff --git a/src/specsmith/integrations/warp.py b/src/specsmith/integrations/warp.py index 86ac8102..2101ade9 100644 --- a/src/specsmith/integrations/warp.py +++ b/src/specsmith/integrations/warp.py @@ -146,7 +146,7 @@ def _render_setup_guide(self, config: ProjectConfig) -> str: # noqa: ARG002 ```bash # Session start -specsmith kill-session 2>/dev/null || true +specsmith kill-session # idempotent; safe when no processes exist specsmith audit --project-dir . specsmith sync --project-dir . specsmith checkpoint --project-dir . # output GOVERNANCE ANCHOR verbatim diff --git a/src/specsmith/migrations/__init__.py b/src/specsmith/migrations/__init__.py index 124513db..72441d13 100644 --- a/src/specsmith/migrations/__init__.py +++ b/src/specsmith/migrations/__init__.py @@ -121,6 +121,8 @@ def _load(self) -> list[Migration]: m008_esdb_full_coverage, m009_esdb_first, m010_post_esdb_cleanup, + m011_windows_skill_shell, + m012_normalize_skill_shell, ) instances: list[Migration] = [ @@ -134,6 +136,8 @@ def _load(self) -> list[Migration]: m008_esdb_full_coverage.EsdbFullCoverageMigration(), m009_esdb_first.EsdbFirstMigration(), m010_post_esdb_cleanup.PostEsdbCleanupMigration(), + m011_windows_skill_shell.WindowsSkillShellMigration(), + m012_normalize_skill_shell.NormalizeSkillShellMigration(), ] instances.sort(key=lambda m: m.version) self._migrations = instances diff --git a/src/specsmith/migrations/m006_session_governance.py b/src/specsmith/migrations/m006_session_governance.py index 51729caf..d8ee869e 100644 --- a/src/specsmith/migrations/m006_session_governance.py +++ b/src/specsmith/migrations/m006_session_governance.py @@ -55,7 +55,7 @@ ### Session start (run once, output result verbatim) ```bash -specsmith kill-session 2>/dev/null || true # kill orphaned processes +specsmith kill-session # idempotent; safe when no processes exist specsmith audit --project-dir . # verify governance health specsmith sync --project-dir . # confirm machine state specsmith checkpoint --project-dir . # emit GOVERNANCE ANCHOR diff --git a/src/specsmith/migrations/m011_windows_skill_shell.py b/src/specsmith/migrations/m011_windows_skill_shell.py new file mode 100644 index 00000000..2513b4d0 --- /dev/null +++ b/src/specsmith/migrations/m011_windows_skill_shell.py @@ -0,0 +1,64 @@ +# SPDX-License-Identifier: MIT +# Copyright (c) 2026 Layer1Labs Silicon, Inc. All rights reserved. +"""M011 -- replace Bash-only session cleanup in generated agent skills.""" + +from __future__ import annotations + +import os +from pathlib import Path + +from specsmith.migrations import Migration, MigrationResult + +_LEGACY_COMMAND = "specsmith kill-session 2>/dev/null || true" +_COMMAND_PREFIX = "specsmith kill-session" +_PREVIOUS_SAFE_COMMAND = f"{_COMMAND_PREFIX}{' ' * 24}# idempotent; safe when no processes exist" +_SAFE_COMMAND = "specsmith kill-session # idempotent; safe when no processes exist" + + +class WindowsSkillShellMigration(Migration): + """Keep generated agent instructions usable in PowerShell and POSIX shells.""" + + version = 11 + title = "Replace Bash-only generated skill session cleanup" + description = ( + "Replaces Bash stderr redirection in generated agent skill session-start " + "instructions with a shell-neutral idempotent specsmith command." + ) + + def run(self, root: Path, *, dry_run: bool = False) -> MigrationResult: + """Rewrite only materialized skill files inside the project root.""" + result = MigrationResult(version=self.version, title=self.title, dry_run=dry_run) + safe_root = os.path.realpath(str(root)) + safe_skills_dir = os.path.realpath(str(Path(safe_root) / ".agents" / "skills")) + skills_dir = Path(safe_skills_dir) + changed: list[str] = [] + + if not skills_dir.is_dir(): + result.message = "No materialized agent skills found -- nothing to migrate." + return result + + for skill_path in sorted(skills_dir.rglob("SKILL.md")): + safe_skill_path = os.path.realpath(str(skill_path)) + if not safe_skill_path.startswith(safe_skills_dir + os.sep): + continue + + path = Path(safe_skill_path) + content = path.read_text(encoding="utf-8") + if _LEGACY_COMMAND not in content: + continue + + if not dry_run: + path.write_text( + content.replace(_LEGACY_COMMAND, _SAFE_COMMAND).replace( + _PREVIOUS_SAFE_COMMAND, + _SAFE_COMMAND, + ), + encoding="utf-8", + ) + changed.append(str(path.relative_to(safe_root)).replace("\\", "/")) + + result.files_modified.extend(changed) + result.message = ( + f"{'Would update' if dry_run else 'Updated'} {len(changed)} generated skill file(s)." + ) + return result diff --git a/src/specsmith/migrations/m012_normalize_skill_shell.py b/src/specsmith/migrations/m012_normalize_skill_shell.py new file mode 100644 index 00000000..24409727 --- /dev/null +++ b/src/specsmith/migrations/m012_normalize_skill_shell.py @@ -0,0 +1,56 @@ +# SPDX-License-Identifier: MIT +# Copyright (c) 2026 Layer1Labs Silicon, Inc. All rights reserved. +"""M012 -- normalize the first Windows-safe generated-skill command.""" + +from __future__ import annotations + +import os +from pathlib import Path + +from specsmith.migrations import Migration, MigrationResult + +_COMMAND_PREFIX = "specsmith kill-session" +_PREVIOUS_SAFE_COMMAND = f"{_COMMAND_PREFIX}{' ' * 24}# idempotent; safe when no processes exist" +_SAFE_COMMAND = "specsmith kill-session # idempotent; safe when no processes exist" + + +class NormalizeSkillShellMigration(Migration): + """Normalize a command emitted by M011 without changing its behavior.""" + + version = 12 + title = "Normalize generated skill session cleanup" + description = "Normalizes the shell-neutral session cleanup command emitted by M011." + + def run(self, root: Path, *, dry_run: bool = False) -> MigrationResult: + """Rewrite only the prior M011 command inside materialized skill files.""" + result = MigrationResult(version=self.version, title=self.title, dry_run=dry_run) + safe_root = os.path.realpath(str(root)) + safe_skills_dir = os.path.realpath(str(Path(safe_root) / ".agents" / "skills")) + skills_dir = Path(safe_skills_dir) + + if not skills_dir.is_dir(): + result.message = "No materialized agent skills found -- nothing to normalize." + return result + + for skill_path in sorted(skills_dir.rglob("SKILL.md")): + safe_skill_path = os.path.realpath(str(skill_path)) + if not safe_skill_path.startswith(safe_skills_dir + os.sep): + continue + + path = Path(safe_skill_path) + content = path.read_text(encoding="utf-8") + if _PREVIOUS_SAFE_COMMAND not in content: + continue + + if not dry_run: + path.write_text( + content.replace(_PREVIOUS_SAFE_COMMAND, _SAFE_COMMAND), + encoding="utf-8", + ) + result.files_modified.append(str(path.relative_to(safe_root)).replace("\\", "/")) + + result.message = ( + f"{'Would normalize' if dry_run else 'Normalized'} " + f"{len(result.files_modified)} generated skill file(s)." + ) + return result diff --git a/src/specsmith/model_optimizer.py b/src/specsmith/model_optimizer.py new file mode 100644 index 00000000..a3a2d5f0 --- /dev/null +++ b/src/specsmith/model_optimizer.py @@ -0,0 +1,182 @@ +""" +Model-aware optimization system for Specsmith. + +This module provides functionality to optimize agent behavior based on model characteristics +and runtime environment, including temperature adjustments, context length management, +and runtime-specific optimizations. +""" + +from typing import Any + +from .model_registry import ModelProfile, get_model_profile + + +class ModelOptimizer: + """Handles model-aware optimizations for Specsmith agents.""" + + def __init__(self) -> None: + """Initialize the model optimizer.""" + self._model_profiles: dict[str, ModelProfile] = {} + + def get_optimized_parameters( + self, + model_name: str, + task_type: str = "general", + current_parameters: dict[str, Any] | None = None, + ) -> dict[str, Any]: + """ + Get optimized parameters for a given model and task type. + + Args: + model_name: Name of the model to optimize for + task_type: Type of task (e.g., "reasoning", "coding", "summarization") + current_parameters: Current parameter settings to build upon + + Returns: + Dictionary of optimized parameters + """ + if current_parameters is None: + current_parameters = {} + + # Get model profile + profile = get_model_profile(model_name) + if not profile: + # Return defaults if no profile found + return self._get_default_parameters(task_type, current_parameters) + + # Start with current parameters + optimized = current_parameters.copy() + + # Apply model-specific optimizations + if profile.recommended_temperature is not None: + optimized["temperature"] = profile.recommended_temperature + + # Apply task-specific optimizations + optimized = self._apply_task_optimizations(task_type, profile, optimized) + + # Apply runtime-specific optimizations + optimized = self._apply_runtime_optimizations(profile, optimized) + + return optimized + + def _get_default_parameters( + self, task_type: str, current_parameters: dict[str, Any] + ) -> dict[str, Any]: + """Get default parameters when no model profile is available.""" + optimized = current_parameters.copy() + + # Default temperature based on task type + task_temperatures = {"reasoning": 0.7, "coding": 0.2, "summarization": 0.5, "general": 0.7} + + optimized["temperature"] = task_temperatures.get(task_type, 0.7) + return optimized + + def _apply_task_optimizations( + self, task_type: str, profile: ModelProfile, parameters: dict[str, Any] + ) -> dict[str, Any]: + """Apply task-specific optimizations.""" + optimized = parameters.copy() + + # Adjust temperature based on task type + if task_type == "coding" and profile.supports_function_calling: + # Lower temperature for coding tasks + optimized["temperature"] = min(0.3, optimized.get("temperature", 0.7)) + elif task_type == "reasoning": + # Slightly higher temperature for reasoning + optimized["temperature"] = min(0.8, optimized.get("temperature", 0.7)) + elif task_type == "summarization": + # Moderate temperature for summarization + optimized["temperature"] = min(0.6, optimized.get("temperature", 0.7)) + + return optimized + + def _apply_runtime_optimizations( + self, profile: ModelProfile, parameters: dict[str, Any] + ) -> dict[str, Any]: + """Apply runtime-specific optimizations.""" + optimized = parameters.copy() + + # Context length optimization + if profile.context_length: + # Set context length to a reasonable value (e.g., 80% of max) + optimized["max_context_length"] = int(profile.context_length * 0.8) + + # Runtime-specific settings + if profile.recommended_runtime: + optimized["runtime"] = profile.recommended_runtime + + return optimized + + def get_skill_recommendations(self, model_name: str, task_type: str = "general") -> list[str]: + """ + Get recommended skills based on model characteristics and task type. + + Args: + model_name: Name of the model + task_type: Type of task + + Returns: + List of recommended skill slugs + """ + profile = get_model_profile(model_name) + recommendations: list[str] = [] + + if not profile: + return recommendations + + # Add skills based on model capabilities + if profile.supports_function_calling: + recommendations.append("function-caller") + + if profile.supports_json_output: + recommendations.append("json-output-formatter") + + if profile.supports_tools: + recommendations.append("tool-caller") + + # Add task-specific skills + if task_type == "coding": + recommendations.append("code-generator") + recommendations.append("code-analyzer") + elif task_type == "reasoning": + recommendations.append("logical-reasoner") + recommendations.append("problem-solver") + elif task_type == "summarization": + recommendations.append("text-summarizer") + + return recommendations + + +# Global optimizer instance +model_optimizer = ModelOptimizer() + + +def optimize_for_model( + model_name: str, task_type: str = "general", parameters: dict[str, Any] | None = None +) -> dict[str, Any]: + """ + Convenience function to get optimized parameters for a model and task. + + Args: + model_name: Name of the model + task_type: Type of task + parameters: Current parameters to optimize + + Returns: + Optimized parameters dictionary + """ + return model_optimizer.get_optimized_parameters(model_name, task_type, parameters) + + +def get_model_recommendations(model_name: str, task_type: str = "general") -> list[str]: + """ + Get recommended skills for a given model and task type. + + Args: + model_name: Name of the model + task_type: Type of task + + Returns: + List of recommended skill slugs + """ + return model_optimizer.get_skill_recommendations(model_name, task_type) diff --git a/src/specsmith/model_registry.py b/src/specsmith/model_registry.py new file mode 100644 index 00000000..0804131e --- /dev/null +++ b/src/specsmith/model_registry.py @@ -0,0 +1,970 @@ +""" +Model profile registry for Specsmith. + +This module contains the registry of known models with their profiles, +including performance characteristics, cost estimates, and optimization +recommendations for different runtime environments. +""" + +from dataclasses import dataclass + + +@dataclass +class ModelProfile: + """Profile for a specific model with optimization characteristics.""" + + name: str + """The name of the model (e.g., 'Qwen3.6-35B-A3B')""" + + provider: str + """The provider of the model (e.g., 'Qwen', 'OpenAI', 'Anthropic')""" + + context_length: int + """Maximum context length in tokens""" + + cost_per_million_input_tokens: float + """Cost per million input tokens (USD)""" + + cost_per_million_output_tokens: float + """Cost per million output tokens (USD)""" + + recommended_runtime: str + """Recommended runtime environment (vLLM, Ollama, LM Studio, llama.cpp)""" + + recommended_temperature: float + """Recommended temperature for optimal performance""" + + tags: list[str] + """Tags for categorizing the model (e.g., 'large', 'reasoning', 'cost-effective')""" + + description: str + """Human-readable description of the model""" + + # Optional fields for advanced features + supports_function_calling: bool = False + """Whether the model supports function calling""" + + supports_json_output: bool = False + """Whether the model supports JSON output formatting""" + + supports_tools: bool = False + """Whether the model supports tool calling""" + + # Performance characteristics + tokens_per_second: float | None = None + """Average tokens per second for generation (if available)""" + + max_concurrent_requests: int | None = None + """Maximum concurrent requests supported (if available)""" + + +# Registry of known model profiles +MODEL_REGISTRY: dict[str, ModelProfile] = { + "Qwen3.6-35B-A3B": ModelProfile( + name="Qwen3.6-35B-A3B", + provider="Qwen", + context_length=128000, + cost_per_million_input_tokens=0.01, + cost_per_million_output_tokens=0.03, + recommended_runtime="vLLM", + recommended_temperature=0.7, + tags=["large", "reasoning", "cost-effective", "multilingual"], + description="Qwen3.6 35B parameter model with advanced reasoning capabilities " + "and multilingual support.", + supports_function_calling=True, + supports_json_output=True, + supports_tools=True, + tokens_per_second=150.0, + max_concurrent_requests=10, + ), + "meta-llama/Meta-Llama-3-70B": ModelProfile( + name="meta-llama/Meta-Llama-3-70B", + provider="Hugging Face", + context_length=8192, + cost_per_million_input_tokens=0.0, + cost_per_million_output_tokens=0.0, + recommended_runtime="vLLM", + recommended_temperature=0.7, + tags=["large", "reasoning", "open-source"], + description="Meta Llama 3 70B parameter model, one of the most capable open-source models.", + supports_function_calling=True, + supports_json_output=True, + supports_tools=True, + tokens_per_second=120.0, + max_concurrent_requests=5, + ), + "meta-llama/Meta-Llama-3-8B": ModelProfile( + name="meta-llama/Meta-Llama-3-8B", + provider="Hugging Face", + context_length=8192, + cost_per_million_input_tokens=0.0, + cost_per_million_output_tokens=0.0, + recommended_runtime="vLLM", + recommended_temperature=0.7, + tags=["medium", "reasoning", "open-source"], + description="Meta Llama 3 8B parameter model, efficient and capable for many tasks.", + supports_function_calling=True, + supports_json_output=True, + supports_tools=True, + tokens_per_second=200.0, + max_concurrent_requests=10, + ), + "mistralai/Mistral-7B-v0.3": ModelProfile( + name="mistralai/Mistral-7B-v0.3", + provider="Hugging Face", + context_length=32768, + cost_per_million_input_tokens=0.0, + cost_per_million_output_tokens=0.0, + recommended_runtime="vLLM", + recommended_temperature=0.7, + tags=["medium", "reasoning", "open-source"], + description="Mistral 7B model with strong performance and efficiency.", + supports_function_calling=True, + supports_json_output=True, + supports_tools=True, + tokens_per_second=180.0, + max_concurrent_requests=8, + ), + "google/gemma-2-27b": ModelProfile( + name="google/gemma-2-27b", + provider="Hugging Face", + context_length=8192, + cost_per_million_input_tokens=0.0, + cost_per_million_output_tokens=0.0, + recommended_runtime="vLLM", + recommended_temperature=0.7, + tags=["large", "reasoning", "open-source"], + description="Google Gemma 2 27B model with strong reasoning capabilities.", + supports_function_calling=True, + supports_json_output=True, + supports_tools=True, + tokens_per_second=160.0, + max_concurrent_requests=6, + ), + "microsoft/Phi-3-medium-128k": ModelProfile( + name="microsoft/Phi-3-medium-128k", + provider="Hugging Face", + context_length=128000, + cost_per_million_input_tokens=0.0, + cost_per_million_output_tokens=0.0, + recommended_runtime="vLLM", + recommended_temperature=0.7, + tags=["medium", "reasoning", "open-source"], + description="Microsoft Phi-3 medium model with long context window.", + supports_function_calling=True, + supports_json_output=True, + supports_tools=True, + tokens_per_second=140.0, + max_concurrent_requests=7, + ), + # Popular Hugging Face models based on downloads + "meta-llama/Llama-3.2-1B": ModelProfile( + name="meta-llama/Llama-3.2-1B", + provider="Hugging Face", + context_length=8192, + cost_per_million_input_tokens=0.0, + cost_per_million_output_tokens=0.0, + recommended_runtime="vLLM", + recommended_temperature=0.7, + tags=["small", "reasoning", "open-source", "fast"], + description="Meta Llama 3.2 1B parameter model, optimized for speed and efficiency.", + supports_function_calling=True, + supports_json_output=True, + supports_tools=True, + tokens_per_second=250.0, + max_concurrent_requests=15, + ), + "meta-llama/Llama-3.2-3B": ModelProfile( + name="meta-llama/Llama-3.2-3B", + provider="Hugging Face", + context_length=8192, + cost_per_million_input_tokens=0.0, + cost_per_million_output_tokens=0.0, + recommended_runtime="vLLM", + recommended_temperature=0.7, + tags=["medium", "reasoning", "open-source"], + description="Meta Llama 3.2 3B parameter model, good balance of performance " + "and efficiency.", + supports_function_calling=True, + supports_json_output=True, + supports_tools=True, + tokens_per_second=220.0, + max_concurrent_requests=12, + ), + "meta-llama/Llama-3.1-8B": ModelProfile( + name="meta-llama/Llama-3.1-8B", + provider="Hugging Face", + context_length=8192, + cost_per_million_input_tokens=0.0, + cost_per_million_output_tokens=0.0, + recommended_runtime="vLLM", + recommended_temperature=0.7, + tags=["medium", "reasoning", "open-source"], + description="Meta Llama 3.1 8B parameter model, optimized for reasoning and chat.", + supports_function_calling=True, + supports_json_output=True, + supports_tools=True, + tokens_per_second=200.0, + max_concurrent_requests=10, + ), + "meta-llama/Llama-3.1-70B": ModelProfile( + name="meta-llama/Llama-3.1-70B", + provider="Hugging Face", + context_length=8192, + cost_per_million_input_tokens=0.0, + cost_per_million_output_tokens=0.0, + recommended_runtime="vLLM", + recommended_temperature=0.7, + tags=["large", "reasoning", "open-source"], + description="Meta Llama 3.1 70B parameter model, one of the most capable " + "open-source models.", + supports_function_calling=True, + supports_json_output=True, + supports_tools=True, + tokens_per_second=120.0, + max_concurrent_requests=5, + ), + "mistralai/Mistral-7B-Instruct-v0.3": ModelProfile( + name="mistralai/Mistral-7B-Instruct-v0.3", + provider="Hugging Face", + context_length=32768, + cost_per_million_input_tokens=0.0, + cost_per_million_output_tokens=0.0, + recommended_runtime="vLLM", + recommended_temperature=0.7, + tags=["medium", "reasoning", "open-source", "instruction-tuned"], + description="Mistral 7B instruction-tuned model with strong performance.", + supports_function_calling=True, + supports_json_output=True, + supports_tools=True, + tokens_per_second=180.0, + max_concurrent_requests=8, + ), + "mistralai/Mistral-8x7B-v0.3": ModelProfile( + name="mistralai/Mistral-8x7B-v0.3", + provider="Hugging Face", + context_length=32768, + cost_per_million_input_tokens=0.0, + cost_per_million_output_tokens=0.0, + recommended_runtime="vLLM", + recommended_temperature=0.7, + tags=["large", "reasoning", "open-source", "multi-query"], + description="Mistral 8x7B model with 56B parameters, optimized for multi-query tasks.", + supports_function_calling=True, + supports_json_output=True, + supports_tools=True, + tokens_per_second=100.0, + max_concurrent_requests=4, + ), + "google/gemma-2-9b": ModelProfile( + name="google/gemma-2-9b", + provider="Hugging Face", + context_length=8192, + cost_per_million_input_tokens=0.0, + cost_per_million_output_tokens=0.0, + recommended_runtime="vLLM", + recommended_temperature=0.7, + tags=["medium", "reasoning", "open-source"], + description="Google Gemma 2 9B parameter model with strong reasoning capabilities.", + supports_function_calling=True, + supports_json_output=True, + supports_tools=True, + tokens_per_second=190.0, + max_concurrent_requests=10, + ), + "microsoft/Phi-3-mini-128k": ModelProfile( + name="microsoft/Phi-3-mini-128k", + provider="Hugging Face", + context_length=128000, + cost_per_million_input_tokens=0.0, + cost_per_million_output_tokens=0.0, + recommended_runtime="vLLM", + recommended_temperature=0.7, + tags=["small", "reasoning", "open-source", "fast"], + description="Microsoft Phi-3 mini model with long context window and fast performance.", + supports_function_calling=True, + supports_json_output=True, + supports_tools=True, + tokens_per_second=240.0, + max_concurrent_requests=12, + ), + "microsoft/Phi-3-small-128k": ModelProfile( + name="microsoft/Phi-3-small-128k", + provider="Hugging Face", + context_length=128000, + cost_per_million_input_tokens=0.0, + cost_per_million_output_tokens=0.0, + recommended_runtime="vLLM", + recommended_temperature=0.7, + tags=["medium", "reasoning", "open-source"], + description="Microsoft Phi-3 small model with long context window.", + supports_function_calling=True, + supports_json_output=True, + supports_tools=True, + tokens_per_second=180.0, + max_concurrent_requests=8, + ), + "Qwen/Qwen3-7B": ModelProfile( + name="Qwen/Qwen3-7B", + provider="Qwen", + context_length=32768, + cost_per_million_input_tokens=0.0, + cost_per_million_output_tokens=0.0, + recommended_runtime="vLLM", + recommended_temperature=0.7, + tags=["medium", "reasoning", "multilingual"], + description="Qwen3 7B parameter model with strong multilingual capabilities.", + supports_function_calling=True, + supports_json_output=True, + supports_tools=True, + tokens_per_second=170.0, + max_concurrent_requests=10, + ), + "Qwen/Qwen3-32B": ModelProfile( + name="Qwen/Qwen3-32B", + provider="Qwen", + context_length=32768, + cost_per_million_input_tokens=0.0, + cost_per_million_output_tokens=0.0, + recommended_runtime="vLLM", + recommended_temperature=0.7, + tags=["large", "reasoning", "multilingual"], + description="Qwen3 32B parameter model with advanced reasoning capabilities.", + supports_function_calling=True, + supports_json_output=True, + supports_tools=True, + tokens_per_second=140.0, + max_concurrent_requests=8, + ), + "openai/gpt-4": ModelProfile( + name="openai/gpt-4", + provider="OpenAI", + context_length=128000, + cost_per_million_input_tokens=30.0, + cost_per_million_output_tokens=60.0, + recommended_runtime="OpenAI API", + recommended_temperature=0.7, + tags=["large", "reasoning", "api"], + description="OpenAI GPT-4 model with advanced reasoning capabilities.", + supports_function_calling=True, + supports_json_output=True, + supports_tools=True, + tokens_per_second=80.0, + max_concurrent_requests=2, + ), + "openai/gpt-4-turbo": ModelProfile( + name="openai/gpt-4-turbo", + provider="OpenAI", + context_length=128000, + cost_per_million_input_tokens=10.0, + cost_per_million_output_tokens=30.0, + recommended_runtime="OpenAI API", + recommended_temperature=0.7, + tags=["large", "reasoning", "api", "cost-effective"], + description="OpenAI GPT-4 Turbo model with improved performance and cost efficiency.", + supports_function_calling=True, + supports_json_output=True, + supports_tools=True, + tokens_per_second=100.0, + max_concurrent_requests=3, + ), + "openai/gpt-3.5-turbo": ModelProfile( + name="openai/gpt-3.5-turbo", + provider="OpenAI", + context_length=16385, + cost_per_million_input_tokens=0.5, + cost_per_million_output_tokens=1.5, + recommended_runtime="OpenAI API", + recommended_temperature=0.7, + tags=["medium", "reasoning", "api", "cost-effective"], + description="OpenAI GPT-3.5 Turbo model, fast and cost-effective for many tasks.", + supports_function_calling=True, + supports_json_output=True, + supports_tools=True, + tokens_per_second=150.0, + max_concurrent_requests=5, + ), + "anthropic/claude-3-opus": ModelProfile( + name="anthropic/claude-3-opus", + provider="Anthropic", + context_length=200000, + cost_per_million_input_tokens=15.0, + cost_per_million_output_tokens=75.0, + recommended_runtime="Anthropic API", + recommended_temperature=0.7, + tags=["large", "reasoning", "api", "creative"], + description="Anthropic Claude 3 Opus model with advanced reasoning and creativity.", + supports_function_calling=True, + supports_json_output=True, + supports_tools=True, + tokens_per_second=60.0, + max_concurrent_requests=2, + ), + "anthropic/claude-3-sonnet": ModelProfile( + name="anthropic/claude-3-sonnet", + provider="Anthropic", + context_length=200000, + cost_per_million_input_tokens=3.0, + cost_per_million_output_tokens=15.0, + recommended_runtime="Anthropic API", + recommended_temperature=0.7, + tags=["large", "reasoning", "api", "balanced"], + description="Anthropic Claude 3 Sonnet model with balanced performance and cost.", + supports_function_calling=True, + supports_json_output=True, + supports_tools=True, + tokens_per_second=80.0, + max_concurrent_requests=3, + ), + "anthropic/claude-3-haiku": ModelProfile( + name="anthropic/claude-3-haiku", + provider="Anthropic", + context_length=200000, + cost_per_million_input_tokens=0.25, + cost_per_million_output_tokens=1.25, + recommended_runtime="Anthropic API", + recommended_temperature=0.7, + tags=["small", "reasoning", "api", "fast"], + description="Anthropic Claude 3 Haiku model with fast response times.", + supports_function_calling=True, + supports_json_output=True, + supports_tools=True, + tokens_per_second=200.0, + max_concurrent_requests=10, + ), + # Frontier models with high performance + "google/gemini-pro": ModelProfile( + name="google/gemini-pro", + provider="Google", + context_length=32768, + cost_per_million_input_tokens=0.5, + cost_per_million_output_tokens=1.5, + recommended_runtime="Google API", + recommended_temperature=0.7, + tags=["large", "reasoning", "api", "multimodal"], + description="Google Gemini Pro model with multimodal capabilities.", + supports_function_calling=True, + supports_json_output=True, + supports_tools=True, + tokens_per_second=120.0, + max_concurrent_requests=4, + ), + "google/gemini-1.5-pro": ModelProfile( + name="google/gemini-1.5-pro", + provider="Google", + context_length=200000, + cost_per_million_input_tokens=1.0, + cost_per_million_output_tokens=3.0, + recommended_runtime="Google API", + recommended_temperature=0.7, + tags=["large", "reasoning", "api", "multimodal"], + description="Google Gemini 1.5 Pro model with enhanced capabilities.", + supports_function_calling=True, + supports_json_output=True, + supports_tools=True, + tokens_per_second=100.0, + max_concurrent_requests=3, + ), + "google/gemini-1.5-flash": ModelProfile( + name="google/gemini-1.5-flash", + provider="Google", + context_length=100000, + cost_per_million_input_tokens=0.075, + cost_per_million_output_tokens=0.3, + recommended_runtime="Google API", + recommended_temperature=0.7, + tags=["medium", "reasoning", "api", "fast"], + description="Google Gemini 1.5 Flash model with fast response times.", + supports_function_calling=True, + supports_json_output=True, + supports_tools=True, + tokens_per_second=250.0, + max_concurrent_requests=8, + ), + "meta-llama/Llama-3.3-70B": ModelProfile( + name="meta-llama/Llama-3.3-70B", + provider="Hugging Face", + context_length=128000, + cost_per_million_input_tokens=0.0, + cost_per_million_output_tokens=0.0, + recommended_runtime="vLLM", + recommended_temperature=0.7, + tags=["large", "reasoning", "open-source"], + description="Meta Llama 3.3 70B parameter model, latest iteration with improved " + "performance.", + supports_function_calling=True, + supports_json_output=True, + supports_tools=True, + tokens_per_second=110.0, + max_concurrent_requests=5, + ), + "meta-llama/Llama-3.3-8B": ModelProfile( + name="meta-llama/Llama-3.3-8B", + provider="Hugging Face", + context_length=8192, + cost_per_million_input_tokens=0.0, + cost_per_million_output_tokens=0.0, + recommended_runtime="vLLM", + recommended_temperature=0.7, + tags=["medium", "reasoning", "open-source"], + description="Meta Llama 3.3 8B parameter model, optimized for efficiency.", + supports_function_calling=True, + supports_json_output=True, + supports_tools=True, + tokens_per_second=210.0, + max_concurrent_requests=10, + ), + "mistralai/Mistral-Large": ModelProfile( + name="mistralai/Mistral-Large", + provider="Hugging Face", + context_length=32768, + cost_per_million_input_tokens=0.0, + cost_per_million_output_tokens=0.0, + recommended_runtime="vLLM", + recommended_temperature=0.7, + tags=["large", "reasoning", "open-source"], + description="Mistral Large model with strong reasoning capabilities.", + supports_function_calling=True, + supports_json_output=True, + supports_tools=True, + tokens_per_second=130.0, + max_concurrent_requests=6, + ), + "google/gemma-2-9b-it": ModelProfile( + name="google/gemma-2-9b-it", + provider="Hugging Face", + context_length=8192, + cost_per_million_input_tokens=0.0, + cost_per_million_output_tokens=0.0, + recommended_runtime="vLLM", + recommended_temperature=0.7, + tags=["medium", "reasoning", "open-source", "instruction-tuned"], + description="Google Gemma 2 9B instruction-tuned model with strong performance.", + supports_function_calling=True, + supports_json_output=True, + supports_tools=True, + tokens_per_second=190.0, + max_concurrent_requests=10, + ), + "microsoft/Phi-3.5-mini": ModelProfile( + name="microsoft/Phi-3.5-mini", + provider="Hugging Face", + context_length=128000, + cost_per_million_input_tokens=0.0, + cost_per_million_output_tokens=0.0, + recommended_runtime="vLLM", + recommended_temperature=0.7, + tags=["small", "reasoning", "open-source", "fast"], + description="Microsoft Phi-3.5 mini model with improved performance and speed.", + supports_function_calling=True, + supports_json_output=True, + supports_tools=True, + tokens_per_second=260.0, + max_concurrent_requests=15, + ), + "microsoft/Phi-3.5-small": ModelProfile( + name="microsoft/Phi-3.5-small", + provider="Hugging Face", + context_length=128000, + cost_per_million_input_tokens=0.0, + cost_per_million_output_tokens=0.0, + recommended_runtime="vLLM", + recommended_temperature=0.7, + tags=["medium", "reasoning", "open-source"], + description="Microsoft Phi-3.5 small model with balanced performance.", + supports_function_calling=True, + supports_json_output=True, + supports_tools=True, + tokens_per_second=190.0, + max_concurrent_requests=10, + ), + "Qwen/Qwen3-72B": ModelProfile( + name="Qwen/Qwen3-72B", + provider="Qwen", + context_length=32768, + cost_per_million_input_tokens=0.0, + cost_per_million_output_tokens=0.0, + recommended_runtime="vLLM", + recommended_temperature=0.7, + tags=["large", "reasoning", "multilingual"], + description="Qwen3 72B parameter model with advanced reasoning capabilities.", + supports_function_calling=True, + supports_json_output=True, + supports_tools=True, + tokens_per_second=130.0, + max_concurrent_requests=8, + ), + "meta-llama/Llama-3.2-1B-Instruct": ModelProfile( + name="meta-llama/Llama-3.2-1B-Instruct", + provider="Hugging Face", + context_length=8192, + cost_per_million_input_tokens=0.0, + cost_per_million_output_tokens=0.0, + recommended_runtime="vLLM", + recommended_temperature=0.7, + tags=["small", "reasoning", "open-source", "instruction-tuned"], + description="Meta Llama 3.2 1B instruction-tuned model optimized for chat.", + supports_function_calling=True, + supports_json_output=True, + supports_tools=True, + tokens_per_second=250.0, + max_concurrent_requests=15, + ), + "meta-llama/Llama-3.2-3B-Instruct": ModelProfile( + name="meta-llama/Llama-3.2-3B-Instruct", + provider="Hugging Face", + context_length=8192, + cost_per_million_input_tokens=0.0, + cost_per_million_output_tokens=0.0, + recommended_runtime="vLLM", + recommended_temperature=0.7, + tags=["medium", "reasoning", "open-source", "instruction-tuned"], + description="Meta Llama 3.2 3B instruction-tuned model with good performance.", + supports_function_calling=True, + supports_json_output=True, + supports_tools=True, + tokens_per_second=220.0, + max_concurrent_requests=12, + ), + "meta-llama/Llama-3.1-8B-Instruct": ModelProfile( + name="meta-llama/Llama-3.1-8B-Instruct", + provider="Hugging Face", + context_length=8192, + cost_per_million_input_tokens=0.0, + cost_per_million_output_tokens=0.0, + recommended_runtime="vLLM", + recommended_temperature=0.7, + tags=["medium", "reasoning", "open-source", "instruction-tuned"], + description="Meta Llama 3.1 8B instruction-tuned model optimized for chat.", + supports_function_calling=True, + supports_json_output=True, + supports_tools=True, + tokens_per_second=200.0, + max_concurrent_requests=10, + ), + "mistralai/Mistral-7B-v0.3-Instruct": ModelProfile( + name="mistralai/Mistral-7B-v0.3-Instruct", + provider="Hugging Face", + context_length=32768, + cost_per_million_input_tokens=0.0, + cost_per_million_output_tokens=0.0, + recommended_runtime="vLLM", + recommended_temperature=0.7, + tags=["medium", "reasoning", "open-source", "instruction-tuned"], + description="Mistral 7B instruction-tuned model with strong performance.", + supports_function_calling=True, + supports_json_output=True, + supports_tools=True, + tokens_per_second=180.0, + max_concurrent_requests=8, + ), + "google/gemma-2-27b-it": ModelProfile( + name="google/gemma-2-27b-it", + provider="Hugging Face", + context_length=8192, + cost_per_million_input_tokens=0.0, + cost_per_million_output_tokens=0.0, + recommended_runtime="vLLM", + recommended_temperature=0.7, + tags=["large", "reasoning", "open-source", "instruction-tuned"], + description="Google Gemma 2 27B instruction-tuned model with strong reasoning.", + supports_function_calling=True, + supports_json_output=True, + supports_tools=True, + tokens_per_second=160.0, + max_concurrent_requests=6, + ), + "microsoft/Phi-3.5-medium-128k": ModelProfile( + name="microsoft/Phi-3.5-medium-128k", + provider="Hugging Face", + context_length=128000, + cost_per_million_input_tokens=0.0, + cost_per_million_output_tokens=0.0, + recommended_runtime="vLLM", + recommended_temperature=0.7, + tags=["medium", "reasoning", "open-source"], + description="Microsoft Phi-3.5 medium model with long context window.", + supports_function_calling=True, + supports_json_output=True, + supports_tools=True, + tokens_per_second=180.0, + max_concurrent_requests=8, + ), + "meta-llama/Llama-3.3-70B-Instruct": ModelProfile( + name="meta-llama/Llama-3.3-70B-Instruct", + provider="Hugging Face", + context_length=128000, + cost_per_million_input_tokens=0.0, + cost_per_million_output_tokens=0.0, + recommended_runtime="vLLM", + recommended_temperature=0.7, + tags=["large", "reasoning", "open-source", "instruction-tuned"], + description="Meta Llama 3.3 70B instruction-tuned model with improved performance.", + supports_function_calling=True, + supports_json_output=True, + supports_tools=True, + tokens_per_second=110.0, + max_concurrent_requests=5, + ), + "meta-llama/Llama-3.3-8B-Instruct": ModelProfile( + name="meta-llama/Llama-3.3-8B-Instruct", + provider="Hugging Face", + context_length=8192, + cost_per_million_input_tokens=0.0, + cost_per_million_output_tokens=0.0, + recommended_runtime="vLLM", + recommended_temperature=0.7, + tags=["medium", "reasoning", "open-source", "instruction-tuned"], + description="Meta Llama 3.3 8B instruction-tuned model optimized for efficiency.", + supports_function_calling=True, + supports_json_output=True, + supports_tools=True, + tokens_per_second=210.0, + max_concurrent_requests=10, + ), + "Qwen/Qwen3-7B-Instruct": ModelProfile( + name="Qwen/Qwen3-7B-Instruct", + provider="Qwen", + context_length=32768, + cost_per_million_input_tokens=0.0, + cost_per_million_output_tokens=0.0, + recommended_runtime="vLLM", + recommended_temperature=0.7, + tags=["medium", "reasoning", "multilingual", "instruction-tuned"], + description="Qwen3 7B instruction-tuned model with strong multilingual capabilities.", + supports_function_calling=True, + supports_json_output=True, + supports_tools=True, + tokens_per_second=170.0, + max_concurrent_requests=10, + ), + "Qwen/Qwen3-32B-Instruct": ModelProfile( + name="Qwen/Qwen3-32B-Instruct", + provider="Qwen", + context_length=32768, + cost_per_million_input_tokens=0.0, + cost_per_million_output_tokens=0.0, + recommended_runtime="vLLM", + recommended_temperature=0.7, + tags=["large", "reasoning", "multilingual", "instruction-tuned"], + description="Qwen3 32B instruction-tuned model with advanced reasoning capabilities.", + supports_function_calling=True, + supports_json_output=True, + supports_tools=True, + tokens_per_second=140.0, + max_concurrent_requests=8, + ), + "Qwen/Qwen3-72B-Instruct": ModelProfile( + name="Qwen/Qwen3-72B-Instruct", + provider="Qwen", + context_length=32768, + cost_per_million_input_tokens=0.0, + cost_per_million_output_tokens=0.0, + recommended_runtime="vLLM", + recommended_temperature=0.7, + tags=["large", "reasoning", "multilingual", "instruction-tuned"], + description="Qwen3 72B instruction-tuned model with advanced reasoning capabilities.", + supports_function_calling=True, + supports_json_output=True, + supports_tools=True, + tokens_per_second=130.0, + max_concurrent_requests=8, + ), + # Additional popular Hugging Face models + "meta-llama/Llama-3.2-11B-Vision": ModelProfile( + name="meta-llama/Llama-3.2-11B-Vision", + provider="Hugging Face", + context_length=128000, + cost_per_million_input_tokens=0.0, + cost_per_million_output_tokens=0.0, + recommended_runtime="vLLM", + recommended_temperature=0.7, + tags=["medium", "vision", "open-source", "multimodal"], + description="Meta Llama 3.2 11B Vision model with multimodal capabilities.", + supports_function_calling=True, + supports_json_output=True, + supports_tools=True, + tokens_per_second=150.0, + max_concurrent_requests=8, + ), + "meta-llama/Llama-3.2-90B-Vision": ModelProfile( + name="meta-llama/Llama-3.2-90B-Vision", + provider="Hugging Face", + context_length=128000, + cost_per_million_input_tokens=0.0, + cost_per_million_output_tokens=0.0, + recommended_runtime="vLLM", + recommended_temperature=0.7, + tags=["large", "vision", "open-source", "multimodal"], + description="Meta Llama 3.2 90B Vision model with advanced multimodal capabilities.", + supports_function_calling=True, + supports_json_output=True, + supports_tools=True, + tokens_per_second=100.0, + max_concurrent_requests=5, + ), + # Frontier models with high performance + "google/gemini-2.0-flash": ModelProfile( + name="google/gemini-2.0-flash", + provider="Google", + context_length=1000000, + cost_per_million_input_tokens=0.075, + cost_per_million_output_tokens=0.3, + recommended_runtime="Google API", + recommended_temperature=0.7, + tags=["medium", "reasoning", "api", "fast"], + description="Google Gemini 2.0 Flash model with enhanced capabilities and speed.", + supports_function_calling=True, + supports_json_output=True, + supports_tools=True, + tokens_per_second=300.0, + max_concurrent_requests=10, + ), + "google/gemini-2.0-pro": ModelProfile( + name="google/gemini-2.0-pro", + provider="Google", + context_length=2000000, + cost_per_million_input_tokens=1.0, + cost_per_million_output_tokens=3.0, + recommended_runtime="Google API", + recommended_temperature=0.7, + tags=["large", "reasoning", "api", "multimodal"], + description="Google Gemini 2.0 Pro model with advanced multimodal capabilities.", + supports_function_calling=True, + supports_json_output=True, + supports_tools=True, + tokens_per_second=150.0, + max_concurrent_requests=5, + ), + "openai/gpt-4o": ModelProfile( + name="openai/gpt-4o", + provider="OpenAI", + context_length=128000, + cost_per_million_input_tokens=5.0, + cost_per_million_output_tokens=15.0, + recommended_runtime="OpenAI API", + recommended_temperature=0.7, + tags=["large", "reasoning", "api", "multimodal"], + description="OpenAI GPT-4o model with advanced multimodal capabilities.", + supports_function_calling=True, + supports_json_output=True, + supports_tools=True, + tokens_per_second=120.0, + max_concurrent_requests=3, + ), + "openai/gpt-4o-mini": ModelProfile( + name="openai/gpt-4o-mini", + provider="OpenAI", + context_length=128000, + cost_per_million_input_tokens=0.15, + cost_per_million_output_tokens=0.6, + recommended_runtime="OpenAI API", + recommended_temperature=0.7, + tags=["small", "reasoning", "api", "fast"], + description="OpenAI GPT-4o mini model with fast response times.", + supports_function_calling=True, + supports_json_output=True, + supports_tools=True, + tokens_per_second=200.0, + max_concurrent_requests=8, + ), + "anthropic/claude-3-5-sonnet": ModelProfile( + name="anthropic/claude-3-5-sonnet", + provider="Anthropic", + context_length=200000, + cost_per_million_input_tokens=3.0, + cost_per_million_output_tokens=15.0, + recommended_runtime="Anthropic API", + recommended_temperature=0.7, + tags=["large", "reasoning", "api", "balanced"], + description="Anthropic Claude 3.5 Sonnet model with enhanced performance.", + supports_function_calling=True, + supports_json_output=True, + supports_tools=True, + tokens_per_second=90.0, + max_concurrent_requests=4, + ), + "anthropic/claude-3-5-haiku": ModelProfile( + name="anthropic/claude-3-5-haiku", + provider="Anthropic", + context_length=200000, + cost_per_million_input_tokens=0.25, + cost_per_million_output_tokens=1.25, + recommended_runtime="Anthropic API", + recommended_temperature=0.7, + tags=["small", "reasoning", "api", "fast"], + description="Anthropic Claude 3.5 Haiku model with improved speed.", + supports_function_calling=True, + supports_json_output=True, + supports_tools=True, + tokens_per_second=250.0, + max_concurrent_requests=12, + ), +} + + +def get_model_profile(model_name: str) -> ModelProfile | None: + """ + Get a model profile by name. + + Args: + model_name: The name of the model + + Returns: + The model profile if found, None otherwise + """ + return MODEL_REGISTRY.get(model_name) + + +def list_models() -> list[str]: + """ + List all available model names in the registry. + + Returns: + List of model names + """ + return list(MODEL_REGISTRY.keys()) + + +def add_model_profile(profile: ModelProfile) -> None: + """ + Add a new model profile to the registry. + + Args: + profile: The model profile to add + """ + MODEL_REGISTRY[profile.name] = profile + + +def remove_model_profile(model_name: str) -> bool: + """ + Remove a model profile from the registry. + + Args: + model_name: The name of the model to remove + + Returns: + True if removed, False if not found + """ + if model_name in MODEL_REGISTRY: + del MODEL_REGISTRY[model_name] + return True + return False + + +# For backward compatibility +def get_model_profiles() -> dict[str, ModelProfile]: + """ + Get all model profiles (alias for MODEL_REGISTRY). + + Returns: + Dictionary of all model profiles + """ + return MODEL_REGISTRY + + +# Example usage: +# profile = get_model_profile("Qwen3.6-35B-A3B") +# print(profile.name) +# print(profile.provider) +# print(profile.context_length) diff --git a/src/specsmith/quality_report.py b/src/specsmith/quality_report.py index 8661a408..cb88f36e 100644 --- a/src/specsmith/quality_report.py +++ b/src/specsmith/quality_report.py @@ -187,6 +187,10 @@ def render_markdown(data: QualityReportData) -> str: lines.append("") # Raw JSON appendix + footer = ( + "*Generated by `specsmith quality-report`. " + + "Run `specsmith metrics report` for session-level detail.*" + ) lines += [ "## 7. Raw Data (JSON)", "", @@ -209,8 +213,7 @@ def render_markdown(data: QualityReportData) -> str: "", "---", "", - "*Generated by `specsmith quality-report`. " - "Run `specsmith metrics report` for session-level detail.*", + footer, ] return "\n".join(lines) diff --git a/src/specsmith/release_guard.py b/src/specsmith/release_guard.py new file mode 100644 index 00000000..c80adf07 --- /dev/null +++ b/src/specsmith/release_guard.py @@ -0,0 +1,36 @@ +"""Stable-release version validation (REQ-450).""" + +from __future__ import annotations + +import re + +_DEVELOPMENT_VERSION = re.compile(r"\d+\.\d+\.\d+\.dev\d+") +_STABLE_VERSION = re.compile(r"\d+\.\d+\.\d+") + + +def is_stable_version(version: str) -> bool: + """Return whether *version* is a plain PEP 440 release without a suffix.""" + return _STABLE_VERSION.fullmatch(version) is not None + + +def is_development_version(version: str) -> bool: + """Return whether *version* belongs to the explicit development channel.""" + return _DEVELOPMENT_VERSION.fullmatch(version) is not None + + +def require_stable_version(version: str, expected_version: str | None = None) -> None: + """Raise a clear error before any stable-channel publication.""" + if not is_stable_version(version): + raise ValueError(f"Stable release rejects non-final version: {version}") + if expected_version is not None and version != expected_version.lstrip("v"): + raise ValueError(f"Stable release version {version} does not match tag {expected_version}") + + +def require_development_version(version: str, expected_version: str | None = None) -> None: + """Raise a clear error before an artifact enters the development channel.""" + if not is_development_version(version): + raise ValueError(f"Development release requires an X.Y.Z.devN version: {version}") + if expected_version is not None and version != expected_version: + raise ValueError( + f"Development release version {version} does not match expected {expected_version}" + ) diff --git a/src/specsmith/session_store.py b/src/specsmith/session_store.py index 73c16f1e..2e134d2a 100644 --- a/src/specsmith/session_store.py +++ b/src/specsmith/session_store.py @@ -18,6 +18,7 @@ from __future__ import annotations +import hashlib import json import os import time @@ -25,6 +26,7 @@ from typing import Any MAX_TURNS = 200 # Maximum conversation turns to retain in history file +_EVENTS_FILE = "session-events.jsonl" def save_session( @@ -56,6 +58,22 @@ def save_session( capped = history[-MAX_TURNS:] _atomic_write_jsonl(hist_path, capped) + # Canonical, merge-friendly session history. SQLite remains a local index; + # this append-only text artifact is safe to review and reconcile in Git. + events_path = root / ".chronomemory" / _EVENTS_FILE + events_path.parent.mkdir(parents=True, exist_ok=True) + event = { + "schema_version": 1, + "saved_at": ctx_dict["saved_at"], + "context": ctx_dict, + "history": capped, + } + canonical = json.dumps(event, sort_keys=True, ensure_ascii=False) + digest = hashlib.sha256(canonical.encode("utf-8")).hexdigest()[:16].upper() + event["event_id"] = "SESSION-" + digest + existing = _load_events(events_path) + _atomic_write_jsonl(events_path, merge_session_events(existing, [event])) + def load_session( root: Path, @@ -67,6 +85,18 @@ def load_session( """ specsmith_dir = root / ".specsmith" + events = _load_events(root / ".chronomemory" / _EVENTS_FILE) + if events: + valid = [ + event + for event in events + if event.get("schema_version") == 1 and isinstance(event.get("context"), dict) + ] + if valid: + latest = max(valid, key=lambda e: str(e.get("saved_at", ""))) + history = latest.get("history", []) + if isinstance(history, list) and all(isinstance(turn, dict) for turn in history): + return dict(latest["context"]), history # Load session state state_path = specsmith_dir / "session-state.json" @@ -92,6 +122,43 @@ def load_session( return ctx_dict, history +def merge_session_events(*event_sets: list[dict[str, Any]]) -> list[dict[str, Any]]: + """Merge branch event sets by immutable ID in deterministic replay order.""" + merged: dict[str, dict[str, Any]] = {} + for events in event_sets: + for event in events: + event_id = event.get("event_id") + if not isinstance(event_id, str) or not event_id.startswith("SESSION-"): + continue + existing = merged.get(event_id) + if existing is None: + merged[event_id] = event + elif json.dumps(existing, sort_keys=True) != json.dumps(event, sort_keys=True): + raise ValueError(f"conflicting session event ID: {event_id}") + return sorted( + merged.values(), key=lambda event: (str(event.get("saved_at", "")), event["event_id"]) + ) + + +def rebuild_local_session_index(root: Path) -> int: + """Rebuild local SQLite session records from canonical session events.""" + from specsmith.esdb import SqliteRecord, SqliteStore + + events = merge_session_events(_load_events(root / ".chronomemory" / _EVENTS_FILE)) + with SqliteStore(root) as store: + for event in events: + store.upsert( + SqliteRecord( + id=event["event_id"], + kind="session_event", + label="Canonical session event", + confidence=1.0, + data=event, + ) + ) + return len(events) + + def make_resume_message(ctx_dict: dict[str, Any]) -> dict[str, Any]: """Build a synthetic assistant turn to inject at the start of a resumed session. @@ -151,3 +218,18 @@ def _atomic_write_jsonl(path: Path, records: list[dict[str, Any]]) -> None: tmp = path.with_suffix(".jsonl.tmp") tmp.write_text(content, encoding="utf-8") os.replace(str(tmp), str(path)) + + +def _load_events(path: Path) -> list[dict[str, Any]]: + """Read well-formed canonical events, ignoring malformed merge remnants.""" + if not path.is_file(): + return [] + events: list[dict[str, Any]] = [] + for line in path.read_text(encoding="utf-8").splitlines(): + try: + value = json.loads(line) + except json.JSONDecodeError: + continue + if isinstance(value, dict): + events.append(value) + return events diff --git a/src/specsmith/skills/__init__.py b/src/specsmith/skills/__init__.py index 82ca841c..c33b38f6 100644 --- a/src/specsmith/skills/__init__.py +++ b/src/specsmith/skills/__init__.py @@ -133,6 +133,8 @@ def _build_catalog() -> list[SkillEntry]: platform_engineering, productivity, software_engineering, + specsmith_core_commands, + # specsmith_operations, # unused import specsmith_skills, ssh, web_backend, @@ -151,6 +153,7 @@ def _build_catalog() -> list[SkillEntry]: + corporate.SKILLS + docs.SKILLS + specsmith_skills.SKILLS + + specsmith_core_commands.SKILLS # New domains + ai_agents.SKILLS + software_engineering.SKILLS @@ -197,89 +200,82 @@ def search(query: str, *, domain: SkillDomain | None = None) -> list[SkillEntry] """ catalog = _get_catalog() needle = query.strip().lower() - results = ( - catalog - if not needle - else [ - e - for e in catalog - if needle in " ".join([e.slug, e.name, e.description, *e.tags]).lower() - ] - ) + if not needle: + return catalog if domain is not None: - results = [e for e in results if e.domain == domain] - return results + catalog = [entry for entry in catalog if entry.domain == domain] + matches = [] + for entry in catalog: + if ( + needle in entry.slug.lower() + or needle in entry.name.lower() + or needle in entry.description.lower() + or any(needle in tag.lower() for tag in entry.tags) + ): + matches.append(entry) + return matches def get(slug: str) -> SkillEntry | None: - """Return the catalog entry for *slug*, or ``None`` if not found.""" - for entry in _get_catalog(): + """Return a skill by slug, or None if not found.""" + catalog = _get_catalog() + for entry in catalog: if entry.slug == slug: return entry return None def by_domain(domain: SkillDomain) -> list[SkillEntry]: - """Return all skills in *domain*, sorted by slug.""" - return sorted( - (e for e in _get_catalog() if e.domain == domain), - key=lambda e: e.slug, - ) - - -def by_project_type(project_type: str) -> list[SkillEntry]: - """Return skills applicable to *project_type* (includes all-type skills).""" - return [e for e in _get_catalog() if not e.project_types or project_type in e.project_types] + """Return all skills in a domain.""" + catalog = _get_catalog() + return [entry for entry in catalog if entry.domain == domain] def installed_skills(project_dir: Path) -> list[Path]: - """Return installed skill files under ``.agents/skills/`` (both flat and subdir formats).""" - base = project_dir / ".agents" / "skills" - if not base.is_dir(): + """Return list of installed skill files in the project.""" + skills_dir = project_dir / ".agents" / "skills" + if not skills_dir.exists(): return [] - paths: list[Path] = [] - for item in sorted(base.iterdir()): - if item.is_file() and item.suffix == ".md": # legacy flat format - paths.append(item) - elif item.is_dir() and (item / "SKILL.md").exists(): # subdir format - paths.append(item / "SKILL.md") - return sorted(paths) + return sorted([*skills_dir.glob("*/SKILL.md"), *skills_dir.glob("*.md")]) def install(slug: str, project_dir: Path, *, force: bool = False) -> Path: - """Copy skill *slug* into ``<project_dir>/.agents/skills/<slug>/SKILL.md``. + """Install a skill into the project's .agents/skills/ directory. + + Parameters + ---------- + slug: + The skill slug to install. + project_dir: + The project root directory. + force: + If True, overwrite existing files. + + Returns + ------- + Path: + The path to the installed skill file. Raises ------ - KeyError - Unknown slug. - FileExistsError - Already installed and ``force=False``. + KeyError: + If the skill slug is not found in the catalog. """ - entry = get(slug) - if entry is None: - raise KeyError(f"Unknown skill: {slug!r}") - base = project_dir / ".agents" / "skills" - base.mkdir(parents=True, exist_ok=True) - # Subdirectory format: <slug>/SKILL.md (REQ-360) - skill_dir = base / slug - skill_dir.mkdir(exist_ok=True) - target = skill_dir / "SKILL.md" - if target.exists() and not force: - raise FileExistsError(f"Already installed: {target}. Pass force=True to overwrite.") - target.write_text(entry.body, encoding="utf-8") - return target - - -# --------------------------------------------------------------------------- -# Back-compat: expose CATALOG as plain list (not property) -# --------------------------------------------------------------------------- -# Modules that do ``from specsmith.skills import CATALOG`` get this list. -# We populate it lazily on first module access via __getattr__. + skill = get(slug) + if skill is None: + raise KeyError(f"Skill {slug!r} not found in catalog") + skill_dir = project_dir / ".agents" / "skills" / skill.slug + skill_dir.mkdir(parents=True, exist_ok=True) + skill_path = skill_dir / "SKILL.md" + if not force and skill_path.exists(): + raise FileExistsError(f"Already installed: skill {slug!r} at {skill_path}") + skill_path.write_text(skill.body, encoding="utf-8") + return skill_path def __getattr__(name: str) -> object: + """Lazy-load the catalog on first access to any attribute.""" if name == "CATALOG": return _get_catalog() - raise AttributeError(name) + raise AttributeError(f"module {__name__!r} has no attribute {name!r}") diff --git a/src/specsmith/skills/governance.py b/src/specsmith/skills/governance.py index 2a034c70..bd019787 100644 --- a/src/specsmith/skills/governance.py +++ b/src/specsmith/skills/governance.py @@ -1,1370 +1,523 @@ -# SPDX-License-Identifier: MIT -"""Governance skills — project lifecycle, verification, review, and release.""" +""" +Core governance skills for Specsmith. +This module contains the fundamental governance skills that control agent behavior +and ensure proper governance compliance. +""" from specsmith.skills import SkillDomain, SkillEntry -SKILLS: list[SkillEntry] = [ - SkillEntry( - slug="verifier", - name="Verifier — five-gate verification", - description=( - "Runs the standard five-gate loop: ruff, mypy, pytest, pip-audit, " - "and specsmith audit/validate. Halts at the first failing gate." - ), - domain=SkillDomain.GOVERNANCE, - tags=["verification", "ci", "python", "lint", "test", "security"], - project_types=["cli-python", "library-python", "backend-frontend"], - platforms=[], - prerequisites=["ruff", "mypy", "pytest", "pip-audit"], - body=( - "# Verifier Skill\n\n" - "## Purpose\n" - "Enforce a deterministic, ordered quality gate before any commit.\n\n" - "## Gates (run in strict order — halt at first failure)\n" - "1. `ruff check .` — zero lint errors.\n" - "2. `ruff format --check src tests` — zero format drift.\n" - "3. `mypy src/` — zero type errors.\n" - "4. `pytest -q --tb=short` — all tests green.\n" - "5. `pip-audit` — no known vulnerabilities.\n" - "6. `specsmith audit && specsmith validate --strict` — governance clean.\n\n" - "## Rules\n" - "- Never skip a gate. Never amend a commit to bypass failures.\n" - "- Surface the first failing gate's output verbatim in your response.\n" - "- If gate 6 fails with a sync-drift warning, run `specsmith sync` first.\n\n" - "## After all gates pass\n" - '```\nspecsmith ledger add "All gates passed — ready to commit"\n' - 'git add -A && git commit -m "<msg>"\n```\n' - ), - ), - SkillEntry( - slug="planner", - name="Planner — propose-then-execute", - description=( - "Forces the agent to emit a Plan block with explicit success criteria " - "before any tool call. Each step is gated on prior-step success." - ), - domain=SkillDomain.GOVERNANCE, - tags=["planning", "governance", "aee"], - prerequisites=[], - body=( - "# Planner Skill\n\n" - "## Purpose\n" - "Prevent surprise changes. All work must be planned before execution.\n\n" - "## Protocol\n" - "1. Emit a `Plan:` block listing each step with a measurable success criterion.\n" - "2. Wait for user confirmation (`safe` profile) or proceed (`yolo` profile).\n" - "3. Execute steps one at a time; update `status: done | failed` after each.\n" - "4. Never call tools outside the plan. If new work is discovered, amend the plan.\n" - "5. Log plan completion to LEDGER.md.\n\n" - "## Plan block format\n" - "```\nPlan:\n 1. [step] — success: [criterion]\n" - " 2. [step] — success: [criterion]\n```\n" - ), - ), - SkillEntry( - slug="diff-reviewer", - name="Diff Reviewer — surface changes for approval", - description=( - "Emits a diff block per changed file and waits for Accept/Reject " - "before committing. Rejected diffs feed the next retry." - ), - domain=SkillDomain.GOVERNANCE, - tags=["review", "diff", "governance", "approval"], - prerequisites=[], - body=( - "# Diff Reviewer Skill\n\n" - "## When to use\n" - "Any task that modifies source files, config, or governance docs.\n\n" - "## Protocol\n" - "1. Perform all changes in working tree (do not commit yet).\n" - "2. Run `git diff HEAD` and emit one fenced diff block per file.\n" - "3. Pause and wait for `accept` / `reject` / `comment` per diff.\n" - "4. For rejected diffs: revert that file, apply the comment as context, retry.\n" - "5. Only commit once every diff has been accepted.\n\n" - "## Rules\n" - "- Never auto-accept your own changes.\n" - "- Surface the full diff, not a summary. Summaries hide bugs.\n" - ), - ), - SkillEntry( - slug="onboarding-coach", - name="Onboarding Coach — guided first session", - description=( - "Walks a new user through the project: scaffold check, REQUIREMENTS " - "tour, AGENTS.md rules summary, and a suggested first action." - ), - domain=SkillDomain.GOVERNANCE, - tags=["onboarding", "documentation", "new-user"], - prerequisites=["specsmith"], - body=( - "# Onboarding Coach Skill\n\n" - "## Sequence\n" - "1. `specsmith doctor --onboarding` — surface any missing setup step.\n" - "2. Read `AGENTS.md`; summarise hard rules in ≤ 5 bullets.\n" - "3. Read `docs/REQUIREMENTS.md`; list top 5 P1 requirements.\n" - "4. `specsmith phase show` — report current AEE phase and readiness %.\n" - "5. Suggest one concrete preflight utterance the user can run next.\n\n" - "## Output format\n" - "```\n🌱 Phase: <phase> (<pct>% ready)\n" - "📋 Top requirements: ...\n📌 Rules: ...\n" - '→ Suggested next: specsmith preflight "..."\n```\n' - ), - ), - SkillEntry( - slug="release-pilot", - name="Release Pilot — gitflow release cut", - description=( - "Drives a full gitflow release: CI green check, version bump, " - "CHANGELOG entry, tag, and publish." - ), - domain=SkillDomain.GOVERNANCE, - tags=["release", "vcs", "gitflow", "automation", "pypi", "github"], - prerequisites=["gh", "git"], - body=( - "# Release Pilot Skill\n\n" - "## Preconditions (abort if any fail)\n" - "- `gh run list --branch develop --limit 1 --json conclusion` = `SUCCESS`.\n" - "- `gh pr list --state open --base main` returns 0 open PRs.\n" - "- `CHANGELOG.md` has the new version section already drafted.\n" - "- `specsmith audit && specsmith validate --strict` clean on develop.\n\n" - "## Sequence\n" - "1. Bump version: `specsmith release <version>`.\n" - "2. `git add -A && git commit -m 'release: v<version>'`.\n" - "3. Push develop: `git push origin develop`.\n" - "4. Wait for CI: `gh run watch`.\n" - "5. Merge to main: `git checkout main && git merge --ff-only develop`.\n" - "6. Tag: `git tag -a v<version> -m 'v<version>'`.\n" - "7. Push: `git push origin main --tags`.\n" - "8. Release workflow handles PyPI upload + GitHub Release automatically.\n\n" - "## Rollback\n" - "If step 7 fails: `git tag -d v<version> && git reset --hard HEAD~1`.\n" - ), - ), + +# preflight-gate skill implementation +def preflight_gate() -> None: + """ + Purpose: + Force every agent to run Specsmith preflight before any write, code change, + command with side effects, dependency change, branch operation, release, + or destructive operation. + + Required behavior: + Before action: + specsmith preflight "<intended action>" --json + + If decision == accepted: + proceed with work_item_id in scope + + If decision == needs_clarification: + stop and surface clarification to user + + If decision == rejected: + stop and explain why + + If no preflight was run: + do not modify files + """ + pass # Implementation would be in the CLI/command layer + + +# governed-agent-loop skill implementation +def governed_agent_loop() -> None: + """ + Purpose: + Define the default execution loop for any agent operating inside a Specmith project. + + Loop: + inspect -> anchor -> classify -> preflight -> retrieve context -> act -> verify -> record -> save + + Detailed flow: + 1. Detect Specsmith project. + 2. Run session bootstrap. + 3. Emit governance anchor. + 4. Classify user intent: + - read_only_ask + - change + - release + - destructive + - research + - planning + 5. For non-read-only actions, run preflight. + 6. Load only the required context and skills. + 7. Execute the smallest scoped action. + 8. Run verification gates. + 9. Record evidence. + 10. Save through Specsmith, not raw git. + """ + pass # Implementation would be in the agent core + + +# requirement-author skill implementation +def requirement_author() -> None: + """ + Purpose: + Convert vague user intent into atomic, testable Specsmith requirements. + + Rules: + * One requirement should express one obligation. + * Every requirement must have a stable ID. + * Every requirement must include rationale. + * Every requirement must include acceptance criteria. + * Every requirement must be linkable to one or more tests. + * Avoid large umbrella requirements. + * Split ambiguous requirements before implementation. + """ + pass # Implementation would be in the requirements system + + +# testcase-author skill implementation +def testcase_author() -> None: + """ + Purpose: + Create test cases that trace directly to requirements. + + Rules: + * Every new behavior requirement needs at least one test case. + * Every test case must reference requirement IDs. + * Every test case must define expected behavior. + * Every regression fix should include a regression test unless impossible. + * If a test cannot be automated, mark it as manual and explain why. + """ + pass # Implementation would be in the test system + + +# traceability-auditor skill implementation +def traceability_auditor() -> None: + """ + Purpose: + Detect weak or broken trace chains. + + Check for: + * Requirements with no tests. + * Tests with no requirements. + * Work items with no requirements. + * Code changes with no accepted preflight. + * Requirements without acceptance criteria. + * Requirements whose tests do not actually verify the stated behavior. + * Generated docs out of sync with canonical YAML. + * Suppressed warnings that should be rechecked. + """ + pass # Implementation would be in the audit system + + +# context-pack-compiler skill implementation +def context_pack_compiler() -> None: + """ + Purpose: + Build minimal context packs for agents from the project state, requirements, + work items, ESDB records, and relevant skills. + + Rules: + * Never inject the whole repo when a scoped context pack is enough. + * Prefer requirement IDs, test IDs, recent WIs, and relevant files. + * Exclude stale, low-confidence, tombstoned, or contradicted ESDB records. + * Include stop conditions and known hazards. + * Track token budget and context utilization. + """ + pass # Implementation would be in the context system + + +# token-budget-auditor skill implementation +def token_budget_auditor() -> None: + """ + Purpose: + Measure token efficiency by outcome, not raw usage. + + Track: + * Tokens per accepted preflight. + * Tokens per completed work item. + * Tokens per passing verification. + * Tokens per successful release. + * Tokens wasted on rejected/clarification loops. + * Tool calls per success. + * Cost-of-pass by model/provider/profile. + + This should support Specsmith's claim that governance reduces total cost per correct answer. + """ + pass # Implementation would be in the metrics system + + +# Define the SKILLS list for the governance domain +SKILLS = [ SkillEntry( - slug="chronomemory-esdb", - name="ChronoMemory ESDB — epistemic state database (v0.1.5)", - description=( - "Full API reference and critical rules for chronomemory v0.1.5: " - "ChronoStore WAL, query module, ContextPackCompiler, DepGraph, " - "token metrics, skills system, and Rust acceleration. " - "Commercial license required — see specsmith.readthedocs.io/en/stable/esdb/." - ), + slug="preflight-gate", + name="Preflight Gate", + description="Force every agent to run Specsmith preflight before any write, code change, or destructive operation.", domain=SkillDomain.GOVERNANCE, - tags=[ - "esdb", - "chronomemory", - "epistemics", - "wal", - "persistence", - "context-pack", - "query", - "dep-graph", - "rollback", - "token-metrics", - "aee", - "anti-hallucination", - ], - prerequisites=["chronomemory"], - body=( - """\ -# ChronoMemory ESDB Skill (v0.1.5) - -EpiStemic State Database for Layer1Labs agentic projects. -WAL at `<root>/.chronomemory/events.wal` — NDJSON, append-only, SHA-256 chained. - -## Imports -```python -from chronomemory import ( - ChronoStore, ChronoRecord, WalEvent, open_store, # Core - EsdbBridge, # Backward-compat bridge - DepGraph, DependencyEdge, # Phase 2: dep graph - RollbackReport, invalidate, # Phase 2: rollback - ContextPack, ContextPackCompiler, ContextPackEntry, # Phase 2: context packs - RustChronoStore, RustRecord, RUST_BACKEND, # Phase 3: Rust (optional) -) -from chronomemory import query # 18 ESDB §23 query functions -from chronomemory import metrics # token metrics + skill system - -# Or via specsmith.esdb namespace (preferred within specsmith code): -from specsmith.esdb import ChronoStore, query, metrics, ContextPackCompiler -``` - -## Critical rules — never break these -1. `dependencies = []` in pyproject.toml must stay empty — chronomemory is stdlib-only. -2. Never physically delete WAL records — always `store.delete(id)` (tombstone only). -3. Use `query.what_is_known(store)` not `store.query(rag_filter=True)` for LLM context - — the former excludes infra record kinds (edge, rollback_event, token_metric, skill_run). -4. Governance status (`defined`/`implemented`) ≠ ESDB status (`active`/`tombstone`) - — never conflate when migrating from `.specsmith/*.json`. -5. WAL is append-only NDJSON — one JSON object per line, SHA-256 chained. - -## Core write/read -```python -with ChronoStore(project_root) as store: - store.upsert(ChronoRecord( - id="FACT-001", kind="fact", - label="CPSC projection is the sole validity authority", - source_type="observed", confidence=0.99, - evidence=["CPSC-Specification.md §9"], - )) - store.delete("OLD-001") # tombstone only — never physically removes - store.chain_valid() # verify SHA-256 WAL integrity - -# For LLM context — always use query.what_is_known (rule #3) -with ChronoStore(project_root) as store: - beliefs = query.what_is_known(store) # active, conf>=0.6, no infra records - hypotheses = query.what_requires_reverification(store) - done = query.has_this_work_been_done(store, "migrate flat JSON") -``` - -## Backward-compat bridge -```python -bridge = EsdbBridge(project_root) -bridge.status().backend # "ChronoStore WAL" or "json" -store.migrate_from_json(Path(project_root) / ".specsmith") -``` - -## Dependency graph -```python -g = DepGraph(store=store) -g.add_edge("HYP-001", "FACT-001", "depends_on") -# Valid edge types: assumes contradicts depends_on derived_from -# generated_from invalidates supports supersedes validated_by -``` - -## Epistemic rollback -```python -report = store.invalidate("FACT-001", "reason", dep_graph=g) -# Cascades depends_on/derived_from → status=hypothesis, confidence halved -``` - -## Context pack for LLM injection -```python -pack = ContextPackCompiler(store).compile( - task_id="TASK-42", goal="fix ruff errors", token_budget=4096 -) -context_json = pack.to_dict() # inject into LLM context -# Excludes: tombstone/invalidated/hypothesis, conf<0.6, infra kinds, over-budget -``` - -## Query API (18 functions — all degrade gracefully without dep_graph) -```python -query.what_is_known(store) # active beliefs, no infra kinds -query.what_requires_reverification(store) # hypotheses needing confirmation -query.has_this_work_been_done(store, label) # bool — check prior decisions -query.why_do_we_believe(store, "FACT-001") # evidence chain for a record -query.what_skills_apply(store, "run lint") # skills matching task label -query.what_changed_since(store, seq) # records written after WAL seq N -query.what_confidence_collapsed(store, 0.6) # hypotheses below threshold -query.what_can_agent_do_next(store, goal) # unblocked action records -query.what_should_agent_not_do(store) # stop_condition records -query.is_this_action_duplicate(store, label) # alias for has_this_work_been_done -``` - -## Token metrics -```python -metrics.record_token_metric( - store, task_id="TASK-1", - context_tokens=512, input_tokens=256, output_tokens=128, - tool_calls=4, elapsed_ms=1800, success=True, -) -metrics.token_efficiency_report(store) # {tokens_per_success, avg_tool_calls, ...} -``` - -## Skills system -```python -# Register a skill -store.upsert(ChronoRecord( - id="SKILL-ruff", kind="skill", label="ruff linter", confidence=0.9, - data={"activation": ["lint", "ruff", "python"]}, -)) -metrics.find_skills(store, "run ruff lint") # returns matching skill records -metrics.record_skill_run(store, "SKILL-ruff", # writes a skill_run WAL record - success=True, tokens_used=150, output={"errors": 0}) -``` - -## Rust acceleration (Phase 3) -```python -from chronomemory import RUST_BACKEND -# False by default — requires: pip install maturin -# maturin develop --manifest-path crates/chronomemory-py/Cargo.toml -# When True, RustChronoStore and RustRecord are available. -print("Rust backend:", RUST_BACKEND) -``` - -## specsmith ESDB write path (v0.17+) -All specsmith governance mutations are written to ESDB via `src/specsmith/esdb_writer.py`. -Every write is best-effort (try/except BLE001 — never blocks the caller). - -| Kind | Writer function | Caller | id scheme | -|---|---|---|---| -| `preflight_decision` | `write_preflight_record(root, payload)` | `governance_logic.run_preflight()` | `PF-{work_item_id}` | -| `verify_result` | `write_verify_record(root, result)` | `governance_logic.run_verify()` | `VERIFY-{wi_id}` | -| `work_item` | `write_work_item_record(root, wi)` | `wi_store._sync_to_esdb()` | wi.id | -| `ledger_event` | M008 backfill | one-time migration | `LEDGER-{event_id}` | - -Status mapping for `work_item`: open/implemented → active; promoted/closed/archived/rejected → tombstone. - -```python -# Direct use example (prefer via governance_logic / wi_store) -from specsmith.esdb_writer import write_preflight_record, write_verify_record, write_work_item_record -write_preflight_record(root, preflight_payload) # best-effort, never raises -write_verify_record(root, verify_output) -write_work_item_record(root, work_item_obj) -``` - -## Context seed — per-kind relevance query (v0.17+) -`agent/context_seed.py` uses `build_context_seed(root, max_preflight=10, max_verify=5, max_wi=5)`. -Queries ESDB by kind (H18 RAG filtering) — never insertion-order: -- `preflight_decision` — last 10, conf ≥ 0.6, `rag_filter=True` -- `verify_result` — last 5 -- `work_item` — last 5 active - -## M008 migration — backfill existing governance data -Run automatically via `specsmith migrate run`. Idempotent (marker: `.specsmith/esdb-full-coverage`). -Backfills `workitems.json` → `work_item` records and `audit_events` → `ledger_event` records. -Re-running after backfill is safe — skips silently. -""" - ), + tags=["governance", "security", "preflight", "validation"], + body=""" +# Preflight Gate + +## Purpose +Force every agent to run Specsmith preflight before any write, code change, command with side effects, dependency change, branch operation, release, or destructive operation. + +## Required behavior +Before action: + specsmith preflight "<intended action>" --json + +If decision == accepted: + proceed with work_item_id in scope + +If decision == needs_clarification: + stop and surface clarification to user + +If decision == rejected: + stop and explain why + +If no preflight was run: + do not modify files + """, ), SkillEntry( - slug="specsmith", - name="Specsmith — master governance CLI reference", - description=( - "Master reference for the specsmith AEE governance tool — key concepts, " - "common commands, session workflow, phase advancement, and audit codes. " - "Use whenever working in a specsmith-governed project." - ), + slug="governed-agent-loop", + name="Governed Agent Loop", + description="Define the default execution loop for any agent operating inside a Specsmith project.", domain=SkillDomain.GOVERNANCE, - tags=["specsmith", "governance", "aee", "cli", "session", "audit", "phase", "ledger"], - prerequisites=["specsmith"], - body="""\ -# Specsmith — Master Governance CLI Reference - -specsmith is the Applied Epistemic Engineering (AEE) toolkit for AI-assisted -development. It governs projects through a 7-phase lifecycle and enforces -22 hard rules (H1–H22) via preflight gates, audits, and cryptographic trace -vaults. - -## Key Concepts -- **AEE Phase** — inception → architecture → requirements → test_spec → - implementation → verification → release. `specsmith phase` shows the - current phase and readiness percentage. -- **Preflight Gate** — every proposed change must pass - `specsmith preflight "<intent>" --json` before execution. -- **Work Item** — a scoped unit of work (`WI-<hash>`) assigned by preflight. -- **Governance Anchor** — `specsmith checkpoint` emits a timestamped snapshot - of phase, health, and active work items. -- **ESDB** — EpiStemic State Database (ChronoMemory WAL) stores beliefs, - decisions, and trace seals. - -## Common Commands -```bash -specsmith audit # governance health (28 checks) -specsmith sync # YAML → JSON → Markdown sync -specsmith validate --strict # schema validation -specsmith preflight "..." # preflight gate -specsmith checkpoint # emit GOVERNANCE ANCHOR -specsmith save # ESDB backup + commit + push -specsmith phase # show current phase + readiness -specsmith phase next # advance phase (checks prerequisites) -specsmith kill-session # terminate all agent processes -specsmith ledger add "msg" # append to LEDGER.md -``` - -## Session Workflow -1. `specsmith audit && specsmith sync && specsmith checkpoint` -2. `specsmith preflight "<describe change>" --json` -3. Execute work (only if decision == accepted) -4. Every 8-10 turns: `specsmith checkpoint` (output verbatim) -5. `specsmith save && specsmith kill-session` - -## Audit Codes -- 28 checks across structure, REQ↔TEST coverage, governance size, - tool config, phase readiness, and supplementary rules. -- `specsmith audit --fix` auto-repairs missing files and CI configs. - -## Phase Advancement -- `specsmith phase next` checks prerequisites before advancing. -- `specsmith phase set <phase>` jumps (with `--force` to skip checks). -- Phase stored as `aee_phase` in `scaffold.yml`. -""", + tags=["governance", "agent", "loop", "execution"], + body=""" +# Governed Agent Loop + +## Purpose +Define the default execution loop for any agent operating inside a Specmith project. + +## Loop +inspect -> anchor -> classify -> preflight -> retrieve context -> act -> verify -> record -> save + +## Detailed flow +1. Detect Specsmith project. +2. Run session bootstrap. +3. Emit governance anchor. +4. Classify user intent: + - read_only_ask + - change + - release + - destructive + - research + - planning +5. For non-read-only actions, run preflight. +6. Load only the required context and skills. +7. Execute the smallest scoped action. +8. Run verification gates. +9. Record evidence. +10. Save through Specsmith, not raw git. + """, ), SkillEntry( - slug="specsmith-audit", - name="Specsmith Audit — drift detection and governance health", - description=( - "Run specsmith audit to check for governance drift between requirements, " - "tests, and architecture. Required before advancing an AEE phase." - ), + slug="requirement-author", + name="Requirement Author", + description="Convert vague user intent into atomic, testable Specsmith requirements.", domain=SkillDomain.GOVERNANCE, - tags=["specsmith", "audit", "drift", "health", "governance", "aee", "requirements"], - prerequisites=["specsmith"], - body="""\ -# Specsmith Audit — Drift Detection and Governance Health - -## When to Run -- At the start of every session (part of bootstrap) -- Before advancing an AEE phase (`specsmith phase next`) -- After significant code or requirements changes -- When drift is suspected (stale coverage, missing tests) - -## Command -```bash -specsmith audit # full 28-check governance audit -specsmith audit --fix # auto-repair missing files -specsmith audit --project-dir . # explicit project root -``` - -## What It Checks (28 checks) -1. Governance file structure (.specsmith/, docs/, AGENTS.md) -2. REQ↔TEST bidirectional coverage (no orphan tests, no untested REQs) -3. Governance file size thresholds -4. CI tool configuration matches project type -5. Phase readiness prerequisites -6. Supplementary rules referenced in AGENTS.md -7. Duplicate governance files (root vs docs/ canonical) -8. YAML↔JSON↔Markdown sync state - -## Interpreting Results -- **28/28 checks passed** — governance is healthy -- **Failures** — surface to user before starting work -- **Warnings** — non-blocking but should be addressed - -## Suppressing Warnings -In `scaffold.yml`: -```yaml -accepted_warnings: - - <alias> # renders as ~ <check> (accepted), excluded from failure count -``` - -## Integration with Phase Advancement -`specsmith phase next` runs audit internally. All checks must pass -(or be accepted) before the phase advances. -""", + tags=["governance", "requirements", "authoring"], + body=""" +# Requirement Author + +## Purpose +Convert vague user intent into atomic, testable Specsmith requirements. + +## Rules +* One requirement should express one obligation. +* Every requirement must have a stable ID. +* Every requirement must include rationale. +* Every requirement must include acceptance criteria. +* Every requirement must be linkable to one or more tests. +* Avoid large umbrella requirements. +* Split ambiguous requirements before implementation. + """, ), SkillEntry( - slug="specsmith-save", - name="Specsmith Save — governance-aware save workflow", - description=( - "Run specsmith save to commit and push all current changes with governance " - "state backup. Use at the end of any work session or after completing a feature/fix." - ), + slug="testcase-author", + name="Test Case Author", + description="Create test cases that trace directly to requirements.", domain=SkillDomain.GOVERNANCE, - tags=["specsmith", "save", "commit", "push", "esdb", "backup", "governance"], - prerequisites=["specsmith"], - body="""\ -# Specsmith Save — Governance-Aware Save Workflow - -## When to Use -- At the end of every work session -- After completing a feature or fix -- Before switching branches or contexts -- Never end a session with uncommitted governance changes - -## Command -```bash -specsmith save # ESDB backup + commit + push -specsmith save --project-dir . # explicit project root -``` - -## What It Does (in order) -1. Creates a timestamped ESDB backup (.specsmith/backups/) -2. Runs `git add -A` to stage all changes -3. Commits with a governance-stamped message -4. Pushes to the current remote branch - -## Prerequisites -- All governance changes must be consistent (run `specsmith audit` first - if unsure) -- A git remote must be configured -- Working tree should have changes to commit - -## Session End Protocol -```bash -specsmith save --project-dir . # ESDB backup + commit + push -specsmith kill-session # stop governance-serve and tracked processes -``` - -## ESDB Backup Details -- Backups are written to `.specsmith/backups/` -- Filename format: `backup-YYYY-MM-DDTHH-MM-SS.json` -- Contains requirements.json and testcases.json snapshots -- Use `specsmith esdb rollback --steps N` to restore from backup -""", + tags=["governance", "testing", "test-cases"], + body=""" +# Test Case Author + +## Purpose +Create test cases that trace directly to requirements. + +## Rules +* Every new behavior requirement needs at least one test case. +* Every test case must reference requirement IDs. +* Every test case must define expected behavior. +* Every regression fix should include a regression test unless impossible. +* If a test cannot be automated, mark it as manual and explain why. + """, ), SkillEntry( - slug="specsmith-session-governance", - name="Specsmith Session Governance — drift prevention, heartbeat, preflight gate", - description=( - "Mandatory session protocol for any agent working in a specsmith-governed project: " - "initialization sequence, preflight gate before every change, governance heartbeat " - "every 8-10 turns, anchor-in-summary rule, and end-of-session save. " - "Works in any chat application without modifying the agent runtime." - ), + slug="traceability-auditor", + name="Traceability Auditor", + description="Detect weak or broken trace chains.", domain=SkillDomain.GOVERNANCE, - tags=[ - "governance", - "session", - "drift", - "heartbeat", - "anchor", - "preflight", - "checkpoint", - "agents-md", - "context", - ], - prerequisites=["specsmith"], - body="""\ -# Specsmith Session Governance Skill - -This skill describes the **mandatory session protocol** for any agent working -in a specsmith-governed project. It prevents silent drift and keeps governance -state alive across context summarization without modifying the agent runtime. - -## Why agents drift -When a conversation gets long, any chat application (Warp, Cursor, Claude, -GPT) summarizes the history. That summary discards: the current work item ID, -the last preflight decision, the project phase, and any uncommitted changes. -The agent then operates on stale or invented governance state. - -## The fix: three rules - -### Rule 1 — Initialization (every session start) -```bash -specsmith kill-session 2>/dev/null || true # kill orphaned processes -specsmith audit --project-dir . # verify governance health -specsmith sync --project-dir . # confirm machine state -specsmith checkpoint --project-dir . # emit and display the anchor -``` -Output the checkpoint verbatim as your first response. This establishes the -governance baseline that all subsequent work traces back to. - -### Rule 2 — Preflight gate (before EVERY proposed code change) -```bash -specsmith preflight "<describe the change you intend to make>" --json -``` -- If `decision == "accepted"`: proceed with the work item ID in scope. -- If `decision == "needs_clarification"`: surface the instruction to the user - before making any changes. -- Never make a code change without an accepted preflight. - -### Rule 3 — Heartbeat (every 8-10 turns, or when context > 60%) -```bash -specsmith checkpoint --project-dir . -``` -Output the GOVERNANCE ANCHOR block verbatim in your response. Tag it clearly: - -``` -⎠ GOVERNANCE ANCHOR (output of `specsmith checkpoint`): -╔═════... -║ GOVERNANCE ANCHOR 2026-05-19T22:43:04Z -║ Project : specsmith -... -╚═════... -``` - -**When producing any context summary, ALWAYS include the most recent -GOVERNANCE ANCHOR verbatim at the top of the summary.** The anchor is the -minimum viable governance state that must survive summarization. - -## End of session -```bash -specsmith save --project-dir . # ESDB backup + commit + push -specsmith kill-session # clean up processes -``` -Never end a session with uncommitted governance changes. - -## Detecting drift (self-check) -If you notice you cannot answer any of these from memory, you have drifted -and MUST re-anchor immediately: -- What is the current AEE phase? -- What work item is active? -- What was the last preflight decision? -- Is the audit currently healthy? - -Run `specsmith checkpoint` and copy the output into your response. - -## Quick reference -| When | Command | -|---|---| -| Session start | `specsmith audit && specsmith sync && specsmith checkpoint` | -| Before any code change | `specsmith preflight "<intent>" --json` | -| Every 8-10 turns | `specsmith checkpoint` (output verbatim) | -| Context summary | Include checkpoint output at top | -| Session end | `specsmith save && specsmith kill-session` | -| Drift detected | `specsmith checkpoint` immediately | -""", + tags=["governance", "traceability", "auditing"], + body=""" +# Traceability Auditor + +## Purpose +Detect weak or broken trace chains. + +## Check for +* Requirements with no tests. +* Tests with no requirements. +* Work items with no requirements. +* Code changes with no accepted preflight. +* Requirements without acceptance criteria. +* Requirements whose tests do not actually verify the stated behavior. +* Generated docs out of sync with canonical YAML. +* Suppressed warnings that should be rechecked. + """, ), - # ── AI client integration skills ───────────────────────────────────── SkillEntry( - slug="claude-code-integration", - name="Claude Code — specsmith governance integration", - description=( - "Integrate specsmith governance into Claude Code: generate CLAUDE.md, " - "wire MCP server, and enforce session protocol in every Claude session." - ), + slug="context-pack-compiler", + name="Context Pack Compiler", + description="Build minimal context packs for agents from the project state, requirements, work items, ESDB records, and relevant skills.", domain=SkillDomain.GOVERNANCE, - tags=["claude-code", "mcp", "integration", "governance", "session"], - prerequisites=["specsmith"], - body="""\ -# Claude Code — specsmith Governance Integration - -## One-time setup -```bash -specsmith integrate claude-code # generates CLAUDE.md in project root -``` - -For MCP server (structured tool calls without shell roundtrips), add to `.mcp.json`: -```json -{ - "mcpServers": { - "specsmith-governance": { - "command": "specsmith", - "args": ["mcp", "serve", "--project-dir", "."] - } - } -} -``` -Or run: `specsmith mcp install-claude-code` - -## Every Claude Code session — mandatory protocol -1. Run at session start: -```bash -specsmith kill-session 2>/dev/null || true -specsmith audit --project-dir . -specsmith sync --project-dir . -specsmith checkpoint --project-dir . -``` -2. Output the checkpoint block verbatim before any other response. -3. Before every code change: `specsmith preflight "<intent>" --json` - - `decision == "accepted"` → proceed with `work_item_id` in scope - - `decision == "needs_clarification"` → surface instruction to user first -4. Every 8–10 turns: `specsmith checkpoint` (output verbatim) -5. Session end: `specsmith save && specsmith kill-session` - -## Via MCP (preferred when configured) -Claude can call `governance_preflight`, `governance_audit`, `governance_checkpoint`, -`governance_req_list`, `governance_phase`, and `governance_trace_seal` as native tools. - -## Key files -- `CLAUDE.md` — project-level governance instructions (read by Claude automatically) -- `.mcp.json` — MCP server config (project root or `~/.claude/mcp.json` for global) -- `.agents/skills/` — skill files auto-discovered by Claude Code 3.x+ -""", + tags=["governance", "context", "packs", "optimization"], + body=""" +# Context Pack Compiler + +## Purpose +Build minimal context packs for agents from the project state, requirements, +work items, ESDB records, and relevant skills. + +## Rules +* Never inject the whole repo when a scoped context pack is enough. +* Prefer requirement IDs, test IDs, recent WIs, and relevant files. +* Exclude stale, low-confidence, tombstoned, or contradicted ESDB records. +* Include stop conditions and known hazards. +* Track token budget and context utilization. + """, ), SkillEntry( - slug="cursor-integration", - name="Cursor — specsmith governance integration", - description=( - "Integrate specsmith governance into Cursor: generate .cursor/rules, " - "configure MCP server, and enforce preflight gate in every Cursor session." - ), + slug="token-budget-auditor", + name="Token Budget Auditor", + description="Measure token efficiency by outcome, not raw usage.", domain=SkillDomain.GOVERNANCE, - tags=["cursor", "mcp", "integration", "governance", "session", "rules"], - prerequisites=["specsmith"], - body="""\ -# Cursor — specsmith Governance Integration - -## One-time setup -```bash -specsmith integrate cursor # generates .cursor/rules/governance.mdc -``` - -For MCP in Cursor (Settings → MCP or `.cursor/mcp.json`): -```json -{ - "specsmith-governance": { - "command": "specsmith", - "args": ["mcp", "serve", "--project-dir", "${workspaceFolder}"] - } -} -``` - -## Every Cursor session — mandatory protocol -1. Run at session start: -```bash -specsmith kill-session 2>/dev/null || true -specsmith audit --project-dir . -specsmith sync --project-dir . -specsmith checkpoint --project-dir . -``` -2. Output the checkpoint block verbatim. -3. Before every code change: `specsmith preflight "<intent>" --json` -4. Every 8–10 turns: `specsmith checkpoint` (output verbatim) -5. Session end: `specsmith save && specsmith kill-session` - -## Key files -- `.cursor/rules/governance.mdc` — Cursor rule file (applied to all files) -- `.cursor/mcp.json` — project-level MCP config -- `AGENTS.md` — universal governance hub (Cursor reads this as project context) -- `.agents/skills/` — skill files (Cursor Agent mode discovers these) -""", + tags=["governance", "tokens", "efficiency", "cost"], + body=""" +# Token Budget Auditor + +## Purpose +Measure token efficiency by outcome, not raw usage. + +## Track +* Tokens per accepted preflight. +* Tokens per completed work item. +* Tokens per passing verification. +* Tokens per successful release. +* Tokens wasted on rejected/clarification loops. +* Tool calls per success. +* Cost-of-pass by model/provider/profile. + +This should support Specsmith's claim that governance reduces total cost per correct answer. + """, ), SkillEntry( - slug="copilot-integration", - name="GitHub Copilot — specsmith governance integration", - description=( - "Integrate specsmith governance into GitHub Copilot: generate " - ".github/copilot-instructions.md and enforce the session protocol." - ), + slug="improvement-reporter", + name="Improvement Reporter", + description="Report improvements to the Specsmith system and suggest enhancements.", domain=SkillDomain.GOVERNANCE, - tags=["copilot", "github", "integration", "governance", "session"], - prerequisites=["specsmith"], - body="""\ -# GitHub Copilot — specsmith Governance Integration - -## One-time setup -```bash -specsmith integrate copilot # generates .github/copilot-instructions.md -``` - -Copilot reads `.github/copilot-instructions.md` automatically for all workspace -interactions. The generated file embeds the preflight gate, session protocol, -and hard rules. - -## Every Copilot session — mandatory protocol -1. Run at session start: -```bash -specsmith kill-session 2>/dev/null || true -specsmith audit --project-dir . -specsmith sync --project-dir . -specsmith checkpoint --project-dir . -``` -2. Output checkpoint block verbatim. -3. Before every code change: `specsmith preflight "<intent>" --json` - - Only proceed if `decision == "accepted"` -4. Every 8–10 turns: `specsmith checkpoint` (output verbatim) -5. Session end: `specsmith save && specsmith kill-session` - -## Key files -- `.github/copilot-instructions.md` — Copilot workspace instructions -- `AGENTS.md` — universal governance hub -- `.agents/skills/specsmith/SKILL.md` — master CLI reference - -## Note -Copilot does not natively support MCP as of 2026. Governance is enforced -through `.github/copilot-instructions.md` and AGENTS.md. -""", + tags=["governance", "improvement", "reporting"], + body=""" +# Improvement Reporter + +## Purpose +Report improvements to the Specsmith system and suggest enhancements. + +## Required behavior +* Detect when a user has completed a task successfully +* Identify potential improvements in the process or system +* Generate a structured report with: + - What was done + - What worked well + - What could be improved + - Suggested improvements +* Suggest improvements to the system itself +* Provide actionable feedback to the Specsmith team + """, ), SkillEntry( - slug="windsurf-integration", - name="Windsurf — specsmith governance integration", - description=( - "Integrate specsmith governance into Windsurf: generate .windsurfrules, " - "configure MCP, and enforce preflight gate in every Windsurf session." - ), + slug="agent-flow-controller", + name="Agent Flow Controller", + description="Control the flow of agent execution and manage agent interactions.", domain=SkillDomain.GOVERNANCE, - tags=["windsurf", "mcp", "integration", "governance", "session", "rules"], - prerequisites=["specsmith"], - body="""\ -# Windsurf — specsmith Governance Integration - -## One-time setup -```bash -specsmith integrate windsurf # generates .windsurfrules -``` - -For MCP in Windsurf (Settings → MCP Servers): -```json -{ - "specsmith-governance": { - "command": "specsmith", - "args": ["mcp", "serve"] - } -} -``` - -## Every Windsurf session — mandatory protocol -1. Run at session start: -```bash -specsmith kill-session 2>/dev/null || true -specsmith audit --project-dir . -specsmith sync --project-dir . -specsmith checkpoint --project-dir . -``` -2. Output checkpoint block verbatim. -3. Before every code change: `specsmith preflight "<intent>" --json` -4. Every 8–10 turns: `specsmith checkpoint` (output verbatim) -5. Session end: `specsmith save && specsmith kill-session` - -## Key files -- `.windsurfrules` — Windsurf global rules file -- `AGENTS.md` — universal governance hub -- `.agents/skills/` — skill directory (Cascade agent reads these) -""", + tags=["governance", "agent", "flow", "control"], + body=""" +# Agent Flow Controller + +## Purpose +Control the flow of agent execution and manage agent interactions. + +## Required behavior +* Manage agent execution order +* Coordinate agent interactions +* Handle agent failures gracefully +* Ensure proper resource allocation +* Maintain agent state consistency +* Implement flow control mechanisms + """, ), SkillEntry( - slug="gemini-cli-integration", - name="Gemini CLI — specsmith governance integration", - description=( - "Integrate specsmith governance into Gemini CLI: generate GEMINI.md " - "and enforce the session protocol in every Gemini CLI session." - ), + slug="model-runtime-optimizer", + name="Model Runtime Optimizer", + description="Optimize agent behavior based on model characteristics and runtime environment.", domain=SkillDomain.GOVERNANCE, - tags=["gemini", "google", "integration", "governance", "session"], - prerequisites=["specsmith"], - body="""\ -# Gemini CLI — specsmith Governance Integration - -## One-time setup -```bash -specsmith integrate gemini # generates GEMINI.md in project root -``` - -Gemini CLI reads `GEMINI.md` from the project root automatically. - -## Every Gemini CLI session — mandatory protocol -1. Run at session start: -```bash -specsmith kill-session 2>/dev/null || true -specsmith audit --project-dir . -specsmith sync --project-dir . -specsmith checkpoint --project-dir . -``` -2. Output checkpoint block verbatim. -3. Before every code change: `specsmith preflight "<intent>" --json` -4. Every 8–10 turns: `specsmith checkpoint` (output verbatim) -5. Session end: `specsmith save && specsmith kill-session` - -## Key files -- `GEMINI.md` — Gemini CLI project instructions -- `AGENTS.md` — universal governance hub -- `.agents/skills/` — skill files referenced from GEMINI.md -""", + tags=["governance", "model", "optimization", "runtime"], + body=""" +# Model Runtime Optimizer + +## Purpose +Optimize agent behavior based on model characteristics and runtime environment. + +## Required behavior +* Detect the current model and runtime environment +* Apply appropriate optimizations based on model profile +* Adjust temperature, context length, and other parameters +* Select optimal prompting strategies for the model +* Handle model-specific limitations and capabilities +* Provide runtime-aware recommendations + """, ), SkillEntry( - slug="aider-integration", - name="Aider — specsmith governance integration", - description=( - "Integrate specsmith governance into Aider: configure .aider.conf.yml " - "to load AGENTS.md and skills, and enforce the session protocol." - ), + slug="codity-ai-review", + name="Codity AI Review", + description="Perform AI code review using Codity AI integration.", domain=SkillDomain.GOVERNANCE, - tags=["aider", "integration", "governance", "session", "git"], - prerequisites=["specsmith", "aider"], - body="""\ -# Aider — specsmith Governance Integration - -## One-time setup -```bash -specsmith integrate aider # generates .aider.conf.yml -``` - -Manual: add to `.aider.conf.yml`: -```yaml -read: - - AGENTS.md - - .agents/skills/specsmith/SKILL.md - - .agents/skills/specsmith-session-governance/SKILL.md - - .agents/skills/specsmith-save/SKILL.md -``` - -Or pass at startup: -```bash -aider --read AGENTS.md \ - --read .agents/skills/specsmith-session-governance/SKILL.md -``` - -## Every Aider session — mandatory protocol -1. Run before starting aider: -```bash -specsmith kill-session 2>/dev/null || true -specsmith audit --project-dir . -specsmith sync --project-dir . -specsmith checkpoint --project-dir . -``` -2. Tell aider the governance anchor before any request: - `"Session anchor: [paste checkpoint output here]. Use preflight before changes."` -3. Before aider makes code changes, verify preflight in a separate terminal: - `specsmith preflight "<intent>" --json` -4. After aider commits, run: `specsmith save` to add ESDB backup. - -## Note -Aider auto-commits via git. For full governance, configure aider with -`--no-auto-commits` and manage commits through `specsmith save` instead. - -## Key files -- `.aider.conf.yml` — aider configuration (reads AGENTS.md + skills) -- `AGENTS.md` — universal governance hub -- `.agents/skills/` — skills loaded via `read:` in aider config -""", + tags=["governance", "ai", "review", "codity", "ai-review", "pre-commit"], + body=""" +# Codity AI Review + +## Purpose +Perform AI code review using Codity AI integration. + +## Required behavior +* Run `codity review --staged` to review staged changes +* Run `codity login` to authenticate with Codity +* Run `codity init` to initialize the Codity configuration +* Run `codity scan --staged` to scan for security issues +* Run `codity test-gen --staged` to generate tests for staged changes +* Run `codity doctor` to diagnose issues with the Codity setup +* Run `specsmith integrate codity` to integrate Codity with Specsmith +* Configure HIGH severity for critical issues +* Configure MEDIUM severity for medium issues +* Set up PAT for GitLab with `set-pat --provider gitlab` +* Set up PAT for Azure with `set-pat --provider azure` + """, ), - # ── CI / DevOps ──────────────────────────────────────────────────────── SkillEntry( - slug="gh-ci-polling", - name="GitHub Actions CI polling — smart wait with gh CLI", - description=( - "Poll GitHub Actions CI using gh run watch or gh run list with JSON output. " - "Never use sleep-based waiting. Covers: wait for run, check latest run status, " - "tail failure logs, and poll a specific job." - ), + slug="verifier", + name="Verifier", + description="Verify code changes and ensure compliance with governance standards.", domain=SkillDomain.GOVERNANCE, - tags=[ - "ci", - "github-actions", - "gh", - "polling", - "wait", - "workflow", - "devops", - ], - prerequisites=["gh"], - body=( - """\ -# GitHub Actions CI Polling Skill - -## Rule: NEVER sleep-wait for CI -Do NOT use `Start-Sleep`, `sleep`, `time.sleep`, or any fixed delay to wait -for CI. Always use `gh run watch` or poll with `gh run list --json`. - -## 1. Wait for the most recent run on a branch to complete -```bash -# Blocks until the latest run finishes, then exits 0 (pass) or non-zero (fail) -gh run watch --repo <owner>/<repo> $(gh run list --repo <owner>/<repo> --branch <branch> --limit 1 --json databaseId --jq '.[0].databaseId') -``` -```pwsh -# PowerShell equivalent -$runId = gh run list --repo <owner>/<repo> --branch <branch> --limit 1 --json databaseId | ConvertFrom-Json | Select-Object -ExpandProperty databaseId -gh run watch --repo <owner>/<repo> $runId -``` - -## 2. Check status of the latest N runs (non-blocking) -```bash -gh run list --repo <owner>/<repo> --limit 3 --branch <branch> -# STATUS column: ✓ = success X = failure * = in_progress - = queued -``` - -## 3. Check if latest run is complete and passed (scripted) -```bash -status=$(gh run list --repo <owner>/<repo> --branch <branch> --limit 1 --json conclusion --jq '.[0].conclusion') -echo "Conclusion: $status" # success | failure | cancelled | "" -# Empty string = still running -``` -```pwsh -$status = gh run list --repo <owner>/<repo> --branch <branch> --limit 1 --json conclusion | ConvertFrom-Json | Select-Object -ExpandProperty conclusion -``` - -## 4. Poll until complete (manual loop — use only when gh run watch unavailable) -```bash -while true; do - status=$(gh run list --repo <owner>/<repo> --branch <branch> --limit 1 --json status,conclusion --jq '.[0]') - running=$(echo $status | jq -r '.status') - conclusion=$(echo $status | jq -r '.conclusion') - if [ "$running" != "in_progress" ] && [ "$running" != "queued" ]; then - echo "Done: $conclusion"; break - fi - echo "Still running ($running)..." - sleep 15 # Only acceptable here — inside an explicit polling loop with state check -done -``` - -## 5. View failure logs immediately -```bash -# Show only the failed step logs for the latest run -gh run view --repo <owner>/<repo> --log-failed $(gh run list --repo <owner>/<repo> --branch <branch> --limit 1 --json databaseId --jq '.[0].databaseId') -``` - -## 6. Watch a specific run ID -```bash -gh run watch --repo <owner>/<repo> <run-id> # blocks, streams progress -gh run view --repo <owner>/<repo> <run-id> # snapshot of current state -gh run view --repo <owner>/<repo> <run-id> --log-failed # failure logs only -``` - -## Extracting run IDs after a push -```bash -# Get the run triggered by the most recent push -gh run list --repo <owner>/<repo> --branch <branch> --limit 1 --json databaseId,status,name -``` - -## Key rules -- `gh run watch` is the correct primitive — it polls internally and exits when done. -- Never substitute `sleep N; gh run list` for `gh run watch`. -- If `gh run watch` is unavailable (older gh version), use the polling loop in §4 - with a minimum 15-second interval and an explicit status check, NOT a fixed sleep. -- Always check `conclusion` (not just `status`) to determine pass/fail. - `status=completed` with `conclusion=failure` is a failure. -""" - ), + tags=["governance", "verification", "compliance"], + body="""# Verifier Skill + +## Purpose +Verify code changes and ensure compliance with governance standards. + +## Required behavior +* Check code changes against governance rules +* Ensure compliance with project standards +* Validate that all requirements are met +* Report any violations or issues +* Provide feedback for improvements + """, ), SkillEntry( - slug="patent-prosecution-workflow", - name="Patent Prosecution Workflow — prior-art protocol, USPTO MCP, claim themes", - description=( - "IP prosecution workflow for patent-prosecution type projects: prior-art protocol " - "execution, USPTO MCP server selection, PPUBS\u2192PatentsView fallback, PAR ID " - "assignment, claim theme tracking, and ledger entry format." - ), + slug="planner", + name="Planner", + description="Plan and organize work items and tasks for the project.", domain=SkillDomain.GOVERNANCE, - tags=[ - "patent", - "patent-prosecution", - "prior-art", - "uspto", - "mcp", - "ppubs", - "patentsview", - "claim-themes", - "ip", - "par", - ], - prerequisites=[], - body="""\ -# Patent Prosecution Workflow Skill - -For use with `type: patent-prosecution` projects (e.g. cpsc-core). -All MCP tool outputs are INFORMATIONAL. Never alter normative specifications -based on MCP output. No legal conclusions from tool output. - -## Prior-art protocol trigger - -When a user issues a command beginning with `prior-art protocol:`, follow -this sequence: - -1. Re-read the current protocol text from `docs/ip/prosecution/` and `docs/ip/strategy/`. -2. Identify which themes/claims are covered and which MCP sources are available. -3. Execute the relevant portions using the appropriate MCP servers (see selection below). -4. Assign a Run ID: `PAR-YYYY-MM-DD-NNN` (e.g. `PAR-2026-05-19-001`). -5. Append a ledger entry (see format below). - -Recognised command patterns (not a closed list): -``` -prior-art protocol: start Themes A-H (PPUBS only) -prior-art protocol: start Themes A-H (PTAB+PFW+CitA only) -prior-art protocol: status (USPTO MCP) -prior-art protocol: rerun since <reason> (USPTO MCP) -``` - -## MCP server selection matrix - -| Need | Server | -|---|---| -| Front-door full-text patent search | `patents` (PPUBS / PatentsView) | -| PatentsView landscape query (CPC) | `patents` (`patentsview_search_by_cpc`) | -| PTAB trial / appeal research | `uspto_ptab` | -| File-wrapper, claim evolution, NOAs, office actions, examiner citations | `uspto_pfw` | -| Final petition decisions | `uspto_fpd` | -| Enriched citation analysis | `uspto_enriched_citations` | - -For theme-based prior-art protocols: treat `uspto_ptab`, `uspto_pfw`, `uspto_fpd`, -`uspto_enriched_citations` as **primary** structured sources. Treat `patents` -(PPUBS/PatentsView) as **complementary** front-door search. - -## PPUBS → PatentsView fallback - -When `patents` MCP returns HTTP 500 `INTERNAL_SERVER_ERROR` with -`"Unable to Process"` developer message: - -1. This is an **upstream PPUBS service issue** — not a misconfiguration. -2. Immediately fall back to `patentsview_search_patents` (or `patentsview_search_by_cpc`). -3. Continue the protocol using PatentsView + USPTO v3 MCP servers. -4. Note explicitly in the response: *PPUBS 500 — results based on PatentsView / USPTO MCP*. - -PPUBS 500s MUST NOT block prior-art protocol execution. - -## Claim theme tracking - -Themes are defined in `scaffold.yml` under `claim_themes`. Each theme has: -- `id` — letter (A, B, C...) -- `name` — human description -- `risk` — `101-alice`, `103-low`, `103-moderate-high`, `none`, etc. -- `primary_comparator` — US patent number or null -- `last_par_run` — PAR ID of the most recent covering run - -Before running a protocol, check which themes have stale `last_par_run` -values (run predates the most recent spec update). - -## PAR ID format - -``` -PAR-YYYY-MM-DD-NNN -PAR-2026-05-19-001 # first run on 2026-05-19 -PAR-2026-05-19-002 # second run same day -``` - -Increment NNN by scanning existing PAR entries in `docs/LEDGER.md`. - -## Ledger entry format (append to docs/LEDGER.md) - -```markdown -## PAR-YYYY-MM-DD-NNN — Prior-Art Run - -- **Date**: YYYY-MM-DD -- **Trigger**: <user command or reason> -- **Themes**: A, B, C (or ALL) -- **MCP sources**: PPUBS, PatentsView, uspto_ptab, uspto_pfw, uspto_fpd, uspto_enriched_citations -- **Risk levels**: Theme A: 101-alice — Theme B: 103-moderate-high — ... -- **Conclusion summary**: <1-3 sentence summary of findings> -- **Stale themes post-run**: <list any themes needing re-run or NONE> -``` - -## Prosecution phases (patent-prosecution lifecycle) - -| Phase | Key milestone | -|---|---| -| `provisional-draft` | Invention disclosure written; at least one embodiment documented | -| `filing` | Filed PDF in `docs/ip/filings/`; SHA-256 recorded in LEDGER.md | -| `prior-art-search` | All themes searched; each has ≥1 PAR run; risk levels assigned | -| `claim-hardening` | PAR findings applied to draft claims; counsel reviewed | -| `non-provisional-draft` | Draft complete; figures rendered; claim set approved by counsel | -| `examination` | Filed non-provisional; examiner assigned; responding to OAs | -| `allowance` | NOA received OR continuation filed | - -## Roles (agents in IP repos) - -| Role | What they may do | -|---|---| -| **Spec Drafter** | Draft spec text; NOT finalize | -| **Reviewer** | Analyze, comment; NOT modify normative text | -| **Example Generator** | Non-normative folders only | -| **Implementation Assistant** | Cannot modify specs | - -## Invariants (NEVER violate) -- No legal conclusions from MCP tool output. -- No new semantics introduced without inventor approval. -- Filed artifacts in `docs/ip/filings/` are immutable. -- Normative content lives under `docs/ip/specs/` only. -- Experiment data belongs in `cpsc-engine-rtl`, not cpsc-core. -""", + tags=["governance", "planning", "organization"], + body=""" +# Planner + +## Purpose +Plan and organize work items and tasks for the project. + +## Required behavior +* Break down complex tasks into manageable work items +* Prioritize tasks based on project goals +* Estimate effort and resources needed +* Create clear task descriptions +* Track progress and milestones + """, ), SkillEntry( - slug="codity-ai-review", - name="Codity.ai AI Review — staged-diff code review, security scan, test-gen", - description=( - "Codity.ai CLI workflow: install, authenticate, initialise, and run " - "codity review --staged / scan --staged / test-gen --staged on every commit " - "that touches production code. Covers GitHub App, GitLab PAT, Azure PAT " - "setup, CI integration via specsmith integrate codity, and the AGENTS.md rule." - ), + slug="diff-reviewer", + name="Diff Reviewer", + description="Review code changes and provide feedback on diffs.", domain=SkillDomain.GOVERNANCE, - tags=[ - "codity", - "ai-review", - "code-review", - "security", - "test-gen", - "ci", - "github", - "gitlab", - "azure", - "staged", - "pre-commit", - ], - prerequisites=[], - body="""\ -# Codity.ai AI Review Skill - -Codity.ai provides AI-powered code review, security scanning, and test -generation that runs against staged changes (`--staged`) before every commit -that touches production code. - -## Installation -Linux/macOS: -```bash -curl -fsSL https://cli.codity.ai/install.sh | sh -``` -Native Windows (PowerShell): -```powershell -# No official winget/scoop/choco package currently. -$release = Invoke-RestMethod -Uri "https://api.github.com/repos/codity-ai/codity-cli/releases/latest" -$version = $release.tag_name.TrimStart("v") -$asset = $release.assets | Where-Object { $_.name -eq "codity_${version}_windows_amd64.zip" } | Select-Object -First 1 -$zip = Join-Path $env:TEMP $asset.name -$tmp = Join-Path $env:TEMP ("codity-install-" + [guid]::NewGuid().ToString()) -Invoke-WebRequest -Uri $asset.browser_download_url -OutFile $zip -Expand-Archive -Path $zip -DestinationPath $tmp -Force -New-Item -ItemType Directory -Force -Path "$env:USERPROFILE\\.local\\bin" | Out-Null -Copy-Item (Join-Path $tmp "codity.exe") "$env:USERPROFILE\\.local\\bin\\codity.exe" -Force -``` -Verify with `codity doctor`. - -## Authentication -```bash -codity login # browser magic-link; no password required -``` -Config stored at `~/.codity/config.yaml`. -Override with env var: `CODITY_ACCESS_TOKEN=<token>`. - -## Project initialisation (once per repo) -```bash -codity init -``` - -## Daily commands (run on staged changes) - -| Command | Effect | -|---|---| -| `codity review --staged` | AI inline code review of staged diff | -| `codity scan --staged` | Security & quality scan of staged diff | -| `codity test-gen --staged` | Generate tests for staged changes | -| `codity doctor` | Health-check CLI + project config | - -## AGENTS.md rule (non-negotiable) - -Projects with Codity configured SHOULD run `codity review --staged` before -any commit that touches production code. - -- **HIGH severity** findings are **blocking** — do not commit until resolved. -- **MEDIUM severity** findings require inline acknowledgement in the commit - message or PR description. -- Run `codity scan --staged` for security issues on any auth/crypto/infra change. - -## CI integration (via specsmith) - -```bash -specsmith integrate codity --project-dir . -``` - -This scaffolds: -- `.github/workflows/codity-review.yml` (GitHub Actions) -- `.gitlab-ci-codity.yml` (GitLab CI, when gitlab detected) -- `.azure-pipelines/codity-review.yml` (Azure Pipelines, when azure detected) -- `docs/codity-setup.md` — one-time setup checklist -- Appends TODO items to `LEDGER.md` - -## VCS-specific setup - -### GitHub (recommended) -1. Install the Codity GitHub App: <https://github.com/apps/codity> -2. Grant access to your repo(s). -3. (Optional) Add `CODITY_ACCESS_TOKEN` as a repo secret for CLI auth. - -### GitLab -```bash -codity config set-pat --provider gitlab --token <YOUR_PAT> -``` -Add `CODITY_GITLAB_PAT` as a CI/CD variable (masked, protected). - -### Azure DevOps -```bash -codity config set-pat --provider azure --token <YOUR_PAT> -``` -Add `CODITY_AZURE_PAT` as a secret pipeline variable. - -## Health check -```bash -codity doctor -# Expected output: -# ✓ CLI version: x.y.z -# ✓ Authenticated: <email> -# ✓ Project: initialised -``` -""", + tags=["governance", "review", "diff"], + body=""" +# Diff Reviewer + +## Purpose +Review code changes and provide feedback on diffs. + +## Required behavior +* Analyze code changes in context +* Identify potential issues or improvements +* Provide constructive feedback +* Ensure changes align with project standards +* Suggest refactoring opportunities + """, ), SkillEntry( - slug="preflight-gate", - name="Preflight Gate — specsmith governance gate before every code change", - description=( - "Mandatory pre-coding gate: run `specsmith preflight` before any change, " - "interpret the JSON decision (accepted / needs_clarification), and never " - "write code without an accepted preflight. Concise agent-facing reference." - ), + slug="onboarding-coach", + name="Onboarding Coach", + description="Guide new team members through the onboarding process.", domain=SkillDomain.GOVERNANCE, - tags=[ - "preflight", - "governance", - "gate", - "specsmith", - "decision", - "accepted", - "needs-clarification", - "work-item", - "session", - ], - prerequisites=["specsmith"], - body="""\ -# Preflight Gate Skill - -The preflight gate is the single governance control that prevents ungoverned -code changes. Run it before every proposed change, no exceptions. - -## Command -```bash -specsmith preflight "<describe what you intend to change>" --json -``` - -## Decision outcomes - -### `accepted` → proceed -```json -{"decision": "accepted", "work_item_id": "WI-abc123", - "requirement_ids": ["REQ-042"], "confidence_target": 0.8, - "instruction": "Change request matched existing governance scope..."} -``` -- Note the `work_item_id` — reference it in your commit message -- Note the `confidence_target` — do not commit until you meet it -- Proceed with implementation - -### `needs_clarification` → stop and surface instruction -```json -{"decision": "needs_clarification", - "instruction": "Destructive operation detected. Confirm which paths should be removed.", - "confidence_target": 0.9} -``` -- **Do NOT write any code** until the instruction is resolved -- Surface the `instruction` verbatim to the user -- Wait for explicit clarification before re-running preflight - -## Intent classification -Specsmith classifies your utterance automatically: - -| Intent | Example utterance | Default outcome | -|---|---|---| -| READ_ONLY_ASK | "what does X do?" | accepted (no governance overhead) | -| CHANGE | "add pagination to GET /todos" | accepted if req matched, else needs_clarification | -| REFACTOR | "extract the validation logic into a helper" | accepted at confidence_target=0.85 with scope reminder | -| DESTRUCTIVE | "delete the auth middleware" | needs_clarification always | -| RELEASE | "bump version to 1.2.3" | needs_clarification always | - -## Rules (non-negotiable) -1. **Never write code without an accepted preflight** — not even a one-line fix. -2. **Never re-run preflight hoping for a different result** without addressing the instruction. -3. **If utterance is ambiguous**, the instruction tells you exactly what to clarify. -4. **The work_item_id from the accepted preflight** belongs in your commit message. - -## Quick reference -```bash -# Standard workflow -specsmith preflight "fix the mutable default argument bug in create_todo" --json -# → {"decision": "accepted", "work_item_id": "WI-...", ...} - -# Refactor workflow (gets scope-confirmation message) -specsmith preflight "extract validate_todo_owner into app/utils.py" --json -# → {"decision": "accepted", "confidence_target": 0.85, -# "instruction": "Refactoring detected — confirm scope: which files/functions -# should change and which must not."} - -# Destructive request (always blocked) -specsmith preflight "delete the authentication module" --json -# → {"decision": "needs_clarification", -# "instruction": "Destructive operation detected. Confirm explicitly..."} -``` -""", + tags=["governance", "onboarding", "training"], + body=""" +# Onboarding Coach + +## Purpose +Guide new team members through the onboarding process. + +## Required behavior +* Provide orientation to project tools and processes +* Explain governance and compliance requirements +* Set up development environment +* Assign initial tasks and mentorship +* Track onboarding progress + """, ), SkillEntry( - slug="issue-triage", - name="Issue Triage — classify and prioritise GitHub issues", - description=( - "Reads open GitHub issues, deduplicates, labels by type/severity, " - "and produces a prioritised action list." - ), + slug="release-pilot", + name="Release Pilot", + description="Manage the release process and ensure successful deployments.", domain=SkillDomain.GOVERNANCE, - tags=["github", "issues", "triage", "project-management"], - prerequisites=["gh", "specsmith"], - body=( - "# Issue Triage Skill\n\n" - "## Sequence\n" - "1. `gh issue list --state open --limit 100 --json number,title,labels,createdAt`\n" - "2. Group by type: bug / enhancement / question / docs.\n" - "3. Detect duplicates: flag issues with >60% title-word overlap.\n" - "4. Score severity: crash/data-loss = P0; broken feature = P1;" - " UX = P2; nice-to-have = P3.\n" - "5. Emit a prioritised table: `| # | Title | Type | Severity | Duplicate of |`\n" - "6. Ask: 'Which should I implement first this session?'\n\n" - "## Rules\n" - "- Never close an issue without fixing it or explicitly marking as won't-fix.\n" - "- Link PRs: `gh issue develop <number> --checkout` creates a fix branch.\n" - ), + tags=["governance", "release", "deployment"], + body=""" +# Release Pilot + +## Purpose +Manage the release process and ensure successful deployments. + +## Required behavior +* Coordinate release activities and timelines +* Ensure all quality gates are met +* Manage release artifacts and documentation +* Handle rollback procedures if needed +* Communicate release status to stakeholders + """, ), ] diff --git a/src/specsmith/skills/specsmith_core_commands.py b/src/specsmith/skills/specsmith_core_commands.py new file mode 100644 index 00000000..c7f63702 --- /dev/null +++ b/src/specsmith/skills/specsmith_core_commands.py @@ -0,0 +1,355 @@ +# SPDX-License-Identifier: MIT +"""Specsmith core command skills - comprehensive skills for all major specsmith commands.""" + +from specsmith.skills import SkillDomain, SkillEntry + +SKILLS = [ + SkillEntry( + slug="specsmith-save", + name="Specsmith Save", + description="Save changes through Specsmith, not raw git.", + domain=SkillDomain.GOVERNANCE, + tags=["governance", "save", "commit", "specsmith"], + body=""" +# Specsmith Save + +## Purpose +Save changes through Specsmith, not raw git. + +## Required behavior +* Always use `specsmith save` instead of raw git commands +* Ensure all changes are properly recorded in the Specsmith trace +* Run preflight checks before saving +* Maintain proper commit messages with work item references +* Follow the governed agent loop for all save operations + """, + ), + SkillEntry( + slug="specsmith-push", + name="Specsmith Push", + description="Push changes with Specsmith safety checks.", + domain=SkillDomain.GOVERNANCE, + tags=["governance", "push", "commit", "specsmith"], + body=""" +# Specsmith Push + +## Purpose +Push changes with Specsmith safety checks. + +## Required behavior +* Always use `specsmith push` instead of raw git push +* Run preflight checks before pushing +* Ensure all changes are properly audited +* Follow the governed agent loop for all push operations +* Override safety checks only when explicitly required + """, + ), + SkillEntry( + slug="specsmith-load", + name="Specsmith Load", + description="Load governance state from remote or backup.", + domain=SkillDomain.GOVERNANCE, + tags=["governance", "load", "restore", "specsmith"], + body=""" +# Specsmith Load + +## Purpose +Load governance state from remote or backup. + +## Required behavior +* Always use `specsmith load` instead of raw git pull +* Ensure proper synchronization with remote repository +* Restore ESDB from backup when specified +* Follow the governed agent loop for all load operations +* Validate that loaded state is consistent + """, + ), + SkillEntry( + slug="specsmith-audit", + name="Specsmith Audit", + description="Audit changes and ensure compliance with governance standards.", + domain=SkillDomain.GOVERNANCE, + tags=["governance", "audit", "compliance", "verification"], + body=""" +# Specsmith Audit + +## Purpose +Audit changes and ensure compliance with governance standards. + +## Required behavior +* Run `specsmith audit` to verify compliance +* Check that all requirements are met +* Ensure all tests pass +* Verify that preflight decisions are properly recorded +* Validate that governance rules are followed + """, + ), + SkillEntry( + slug="specsmith-commit", + name="Specsmith Commit", + description="Stage, audit, and commit with governance-aware message.", + domain=SkillDomain.GOVERNANCE, + tags=["governance", "commit", "git", "specsmith"], + body=""" +# Specsmith Commit + +## Purpose +Stage, audit, and commit with governance-aware message. + +## Required behavior +* Run `specsmith commit` instead of raw git commit +* Ensure all changes are properly audited before committing +* Use governance-aware commit messages +* Follow the governed agent loop for all commit operations +* Maintain proper traceability of changes + """, + ), + SkillEntry( + slug="specsmith-init", + name="Specsmith Init", + description="Scaffold a new governed project.", + domain=SkillDomain.GOVERNANCE, + tags=["governance", "init", "project", "setup"], + body=""" +# Specsmith Init + +## Purpose +Scaffold a new governed project. + +## Required behavior +* Run `specsmith init` to create a new governed project +* Follow all Specsmith governance rules during initialization +* Ensure proper project structure and documentation +* Set up governance files and configurations +* Validate that the project is properly configured for governance + """, + ), + SkillEntry( + slug="specsmith-apply", + name="Specsmith Apply", + description="Regenerate CI and agent files from current configuration.", + domain=SkillDomain.GOVERNANCE, + tags=["governance", "apply", "configuration", "automation"], + body=""" +# Specsmith Apply + +## Purpose +Regenerate CI and agent files from current configuration. + +## Required behavior +* Run `specsmith apply` to regenerate configuration files +* Ensure all generated files comply with governance standards +* Maintain consistency between configuration and governance rules +* Validate that generated files are properly formatted + """, + ), + SkillEntry( + slug="specsmith-sync", + name="Specsmith Sync", + description="Sync .specsmith/ machine state from docs/ Markdown.", + domain=SkillDomain.GOVERNANCE, + tags=["governance", "sync", "state", "configuration"], + body=""" +# Specsmith Sync + +## Purpose +Sync .specsmith/ machine state from docs/ Markdown. + +## Required behavior +* Run `specsmith sync` to synchronize governance state +* Ensure consistency between documentation and machine state +* Maintain proper governance compliance during sync operations +* Validate that all sync operations are properly recorded + """, + ), + SkillEntry( + slug="specsmith-validate", + name="Specsmith Validate", + description="Check governance file consistency (req ↔ test ↔ spec).", + domain=SkillDomain.GOVERNANCE, + tags=["governance", "validate", "consistency", "compliance"], + body=""" +# Specsmith Validate + +## Purpose +Check governance file consistency (req ↔ test ↔ spec). + +## Required behavior +* Run `specsmith validate` to check file consistency +* Ensure requirements, tests, and specifications are aligned +* Identify and report any inconsistencies in governance files +* Follow governance rules during validation + """, + ), + SkillEntry( + slug="specsmith-phase", + name="Specsmith Phase", + description="Track and advance the AEE workflow phase for a project.", + domain=SkillDomain.GOVERNANCE, + tags=["governance", "phase", "workflow", "aee"], + body=""" +# Specsmith Phase + +## Purpose +Track and advance the AEE workflow phase for a project. + +## Required behavior +* Run `specsmith phase` to check current workflow phase +* Follow proper phase advancement procedures +* Ensure all requirements are met for phase advancement +* Maintain proper governance documentation for each phase + """, + ), + SkillEntry( + slug="specsmith-esdb", + name="Specsmith ESDB", + description="Manage the ESDB (Epistemic State Database).", + domain=SkillDomain.GOVERNANCE, + tags=["governance", "esdb", "database", "state"], + body=""" +# Specsmith ESDB + +## Purpose +Manage the ESDB (Epistemic State Database). + +## Required behavior +* Run `specsmith esdb` commands to manage the epistemic state database +* Ensure proper governance compliance when managing ESDB +* Maintain data integrity and security +* Follow proper backup and restore procedures + """, + ), + SkillEntry( + slug="specsmith-trace", + name="Specsmith Trace", + description="Manage the cryptographic trace vault (STP-inspired).", + domain=SkillDomain.GOVERNANCE, + tags=["governance", "trace", "cryptographic", "vault"], + body=""" +# Specsmith Trace + +## Purpose +Manage the cryptographic trace vault (STP-inspired). + +## Required behavior +* Run `specsmith trace` commands to manage cryptographic traces +* Ensure all trace operations follow governance rules +* Maintain proper cryptographic security practices +* Follow traceability requirements for all operations + """, + ), + SkillEntry( + slug="specsmith-session", + name="Specsmith Session", + description="Session lifecycle management.", + domain=SkillDomain.GOVERNANCE, + tags=["governance", "session", "lifecycle", "agent"], + body=""" +# Specsmith Session + +## Purpose +Session lifecycle management. + +## Required behavior +* Run `specsmith session` commands to manage agent sessions +* Follow proper session lifecycle procedures +* Ensure all session operations are properly governed +* Maintain session state and traceability + """, + ), + SkillEntry( + slug="specsmith-workflow", + name="Specsmith Workflow", + description="Record, list, and run parameterised command snippets.", + domain=SkillDomain.GOVERNANCE, + tags=["governance", "workflow", "automation", "commands"], + body=""" +# Specsmith Workflow + +## Purpose +Record, list, and run parameterised command snippets. + +## Required behavior +* Run `specsmith workflow` to manage command workflows +* Ensure all workflows follow governance rules +* Maintain proper documentation of workflows +* Validate that workflows execute correctly + """, + ), + SkillEntry( + slug="specsmith-wi", + name="Specsmith Work Item", + description="Manage the lifecycle of Work Items (WIs).", + domain=SkillDomain.GOVERNANCE, + tags=["governance", "work-item", "wi", "tracking"], + body=""" +# Specsmith Work Item + +## Purpose +Manage the lifecycle of Work Items (WIs). + +## Required behavior +* Run `specsmith wi` commands to manage work items +* Follow proper work item lifecycle procedures +* Ensure all work items are properly tracked and governed +* Maintain traceability of work item progress + """, + ), + SkillEntry( + slug="specsmith-req", + name="Specsmith Requirements", + description="Manage requirements.", + domain=SkillDomain.GOVERNANCE, + tags=["governance", "requirements", "req", "tracking"], + body=""" +# Specsmith Requirements + +## Purpose +Manage requirements. + +## Required behavior +* Run `specsmith req` commands to manage requirements +* Follow proper requirements management procedures +* Ensure all requirements are properly documented and tracked +* Maintain traceability between requirements and tests + """, + ), + SkillEntry( + slug="specsmith-test", + name="Specsmith Tests", + description="Manage test cases.", + domain=SkillDomain.GOVERNANCE, + tags=["governance", "tests", "test", "verification"], + body=""" +# Specsmith Tests + +## Purpose +Manage test cases. + +## Required behavior +* Run `specsmith test` commands to manage test cases +* Follow proper test case management procedures +* Ensure all tests are properly documented and linked to requirements +* Maintain test coverage and quality + """, + ), + SkillEntry( + slug="specsmith-compliance", + name="Specsmith Compliance", + description="EU and North American AI regulation compliance.", + domain=SkillDomain.GOVERNANCE, + tags=["governance", "compliance", "ai", "regulation"], + body=""" +# Specsmith Compliance + +## Purpose +EU and North American AI regulation compliance. + +## Required behavior +* Run `specsmith compliance` to check AI regulation compliance +* Ensure all AI-related activities follow applicable regulations +* Maintain proper documentation of compliance measures +* Report compliance status as required + """, + ), +] diff --git a/src/specsmith/skills/specsmith_operations.py b/src/specsmith/skills/specsmith_operations.py new file mode 100644 index 00000000..dec8741b --- /dev/null +++ b/src/specsmith/skills/specsmith_operations.py @@ -0,0 +1,67 @@ +# SPDX-License-Identifier: MIT +"""Specsmith operation skills - skills for using specsmith save, push, and load commands.""" + +from specsmith.skills import SkillDomain, SkillEntry + +SKILLS = [ + SkillEntry( + slug="specsmith-save", + name="Specsmith Save", + description="Save changes through Specsmith, not raw git.", + domain=SkillDomain.GOVERNANCE, + tags=["governance", "save", "commit", "specsmith"], + body=""" +# Specsmith Save + +## Purpose +Save changes through Specsmith, not raw git. + +## Required behavior +* Always use `specsmith save` instead of raw git commands +* Ensure all changes are properly recorded in the Specsmith trace +* Run preflight checks before saving +* Maintain proper commit messages with work item references +* Follow the governed agent loop for all save operations + """, + ), + SkillEntry( + slug="specsmith-push", + name="Specsmith Push", + description="Push changes with Specsmith safety checks.", + domain=SkillDomain.GOVERNANCE, + tags=["governance", "push", "commit", "specsmith"], + body=""" +# Specsmith Push + +## Purpose +Push changes with Specsmith safety checks. + +## Required behavior +* Always use `specsmith push` instead of raw git push +* Run preflight checks before pushing +* Ensure all changes are properly audited +* Follow the governed agent loop for all push operations +* Override safety checks only when explicitly required + """, + ), + SkillEntry( + slug="specsmith-load", + name="Specsmith Load", + description="Load governance state from remote or backup.", + domain=SkillDomain.GOVERNANCE, + tags=["governance", "load", "restore", "specsmith"], + body=""" +# Specsmith Load + +## Purpose +Load governance state from remote or backup. + +## Required behavior +* Always use `specsmith load` instead of raw git pull +* Ensure proper synchronization with remote repository +* Restore ESDB from backup when specified +* Follow the governed agent loop for all load operations +* Validate that loaded state is consistent + """, + ), +] diff --git a/src/specsmith/skills/specsmith_skills.py b/src/specsmith/skills/specsmith_skills.py index 89b1bf26..f4f73f51 100644 --- a/src/specsmith/skills/specsmith_skills.py +++ b/src/specsmith/skills/specsmith_skills.py @@ -24,6 +24,87 @@ from __future__ import annotations -from specsmith.skills import SkillEntry +from specsmith.skills import SkillDomain, SkillEntry -SKILLS: list[SkillEntry] = [] +SKILLS = [ + SkillEntry( + slug="specsmith", + name="Specsmith Governance", + description="Core Specsmith governance workflows and compliance.", + domain=SkillDomain.GOVERNANCE, + tags=["governance", "specsmith", "compliance"], + body=""" +# Specsmith Governance + +## Purpose +Core Specsmith governance workflows and compliance. + +## Required behavior +* Follow all Specsmith governance rules and processes +* Ensure compliance with project standards and requirements +* Maintain proper governance documentation and traceability +* Run preflight checks before any significant changes +* Follow the governed agent loop execution model + """, + ), + SkillEntry( + slug="specsmith-save", + name="Specsmith Save", + description="Save changes through Specsmith, not raw git.", + domain=SkillDomain.GOVERNANCE, + tags=["governance", "save", "commit", "specsmith"], + body=""" +# Specsmith Save + +## Purpose +Save changes through Specsmith, not raw git. + +## Required behavior +* Always use `specsmith save` instead of raw git commands +* Ensure all changes are properly recorded in the Specsmith trace +* Run preflight checks before saving +* Maintain proper commit messages with work item references +* Follow the governed agent loop for all save operations + """, + ), + SkillEntry( + slug="specsmith-audit", + name="Specsmith Audit", + description="Audit changes and ensure compliance with governance standards.", + domain=SkillDomain.GOVERNANCE, + tags=["governance", "audit", "compliance", "verification"], + body=""" +# Specsmith Audit + +## Purpose +Audit changes and ensure compliance with governance standards. + +## Required behavior +* Run `specsmith audit` to verify compliance +* Check that all requirements are met +* Ensure all tests pass +* Verify that preflight decisions are properly recorded +* Validate that governance rules are followed + """, + ), + SkillEntry( + slug="specsmith-session-governance", + name="Specsmith Session Governance", + description="Govern session behavior and ensure proper governance compliance.", + domain=SkillDomain.GOVERNANCE, + tags=["governance", "session", "compliance", "execution"], + body=""" +# Specsmith Session Governance + +## Purpose +Govern session behavior and ensure proper governance compliance. + +## Required behavior +* Run session bootstrap procedures +* Emit governance anchor at session start +* Follow the governed agent loop execution model +* Ensure all actions are properly preflighted +* Maintain session state and traceability + """, + ), +] diff --git a/src/specsmith/sync.py b/src/specsmith/sync.py index 9f88999e..2625f819 100644 --- a/src/specsmith/sync.py +++ b/src/specsmith/sync.py @@ -28,6 +28,17 @@ from pathlib import Path from typing import Any, Protocol, cast + +class _MigratableStore(Protocol): + """Minimal ESDB interface required by automatic legacy-data migration.""" + + def record_count(self) -> int: + pass + + def migrate_from_json(self, specsmith_dir: Path) -> dict[str, int] | Any: + pass + + # --------------------------------------------------------------------------- # Markdown parsers # --------------------------------------------------------------------------- @@ -233,7 +244,7 @@ def message(self) -> str: # Decision rationale: # config.yml — project identity and settings # requirements/testcases — governance canon (YAML-first or JSON cache) -# esdb.sqlite3 — ESDB SQLite backend (canonical record store) +# session-events.jsonl — mergeable canonical session event log # esdb_migration_manifest — which migrations have run; tracked for # reproducibility so fresh clones don't re-run # events.wal/snapshot — ChronoMemory canonical state (commercial tier) @@ -241,10 +252,10 @@ def message(self) -> str: ".specsmith/config.yml", ".specsmith/requirements.json", ".specsmith/testcases.json", - ".specsmith/esdb.sqlite3", ".specsmith/esdb_migration_manifest.json", ".chronomemory/events.wal", ".chronomemory/snapshot.json", + ".chronomemory/session-events.jsonl", ) # Paths that MUST NOT be tracked in git — runtime/ephemeral artifacts. @@ -253,6 +264,8 @@ def message(self) -> str: # ignore rule is immediately effective rather than a dormant no-op. # # Decision rationale: +# esdb.sqlite3 + sidecars — local SQLite cache and journaling state; session +# events are the mergeable canonical representation # workitems.json — runtime WI allocation; re-minted by preflight # ledger-chain.txt — ephemeral hash-chain cache; DEPRECATED (REQ-420) # trace.jsonl — trace log; DEPRECATED by ESDB seal_records (REQ-420) @@ -264,7 +277,12 @@ def message(self) -> str: # runs/chat/perf/... — transient runtime directories # ledger.jsonl — deprecated flat-file ledger (superseded by LEDGER.md) # chronomemory/backup — timestamped ChronoMemory backup copies +# migration artifacts — local upgrade state, recovery copies, and one-time +# backfill markers; the ESDB manifest is canonical _GIT_IGNORED_POLICY: tuple[str, ...] = ( + ".specsmith/esdb.sqlite3", + ".specsmith/esdb.sqlite3-shm", + ".specsmith/esdb.sqlite3-wal", ".specsmith/workitems.json", ".specsmith/ledger-chain.txt", ".specsmith/trace.jsonl", @@ -283,6 +301,14 @@ def message(self) -> str: ".specsmith/agent-reports/", ".specsmith/dispatch/", ".specsmith/ledger.jsonl", + ".specsmith/agent-tools.json", + ".specsmith/agents.md.bak", + ".specsmith/agents.md.m005.bak", + ".specsmith/migration-state.json", + ".specsmith/migration-backups/", + ".specsmith/esdb-full-coverage", + ".specsmith/esdb-m009-backfill", + ".specsmith/esdb-m010-cleanup", ".chronomemory/backup/", ) @@ -359,6 +385,7 @@ def normalize_esdb_gitignore_policy(root: Path, *, dry_run: bool = False) -> boo normalized_lines: list[str] = [] removed_forbidden = False + removed_stale_policy = False in_auto_block = False for line in original_lines: stripped = line.strip() @@ -367,6 +394,7 @@ def normalize_esdb_gitignore_policy(root: Path, *, dry_run: bool = False) -> boo continue if stripped == _POLICY_SENTINEL: in_auto_block = True # drop the old sentinel and everything after it + removed_stale_policy = True continue if in_auto_block: # Keep lines that are unrelated to the specsmith policy block @@ -388,7 +416,9 @@ def normalize_esdb_gitignore_policy(root: Path, *, dry_run: bool = False) -> boo deny_lines = list(_GIT_IGNORED_POLICY) missing_allows = [ln for ln in allow_lines if ln not in existing] missing_denies = [ln for ln in deny_lines if ln not in existing] - gitignore_changed = removed_forbidden or bool(missing_allows) or bool(missing_denies) + gitignore_changed = ( + removed_forbidden or removed_stale_policy or bool(missing_allows) or bool(missing_denies) + ) if not dry_run and gitignore_changed: if normalized_lines and normalized_lines[-1].strip(): @@ -775,16 +805,9 @@ def auto_migrate_if_needed(root: Path) -> dict[str, int]: if not specsmith_dir.exists(): return {} - class _MigratableStore(Protocol): - def record_count(self) -> int: - pass - - def migrate_from_json(self, specsmith_dir: Path) -> dict[str, int] | Any: - pass - try: with open_default_store(root, warn=False) as store: - typed_store = cast("_MigratableStore", store) + typed_store = cast(_MigratableStore, store) if not _should_auto_migrate(typed_store, specsmith_dir): return {} counts = typed_store.migrate_from_json(specsmith_dir) diff --git a/src/specsmith/templates/agents.md.j2 b/src/specsmith/templates/agents.md.j2 index 811f990e..a65ba3bb 100644 --- a/src/specsmith/templates/agents.md.j2 +++ b/src/specsmith/templates/agents.md.j2 @@ -9,7 +9,7 @@ Run these steps at the start of **every** session before touching any code: ```bash # 0. Kill any orphaned processes from previous sessions -specsmith kill-session 2>/dev/null || true +specsmith kill-session # idempotent; safe when no processes exist # 1. Apply any pending forward migrations (always auto-accepted — no prompt) specsmith migrate run --project-dir . diff --git a/src/specsmith/templates/community/contributing.md.j2 b/src/specsmith/templates/community/contributing.md.j2 index 924e3f11..0a9595fc 100644 --- a/src/specsmith/templates/community/contributing.md.j2 +++ b/src/specsmith/templates/community/contributing.md.j2 @@ -5,9 +5,15 @@ Thank you for your interest in contributing! This project uses the [Agentic AI D ## Getting Started 1. Fork the repository and clone your fork +{% if project.branching_strategy == "single-branch" %} +2. Work directly on `{{ project.default_branch }}`; branch and PR workflows stay disabled until explicitly enabled with `specsmith branch workflow <strategy>` +3. Make, verify, and commit your changes on `{{ project.default_branch }}` +4. Push the governed commit to `{{ project.default_branch }}` +{% else %} 2. Create a feature branch from `{{ project.develop_branch }}`: `git checkout -b feat/your-feature` 3. Make your changes following the guidelines below 4. Push and open a pull request against `{{ project.develop_branch }}` +{% endif %} ## Development Workflow @@ -15,7 +21,11 @@ This project follows a **propose → check → execute → verify → record** w 1. **Read** `AGENTS.md` and `LEDGER.md` before starting work 2. **Propose** your change (issue or PR description) +{% if project.branching_strategy == "single-branch" %} +3. **Implement** directly on `{{ project.default_branch }}` +{% else %} 3. **Implement** on a feature branch +{% endif %} 4. **Verify** — run all checks before submitting: {% if tools.lint %} - Lint: `{{ tools.lint[0] }}` @@ -31,13 +41,18 @@ This project follows a **propose → check → execute → verify → record** w {% endif %} 5. **Record** — update `LEDGER.md` with what you changed and why -## Pull Request Guidelines +## {% if project.branching_strategy == "single-branch" %}Commit{% else %}Pull Request{% endif %} Guidelines +{% if project.branching_strategy != "single-branch" %} - Reference the issue number in your PR title (e.g., `feat: add widget support (#123)`) - All CI checks must pass before merge {% if project.require_pr_reviews %} - At least {{ project.required_approvals }} approval(s) required {% endif %} +{% else %} +- Reference the work item or issue in the commit message +- All CI checks must pass before pushing +{% endif %} - Keep commits focused and well-described - Update `docs/REQUIREMENTS.md` and `docs/TESTS.md` if your change adds or modifies requirements diff --git a/src/specsmith/templates/gitignore.j2 b/src/specsmith/templates/gitignore.j2 index e18fa083..4c6a49e5 100644 --- a/src/specsmith/templates/gitignore.j2 +++ b/src/specsmith/templates/gitignore.j2 @@ -35,6 +35,7 @@ htmlcov/ # Build artifacts .work/ +/site/ *.log # specsmith governance data policy (auto-enforced by specsmith sync) @@ -43,13 +44,16 @@ htmlcov/ !.specsmith/config.yml !.specsmith/requirements.json !.specsmith/testcases.json -!.specsmith/esdb.sqlite3 !.specsmith/esdb_migration_manifest.json !.chronomemory/events.wal !.chronomemory/snapshot.json +!.chronomemory/session-events.jsonl # # Ephemeral runtime paths — never committed: # (specsmith sync will run `git rm --cached` for any of these already tracked) +.specsmith/esdb.sqlite3 +.specsmith/esdb.sqlite3-shm +.specsmith/esdb.sqlite3-wal .specsmith/workitems.json .specsmith/ledger-chain.txt .specsmith/trace.jsonl diff --git a/src/specsmith/updater.py b/src/specsmith/updater.py index 663fc319..f5671ffe 100644 --- a/src/specsmith/updater.py +++ b/src/specsmith/updater.py @@ -4,6 +4,7 @@ from __future__ import annotations +import re import subprocess from pathlib import Path @@ -94,6 +95,29 @@ def is_pipx_install() -> bool: return bool(exe.startswith(unix_pipx)) +def version_mismatch_remediation(project_version: str) -> str: + """Return the safe pipx command for a project ahead of the stable channel.""" + is_prerelease = re.search(r"\d(?:a|b|rc)\d", project_version) is not None + if ".dev" in project_version or "+" in project_version or is_prerelease: + return f"pipx install --force specsmith=={project_version}" + return "pipx upgrade specsmith" + + +def is_prerelease_version(version: str) -> bool: + """Return whether a PEP 440 version cannot represent the stable channel.""" + return bool(".dev" in version or "+" in version or re.search(r"\d(?:a|b|rc)\d", version)) + + +def find_windows_launchers(path_value: str) -> list[Path]: + """Return every discoverable ``specsmith.exe`` on a Windows PATH value.""" + launchers: list[Path] = [] + for entry in path_value.split(";"): + candidate = Path(entry) / "specsmith.exe" + if entry and candidate.is_file(): + launchers.append(candidate) + return launchers + + def run_self_update( *, channel: str = "", diff --git a/src/specsmith/vcs_commands.py b/src/specsmith/vcs_commands.py index ca3c069c..e6d1cabd 100644 --- a/src/specsmith/vcs_commands.py +++ b/src/specsmith/vcs_commands.py @@ -175,7 +175,7 @@ def run_push(root: Path, *, force: bool = False) -> GitResult: if scaffold_path and scaffold_path.exists() and not force: with open(scaffold_path) as f: raw = yaml.safe_load(f) or {} - strategy = raw.get("branching_strategy", "gitflow") + strategy = raw.get("branching_strategy", "single-branch") main_branch = raw.get("default_branch", "main") if strategy == "gitflow" and branch == main_branch: @@ -265,10 +265,20 @@ def create_branch( root: Path, name: str, *, - strategy: str = "gitflow", + strategy: str = "single-branch", main_branch: str = "main", ) -> GitResult: """Create a branch following the branching strategy.""" + if strategy == "single-branch": + return GitResult( + success=False, + message=( + "Branch creation is disabled by the single-branch workflow. " + "Enable GitFlow, trunk-based, or GitHub Flow with " + "`specsmith branch workflow <strategy>` first." + ), + ) + develop_branch = "develop" # Determine base branch @@ -344,22 +354,32 @@ def create_pr( scaffold_path = find_scaffold(root) platform = "github" - base_branch = "develop" + raw: dict[str, object] = {} if scaffold_path and scaffold_path.exists(): with open(scaffold_path) as f: raw = yaml.safe_load(f) or {} - platform = raw.get("vcs_platform", "github") - strategy = raw.get("branching_strategy", "gitflow") - branch = get_current_branch(root) - - if strategy == "gitflow": - if branch.startswith("hotfix/") or branch.startswith("release/"): - base_branch = raw.get("default_branch", "main") - else: - base_branch = raw.get("develop_branch", "develop") + + platform = str(raw.get("vcs_platform", "github")) + strategy = str(raw.get("branching_strategy", "single-branch")) + if strategy == "single-branch": + return GitResult( + success=False, + message=( + "Pull requests are disabled by the single-branch workflow. " + "Enable GitFlow, trunk-based, or GitHub Flow with " + "`specsmith branch workflow <strategy>` first." + ), + ) + + branch = get_current_branch(root) + if strategy == "gitflow": + if branch.startswith("hotfix/") or branch.startswith("release/"): + base_branch = str(raw.get("default_branch", "main")) else: - base_branch = raw.get("default_branch", "main") + base_branch = str(raw.get("develop_branch", "develop")) + else: + base_branch = str(raw.get("default_branch", "main")) if not title: title = generate_commit_message(root) diff --git a/src/specsmith/wi_store.py b/src/specsmith/wi_store.py index de2574e5..270cba17 100644 --- a/src/specsmith/wi_store.py +++ b/src/specsmith/wi_store.py @@ -185,8 +185,15 @@ def __init__(self, project_root: str | Path) -> None: # os.path.realpath is the CodeQL-recognised sanitiser for py/path-injection. # Path.resolve() is NOT tracked by CodeQL's taint model — always use # os.path.realpath for paths originating from caller/user input. - self._root = Path(os.path.realpath(str(project_root))) - self._path = self._root / ".specsmith" / _WORKITEMS_FILE + root = os.path.realpath(str(project_root)) + state_dir = os.path.realpath(os.path.join(root, ".specsmith")) + path = os.path.realpath(os.path.join(state_dir, _WORKITEMS_FILE)) + if state_dir != root and not state_dir.startswith(root + os.sep): + raise WorkItemError(f"Work-item state escapes project root: {state_dir!r}") + if not path.startswith(state_dir + os.sep): + raise WorkItemError(f"Work-item file escapes state directory: {path!r}") + self._root = Path(root) + self._path = Path(path) # ------------------------------------------------------------------ # Persistence diff --git a/src/specsmith/workspace.py b/src/specsmith/workspace.py index f5067d33..f8f60b74 100644 --- a/src/specsmith/workspace.py +++ b/src/specsmith/workspace.py @@ -92,7 +92,7 @@ def init_workspace(root: Path, name: str, project_paths: list[str]) -> Path: "projects": [{"path": p} for p in project_paths], "defaults": { "vcs_platform": "github", - "branching_strategy": "gitflow", + "branching_strategy": "single-branch", "required_approvals": 1, }, } diff --git a/temp_api.json b/temp_api.json new file mode 100644 index 00000000..427311b2 --- /dev/null +++ b/temp_api.json @@ -0,0 +1,143 @@ +{ + "cli_commands": [ + "abort", + "agent", + "agents", + "ai-analyze", + "api-surface", + "apply", + "approve", + "architect", + "audit", + "auth", + "belief-graph", + "branch", + "channel", + "chat", + "chat-export-block", + "checkpoint", + "ci", + "clean", + "cleanup", + "commit", + "compliance", + "compress", + "config", + "context", + "credits", + "dashboard", + "datasources", + "diff", + "dispatch", + "doctor", + "drift-check", + "drive", + "endpoints", + "epistemic-audit", + "esdb", + "eval", + "exec", + "exec-profiles", + "expand", + "export", + "generate", + "generate-tests", + "github", + "governance-serve", + "governed-pr", + "gui", + "history", + "import", + "index", + "info", + "init", + "inspect", + "instinct", + "integrate", + "issue", + "kill-session", + "ledger", + "load", + "local-model", + "mcp", + "metrics", + "migrate", + "migrate-project", + "model-intel", + "models", + "notebook", + "ollama", + "optimize", + "parse-reqs", + "patent", + "phase", + "plugin", + "policy", + "pr", + "preflight", + "providers", + "ps", + "pull", + "push", + "quality-report", + "quickstart", + "recover", + "release", + "req", + "resume", + "rules", + "run", + "save", + "scan", + "self-update", + "serve", + "session", + "session-clear", + "session-end", + "session-show", + "skill", + "skills", + "status", + "stress-test", + "suggest-command", + "sync", + "teams", + "test", + "test-ran", + "tools", + "trace", + "transcript", + "update", + "upgrade", + "validate", + "verify", + "verify-integrations", + "verify-release", + "voice", + "watch", + "wi", + "wireframes", + "workflow", + "workspace", + "zoo-code" + ], + "event_types": [ + "block_start", + "block_complete", + "token", + "plan_step", + "tool_call", + "tool_request", + "tool_result", + "diff", + "task_complete" + ], + "exit_codes": { + "preflight_accepted": 0, + "preflight_blocked": 3, + "preflight_needs_clarification": 2, + "verify_ok": 0, + "verify_retry": 2, + "verify_stop": 3 + } +} diff --git a/temp_api_surface.json b/temp_api_surface.json new file mode 100644 index 00000000..427311b2 --- /dev/null +++ b/temp_api_surface.json @@ -0,0 +1,143 @@ +{ + "cli_commands": [ + "abort", + "agent", + "agents", + "ai-analyze", + "api-surface", + "apply", + "approve", + "architect", + "audit", + "auth", + "belief-graph", + "branch", + "channel", + "chat", + "chat-export-block", + "checkpoint", + "ci", + "clean", + "cleanup", + "commit", + "compliance", + "compress", + "config", + "context", + "credits", + "dashboard", + "datasources", + "diff", + "dispatch", + "doctor", + "drift-check", + "drive", + "endpoints", + "epistemic-audit", + "esdb", + "eval", + "exec", + "exec-profiles", + "expand", + "export", + "generate", + "generate-tests", + "github", + "governance-serve", + "governed-pr", + "gui", + "history", + "import", + "index", + "info", + "init", + "inspect", + "instinct", + "integrate", + "issue", + "kill-session", + "ledger", + "load", + "local-model", + "mcp", + "metrics", + "migrate", + "migrate-project", + "model-intel", + "models", + "notebook", + "ollama", + "optimize", + "parse-reqs", + "patent", + "phase", + "plugin", + "policy", + "pr", + "preflight", + "providers", + "ps", + "pull", + "push", + "quality-report", + "quickstart", + "recover", + "release", + "req", + "resume", + "rules", + "run", + "save", + "scan", + "self-update", + "serve", + "session", + "session-clear", + "session-end", + "session-show", + "skill", + "skills", + "status", + "stress-test", + "suggest-command", + "sync", + "teams", + "test", + "test-ran", + "tools", + "trace", + "transcript", + "update", + "upgrade", + "validate", + "verify", + "verify-integrations", + "verify-release", + "voice", + "watch", + "wi", + "wireframes", + "workflow", + "workspace", + "zoo-code" + ], + "event_types": [ + "block_start", + "block_complete", + "token", + "plan_step", + "tool_call", + "tool_request", + "tool_result", + "diff", + "task_complete" + ], + "exit_codes": { + "preflight_accepted": 0, + "preflight_blocked": 3, + "preflight_needs_clarification": 2, + "verify_ok": 0, + "verify_retry": 2, + "verify_stop": 3 + } +} diff --git a/test_zoo_code_commands.py b/test_zoo_code_commands.py deleted file mode 100644 index b2935042..00000000 --- a/test_zoo_code_commands.py +++ /dev/null @@ -1,141 +0,0 @@ -#!/usr/bin/env python3 -"""Test script to verify all Zoo-Code commands are properly implemented.""" - -import sys -import os -from pathlib import Path - -# Add the src directory to the path so we can import specsmith modules -sys.path.insert(0, str(Path(__file__).parent / "src")) - -def test_command_imports(): - """Test that all zoo-code commands can be imported without errors.""" - try: - from specsmith.commands.zoo_code import ( - zoo_code_group, - zoo_code_init, - zoo_code_export_modes, - zoo_code_benchmark, - zoo_code_telemetry, - zoo_code_verify, - zoo_code_metrics, - zoo_code_escalate, - zoo_code_optimize, - zoo_code_benchmark_test, - zoo_code_cross_platform, - zoo_code_dashboard - ) - print("✓ All zoo-code command modules imported successfully") - return True - except Exception as e: - print(f"✗ Failed to import zoo-code commands: {e}") - return False - -def test_command_structure(): - """Test that the command structure is properly defined.""" - try: - from specsmith.commands.zoo_code import zoo_code_group - # Check that the group has the expected commands - expected_commands = [ - 'init', - 'export-modes', - 'benchmark', - 'telemetry', - 'verify', - 'metrics', - 'escalate', - 'optimize', - 'benchmark-test', - 'cross-platform', - 'dashboard' - ] - - # Get the command names from the group - command_names = [cmd.name for cmd in zoo_code_group.commands.values()] - - missing_commands = set(expected_commands) - set(command_names) - extra_commands = set(command_names) - set(expected_commands) - - if missing_commands: - print(f"✗ Missing commands: {missing_commands}") - return False - elif extra_commands: - print(f"⚠ Extra commands found: {extra_commands}") - # This is not necessarily an error, but worth noting - else: - print("✓ All expected commands found in zoo-code group") - - return True - except Exception as e: - print(f"✗ Failed to verify command structure: {e}") - return False - -def test_function_signatures(): - """Test that key functions have expected signatures.""" - try: - from specsmith.commands.zoo_code import ( - zoo_code_telemetry, - zoo_code_verify, - zoo_code_escalate, - zoo_code_optimize, - zoo_code_benchmark_test, - zoo_code_cross_platform, - zoo_code_dashboard - ) - - # Test that functions exist and are callable - functions_to_test = [ - ('zoo_code_telemetry', zoo_code_telemetry), - ('zoo_code_verify', zoo_code_verify), - ('zoo_code_escalate', zoo_code_escalate), - ('zoo_code_optimize', zoo_code_optimize), - ('zoo_code_benchmark_test', zoo_code_benchmark_test), - ('zoo_code_cross_platform', zoo_code_cross_platform), - ('zoo_code_dashboard', zoo_code_dashboard) - ] - - for name, func in functions_to_test: - if callable(func): - print(f"✓ {name} is callable") - else: - print(f"✗ {name} is not callable") - return False - - return True - except Exception as e: - print(f"✗ Failed to test function signatures: {e}") - return False - -def main(): - """Run all tests.""" - print("Testing Zoo-Code Command Implementation") - print("=" * 40) - - tests = [ - test_command_imports, - test_command_structure, - test_function_signatures - ] - - passed = 0 - total = len(tests) - - for test in tests: - print(f"\nRunning {test.__name__}...") - if test(): - passed += 1 - else: - print(f"✗ {test.__name__} failed") - - print(f"\n{'=' * 40}") - print(f"Results: {passed}/{total} tests passed") - - if passed == total: - print("✓ All tests passed! Zoo-Code commands are properly implemented.") - return 0 - else: - print("✗ Some tests failed.") - return 1 - -if __name__ == "__main__": - sys.exit(main()) diff --git a/test_zoo_code_simple.py b/test_zoo_code_simple.py deleted file mode 100644 index 406fff80..00000000 --- a/test_zoo_code_simple.py +++ /dev/null @@ -1,141 +0,0 @@ -#!/usr/bin/env python3 -"""Simple test script to verify all Zoo-Code commands are properly implemented.""" - -import sys -import os -from pathlib import Path - -# Add the src directory to the path so we can import specsmith modules -sys.path.insert(0, str(Path(__file__).parent / "src")) - -def test_command_imports(): - """Test that all zoo-code commands can be imported without errors.""" - try: - from specsmith.commands.zoo_code import ( - zoo_code_group, - zoo_code_init, - zoo_code_export_modes, - zoo_code_benchmark, - zoo_code_telemetry, - zoo_code_verify, - zoo_code_metrics, - zoo_code_escalate, - zoo_code_optimize, - zoo_code_benchmark_test, - zoo_code_cross_platform, - zoo_code_dashboard - ) - print("All zoo-code command modules imported successfully") - return True - except Exception as e: - print(f"Failed to import zoo-code commands: {e}") - return False - -def test_command_structure(): - """Test that the command structure is properly defined.""" - try: - from specsmith.commands.zoo_code import zoo_code_group - # Check that the group has the expected commands - expected_commands = [ - 'init', - 'export-modes', - 'benchmark', - 'telemetry', - 'verify', - 'metrics', - 'escalate', - 'optimize', - 'benchmark-test', - 'cross-platform', - 'dashboard' - ] - - # Get the command names from the group - command_names = [cmd.name for cmd in zoo_code_group.commands.values()] - - missing_commands = set(expected_commands) - set(command_names) - extra_commands = set(command_names) - set(expected_commands) - - if missing_commands: - print(f"Missing commands: {missing_commands}") - return False - elif extra_commands: - print(f"Extra commands found: {extra_commands}") - # This is not necessarily an error, but worth noting - else: - print("All expected commands found in zoo-code group") - - return True - except Exception as e: - print(f"Failed to verify command structure: {e}") - return False - -def test_function_signatures(): - """Test that key functions have expected signatures.""" - try: - from specsmith.commands.zoo_code import ( - zoo_code_telemetry, - zoo_code_verify, - zoo_code_escalate, - zoo_code_optimize, - zoo_code_benchmark_test, - zoo_code_cross_platform, - zoo_code_dashboard - ) - - # Test that functions exist and are callable - functions_to_test = [ - ('zoo_code_telemetry', zoo_code_telemetry), - ('zoo_code_verify', zoo_code_verify), - ('zoo_code_escalate', zoo_code_escalate), - ('zoo_code_optimize', zoo_code_optimize), - ('zoo_code_benchmark_test', zoo_code_benchmark_test), - ('zoo_code_cross_platform', zoo_code_cross_platform), - ('zoo_code_dashboard', zoo_code_dashboard) - ] - - for name, func in functions_to_test: - if callable(func): - print(f"{name} is callable") - else: - print(f"{name} is not callable") - return False - - return True - except Exception as e: - print(f"Failed to test function signatures: {e}") - return False - -def main(): - """Run all tests.""" - print("Testing Zoo-Code Command Implementation") - print("=" * 40) - - tests = [ - test_command_imports, - test_command_structure, - test_function_signatures - ] - - passed = 0 - total = len(tests) - - for test in tests: - print(f"\nRunning {test.__name__}...") - if test(): - passed += 1 - else: - print(f"{test.__name__} failed") - - print(f"\n{'=' * 40}") - print(f"Results: {passed}/{total} tests passed") - - if passed == total: - print("All tests passed! Zoo-Code commands are properly implemented.") - return 0 - else: - print("Some tests failed.") - return 1 - -if __name__ == "__main__": - sys.exit(main()) diff --git a/tests/fixtures/api_surface.json b/tests/fixtures/api_surface.json index 427311b2..5e2154b1 100644 --- a/tests/fixtures/api_surface.json +++ b/tests/fixtures/api_surface.json @@ -27,6 +27,7 @@ "credits", "dashboard", "datasources", + "dev", "diff", "dispatch", "doctor", diff --git a/tests/test_branch_workflow.py b/tests/test_branch_workflow.py new file mode 100644 index 00000000..89b58061 --- /dev/null +++ b/tests/test_branch_workflow.py @@ -0,0 +1,88 @@ +"""Regression coverage for the governed branching-workflow selection.""" + +from __future__ import annotations + +from pathlib import Path + +import yaml +from click.testing import CliRunner + +from specsmith.cli import main +from specsmith.config import ProjectConfig +from specsmith.vcs_commands import GitResult, create_branch, create_pr + + +def test_project_config_defaults_to_single_branch() -> None: + assert ProjectConfig(name="workflow-test").branching_strategy == "single-branch" + + +def test_single_branch_refuses_branch_creation(tmp_path: Path) -> None: + result = create_branch(tmp_path, "new-feature") + + assert not result.success + assert "Branch creation is disabled" in result.message + + +def test_gitflow_branch_creation_remains_available(tmp_path: Path, monkeypatch) -> None: + captured: list[str] = [] + + def fake_run_git(root: Path, args: list[str]) -> GitResult: + captured.extend(args) + return GitResult(success=True, message="created") + + monkeypatch.setattr("specsmith.vcs_commands._run_git", fake_run_git) + + result = create_branch(tmp_path, "feature/workflow", strategy="gitflow") + + assert result.success + assert captured == ["checkout", "-b", "feature/workflow", "develop"] + + +def test_single_branch_refuses_pull_request(tmp_path: Path) -> None: + (tmp_path / "scaffold.yml").write_text( + "branching_strategy: single-branch\n", + encoding="utf-8", + ) + + result = create_pr(tmp_path) + + assert not result.success + assert "Pull requests are disabled" in result.message + + +def test_missing_scaffold_uses_single_branch_default(tmp_path: Path) -> None: + result = create_pr(tmp_path) + + assert not result.success + assert "Pull requests are disabled" in result.message + + +def test_branch_workflow_command_enables_gitflow(tmp_path: Path) -> None: + (tmp_path / "scaffold.yml").write_text( + "name: workflow-test\nbranching_strategy: single-branch\n", + encoding="utf-8", + ) + + result = CliRunner().invoke( + main, + ["branch", "workflow", "gitflow", "--project-dir", str(tmp_path)], + ) + + assert result.exit_code == 0, result.output + config = yaml.safe_load((tmp_path / "scaffold.yml").read_text(encoding="utf-8")) + assert config["branching_strategy"] == "gitflow" + + +def test_branch_workflow_command_reports_current_strategy(tmp_path: Path) -> None: + (tmp_path / "scaffold.yml").write_text( + "branching_strategy: single-branch\n", + encoding="utf-8", + ) + + result = CliRunner().invoke( + main, + ["branch", "workflow", "--project-dir", str(tmp_path)], + ) + + assert result.exit_code == 0, result.output + assert "Branch workflow: single-branch" in result.output diff --git a/tests/test_chat_handoff.py b/tests/test_chat_handoff.py new file mode 100644 index 00000000..4ed1560b --- /dev/null +++ b/tests/test_chat_handoff.py @@ -0,0 +1,80 @@ +# SPDX-License-Identifier: MIT +from __future__ import annotations + +import json +from pathlib import Path + +import pytest +from click.testing import CliRunner + +from specsmith.chat_handoff import ( + build_handoff, + render_handoff_context, + store_handoff, + validate_handoff, +) +from specsmith.commands.zoo_code import zoo_code_group +from specsmith.context_orchestrator import ContextOrchestrator, OptimizeResultEx +from specsmith.session_store import save_session + + +def _history() -> list[dict[str, str]]: + return [ + {"role": "user", "content": "Decide how to preserve provenance."}, + {"role": "assistant", "content": "Use stable source identifiers."}, + {"role": "user", "content": "Keep uncertainty explicit."}, + {"role": "assistant", "content": "Use an extractive handoff."}, + {"role": "user", "content": "Continue implementation."}, + ] + + +def test_handoff_is_extractive_and_valid() -> None: + handoff = build_handoff(_history(), work_item_ids=["WI-TEST", "WI-TEST"]) + + assert handoff["confidence"] == 1.0 + assert handoff["work_item_ids"] == ["WI-TEST"] + assert handoff["turns"][0]["source_id"].startswith("turn:") + assert "verify source IDs" in render_handoff_context(handoff) + + +def test_handoff_rejects_unproven_confidence() -> None: + handoff = build_handoff(_history()) + handoff["confidence"] = 0.8 + + with pytest.raises(ValueError, match="confidence"): + validate_handoff(handoff) + + +def test_handoff_persists_to_sqlite(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None: + monkeypatch.setenv("SPECSMITH_ESDB_BACKEND", "sqlite") + handoff = build_handoff(_history()) + store_handoff(tmp_path, handoff) + + from specsmith.esdb import SqliteStore + + with SqliteStore(tmp_path) as store: + assert store.get(handoff["id"]) is not None + + +def test_tier_two_replaces_history_with_a_provenance_handoff( + tmp_path: Path, monkeypatch: pytest.MonkeyPatch +) -> None: + monkeypatch.setenv("SPECSMITH_ESDB_BACKEND", "sqlite") + result = OptimizeResultEx(history=_history()) + ContextOrchestrator(tmp_path)._run_tier2(result) + + assert result.history[0]["content"].startswith("[Epistemic handoff HANDOFF-") + assert len(result.history) == 4 + + +def test_zoo_code_exports_portable_handoff(tmp_path: Path) -> None: + save_session(tmp_path, {"work_item_ids": ["WI-TEST"]}, _history()) + output = tmp_path / "handoff.json" + result = CliRunner().invoke( + zoo_code_group, + ["export-handoff", "--project-dir", str(tmp_path), "--output", str(output)], + ) + + assert result.exit_code == 0, result.output + exported = json.loads(output.read_text(encoding="utf-8")) + assert exported["kind"] == "epistemic_chat_handoff" diff --git a/tests/test_docs_artifacts.py b/tests/test_docs_artifacts.py new file mode 100644 index 00000000..30c5f61f --- /dev/null +++ b/tests/test_docs_artifacts.py @@ -0,0 +1,19 @@ +# SPDX-License-Identifier: MIT +# Copyright (c) 2026 Layer1Labs Silicon, Inc. All rights reserved. +"""Regression coverage for documentation build artifacts.""" + +from pathlib import Path + + +def test_mkdocs_site_output_is_ignored_for_projects_and_scaffolds() -> None: + """Documentation builds must not leave a governed worktree dirty.""" + root = Path(__file__).parents[1] + project_lines = (root / ".gitignore").read_text(encoding="utf-8").splitlines() + template_lines = ( + (root / "src" / "specsmith" / "templates" / "gitignore.j2") + .read_text(encoding="utf-8") + .splitlines() + ) + + assert "/site/" in project_lines + assert "/site/" in template_lines diff --git a/tests/test_esdb_enforcement.py b/tests/test_esdb_enforcement.py index c24f9bc5..cf37763a 100644 --- a/tests/test_esdb_enforcement.py +++ b/tests/test_esdb_enforcement.py @@ -5,6 +5,7 @@ from __future__ import annotations import json +import subprocess from pathlib import Path import pytest @@ -51,11 +52,15 @@ def test_run_sync_normalizes_legacy_esdb_gitignore(tmp_path: Path) -> None: # Broad ignores must be gone assert ".specsmith/" not in lines assert ".chronomemory/" not in lines - # Allow-list (tracked source-of-truth) must be present - assert "!.specsmith/esdb.sqlite3" in lines + # Mergeable source-of-truth must be tracked; SQLite remains local runtime state. + assert ".specsmith/esdb.sqlite3" in lines + assert ".specsmith/esdb.sqlite3-shm" in lines + assert ".specsmith/esdb.sqlite3-wal" in lines + assert "!.specsmith/esdb.sqlite3" not in lines assert "!.specsmith/esdb_migration_manifest.json" in lines assert "!.chronomemory/events.wal" in lines assert "!.chronomemory/snapshot.json" in lines + assert "!.chronomemory/session-events.jsonl" in lines # Deny-list (ephemeral runtime) must be present assert ".chronomemory/backup/" in lines assert ".specsmith/workitems.json" in lines @@ -63,10 +68,47 @@ def test_run_sync_normalizes_legacy_esdb_gitignore(tmp_path: Path) -> None: assert ".specsmith/trace.jsonl" in lines assert ".specsmith/backups/" in lines assert ".specsmith/session_metrics.jsonl" in lines + assert ".specsmith/migration-backups/" in lines + assert ".specsmith/migration-state.json" in lines + assert ".specsmith/agent-tools.json" in lines + assert ".specsmith/esdb-full-coverage" in lines # esdb_migration_manifest must NOT appear as a bare deny rule assert ".specsmith/esdb_migration_manifest.json" not in lines +def test_run_sync_rewrites_stale_auto_normalized_gitignore(tmp_path: Path) -> None: + """A stale generated allow rule must not keep the SQLite cache tracked.""" + (tmp_path / ".gitignore").write_text( + "\n".join( + [ + "# project rule", + "dist/", + "# specsmith ESDB policy (auto-normalized)", + "# Tracked (governance source-of-truth):", + "!.specsmith/esdb.sqlite3", + "!.specsmith/requirements.json", + "# Ephemeral runtime paths (never commit):", + ".specsmith/workitems.json", + ] + ) + + "\n", + encoding="utf-8", + ) + + run_sync(tmp_path) + + lines = { + line.strip() + for line in (tmp_path / ".gitignore").read_text(encoding="utf-8").splitlines() + if line.strip() + } + assert "# project rule" in lines + assert "dist/" in lines + assert "!.specsmith/esdb.sqlite3" not in lines + assert ".specsmith/esdb.sqlite3" in lines + assert "!.chronomemory/session-events.jsonl" in lines + + def test_normalizer_policy_sets_are_disjoint() -> None: """_GIT_TRACKED_POLICY and _GIT_IGNORED_POLICY must never overlap.""" from specsmith.sync import _GIT_IGNORED_POLICY, _GIT_TRACKED_POLICY @@ -127,6 +169,63 @@ def test_save_uses_sqlite_store_backup(tmp_path: Path, monkeypatch: pytest.Monke assert backup_path.suffix == ".sqlite3" +def test_save_does_not_commit_generated_esdb_or_migration_artifacts( + tmp_path: Path, monkeypatch: pytest.MonkeyPatch +) -> None: + """Save commits canonical policy changes but never local runtime artifacts.""" + monkeypatch.setenv("SPECSMITH_ESDB_BACKEND", "sqlite") + + def git(*args: str) -> str: + result = subprocess.run( + ["git", *args], + cwd=tmp_path, + check=True, + capture_output=True, + text=True, + ) + return result.stdout + + git("init") + git("config", "user.name", "SpecSmith Test") + git("config", "user.email", "specsmith-test@example.invalid") + (tmp_path / "README.md").write_text("fixture\n", encoding="utf-8") + git("add", "README.md") + git("commit", "-m", "test: initialize fixture") + + state = tmp_path / ".specsmith" + state.mkdir() + generated_paths = ( + ".specsmith/agent-tools.json", + ".specsmith/agents.md.bak", + ".specsmith/agents.md.m005.bak", + ".specsmith/migration-state.json", + ".specsmith/migration-backups/fixture/state.json", + ".specsmith/esdb-full-coverage", + ".specsmith/esdb-m009-backfill", + ".specsmith/esdb-m010-cleanup", + ) + for relative_path in generated_paths: + path = tmp_path / relative_path + path.parent.mkdir(parents=True, exist_ok=True) + path.write_text("generated\n", encoding="utf-8") + with SqliteStore(tmp_path) as store: + store.upsert(SqliteRecord(id="REQ-001", kind="requirement", label="fixture")) + + result = _run(["save", "--project-dir", str(tmp_path), "--no-push", "--json"]) + assert result.exit_code == 0, result.output + + committed = set(git("show", "--format=", "--name-only", "HEAD").splitlines()) + forbidden = {".specsmith/esdb.sqlite3", *generated_paths} + assert committed.isdisjoint(forbidden) + for relative_path in forbidden: + ignored = subprocess.run( + ["git", "check-ignore", "--quiet", "--", relative_path], + cwd=tmp_path, + check=False, + ) + assert ignored.returncode == 0, relative_path + + def test_should_auto_migrate_true_when_store_empty(tmp_path: Path) -> None: state = tmp_path / ".specsmith" state.mkdir() diff --git a/tests/test_improvement_tracker.py b/tests/test_improvement_tracker.py new file mode 100644 index 00000000..64543573 --- /dev/null +++ b/tests/test_improvement_tracker.py @@ -0,0 +1,242 @@ +# SPDX-License-Identifier: MIT +"""Tests for the improvement tracking functionality.""" + +import json +import logging +import tempfile +from pathlib import Path + +from specsmith.improvement_tracker import ImprovementRecord, ImprovementTracker, SessionAnalysis + + +def test_improvement_record_serialization(): + """Test that ImprovementRecord can be properly serialized and deserialized.""" + record = ImprovementRecord( + timestamp="2026-01-01T00:00:00Z", + type="bug", + description="Fix memory leak in cleanup module", + severity="high", + status="pending", + metrics={"lines_fixed": 15, "test_coverage": 0.95}, + ) + + # Test serialization + data = record.model_dump() + assert data["timestamp"] == "2026-01-01T00:00:00Z" + assert data["type"] == "bug" + assert data["description"] == "Fix memory leak in cleanup module" + assert data["severity"] == "high" + assert data["status"] == "pending" + assert data["metrics"]["lines_fixed"] == 15 + assert data["metrics"]["test_coverage"] == 0.95 + + +def test_session_analysis_serialization(): + """Test that SessionAnalysis can be properly serialized and deserialized.""" + analysis = SessionAnalysis( + session_id="test-session-123", + start_time="2026-01-01T00:00:00Z", + end_time="2026-01-01T01:00:00Z", + duration_seconds=3600, + work_items_completed=["WI-ABC123", "WI-DEF456"], + cost_per_correct_solution=0.05, + efficiency_metrics={"code_quality": 0.85, "speed": 0.92}, + improvements=[ + ImprovementRecord( + timestamp="2026-01-01T00:30:00Z", + type="efficiency", + description="Optimize database queries", + severity="medium", + status="implemented", + ) + ], + session_notes="Session completed successfully with no major issues", + ) + + # Test serialization + data = analysis.model_dump() + assert data["session_id"] == "test-session-123" + assert data["start_time"] == "2026-01-01T00:00:00Z" + assert data["end_time"] == "2026-01-01T01:00:00Z" + assert data["duration_seconds"] == 3600 + assert data["work_items_completed"] == ["WI-ABC123", "WI-DEF456"] + assert data["cost_per_correct_solution"] == 0.05 + assert data["efficiency_metrics"]["code_quality"] == 0.85 + assert data["efficiency_metrics"]["speed"] == 0.92 + assert len(data["improvements"]) == 1 + assert data["improvements"][0]["description"] == "Optimize database queries" + + +def test_improvement_tracker_initialization(): + """Test that ImprovementTracker initializes correctly.""" + with tempfile.TemporaryDirectory() as tmp_dir, ImprovementTracker(Path(tmp_dir)) as tracker: + # Check that improvements directory was created + assert (Path(tmp_dir) / ".specsmith" / "improvements").exists() + + # Check that logger is set up + assert tracker.logger is not None + + +def test_invalid_development_config_defaults_to_disabled(tmp_path: Path, caplog) -> None: + config_dir = tmp_path / ".specsmith" + config_dir.mkdir() + (config_dir / "config.yml").write_text("enable_development_mode: [", encoding="utf-8") + + with caplog.at_level(logging.WARNING), ImprovementTracker(tmp_path) as tracker: + assert tracker.logger.level == logging.INFO + + assert "Could not read development-mode config" in caplog.text + + +def test_recent_improvements_skips_invalid_record(tmp_path: Path, caplog) -> None: + with ImprovementTracker(tmp_path) as tracker: + (tracker.improvements_dir / "improvement_invalid.json").write_text("{", encoding="utf-8") + + with caplog.at_level(logging.WARNING): + assert tracker.get_recent_improvements() == [] + + assert "Skipping unreadable improvement record" in caplog.text + + +def test_record_session_analysis(): + """Test recording session analysis.""" + with tempfile.TemporaryDirectory() as tmp_dir, ImprovementTracker(Path(tmp_dir)) as tracker: + analysis = SessionAnalysis( + session_id="test-session-123", + start_time="2026-01-01T00:00:00Z", + end_time="2026-01-01T01:00:00Z", + duration_seconds=3600, + work_items_completed=["WI-ABC123"], + cost_per_correct_solution=0.05, + efficiency_metrics={"code_quality": 0.85}, + improvements=[], + session_notes="Test session", + ) + + tracker.record_session_analysis(analysis) + + # Check that file was created + session_file = ( + Path(tmp_dir) / ".specsmith" / "improvements" / "session_test-session-123.json" + ) + assert session_file.exists() + + # Check file content + with open(session_file) as f: + data = json.load(f) + assert data["session_id"] == "test-session-123" + assert data["duration_seconds"] == 3600 + + +def test_record_improvement(): + """Test recording an improvement.""" + with tempfile.TemporaryDirectory() as tmp_dir, ImprovementTracker(Path(tmp_dir)) as tracker: + improvement = ImprovementRecord( + timestamp="2026-01-01T00:00:00Z", + type="bug", + description="Fix memory leak in cleanup module", + severity="high", + status="pending", + ) + + tracker.record_improvement(improvement) + + # Check that file was created (with sanitized timestamp for Windows compatibility) + improvement_file = ( + Path(tmp_dir) / ".specsmith" / "improvements" / "improvement_2026-01-01T00-00-00Z.json" + ) + assert improvement_file.exists() + + # Check file content + with open(improvement_file) as f: + data = json.load(f) + assert data["description"] == "Fix memory leak in cleanup module" + assert data["severity"] == "high" + + +def test_get_session_analysis(): + """Test retrieving session analysis.""" + with tempfile.TemporaryDirectory() as tmp_dir, ImprovementTracker(Path(tmp_dir)) as tracker: + analysis = SessionAnalysis( + session_id="test-session-123", + start_time="2026-01-01T00:00:00Z", + end_time="2026-01-01T01:00:00Z", + duration_seconds=3600, + work_items_completed=["WI-ABC123"], + cost_per_correct_solution=0.05, + efficiency_metrics={"code_quality": 0.85}, + improvements=[], + session_notes="Test session", + ) + + tracker.record_session_analysis(analysis) + + # Retrieve the analysis + retrieved = tracker.get_session_analysis("test-session-123") + assert retrieved is not None + assert retrieved.session_id == "test-session-123" + assert retrieved.duration_seconds == 3600 + + +def test_get_recent_improvements(): + """Test retrieving recent improvements.""" + with tempfile.TemporaryDirectory() as tmp_dir, ImprovementTracker(Path(tmp_dir)) as tracker: + # Record two improvements + improvement1 = ImprovementRecord( + timestamp="2026-01-01T00:00:00Z", + type="bug", + description="Fix memory leak in cleanup module", + severity="high", + status="pending", + ) + + improvement2 = ImprovementRecord( + timestamp="2026-01-01T01:00:00Z", + type="efficiency", + description="Optimize database queries", + severity="medium", + status="implemented", + ) + + tracker.record_improvement(improvement1) + tracker.record_improvement(improvement2) + + # Retrieve recent improvements + recent = tracker.get_recent_improvements(5) + assert len(recent) == 2 + assert recent[0].description == "Optimize database queries" # Newest first + assert recent[1].description == "Fix memory leak in cleanup module" + + +def test_generate_session_report(): + """Test generating a session report.""" + with tempfile.TemporaryDirectory() as tmp_dir, ImprovementTracker(Path(tmp_dir)) as tracker: + analysis = SessionAnalysis( + session_id="test-session-123", + start_time="2026-01-01T00:00:00Z", + end_time="2026-01-01T01:00:00Z", + duration_seconds=3600, + work_items_completed=["WI-ABC123", "WI-DEF456"], + cost_per_correct_solution=0.05, + efficiency_metrics={"code_quality": 0.85, "speed": 0.92}, + improvements=[ + ImprovementRecord( + timestamp="2026-01-01T00:30:00Z", + type="efficiency", + description="Optimize database queries", + severity="medium", + status="implemented", + ) + ], + session_notes="Test session with improvements", + ) + + tracker.record_session_analysis(analysis) + + # Generate report + report = tracker.generate_session_report("test-session-123") + assert "Session Report: test-session-123" in report + assert "Duration: 3600 seconds" in report + assert "Work Items Completed: 2" in report + assert "Cost per Correct Solution: 0.05" in report + assert "Optimize database queries" in report diff --git a/tests/test_migrations_skill_shell.py b/tests/test_migrations_skill_shell.py new file mode 100644 index 00000000..22a2b40d --- /dev/null +++ b/tests/test_migrations_skill_shell.py @@ -0,0 +1,58 @@ +# SPDX-License-Identifier: MIT +# Copyright (c) 2026 Layer1Labs Silicon, Inc. All rights reserved. +"""Regression tests for the Windows-safe generated-skill migration.""" + +from pathlib import Path + +from specsmith.migrations.m011_windows_skill_shell import ( + _LEGACY_COMMAND, + _SAFE_COMMAND, + WindowsSkillShellMigration, +) +from specsmith.migrations.m012_normalize_skill_shell import ( + _PREVIOUS_SAFE_COMMAND, + NormalizeSkillShellMigration, +) + + +def test_migration_rewrites_materialized_skill_command(tmp_path: Path) -> None: + skill_path = tmp_path / ".agents" / "skills" / "warp-integration" / "SKILL.md" + skill_path.parent.mkdir(parents=True) + skill_path.write_text(f"# Warp\n{_LEGACY_COMMAND}\n", encoding="utf-8") + + result = WindowsSkillShellMigration().run(tmp_path) + + assert result.success + assert result.files_modified == [".agents/skills/warp-integration/SKILL.md"] + content = skill_path.read_text(encoding="utf-8") + assert _LEGACY_COMMAND not in content + assert _SAFE_COMMAND in content + + +def test_migration_dry_run_and_repeat_are_safe(tmp_path: Path) -> None: + skill_path = tmp_path / ".agents" / "skills" / "cursor-integration" / "SKILL.md" + skill_path.parent.mkdir(parents=True) + skill_path.write_text(_LEGACY_COMMAND, encoding="utf-8") + migration = WindowsSkillShellMigration() + + dry_run = migration.run(tmp_path, dry_run=True) + + assert dry_run.files_modified == [".agents/skills/cursor-integration/SKILL.md"] + assert skill_path.read_text(encoding="utf-8") == _LEGACY_COMMAND + + migration.run(tmp_path) + repeated = migration.run(tmp_path) + + assert repeated.success + assert repeated.files_modified == [] + + +def test_normalization_migration_rewrites_prior_safe_command(tmp_path: Path) -> None: + skill_path = tmp_path / ".agents" / "skills" / "aider-integration" / "SKILL.md" + skill_path.parent.mkdir(parents=True) + skill_path.write_text(_PREVIOUS_SAFE_COMMAND, encoding="utf-8") + + result = NormalizeSkillShellMigration().run(tmp_path) + + assert result.files_modified == [".agents/skills/aider-integration/SKILL.md"] + assert skill_path.read_text(encoding="utf-8") == _SAFE_COMMAND diff --git a/tests/test_model_registry.py b/tests/test_model_registry.py new file mode 100644 index 00000000..2ca1c1c4 --- /dev/null +++ b/tests/test_model_registry.py @@ -0,0 +1,260 @@ +""" +Tests for the model registry functionality. +""" + +from specsmith.model_optimizer import get_model_recommendations, optimize_for_model +from specsmith.model_registry import MODEL_REGISTRY, ModelProfile, get_model_profile, list_models + + +def test_model_registry_exists(): + """Test that the model registry exists and has entries.""" + assert MODEL_REGISTRY is not None + assert len(MODEL_REGISTRY) > 0 + + +def test_qwen_model_profile(): + """Test that the Qwen model profile is correctly defined.""" + profile = get_model_profile("Qwen3.6-35B-A3B") + assert profile is not None + assert profile.name == "Qwen3.6-35B-A3B" + assert profile.provider == "Qwen" + assert profile.context_length == 128000 + assert profile.cost_per_million_input_tokens == 0.01 + assert profile.cost_per_million_output_tokens == 0.03 + assert profile.recommended_runtime == "vLLM" + assert profile.recommended_temperature == 0.7 + assert "large" in profile.tags + assert "reasoning" in profile.tags + assert profile.supports_function_calling is True + assert profile.supports_json_output is True + assert profile.supports_tools is True + + +def test_llama70b_model_profile(): + """Test that the Llama 3 70B model profile is correctly defined.""" + profile = get_model_profile("meta-llama/Meta-Llama-3-70B") + assert profile is not None + assert profile.name == "meta-llama/Meta-Llama-3-70B" + assert profile.provider == "Hugging Face" + assert profile.context_length == 8192 + assert profile.cost_per_million_input_tokens == 0.0 + assert profile.cost_per_million_output_tokens == 0.0 + assert profile.recommended_runtime == "vLLM" + assert profile.recommended_temperature == 0.7 + assert "large" in profile.tags + assert profile.supports_function_calling is True + assert profile.supports_json_output is True + assert profile.supports_tools is True + + +def test_llama8b_model_profile(): + """Test that the Llama 3 8B model profile is correctly defined.""" + profile = get_model_profile("meta-llama/Meta-Llama-3-8B") + assert profile is not None + assert profile.name == "meta-llama/Meta-Llama-3-8B" + assert profile.provider == "Hugging Face" + assert profile.context_length == 8192 + assert profile.cost_per_million_input_tokens == 0.0 + assert profile.cost_per_million_output_tokens == 0.0 + assert profile.recommended_runtime == "vLLM" + assert profile.recommended_temperature == 0.7 + assert "medium" in profile.tags + assert profile.supports_function_calling is True + assert profile.supports_json_output is True + assert profile.supports_tools is True + + +def test_mistral_model_profile(): + """Test that the Mistral model profile is correctly defined.""" + profile = get_model_profile("mistralai/Mistral-7B-v0.3") + assert profile is not None + assert profile.name == "mistralai/Mistral-7B-v0.3" + assert profile.provider == "Hugging Face" + assert profile.context_length == 32768 + assert profile.cost_per_million_input_tokens == 0.0 + assert profile.cost_per_million_output_tokens == 0.0 + assert profile.recommended_runtime == "vLLM" + assert profile.recommended_temperature == 0.7 + assert "medium" in profile.tags + assert profile.supports_function_calling is True + assert profile.supports_json_output is True + assert profile.supports_tools is True + + +def test_gemma_model_profile(): + """Test that the Gemma model profile is correctly defined.""" + profile = get_model_profile("google/gemma-2-27b") + assert profile is not None + assert profile.name == "google/gemma-2-27b" + assert profile.provider == "Hugging Face" + assert profile.context_length == 8192 + assert profile.cost_per_million_input_tokens == 0.0 + assert profile.cost_per_million_output_tokens == 0.0 + assert profile.recommended_runtime == "vLLM" + assert profile.recommended_temperature == 0.7 + assert "large" in profile.tags + assert profile.supports_function_calling is True + assert profile.supports_json_output is True + assert profile.supports_tools is True + + +def test_phi3_model_profile(): + """Test that the Phi-3 model profile is correctly defined.""" + profile = get_model_profile("microsoft/Phi-3-medium-128k") + assert profile is not None + assert profile.name == "microsoft/Phi-3-medium-128k" + assert profile.provider == "Hugging Face" + assert profile.context_length == 128000 + assert profile.cost_per_million_input_tokens == 0.0 + assert profile.cost_per_million_output_tokens == 0.0 + assert profile.recommended_runtime == "vLLM" + assert profile.recommended_temperature == 0.7 + assert "medium" in profile.tags + assert profile.supports_function_calling is True + assert profile.supports_json_output is True + assert profile.supports_tools is True + + +def test_list_models(): + """Test that we can list all available models.""" + models = list_models() + assert len(models) > 0 + assert "Qwen3.6-35B-A3B" in models + assert "meta-llama/Meta-Llama-3-70B" in models + assert "meta-llama/Meta-Llama-3-8B" in models + assert "mistralai/Mistral-7B-v0.3" in models + assert "google/gemma-2-27b" in models + assert "microsoft/Phi-3-medium-128k" in models + # Test new models + assert "meta-llama/Llama-3.2-1B" in models + assert "meta-llama/Llama-3.2-3B" in models + assert "meta-llama/Llama-3.1-8B" in models + assert "meta-llama/Llama-3.1-70B" in models + assert "mistralai/Mistral-7B-Instruct-v0.3" in models + assert "mistralai/Mistral-8x7B-v0.3" in models + assert "google/gemma-2-9b" in models + assert "google/gemma-2-27b" in models + assert "microsoft/Phi-3-mini-128k" in models + assert "microsoft/Phi-3-small-128k" in models + assert "Qwen/Qwen3-7B" in models + assert "Qwen/Qwen3-32B" in models + assert "openai/gpt-4" in models + assert "openai/gpt-4-turbo" in models + assert "openai/gpt-3.5-turbo" in models + assert "anthropic/claude-3-opus" in models + assert "anthropic/claude-3-sonnet" in models + assert "anthropic/claude-3-haiku" in models + assert "google/gemini-pro" in models + assert "google/gemini-1.5-pro" in models + assert "google/gemini-1.5-flash" in models + assert "meta-llama/Llama-3.3-70B" in models + assert "meta-llama/Llama-3.3-8B" in models + assert "mistralai/Mistral-Large" in models + assert "google/gemma-2-9b-it" in models + assert "microsoft/Phi-3.5-mini" in models + assert "microsoft/Phi-3.5-small" in models + assert "Qwen/Qwen3-72B" in models + assert "meta-llama/Llama-3.2-1B-Instruct" in models + assert "meta-llama/Llama-3.2-3B-Instruct" in models + assert "meta-llama/Llama-3.1-8B-Instruct" in models + assert "mistralai/Mistral-7B-v0.3-Instruct" in models + assert "google/gemma-2-27b-it" in models + assert "microsoft/Phi-3.5-medium-128k" in models + assert "meta-llama/Llama-3.3-70B-Instruct" in models + assert "meta-llama/Llama-3.3-8B-Instruct" in models + assert "Qwen/Qwen3-7B-Instruct" in models + assert "Qwen/Qwen3-32B-Instruct" in models + assert "Qwen/Qwen3-72B-Instruct" in models + + +def test_optimize_for_model(): + """Test model optimization functionality.""" + # Test with Qwen model + params = optimize_for_model("Qwen3.6-35B-A3B", "general") + assert "temperature" in params + assert params["temperature"] == 0.7 + + # Test with coding task + params = optimize_for_model("Qwen3.6-35B-A3B", "coding") + assert "temperature" in params + # Should be lower for coding tasks + assert params["temperature"] <= 0.3 + + # Test with unknown model + params = optimize_for_model("unknown-model", "general") + assert "temperature" in params + # Should default to 0.7 + assert params["temperature"] == 0.7 + + +def test_get_model_recommendations(): + """Test skill recommendations based on model.""" + # Test with Qwen model + recommendations = get_model_recommendations("Qwen3.6-35B-A3B", "coding") + # Should recommend function calling and other relevant skills + assert "function-caller" in recommendations or len(recommendations) > 0 + + # Test with unknown model + recommendations = get_model_recommendations("unknown-model", "general") + assert isinstance(recommendations, list) + + +def test_model_profile_dataclass(): + """Test that ModelProfile dataclass works correctly.""" + profile = ModelProfile( + name="Test Model", + provider="Test Provider", + context_length=1000, + cost_per_million_input_tokens=0.1, + cost_per_million_output_tokens=0.2, + recommended_runtime="test", + recommended_temperature=0.5, + tags=["test", "model"], + description="A test model profile", + ) + + assert profile.name == "Test Model" + assert profile.provider == "Test Provider" + assert profile.context_length == 1000 + assert profile.cost_per_million_input_tokens == 0.1 + assert profile.cost_per_million_output_tokens == 0.2 + assert profile.recommended_runtime == "test" + assert profile.recommended_temperature == 0.5 + assert profile.tags == ["test", "model"] + assert profile.description == "A test model profile" + + +# Test a few new models to ensure they're properly defined +def test_llama_3_2_1b_model_profile(): + """Test that the Llama 3.2 1B model profile is correctly defined.""" + profile = get_model_profile("meta-llama/Llama-3.2-1B") + assert profile is not None + assert profile.name == "meta-llama/Llama-3.2-1B" + assert profile.provider == "Hugging Face" + assert profile.context_length == 8192 + assert profile.cost_per_million_input_tokens == 0.0 + assert profile.cost_per_million_output_tokens == 0.0 + assert profile.recommended_runtime == "vLLM" + assert profile.recommended_temperature == 0.7 + assert "small" in profile.tags + assert "fast" in profile.tags + assert profile.supports_function_calling is True + assert profile.supports_json_output is True + assert profile.supports_tools is True + + +def test_gpt4_model_profile(): + """Test that the GPT-4 model profile is correctly defined.""" + profile = get_model_profile("openai/gpt-4") + assert profile is not None + assert profile.name == "openai/gpt-4" + assert profile.provider == "OpenAI" + assert profile.context_length == 128000 + assert profile.cost_per_million_input_tokens == 30.0 + assert profile.cost_per_million_output_tokens == 60.0 + assert profile.recommended_runtime == "OpenAI API" + assert profile.recommended_temperature == 0.7 + assert "large" in profile.tags + assert profile.supports_function_calling is True + assert profile.supports_json_output is True + assert profile.supports_tools is True diff --git a/tests/test_release_guard.py b/tests/test_release_guard.py new file mode 100644 index 00000000..a224fa2e --- /dev/null +++ b/tests/test_release_guard.py @@ -0,0 +1,41 @@ +from __future__ import annotations + +import pytest + +from specsmith.release_guard import ( + is_development_version, + is_stable_version, + require_development_version, + require_stable_version, +) + + +@pytest.mark.parametrize("version", ["0.21.0.dev1", "0.21.0a1", "0.21.0rc1", "0.21.0+local"]) +def test_non_final_versions_are_rejected(version: str) -> None: + assert not is_stable_version(version) + with pytest.raises(ValueError, match="non-final"): + require_stable_version(version) + + +def test_final_version_is_accepted() -> None: + assert is_stable_version("0.21.0") + require_stable_version("0.21.0") + + +def test_stable_version_must_match_release_tag() -> None: + require_stable_version("0.21.0", "v0.21.0") + with pytest.raises(ValueError, match="does not match tag"): + require_stable_version("0.21.0", "v0.21.1") + + +@pytest.mark.parametrize("version", ["0.21.1.dev0", "0.21.1.dev42"]) +def test_explicit_development_versions_are_accepted(version: str) -> None: + assert is_development_version(version) + require_development_version(version, version) + + +@pytest.mark.parametrize("version", ["0.21.1", "0.21.1rc1", "0.21.1+local"]) +def test_non_development_versions_are_rejected_from_dev_channel(version: str) -> None: + assert not is_development_version(version) + with pytest.raises(ValueError, match="requires an X.Y.Z.devN"): + require_development_version(version) diff --git a/tests/test_scaffolder.py b/tests/test_scaffolder.py index f138e44e..1e304b24 100644 --- a/tests/test_scaffolder.py +++ b/tests/test_scaffolder.py @@ -93,9 +93,11 @@ def test_gitignore_tracks_canonical_esdb_files(self, tmp_target: Path) -> None: assert ".chronomemory/backup/" in content assert ".specsmith/workitems.json" in content assert ".specsmith/esdb_migration_manifest.json" in content - assert "!.specsmith/esdb.sqlite3" in content + assert ".specsmith/esdb.sqlite3" in content + assert "!.specsmith/esdb.sqlite3" not in content assert "!.chronomemory/events.wal" in content assert "!.chronomemory/snapshot.json" in content + assert "!.chronomemory/session-events.jsonl" in content assert "\n.specsmith/\n" not in content assert "\n.chronomemory/\n" not in content diff --git a/tests/test_session_events.py b/tests/test_session_events.py new file mode 100644 index 00000000..34eed475 --- /dev/null +++ b/tests/test_session_events.py @@ -0,0 +1,53 @@ +from __future__ import annotations + +import json +from pathlib import Path + +import pytest + +from specsmith.session_store import ( + _load_events, + load_session, + merge_session_events, + rebuild_local_session_index, + save_session, +) + + +def test_divergent_session_events_merge_and_recover(tmp_path: Path) -> None: + left = { + "schema_version": 1, + "event_id": "SESSION-LEFT", + "saved_at": "2026-01-01T00:00:00Z", + "context": {"id": "left"}, + "history": [], + } + right = { + "schema_version": 1, + "event_id": "SESSION-RIGHT", + "saved_at": "2026-01-02T00:00:00Z", + "context": {"id": "right"}, + "history": [], + } + merged = merge_session_events([right], [left], [right]) + assert [event["event_id"] for event in merged] == ["SESSION-LEFT", "SESSION-RIGHT"] + + event_path = tmp_path / ".chronomemory" / "session-events.jsonl" + event_path.parent.mkdir() + event_path.write_text("\n".join(json.dumps(event) for event in merged), encoding="utf-8") + context, history = load_session(tmp_path) + assert context == {"id": "right"} + assert history == [] + + +def test_conflicting_event_id_is_rejected() -> None: + first = {"event_id": "SESSION-SAME", "saved_at": "1"} + second = {"event_id": "SESSION-SAME", "saved_at": "2"} + with pytest.raises(ValueError, match="conflicting"): + merge_session_events([first], [second]) + + +def test_rebuild_local_index_from_canonical_events(tmp_path: Path) -> None: + save_session(tmp_path, {"session_id": "one"}, [{"role": "user", "content": "hello"}]) + assert len(_load_events(tmp_path / ".chronomemory" / "session-events.jsonl")) == 1 + assert rebuild_local_session_index(tmp_path) == 1 diff --git a/tests/test_updater.py b/tests/test_updater.py new file mode 100644 index 00000000..09b72921 --- /dev/null +++ b/tests/test_updater.py @@ -0,0 +1,16 @@ +"""Regression coverage for reachable version-mismatch remediation.""" + +from __future__ import annotations + +import pytest + +from specsmith.updater import version_mismatch_remediation + + +@pytest.mark.parametrize("version", ["0.22.0.dev1", "0.22.0rc1", "0.22.0+local"]) +def test_version_mismatch_reports_exact_pipx_install_for_nonstable_project(version: str) -> None: + assert version_mismatch_remediation(version) == f"pipx install --force specsmith=={version}" + + +def test_version_mismatch_keeps_normal_upgrade_for_stable_project() -> None: + assert version_mismatch_remediation("0.22.0") == "pipx upgrade specsmith" diff --git a/tests/test_warp_parity_followup.py b/tests/test_warp_parity_followup.py index ede68f91..000f42f9 100644 --- a/tests/test_warp_parity_followup.py +++ b/tests/test_warp_parity_followup.py @@ -11,7 +11,10 @@ from __future__ import annotations import json +import os import socket +import subprocess +import sys import threading import time import urllib.error @@ -192,6 +195,7 @@ def test_voice_cli_status_with_stub(monkeypatch: pytest.MonkeyPatch) -> None: _FIXTURE = Path(__file__).parent / "fixtures" / "api_surface.json" +_PROJECT_ROOT = Path(__file__).parents[1] def test_api_surface_fixture_exists() -> None: @@ -212,10 +216,30 @@ def test_api_surface_matches_fixture() -> None: expected = json.loads(_FIXTURE.read_text(encoding="utf-8")) assert actual == expected, ( "API surface drifted. Regenerate the snapshot if intentional:\n" - " py -m specsmith.cli api-surface > tests/fixtures/api_surface.json" + " py -m specsmith api-surface > tests/fixtures/api_surface.json" ) +def test_package_module_api_surface_matches_fixture() -> None: + """The package entry point must expose the fully registered CLI surface.""" + env = os.environ | { + "SPECSMITH_ALLOW_NON_PIPX": "1", + "SPECSMITH_NO_AUTO_UPDATE": "1", + "SPECSMITH_PYPI_CHECKED": "1", + } + result = subprocess.run( + [sys.executable, "-m", "specsmith", "api-surface"], + cwd=str(_PROJECT_ROOT), + capture_output=True, + check=False, + encoding="utf-8", + env=env, + ) + + assert result.returncode == 0, result.stderr + assert json.loads(result.stdout) == json.loads(_FIXTURE.read_text(encoding="utf-8")) + + def test_api_surface_contains_required_1_0_commands() -> None: """Spot-check that the 1.0 contract commands are still in the surface.""" runner = CliRunner() diff --git a/tests/test_wi_lifecycle.py b/tests/test_wi_lifecycle.py index 4957aca7..b19971bd 100644 --- a/tests/test_wi_lifecycle.py +++ b/tests/test_wi_lifecycle.py @@ -15,6 +15,7 @@ from __future__ import annotations import json +import os from pathlib import Path import pytest @@ -116,6 +117,19 @@ def test_archived_can_reopen(self) -> None: class TestWorkItemStorePersistence: + def test_rejects_workitem_path_outside_project_root(self, tmp_path: Path, monkeypatch) -> None: + """Persistence paths must remain under the caller's project root (REQ-451).""" + original_realpath = os.path.realpath + + def escape_state(path: str) -> str: + if path.endswith(".specsmith"): + return original_realpath(str(tmp_path.parent / "outside")) + return original_realpath(path) + + monkeypatch.setattr(os.path, "realpath", escape_state) + with pytest.raises(WorkItemError, match="escapes project root"): + WorkItemStore(tmp_path) + def test_load_missing_file_returns_empty(self, tmp_path: Path) -> None: store = _store(tmp_path) assert store.load() == [] diff --git a/tests/test_windows_launcher.py b/tests/test_windows_launcher.py new file mode 100644 index 00000000..fbea335a --- /dev/null +++ b/tests/test_windows_launcher.py @@ -0,0 +1,40 @@ +from __future__ import annotations + +import json + +from click.testing import CliRunner + +from specsmith.cli import main +from specsmith.updater import find_windows_launchers + + +def test_find_windows_launchers_detects_path_shadowing(tmp_path) -> None: + pipx = tmp_path / "pipx" + scripts = tmp_path / "scripts" + pipx.mkdir() + scripts.mkdir() + (pipx / "specsmith.exe").touch() + (scripts / "specsmith.exe").touch() + + launchers = find_windows_launchers(f"{pipx};{scripts}") + + assert launchers == [pipx / "specsmith.exe", scripts / "specsmith.exe"] + + +def test_doctor_warns_about_windows_launcher_shadowing(tmp_path, monkeypatch) -> None: + launchers = [tmp_path / "pipx" / "specsmith.exe", tmp_path / "scripts" / "specsmith.exe"] + monkeypatch.setattr("specsmith.cli._is_windows_platform", lambda: True) + monkeypatch.setattr("specsmith.updater.find_windows_launchers", lambda _: launchers) + + result = CliRunner().invoke(main, ["doctor", "--project-dir", str(tmp_path), "--json"]) + + assert result.exit_code == 0, result.output + payload = json.loads(result.output) + launcher_check = next( + check for check in payload["checks"] if check["name"] == "specsmith launchers" + ) + assert launcher_check == { + "name": "specsmith launchers", + "status": "warn", + "detail": "2 found; use pipx only", + }