From 237d295a88209bf7f4f2b0811d00da515f7eacd4 Mon Sep 17 00:00:00 2001 From: Jeff Williams Date: Sun, 22 Mar 2026 09:29:37 -0400 Subject: [PATCH 01/15] docs(speckit): write spec for spec-kit workflow update (#31) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Fill spec.md with 6 user stories (P1–P3) covering GitHub issue linkage, per-phase commits, status lifecycle enforcement, stack-aware agents, issues backlog memory file, and constitution auto-update - Add FR-001 through FR-012 with testable acceptance scenarios - Define SC-001 through SC-007 measurable outcomes - Add quality checklist (all items passing) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../checklists/requirements.md | 36 ++++ specs/020-speckit-workflow/spec.md | 167 ++++++++++++++++++ 2 files changed, 203 insertions(+) create mode 100644 specs/020-speckit-workflow/checklists/requirements.md create mode 100644 specs/020-speckit-workflow/spec.md diff --git a/specs/020-speckit-workflow/checklists/requirements.md b/specs/020-speckit-workflow/checklists/requirements.md new file mode 100644 index 0000000..0ebf475 --- /dev/null +++ b/specs/020-speckit-workflow/checklists/requirements.md @@ -0,0 +1,36 @@ +# Specification Quality Checklist: Spec-Kit Workflow Update + +**Purpose**: Validate specification completeness and quality before proceeding to planning +**Created**: 2026-03-22 +**Feature**: [spec.md](../spec.md) + +## Content Quality + +- [x] No implementation details (languages, frameworks, APIs) +- [x] Focused on user value and business needs +- [x] Written for non-technical stakeholders +- [x] All mandatory sections completed + +## Requirement Completeness + +- [x] No [NEEDS CLARIFICATION] markers remain +- [x] Requirements are testable and unambiguous +- [x] Success criteria are measurable +- [x] Success criteria are technology-agnostic (no implementation details) +- [x] All acceptance scenarios are defined +- [x] Edge cases are identified +- [x] Scope is clearly bounded +- [x] Dependencies and assumptions identified + +## Feature Readiness + +- [x] All functional requirements have clear acceptance criteria +- [x] User scenarios cover primary flows +- [x] Feature meets measurable outcomes defined in Success Criteria +- [x] No implementation details leak into specification + +## Notes + +- All items pass. Spec is ready for `/speckit.clarify` or `/speckit.plan`. +- Stack-aware agent behavior (FR-007/FR-008) is scoped to prompting and storage; the specific memory file format is left to planning. +- "Paradigm shift" detection (FR-010) is intentionally heuristic — the spec documents this as an assumption rather than a precise trigger definition. diff --git a/specs/020-speckit-workflow/spec.md b/specs/020-speckit-workflow/spec.md new file mode 100644 index 0000000..1d52874 --- /dev/null +++ b/specs/020-speckit-workflow/spec.md @@ -0,0 +1,167 @@ +# Feature Specification: Spec-Kit Workflow Update + +**Feature Branch**: `020-speckit-workflow` +**Created**: 2026-03-22 +**Status**: Draft +**GitHub Issue**: [#31](https://github.com/jwill824/ordrctrl/issues/31) +**Input**: Update our spec-kit workflow to integrate with GitHub, enforce constitution hygiene, add stack-awareness to agents/skills, and improve commit/PR automation across all speckit phases. + + + +## User Scenarios & Testing *(mandatory)* + +### User Story 1 - GitHub Issue Linkage During Specify (Priority: P1) + +A developer runs `/speckit.specify` and the workflow automatically verifies GitHub MCP connectivity, retrieves relevant open issues, and links the new feature branch to the corresponding issue. The spec file records the issue number. When the feature is eventually implemented, the PR is automatically created and linked to that issue. + +**Why this priority**: Issue traceability is foundational — every subsequent phase (plan, tasks, implement) benefits from knowing which issue a spec addresses. Without this, PRs and specs are disconnected from the backlog. + +**Independent Test**: Run `/speckit.specify` on a new feature description while a matching open GitHub issue exists. Verify the generated spec.md contains a GitHub Issue link and that the branch name is associated with the issue in GitHub. + +**Acceptance Scenarios**: + +1. **Given** GitHub MCP is configured and reachable, **When** `/speckit.specify` runs, **Then** the spec file includes a `GitHub Issue` field populated with the relevant issue number and URL. +2. **Given** GitHub MCP is not reachable, **When** `/speckit.specify` runs, **Then** the workflow surfaces a clear warning and continues without blocking spec creation. +3. **Given** a spec branch is created, **When** `/speckit.implement` completes all tasks, **Then** a PR is automatically opened with the relevant GitHub issue(s) attached. + +--- + +### User Story 2 - Per-Phase Commits (Priority: P2) + +A developer progresses through speckit phases (`/speckit.specify`, `/speckit.plan`, `/speckit.tasks`, `/speckit.implement`). At the end of each phase, the workflow automatically commits all relevant artifact changes (spec.md, plan.md, tasks.md, checklists) to the feature branch with a conventional commit message. + +**Why this priority**: Without automatic commits per phase, artifact history is lost and it's unclear what state the spec was in at each decision point. It also prevents accidental loss of work. + +**Independent Test**: Run `/speckit.plan` on a feature with a complete spec. Verify that a commit appears on the branch containing plan.md and any updated artifacts, with a message following Conventional Commits format. + +**Acceptance Scenarios**: + +1. **Given** `/speckit.specify` completes successfully, **When** the phase ends, **Then** a commit is made on the feature branch containing the spec.md and checklist files. +2. **Given** `/speckit.plan` completes, **When** the phase ends, **Then** a commit is made containing plan.md and any updated spec artifacts. +3. **Given** `/speckit.implement` completes all tasks, **When** the phase ends, **Then** a commit is made, the branch is pushed, and a PR is created referencing the GitHub issue. + +--- + +### User Story 3 - Spec Status Lifecycle Enforcement (Priority: P2) + +A developer completes the `/speckit.implement` phase. The workflow automatically updates the `Status` field in spec.md from `In Progress` to `Implemented`. After `/speckit.analyze` confirms cross-artifact consistency, the status advances to `Analyzed`. + +**Why this priority**: Stale or incorrect status fields cause confusion about which specs are ready to plan, implement, or review. Automating status updates removes a manual step that is frequently forgotten. + +**Independent Test**: Run `/speckit.implement` to completion on a spec with `Status: In Progress`. Verify spec.md is updated to `Status: Implemented` and committed. + +**Acceptance Scenarios**: + +1. **Given** all tasks in tasks.md are marked done, **When** `/speckit.implement` finishes, **Then** spec.md `Status` is updated to `Implemented`. +2. **Given** `/speckit.analyze` reports no consistency issues, **When** the analysis phase ends, **Then** spec.md `Status` is updated to `Analyzed`. +3. **Given** `/speckit.analyze` reports unresolved issues, **When** the analysis phase ends, **Then** spec.md `Status` remains `Implemented` and issues are listed. + +--- + +### User Story 4 - Stack-Aware Agents (Priority: P3) + +A developer runs any speckit command on a new project. The agents/skills detect or prompt for project stack information (packaging tool, linting tool, test library, version constraints, and key conventions) and persist this in the constitution or memory files. Subsequent speckit commands use this stack context to generate accurate tasks, commands, and recommendations without re-asking. + +**Why this priority**: Stack-unaware task generation produces incorrect commands (wrong test runner, wrong package manager). Capturing this once and reusing it improves all future speckit output quality. + +**Independent Test**: Run `/speckit.specify` on a fresh project where stack info is not yet captured. Verify the workflow prompts for packaging tool, test library, and linting tool, then stores the answers. Run `/speckit.tasks` and verify the generated tasks reference the correct tooling. + +**Acceptance Scenarios**: + +1. **Given** no stack info exists in memory, **When** a speckit command runs, **Then** the agent prompts for packaging tool, test library, linting tool, and version constraints. +2. **Given** stack info is already stored, **When** any speckit command runs, **Then** the agent uses the stored info without re-prompting. +3. **Given** stack info changes (e.g., migration from npm to pnpm), **When** the constitution is updated, **Then** subsequent speckit commands reflect the updated stack. + +--- + +### User Story 5 - GitHub Issues Backlog Tracking in Memory (Priority: P3) + +A developer wants to know which GitHub issues are candidates for the next spec. The speckit workflow maintains a memory file (`.specify/memory/`) that lists open GitHub issues not yet associated with a spec, updated automatically during the specify phase. + +**Why this priority**: Without a persistent view of unspecified issues, developers must manually cross-reference GitHub and the specs directory to find the next thing to work on. + +**Independent Test**: After `/speckit.specify` runs and links issue #31, verify the memory file no longer lists #31 as unspecified, and that remaining open issues are still listed. + +**Acceptance Scenarios**: + +1. **Given** open GitHub issues exist with no corresponding spec branch, **When** the memory file is read, **Then** those issues are listed as candidates for the next spec. +2. **Given** `/speckit.specify` completes for an issue, **When** the phase ends, **Then** that issue is removed from the unspecified list in the memory file. +3. **Given** new issues are opened in GitHub, **When** the next speckit command runs, **Then** the memory file is refreshed to include newly opened issues. + +--- + +### User Story 6 - Constitution Auto-Update (Priority: P3) + +A developer introduces a paradigm shift (e.g., new architecture pattern, new tooling decision). The speckit workflow detects that the constitution is out of date and prompts the developer to review and update it. The constitution update is committed and all dependent templates are synchronized. + +**Why this priority**: A stale constitution causes speckit to generate artifacts inconsistent with current project standards. + +**Independent Test**: Manually edit the constitution to mark a section as outdated. Run `/speckit.specify`. Verify the workflow detects the change and prompts for a constitution review before proceeding. + +**Acceptance Scenarios**: + +1. **Given** a significant project change is detected (new dependency, new pattern), **When** any speckit phase starts, **Then** the workflow prompts the developer to confirm the constitution is current. +2. **Given** the constitution is updated, **When** the update is committed, **Then** all dependent templates (spec-template.md, plan-template.md, etc.) are checked for consistency and updated if needed. + +--- + +### Edge Cases + +- What happens when GitHub MCP is unavailable during the specify phase — spec creation must not be blocked. +- What happens when the developer declines to provide stack information — workflow proceeds with defaults and marks stack fields as unset. +- What happens when a spec branch already has a commit for the current phase — duplicate commit must not be created. +- What happens when tasks.md has partially completed tasks when `/speckit.implement` is re-run — already-done tasks are skipped, status is not regressed. +- What happens when two issues could plausibly map to the same spec — the workflow picks the closest match and notes the ambiguity in spec.md. + +## Requirements *(mandatory)* + +### Functional Requirements + +- **FR-001**: The workflow MUST verify GitHub MCP connectivity at the start of the `/speckit.specify` phase and report status to the developer. +- **FR-002**: The workflow MUST retrieve open GitHub issues during `/speckit.specify` and populate the `GitHub Issue` field in spec.md with the best-matched issue. +- **FR-003**: The workflow MUST commit all phase artifacts to the feature branch at the end of each speckit phase using a Conventional Commits message. +- **FR-004**: The workflow MUST update the `Status` field in spec.md to `Implemented` when all tasks in tasks.md are complete. +- **FR-005**: The workflow MUST update the `Status` field in spec.md to `Analyzed` when `/speckit.analyze` confirms consistency with no unresolved issues. +- **FR-006**: The workflow MUST create a GitHub PR and attach relevant issue(s) when `/speckit.implement` completes and pushes the branch. +- **FR-007**: The workflow MUST prompt for stack information (packaging tool, test library, linting tool, version constraints) when none is stored and persist the answers in the constitution or a memory file. +- **FR-008**: The workflow MUST use stored stack information in all task and command generation without re-prompting. +- **FR-009**: The workflow MUST maintain a memory file listing open GitHub issues that do not yet have a corresponding spec branch, refreshed on each specify phase run. +- **FR-010**: The workflow MUST prompt the developer to review the constitution when a paradigm shift is detected, and synchronize dependent templates after an update. +- **FR-011**: The workflow MUST add regression test execution as a step in the `/speckit.implement` phase to verify no existing functionality is broken. +- **FR-012**: The workflow MUST update tasks.md with any additional tasks discovered during implementation and commit the update. + +### Key Entities + +- **Constitution**: The project's authoritative source of standards, patterns, and conventions. Updated when paradigm shifts occur; drives template consistency. +- **Memory File (GitHub Issues)**: A file in `.specify/memory/` that tracks open GitHub issues not yet associated with a spec. Refreshed during the specify phase. +- **Stack Profile**: A persisted record of the project's tooling choices (package manager, test library, linter, version constraints). Stored in the constitution or a dedicated memory file. +- **Phase Commit**: A git commit made at the end of each speckit phase capturing all artifact changes for that phase. +- **Spec Status**: The lifecycle state of a spec (Draft → Planned → Tasked → In Progress → Implemented → Analyzed), automatically advanced by the workflow. + +## Success Criteria *(mandatory)* + +### Measurable Outcomes + +- **SC-001**: 100% of spec.md files produced by `/speckit.specify` include a populated `GitHub Issue` field when a matching open issue exists. +- **SC-002**: 100% of speckit phases that produce artifact changes result in a git commit on the feature branch before the phase ends. +- **SC-003**: spec.md `Status` is automatically advanced to `Implemented` within the same session that `/speckit.implement` completes — no manual update required. +- **SC-004**: Stack information is prompted for at most once per project; subsequent speckit commands across all features use the stored stack profile without re-prompting. +- **SC-005**: The GitHub issues memory file is accurate within one speckit session — issues linked to a spec are removed, and new open issues appear, after each specify phase run. +- **SC-006**: PRs created by the workflow are linked to their corresponding GitHub issue(s) 100% of the time when issue linkage data is available. +- **SC-007**: Regression tests are executed as part of every `/speckit.implement` run; a failing test prevents the phase from being marked complete. + +## Assumptions + +- GitHub MCP server is already configured in the developer's Copilot CLI environment; this feature adds verification and usage, not initial setup. +- The constitution file exists at `.specify/memory/constitution.md` and is the authoritative source for project standards. +- The speckit scripts (`.specify/scripts/`) are bash-based and can be extended to include git commit and push operations. +- "Paradigm shift" detection is heuristic — the workflow prompts for constitution review on significant dependency additions or pattern-level changes rather than detecting it automatically. +- Stack information is project-scoped, not per-feature; it is captured once and shared across all features in the repository. From 9abfc33f5514a79de87b5e9a8200d06d4225a51d Mon Sep 17 00:00:00 2001 From: Jeff Williams Date: Sun, 22 Mar 2026 10:18:01 -0400 Subject: [PATCH 02/15] docs(speckit): fine-tune spec for spec-kit workflow update (#31) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - US1: add multi-issue support per spec and issue-triage guard before specify - US2: extend per-phase commits to all 7 speckit phases; use conventional-commit skill - US4: redesign as stack.md template with auto-detect and manual-entry modes; extensible schema - US7 (new): spec artifact drift detection via git diff from branch creation - FR-001–FR-022: updated/expanded to cover all new requirements - SC-001–SC-010: updated to match new user stories - Key entities: added stack.md, Stack Template, Drift Report - Assumptions: added conventional-commit skill dependency, stack.md versioning, drift scope Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../checklists/requirements.md | 7 +- specs/020-speckit-workflow/spec.md | 146 ++++++++++++------ 2 files changed, 103 insertions(+), 50 deletions(-) diff --git a/specs/020-speckit-workflow/checklists/requirements.md b/specs/020-speckit-workflow/checklists/requirements.md index 0ebf475..87d232e 100644 --- a/specs/020-speckit-workflow/checklists/requirements.md +++ b/specs/020-speckit-workflow/checklists/requirements.md @@ -2,6 +2,7 @@ **Purpose**: Validate specification completeness and quality before proceeding to planning **Created**: 2026-03-22 +**Updated**: 2026-03-22 (v2 — fine-tuning pass) **Feature**: [spec.md](../spec.md) ## Content Quality @@ -32,5 +33,7 @@ ## Notes - All items pass. Spec is ready for `/speckit.clarify` or `/speckit.plan`. -- Stack-aware agent behavior (FR-007/FR-008) is scoped to prompting and storage; the specific memory file format is left to planning. -- "Paradigm shift" detection (FR-010) is intentionally heuristic — the spec documents this as an assumption rather than a precise trigger definition. +- v2 changes: US1 now supports multiple issues + issue-triage guard; US2 now covers all 7 speckit phases and references the conventional-commit skill; US4 redesigned around stack.md template with auto-detect/manual-entry modes; US7 added for spec artifact drift detection. +- The conventional-commit skill reference in FR-004/FR-016 is a workflow-level dependency — its availability should be verified during planning. +- stack.md template versioning (FR-012) is intentionally left to planning/design for field definition; the spec defines the shape of the requirement only. +- Drift detection (FR-019–FR-022) is scoped to tracked spec artifacts; source code semantic analysis is explicitly out of scope (see Assumptions). diff --git a/specs/020-speckit-workflow/spec.md b/specs/020-speckit-workflow/spec.md index 1d52874..911e4c2 100644 --- a/specs/020-speckit-workflow/spec.md +++ b/specs/020-speckit-workflow/spec.md @@ -20,33 +20,39 @@ ### User Story 1 - GitHub Issue Linkage During Specify (Priority: P1) -A developer runs `/speckit.specify` and the workflow automatically verifies GitHub MCP connectivity, retrieves relevant open issues, and links the new feature branch to the corresponding issue. The spec file records the issue number. When the feature is eventually implemented, the PR is automatically created and linked to that issue. +Before a developer runs `/speckit.specify`, the workflow first executes the issue-triage agent to surface open issue candidates, giving the developer a prioritized view of what to specify next. The developer may then confirm one or more issues (e.g., when related issues are consolidated into a single spec) to associate with the new feature. The spec file records all linked issue numbers. When the feature is eventually implemented, the PR is automatically created and linked to every associated issue. -**Why this priority**: Issue traceability is foundational — every subsequent phase (plan, tasks, implement) benefits from knowing which issue a spec addresses. Without this, PRs and specs are disconnected from the backlog. +**Why this priority**: Issue traceability is foundational — every subsequent phase (plan, tasks, implement) benefits from knowing which issue(s) a spec addresses. Consolidating related issues into one spec prevents duplicated work, and the triage guard ensures the developer is always working from a prioritized backlog view rather than guessing. -**Independent Test**: Run `/speckit.specify` on a new feature description while a matching open GitHub issue exists. Verify the generated spec.md contains a GitHub Issue link and that the branch name is associated with the issue in GitHub. +**Independent Test**: Run `/speckit.specify`. Verify the triage report appears first, confirm two related issues as consolidated, and verify spec.md contains a `GitHub Issue` field listing both issue numbers and URLs. Run `/speckit.implement` to completion and verify the PR references both issues. **Acceptance Scenarios**: -1. **Given** GitHub MCP is configured and reachable, **When** `/speckit.specify` runs, **Then** the spec file includes a `GitHub Issue` field populated with the relevant issue number and URL. -2. **Given** GitHub MCP is not reachable, **When** `/speckit.specify` runs, **Then** the workflow surfaces a clear warning and continues without blocking spec creation. -3. **Given** a spec branch is created, **When** `/speckit.implement` completes all tasks, **Then** a PR is automatically opened with the relevant GitHub issue(s) attached. +1. **Given** GitHub MCP is configured and reachable, **When** `/speckit.specify` is invoked, **Then** the issue-triage agent runs first and presents a prioritized list of open issues before spec creation begins. +2. **Given** the triage report is shown, **When** the developer selects multiple issues to consolidate into one spec, **Then** spec.md `GitHub Issue` field lists all selected issue numbers and URLs. +3. **Given** GitHub MCP is not reachable, **When** `/speckit.specify` runs, **Then** the workflow surfaces a clear warning, skips the triage guard, and continues without blocking spec creation. +4. **Given** a spec branch is created with one or more linked issues, **When** `/speckit.implement` completes all tasks, **Then** a PR is automatically opened referencing all linked GitHub issues. --- -### User Story 2 - Per-Phase Commits (Priority: P2) +### User Story 2 - Per-Phase Commits with Conventional Commit Skill (Priority: P2) -A developer progresses through speckit phases (`/speckit.specify`, `/speckit.plan`, `/speckit.tasks`, `/speckit.implement`). At the end of each phase, the workflow automatically commits all relevant artifact changes (spec.md, plan.md, tasks.md, checklists) to the feature branch with a conventional commit message. +A developer progresses through any speckit phase (`/speckit.specify`, `/speckit.clarify`, `/speckit.plan`, `/speckit.tasks`, `/speckit.checklist`, `/speckit.implement`, `/speckit.analyze`). At the end of each phase, the workflow invokes the `conventional-commit` skill to generate a properly structured commit message, then commits all relevant artifact changes (spec.md, plan.md, tasks.md, checklists, memory files) to the feature branch. The constitution is also updated to document that the `conventional-commit` skill is required for all speckit-phase commits. -**Why this priority**: Without automatic commits per phase, artifact history is lost and it's unclear what state the spec was in at each decision point. It also prevents accidental loss of work. +**Why this priority**: Without automatic commits per phase, artifact history is lost and it's unclear what state the spec was in at each decision point. Using the conventional-commit skill ensures commit messages are consistently formatted and carry correct type/scope metadata, which enables changelog generation and traceability. -**Independent Test**: Run `/speckit.plan` on a feature with a complete spec. Verify that a commit appears on the branch containing plan.md and any updated artifacts, with a message following Conventional Commits format. +**Independent Test**: Run `/speckit.plan` on a feature with a complete spec. Verify that a commit appears on the branch containing plan.md and any updated artifacts, with a message conforming to Conventional Commits format (type, scope, description) as produced by the conventional-commit skill. **Acceptance Scenarios**: -1. **Given** `/speckit.specify` completes successfully, **When** the phase ends, **Then** a commit is made on the feature branch containing the spec.md and checklist files. -2. **Given** `/speckit.plan` completes, **When** the phase ends, **Then** a commit is made containing plan.md and any updated spec artifacts. -3. **Given** `/speckit.implement` completes all tasks, **When** the phase ends, **Then** a commit is made, the branch is pushed, and a PR is created referencing the GitHub issue. +1. **Given** `/speckit.specify` completes successfully, **When** the phase ends, **Then** the conventional-commit skill generates a commit message and a commit is made containing spec.md and checklist files. +2. **Given** `/speckit.clarify` updates the spec with resolved answers, **When** the phase ends, **Then** a conventional-commit-formatted commit is made with the updated spec.md. +3. **Given** `/speckit.plan` completes, **When** the phase ends, **Then** a conventional-commit-formatted commit is made containing plan.md and any updated spec artifacts. +4. **Given** `/speckit.tasks` generates tasks.md, **When** the phase ends, **Then** a conventional-commit-formatted commit is made containing tasks.md. +5. **Given** `/speckit.checklist` generates a checklist file, **When** the phase ends, **Then** a conventional-commit-formatted commit is made containing the checklist. +6. **Given** `/speckit.analyze` completes, **When** the phase ends, **Then** a conventional-commit-formatted commit is made with any updated artifacts and the advanced spec status. +7. **Given** `/speckit.implement` completes all tasks, **When** the phase ends, **Then** a conventional-commit-formatted commit is made, the branch is pushed, and a PR is created referencing all linked GitHub issues. +8. **Given** a phase produces no artifact changes, **When** the phase ends, **Then** no commit is created (duplicate empty commits are prevented). --- @@ -66,19 +72,22 @@ A developer completes the `/speckit.implement` phase. The workflow automatically --- -### User Story 4 - Stack-Aware Agents (Priority: P3) +### User Story 4 - Stack-Aware Agents with stack.md Template (Priority: P3) -A developer runs any speckit command on a new project. The agents/skills detect or prompt for project stack information (packaging tool, linting tool, test library, version constraints, and key conventions) and persist this in the constitution or memory files. Subsequent speckit commands use this stack context to generate accurate tasks, commands, and recommendations without re-asking. +A developer runs any speckit command on a new project. The workflow checks for a `stack.md` file in `.specify/memory/`. If absent, it offers two modes: **auto-detect** (the model inspects the repository and infers stack fields from project files) or **manual entry** (the developer fills in a prompted form based on a standard template). Either mode produces a fully populated `stack.md` that is committed to the repo. Subsequent speckit commands read `stack.md` to generate accurate tasks, commands, and recommendations without re-prompting. The `stack.md` template is designed to be extensible — new fields can be added to the template without breaking existing entries. -**Why this priority**: Stack-unaware task generation produces incorrect commands (wrong test runner, wrong package manager). Capturing this once and reusing it improves all future speckit output quality. +**Why this priority**: Stack-unaware task generation produces incorrect commands (wrong test runner, wrong package manager). A template-driven `stack.md` makes the stack profile visible, version-controllable, and easily extendable as the project evolves or new speckit capabilities are added. -**Independent Test**: Run `/speckit.specify` on a fresh project where stack info is not yet captured. Verify the workflow prompts for packaging tool, test library, and linting tool, then stores the answers. Run `/speckit.tasks` and verify the generated tasks reference the correct tooling. +**Independent Test**: Delete `stack.md` from `.specify/memory/`. Run `/speckit.specify`. Verify the workflow offers both auto-detect and manual entry modes. Select auto-detect; verify `stack.md` is created with all standard template fields populated. Run `/speckit.tasks` and verify the generated tasks reference the tooling recorded in `stack.md`. **Acceptance Scenarios**: -1. **Given** no stack info exists in memory, **When** a speckit command runs, **Then** the agent prompts for packaging tool, test library, linting tool, and version constraints. -2. **Given** stack info is already stored, **When** any speckit command runs, **Then** the agent uses the stored info without re-prompting. -3. **Given** stack info changes (e.g., migration from npm to pnpm), **When** the constitution is updated, **Then** subsequent speckit commands reflect the updated stack. +1. **Given** `stack.md` does not exist, **When** any speckit command runs, **Then** the workflow presents the developer with a choice: auto-detect stack or manually enter stack details. +2. **Given** the developer selects auto-detect, **When** the model inspects the repository, **Then** `stack.md` is created with all standard template fields inferred from project files (e.g., package manager detected from lock file, test library detected from config or dependencies). +3. **Given** the developer selects manual entry, **When** they complete the prompted form, **Then** `stack.md` is created with the developer-provided values filling all standard template fields. +4. **Given** `stack.md` already exists, **When** any speckit command runs, **Then** the workflow reads the file and uses its values without prompting. +5. **Given** new fields are added to the `stack.md` template (e.g., for a future speckit extension), **When** an existing `stack.md` is loaded, **Then** the workflow detects missing fields, prompts only for the new fields, and appends them without overwriting existing values. +6. **Given** a stack field changes (e.g., migration from npm to pnpm), **When** `stack.md` is updated and committed, **Then** all subsequent speckit commands use the new values. --- @@ -113,55 +122,96 @@ A developer introduces a paradigm shift (e.g., new architecture pattern, new too --- +### User Story 7 - Spec Artifact Drift Detection and Auto-Update (Priority: P3) + +During or after implementation, a developer steers the feature in a direction that diverges from what was originally specified. The speckit workflow — at the end of the implement or analyze phase — diffs the feature branch artifacts (spec.md, plan.md, tasks.md) against what they contained at the point of branch creation. Where it detects a meaningful mismatch between the written spec and the actual code changes, it prompts the developer to confirm whether the spec should be updated to reflect reality. If confirmed, the affected artifact(s) are updated and committed. + +**Why this priority**: Specs and implementation routinely drift during development. Without a drift-detection pass, the spec becomes a historical artifact rather than a living document. Keeping spec.md, plan.md, and tasks.md synchronized with what was actually built ensures the analyze phase is meaningful and future maintainers understand the true intent of each feature. + +**Independent Test**: Create a feature branch with a spec. Implement a change that differs from the spec (e.g., add a capability not listed in functional requirements). Run `/speckit.analyze`. Verify the workflow reports the drift, presents the diff, and offers to update spec.md to include the new capability. Confirm the update and verify a commit is made containing the revised spec.md. + +**Acceptance Scenarios**: + +1. **Given** implementation code changes exist on the branch since branch creation, **When** `/speckit.analyze` runs, **Then** the workflow diffs spec.md, plan.md, and tasks.md against their state at branch-creation commit and reports any detected mismatches. +2. **Given** a mismatch is detected (e.g., a requirement in spec.md was not implemented, or code was added beyond the spec scope), **When** the drift report is shown, **Then** the developer is prompted to confirm whether each artifact should be updated. +3. **Given** the developer confirms an artifact update, **When** the update is applied, **Then** the artifact is revised to reflect the actual implementation direction and a conventional-commit-formatted commit is made. +4. **Given** the developer declines an artifact update, **When** the decision is recorded, **Then** the mismatch is noted in the analysis output but the artifact is left unchanged. +5. **Given** no drift is detected (implementation matches spec), **When** `/speckit.analyze` completes, **Then** no drift report is generated and the phase proceeds normally. +6. **Given** plan.md or tasks.md contain items that were never addressed (skipped or descoped), **When** drift detection runs, **Then** those items are flagged as unresolved and the developer is prompted to either remove them or mark them as deferred. + +--- + ### Edge Cases -- What happens when GitHub MCP is unavailable during the specify phase — spec creation must not be blocked. -- What happens when the developer declines to provide stack information — workflow proceeds with defaults and marks stack fields as unset. -- What happens when a spec branch already has a commit for the current phase — duplicate commit must not be created. +- What happens when GitHub MCP is unavailable during the specify phase — spec creation must not be blocked; triage guard is skipped with a warning. +- What happens when the developer selects multiple issues to consolidate and then deselects one mid-way — only confirmed issues are written to spec.md. +- What happens when the developer declines to provide stack information or skips auto-detect — workflow proceeds with defaults and marks stack fields as unset in stack.md. +- What happens when auto-detect cannot determine a stack field — that field is left blank in stack.md and flagged for manual entry on the next speckit run. +- What happens when a spec branch already has a commit for the current phase — no duplicate commit is created; the workflow checks for unstaged changes before committing. - What happens when tasks.md has partially completed tasks when `/speckit.implement` is re-run — already-done tasks are skipped, status is not regressed. -- What happens when two issues could plausibly map to the same spec — the workflow picks the closest match and notes the ambiguity in spec.md. +- What happens when two issues could plausibly map to the same spec — the triage guard presents both candidates and the developer explicitly confirms which to link. +- What happens when drift detection finds changes in a binary or non-text asset — drift detection is scoped to tracked spec artifacts (spec.md, plan.md, tasks.md) only. +- What happens when the developer confirms a spec update but the artifact has conflicting changes — the workflow presents the diff and requires explicit resolution before committing. ## Requirements *(mandatory)* ### Functional Requirements -- **FR-001**: The workflow MUST verify GitHub MCP connectivity at the start of the `/speckit.specify` phase and report status to the developer. -- **FR-002**: The workflow MUST retrieve open GitHub issues during `/speckit.specify` and populate the `GitHub Issue` field in spec.md with the best-matched issue. -- **FR-003**: The workflow MUST commit all phase artifacts to the feature branch at the end of each speckit phase using a Conventional Commits message. -- **FR-004**: The workflow MUST update the `Status` field in spec.md to `Implemented` when all tasks in tasks.md are complete. -- **FR-005**: The workflow MUST update the `Status` field in spec.md to `Analyzed` when `/speckit.analyze` confirms consistency with no unresolved issues. -- **FR-006**: The workflow MUST create a GitHub PR and attach relevant issue(s) when `/speckit.implement` completes and pushes the branch. -- **FR-007**: The workflow MUST prompt for stack information (packaging tool, test library, linting tool, version constraints) when none is stored and persist the answers in the constitution or a memory file. -- **FR-008**: The workflow MUST use stored stack information in all task and command generation without re-prompting. -- **FR-009**: The workflow MUST maintain a memory file listing open GitHub issues that do not yet have a corresponding spec branch, refreshed on each specify phase run. -- **FR-010**: The workflow MUST prompt the developer to review the constitution when a paradigm shift is detected, and synchronize dependent templates after an update. -- **FR-011**: The workflow MUST add regression test execution as a step in the `/speckit.implement` phase to verify no existing functionality is broken. -- **FR-012**: The workflow MUST update tasks.md with any additional tasks discovered during implementation and commit the update. +- **FR-001**: The workflow MUST run the issue-triage agent before `/speckit.specify` begins when GitHub MCP is reachable, presenting a prioritized list of open issues for the developer to select from. +- **FR-002**: The workflow MUST support selecting one or more GitHub issues to associate with a single spec, recording all linked issue numbers and URLs in spec.md's `GitHub Issue` field. +- **FR-003**: The workflow MUST verify GitHub MCP connectivity at the start of the `/speckit.specify` phase and skip the triage guard with a warning when unavailable. +- **FR-004**: The workflow MUST invoke the `conventional-commit` skill to generate commit messages at the end of every speckit phase that produces artifact changes (`/speckit.specify`, `/speckit.clarify`, `/speckit.plan`, `/speckit.tasks`, `/speckit.checklist`, `/speckit.implement`, `/speckit.analyze`). +- **FR-005**: The workflow MUST NOT create a commit at the end of a phase if no artifact changes were made. +- **FR-006**: The workflow MUST update the `Status` field in spec.md to `Implemented` when all tasks in tasks.md are complete. +- **FR-007**: The workflow MUST update the `Status` field in spec.md to `Analyzed` when `/speckit.analyze` confirms consistency with no unresolved issues. +- **FR-008**: The workflow MUST create a GitHub PR and attach all linked issue(s) from spec.md when `/speckit.implement` completes and pushes the branch. +- **FR-009**: The workflow MUST check for a `stack.md` file in `.specify/memory/` at the start of any speckit command; if absent, present the developer with a choice between auto-detect and manual entry modes. +- **FR-010**: In auto-detect mode, the workflow MUST inspect the repository and populate all standard `stack.md` template fields from project files, leaving blank only fields that cannot be inferred. +- **FR-011**: In manual entry mode, the workflow MUST prompt the developer for each standard `stack.md` template field and write the provided values to `stack.md`. +- **FR-012**: The `stack.md` template MUST define a versioned set of standard fields (package manager, test library, linting tool, language version constraints, build tool, project type) that can be extended by adding new fields without invalidating existing entries. +- **FR-013**: The workflow MUST use values from `stack.md` in all task and command generation without re-prompting when the file is present and all required fields are populated. +- **FR-014**: The workflow MUST maintain a memory file listing open GitHub issues not yet associated with a spec branch, refreshed on each `/speckit.specify` run. +- **FR-015**: The workflow MUST prompt the developer to review the constitution when a paradigm shift is detected, and synchronize dependent templates after an update. +- **FR-016**: The constitution MUST be updated to document that the `conventional-commit` skill is required for all speckit-phase commits. +- **FR-017**: The workflow MUST add regression test execution as a step in the `/speckit.implement` phase; a failing test prevents the phase from being marked complete. +- **FR-018**: The workflow MUST update tasks.md with any additional tasks discovered during implementation and commit the update. +- **FR-019**: At the end of `/speckit.analyze` (or `/speckit.implement`), the workflow MUST diff spec.md, plan.md, and tasks.md against their state at branch-creation commit and report any detected mismatches between the written spec and actual changes. +- **FR-020**: When drift is detected, the workflow MUST present the diff to the developer and prompt for confirmation before updating any artifact. +- **FR-021**: When the developer confirms an artifact update due to drift, the workflow MUST revise the artifact to reflect the actual implementation direction and commit it using the `conventional-commit` skill. +- **FR-022**: When plan.md or tasks.md contain unresolved items (never implemented, not deferred), the workflow MUST flag them during drift detection and prompt the developer to remove or defer them. ### Key Entities -- **Constitution**: The project's authoritative source of standards, patterns, and conventions. Updated when paradigm shifts occur; drives template consistency. +- **Constitution**: The project's authoritative source of standards, patterns, and conventions. Updated when paradigm shifts occur; drives template consistency. Documents the requirement to use the conventional-commit skill for all speckit-phase commits. +- **stack.md**: A versioned memory file in `.specify/memory/` containing a standardized, extensible set of project stack fields (package manager, test library, linter, language version constraints, build tool, project type). Populated via auto-detect or manual entry; read by all speckit agents for task and command generation. +- **Stack Template**: The canonical definition of all standard `stack.md` fields, versioned so new fields can be appended without invalidating existing entries. Lives alongside the other speckit templates. - **Memory File (GitHub Issues)**: A file in `.specify/memory/` that tracks open GitHub issues not yet associated with a spec. Refreshed during the specify phase. -- **Stack Profile**: A persisted record of the project's tooling choices (package manager, test library, linter, version constraints). Stored in the constitution or a dedicated memory file. -- **Phase Commit**: A git commit made at the end of each speckit phase capturing all artifact changes for that phase. +- **Phase Commit**: A git commit made at the end of each speckit phase capturing all artifact changes for that phase, with message generated by the conventional-commit skill. - **Spec Status**: The lifecycle state of a spec (Draft → Planned → Tasked → In Progress → Implemented → Analyzed), automatically advanced by the workflow. +- **Drift Report**: The output of comparing spec artifacts (spec.md, plan.md, tasks.md) against their branch-creation state, identifying mismatches between what was specified and what was implemented. ## Success Criteria *(mandatory)* ### Measurable Outcomes -- **SC-001**: 100% of spec.md files produced by `/speckit.specify` include a populated `GitHub Issue` field when a matching open issue exists. -- **SC-002**: 100% of speckit phases that produce artifact changes result in a git commit on the feature branch before the phase ends. -- **SC-003**: spec.md `Status` is automatically advanced to `Implemented` within the same session that `/speckit.implement` completes — no manual update required. -- **SC-004**: Stack information is prompted for at most once per project; subsequent speckit commands across all features use the stored stack profile without re-prompting. -- **SC-005**: The GitHub issues memory file is accurate within one speckit session — issues linked to a spec are removed, and new open issues appear, after each specify phase run. -- **SC-006**: PRs created by the workflow are linked to their corresponding GitHub issue(s) 100% of the time when issue linkage data is available. -- **SC-007**: Regression tests are executed as part of every `/speckit.implement` run; a failing test prevents the phase from being marked complete. +- **SC-001**: 100% of `/speckit.specify` runs where GitHub MCP is reachable present the issue-triage report before spec creation begins. +- **SC-002**: 100% of spec.md files include a `GitHub Issue` field with at least one linked issue when the developer confirms issue selection during specify. +- **SC-003**: 100% of speckit phases that produce artifact changes result in a git commit on the feature branch generated by the conventional-commit skill before the phase ends. +- **SC-004**: spec.md `Status` is automatically advanced to `Implemented` within the same session that `/speckit.implement` completes — no manual update required. +- **SC-005**: `stack.md` is created on first speckit use of a project; subsequent speckit commands across all features require zero re-prompting for stack fields already present in the file. +- **SC-006**: The GitHub issues memory file is accurate within one speckit session — issues linked to a spec are removed, and new open issues appear, after each specify phase run. +- **SC-007**: PRs created by the workflow reference all linked GitHub issues from spec.md 100% of the time when issue linkage data is available. +- **SC-008**: Regression tests are executed as part of every `/speckit.implement` run; a failing test prevents the phase from being marked complete. +- **SC-009**: 100% of `/speckit.analyze` runs on a feature branch with code changes produce a drift report comparing spec artifacts against their branch-creation state. +- **SC-010**: When the developer confirms a drift-based artifact update, the updated artifact is committed in the same session with no manual git steps required. ## Assumptions -- GitHub MCP server is already configured in the developer's Copilot CLI environment; this feature adds verification and usage, not initial setup. +- GitHub MCP server is already configured in the developer's Copilot CLI environment; this feature adds verification, triage integration, and usage, not initial setup. +- The `conventional-commit` skill is available in the project's `.github/extensions/` or the user extensions directory and can be invoked by speckit agents. - The constitution file exists at `.specify/memory/constitution.md` and is the authoritative source for project standards. - The speckit scripts (`.specify/scripts/`) are bash-based and can be extended to include git commit and push operations. - "Paradigm shift" detection is heuristic — the workflow prompts for constitution review on significant dependency additions or pattern-level changes rather than detecting it automatically. -- Stack information is project-scoped, not per-feature; it is captured once and shared across all features in the repository. +- `stack.md` is project-scoped, not per-feature; it is created once and shared across all features in the repository. +- The `stack.md` template is versioned with a schema version field so future extensions (new standard fields) can be detected and incrementally prompted without full re-entry. +- Drift detection uses `git diff ..HEAD` scoped to spec artifact paths (spec.md, plan.md, tasks.md); it does not analyze source code semantics. From a79c11cf821f581cf51079eea003092a093a3872 Mon Sep 17 00:00:00 2001 From: Jeff Williams Date: Sun, 22 Mar 2026 10:27:20 -0400 Subject: [PATCH 03/15] docs(speckit): add instructions consolidation and copilot-instructions overlap fixes (#31) - FR-023: embed issue-triage invocation in speckit.specify agent directly (agent-to-agent) - FR-024: remove issue-triage.instructions.md; consolidate routing into copilot-instructions.md - FR-025: replace abridged constitution in copilot-instructions.md with pointer to constitution.md; add spec-kit workflow reference - Assumptions: document copilot-instructions vs constitution overlap rationale and instructions file removal rationale Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- specs/020-speckit-workflow/spec.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/specs/020-speckit-workflow/spec.md b/specs/020-speckit-workflow/spec.md index 911e4c2..06d8ae0 100644 --- a/specs/020-speckit-workflow/spec.md +++ b/specs/020-speckit-workflow/spec.md @@ -179,6 +179,9 @@ During or after implementation, a developer steers the feature in a direction th - **FR-020**: When drift is detected, the workflow MUST present the diff to the developer and prompt for confirmation before updating any artifact. - **FR-021**: When the developer confirms an artifact update due to drift, the workflow MUST revise the artifact to reflect the actual implementation direction and commit it using the `conventional-commit` skill. - **FR-022**: When plan.md or tasks.md contain unresolved items (never implemented, not deferred), the workflow MUST flag them during drift detection and prompt the developer to remove or defer them. +- **FR-023**: The issue-triage invocation in `/speckit.specify` MUST be embedded directly in the `speckit.specify` agent definition (agent-to-agent call), not routed via an instructions file. +- **FR-024**: The `.github/instructions/issue-triage.instructions.md` file MUST be removed; its routing trigger ("when user says triage, invoke issue-triage agent") MUST be consolidated into `copilot-instructions.md` as a single reference line. +- **FR-025**: The "Constitution Principles (abridged)" section in `copilot-instructions.md` MUST be replaced with a single pointer to `.specify/memory/constitution.md`, eliminating the drift risk between the two files. A brief "Spec-Kit Workflow" reference MUST also be added to `copilot-instructions.md` pointing to the agent definitions. ### Key Entities @@ -215,3 +218,5 @@ During or after implementation, a developer steers the feature in a direction th - `stack.md` is project-scoped, not per-feature; it is created once and shared across all features in the repository. - The `stack.md` template is versioned with a schema version field so future extensions (new standard fields) can be detected and incrementally prompted without full re-entry. - Drift detection uses `git diff ..HEAD` scoped to spec artifact paths (spec.md, plan.md, tasks.md); it does not analyze source code semantics. +- `copilot-instructions.md` and `constitution.md` serve different purposes and MUST coexist: `copilot-instructions.md` is the model's operational quick reference (commands, import paths, code patterns); the constitution is the governance document (principles, rationale, amendment procedure). The "abridged" principles section in `copilot-instructions.md` creates a drift risk and will be replaced with a pointer to the constitution as part of this feature. +- `.github/instructions/issue-triage.instructions.md` with `applyTo: "**"` is a global context file that duplicates routing logic better placed in `copilot-instructions.md`. It has no role in agent-to-agent invocation and will be removed. From e716f1a82b107850d46e1b2259ba7958552a418c Mon Sep 17 00:00:00 2001 From: Jeff Williams Date: Sun, 22 Mar 2026 10:30:43 -0400 Subject: [PATCH 04/15] docs(speckit): add hooks and skills integration to spec (#31) - FR-026: context-map skill invoked at start of /speckit.plan - FR-027: context-map skill invoked per task group in /speckit.implement - FR-028: github-issues skill posts comment on linked issues after /speckit.specify - FR-029: github-issues skill creates PR with Closes refs in /speckit.implement - FR-030: sessionEnd hook warns on uncommitted speckit artifacts - FR-031: userPromptSubmitted hook fixed (copy-paste bug) + logs phase invocations - FR-032: sessionStart hook detects active speckit branch and logs current phase - Key Entities: added Context Map and Session Audit Log - Assumptions: documented skill/hook constraints and the log-prompt.sh bug Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- specs/020-speckit-workflow/spec.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/specs/020-speckit-workflow/spec.md b/specs/020-speckit-workflow/spec.md index 06d8ae0..a6e0326 100644 --- a/specs/020-speckit-workflow/spec.md +++ b/specs/020-speckit-workflow/spec.md @@ -182,6 +182,13 @@ During or after implementation, a developer steers the feature in a direction th - **FR-023**: The issue-triage invocation in `/speckit.specify` MUST be embedded directly in the `speckit.specify` agent definition (agent-to-agent call), not routed via an instructions file. - **FR-024**: The `.github/instructions/issue-triage.instructions.md` file MUST be removed; its routing trigger ("when user says triage, invoke issue-triage agent") MUST be consolidated into `copilot-instructions.md` as a single reference line. - **FR-025**: The "Constitution Principles (abridged)" section in `copilot-instructions.md` MUST be replaced with a single pointer to `.specify/memory/constitution.md`, eliminating the drift risk between the two files. A brief "Spec-Kit Workflow" reference MUST also be added to `copilot-instructions.md` pointing to the agent definitions. +- **FR-026**: The `context-map` skill MUST be invoked at the start of `/speckit.plan` to produce a map of files relevant to the feature before design artifacts are generated, ensuring plan.md references accurate file paths and dependencies. +- **FR-027**: The `context-map` skill MUST be invoked at the start of each task group in `/speckit.implement` before any code changes are made, identifying files to modify, dependent files, related tests, and risk areas for that task group. +- **FR-028**: The `github-issues` skill MUST be used during `/speckit.specify` to post a comment on each linked GitHub issue confirming the spec branch name and linking to the spec file, creating a visible trail from issue to spec. +- **FR-029**: The `github-issues` skill MUST be used during `/speckit.implement` to create the PR with `Closes #N` references for all linked issues, and to post a comment on each issue with the PR URL when opened. +- **FR-030**: The `sessionEnd` hook MUST be updated to detect uncommitted speckit artifacts (spec.md, plan.md, tasks.md with unstaged or staged-but-uncommitted changes on a speckit branch) and emit a warning before the session closes. +- **FR-031**: The `userPromptSubmitted` hook MUST be fixed to log the submitted prompt content (currently a copy-paste of `log-session-end.sh` — logs nothing useful) and extended to detect and log speckit phase command invocations for session-level audit trail. +- **FR-032**: The `sessionStart` hook MUST be updated to detect if the current branch is a speckit feature branch, and if so, log the active spec name, current status from spec.md, and the last committed speckit phase. ### Key Entities @@ -192,6 +199,8 @@ During or after implementation, a developer steers the feature in a direction th - **Phase Commit**: A git commit made at the end of each speckit phase capturing all artifact changes for that phase, with message generated by the conventional-commit skill. - **Spec Status**: The lifecycle state of a spec (Draft → Planned → Tasked → In Progress → Implemented → Analyzed), automatically advanced by the workflow. - **Drift Report**: The output of comparing spec artifacts (spec.md, plan.md, tasks.md) against their branch-creation state, identifying mismatches between what was specified and what was implemented. +- **Context Map**: The output of the `context-map` skill — a structured table of files to modify, dependencies, related tests, and risk areas. Produced before planning and before each implementation task group. +- **Session Audit Log**: The log written by the session-logger hooks to `logs/copilot/session.log`, capturing session start/end events, active speckit branch/phase, and prompt-level speckit command invocations. ## Success Criteria *(mandatory)* @@ -220,3 +229,8 @@ During or after implementation, a developer steers the feature in a direction th - Drift detection uses `git diff ..HEAD` scoped to spec artifact paths (spec.md, plan.md, tasks.md); it does not analyze source code semantics. - `copilot-instructions.md` and `constitution.md` serve different purposes and MUST coexist: `copilot-instructions.md` is the model's operational quick reference (commands, import paths, code patterns); the constitution is the governance document (principles, rationale, amendment procedure). The "abridged" principles section in `copilot-instructions.md` creates a drift risk and will be replaced with a pointer to the constitution as part of this feature. - `.github/instructions/issue-triage.instructions.md` with `applyTo: "**"` is a global context file that duplicates routing logic better placed in `copilot-instructions.md`. It has no role in agent-to-agent invocation and will be removed. +- The `context-map` and `github-issues` skills are already present in `.github/skills/`; this feature wires them into speckit agent definitions rather than creating new skills. +- The `github-issues` skill handles both MCP-based operations (preferred) and `gh api` fallback; internet/MCP connectivity is required for issue commenting and PR creation. +- Session-logger hooks are shell scripts fired by the Copilot CLI runtime and cannot influence model behavior; they serve only as observability and safety-net tooling. Hook improvements in FR-030–FR-032 are low-risk shell changes. +- The `userPromptSubmitted` hook (`log-prompt.sh`) is currently a copy-paste of `log-session-end.sh` and logs nothing meaningful. FR-031 treats this as a bug fix as well as an enhancement. +- Hooks operate at session boundaries; they cannot detect speckit phase transitions mid-session except via prompt text pattern matching in `userPromptSubmitted`. From 6c59216ddf5e8ca4f6bdd455878c0a4cf48559cf Mon Sep 17 00:00:00 2001 From: Jeff Williams Date: Sun, 22 Mar 2026 10:35:16 -0400 Subject: [PATCH 05/15] docs(speckit): add session lifecycle management to spec (#31) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - US8: Session Lifecycle Management (P2) with 5 acceptance scenarios - FR-033: hook setup guard — check .gitignore + logs dir before writing - FR-034: /speckit.specify warns on non-fresh session (non-blocking) - FR-035: resuming agents must explicitly load constitution, stack.md, spec.md, phase artifacts - Edge cases: partial setup warning, non-blocking session contamination check - Assumptions: CLI auto-load limitation, advisory-only session boundary, .gitignore guard rationale Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- specs/020-speckit-workflow/spec.md | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/specs/020-speckit-workflow/spec.md b/specs/020-speckit-workflow/spec.md index a6e0326..9d17732 100644 --- a/specs/020-speckit-workflow/spec.md +++ b/specs/020-speckit-workflow/spec.md @@ -141,6 +141,24 @@ During or after implementation, a developer steers the feature in a direction th --- +### User Story 8 - Session Lifecycle Management (Priority: P2) + +When a developer starts a new spec, the workflow enforces that it begins in a fresh Copilot CLI session to prevent context bleed from a prior spec's conversation history. When a session starts on an existing speckit feature branch, the workflow automatically surfaces a context summary (spec name, current status, last committed phase) so the developer knows where they left off. Each speckit agent that can resume a workflow (plan, tasks, implement, analyze) explicitly loads all relevant context files at startup — constitution, stack.md, spec.md, and any existing phase artifacts — since only `copilot-instructions.md` is loaded automatically by the CLI. The session-logger hooks are guarded: they check prerequisites (logs directory, `.gitignore` entry) before writing, and emit a one-time setup reminder rather than silently failing or writing untracked files. + +**Why this priority**: Without session boundaries, context from a prior spec's plan or implementation bleeds into a new feature, leading to hallucinated file paths or incorrect assumptions. Without explicit context loading in resuming agents, the model may lack the constitution, stack constraints, or prior decisions needed to produce consistent artifacts. + +**Independent Test**: Start a fresh session, run `/speckit.specify` — verify a session boundary reminder appears. Close the session, reopen in the same branch, run `/speckit.plan` — verify the agent outputs a context summary showing the spec name and status before proceeding. Verify `logs/copilot/session.log` is not committed (present in `.gitignore`) and hook scripts emit a reminder if setup is incomplete. + +**Acceptance Scenarios**: + +1. **Given** a developer invokes `/speckit.specify` in a session that already has prior conversation history, **When** the phase begins, **Then** the agent surfaces a session boundary reminder recommending a fresh session for a new spec. +2. **Given** a developer starts a new session on a speckit feature branch, **When** `sessionStart` fires, **Then** the hook logs and surfaces a context summary: active spec name, current status, and last committed phase. +3. **Given** a developer resumes `/speckit.plan`, `/speckit.tasks`, `/speckit.implement`, or `/speckit.analyze` in a new session, **When** the agent starts, **Then** it explicitly reads constitution, stack.md, spec.md, and any existing phase artifacts before generating output. +4. **Given** the session-logger hook fires and `logs/` is not in `.gitignore`, **When** the hook runs, **Then** it emits a one-time setup reminder and skips writing logs rather than creating untracked files. +5. **Given** session-logger setup is complete (`logs/` in `.gitignore`, directory present), **When** any session lifecycle event fires, **Then** the hook writes structured JSON to `logs/copilot/session.log` without any warnings. + +--- + ### Edge Cases - What happens when GitHub MCP is unavailable during the specify phase — spec creation must not be blocked; triage guard is skipped with a warning. @@ -152,6 +170,8 @@ During or after implementation, a developer steers the feature in a direction th - What happens when two issues could plausibly map to the same spec — the triage guard presents both candidates and the developer explicitly confirms which to link. - What happens when drift detection finds changes in a binary or non-text asset — drift detection is scoped to tracked spec artifacts (spec.md, plan.md, tasks.md) only. - What happens when the developer confirms a spec update but the artifact has conflicting changes — the workflow presents the diff and requires explicit resolution before committing. +- What happens when a developer runs `/speckit.specify` in a resumed session — the agent warns about session contamination risk but does not hard-block if the developer confirms they want to proceed. +- What happens when session-logger setup is partial (directory exists but logs/ not in .gitignore) — the hook emits a specific warning identifying the missing step and skips writing. ## Requirements *(mandatory)* @@ -189,6 +209,9 @@ During or after implementation, a developer steers the feature in a direction th - **FR-030**: The `sessionEnd` hook MUST be updated to detect uncommitted speckit artifacts (spec.md, plan.md, tasks.md with unstaged or staged-but-uncommitted changes on a speckit branch) and emit a warning before the session closes. - **FR-031**: The `userPromptSubmitted` hook MUST be fixed to log the submitted prompt content (currently a copy-paste of `log-session-end.sh` — logs nothing useful) and extended to detect and log speckit phase command invocations for session-level audit trail. - **FR-032**: The `sessionStart` hook MUST be updated to detect if the current branch is a speckit feature branch, and if so, log the active spec name, current status from spec.md, and the last committed speckit phase. +- **FR-033**: Each session-logger hook script MUST guard against prerequisites before writing: verify `logs/` is present in `.gitignore` and the `logs/copilot/` directory exists; emit a one-time actionable setup reminder and exit cleanly if either check fails. +- **FR-034**: The `/speckit.specify` agent MUST include a session boundary reminder at startup — informing the developer that new specs should begin in a fresh session — and surface the reminder as a non-blocking prompt if the session appears to have prior speckit conversation history. +- **FR-035**: Every speckit agent that resumes a workflow (`/speckit.plan`, `/speckit.tasks`, `/speckit.implement`, `/speckit.analyze`) MUST explicitly load the following context files at startup before generating any output: `.specify/memory/constitution.md`, `.specify/memory/stack.md` (if present), the current spec's `spec.md`, and any existing phase artifacts (`plan.md`, `tasks.md`). Only `copilot-instructions.md` is loaded automatically by the CLI; all other speckit context must be loaded explicitly. ### Key Entities @@ -234,3 +257,6 @@ During or after implementation, a developer steers the feature in a direction th - Session-logger hooks are shell scripts fired by the Copilot CLI runtime and cannot influence model behavior; they serve only as observability and safety-net tooling. Hook improvements in FR-030–FR-032 are low-risk shell changes. - The `userPromptSubmitted` hook (`log-prompt.sh`) is currently a copy-paste of `log-session-end.sh` and logs nothing meaningful. FR-031 treats this as a bug fix as well as an enhancement. - Hooks operate at session boundaries; they cannot detect speckit phase transitions mid-session except via prompt text pattern matching in `userPromptSubmitted`. +- `copilot-instructions.md` is the only file loaded automatically by the Copilot CLI into every session context. Constitution, stack.md, and spec artifacts are NOT automatically injected — speckit agents must read them explicitly (FR-035). +- Session boundary enforcement (FR-034) is advisory, not hard-blocking: the CLI has no API to terminate a session mid-conversation; the agent can warn but not force a new session. +- The session-logger hook setup (chmod +x, logs/ in .gitignore) is a one-time project-level task. Because the hooks.json uses a `bash` prefix for invocation, the execute bit may not be strictly required at runtime, but the `.gitignore` guard (FR-033) is critical to prevent session log data from being committed. From 7a65221dbb490de710cc10129a60bc7679255f75 Mon Sep 17 00:00:00 2001 From: Jeff Williams Date: Sun, 22 Mar 2026 10:43:03 -0400 Subject: [PATCH 06/15] docs(speckit): add portability and cross-repo bootstrap to spec (#31) - US9: Portability and Cross-Repo Bootstrap (P3) with 5 acceptance scenarios - FR-036: separate generic tooling from project-specific context - FR-037: bootstrap script scaffolds project-specific layer in new repos - FR-038: bootstrap script is idempotent, skips existing artifacts - FR-039: project-level agent/skill definitions take precedence over global - Edge cases: idempotent bootstrap, local-over-global name conflict - Key Entities: Speckit Repo, Bootstrap Script, User-Level Extensions - Assumptions: portability contract scoped to current feature; actual standalone repo is future work Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- specs/020-speckit-workflow/spec.md | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/specs/020-speckit-workflow/spec.md b/specs/020-speckit-workflow/spec.md index 9d17732..3ada401 100644 --- a/specs/020-speckit-workflow/spec.md +++ b/specs/020-speckit-workflow/spec.md @@ -172,6 +172,26 @@ When a developer starts a new spec, the workflow enforces that it begins in a fr - What happens when the developer confirms a spec update but the artifact has conflicting changes — the workflow presents the diff and requires explicit resolution before committing. - What happens when a developer runs `/speckit.specify` in a resumed session — the agent warns about session contamination risk but does not hard-block if the developer confirms they want to proceed. - What happens when session-logger setup is partial (directory exists but logs/ not in .gitignore) — the hook emits a specific warning identifying the missing step and skips writing. +- What happens when the bootstrap script is run on a repo that already has some speckit artifacts — the script is idempotent and skips existing files without overwriting. +- What happens when a user-level agent and a project-level agent share the same name — the project-level definition always wins (local-over-global override). + +--- + +### User Story 9 - Portability and Cross-Repo Bootstrap (Priority: P3) + +A developer who has refined their speckit workflow in one project wants to use the same agents, skills, templates, and scripts globally — available in every repository without manual copying. They publish all generic, project-agnostic tooling (agents, skills, templates, scripts) to a standalone speckit repository and install it once into the Copilot CLI's user-level extensions directory. For each new project, a bootstrap script from the speckit repository scaffolds the project-specific layer: constitution stub, `stack.md` prompt, hooks setup, `logs/` added to `.gitignore`, and a `copilot-instructions.md` reference block. Project-specific context (constitution, stack.md, specs) always lives in the target repo and is never stored globally. Local project overrides always take precedence over user-level defaults. + +**Why this priority**: Once the workflow is trusted, copying agents and skills into every new repo manually is error-prone and prevents consistent updates. A single global install point with a per-project bootstrap separates versioned generic tooling from always-local project context. P3 because it depends on all prior stories being stable and validated. + +**Independent Test**: Create a blank repository with no `.github/` directory. Run the bootstrap script from the speckit repo. Verify that `/speckit.specify` and all skills are available without any files copied into `.github/`, that the constitution stub and `copilot-instructions.md` reference block were created, and that running the bootstrap script a second time changes nothing. + +**Acceptance Scenarios**: + +1. **Given** the speckit repo's agents and skills are installed in the user-level extensions directory, **When** a developer opens any repository in Copilot CLI, **Then** all `/speckit.*` commands and skills (`conventional-commit`, `context-map`, `github-issues`) are available without project-level `.github/` files. +2. **Given** a new blank repository, **When** the developer runs the speckit bootstrap script, **Then** the project-specific scaffold is created: constitution stub, empty `stack.md`, hooks wired up, `logs/` in `.gitignore`, and a `copilot-instructions.md` pointer to the constitution. +3. **Given** a speckit repo update ships a new agent version, **When** the developer updates the user-level extensions install, **Then** all repos immediately benefit with no per-project changes required. +4. **Given** a project defines its own `.github/agents/speckit.specify.agent.md`, **When** `/speckit.specify` runs in that project, **Then** the project-level definition takes precedence over the user-level global one. +5. **Given** the bootstrap script has already been run on a project, **When** it is run again, **Then** it skips all existing files without overwriting them and reports which artifacts were already present. ## Requirements *(mandatory)* @@ -212,6 +232,10 @@ When a developer starts a new spec, the workflow enforces that it begins in a fr - **FR-033**: Each session-logger hook script MUST guard against prerequisites before writing: verify `logs/` is present in `.gitignore` and the `logs/copilot/` directory exists; emit a one-time actionable setup reminder and exit cleanly if either check fails. - **FR-034**: The `/speckit.specify` agent MUST include a session boundary reminder at startup — informing the developer that new specs should begin in a fresh session — and surface the reminder as a non-blocking prompt if the session appears to have prior speckit conversation history. - **FR-035**: Every speckit agent that resumes a workflow (`/speckit.plan`, `/speckit.tasks`, `/speckit.implement`, `/speckit.analyze`) MUST explicitly load the following context files at startup before generating any output: `.specify/memory/constitution.md`, `.specify/memory/stack.md` (if present), the current spec's `spec.md`, and any existing phase artifacts (`plan.md`, `tasks.md`). Only `copilot-instructions.md` is loaded automatically by the CLI; all other speckit context must be loaded explicitly. +- **FR-036**: The speckit repository MUST separate generic tooling (agents, skills, templates, scripts) from project-specific context (constitution, stack.md, specs) so that generic artifacts can be installed globally and project context always lives in the target repo. +- **FR-037**: A bootstrap script MUST be provided that, when run in a new repository, scaffolds the project-specific layer: creates a constitution stub at `.specify/memory/constitution.md`, creates an empty `.specify/memory/stack.md`, wires up session-logger hooks, adds `logs/` to `.gitignore`, and appends a speckit reference block to `copilot-instructions.md`. +- **FR-038**: The bootstrap script MUST be idempotent — running it multiple times on the same repository MUST skip all already-present artifacts without overwriting them and MUST report which items were skipped. +- **FR-039**: When a project defines a local agent or skill with the same name as a user-level global definition, the project-level definition MUST take precedence, enabling per-project overrides of the global speckit workflow. ### Key Entities @@ -224,6 +248,9 @@ When a developer starts a new spec, the workflow enforces that it begins in a fr - **Drift Report**: The output of comparing spec artifacts (spec.md, plan.md, tasks.md) against their branch-creation state, identifying mismatches between what was specified and what was implemented. - **Context Map**: The output of the `context-map` skill — a structured table of files to modify, dependencies, related tests, and risk areas. Produced before planning and before each implementation task group. - **Session Audit Log**: The log written by the session-logger hooks to `logs/copilot/session.log`, capturing session start/end events, active speckit branch/phase, and prompt-level speckit command invocations. +- **Speckit Repo**: A standalone repository containing all generic, project-agnostic speckit tooling (agents, skills, templates, scripts, bootstrap script). Installed once at the user-level extensions directory; updated independently of any project repo. +- **Bootstrap Script**: A one-time idempotent setup script shipped in the speckit repo that scaffolds the project-specific speckit layer into a target repository (constitution stub, stack.md, hooks, .gitignore entry, copilot-instructions.md reference). +- **User-Level Extensions**: The Copilot CLI's personal extensions directory where agents and skills installed globally are available across all repositories, with project-level definitions taking precedence when names conflict. ## Success Criteria *(mandatory)* @@ -260,3 +287,6 @@ When a developer starts a new spec, the workflow enforces that it begins in a fr - `copilot-instructions.md` is the only file loaded automatically by the Copilot CLI into every session context. Constitution, stack.md, and spec artifacts are NOT automatically injected — speckit agents must read them explicitly (FR-035). - Session boundary enforcement (FR-034) is advisory, not hard-blocking: the CLI has no API to terminate a session mid-conversation; the agent can warn but not force a new session. - The session-logger hook setup (chmod +x, logs/ in .gitignore) is a one-time project-level task. Because the hooks.json uses a `bash` prefix for invocation, the execute bit may not be strictly required at runtime, but the `.gitignore` guard (FR-033) is critical to prevent session log data from being committed. +- The Copilot CLI's local-over-global override behavior (FR-039) is a platform convention, not something this feature implements; the FR documents the expected behavior to rely on, not something to build. +- The speckit repo is out of scope for implementation in this feature; FR-036–FR-039 define the portability contract so that the current implementation is structured to support extraction. The actual standalone repo creation is a future activity. +- The exact location of the user-level Copilot CLI extensions directory is platform-dependent; the bootstrap script must handle this gracefully (document the path, fail with a clear error if not found). From 2a8e3414de7b1d116e1db007edb9a415badb972c Mon Sep 17 00:00:00 2001 From: Jeff Williams Date: Sun, 22 Mar 2026 10:45:47 -0400 Subject: [PATCH 07/15] docs(speckit): add pre-commit summary guard to spec (#31) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - US2 scenarios 9-10: pre-commit summary required before git commit; developer decline aborts phase without marking it complete - FR-040: conventional-commit skill MUST show staged files + message preview and require explicit confirmation before committing; guard applies in all permission modes including YOLO/auto-approve - Edge case: developer declines pre-commit summary -> phase aborted - Assumption: YOLO bypasses tool permissions, not conversational prompts Note: current conventional-commit SKILL.md says 'no confirmation needed' — FR-040 requires updating that skill definition during implement. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- specs/020-speckit-workflow/spec.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/specs/020-speckit-workflow/spec.md b/specs/020-speckit-workflow/spec.md index 3ada401..2887222 100644 --- a/specs/020-speckit-workflow/spec.md +++ b/specs/020-speckit-workflow/spec.md @@ -53,6 +53,8 @@ A developer progresses through any speckit phase (`/speckit.specify`, `/speckit. 6. **Given** `/speckit.analyze` completes, **When** the phase ends, **Then** a conventional-commit-formatted commit is made with any updated artifacts and the advanced spec status. 7. **Given** `/speckit.implement` completes all tasks, **When** the phase ends, **Then** a conventional-commit-formatted commit is made, the branch is pushed, and a PR is created referencing all linked GitHub issues. 8. **Given** a phase produces no artifact changes, **When** the phase ends, **Then** no commit is created (duplicate empty commits are prevented). +9. **Given** YOLO/auto-approve permissions are active and a speckit phase ends, **When** the `conventional-commit` skill is invoked, **Then** the skill still presents a pre-commit summary (list of staged files and generated commit message) and requires explicit developer confirmation before running `git commit` — auto-approve does not bypass this conversational prompt. +10. **Given** the pre-commit summary is presented and the developer declines, **When** the decision is recorded, **Then** the commit is aborted, the phase is not marked complete, and the developer is informed they can re-run the phase or commit manually. --- @@ -174,6 +176,7 @@ When a developer starts a new spec, the workflow enforces that it begins in a fr - What happens when session-logger setup is partial (directory exists but logs/ not in .gitignore) — the hook emits a specific warning identifying the missing step and skips writing. - What happens when the bootstrap script is run on a repo that already has some speckit artifacts — the script is idempotent and skips existing files without overwriting. - What happens when a user-level agent and a project-level agent share the same name — the project-level definition always wins (local-over-global override). +- What happens when the developer declines the pre-commit summary — the commit is aborted, the phase is not marked complete, and the developer is prompted to re-run the phase or commit manually. --- @@ -236,6 +239,7 @@ A developer who has refined their speckit workflow in one project wants to use t - **FR-037**: A bootstrap script MUST be provided that, when run in a new repository, scaffolds the project-specific layer: creates a constitution stub at `.specify/memory/constitution.md`, creates an empty `.specify/memory/stack.md`, wires up session-logger hooks, adds `logs/` to `.gitignore`, and appends a speckit reference block to `copilot-instructions.md`. - **FR-038**: The bootstrap script MUST be idempotent — running it multiple times on the same repository MUST skip all already-present artifacts without overwriting them and MUST report which items were skipped. - **FR-039**: When a project defines a local agent or skill with the same name as a user-level global definition, the project-level definition MUST take precedence, enabling per-project overrides of the global speckit workflow. +- **FR-040**: Before executing any phase commit, the `conventional-commit` skill MUST present a pre-commit summary to the developer showing: (1) the list of files staged for commit, (2) the generated commit message with type, scope, and description. The commit MUST NOT proceed until the developer explicitly confirms. This guard applies regardless of session permission mode, including YOLO/auto-approve, because it is a conversational prompt, not a tool execution request. ### Key Entities @@ -290,3 +294,4 @@ A developer who has refined their speckit workflow in one project wants to use t - The Copilot CLI's local-over-global override behavior (FR-039) is a platform convention, not something this feature implements; the FR documents the expected behavior to rely on, not something to build. - The speckit repo is out of scope for implementation in this feature; FR-036–FR-039 define the portability contract so that the current implementation is structured to support extraction. The actual standalone repo creation is a future activity. - The exact location of the user-level Copilot CLI extensions directory is platform-dependent; the bootstrap script must handle this gracefully (document the path, fail with a clear error if not found). +- YOLO/auto-approve mode in the Copilot CLI bypasses tool execution permission prompts ("do you want to run this command?") but does NOT bypass conversational questions directed at the developer. The pre-commit summary in FR-040 is a conversational prompt and is therefore unaffected by YOLO mode. From 49247428d61bdc34f3e1573fe8cbb4845dc91971 Mon Sep 17 00:00:00 2001 From: Jeff Williams Date: Sun, 22 Mar 2026 17:42:20 -0400 Subject: [PATCH 08/15] docs(plan): add implementation plan for 020-speckit-workflow MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - plan.md: technical context, constitution check (all pass), file change inventory, agent/skill change designs, phase-end commit block pattern, conventional-commit skill update design - research.md: 5 decisions documented (pre-commit guard, hook guards, branch detection, drift detection, stack-template schema); full codebase inventory of 14 files to change/create - data-model.md: stack-template.md schema v1.0 with all standard fields, auto-detection sources, version upgrade procedure, state transitions - spec.md: Status advanced Draft → Planned Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- specs/020-speckit-workflow/data-model.md | 151 +++++++++++++++++ specs/020-speckit-workflow/plan.md | 196 +++++++++++++++++++++++ specs/020-speckit-workflow/research.md | 111 +++++++++++++ specs/020-speckit-workflow/spec.md | 2 +- 4 files changed, 459 insertions(+), 1 deletion(-) create mode 100644 specs/020-speckit-workflow/data-model.md create mode 100644 specs/020-speckit-workflow/plan.md create mode 100644 specs/020-speckit-workflow/research.md diff --git a/specs/020-speckit-workflow/data-model.md b/specs/020-speckit-workflow/data-model.md new file mode 100644 index 0000000..4a48ae6 --- /dev/null +++ b/specs/020-speckit-workflow/data-model.md @@ -0,0 +1,151 @@ +# Data Model: stack-template.md Schema + +**Feature**: Spec-Kit Workflow Update (020-speckit-workflow) +**Schema Version**: 1.0 +**Purpose**: Defines the canonical field set for any project's `stack.md` file, versioned so new fields can be appended without invalidating existing entries. + +--- + +## Schema Structure + +The `stack-template.md` file is a Markdown document with a `schema_version` field and standard sections. When a speckit agent reads an existing `stack.md`, it compares the `schema_version` to the template's current version and prompts only for missing fields. + +### Meta Section + +| Field | Type | Required | Auto-detectable | Description | +|-------|------|----------|----------------|-------------| +| `schema_version` | string (semver) | Yes | No — set by template | Template version; used for upgrade detection | +| `last_updated` | date (YYYY-MM-DD) | Yes | Yes — set on write | Date last modified | +| `updated_by` | string | Yes | Yes — set on write | Agent or user who last updated | + +### Packaging Section + +| Field | Type | Required | Auto-detectable | Detection source | +|-------|------|----------|----------------|-----------------| +| `tool` | string | Yes | Yes | Presence of `pnpm-lock.yaml`, `yarn.lock`, `package-lock.json`, `Pipfile.lock`, `Cargo.lock`, etc. | +| `workspace_file` | string | No | Yes | `pnpm-workspace.yaml`, `lerna.json`, etc. | +| `lock_file` | string | Yes | Yes | File name of detected lock file | +| `install_cmd` | string | Yes | Yes | Inferred from `tool` | +| `add_dep_cmd` | string | Yes | Yes | Inferred from `tool` | + +### Version Constraints Section + +| Field | Type | Required | Auto-detectable | Detection source | +|-------|------|----------|----------------|-----------------| +| `node_version` | string | No | Yes | `.nvmrc`, `engines` in `package.json` | +| `package_manager_version` | string | No | Yes | `packageManager` in `package.json` | +| `language_version` | string | No | Yes | `tsconfig.json`, `pyproject.toml`, `.ruby-version`, etc. | + +### Linting Section + +| Field | Type | Required | Auto-detectable | Detection source | +|-------|------|----------|----------------|-----------------| +| `tool` | string | Yes | Yes | `eslint.config.*`, `.eslintrc*`, `.pylintrc`, `rubocop.yml`, etc. | +| `config_file` | string | No | Yes | First matching config file found | +| `lint_cmd` | string | Yes | Yes | From `package.json` scripts or inferred | +| `fix_cmd` | string | No | Yes | From `package.json` scripts or inferred | + +### Testing Section + +| Field | Type | Required | Auto-detectable | Detection source | +|-------|------|----------|----------------|-----------------| +| `backend_framework` | string | Yes | Yes | From `package.json` devDependencies (vitest, jest, pytest, rspec, etc.) | +| `backend_run_cmd` | string | Yes | Yes | From `package.json` test script | +| `backend_contract_cmd` | string | No | Yes | From `package.json` test:contract script | +| `frontend_unit_cmd` | string | No | Yes | From frontend `package.json` test script | +| `frontend_e2e_framework` | string | No | Yes | From devDependencies (playwright, cypress, etc.) | +| `frontend_e2e_cmd` | string | No | Yes | From `package.json` test:e2e script | +| `e2e_requires_servers` | boolean | No | Yes | If `playwright` detected, default `true` | + +### Build Section + +| Field | Type | Required | Auto-detectable | Detection source | +|-------|------|----------|----------------|-----------------| +| `build_cmd` | string | Yes | Yes | From root `package.json` build script | +| `backend_build_cmd` | string | No | Yes | From backend `package.json` | +| `frontend_build_cmd` | string | No | Yes | From frontend `package.json` | + +### Infrastructure Section + +| Field | Type | Required | Auto-detectable | Detection source | +|-------|------|----------|----------------|-----------------| +| `local_dev_cmd` | string | No | Yes | From `package.json` dev script | +| `required_services` | string[] | No | Partial | From `docker-compose.yml` service names | +| `infra_start_cmd` | string | No | Yes | `docker compose up -d` if `docker-compose.yml` present | + +### Database Section (include only if DB detected) + +| Field | Type | Required | Auto-detectable | Detection source | +|-------|------|----------|----------------|-----------------| +| `orm` | string | No | Yes | From dependencies (prisma, typeorm, drizzle, sqlalchemy, etc.) | +| `schema_file` | string | No | Yes | `prisma/schema.prisma`, etc. | +| `migrate_cmd` | string | No | Yes | From `package.json` prisma:migrate script | +| `generate_cmd` | string | No | Yes | From `package.json` prisma:generate script | + +### Project Type Section + +| Field | Type | Required | Auto-detectable | Detection source | +|-------|------|----------|----------------|-----------------| +| `type` | enum | Yes | Yes | `web-service` / `mobile-app` / `library` / `cli` / `desktop-app` / `monorepo` | +| `platforms` | string[] | No | Yes | From directory structure, Capacitor config, Tauri config | + +### Commit Convention Section + +| Field | Type | Required | Auto-detectable | Detection source | +|-------|------|----------|----------------|-----------------| +| `format` | string | Yes | No — copy from constitution | Conventional Commits format string | +| `phase_commit_formats` | table | Yes | No — copy from constitution | Phase → message format mapping | + +### Regression Test Commands Section + +| Field | Type | Required | Auto-detectable | Detection source | +|-------|------|----------|----------------|-----------------| +| `lint_cmd` | string | Yes | Yes | Same as Linting.lint_cmd | +| `test_cmd` | string | Yes | Yes | Same as Testing.backend_run_cmd | +| `e2e_cmd` | string | No | Yes | Same as Testing.frontend_e2e_cmd | +| `e2e_requires` | string | No | Yes | Note about server startup if `e2e_requires_servers` is true | + +--- + +## Version Upgrade Procedure + +When `schema_version` in an existing `stack.md` is lower than the template's current version: + +1. Agent reads existing `stack.md` and notes the `schema_version` +2. Agent reads `stack-template.md` and identifies all fields not present in existing file +3. For each missing field: attempt auto-detect first; if not detectable, prompt developer +4. Append missing fields to existing `stack.md` under their correct sections +5. Update `schema_version`, `last_updated`, `updated_by` +6. Commit updated `stack.md` using `conventional-commit` skill + +**Invariant**: Fields already present in `stack.md` are NEVER overwritten during a version upgrade. + +--- + +## State Transitions + +``` +stack.md absent + │ + ▼ +[Offer: auto-detect | manual entry] + │ + ├── auto-detect → inspect repo files → populate all detectable fields → prompt for non-detectable + │ + └── manual entry → prompt for each required field in section order + │ + ▼ +stack.md created (schema_version: 1.0) + │ + ▼ +[Future: template schema_version 1.1 released] + │ + ▼ +[Detect version mismatch on next speckit run] + │ + ▼ +[Prompt only for new fields, append, update schema_version] + │ + ▼ +stack.md upgraded (schema_version: 1.1) +``` diff --git a/specs/020-speckit-workflow/plan.md b/specs/020-speckit-workflow/plan.md new file mode 100644 index 0000000..3c79c4e --- /dev/null +++ b/specs/020-speckit-workflow/plan.md @@ -0,0 +1,196 @@ +# Implementation Plan: Spec-Kit Workflow Update + +**Branch**: `020-speckit-workflow` | **Date**: 2026-03-22 | **Spec**: [spec.md](./spec.md) +**Input**: Feature specification from `/specs/020-speckit-workflow/spec.md` + +## Summary + +Update the speckit workflow tooling to integrate GitHub issue traceability, enforce per-phase conventional commits with a pre-commit summary guard, add stack-aware context loading in all agents, implement spec artifact drift detection, wire in the `context-map` and `github-issues` skills, fix and extend the session-logger hooks, and lay the groundwork for future portability via a clean separation of generic tooling from project-specific context. This feature touches exclusively non-application files: agent definitions, skill definitions, hook scripts, templates, and config files. No backend or frontend source code changes are required. + +## Technical Context + +**Language/Version**: Node.js (TypeScript) — pnpm monorepo; hook scripts in Bash +**Primary Dependencies**: Copilot CLI agent/skill/hook system; GitHub MCP; `gh` CLI fallback; `jq` (Bash hooks); `git` +**Storage**: Markdown files (`.specify/memory/`, `.github/agents/`, `.github/skills/`, `.specify/templates/`); `.gitignore` +**Testing**: `pnpm lint` (ESLint); `pnpm test` (Vitest backend); no new test suite required — changes are agent/shell/markdown files +**Target Platform**: GitHub Copilot CLI (macOS/Linux); Bash hooks +**Project Type**: Developer tooling / workflow automation +**Performance Goals**: N/A — no runtime performance impact on the application +**Constraints**: All changes must be backward-compatible with existing speckit workflow; agents must gracefully degrade when GitHub MCP is unavailable +**Scale/Scope**: ~14 files modified or created; zero application source code changes + +## Constitution Check + +*GATE: Must pass before Phase 0 research. Re-check after Phase 1 design.* + +| Principle | Status | Notes | +|-----------|--------|-------| +| I. Integration Modularity | ✅ Pass | No integration adapter code touched | +| II. Minimalism-First | ✅ Pass | All changes are in speckit tooling only; no new UI surfaces | +| III. Security & Privacy | ✅ Pass | No token handling or user data involved; hook logs are local-only and gitignored | +| IV. Test Coverage Required | ✅ Pass | No new application logic; agent/skill changes are markdown/shell — no test suite change required | +| V. Simplicity & Deferred Decisions | ✅ Pass | No new dependencies; changes use existing Copilot CLI primitives | +| VI. Spec-Kit Workflow | ✅ Pass | This feature *is* the spec-kit workflow update; it advances the workflow itself | + +**No violations. No Complexity Tracking required.** + +## Project Structure + +### Documentation (this feature) + +```text +specs/020-speckit-workflow/ +├── plan.md ← this file +├── research.md ← Phase 0 output (no unknowns; see below) +├── data-model.md ← Phase 1 output (stack.md template schema) +└── tasks.md ← Phase 2 output (/speckit.tasks — not created here) +``` + +### Files Changed / Created by This Feature + +```text +# Agent definitions (modified) +.github/agents/ +├── speckit.specify.agent.md ← add: issue-triage guard, multi-issue, MCP check, session reminder, github-issues skill, stack check, conventional-commit skill +├── speckit.plan.agent.md ← add: explicit context loading, context-map skill, conventional-commit skill +├── speckit.tasks.agent.md ← add: explicit context loading, conventional-commit skill +├── speckit.implement.agent.md ← add: context-map skill, regression tests, spec status update, github-issues skill (PR), conventional-commit skill +├── speckit.analyze.agent.md ← add: drift detection, spec status update, conventional-commit skill +├── speckit.clarify.agent.md ← add: conventional-commit skill +└── speckit.checklist.agent.md ← add: conventional-commit skill + +# Skill definitions (modified) +.github/skills/ +└── conventional-commit/ + └── SKILL.md ← update: add pre-commit summary + confirmation gate (FR-040); remove "no confirmation needed" auto-commit + +# Hook scripts (modified) +.github/hooks/session-logger/ +├── log-session-start.sh ← add: .gitignore guard; speckit branch detection + context summary log +├── log-session-end.sh ← add: .gitignore guard; uncommitted speckit artifact warning +└── log-prompt.sh ← fix: copy-paste bug (currently clone of log-session-end.sh); add speckit phase command detection + +# Templates (created) +.specify/templates/ +└── stack-template.md ← CREATE: versioned standard fields schema for stack.md + +# Config (modified) +.github/copilot-instructions.md ← replace abridged constitution section with pointer; add speckit workflow reference + +# Repo root +.gitignore ← add: logs/ entry +``` + +## Phase 0: Research + +No NEEDS CLARIFICATION markers identified. All technical decisions are resolved from existing codebase inspection: + +**Decision 1 — Pre-commit summary pattern (FR-040)** +- Decision: Conversational confirmation step added to `conventional-commit` SKILL.md before `git commit` runs +- Rationale: Copilot CLI YOLO mode bypasses tool execution prompts but not model-to-user conversational questions; placing the summary+confirm in the skill's instruction text makes it immune to YOLO +- Alternative rejected: Adding a shell `read` in the commit script — would not work in all TTY contexts and would be bypassable + +**Decision 2 — Hook prerequisite guard strategy (FR-033)** +- Decision: Each hook script checks for `logs/` in `.gitignore` using `grep -q '^logs/' .gitignore` and for directory existence before writing +- Rationale: Idiomatic Bash, no new dependencies; `jq` already used in `log-session-start.sh` +- Alternative rejected: Relying on README instructions alone — too easy to miss on new machine setup + +**Decision 3 — Speckit branch detection in hooks (FR-032)** +- Decision: Detect speckit branch with `git branch --show-current | grep -E '^[0-9]+-'`; extract spec name from `specs/$(git branch --show-current)/spec.md` Status line +- Rationale: Zero new dependencies; branch naming convention is already enforced + +**Decision 4 — Drift detection approach (FR-019)** +- Decision: `git diff $(git log --oneline --reverse | head -1 | cut -d' ' -f1)..HEAD -- specs/NNN-*/spec.md specs/NNN-*/plan.md specs/NNN-*/tasks.md` +- Rationale: Uses git-native diff scoped to spec artifact paths; no semantic analysis of source code + +**Decision 5 — stack-template.md schema** +- Decision: Versioned YAML-like markdown with a `schema_version` field + standard sections: Packaging, Version Constraints, Linting, Testing, Build, Infrastructure, Database, Project Type +- Rationale: Matches existing `stack.md` structure exactly; version field enables future field additions without full re-prompting + +## Phase 1: Design + +### Data Model — stack-template.md Schema + +The `stack-template.md` defines the canonical field set for any project's `stack.md`. It is versioned so new fields can be appended without invalidating existing entries. + +**Standard Fields (v1.0)** + +| Section | Fields | Required | Auto-detectable | +|---------|--------|----------|----------------| +| Meta | `schema_version`, `last_updated`, `updated_by` | Yes | Partial | +| Packaging | `tool`, `workspace_file`, `lock_file`, `install_cmd`, `add_dep_cmd` | Yes | Yes — detect from lock file | +| Version Constraints | `node_version`, `package_manager_version`, `language_version` | No | Yes — from `package.json` engines | +| Linting | `tool`, `config_file`, `lint_cmd`, `fix_cmd` | Yes | Yes — from config files | +| Testing | `backend_framework`, `backend_run_cmd`, `frontend_unit_cmd`, `frontend_e2e_cmd` | Yes | Yes — from `package.json` scripts | +| Build | `build_cmd` | Yes | Yes | +| Infrastructure | `local_dev_cmd`, `required_services` | No | Partial | +| Database | `orm`, `schema_file`, `migrate_cmd`, `generate_cmd` | No | Yes — if Prisma detected | +| Project Type | `type` (web-service / mobile-app / library / cli / desktop-app) | Yes | Yes — from repo structure | +| Commit Convention | `format`, `phase_commit_formats` | Yes | No — copied from constitution | +| Regression Tests | `lint_cmd`, `test_cmd`, `e2e_cmd`, `e2e_requires` | Yes | Yes | + +**Version upgrade path**: When `schema_version` in an existing `stack.md` is lower than the template's current version, the speckit workflow prompts only for missing fields and appends them. Existing fields are never overwritten. + +### Agent Change Design + +Each agent gets a standardized preamble block and a phase-end commit block: + +**Context Loading Preamble** (for all resuming agents: plan, tasks, implement, analyze): +``` +## Context Loading (run at startup before any output) +1. Read `.specify/memory/constitution.md` +2. Read `.specify/memory/stack.md` (if present; surface missing-stack warning if absent) +3. Read current spec's `spec.md` +4. Read any existing phase artifacts (plan.md, tasks.md) if present +5. Output a one-line context summary: "Loaded: [spec name] | Status: [status] | Stack: [tool]" +``` + +**Phase-End Commit Block** (for all 7 phases): +``` +## Phase Commit (run at end of phase if artifacts changed) +1. Run `git status --short` scoped to spec artifact paths +2. If no changes: skip commit, report "No changes to commit" +3. If changes: invoke `conventional-commit` skill + - Skill presents: staged files list + generated message + - Await developer confirmation + - On confirm: commit; On decline: abort phase, do not mark complete +``` + +**speckit.specify additions**: +- Session boundary reminder at top (non-blocking if prior history detected) +- MCP connectivity check → run issue-triage agent if reachable, else warn + skip +- Multi-issue selection → write all to `GitHub Issue` field as `#N, #N` list +- Stack check → if `stack.md` absent, offer auto-detect vs manual entry +- Post-spec: `github-issues` skill posts branch+spec link comment on each linked issue + +**speckit.implement additions**: +- Per task-group: invoke `context-map` skill before editing files +- Post all tasks complete: run regression tests (`pnpm lint && pnpm test`) +- Update spec.md Status → Implemented +- `github-issues` skill: create PR with `Closes #N` for all linked issues; post PR URL comment + +**speckit.analyze additions**: +- Drift detection: `git diff ..HEAD -- specs/020-*/spec.md plan.md tasks.md` +- Present diff → confirm per artifact → update or skip +- Flag unresolved plan.md/tasks.md items (never implemented, not deferred) +- Update spec.md Status → Analyzed + +### conventional-commit Skill Change Design + +Current step 5 reads: *"Copilot will automatically run the following command… (no confirmation needed)"* + +New step 5: +``` +5. Present a pre-commit summary to the developer: + - List of files staged (from `git status --short`) + - Generated commit message (type, scope, description, body if any) + Ask: "Proceed with this commit? (yes/no)" + - On YES: run `git commit -m "..."` + - On NO: do not commit; inform developer the phase is not marked complete +``` + +This is a conversational prompt, not a shell command — it is unaffected by YOLO/auto-approve mode. + +## Complexity Tracking + +No violations. All changes use existing file types (Markdown, Bash) and existing Copilot CLI extension primitives. No new infrastructure, dependencies, or patterns introduced. diff --git a/specs/020-speckit-workflow/research.md b/specs/020-speckit-workflow/research.md new file mode 100644 index 0000000..ca8d83d --- /dev/null +++ b/specs/020-speckit-workflow/research.md @@ -0,0 +1,111 @@ +# Research: Spec-Kit Workflow Update + +**Feature**: 020-speckit-workflow +**Status**: Complete — no NEEDS CLARIFICATION markers in spec; all decisions resolved via codebase inspection + +--- + +## Summary + +No external research required. All decisions were resolved through direct inspection of existing files in the repository. The five key decisions and their rationale are documented below. + +--- + +## Decision 1 — Pre-commit Summary Guard (FR-040) + +**Decision**: Add a conversational confirmation step to `conventional-commit` SKILL.md that presents staged files + generated message and awaits explicit "yes/no" before running `git commit`. + +**Rationale**: The Copilot CLI's YOLO/auto-approve mode bypasses **tool execution** prompts (bash commands, file edits) but does NOT bypass **conversational** questions the model directs to the developer. By placing the summary+confirm step as a model-to-user message (not a shell script), the guard is immune to YOLO mode. + +**Finding from codebase**: `.github/skills/conventional-commit/SKILL.md` step 5 currently reads: *"Copilot will automatically run the following command… (no confirmation needed)"* — this directly contradicts FR-040 and must be updated. + +**Alternatives considered**: +- Shell `read` prompt in commit script — rejected: unreliable across TTY contexts; bypassable +- Separate confirmation hook — rejected: adds complexity; conversational prompt is sufficient + +--- + +## Decision 2 — Hook Prerequisite Guard (FR-033) + +**Decision**: Each hook script guards with: +```bash +if ! grep -q '^logs/' .gitignore 2>/dev/null; then + echo "⚠️ speckit-setup: add 'logs/' to .gitignore before session logging is active" + exit 0 +fi +if [ ! -d "logs/copilot" ]; then + mkdir -p logs/copilot +fi +``` + +**Rationale**: `jq` is already used in `log-session-start.sh`; no new tool dependencies. The guard emits a one-time actionable message and exits cleanly (exit 0) so the hook doesn't block CLI startup. + +**Finding from codebase**: `.gitignore` has no `logs/` entry today. Running hooks without this guard would create `logs/copilot/` as an untracked directory visible in `git status`, risking accidental commits of session log data. + +--- + +## Decision 3 — Speckit Branch Detection in Hooks (FR-032) + +**Decision**: +```bash +BRANCH=$(git branch --show-current 2>/dev/null) +if echo "$BRANCH" | grep -qE '^[0-9]+-'; then + SPEC_FILE="specs/$BRANCH/spec.md" + SPEC_STATUS=$(grep '^\\*\\*Status\\*\\*:' "$SPEC_FILE" 2>/dev/null | sed 's/.*: //') + LAST_PHASE=$(git log --oneline --grep='docs(spec\|plan\|tasks\|analyze):' -1 --format='%s' 2>/dev/null) +fi +``` + +**Rationale**: Uses only `git` and `grep` — no new dependencies. Branch naming convention (`NNN-short-name`) is already enforced by `create-new-feature.sh`. Status line in spec.md follows the established `**Status**: Draft` format. + +--- + +## Decision 4 — Drift Detection (FR-019) + +**Decision**: +```bash +# Find branch creation commit +BASE_COMMIT=$(git log --oneline --reverse HEAD | head -1 | cut -d' ' -f1) +# Diff spec artifacts +git diff $BASE_COMMIT..HEAD -- specs/$BRANCH/spec.md specs/$BRANCH/plan.md specs/$BRANCH/tasks.md +``` + +**Rationale**: Git-native; scoped to spec artifact paths only; no semantic source code analysis. The "branch creation commit" is reliably the first commit on the branch (first in reverse log). + +**Edge case handled**: If no spec artifacts exist at branch creation (blank template only), the diff is empty — no false drift detected. + +--- + +## Decision 5 — stack-template.md Schema Design + +**Decision**: Single Markdown file with YAML-like field blocks, a `schema_version` semver header, and standard sections matching the structure of the existing `stack.md`. Fields tagged as auto-detectable use heuristics (lock file presence, package.json scripts, config file names) with manual fallback. + +**Rationale**: The existing `.specify/memory/stack.md` (created in constitution v1.1.0) already has the right structure — the template codifies it with version tracking and detection metadata. YAML-in-Markdown is consistent with the rest of the `.specify/` templates. + +**Schema version 1.0** covers all fields currently in `stack.md`. Future extensions increment to 1.1, 1.2, etc. with non-breaking field additions. + +--- + +## Codebase Inventory (relevant files) + +| File | Exists | Change required | +|------|--------|----------------| +| `.github/agents/speckit.specify.agent.md` | ✅ | Add: issue-triage guard, multi-issue, session reminder, github-issues skill, stack check, conventional-commit skill | +| `.github/agents/speckit.plan.agent.md` | ✅ | Add: context loading preamble, context-map skill, conventional-commit skill | +| `.github/agents/speckit.tasks.agent.md` | ✅ | Add: context loading preamble, conventional-commit skill | +| `.github/agents/speckit.implement.agent.md` | ✅ | Add: context-map skill, regression tests, status update, github-issues PR skill, conventional-commit skill | +| `.github/agents/speckit.analyze.agent.md` | ✅ | Add: drift detection, status update, conventional-commit skill | +| `.github/agents/speckit.clarify.agent.md` | ✅ | Add: conventional-commit skill | +| `.github/agents/speckit.checklist.agent.md` | ✅ | Add: conventional-commit skill | +| `.github/agents/issue-triage.agent.md` | ✅ | No change — invoked as-is from speckit.specify | +| `.github/skills/conventional-commit/SKILL.md` | ✅ | Update: add pre-commit summary + confirmation; remove auto-commit | +| `.github/skills/context-map/SKILL.md` | ✅ | No change — invoked as-is from speckit.plan + speckit.implement | +| `.github/skills/github-issues/SKILL.md` | ✅ | No change — invoked as-is from speckit.specify + speckit.implement | +| `.github/hooks/session-logger/log-session-start.sh` | ✅ | Add: gitignore guard, speckit branch detection + summary log | +| `.github/hooks/session-logger/log-session-end.sh` | ✅ | Add: gitignore guard, uncommitted artifact warning | +| `.github/hooks/session-logger/log-prompt.sh` | ✅ | Fix: copy-paste bug; add speckit phase command detection | +| `.github/copilot-instructions.md` | ✅ | Replace abridged constitution with pointer; add speckit workflow reference | +| `.github/instructions/issue-triage.instructions.md` | ❌ Already deleted | No action needed | +| `.specify/templates/stack-template.md` | ❌ Missing | CREATE: versioned standard fields template | +| `.specify/memory/stack.md` | ✅ | No change — already populated for this project | +| `.gitignore` | ✅ | Add: `logs/` entry | diff --git a/specs/020-speckit-workflow/spec.md b/specs/020-speckit-workflow/spec.md index 2887222..84d7a1c 100644 --- a/specs/020-speckit-workflow/spec.md +++ b/specs/020-speckit-workflow/spec.md @@ -2,7 +2,7 @@ **Feature Branch**: `020-speckit-workflow` **Created**: 2026-03-22 -**Status**: Draft +**Status**: Planned **GitHub Issue**: [#31](https://github.com/jwill824/ordrctrl/issues/31) **Input**: Update our spec-kit workflow to integrate with GitHub, enforce constitution hygiene, add stack-awareness to agents/skills, and improve commit/PR automation across all speckit phases. From ed74d5a9fa2193e7e781f826243ed6c3e02057ee Mon Sep 17 00:00:00 2001 From: Jeff Williams Date: Sun, 22 Mar 2026 20:46:07 -0400 Subject: [PATCH 09/15] docs(tasks): generate task list for 020-speckit-workflow (#31) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 42 tasks across 12 phases covering all 9 user stories. Advance spec Status: Planned → Tasked. Phase 1-2: setup (.gitignore, stack-template) + foundational (conventional-commit guard, copilot-instructions pointer) Phase 3: US1 P1 - GitHub issue triage guard + multi-issue + traceability (T005-T008) Phase 4-5: US2/US3 P2 - per-phase commits in all 7 agents + auto status advancement (T009-T018) Phase 6: US8 P2 - session lifecycle, hook fixes, context loading preambles (T019-T026) Phase 7-11: US4-US9 P3 - stack-aware agents, backlog refresh, drift detection, portability (T027-T039) Phase 12: polish + verification (T040-T042) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- specs/020-speckit-workflow/spec.md | 2 +- specs/020-speckit-workflow/tasks.md | 258 ++++++++++++++++++++++++++++ 2 files changed, 259 insertions(+), 1 deletion(-) create mode 100644 specs/020-speckit-workflow/tasks.md diff --git a/specs/020-speckit-workflow/spec.md b/specs/020-speckit-workflow/spec.md index 84d7a1c..a957e5a 100644 --- a/specs/020-speckit-workflow/spec.md +++ b/specs/020-speckit-workflow/spec.md @@ -2,7 +2,7 @@ **Feature Branch**: `020-speckit-workflow` **Created**: 2026-03-22 -**Status**: Planned +**Status**: Tasked **GitHub Issue**: [#31](https://github.com/jwill824/ordrctrl/issues/31) **Input**: Update our spec-kit workflow to integrate with GitHub, enforce constitution hygiene, add stack-awareness to agents/skills, and improve commit/PR automation across all speckit phases. diff --git a/specs/020-speckit-workflow/tasks.md b/specs/020-speckit-workflow/tasks.md new file mode 100644 index 0000000..2916438 --- /dev/null +++ b/specs/020-speckit-workflow/tasks.md @@ -0,0 +1,258 @@ +# Tasks: Spec-Kit Workflow Update + +**Input**: Design documents from `/specs/020-speckit-workflow/` +**Branch**: `020-speckit-workflow` | **Spec**: [spec.md](./spec.md) | **Plan**: [plan.md](./plan.md) +**Prerequisites**: ✅ spec.md, ✅ plan.md, ✅ research.md, ✅ data-model.md + +> **Scope**: Pure tooling — zero application source code changes. All changes target `.github/`, `.specify/`, and `.gitignore`. + +--- + +## Format: `[ID] [P?] [Story] Description` + +- **[P]**: Can run in parallel (independent files, no blocking deps) +- **[USN]**: User story this task belongs to +- All file paths are repo-root-relative + +--- + +## Phase 1 — Setup + +> Initialize shared infrastructure required by all phases. + +**Goal**: `.gitignore` guards session logs; `stack-template.md` schema exists for stack-aware agents. + +- [ ] T001 Add `logs/` entry to `.gitignore` (repo root) so session-logger output is never committed +- [ ] T002 [P] Create `.specify/templates/stack-template.md` with schema v1.0 per `data-model.md` — include all 11 sections (Meta, Packaging, Version Constraints, Linting, Testing, Build, Infrastructure, Database, Project Type, Commit Convention, Regression Tests), `schema_version: "1.0"` header, auto-detectable flags, and version upgrade procedure note + +--- + +## Phase 2 — Foundational + +> Changes that all user-story phases depend on. Must complete before Phases 3+. + +**Goal**: Pre-commit summary guard active; `copilot-instructions.md` no longer contains stale abridged constitution. + +- [ ] T003 Update `.github/skills/conventional-commit/SKILL.md` — replace step 5 "no confirmation needed / auto-runs git commit" with a conversational pre-commit summary step: show staged files + generated message, ask "Proceed with this commit? (yes/no)"; on YES run `git commit`; on NO abort and inform developer phase is not marked complete +- [ ] T004 [P] Update `.github/copilot-instructions.md` — remove the "Constitution Principles (abridged)" section (I–V only, stale); replace with a pointer: `> Full constitution and workflow principles: [`.specify/memory/constitution.md`](.specify/memory/constitution.md)`; add one-line speckit workflow reference below it + +--- + +## Phase 3 — US1 · GitHub Issue Traceability (P1) + +> **Story**: As a developer, when I run `/speckit.specify`, the agent automatically runs issue triage, links one or more GitHub issues to the spec, and posts traceability comments back to those issues. + +**Independent test criteria**: +- Running `/speckit.specify` on a fresh branch triggers issue-triage guard before writing spec.md +- Multiple issue numbers are written to spec.md `GitHub Issue` field as `#N, #N` comma list +- After spec.md is saved, a comment appears on each linked GitHub issue + +**Tasks**: + +- [ ] T005 [US1] Update `.github/agents/speckit.specify.agent.md` — add session boundary check at top: if prior session history detected, surface a non-blocking reminder ("New session recommended per US8 — continue or start fresh?") +- [ ] T006 [US1] Update `.github/agents/speckit.specify.agent.md` — add issue-triage guard block: (1) attempt GitHub MCP connectivity check; (2) if reachable, invoke `issue-triage` agent and await selection; (3) if unreachable, warn and allow manual issue number entry; (4) write all selected issue numbers to spec.md `GitHub Issue` front-matter field as comma-separated `#N, #N` list +- [ ] T007 [P] [US1] Update `.github/agents/speckit.specify.agent.md` — after spec.md is written and committed, invoke `github-issues` skill to post a traceability comment on **each** linked issue: include branch name, spec title, and link to spec.md in the repo +- [ ] T008 [P] [US1] Update `.github/agents/speckit.implement.agent.md` — after all tasks complete, invoke `github-issues` skill to: (1) create PR with `Closes #N` for every issue in spec.md `GitHub Issue` field; (2) post PR URL as comment on each linked issue + +--- + +## Phase 4 — US2 · Per-Phase Conventional Commits (P2) + +> **Story**: As a developer, every speckit phase agent commits its output artifact(s) using the `conventional-commit` skill with a pre-commit summary, so the git history is always in sync with spec progress. + +**Independent test criteria**: +- After each speckit agent completes its phase, `git log --oneline` shows a new commit scoped to that phase +- Running any agent with no artifact changes produces "No changes to commit" (no empty commits) +- The conventional-commit skill presents staged files + message before committing + +**Tasks**: + +- [ ] T009 [US2] Update `.specify/memory/constitution.md` — add to Principle VI (Spec-Kit Workflow): "Every speckit phase MUST end with a `conventional-commit` skill invocation. Phase commits follow the format `docs(): (#)`." +- [ ] T010 [US2] Update `.github/agents/speckit.specify.agent.md` — add Phase-End Commit Block: (1) run `git status --short` scoped to `specs/$BRANCH/`; (2) if no changes skip with "No changes to commit"; (3) if changes, invoke `conventional-commit` skill; type=`docs`, scope=`spec`, include issue numbers in footer +- [ ] T011 [P] [US2] Update `.github/agents/speckit.clarify.agent.md` — add Phase-End Commit Block (same pattern as T010; scope=`clarify`) +- [ ] T012 [P] [US2] Update `.github/agents/speckit.plan.agent.md` — add Phase-End Commit Block (scope=`plan`) +- [ ] T013 [P] [US2] Update `.github/agents/speckit.tasks.agent.md` — add Phase-End Commit Block (scope=`tasks`) +- [ ] T014 [P] [US2] Update `.github/agents/speckit.checklist.agent.md` — add Phase-End Commit Block (scope=`checklist`) +- [ ] T015 [P] [US2] Update `.github/agents/speckit.analyze.agent.md` — add Phase-End Commit Block (scope=`analyze`) +- [ ] T016 [P] [US2] Update `.github/agents/speckit.implement.agent.md` — add Phase-End Commit Block (scope=`implement`); note: implement may produce multiple commits per task group — each group gets its own commit via `conventional-commit` skill + +--- + +## Phase 5 — US3 · Automatic Spec Status Advancement (P2) + +> **Story**: As a developer, spec.md `Status` is automatically advanced at the end of each phase so it always reflects the true workflow state without manual edits. + +**Independent test criteria**: +- After `/speckit.implement` completes, spec.md `Status` reads `Implemented` +- After `/speckit.analyze` completes, spec.md `Status` reads `Analyzed` +- Status advancement is included in the phase-end commit (not a separate commit) + +**Tasks**: + +- [ ] T017 [US3] Update `.github/agents/speckit.implement.agent.md` — before Phase-End Commit Block (T016), add status advancement step: update spec.md `**Status**:` line from `Tasked` → `Implementing` at start, then → `Implemented` on completion; include status change in the phase-end commit +- [ ] T018 [P] [US3] Update `.github/agents/speckit.analyze.agent.md` — before Phase-End Commit Block (T015), add status advancement step: update spec.md `**Status**:` line → `Analyzed` on completion; include in phase-end commit + +--- + +## Phase 6 — US8 · Session Lifecycle Management (P2) + +> **Story**: As a developer, the session-logger hooks are reliable and self-guarding, each speckit phase explicitly loads prior context at startup, and the workflow enforces fresh sessions for new specs. + +**Independent test criteria**: +- Running any hook script when `logs/` is absent from `.gitignore` prints a setup warning and exits cleanly (exit 0) +- `log-prompt.sh` writes prompt content to `logs/copilot/` (not a "sessionEnd" event) +- On a speckit branch, `log-session-start.sh` logs spec name + status in the session JSON +- Each resuming agent (plan, tasks, implement, analyze) prints a one-line context summary at startup + +**Tasks**: + +- [ ] T019 [US8] Fix `.github/hooks/session-logger/log-prompt.sh` — rewrite to actually capture prompt content: log a JSON object with `event: "userPromptSubmitted"`, `prompt` text, `timestamp`, and `branch`; remove copy-pasted "sessionEnd" event code +- [ ] T020 [US8] Update `.github/hooks/session-logger/log-session-start.sh` — add `.gitignore` guard at top (check `grep -q '^logs/' .gitignore`); if missing, print `⚠️ speckit-setup: add 'logs/' to .gitignore` and `exit 0`; add `mkdir -p logs/copilot` guard +- [ ] T021 [P] [US8] Update `.github/hooks/session-logger/log-session-end.sh` — add same `.gitignore` guard (T020 pattern); add speckit branch detection: if on a `NNN-*` branch with uncommitted changes to `specs/$BRANCH/`, append `⚠️ uncommitted spec artifacts detected` warning to session log +- [ ] T022 [P] [US8] Update `.github/hooks/session-logger/log-session-start.sh` — add speckit branch detection block: extract `BRANCH`, check for `specs/$BRANCH/spec.md`, read `**Status**:` line, log `speckit_context: { spec, status, last_phase }` into session-start JSON +- [ ] T023 [US8] Update `.github/agents/speckit.specify.agent.md` — add fresh-session enforcement reminder at very top (above issue-triage guard): "This agent should run in a new Copilot CLI session. If you have prior conversation history, start a new session before proceeding." +- [ ] T024 [P] [US8] Update `.github/agents/speckit.plan.agent.md` — add Context Loading Preamble as first numbered section: (1) Read `.specify/memory/constitution.md`; (2) Read `.specify/memory/stack.md` — warn if absent; (3) Read `spec.md`; (4) Output one-line summary: `Loaded: [spec name] | Status: [status] | Stack: [tool]` +- [ ] T025 [P] [US8] Update `.github/agents/speckit.tasks.agent.md` — add same Context Loading Preamble (T024 pattern): read constitution.md, stack.md, spec.md, plan.md; output context summary line +- [ ] T026 [P] [US8] Update `.github/agents/speckit.implement.agent.md` — add Context Loading Preamble (T024 pattern): read constitution.md, stack.md, spec.md, plan.md, tasks.md; output context summary line + +--- + +## Phase 7 — US4 · Stack-Aware Agents (P3) + +> **Story**: As a developer, speckit agents read a versioned `stack-template.md` schema to auto-detect or prompt for the project stack, storing results in `.specify/memory/stack.md` so all subsequent agents have consistent stack context. + +**Independent test criteria**: +- `/speckit.specify` run on a project without `stack.md` offers auto-detect or manual-entry flow +- `.specify/memory/stack.md` written by specify contains all required v1.0 fields +- plan, tasks, implement, analyze agents each print the stack context line at startup + +**Tasks**: + +- [ ] T027 [US4] Update `.github/agents/speckit.specify.agent.md` — add stack check block after issue-triage guard: (1) check if `.specify/memory/stack.md` exists; (2) if absent, read `.specify/templates/stack-template.md` schema; (3) offer two options — "Auto-detect from repo" (inspect lock files, package.json, config files) or "Manual entry"; (4) write populated `stack.md` using template field order and `schema_version: "1.0"`; (5) if present but `schema_version` < template version, prompt only for missing fields +- [ ] T028 [P] [US4] Update `.github/agents/speckit.plan.agent.md` — in Context Loading Preamble (T024), after reading stack.md, surface tech-specific notes: e.g. if `testing.backend_framework = vitest`, reference vitest patterns in plan; if `database.orm = prisma`, note migration steps +- [ ] T029 [P] [US4] Update `.github/agents/speckit.tasks.agent.md` — in Context Loading Preamble (T025), after reading stack.md, use `regression_tests` section to populate task descriptions with correct lint/test commands from stack.md rather than hardcoded values +- [ ] T030 [P] [US4] Update `.github/agents/speckit.implement.agent.md` — in Context Loading Preamble (T026), after reading stack.md, use `regression_tests.lint_cmd` and `regression_tests.test_cmd` for post-implementation validation steps; use `packaging.install_cmd` for dependency install instructions +- [ ] T031 [P] [US4] Update `.github/agents/speckit.analyze.agent.md` — add Context Loading Preamble (T024 pattern): read constitution.md, stack.md, spec.md, plan.md, tasks.md; output context summary; use stack.md `regression_tests` section to validate that implementation tasks referenced correct commands + +--- + +## Phase 8 — US5 · Issues Backlog Refresh (P3) + +> **Story**: As a developer, running `/speckit.specify` on an existing branch refreshes the `issues-backlog.md` snapshot so issue selection is always up-to-date. + +**Independent test criteria**: +- Running `/speckit.specify` on a branch that already has a spec.md updates `issues-backlog.md` timestamp +- If GitHub MCP is unreachable, the existing `issues-backlog.md` is preserved and a warning is shown + +**Tasks**: + +- [ ] T032 [US5] Update `.github/agents/speckit.specify.agent.md` — after MCP connectivity check (T006), add backlog refresh step: if MCP reachable, invoke `issue-triage` agent in refresh mode and overwrite `.specify/memory/issues-backlog.md` with current open issues snapshot + `last_refreshed` timestamp; if MCP unreachable, read existing `issues-backlog.md` and note its age + +--- + +## Phase 9 — US6 · Paradigm Shift Detection (P3) + +> **Story**: As a developer, speckit agents detect when a proposed change would require updating foundational templates (constitution, stack template, agent templates) and prompt explicitly before proceeding. + +**Independent test criteria**: +- Specifying a feature that adds a new required stack field triggers a template-sync prompt +- speckit.clarify detects constitution-level changes and surfaces them before writing + +**Tasks**: + +- [ ] T033 [US6] Update `.github/agents/speckit.specify.agent.md` — add paradigm shift detection block before writing spec.md: scan spec content for signals of stack changes (new language/framework, new ORM, new test runner) or workflow changes (new phase, new commit format); if detected, present: "This spec may require updating `.specify/templates/stack-template.md` or `.specify/memory/constitution.md` — review before proceeding (yes/no)" +- [ ] T034 [P] [US6] Update `.github/agents/speckit.clarify.agent.md` — add Context Loading Preamble (T024 pattern) and paradigm shift check: if clarification answers change core architecture (project type, ORM, packaging tool), flag that `stack.md` and `stack-template.md` may need updating; surface this as a clarification output item before phase-end commit + +--- + +## Phase 10 — US7 · Spec Artifact Drift Detection (P3) + +> **Story**: As a developer, `/speckit.analyze` compares spec.md, plan.md, and tasks.md against the branch-creation baseline and surfaces any mismatches so docs stay in sync with what was actually built. + +**Independent test criteria**: +- `/speckit.analyze` run after implementation changes shows a diff of spec artifacts vs branch-creation commit +- Unresolved tasks (in tasks.md, never referenced in a commit) are flagged +- Developer is prompted per artifact to accept or skip each update + +**Tasks**: + +- [ ] T035 [US7] Update `.github/agents/speckit.analyze.agent.md` — add drift detection block before status advancement (T018): (1) find branch-creation commit with `git log --oneline --reverse HEAD | head -1 | cut -d' ' -f1`; (2) run `git diff $BASE_COMMIT..HEAD -- specs/$BRANCH/spec.md specs/$BRANCH/plan.md specs/$BRANCH/tasks.md`; (3) if diff is empty, report "No spec artifact drift detected" +- [ ] T036 [US7] Update `.github/agents/speckit.analyze.agent.md` — add drift report presentation: for each artifact with changes, show a structured diff summary (sections added/removed/changed) and prompt: "Update [artifact] to reflect implementation changes? (yes/skip)"; on yes, assist developer in editing that artifact; on skip, continue +- [ ] T037 [P] [US7] Update `.github/agents/speckit.analyze.agent.md` — add unresolved-item check: scan tasks.md for unchecked items (`- [ ]`); cross-reference with `git log --oneline` for task-related commits; flag any tasks with no corresponding commit as "possibly unimplemented or not deferred — confirm status" + +--- + +## Phase 11 — US9 · Portability Contract (P3) + +> **Story**: As a developer, speckit tooling is cleanly separated from project-specific context so it can be bootstrapped into any new repository with a single script. + +**Independent test criteria**: +- `bootstrap.sh` runs on a fresh repo and creates the full `.github/` and `.specify/` directory structure +- `PORTABILITY.md` clearly lists which files are generic tooling vs project-specific + +**Tasks**: + +- [ ] T038 [US9] Create `docs/speckit-portability.md` — document the portability contract: list all generic speckit files (agents, skills, hooks, templates) vs project-specific files (constitution.md, stack.md, copilot-instructions.md); include instructions for applying speckit to a new repo; note that user-level Copilot CLI extensions directory enables global installation without per-repo file copies +- [ ] T039 [P] [US9] Create `.specify/scripts/bash/bootstrap.sh` — script that initializes the full speckit structure in a target repo: creates `.github/agents/`, `.github/skills/`, `.github/hooks/`, `.specify/memory/`, `.specify/templates/`, `.specify/scripts/`; copies generic agent/skill/hook files; adds `logs/` to `.gitignore`; prints next-steps instructions for creating constitution.md and stack.md + +--- + +## Phase 12 — Polish & Verification + +> Verify all changed files are consistent, no broken references, and the workflow is end-to-end coherent. + +- [ ] T040 Run `pnpm lint` from repo root and confirm zero new errors introduced by any markdown/shell changes +- [ ] T041 [P] Verify all 7 speckit agent files contain: (1) Context Loading Preamble, (2) Phase-End Commit Block referencing `conventional-commit` skill — open each `.github/agents/speckit.*.agent.md` and confirm presence +- [ ] T042 [P] Verify all 3 hook scripts contain `.gitignore` guard — open each `.github/hooks/session-logger/*.sh` and confirm `grep -q '^logs/' .gitignore` guard is present at top of each; verify `log-prompt.sh` logs `userPromptSubmitted` event (not `sessionEnd`) + +--- + +## Dependency Graph + +``` +Phase 1 (T001, T002) + └─► Phase 2 (T003, T004) ← blocks all user-story phases + ├─► Phase 3 US1 (T005–T008) P1 — start here + ├─► Phase 4 US2 (T009–T016) P2 + │ └─ T009 (constitution) must precede T010–T016 (agents) + ├─► Phase 5 US3 (T017–T018) P2 — depends on Phase 4 (commit blocks must exist) + ├─► Phase 6 US8 (T019–T026) P2 + │ └─ T019–T022 (hooks) parallelizable; T023–T026 (agents) parallelizable + ├─► Phase 7 US4 (T027–T031) P3 — T027 (specify) must precede T028–T031 + ├─► Phase 8 US5 (T032) P3 — depends on Phase 3 (MCP guard in specify) + ├─► Phase 9 US6 (T033–T034) P3 + ├─► Phase 10 US7 (T035–T037) P3 — T035 must precede T036, T037 + ├─► Phase 11 US9 (T038–T039) P3 — independent + └─► Phase 12 Polish (T040–T042) — after all phases complete +``` + +**US priority execution order**: US1 → US2 → US3 → US8 → US4 → US5 → US6 → US7 → US9 + +--- + +## Parallel Execution Opportunities + +| Phase | Parallelizable tasks | +|-------|----------------------| +| Phase 1 | T001 ‖ T002 | +| Phase 4 | T011 ‖ T012 ‖ T013 ‖ T014 ‖ T015 ‖ T016 (after T009–T010) | +| Phase 6 | T020 ‖ T021 ‖ T022 (hooks); T024 ‖ T025 ‖ T026 (agents) | +| Phase 7 | T028 ‖ T029 ‖ T030 ‖ T031 (after T027) | +| Phase 11 | T038 ‖ T039 | +| Phase 12 | T041 ‖ T042 | + +--- + +## Implementation Strategy + +**MVP scope (Phase 1–3 only)**: Deliver US1 (issue triage guard + multi-issue + traceability comments). This is the highest-value P1 story and validates the GitHub MCP integration path for all downstream stories. + +**Incremental delivery order**: +1. Phases 1–2 (Setup + Foundational) — unblock everything; fix the conventional-commit auto-commit bug +2. Phase 3 (US1) — P1, highest priority +3. Phases 4–6 (US2, US3, US8) — P2 stories; all agent-level changes +4. Phases 7–11 (US4–US9) — P3 stories; can be deferred without blocking P1/P2 value +5. Phase 12 (Polish) — final gate before marking spec Implemented + +**Total tasks**: 42 +**By user story**: US1=4, US2=8, US3=2, US4=5, US5=1, US6=2, US7=3, US8=8, US9=2 | Setup=2, Foundational=2, Polish=3 From e86b96ed06e74b18d32e823ccd0a68ed021264ed Mon Sep 17 00:00:00 2001 From: Jeff Williams Date: Sun, 22 Mar 2026 21:56:22 -0400 Subject: [PATCH 10/15] docs(implement): implement 020-speckit-workflow tooling updates (#31) --- .github/agents/speckit.analyze.agent.md | 66 ++++- .github/agents/speckit.checklist.agent.md | 12 + .github/agents/speckit.clarify.agent.md | 28 +- .github/agents/speckit.implement.agent.md | 49 +++- .github/agents/speckit.plan.agent.md | 25 +- .github/agents/speckit.specify.agent.md | 80 +++++- .github/agents/speckit.tasks.agent.md | 24 +- .github/copilot-instructions.md | 134 ++++++++++ .github/hooks/session-logger/log-prompt.sh | 30 ++- .../hooks/session-logger/log-session-end.sh | 33 ++- .../hooks/session-logger/log-session-start.sh | 36 ++- .github/skills/conventional-commit/SKILL.md | 13 +- .gitignore | 1 + .specify/memory/constitution.md | 90 ++++++- .specify/scripts/bash/bootstrap.sh | 203 +++++++++++++++ .specify/templates/stack-template.md | 245 ++++++++++++++++++ docs/speckit-portability.md | 116 +++++++++ specs/020-speckit-workflow/spec.md | 2 +- specs/020-speckit-workflow/tasks.md | 84 +++--- 19 files changed, 1181 insertions(+), 90 deletions(-) create mode 100644 .github/copilot-instructions.md create mode 100755 .specify/scripts/bash/bootstrap.sh create mode 100644 .specify/templates/stack-template.md create mode 100644 docs/speckit-portability.md diff --git a/.github/agents/speckit.analyze.agent.md b/.github/agents/speckit.analyze.agent.md index 98b04b0..a25affc 100644 --- a/.github/agents/speckit.analyze.agent.md +++ b/.github/agents/speckit.analyze.agent.md @@ -22,7 +22,17 @@ Identify inconsistencies, duplications, ambiguities, and underspecified items ac ## Execution Steps -### 1. Initialize Analysis Context +### 1. Context Loading (run at startup before any output) + +1. Read `.specify/memory/constitution.md` +2. Read `.specify/memory/stack.md` — if absent, warn: "⚠️ stack.md missing — stack-specific command validation will be skipped" +3. If stack.md is present, extract `regression_tests` section to use for command validation: + - `lint_cmd`, `test_cmd`, `e2e_cmd` — verify these exact commands appear in tasks.md regression steps + - If tasks.md uses different (hardcoded) commands, flag as a finding in the analysis report +4. Read current spec's `spec.md`, `plan.md`, `tasks.md` +5. Output one-line summary: `Loaded: [spec name] | Status: [status] | Stack: [packaging tool]` + +### 2. Initialize Analysis Context Run `.specify/scripts/bash/check-prerequisites.sh --json --require-tasks --include-tasks` once from repo root and parse JSON for FEATURE_DIR and AVAILABLE_DOCS. Derive absolute paths: @@ -158,10 +168,60 @@ At end of report, output a concise Next Actions block: - If only LOW/MEDIUM: User may proceed, but provide improvement suggestions - Provide explicit command suggestions: e.g., "Run /speckit.specify with refinement", "Run /speckit.plan to adjust architecture", "Manually edit tasks.md to add coverage for 'performance-metrics'" -### 8. Offer Remediation +### 8. Drift Detection + +Before advancing spec status, detect whether the implementation diverged from the original plan: + +1. **Find branch-creation commit** (approximate base): + ```bash + BASE_COMMIT=$(git log --oneline --reverse HEAD | head -1 | cut -d' ' -f1) + ``` + +2. **Compare spec artifacts against base**: + ```bash + BRANCH=$(git rev-parse --abbrev-ref HEAD) + git diff $BASE_COMMIT..HEAD -- specs/$BRANCH/spec.md specs/$BRANCH/plan.md specs/$BRANCH/tasks.md + ``` + +3. **If diff is empty**: Report "No spec artifact drift detected — artifacts match initial plan." + +4. **If diff is non-empty**: For each changed artifact, show a structured summary: + - Sections added / removed / changed (by heading) + - Prompt: "Update [artifact] to reflect implementation changes? (yes/skip)" + - On **yes**: Assist developer in editing the artifact (note: analyze is otherwise read-only, + but user-approved drift corrections are the exception) + - On **skip**: Continue to next artifact + +5. **Unresolved task check**: Scan `tasks.md` for unchecked items (`- [ ]`): + ```bash + grep -n "^- \[ \]" specs/$BRANCH/tasks.md + ``` + Cross-reference unchecked tasks with `git log --oneline` for task-related commits. + Flag any tasks with no corresponding commit as: + > "⚠️ Task [TID] has no corresponding commit — possibly unimplemented or not formally + > deferred. Confirm status before marking spec Analyzed." + +### 9. Status Advancement + +After drift detection and analysis report are complete: +- Update `spec.md` `**Status**:` line → `Analyzed` +- Include this status change in the phase-end commit + +### 10. Offer Remediation Ask the user: "Would you like me to suggest concrete remediation edits for the top N issues?" (Do NOT apply them automatically.) +## Phase-End Commit + +1. Run `git status --short` scoped to `specs/$BRANCH/` to check for changes +2. If no changes: report "No changes to commit" and skip +3. If changes exist (analysis report + status advancement): invoke the `conventional-commit` skill with: + - type: `docs` + - scope: `analyze` + - description: `add consistency report for NNN-feature-name` + - footer: issue numbers from spec.md `GitHub Issue` field (e.g., `Refs: #31`) +4. Await developer confirmation before committing (per `conventional-commit` skill workflow) + ## Operating Principles ### Context Efficiency @@ -173,7 +233,7 @@ Ask the user: "Would you like me to suggest concrete remediation edits for the t ### Analysis Guidelines -- **NEVER modify files** (this is read-only analysis) +- **NEVER modify files** (this is read-only analysis, except user-approved drift corrections) - **NEVER hallucinate missing sections** (if absent, report them accurately) - **Prioritize constitution violations** (these are always CRITICAL) - **Use examples over exhaustive rules** (cite specific instances, not generic patterns) diff --git a/.github/agents/speckit.checklist.agent.md b/.github/agents/speckit.checklist.agent.md index b7624e2..d1f8b6e 100644 --- a/.github/agents/speckit.checklist.agent.md +++ b/.github/agents/speckit.checklist.agent.md @@ -293,3 +293,15 @@ Sample items: - Correct: Validation of requirement quality - Wrong: "Does it do X?" - Correct: "Is X clearly specified?" + + +## Phase-End Commit + +1. Run `git status --short` scoped to `specs/$BRANCH/` to check for changes +2. If no changes: report "No changes to commit" and skip +3. If changes exist: invoke the `conventional-commit` skill with: + - type: `docs` + - scope: `checklist` + - description: `add [domain] checklist for NNN-feature-name` + - footer: issue numbers from spec.md `GitHub Issue` field (e.g., `Refs: #31`) +4. Await developer confirmation before committing (per `conventional-commit` skill workflow) diff --git a/.github/agents/speckit.clarify.agent.md b/.github/agents/speckit.clarify.agent.md index 657439f..599702a 100644 --- a/.github/agents/speckit.clarify.agent.md +++ b/.github/agents/speckit.clarify.agent.md @@ -22,7 +22,14 @@ Note: This clarification workflow is expected to run (and be completed) BEFORE i Execution steps: -1. Run `.specify/scripts/bash/check-prerequisites.sh --json --paths-only` from repo root **once** (combined `--json --paths-only` mode / `-Json -PathsOnly`). Parse minimal JSON payload fields: +1. **Context Loading** (run at startup before any output): + 1. Read `.specify/memory/constitution.md` + 2. Read `.specify/memory/stack.md` — if absent, warn: "⚠️ stack.md missing — run `/speckit.specify` first to initialize stack context" + 3. Read current spec's `spec.md` + 4. Read any existing phase artifacts (`plan.md`) if present + 5. Output one-line summary: `Loaded: [spec name] | Status: [status] | Stack: [packaging tool]` + +2. Run `.specify/scripts/bash/check-prerequisites.sh --json --paths-only` from repo root **once** (combined `--json --paths-only` mode / `-Json -PathsOnly`). Parse minimal JSON payload fields: - `FEATURE_DIR` - `FEATURE_SPEC` - (Optionally capture `IMPL_PLAN`, `TASKS` for future chained flows.) @@ -168,6 +175,25 @@ Execution steps: - If any Outstanding or Deferred remain, recommend whether to proceed to `/speckit.plan` or run `/speckit.clarify` again later post-plan. - Suggested next command. +9. **Paradigm Shift Check**: If any clarification answers reveal changes to core architecture + (project type, ORM, packaging tool, authentication model, test framework), surface this before + the phase-end commit: + > "⚠️ Clarification answers indicate a potential stack or architecture change. `.specify/memory/stack.md` + > and/or `.specify/templates/stack-template.md` may need updating. Flag this before proceeding? (yes/skip)" + - On **yes**: note the items in the spec's Assumptions section and add a TODO for the developer + - On **skip**: continue to phase-end commit + +10. **Phase-End Commit**: + + 1. Run `git status --short` scoped to `specs/$BRANCH/` to check for changes + 2. If no changes: report "No changes to commit" and skip + 3. If changes exist: invoke the `conventional-commit` skill with: + - type: `docs` + - scope: `clarify` + - description: `update NNN-feature-name spec with clarifications` + - footer: issue numbers from spec.md `GitHub Issue` field (e.g., `Refs: #31`) + 4. Await developer confirmation before committing (per `conventional-commit` skill workflow) + Behavior rules: - If no meaningful ambiguities found (or all potential questions would be low-impact), respond: "No critical ambiguities detected worth formal clarification." and suggest proceeding. diff --git a/.github/agents/speckit.implement.agent.md b/.github/agents/speckit.implement.agent.md index c556691..1cb01e5 100644 --- a/.github/agents/speckit.implement.agent.md +++ b/.github/agents/speckit.implement.agent.md @@ -12,7 +12,19 @@ You **MUST** consider the user input before proceeding (if not empty). ## Outline -1. Run `.specify/scripts/bash/check-prerequisites.sh --json --require-tasks --include-tasks` from repo root and parse FEATURE_DIR and AVAILABLE_DOCS list. All paths must be absolute. For single quotes in args like "I'm Groot", use escape syntax: e.g 'I'\''m Groot' (or double-quote if possible: "I'm Groot"). +1. **Context Loading** (run at startup before any output): + 1. Read `.specify/memory/constitution.md` + 2. Read `.specify/memory/stack.md` — if absent, warn: "⚠️ stack.md missing — regression test commands will fall back to defaults; run `/speckit.specify` to initialize stack context" + 3. If stack.md is present, extract for use throughout implementation: + - `regression_tests.lint_cmd` → use for post-phase lint validation + - `regression_tests.test_cmd` → use for post-phase test validation + - `regression_tests.e2e_cmd` + `regression_tests.e2e_requires` → include only if UI changes + - `packaging.install_cmd` → use for dependency install instructions in setup tasks + 4. Read current spec's `spec.md`, `plan.md`, `tasks.md` + 5. Update spec.md `**Status**:` line → `Implementing` + 6. Output one-line summary: `Loaded: [spec name] | Status: Implementing | Stack: [packaging tool]` + +2. Run `.specify/scripts/bash/check-prerequisites.sh --json --require-tasks --include-tasks` from repo root and parse FEATURE_DIR and AVAILABLE_DOCS list. All paths must be absolute. For single quotes in args like "I'm Groot", use escape syntax: e.g 'I'\''m Groot' (or double-quote if possible: "I'm Groot"). 2. **Check checklists status** (if FEATURE_DIR/checklists/ exists): - Scan all checklist files in the checklists/ directory @@ -168,4 +180,39 @@ You **MUST** consider the user input before proceeding (if not empty). - If a central doc does not exist yet and is needed, create it - If no central docs need updating (e.g. the spec was a pure refactor with no public-facing changes), skip this step and note that in the completion summary +11. **Status Advancement & PR Creation**: + + After all tasks are complete and central docs are updated: + + a. Update spec.md `**Status**:` line → `Implemented` + + b. Invoke the `github-issues` skill to create a Pull Request: + - PR title: `feat(NNN): implement NNN-feature-name` + - PR body: Include `Closes #N` for every issue number in the spec.md `GitHub Issue` field + - PR description: Brief summary of what was implemented, linking to the spec + - Example body: + ``` + Implements [NNN-feature-name](specs/NNN-feature-name/spec.md). + + Closes #N + Closes #M + ``` + + c. For each linked issue, post the PR URL as a comment: + - Comment: "🚀 PR created: [PR title](PR URL) — implementation complete" + +12. **Phase-End Commit**: + + 1. Run `git status --short` scoped to `specs/$BRANCH/` to check for changes + 2. If no changes to spec artifacts: report "No spec changes to commit" and skip + 3. If changes exist (status update, tasks marked complete): invoke the `conventional-commit` + skill with: + - type: `docs` + - scope: `implement` + - description: `mark NNN-feature-name implemented` + - footer: issue numbers (e.g., `Closes: #31`) + 4. Await developer confirmation before committing (per `conventional-commit` skill workflow) + 5. Note: Task-level commits (feat/fix/chore for each implementation task group) are separate + from this spec-level commit — each task group should already have its own commit + Note: This command assumes a complete task breakdown exists in tasks.md. If tasks are incomplete or missing, suggest running `/speckit.tasks` first to regenerate the task list. diff --git a/.github/agents/speckit.plan.agent.md b/.github/agents/speckit.plan.agent.md index 0ffb929..2127f3e 100644 --- a/.github/agents/speckit.plan.agent.md +++ b/.github/agents/speckit.plan.agent.md @@ -20,7 +20,19 @@ You **MUST** consider the user input before proceeding (if not empty). ## Outline -1. **Setup**: Run `.specify/scripts/bash/setup-plan.sh --json` from repo root and parse JSON for FEATURE_SPEC, IMPL_PLAN, SPECS_DIR, BRANCH. For single quotes in args like "I'm Groot", use escape syntax: e.g 'I'\''m Groot' (or double-quote if possible: "I'm Groot"). +1. **Context Loading** (run at startup before any output): + 1. Read `.specify/memory/constitution.md` + 2. Read `.specify/memory/stack.md` — if absent, warn: "⚠️ stack.md missing — run `/speckit.specify` first to initialize stack context" + 3. If stack.md is present, surface tech-specific notes: + - If `testing.backend_framework = vitest`: reference Vitest patterns in the plan (e.g., `vi.mock()`, `describe/it` blocks) + - If `database.orm = prisma`: note migration steps (`prisma migrate dev`) and client import conventions + - If `packaging.tool = pnpm`: use pnpm workspace commands for dependency install + - Apply similar tech-specific guidance for other detected stack values + 4. Read current spec's `spec.md` + 5. Read existing `plan.md` if present (for incremental updates) + 6. Output one-line summary: `Loaded: [spec name] | Status: [status] | Stack: [packaging tool]` + +2. **Setup**: Run `.specify/scripts/bash/setup-plan.sh --json` from repo root and parse JSON for FEATURE_SPEC, IMPL_PLAN, SPECS_DIR, BRANCH. For single quotes in args like "I'm Groot", use escape syntax: e.g 'I'\''m Groot' (or double-quote if possible: "I'm Groot"). 2. **Load context**: Read FEATURE_SPEC and `.specify/memory/constitution.md`. Load IMPL_PLAN template (already copied). @@ -88,3 +100,14 @@ You **MUST** consider the user input before proceeding (if not empty). - Use absolute paths - ERROR on gate failures or unresolved clarifications + +## Phase-End Commit + +1. Run `git status --short` scoped to `specs/$BRANCH/` to check for changes +2. If no changes: report "No changes to commit" and skip +3. If changes exist: invoke the `conventional-commit` skill with: + - type: `docs` + - scope: `plan` + - description: `add implementation plan for NNN-feature-name` + - footer: issue numbers from spec.md `GitHub Issue` field (e.g., `Refs: #31`) +4. Await developer confirmation before committing (per `conventional-commit` skill workflow) diff --git a/.github/agents/speckit.specify.agent.md b/.github/agents/speckit.specify.agent.md index ae62bc6..91644eb 100644 --- a/.github/agents/speckit.specify.agent.md +++ b/.github/agents/speckit.specify.agent.md @@ -20,6 +20,10 @@ You **MUST** consider the user input before proceeding (if not empty). ## Outline +> ⚠️ **New session recommended**: This agent should run in a new Copilot CLI session. If you +> have prior conversation history from a different task, start a new session before proceeding to +> ensure clean context loading. (Non-blocking — continue if already in a fresh session.) + The text the user typed after `/speckit.specify` in the triggering message **is** the feature description. Assume you always have it available in this conversation even if `$ARGUMENTS` appears literally below. Do not ask the user to repeat it unless they provided an empty command. Given that feature description, do this: @@ -68,7 +72,56 @@ Given that feature description, do this: - The JSON output will contain BRANCH_NAME and SPEC_FILE paths - For single quotes in args like "I'm Groot", use escape syntax: e.g 'I'\''m Groot' (or double-quote if possible: "I'm Groot") -3. Load `.specify/templates/spec-template.md` to understand required sections. +3. **GitHub Issue Triage & Backlog Refresh**: + + a. **Check GitHub MCP connectivity**: Attempt to list open GitHub issues via the `github-issues` + skill or MCP tool. This is a connectivity probe only. + + b. **If MCP is reachable**: + - Invoke the `issue-triage` agent to fetch current open issues and allow developer to select + related issue(s) for this feature + - Overwrite `.specify/memory/issues-backlog.md` with a current snapshot of open issues, + appending a `last_refreshed: YYYY-MM-DDTHH:MM:SSZ` timestamp at the top + - Write all selected issue numbers to the `spec.md` `GitHub Issue` front-matter field as a + comma-separated list: `#N, #N` + + c. **If MCP is unreachable**: + - Warn: "⚠️ GitHub MCP not reachable — cannot auto-link issues. Enter issue number(s) + manually (e.g., `#31, #32`) or leave blank." + - Read existing `.specify/memory/issues-backlog.md` if present and note its age + (`last_refreshed` timestamp) + - Accept any manually entered issue numbers for the `GitHub Issue` field + +4. **Stack Check**: + + a. Check if `.specify/memory/stack.md` exists: + - **If absent**: Read `.specify/templates/stack-template.md`; present two options: + 1. **"Auto-detect from repo"** — inspect lock files (`pnpm-lock.yaml`, `yarn.lock`, + `package-lock.json`), `package.json` scripts, config files (`eslint.config.*`, + `tsconfig.json`, `docker-compose.yml`, `prisma/schema.prisma`) to populate all + auto-detectable fields; prompt developer only for non-detectable fields + 2. **"Manual entry"** — prompt developer for each required field in section order + - Write the populated `stack.md` using template field order with `schema_version: "1.0"` + - **If present but `schema_version` < template version**: Prompt only for missing fields + (never overwrite existing fields); append missing fields and update `schema_version` + - **If present and up-to-date**: No action needed — proceed + +5. **Paradigm Shift Detection**: Before writing spec.md, scan the feature description and any + collected spec content for signals of stack or workflow changes: + - New primary language, framework, or runtime + - Authentication model change (e.g., sessions → JWT) + - New test framework or ORM + - New deployment/infrastructure strategy + - New integration pattern (REST → GraphQL, polling → webhooks) + + If any signals are detected, present this prompt before proceeding: + > "⚠️ This spec may require updating `.specify/templates/stack-template.md` or + > `.specify/memory/constitution.md` — review before proceeding. Continue? (yes/no)" + + On **NO**: halt and instruct developer to run `/speckit.constitution` first. + On **YES**: proceed with spec writing, noting the paradigm shift in the spec's Assumptions section. + +6. Load `.specify/templates/spec-template.md` to understand required sections. 4. Follow this execution flow: @@ -96,9 +149,9 @@ Given that feature description, do this: 7. Identify Key Entities (if data involved) 8. Return: SUCCESS (spec ready for planning) -5. Write the specification to SPEC_FILE using the template structure, replacing placeholders with concrete details derived from the feature description (arguments) while preserving section order and headings. +7. Write the specification to SPEC_FILE using the template structure, replacing placeholders with concrete details derived from the feature description (arguments) while preserving section order and headings. -6. **Specification Quality Validation**: After writing the initial spec, validate it against quality criteria: +8. **Specification Quality Validation**: After writing the initial spec, validate it against quality criteria: a. **Create Spec Quality Checklist**: Generate a checklist file at `FEATURE_DIR/checklists/requirements.md` using the checklist template structure with these validation items: @@ -190,7 +243,26 @@ Given that feature description, do this: d. **Update Checklist**: After each validation iteration, update the checklist file with current pass/fail status -7. Report completion with branch name, spec file path, checklist results, and readiness for the next phase (`/speckit.clarify` or `/speckit.plan`). +9. **Issue Traceability Comments**: After spec.md is written and committed, for each issue number + in the `GitHub Issue` field: + - Invoke the `github-issues` skill to post a traceability comment on the issue containing: + - Branch name + - Spec title + - Link to `spec.md` in the repository + - Example comment: "📋 Spec initialized: [NNN-feature-name](link/to/spec.md) on branch `NNN-feature-name`" + +10. **Phase-End Commit**: + + 1. Run `git status --short` scoped to `specs/$BRANCH/` to check for changes + 2. If no changes: report "No changes to commit" and skip + 3. If changes exist: invoke the `conventional-commit` skill with: + - type: `docs` + - scope: `spec` + - description: `initialize NNN-feature-name spec` + - footer: issue numbers (e.g., `Refs: #31`) + 4. Await developer confirmation before committing (per `conventional-commit` skill workflow) + +11. Report completion with branch name, spec file path, checklist results, and readiness for the next phase (`/speckit.clarify` or `/speckit.plan`). **NOTE:** The script creates and checks out the new branch and initializes the spec file before writing. diff --git a/.github/agents/speckit.tasks.agent.md b/.github/agents/speckit.tasks.agent.md index e09112b..4fc5851 100644 --- a/.github/agents/speckit.tasks.agent.md +++ b/.github/agents/speckit.tasks.agent.md @@ -21,7 +21,18 @@ You **MUST** consider the user input before proceeding (if not empty). ## Outline -1. **Setup**: Run `.specify/scripts/bash/check-prerequisites.sh --json` from repo root and parse FEATURE_DIR and AVAILABLE_DOCS list. All paths must be absolute. For single quotes in args like "I'm Groot", use escape syntax: e.g 'I'\''m Groot' (or double-quote if possible: "I'm Groot"). +1. **Context Loading** (run at startup before any output): + 1. Read `.specify/memory/constitution.md` + 2. Read `.specify/memory/stack.md` — if absent, warn: "⚠️ stack.md missing — run `/speckit.specify` first to initialize stack context" + 3. If stack.md is present, extract `regression_tests` section values: + - `lint_cmd` → use this exact command in regression test tasks (not hardcoded `pnpm lint`) + - `test_cmd` → use this exact command in regression test tasks (not hardcoded `pnpm test`) + - `e2e_cmd` + `e2e_requires` → include in tasks only if UI changes are in scope + 4. Read current spec's `spec.md` and `plan.md` + 5. Read existing `tasks.md` if present (for incremental regeneration) + 6. Output one-line summary: `Loaded: [spec name] | Status: [status] | Stack: [packaging tool]` + +2. **Setup**: Run `.specify/scripts/bash/check-prerequisites.sh --json` from repo root and parse FEATURE_DIR and AVAILABLE_DOCS list. All paths must be absolute. For single quotes in args like "I'm Groot", use escape syntax: e.g 'I'\''m Groot' (or double-quote if possible: "I'm Groot"). 2. **Load design documents**: Read from FEATURE_DIR: - **Required**: plan.md (tech stack, libraries, structure), spec.md (user stories with priorities) @@ -135,3 +146,14 @@ Every task MUST strictly follow this format: - Within each story: Tests (if requested) → Models → Services → Endpoints → Integration - Each phase should be a complete, independently testable increment - **Final Phase**: Polish & Cross-Cutting Concerns + +## Phase-End Commit + +1. Run `git status --short` scoped to `specs/$BRANCH/` to check for changes +2. If no changes: report "No changes to commit" and skip +3. If changes exist: invoke the `conventional-commit` skill with: + - type: `docs` + - scope: `tasks` + - description: `generate task breakdown for NNN-feature-name` + - footer: issue numbers from spec.md `GitHub Issue` field (e.g., `Refs: #31`) +4. Await developer confirmation before committing (per `conventional-commit` skill workflow) diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md new file mode 100644 index 0000000..f2f24a9 --- /dev/null +++ b/.github/copilot-instructions.md @@ -0,0 +1,134 @@ +# Copilot Instructions for ordrctrl + +ordrctrl is a unified productivity aggregator that consolidates tasks, reminders, calendar events, and flagged emails from Gmail, Microsoft Tasks, and Apple Calendar into a single chronological feed. It's a pnpm monorepo with a Fastify 4 REST API backend and a Vite 5 + React 18 SPA frontend. + +--- + +## Commands + +### Root (runs both workspaces) +```bash +pnpm dev # start backend + frontend concurrently +pnpm build # build both +pnpm lint # lint both +pnpm lint:fix # auto-fix both +pnpm test # backend unit tests +pnpm test:e2e # frontend Playwright e2e +``` + +### Backend (`cd backend`) +```bash +pnpm dev # tsx watch src/server.ts +pnpm test # vitest run (all) +pnpm test:contract # vitest run tests/contract (API contract tests only) +pnpm test:watch # vitest (watch mode) +pnpm lint # eslint src +pnpm prisma:migrate # prisma migrate dev +pnpm prisma:generate # prisma generate +``` + +### Frontend (`cd frontend`) +```bash +pnpm dev # vite +pnpm test # vitest run +pnpm test:watch # vitest +pnpm test:e2e # playwright test (requires both servers running) +pnpm lint # eslint src +pnpm dev:android # vite --mode android --host +pnpm dev:ios # vite --mode ios --host +``` + +### Run a single test file +```bash +# Backend +cd backend && pnpm vitest run tests/unit/feed.service.test.ts + +# Frontend e2e +cd frontend && pnpm playwright test tests/e2e/feed.spec.ts +``` + +### Infrastructure +```bash +docker compose up -d # start PostgreSQL 16 + Redis 7 (required for local dev) +``` + +--- + +## Architecture + +``` +ordrctrl/ +├── backend/ # Fastify 4 REST API (port 4000) +│ ├── src/ +│ │ ├── api/ # Route handlers (one file per domain) +│ │ ├── services/ # Business logic +│ │ ├── integrations/ # Third-party adapters (Gmail, Microsoft, Apple) +│ │ │ └── _adapter/ # IntegrationAdapter interface + types +│ │ ├── lib/ # db.ts (Prisma), encryption.ts, redis.ts +│ │ ├── jobs/ # BullMQ queue workers (15-min sync) +│ │ ├── app.ts # Fastify app setup + route registration +│ │ └── server.ts # Entry point + env validation +│ └── prisma/ +│ ├── schema.prisma +│ └── migrations/ +└── frontend/ # Vite 5 + React 18 SPA (port 3000) + └── src/ + ├── app/ # Route pages (app/{feature}/page.tsx) + ├── components/ # UI components (components/{domain}/Name.tsx) + ├── hooks/ # State + actions (useFeatureName.ts) + ├── services/ # API client wrappers (feature.service.ts) + ├── plugins/ # Capacitor/Tauri platform abstractions + └── utils/ +``` + +Frontend communicates with backend via REST + session cookies (`credentials: 'include'`). Auth is session-based (Fastify session + Redis), not JWT. + +--- + +## Key Conventions + +### Backend: Routes +Each `backend/src/api/*.routes.ts` exports a `register*Routes(app: FastifyInstance)` function. All route files are registered in `app.ts`. Validate input with Zod at the route entry point. Auth guard: check `request.session.userId`. Errors: `reply.status(code).send({ error, message })`. + +### Backend: Integrations +Every integration implements the `IntegrationAdapter` interface (`backend/src/integrations/_adapter/types.ts`). New integrations must implement `connect`, `disconnect`, `sync`, `refreshToken`, and `getAuthorizationUrl`. The `sync()` method returns `NormalizedItem[]`. Core application code must not be modified to add a new integration — adapters are self-contained. + +### Backend: Database +- ORM: Prisma — import client from `backend/src/lib/db.ts` (`import { prisma } from '../lib/db'`) +- Never edit existing migrations — always `pnpm prisma migrate dev --name ` followed by `pnpm prisma generate` +- OAuth tokens are stored encrypted (AES-256-GCM) via `backend/src/lib/encryption.ts` — never store or log plaintext tokens +- `SyncCacheItem.rawPayload` must never appear in API responses (PII) + +### Frontend: State management +No Redux/Zustand/Context. State lives in custom hooks (`hooks/useFeatureName.ts`). Hooks own `useState`, call service functions, and return both data and action callbacks. Pages/components call hooks and pass data down via props. + +### Frontend: Services +`services/*.service.ts` are pure API wrappers with no state. They use the helpers in `services/api-client.ts` (`apiGet`, `apiPost`, `apiPatch`, `apiDelete`) which set `credentials: 'include'` and throw `ApiError` on non-2xx responses. + +### Frontend: Styling +Tailwind utility classes in `className` only. Do not use `@apply` or `@layer components` in CSS. Do not use inline `style={{}}` props except for runtime-dynamic values that Tailwind cannot express (e.g., a per-record hex color). + +### Branching +Branches follow `NNN-short-name` format where `NNN` is the zero-padded spec number (e.g., `023-todoist-integration`). Each spec has design documents in `specs/NNN-*/`. + +### Commit messages +Conventional Commits: `(): `. Types: `feat`, `fix`, `chore`, `docs`, `refactor`, `test`, `perf`. + +### Testing expectations +| Change | Tests required | +|--------|----------------| +| New API endpoint | Contract test in `backend/tests/contract/` | +| New service method | Unit test in `backend/tests/unit/` | +| New integration adapter | Unit tests for `sync()` normalization | +| New UI flow | Playwright e2e in `frontend/tests/e2e/` | + +### Environment variables +New env vars must be added to `backend/.env.example` (placeholder value, never a real secret), documented in `docs/development.md`, and validated at startup in `backend/src/server.ts`. Never commit `.env` or `.env.device.local` files. + +--- + +## Spec-Kit Workflow + +> Full constitution and workflow principles: [`.specify/memory/constitution.md`](.specify/memory/constitution.md) + +All features follow the spec-kit lifecycle: `/speckit.specify` → `/speckit.plan` → `/speckit.tasks` → `/speckit.implement` → `/speckit.analyze`. Agents and workflow steps are in `.github/agents/`. diff --git a/.github/hooks/session-logger/log-prompt.sh b/.github/hooks/session-logger/log-prompt.sh index 5875bfb..1b83c5f 100644 --- a/.github/hooks/session-logger/log-prompt.sh +++ b/.github/hooks/session-logger/log-prompt.sh @@ -1,25 +1,35 @@ #!/bin/bash -# Log session end event +# Log userPromptSubmitted event set -euo pipefail +# .gitignore guard — session logging requires logs/ to be ignored +if ! grep -q '^logs/' .gitignore 2>/dev/null; then + echo "⚠️ speckit-setup: add 'logs/' to .gitignore before session logging is active" + exit 0 +fi +mkdir -p logs/copilot + # Skip if logging disabled if [[ "${SKIP_LOGGING:-}" == "true" ]]; then exit 0 fi -# Read input from Copilot -INPUT=$(cat) - -# Create logs directory if it doesn't exist -mkdir -p logs/copilot +# Capture prompt text from first argument (passed by hook caller) +PROMPT="${1:-}" -# Extract timestamp +# Extract timestamp and branch TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%SZ") +BRANCH=$(git rev-parse --abbrev-ref HEAD 2>/dev/null || echo "unknown") -# Log session end -echo "{\"timestamp\":\"$TIMESTAMP\",\"event\":\"sessionEnd\"}" >> logs/copilot/session.log +# Log prompt event as JSON +jq -Rn \ + --arg event "userPromptSubmitted" \ + --arg prompt "$PROMPT" \ + --arg timestamp "$TIMESTAMP" \ + --arg branch "$BRANCH" \ + '{"event":$event,"prompt":$prompt,"timestamp":$timestamp,"branch":$branch}' \ + >> logs/copilot/session.log -echo "📝 Session end logged" exit 0 \ No newline at end of file diff --git a/.github/hooks/session-logger/log-session-end.sh b/.github/hooks/session-logger/log-session-end.sh index 5875bfb..9b827e3 100644 --- a/.github/hooks/session-logger/log-session-end.sh +++ b/.github/hooks/session-logger/log-session-end.sh @@ -4,6 +4,13 @@ set -euo pipefail +# .gitignore guard — session logging requires logs/ to be ignored +if ! grep -q '^logs/' .gitignore 2>/dev/null; then + echo "⚠️ speckit-setup: add 'logs/' to .gitignore before session logging is active" + exit 0 +fi +mkdir -p logs/copilot + # Skip if logging disabled if [[ "${SKIP_LOGGING:-}" == "true" ]]; then exit 0 @@ -12,14 +19,28 @@ fi # Read input from Copilot INPUT=$(cat) -# Create logs directory if it doesn't exist -mkdir -p logs/copilot - -# Extract timestamp +# Extract timestamp and branch TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%SZ") +BRANCH=$(git rev-parse --abbrev-ref HEAD 2>/dev/null || echo "unknown") + +# Build base log entry +LOG_ENTRY=$(jq -Rn \ + --arg timestamp "$TIMESTAMP" \ + --arg event "sessionEnd" \ + --arg branch "$BRANCH" \ + '{"timestamp":$timestamp,"event":$event,"branch":$branch}') + +# Speckit branch detection — check for uncommitted spec artifacts +if [[ "$BRANCH" =~ ^[0-9]{3,}- ]]; then + UNCOMMITTED=$(git status --short "specs/$BRANCH/" 2>/dev/null | grep -v '^$' || true) + if [[ -n "$UNCOMMITTED" ]]; then + WARNING="⚠️ uncommitted spec artifacts detected in specs/$BRANCH/ — consider running phase-end commit" + LOG_ENTRY=$(echo "$LOG_ENTRY" | jq --arg w "$WARNING" '. + {"warning":$w}') + echo "$WARNING" + fi +fi -# Log session end -echo "{\"timestamp\":\"$TIMESTAMP\",\"event\":\"sessionEnd\"}" >> logs/copilot/session.log +echo "$LOG_ENTRY" >> logs/copilot/session.log echo "📝 Session end logged" exit 0 \ No newline at end of file diff --git a/.github/hooks/session-logger/log-session-start.sh b/.github/hooks/session-logger/log-session-start.sh index 11c4109..3c377dd 100644 --- a/.github/hooks/session-logger/log-session-start.sh +++ b/.github/hooks/session-logger/log-session-start.sh @@ -4,6 +4,13 @@ set -euo pipefail +# .gitignore guard — session logging requires logs/ to be ignored +if ! grep -q '^logs/' .gitignore 2>/dev/null; then + echo "⚠️ speckit-setup: add 'logs/' to .gitignore before session logging is active" + exit 0 +fi +mkdir -p logs/copilot + # Skip if logging disabled if [[ "${SKIP_LOGGING:-}" == "true" ]]; then exit 0 @@ -12,15 +19,36 @@ fi # Read input from Copilot INPUT=$(cat) -# Create logs directory if it doesn't exist -mkdir -p logs/copilot - # Extract timestamp and session info TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%SZ") CWD=$(pwd) +# Speckit branch detection — check if we're on a NNN-* feature branch +BRANCH=$(git rev-parse --abbrev-ref HEAD 2>/dev/null || echo "unknown") +SPECKIT_CONTEXT=null + +if [[ "$BRANCH" =~ ^[0-9]{3,}- ]]; then + SPEC_FILE="specs/$BRANCH/spec.md" + if [[ -f "$SPEC_FILE" ]]; then + # Extract Status line from spec.md + SPEC_STATUS=$(grep -E '^\*\*Status\*\*:' "$SPEC_FILE" 2>/dev/null | sed 's/\*\*Status\*\*:[[:space:]]*//' | tr -d '\r' | head -1 || echo "unknown") + SPEC_NAME=$(grep -E '^# ' "$SPEC_FILE" 2>/dev/null | sed 's/^# //' | head -1 || echo "unknown") + SPECKIT_CONTEXT=$(jq -Rn \ + --arg spec "$SPEC_NAME" \ + --arg status "$SPEC_STATUS" \ + --arg last_phase "$(echo "$SPEC_STATUS" | tr '[:upper:]' '[:lower:]')" \ + '{"spec":$spec,"status":$status,"last_phase":$last_phase}') + fi +fi + # Log session start (use jq for proper JSON encoding) -jq -Rn --arg timestamp "$TIMESTAMP" --arg cwd "$CWD" '{"timestamp":$timestamp,"event":"sessionStart","cwd":$cwd}' >> logs/copilot/session.log +jq -Rn \ + --arg timestamp "$TIMESTAMP" \ + --arg cwd "$CWD" \ + --arg branch "$BRANCH" \ + --argjson speckit_context "$SPECKIT_CONTEXT" \ + '{"timestamp":$timestamp,"event":"sessionStart","cwd":$cwd,"branch":$branch,"speckit_context":$speckit_context}' \ + >> logs/copilot/session.log echo "📝 Session logged" exit 0 \ No newline at end of file diff --git a/.github/skills/conventional-commit/SKILL.md b/.github/skills/conventional-commit/SKILL.md index 3465092..bd929af 100644 --- a/.github/skills/conventional-commit/SKILL.md +++ b/.github/skills/conventional-commit/SKILL.md @@ -17,13 +17,16 @@ description: 'Prompt and workflow for generating conventional commit messages us 2. Run `git diff` or `git diff --cached` to inspect changes. 3. Stage your changes with `git add `. 4. Construct your commit message using the following XML structure. -5. After generating your commit message, Copilot will automatically run the following command in your integrated terminal (no confirmation needed): +5. Present a pre-commit summary before committing: -```bash -git commit -m "type(scope): description" -``` + a. Run `git status --short` and list the staged files + b. Show the generated commit message + c. Ask: **"Proceed with this commit? (yes/no)"** + d. Wait for the developer's response: + - On **YES**: run `git commit -m "type(scope): description"` + - On **NO**: do **not** commit; inform the developer that the phase is not marked complete and no changes have been committed -6. Just execute this prompt and Copilot will handle the commit for you in the terminal. +6. Only after receiving explicit confirmation will the commit be executed. ### Commit Message Structure diff --git a/.gitignore b/.gitignore index b9c9de1..8b10607 100644 --- a/.gitignore +++ b/.gitignore @@ -18,6 +18,7 @@ out/ .env.production # Logs +logs/ *.log npm-debug.log* yarn-debug.log* diff --git a/.specify/memory/constitution.md b/.specify/memory/constitution.md index be8a2ed..9678ecc 100644 --- a/.specify/memory/constitution.md +++ b/.specify/memory/constitution.md @@ -1,18 +1,26 @@ @@ -98,6 +106,41 @@ deferred until there is sufficient evidence to make them well. **Rationale**: Premature architectural decisions create lock-in and debt. ordrctrl is early-stage; optionality is more valuable than consistency with a decision that may prove wrong. +### VI. Spec-Kit Workflow (NON-NEGOTIABLE) + +All features MUST follow the spec-kit lifecycle in order: +**Specify → Plan → Tasks → Implement → Analyze** + +- `/speckit.specify`: Draft spec.md, link GitHub issue, commit `docs(spec): initialize NNN-feature-name` +- `/speckit.plan`: Generate plan.md + design artifacts, commit `docs(plan): add plan for NNN-feature-name` +- `/speckit.tasks`: Generate tasks.md, commit `docs(tasks): generate tasks for NNN-feature-name` +- `/speckit.implement`: Execute tasks, run regression tests after each phase, update spec status, + commit per phase, push branch, open PR referencing linked GitHub issues +- `/speckit.analyze`: Cross-artifact consistency check, update spec status, commit report + +The `spec.md` **Status** field MUST be updated at each phase gate: +`Draft → Planned → Tasked → In Progress → Implemented → Analyzed` + +GitHub issues MUST be: +1. Linked in `spec.md` header as `**GitHub Issue**: #N` +2. Tracked in `.specify/memory/issues-backlog.md` +3. Referenced in the PR body with `Closes #N` syntax + +Regression tests MUST be run after every implementation phase. A phase MUST NOT be committed if +tests fail. Stack-specific test commands are defined in `.specify/memory/stack.md`. + +Every speckit phase MUST end with a `conventional-commit` skill invocation. Phase commits follow +the format `docs(): (#)` where `` is the speckit phase name +(e.g., `spec`, `plan`, `tasks`, `implement`, `analyze`). + +Project tooling (packaging, linting, test library, version constraints) MUST be documented in +`.specify/memory/stack.md` and kept current. All spec-kit agents MUST read `stack.md` before +generating technical plans or tasks. + +**Rationale**: Spec traceability from GitHub issue to merged PR is the audit trail for every +feature. Without enforced phase commits, status tracking, and test gates, the workflow degrades +silently. Stack documentation prevents agents from hallucinating commands or tool names. + ## Architecture & Platform ordrctrl is a web and mobile application providing a consolidated view of tasks, emails, and @@ -128,7 +171,13 @@ TODO(TECH_STACK): Finalize language, framework, and database choices after proof - Security-sensitive changes (token handling, auth flows, data retention) MUST receive explicit review attention before approval. - Commit messages SHOULD follow Conventional Commits format - (`feat:`, `fix:`, `docs:`, `chore:`, etc.). + (`feat:`, `fix:`, `docs:`, `chore:`, etc.) — see `.specify/memory/stack.md` for spec-kit + phase-specific commit message formats. +- **Regression tests MUST run after every implementation phase** before committing. Failures + block the commit. +- Project tooling and commands are documented in `.specify/memory/stack.md`. This file is the + authoritative reference for packaging tool, version constraints, linting, and test commands. +- GitHub issues MUST be tracked in `.specify/memory/issues-backlog.md` and closed via PRs. ## Governance @@ -149,4 +198,23 @@ conflicts with the constitution, the constitution wins or must be formally amend **Compliance**: All pull request reviews MUST verify compliance with this constitution. Complexity violations must be justified; unjustified complexity MUST block merge. -**Version**: 1.0.0 | **Ratified**: 2026-03-05 | **Last Amended**: 2026-03-05 +### Paradigm Shift Triggers + +The constitution MUST be reviewed and potentially amended (run `/speckit.constitution`) when +any of the following occur: + +- A new primary programming language, runtime, or framework is adopted +- The authentication/authorization model changes fundamentally (e.g., sessions → JWT) +- The deployment or infrastructure strategy changes significantly +- A new integration pattern is mandated (e.g., REST → GraphQL, polling → webhooks) +- The test strategy changes (e.g., new test framework, adopting strict TDD) +- The packaging tool changes (e.g., npm → pnpm, pip → uv) +- A new platform target is added (e.g., desktop app, CLI, browser extension) +- The data persistence layer changes (e.g., new ORM, new database engine) + +When a paradigm shift occurs: +1. Run `/speckit.constitution` to amend the constitution **before** creating any new spec +2. Update `.specify/memory/stack.md` with new tooling information +3. Propagate changes to affected templates and agent files per the amendment procedure + +**Version**: 1.1.0 | **Ratified**: 2026-03-05 | **Last Amended**: 2026-03-22 diff --git a/.specify/scripts/bash/bootstrap.sh b/.specify/scripts/bash/bootstrap.sh new file mode 100755 index 0000000..be91cdc --- /dev/null +++ b/.specify/scripts/bash/bootstrap.sh @@ -0,0 +1,203 @@ +#!/bin/bash +# bootstrap.sh — Initialize speckit workflow structure in a target repository +# +# Usage: bash .specify/scripts/bash/bootstrap.sh [TARGET_DIR] +# TARGET_DIR: optional path to target repo (defaults to current directory) +# +# This script creates the full speckit directory structure, copies generic +# speckit files, adds logs/ to .gitignore, and prints next-steps instructions. + +set -euo pipefail + +# --------------------------------------------------------------------------- +# Configuration +# --------------------------------------------------------------------------- + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +SOURCE_ROOT="$(cd "$SCRIPT_DIR/../../.." && pwd)" +TARGET_DIR="${1:-$(pwd)}" + +# Directories to create +DIRS=( + ".github/agents" + ".github/skills/conventional-commit" + ".github/skills/context-map" + ".github/skills/github-issues" + ".github/hooks/session-logger" + ".specify/memory" + ".specify/templates" + ".specify/scripts/bash" + "specs" +) + +# Generic files to copy (source → destination relative to repo root) +GENERIC_FILES=( + ".github/agents/speckit.specify.agent.md" + ".github/agents/speckit.clarify.agent.md" + ".github/agents/speckit.plan.agent.md" + ".github/agents/speckit.tasks.agent.md" + ".github/agents/speckit.checklist.agent.md" + ".github/agents/speckit.analyze.agent.md" + ".github/agents/speckit.implement.agent.md" + ".github/agents/speckit.constitution.agent.md" + ".github/agents/speckit.taskstoissues.agent.md" + ".github/agents/issue-triage.agent.md" + ".github/hooks/session-logger/log-session-start.sh" + ".github/hooks/session-logger/log-session-end.sh" + ".github/hooks/session-logger/log-prompt.sh" + ".specify/templates/spec-template.md" + ".specify/templates/plan-template.md" + ".specify/templates/tasks-template.md" + ".specify/templates/checklist-template.md" + ".specify/templates/stack-template.md" + ".specify/scripts/bash/check-prerequisites.sh" + ".specify/scripts/bash/create-new-feature.sh" + ".specify/scripts/bash/setup-plan.sh" + ".specify/scripts/bash/update-agent-context.sh" + ".specify/scripts/bash/common.sh" + ".specify/scripts/bash/bootstrap.sh" +) + +# --------------------------------------------------------------------------- +# Helpers +# --------------------------------------------------------------------------- + +log() { echo " ✓ $*"; } +warn() { echo " ⚠️ $*"; } +info() { echo "$*"; } + +# --------------------------------------------------------------------------- +# Validate source +# --------------------------------------------------------------------------- + +if [[ ! -d "$SOURCE_ROOT/.github/agents" ]]; then + echo "❌ Cannot locate speckit source at: $SOURCE_ROOT" + echo " Run this script from a repo that already has speckit installed." + exit 1 +fi + +if [[ "$SOURCE_ROOT" == "$TARGET_DIR" ]]; then + echo "❌ Source and target are the same directory: $TARGET_DIR" + echo " Run this script in a different (target) repo." + exit 1 +fi + +# --------------------------------------------------------------------------- +# Banner +# --------------------------------------------------------------------------- + +echo "" +echo "╔══════════════════════════════════════════════════════════╗" +echo "║ speckit bootstrap — initializing repo ║" +echo "╚══════════════════════════════════════════════════════════╝" +echo "" +echo "Source : $SOURCE_ROOT" +echo "Target : $TARGET_DIR" +echo "" + +# --------------------------------------------------------------------------- +# Step 1: Create directory structure +# --------------------------------------------------------------------------- + +info "📁 Creating directory structure..." +for dir in "${DIRS[@]}"; do + mkdir -p "$TARGET_DIR/$dir" + log "$dir/" +done +echo "" + +# --------------------------------------------------------------------------- +# Step 2: Copy generic files +# --------------------------------------------------------------------------- + +info "📄 Copying generic speckit files..." +COPIED=0 +SKIPPED=0 + +for file in "${GENERIC_FILES[@]}"; do + src="$SOURCE_ROOT/$file" + dst="$TARGET_DIR/$file" + + if [[ ! -f "$src" ]]; then + warn "Source not found, skipping: $file" + SKIPPED=$((SKIPPED + 1)) + continue + fi + + # Don't overwrite project-specific files that may already exist + if [[ -f "$dst" ]]; then + warn "Already exists, skipping: $file" + SKIPPED=$((SKIPPED + 1)) + continue + fi + + cp "$src" "$dst" + log "$file" + COPIED=$((COPIED + 1)) +done + +# Make hook scripts executable +for hook in log-session-start.sh log-session-end.sh log-prompt.sh; do + hook_path="$TARGET_DIR/.github/hooks/session-logger/$hook" + [[ -f "$hook_path" ]] && chmod +x "$hook_path" +done +# Make scripts executable +for script in check-prerequisites.sh create-new-feature.sh setup-plan.sh update-agent-context.sh common.sh bootstrap.sh; do + script_path="$TARGET_DIR/.specify/scripts/bash/$script" + [[ -f "$script_path" ]] && chmod +x "$script_path" +done + +echo "" +echo " Copied: $COPIED files | Skipped: $SKIPPED files" +echo "" + +# --------------------------------------------------------------------------- +# Step 3: Add logs/ to .gitignore +# --------------------------------------------------------------------------- + +info "🔒 Updating .gitignore..." +GITIGNORE="$TARGET_DIR/.gitignore" + +if [[ ! -f "$GITIGNORE" ]]; then + echo "# Session logs (speckit)" > "$GITIGNORE" + echo "logs/" >> "$GITIGNORE" + log "Created .gitignore with logs/ entry" +elif grep -q '^logs/' "$GITIGNORE"; then + warn "logs/ already present in .gitignore — no change" +else + echo "" >> "$GITIGNORE" + echo "# Session logs (speckit)" >> "$GITIGNORE" + echo "logs/" >> "$GITIGNORE" + log "Added logs/ to existing .gitignore" +fi +echo "" + +# --------------------------------------------------------------------------- +# Step 4: Next steps +# --------------------------------------------------------------------------- + +echo "╔══════════════════════════════════════════════════════════╗" +echo "║ bootstrap complete! ║" +echo "╚══════════════════════════════════════════════════════════╝" +echo "" +echo "📋 Next steps:" +echo "" +echo " 1. Create your project constitution:" +echo " → Open GitHub Copilot CLI and run: /speckit.constitution" +echo " → This creates .specify/memory/constitution.md" +echo "" +echo " 2. Create your Copilot instructions:" +echo " → Create .github/copilot-instructions.md with your project context" +echo " → Reference: .specify/memory/constitution.md" +echo "" +echo " 3. Start your first feature spec:" +echo " → Run: /speckit.specify " +echo " → This will auto-create .specify/memory/stack.md" +echo "" +echo " 4. Set up session logging (optional):" +echo " → Configure .github/hooks/hooks.json in your Copilot CLI settings" +echo " → See .github/hooks/session-logger/README.md for instructions" +echo "" +echo " 📖 Full portability guide: docs/speckit-portability.md" +echo " 📖 Constitution: .specify/memory/constitution.md (after step 1)" +echo "" diff --git a/.specify/templates/stack-template.md b/.specify/templates/stack-template.md new file mode 100644 index 0000000..40618a6 --- /dev/null +++ b/.specify/templates/stack-template.md @@ -0,0 +1,245 @@ +# Project Stack Template + +**Schema Version**: 1.0 +**Purpose**: Canonical field set for any project's `stack.md` file. When a speckit agent reads +an existing `stack.md`, it compares `schema_version` to this template's current version and +prompts only for missing fields. + +> Copy this template to `.specify/memory/stack.md` and populate it by running `/speckit.specify` +> (auto-detect) or manually filling in each field. Fields marked **Required** must be present. +> Fields marked **Auto-detectable** can be inferred from repo files. + +--- + +## Meta + +```yaml +schema_version: "1.0" # Required | Not auto-detectable — set by template +last_updated: "YYYY-MM-DD" # Required | Auto-detectable: set on write +updated_by: "" # Required | Auto-detectable: agent name or "manual" +``` + +**Detection notes**: +- `schema_version`: Fixed at `"1.0"` when first created; increment on template upgrade +- `last_updated`: Set to today's date whenever stack.md is written +- `updated_by`: Set to the agent name (e.g., `speckit.specify`) or `manual` + +--- + +## Packaging + +```yaml +packaging: + tool: "" # Required | Auto-detectable: pnpm-lock.yaml → pnpm, yarn.lock → yarn, package-lock.json → npm, Pipfile.lock → pipenv, Cargo.lock → cargo, etc. + workspace_file: "" # Optional | Auto-detectable: pnpm-workspace.yaml, lerna.json, etc. + lock_file: "" # Required | Auto-detectable: file name of detected lock file + install_cmd: "" # Required | Auto-detectable: inferred from tool (e.g., "pnpm install") + add_dep_cmd: "" # Required | Auto-detectable: inferred from tool (e.g., "pnpm add --filter ") +``` + +**Detection sources**: +- `pnpm-lock.yaml` → tool: `pnpm` +- `yarn.lock` → tool: `yarn` +- `package-lock.json` → tool: `npm` +- `Pipfile.lock` → tool: `pipenv` +- `poetry.lock` → tool: `poetry` +- `Cargo.lock` → tool: `cargo` +- `go.sum` → tool: `go modules` + +--- + +## Version Constraints + +```yaml +version_constraints: + node_version: "" # Optional | Auto-detectable: .nvmrc, engines.node in package.json + package_manager_version: "" # Optional | Auto-detectable: packageManager field in package.json + language_version: "" # Optional | Auto-detectable: tsconfig.json target, pyproject.toml python-requires, .ruby-version, etc. +``` + +**Detection sources**: +- `.nvmrc` → node_version +- `package.json` → `engines.node` → node_version; `packageManager` → package_manager_version +- `tsconfig.json` → `compilerOptions.target` → language_version (TypeScript) +- `pyproject.toml` → `tool.poetry.dependencies.python` → language_version (Python) +- `.ruby-version` → language_version (Ruby) + +--- + +## Linting + +```yaml +linting: + tool: "" # Required | Auto-detectable: eslint.config.*, .eslintrc*, .pylintrc, rubocop.yml, etc. + config_file: "" # Optional | Auto-detectable: first matching config file found + lint_cmd: "" # Required | Auto-detectable: from package.json scripts or inferred + fix_cmd: "" # Optional | Auto-detectable: from package.json scripts or inferred +``` + +**Detection sources**: +- `eslint.config.*` or `.eslintrc*` → tool: `ESLint` +- `.pylintrc` or `pyproject.toml [tool.pylint]` → tool: `pylint` +- `rubocop.yml` → tool: `RuboCop` +- `package.json` `scripts.lint` → lint_cmd +- `package.json` `scripts.lint:fix` → fix_cmd + +--- + +## Testing + +```yaml +testing: + backend_framework: "" # Required | Auto-detectable: devDependencies (vitest, jest, pytest, rspec, go test, etc.) + backend_run_cmd: "" # Required | Auto-detectable: package.json test script + backend_contract_cmd: "" # Optional | Auto-detectable: package.json test:contract script + frontend_unit_cmd: "" # Optional | Auto-detectable: frontend package.json test script + frontend_e2e_framework: "" # Optional | Auto-detectable: devDependencies (playwright, cypress, etc.) + frontend_e2e_cmd: "" # Optional | Auto-detectable: package.json test:e2e script + e2e_requires_servers: false # Optional | Auto-detectable: true if playwright detected +``` + +**Detection sources**: +- `devDependencies.vitest` → backend_framework: `vitest` +- `devDependencies.jest` → backend_framework: `jest` +- `devDependencies.pytest` → backend_framework: `pytest` +- `devDependencies.@playwright/test` → frontend_e2e_framework: `playwright`, e2e_requires_servers: `true` +- `devDependencies.cypress` → frontend_e2e_framework: `cypress` + +--- + +## Build + +```yaml +build: + build_cmd: "" # Required | Auto-detectable: root package.json build script + backend_build_cmd: "" # Optional | Auto-detectable: backend package.json build script + frontend_build_cmd: "" # Optional | Auto-detectable: frontend package.json build script +``` + +**Detection sources**: +- Root `package.json` `scripts.build` → build_cmd +- `backend/package.json` `scripts.build` → backend_build_cmd +- `frontend/package.json` `scripts.build` → frontend_build_cmd + +--- + +## Infrastructure + +```yaml +infrastructure: + local_dev_cmd: "" # Optional | Auto-detectable: root package.json dev script + required_services: [] # Optional | Partial auto-detect: docker-compose.yml service names + infra_start_cmd: "" # Optional | Auto-detectable: "docker compose up -d" if docker-compose.yml present +``` + +**Detection sources**: +- Root `package.json` `scripts.dev` → local_dev_cmd +- `docker-compose.yml` services block → required_services +- `docker-compose.yml` presence → infra_start_cmd: `docker compose up -d` + +--- + +## Database + +> Include this section only if a database/ORM is detected in the project. + +```yaml +database: + orm: "" # Optional | Auto-detectable: prisma, typeorm, drizzle, sqlalchemy, activerecord, etc. + schema_file: "" # Optional | Auto-detectable: prisma/schema.prisma, etc. + migrate_cmd: "" # Optional | Auto-detectable: package.json prisma:migrate script + generate_cmd: "" # Optional | Auto-detectable: package.json prisma:generate script +``` + +**Detection sources**: +- `dependencies.@prisma/client` or `devDependencies.prisma` → orm: `prisma` +- `dependencies.typeorm` → orm: `typeorm` +- `dependencies.drizzle-orm` → orm: `drizzle` +- `prisma/schema.prisma` → schema_file +- `package.json` `scripts.prisma:migrate` → migrate_cmd +- `package.json` `scripts.prisma:generate` → generate_cmd + +--- + +## Project Type + +```yaml +project_type: + type: "" # Required | Auto-detectable: web-service / mobile-app / library / cli / desktop-app / monorepo + platforms: [] # Optional | Auto-detectable: from directory structure, Capacitor config, Tauri config +``` + +**Detection sources**: +- `pnpm-workspace.yaml` or `lerna.json` + multiple package dirs → type: `monorepo` +- `capacitor.config.*` → platforms includes `ios`, `android` +- `tauri.conf.json` → type: `desktop-app` +- `bin` field in `package.json` → type: `cli` +- Web server entry point detected → type: `web-service` + +**Allowed values for `type`**: +- `web-service` — REST/GraphQL API or web application +- `mobile-app` — iOS/Android native or cross-platform +- `library` — npm/pip/crate package for consumption by other code +- `cli` — command-line tool +- `desktop-app` — Electron, Tauri, or similar +- `monorepo` — multiple packages in one repo + +--- + +## Commit Convention + +```yaml +commit_convention: + format: "(): " # Required | Not auto-detectable — copy from constitution + phase_commit_formats: # Required | Not auto-detectable — copy from constitution + specify: "docs(spec): initialize NNN-feature-name spec" + clarify: "docs(clarify): update NNN-feature-name spec with clarifications" + plan: "docs(plan): add implementation plan for NNN-feature-name" + tasks: "docs(tasks): generate task breakdown for NNN-feature-name" + implement: "feat(NNN): implement " + analyze: "docs(analyze): add consistency report for NNN-feature-name" + constitution: "docs: amend constitution to vX.Y.Z ()" +``` + +**Notes**: +- Format follows the [Conventional Commits](https://www.conventionalcommits.org/) specification +- Spec-kit phase commit formats are defined in `.specify/memory/constitution.md` Principle VI +- Copy values from constitution; do not deviate without a constitution amendment + +--- + +## Regression Tests + +> These are the commands speckit agents use for post-phase validation. Must match Testing section above. + +```yaml +regression_tests: + lint_cmd: "" # Required | Auto-detectable: same as linting.lint_cmd + test_cmd: "" # Required | Auto-detectable: same as testing.backend_run_cmd + e2e_cmd: "" # Optional | Auto-detectable: same as testing.frontend_e2e_cmd + e2e_requires: "" # Optional | Human-readable note about server startup requirements +``` + +**Example values**: +```yaml +regression_tests: + lint_cmd: "pnpm lint" + test_cmd: "pnpm test" + e2e_cmd: "cd frontend && pnpm test:e2e" + e2e_requires: "Requires docker compose up -d + pnpm dev (both servers)" +``` + +--- + +## Version Upgrade Procedure + +When `schema_version` in an existing `stack.md` is lower than this template's current version: + +1. Agent reads existing `stack.md` and notes the `schema_version` +2. Agent reads this `stack-template.md` and identifies all fields not present in existing file +3. For each missing field: attempt auto-detect first; if not detectable, prompt developer +4. Append missing fields to existing `stack.md` under their correct sections +5. Update `schema_version`, `last_updated`, `updated_by` +6. Commit updated `stack.md` using `conventional-commit` skill + +**Invariant**: Fields already present in `stack.md` are NEVER overwritten during a version upgrade. diff --git a/docs/speckit-portability.md b/docs/speckit-portability.md new file mode 100644 index 0000000..7834433 --- /dev/null +++ b/docs/speckit-portability.md @@ -0,0 +1,116 @@ +# Speckit Portability Guide + +**Purpose**: This document defines the portability contract for the speckit workflow system — +which files are generic (reusable across any project) vs. project-specific (must be customized +per repo), and how to apply speckit to a new repository. + +--- + +## Portability Contract + +### Generic Files (copy as-is to any repo) + +These files contain no project-specific content and can be copied verbatim: + +| File | Description | +|------|-------------| +| `.github/agents/speckit.specify.agent.md` | Feature spec creation workflow | +| `.github/agents/speckit.clarify.agent.md` | Spec clarification workflow | +| `.github/agents/speckit.plan.agent.md` | Implementation planning workflow | +| `.github/agents/speckit.tasks.agent.md` | Task breakdown generation workflow | +| `.github/agents/speckit.checklist.agent.md` | Requirements quality checklist workflow | +| `.github/agents/speckit.analyze.agent.md` | Cross-artifact consistency analysis | +| `.github/agents/speckit.implement.agent.md` | Implementation execution workflow | +| `.github/agents/speckit.constitution.agent.md` | Constitution amendment workflow | +| `.github/agents/speckit.taskstoissues.agent.md` | Task-to-GitHub-issue conversion | +| `.github/agents/issue-triage.agent.md` | GitHub issue triage and prioritization | +| `.github/skills/conventional-commit/SKILL.md` | Conventional commit message workflow | +| `.github/skills/context-map/` | Context map skill | +| `.github/skills/github-issues/` | GitHub issues management skill | +| `.github/hooks/session-logger/log-session-start.sh` | Session start logging hook | +| `.github/hooks/session-logger/log-session-end.sh` | Session end logging hook | +| `.github/hooks/session-logger/log-prompt.sh` | Prompt logging hook | +| `.github/hooks/session-logger/README.md` | Hook setup instructions | +| `.specify/templates/spec-template.md` | Feature specification template | +| `.specify/templates/plan-template.md` | Implementation plan template | +| `.specify/templates/tasks-template.md` | Task breakdown template | +| `.specify/templates/checklist-template.md` | Checklist template | +| `.specify/templates/stack-template.md` | Project stack schema template | +| `.specify/scripts/bash/check-prerequisites.sh` | Prerequisite validation script | +| `.specify/scripts/bash/create-new-feature.sh` | Feature branch creation script | +| `.specify/scripts/bash/setup-plan.sh` | Plan setup script | +| `.specify/scripts/bash/update-agent-context.sh` | Agent context update script | +| `.specify/scripts/bash/bootstrap.sh` | New repo initialization script | + +### Project-Specific Files (must be customized per repo) + +These files contain project-specific content and must be created or customized for each repo: + +| File | Description | How to create | +|------|-------------|---------------| +| `.specify/memory/constitution.md` | Project governance principles | Run `/speckit.constitution` | +| `.specify/memory/stack.md` | Project tooling reference | Run `/speckit.specify` (auto-detect or manual) | +| `.specify/memory/issues-backlog.md` | GitHub issues snapshot | Auto-generated by `/speckit.specify` | +| `.github/copilot-instructions.md` | Repo-specific Copilot instructions | Create manually, reference constitution | +| `specs/` | Feature specs directory | Auto-created by speckit agents | +| `logs/` | Session logs directory | Auto-created by hooks (add to `.gitignore`) | + +--- + +## Applying Speckit to a New Repository + +### Option A: Automated Bootstrap + +Run the bootstrap script from your new repo root: + +```bash +curl -fsSL https://raw.githubusercontent.com///main/.specify/scripts/bash/bootstrap.sh | bash +``` + +Or if you have the file locally: + +```bash +.specify/scripts/bash/bootstrap.sh +``` + +The script will: +1. Create `.github/agents/`, `.github/skills/`, `.github/hooks/`, `.specify/memory/`, + `.specify/templates/`, `.specify/scripts/` +2. Copy all generic files (listed above) into the correct locations +3. Add `logs/` to `.gitignore` +4. Print next-steps instructions + +### Option B: Manual Setup + +1. Copy all **Generic Files** (listed above) to the same paths in your repo +2. Add `logs/` to your `.gitignore` +3. Create `.github/copilot-instructions.md` with your project context +4. Run `/speckit.constitution` to create `.specify/memory/constitution.md` +5. Run `/speckit.specify ` — this will auto-create `stack.md` + +### Option C: Global Installation (Copilot CLI Extensions) + +If your Copilot CLI supports user-level extensions, you can install speckit agents globally +without per-repo file copies. Check your Copilot CLI documentation for the extensions directory +location (typically `~/.copilot/extensions/` or `~/.config/copilot/agents/`). + +Note: Project-specific files (`constitution.md`, `stack.md`) must still exist per-repo. + +--- + +## Maintenance + +When speckit itself is updated (new agent features, schema upgrades, bug fixes): + +1. Pull the latest generic files from the source repo +2. Copy updated generic files to your repo (project-specific files are never overwritten) +3. Check if `stack-template.md` has a new `schema_version` — if so, run `/speckit.specify` + to upgrade existing `stack.md` files + +--- + +## Document History + +| Spec | Change | +|------|--------| +| [020-speckit-workflow](../specs/020-speckit-workflow/) | Initial portability guide created | diff --git a/specs/020-speckit-workflow/spec.md b/specs/020-speckit-workflow/spec.md index a957e5a..c964383 100644 --- a/specs/020-speckit-workflow/spec.md +++ b/specs/020-speckit-workflow/spec.md @@ -2,7 +2,7 @@ **Feature Branch**: `020-speckit-workflow` **Created**: 2026-03-22 -**Status**: Tasked +**Status**: Implemented **GitHub Issue**: [#31](https://github.com/jwill824/ordrctrl/issues/31) **Input**: Update our spec-kit workflow to integrate with GitHub, enforce constitution hygiene, add stack-awareness to agents/skills, and improve commit/PR automation across all speckit phases. diff --git a/specs/020-speckit-workflow/tasks.md b/specs/020-speckit-workflow/tasks.md index 2916438..fb59038 100644 --- a/specs/020-speckit-workflow/tasks.md +++ b/specs/020-speckit-workflow/tasks.md @@ -22,8 +22,8 @@ **Goal**: `.gitignore` guards session logs; `stack-template.md` schema exists for stack-aware agents. -- [ ] T001 Add `logs/` entry to `.gitignore` (repo root) so session-logger output is never committed -- [ ] T002 [P] Create `.specify/templates/stack-template.md` with schema v1.0 per `data-model.md` — include all 11 sections (Meta, Packaging, Version Constraints, Linting, Testing, Build, Infrastructure, Database, Project Type, Commit Convention, Regression Tests), `schema_version: "1.0"` header, auto-detectable flags, and version upgrade procedure note +- [x] T001 Add `logs/` entry to `.gitignore` (repo root) so session-logger output is never committed +- [x] T002 [P] Create `.specify/templates/stack-template.md` with schema v1.0 per `data-model.md` — include all 11 sections (Meta, Packaging, Version Constraints, Linting, Testing, Build, Infrastructure, Database, Project Type, Commit Convention, Regression Tests), `schema_version: "1.0"` header, auto-detectable flags, and version upgrade procedure note --- @@ -33,8 +33,8 @@ **Goal**: Pre-commit summary guard active; `copilot-instructions.md` no longer contains stale abridged constitution. -- [ ] T003 Update `.github/skills/conventional-commit/SKILL.md` — replace step 5 "no confirmation needed / auto-runs git commit" with a conversational pre-commit summary step: show staged files + generated message, ask "Proceed with this commit? (yes/no)"; on YES run `git commit`; on NO abort and inform developer phase is not marked complete -- [ ] T004 [P] Update `.github/copilot-instructions.md` — remove the "Constitution Principles (abridged)" section (I–V only, stale); replace with a pointer: `> Full constitution and workflow principles: [`.specify/memory/constitution.md`](.specify/memory/constitution.md)`; add one-line speckit workflow reference below it +- [x] T003 Update `.github/skills/conventional-commit/SKILL.md` — replace step 5 "no confirmation needed / auto-runs git commit" with a conversational pre-commit summary step: show staged files + generated message, ask "Proceed with this commit? (yes/no)"; on YES run `git commit`; on NO abort and inform developer phase is not marked complete +- [x] T004 [P] Update `.github/copilot-instructions.md` — remove the "Constitution Principles (abridged)" section (I–V only, stale); replace with a pointer: `> Full constitution and workflow principles: [`.specify/memory/constitution.md`](.specify/memory/constitution.md)`; add one-line speckit workflow reference below it --- @@ -49,10 +49,10 @@ **Tasks**: -- [ ] T005 [US1] Update `.github/agents/speckit.specify.agent.md` — add session boundary check at top: if prior session history detected, surface a non-blocking reminder ("New session recommended per US8 — continue or start fresh?") -- [ ] T006 [US1] Update `.github/agents/speckit.specify.agent.md` — add issue-triage guard block: (1) attempt GitHub MCP connectivity check; (2) if reachable, invoke `issue-triage` agent and await selection; (3) if unreachable, warn and allow manual issue number entry; (4) write all selected issue numbers to spec.md `GitHub Issue` front-matter field as comma-separated `#N, #N` list -- [ ] T007 [P] [US1] Update `.github/agents/speckit.specify.agent.md` — after spec.md is written and committed, invoke `github-issues` skill to post a traceability comment on **each** linked issue: include branch name, spec title, and link to spec.md in the repo -- [ ] T008 [P] [US1] Update `.github/agents/speckit.implement.agent.md` — after all tasks complete, invoke `github-issues` skill to: (1) create PR with `Closes #N` for every issue in spec.md `GitHub Issue` field; (2) post PR URL as comment on each linked issue +- [x] T005 [US1] Update `.github/agents/speckit.specify.agent.md` — add session boundary check at top: if prior session history detected, surface a non-blocking reminder ("New session recommended per US8 — continue or start fresh?") +- [x] T006 [US1] Update `.github/agents/speckit.specify.agent.md` — add issue-triage guard block: (1) attempt GitHub MCP connectivity check; (2) if reachable, invoke `issue-triage` agent and await selection; (3) if unreachable, warn and allow manual issue number entry; (4) write all selected issue numbers to spec.md `GitHub Issue` front-matter field as comma-separated `#N, #N` list +- [x] T007 [P] [US1] Update `.github/agents/speckit.specify.agent.md` — after spec.md is written and committed, invoke `github-issues` skill to post a traceability comment on **each** linked issue: include branch name, spec title, and link to spec.md in the repo +- [x] T008 [P] [US1] Update `.github/agents/speckit.implement.agent.md` — after all tasks complete, invoke `github-issues` skill to: (1) create PR with `Closes #N` for every issue in spec.md `GitHub Issue` field; (2) post PR URL as comment on each linked issue --- @@ -67,14 +67,14 @@ **Tasks**: -- [ ] T009 [US2] Update `.specify/memory/constitution.md` — add to Principle VI (Spec-Kit Workflow): "Every speckit phase MUST end with a `conventional-commit` skill invocation. Phase commits follow the format `docs(): (#)`." -- [ ] T010 [US2] Update `.github/agents/speckit.specify.agent.md` — add Phase-End Commit Block: (1) run `git status --short` scoped to `specs/$BRANCH/`; (2) if no changes skip with "No changes to commit"; (3) if changes, invoke `conventional-commit` skill; type=`docs`, scope=`spec`, include issue numbers in footer -- [ ] T011 [P] [US2] Update `.github/agents/speckit.clarify.agent.md` — add Phase-End Commit Block (same pattern as T010; scope=`clarify`) -- [ ] T012 [P] [US2] Update `.github/agents/speckit.plan.agent.md` — add Phase-End Commit Block (scope=`plan`) -- [ ] T013 [P] [US2] Update `.github/agents/speckit.tasks.agent.md` — add Phase-End Commit Block (scope=`tasks`) -- [ ] T014 [P] [US2] Update `.github/agents/speckit.checklist.agent.md` — add Phase-End Commit Block (scope=`checklist`) -- [ ] T015 [P] [US2] Update `.github/agents/speckit.analyze.agent.md` — add Phase-End Commit Block (scope=`analyze`) -- [ ] T016 [P] [US2] Update `.github/agents/speckit.implement.agent.md` — add Phase-End Commit Block (scope=`implement`); note: implement may produce multiple commits per task group — each group gets its own commit via `conventional-commit` skill +- [x] T009 [US2] Update `.specify/memory/constitution.md` — add to Principle VI (Spec-Kit Workflow): "Every speckit phase MUST end with a `conventional-commit` skill invocation. Phase commits follow the format `docs(): (#)`." +- [x] T010 [US2] Update `.github/agents/speckit.specify.agent.md` — add Phase-End Commit Block: (1) run `git status --short` scoped to `specs/$BRANCH/`; (2) if no changes skip with "No changes to commit"; (3) if changes, invoke `conventional-commit` skill; type=`docs`, scope=`spec`, include issue numbers in footer +- [x] T011 [P] [US2] Update `.github/agents/speckit.clarify.agent.md` — add Phase-End Commit Block (same pattern as T010; scope=`clarify`) +- [x] T012 [P] [US2] Update `.github/agents/speckit.plan.agent.md` — add Phase-End Commit Block (scope=`plan`) +- [x] T013 [P] [US2] Update `.github/agents/speckit.tasks.agent.md` — add Phase-End Commit Block (scope=`tasks`) +- [x] T014 [P] [US2] Update `.github/agents/speckit.checklist.agent.md` — add Phase-End Commit Block (scope=`checklist`) +- [x] T015 [P] [US2] Update `.github/agents/speckit.analyze.agent.md` — add Phase-End Commit Block (scope=`analyze`) +- [x] T016 [P] [US2] Update `.github/agents/speckit.implement.agent.md` — add Phase-End Commit Block (scope=`implement`); note: implement may produce multiple commits per task group — each group gets its own commit via `conventional-commit` skill --- @@ -89,8 +89,8 @@ **Tasks**: -- [ ] T017 [US3] Update `.github/agents/speckit.implement.agent.md` — before Phase-End Commit Block (T016), add status advancement step: update spec.md `**Status**:` line from `Tasked` → `Implementing` at start, then → `Implemented` on completion; include status change in the phase-end commit -- [ ] T018 [P] [US3] Update `.github/agents/speckit.analyze.agent.md` — before Phase-End Commit Block (T015), add status advancement step: update spec.md `**Status**:` line → `Analyzed` on completion; include in phase-end commit +- [x] T017 [US3] Update `.github/agents/speckit.implement.agent.md` — before Phase-End Commit Block (T016), add status advancement step: update spec.md `**Status**:` line from `Tasked` → `Implementing` at start, then → `Implemented` on completion; include status change in the phase-end commit +- [x] T018 [P] [US3] Update `.github/agents/speckit.analyze.agent.md` — before Phase-End Commit Block (T015), add status advancement step: update spec.md `**Status**:` line → `Analyzed` on completion; include in phase-end commit --- @@ -106,14 +106,14 @@ **Tasks**: -- [ ] T019 [US8] Fix `.github/hooks/session-logger/log-prompt.sh` — rewrite to actually capture prompt content: log a JSON object with `event: "userPromptSubmitted"`, `prompt` text, `timestamp`, and `branch`; remove copy-pasted "sessionEnd" event code -- [ ] T020 [US8] Update `.github/hooks/session-logger/log-session-start.sh` — add `.gitignore` guard at top (check `grep -q '^logs/' .gitignore`); if missing, print `⚠️ speckit-setup: add 'logs/' to .gitignore` and `exit 0`; add `mkdir -p logs/copilot` guard -- [ ] T021 [P] [US8] Update `.github/hooks/session-logger/log-session-end.sh` — add same `.gitignore` guard (T020 pattern); add speckit branch detection: if on a `NNN-*` branch with uncommitted changes to `specs/$BRANCH/`, append `⚠️ uncommitted spec artifacts detected` warning to session log -- [ ] T022 [P] [US8] Update `.github/hooks/session-logger/log-session-start.sh` — add speckit branch detection block: extract `BRANCH`, check for `specs/$BRANCH/spec.md`, read `**Status**:` line, log `speckit_context: { spec, status, last_phase }` into session-start JSON -- [ ] T023 [US8] Update `.github/agents/speckit.specify.agent.md` — add fresh-session enforcement reminder at very top (above issue-triage guard): "This agent should run in a new Copilot CLI session. If you have prior conversation history, start a new session before proceeding." -- [ ] T024 [P] [US8] Update `.github/agents/speckit.plan.agent.md` — add Context Loading Preamble as first numbered section: (1) Read `.specify/memory/constitution.md`; (2) Read `.specify/memory/stack.md` — warn if absent; (3) Read `spec.md`; (4) Output one-line summary: `Loaded: [spec name] | Status: [status] | Stack: [tool]` -- [ ] T025 [P] [US8] Update `.github/agents/speckit.tasks.agent.md` — add same Context Loading Preamble (T024 pattern): read constitution.md, stack.md, spec.md, plan.md; output context summary line -- [ ] T026 [P] [US8] Update `.github/agents/speckit.implement.agent.md` — add Context Loading Preamble (T024 pattern): read constitution.md, stack.md, spec.md, plan.md, tasks.md; output context summary line +- [x] T019 [US8] Fix `.github/hooks/session-logger/log-prompt.sh` — rewrite to actually capture prompt content: log a JSON object with `event: "userPromptSubmitted"`, `prompt` text, `timestamp`, and `branch`; remove copy-pasted "sessionEnd" event code +- [x] T020 [US8] Update `.github/hooks/session-logger/log-session-start.sh` — add `.gitignore` guard at top (check `grep -q '^logs/' .gitignore`); if missing, print `⚠️ speckit-setup: add 'logs/' to .gitignore` and `exit 0`; add `mkdir -p logs/copilot` guard +- [x] T021 [P] [US8] Update `.github/hooks/session-logger/log-session-end.sh` — add same `.gitignore` guard (T020 pattern); add speckit branch detection: if on a `NNN-*` branch with uncommitted changes to `specs/$BRANCH/`, append `⚠️ uncommitted spec artifacts detected` warning to session log +- [x] T022 [P] [US8] Update `.github/hooks/session-logger/log-session-start.sh` — add speckit branch detection block: extract `BRANCH`, check for `specs/$BRANCH/spec.md`, read `**Status**:` line, log `speckit_context: { spec, status, last_phase }` into session-start JSON +- [x] T023 [US8] Update `.github/agents/speckit.specify.agent.md` — add fresh-session enforcement reminder at very top (above issue-triage guard): "This agent should run in a new Copilot CLI session. If you have prior conversation history, start a new session before proceeding." +- [x] T024 [P] [US8] Update `.github/agents/speckit.plan.agent.md` — add Context Loading Preamble as first numbered section: (1) Read `.specify/memory/constitution.md`; (2) Read `.specify/memory/stack.md` — warn if absent; (3) Read `spec.md`; (4) Output one-line summary: `Loaded: [spec name] | Status: [status] | Stack: [tool]` +- [x] T025 [P] [US8] Update `.github/agents/speckit.tasks.agent.md` — add same Context Loading Preamble (T024 pattern): read constitution.md, stack.md, spec.md, plan.md; output context summary line +- [x] T026 [P] [US8] Update `.github/agents/speckit.implement.agent.md` — add Context Loading Preamble (T024 pattern): read constitution.md, stack.md, spec.md, plan.md, tasks.md; output context summary line --- @@ -128,11 +128,11 @@ **Tasks**: -- [ ] T027 [US4] Update `.github/agents/speckit.specify.agent.md` — add stack check block after issue-triage guard: (1) check if `.specify/memory/stack.md` exists; (2) if absent, read `.specify/templates/stack-template.md` schema; (3) offer two options — "Auto-detect from repo" (inspect lock files, package.json, config files) or "Manual entry"; (4) write populated `stack.md` using template field order and `schema_version: "1.0"`; (5) if present but `schema_version` < template version, prompt only for missing fields -- [ ] T028 [P] [US4] Update `.github/agents/speckit.plan.agent.md` — in Context Loading Preamble (T024), after reading stack.md, surface tech-specific notes: e.g. if `testing.backend_framework = vitest`, reference vitest patterns in plan; if `database.orm = prisma`, note migration steps -- [ ] T029 [P] [US4] Update `.github/agents/speckit.tasks.agent.md` — in Context Loading Preamble (T025), after reading stack.md, use `regression_tests` section to populate task descriptions with correct lint/test commands from stack.md rather than hardcoded values -- [ ] T030 [P] [US4] Update `.github/agents/speckit.implement.agent.md` — in Context Loading Preamble (T026), after reading stack.md, use `regression_tests.lint_cmd` and `regression_tests.test_cmd` for post-implementation validation steps; use `packaging.install_cmd` for dependency install instructions -- [ ] T031 [P] [US4] Update `.github/agents/speckit.analyze.agent.md` — add Context Loading Preamble (T024 pattern): read constitution.md, stack.md, spec.md, plan.md, tasks.md; output context summary; use stack.md `regression_tests` section to validate that implementation tasks referenced correct commands +- [x] T027 [US4] Update `.github/agents/speckit.specify.agent.md` — add stack check block after issue-triage guard: (1) check if `.specify/memory/stack.md` exists; (2) if absent, read `.specify/templates/stack-template.md` schema; (3) offer two options — "Auto-detect from repo" (inspect lock files, package.json, config files) or "Manual entry"; (4) write populated `stack.md` using template field order and `schema_version: "1.0"`; (5) if present but `schema_version` < template version, prompt only for missing fields +- [x] T028 [P] [US4] Update `.github/agents/speckit.plan.agent.md` — in Context Loading Preamble (T024), after reading stack.md, surface tech-specific notes: e.g. if `testing.backend_framework = vitest`, reference vitest patterns in plan; if `database.orm = prisma`, note migration steps +- [x] T029 [P] [US4] Update `.github/agents/speckit.tasks.agent.md` — in Context Loading Preamble (T025), after reading stack.md, use `regression_tests` section to populate task descriptions with correct lint/test commands from stack.md rather than hardcoded values +- [x] T030 [P] [US4] Update `.github/agents/speckit.implement.agent.md` — in Context Loading Preamble (T026), after reading stack.md, use `regression_tests.lint_cmd` and `regression_tests.test_cmd` for post-implementation validation steps; use `packaging.install_cmd` for dependency install instructions +- [x] T031 [P] [US4] Update `.github/agents/speckit.analyze.agent.md` — add Context Loading Preamble (T024 pattern): read constitution.md, stack.md, spec.md, plan.md, tasks.md; output context summary; use stack.md `regression_tests` section to validate that implementation tasks referenced correct commands --- @@ -146,7 +146,7 @@ **Tasks**: -- [ ] T032 [US5] Update `.github/agents/speckit.specify.agent.md` — after MCP connectivity check (T006), add backlog refresh step: if MCP reachable, invoke `issue-triage` agent in refresh mode and overwrite `.specify/memory/issues-backlog.md` with current open issues snapshot + `last_refreshed` timestamp; if MCP unreachable, read existing `issues-backlog.md` and note its age +- [x] T032 [US5] Update `.github/agents/speckit.specify.agent.md` — after MCP connectivity check (T006), add backlog refresh step: if MCP reachable, invoke `issue-triage` agent in refresh mode and overwrite `.specify/memory/issues-backlog.md` with current open issues snapshot + `last_refreshed` timestamp; if MCP unreachable, read existing `issues-backlog.md` and note its age --- @@ -160,8 +160,8 @@ **Tasks**: -- [ ] T033 [US6] Update `.github/agents/speckit.specify.agent.md` — add paradigm shift detection block before writing spec.md: scan spec content for signals of stack changes (new language/framework, new ORM, new test runner) or workflow changes (new phase, new commit format); if detected, present: "This spec may require updating `.specify/templates/stack-template.md` or `.specify/memory/constitution.md` — review before proceeding (yes/no)" -- [ ] T034 [P] [US6] Update `.github/agents/speckit.clarify.agent.md` — add Context Loading Preamble (T024 pattern) and paradigm shift check: if clarification answers change core architecture (project type, ORM, packaging tool), flag that `stack.md` and `stack-template.md` may need updating; surface this as a clarification output item before phase-end commit +- [x] T033 [US6] Update `.github/agents/speckit.specify.agent.md` — add paradigm shift detection block before writing spec.md: scan spec content for signals of stack changes (new language/framework, new ORM, new test runner) or workflow changes (new phase, new commit format); if detected, present: "This spec may require updating `.specify/templates/stack-template.md` or `.specify/memory/constitution.md` — review before proceeding (yes/no)" +- [x] T034 [P] [US6] Update `.github/agents/speckit.clarify.agent.md` — add Context Loading Preamble (T024 pattern) and paradigm shift check: if clarification answers change core architecture (project type, ORM, packaging tool), flag that `stack.md` and `stack-template.md` may need updating; surface this as a clarification output item before phase-end commit --- @@ -176,9 +176,9 @@ **Tasks**: -- [ ] T035 [US7] Update `.github/agents/speckit.analyze.agent.md` — add drift detection block before status advancement (T018): (1) find branch-creation commit with `git log --oneline --reverse HEAD | head -1 | cut -d' ' -f1`; (2) run `git diff $BASE_COMMIT..HEAD -- specs/$BRANCH/spec.md specs/$BRANCH/plan.md specs/$BRANCH/tasks.md`; (3) if diff is empty, report "No spec artifact drift detected" -- [ ] T036 [US7] Update `.github/agents/speckit.analyze.agent.md` — add drift report presentation: for each artifact with changes, show a structured diff summary (sections added/removed/changed) and prompt: "Update [artifact] to reflect implementation changes? (yes/skip)"; on yes, assist developer in editing that artifact; on skip, continue -- [ ] T037 [P] [US7] Update `.github/agents/speckit.analyze.agent.md` — add unresolved-item check: scan tasks.md for unchecked items (`- [ ]`); cross-reference with `git log --oneline` for task-related commits; flag any tasks with no corresponding commit as "possibly unimplemented or not deferred — confirm status" +- [x] T035 [US7] Update `.github/agents/speckit.analyze.agent.md` — add drift detection block before status advancement (T018): (1) find branch-creation commit with `git log --oneline --reverse HEAD | head -1 | cut -d' ' -f1`; (2) run `git diff $BASE_COMMIT..HEAD -- specs/$BRANCH/spec.md specs/$BRANCH/plan.md specs/$BRANCH/tasks.md`; (3) if diff is empty, report "No spec artifact drift detected" +- [x] T036 [US7] Update `.github/agents/speckit.analyze.agent.md` — add drift report presentation: for each artifact with changes, show a structured diff summary (sections added/removed/changed) and prompt: "Update [artifact] to reflect implementation changes? (yes/skip)"; on yes, assist developer in editing that artifact; on skip, continue +- [x] T037 [P] [US7] Update `.github/agents/speckit.analyze.agent.md` — add unresolved-item check: scan tasks.md for unchecked items (`- [ ]`); cross-reference with `git log --oneline` for task-related commits; flag any tasks with no corresponding commit as "possibly unimplemented or not deferred — confirm status" --- @@ -192,8 +192,8 @@ **Tasks**: -- [ ] T038 [US9] Create `docs/speckit-portability.md` — document the portability contract: list all generic speckit files (agents, skills, hooks, templates) vs project-specific files (constitution.md, stack.md, copilot-instructions.md); include instructions for applying speckit to a new repo; note that user-level Copilot CLI extensions directory enables global installation without per-repo file copies -- [ ] T039 [P] [US9] Create `.specify/scripts/bash/bootstrap.sh` — script that initializes the full speckit structure in a target repo: creates `.github/agents/`, `.github/skills/`, `.github/hooks/`, `.specify/memory/`, `.specify/templates/`, `.specify/scripts/`; copies generic agent/skill/hook files; adds `logs/` to `.gitignore`; prints next-steps instructions for creating constitution.md and stack.md +- [x] T038 [US9] Create `docs/speckit-portability.md` — document the portability contract: list all generic speckit files (agents, skills, hooks, templates) vs project-specific files (constitution.md, stack.md, copilot-instructions.md); include instructions for applying speckit to a new repo; note that user-level Copilot CLI extensions directory enables global installation without per-repo file copies +- [x] T039 [P] [US9] Create `.specify/scripts/bash/bootstrap.sh` — script that initializes the full speckit structure in a target repo: creates `.github/agents/`, `.github/skills/`, `.github/hooks/`, `.specify/memory/`, `.specify/templates/`, `.specify/scripts/`; copies generic agent/skill/hook files; adds `logs/` to `.gitignore`; prints next-steps instructions for creating constitution.md and stack.md --- @@ -201,9 +201,9 @@ > Verify all changed files are consistent, no broken references, and the workflow is end-to-end coherent. -- [ ] T040 Run `pnpm lint` from repo root and confirm zero new errors introduced by any markdown/shell changes -- [ ] T041 [P] Verify all 7 speckit agent files contain: (1) Context Loading Preamble, (2) Phase-End Commit Block referencing `conventional-commit` skill — open each `.github/agents/speckit.*.agent.md` and confirm presence -- [ ] T042 [P] Verify all 3 hook scripts contain `.gitignore` guard — open each `.github/hooks/session-logger/*.sh` and confirm `grep -q '^logs/' .gitignore` guard is present at top of each; verify `log-prompt.sh` logs `userPromptSubmitted` event (not `sessionEnd`) +- [x] T040 Run `pnpm lint` from repo root and confirm zero new errors introduced by any markdown/shell changes +- [x] T041 [P] Verify all 7 speckit agent files contain: (1) Context Loading Preamble, (2) Phase-End Commit Block referencing `conventional-commit` skill — open each `.github/agents/speckit.*.agent.md` and confirm presence +- [x] T042 [P] Verify all 3 hook scripts contain `.gitignore` guard — open each `.github/hooks/session-logger/*.sh` and confirm `grep -q '^logs/' .gitignore` guard is present at top of each; verify `log-prompt.sh` logs `userPromptSubmitted` event (not `sessionEnd`) --- From ffacfe84a8ea0b14f4373d5410bfa060bf4a3ccb Mon Sep 17 00:00:00 2001 From: Jeff Williams Date: Sun, 22 Mar 2026 21:58:30 -0400 Subject: [PATCH 11/15] chore(speckit): add issue-triage agent, stack.md, and spec template updates (#31) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add issue-triage.agent.md and issue-triage.prompt.md (US1 triage guard) - Add .specify/memory/stack.md — project stack context for stack-aware agents (US4) - Add .specify/memory/issues-backlog.md — backlog snapshot for US5 refresh - Add --issue N flag to create-new-feature.sh for GitHub issue linking at branch creation (US1) - Add GitHub Issue front-matter field and status lifecycle comment to spec-template.md - Regenerate copilot-instructions.md to reflect spec-020 tooling (drop stale per-spec entries) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/agents/copilot-instructions.md | 43 +---- .github/agents/issue-triage.agent.md | 171 ++++++++++++++++++++ .github/prompts/issue-triage.prompt.md | 3 + .specify/memory/issues-backlog.md | 52 ++++++ .specify/memory/stack.md | 127 +++++++++++++++ .specify/scripts/bash/create-new-feature.sh | 27 +++- .specify/templates/spec-template.md | 11 ++ 7 files changed, 393 insertions(+), 41 deletions(-) create mode 100644 .github/agents/issue-triage.agent.md create mode 100644 .github/prompts/issue-triage.prompt.md create mode 100644 .specify/memory/issues-backlog.md create mode 100644 .specify/memory/stack.md diff --git a/.github/agents/copilot-instructions.md b/.github/agents/copilot-instructions.md index aedc49d..01f172e 100644 --- a/.github/agents/copilot-instructions.md +++ b/.github/agents/copilot-instructions.md @@ -1,43 +1,10 @@ # ordrctrl Development Guidelines -Auto-generated from all feature plans. Last updated: 2026-03-04 +Auto-generated from all feature plans. Last updated: 2026-03-22 ## Active Technologies -- TypeScript 5.4 (backend: Node.js/Fastify; frontend: React/Next.js 14) + Fastify (backend API), React + Tailwind CSS (frontend), Prisma ORM (002-uncheck-completed) -- PostgreSQL 16 (primary data), Redis 7 (session cache, BullMQ job queue) (002-uncheck-completed) -- TypeScript 5.4 (backend + frontend) + Fastify 4, Prisma 5, BullMQ (backend); Next.js 14 + React 18 + Tailwind CSS (frontend); Zod (validation); Vitest + Supertest (tests) (003-selective-import) -- PostgreSQL 16 (Prisma ORM) — two new columns on `Integration` table; Redis 7 for BullMQ sync queue (003-selective-import) -- TypeScript 5.x / Node.js 20 LTS (backend); React 18 + TypeScript (frontend) + Fastify (HTTP server), Prisma (ORM + migrations), BullMQ (sync queue), node-fetch (CalDAV HTTP), zod (input validation), AES-256-GCM via `backend/src/lib/encryption.ts` (004-apple-basic-auth) -- PostgreSQL via Prisma — one new field (`calendarEventWindowDays Int @default(30)`) on existing `Integration` model; one migration required (004-apple-basic-auth) -- TypeScript (Node.js backend, React frontend) + Fastify (API), Prisma (ORM), Zod (validation), React Query (frontend state) (005-feed-dismissal) -- TypeScript — backend Node.js, frontend Next.js 14 / React 18 + Prisma ORM, BullMQ, existing IntegrationAdapter interface (007-source-sync) -- PostgreSQL via Prisma — one schema migration required (new field + enum) (007-source-sync) -- TypeScript (Node.js 18, Next.js 14) + Prisma ORM, Express-style API routes (Next.js App Router + custom backend), React 18, BullMQ (sync scheduler) (008-clear-completed) -- TypeScript (Node.js 20, Next.js 14) + Fastify (backend), Next.js + React 18 (frontend), Prisma ORM, BullMQ (sync queue), Vitest (tests) (009-multi-account) -- PostgreSQL (via Prisma) (009-multi-account) -- TypeScript 5 (backend Node.js 20, frontend Next.js 14) + Fastify 4, Prisma 5, React 18, Tailwind CSS, BullMQ, Redis (010-task-inbox) -- PostgreSQL (via Prisma ORM) (010-task-inbox) -- TypeScript 5 (backend Node.js 20, frontend Next.js 14.1.3) + Fastify 4, Prisma 5, React 18, Tailwind CSS, BullMQ, Redis (011-feed-ux-enhancements) -- TypeScript 5.x (frontend + backend) + Next.js 14 App Router, React, Express, Prisma, BullMQ, Redis (012-app-polish-bugfix) -- PostgreSQL (via Prisma), Redis (sync-status cache) (012-app-polish-bugfix) -- TypeScript 5.x (backend Node 20 LTS + frontend Next.js 15 App Router) + Fastify (backend API), React 19, Prisma 5 ORM, PostgreSQL 16, Redis (013-task-content-enhancements) -- PostgreSQL via Prisma (primary), Redis (short-lived sync cache metadata) (013-task-content-enhancements) -- TypeScript 5.4.2 / React 18.2.0 / Node.js 18+ + Vite 5.1.4 (already installed), react-router-dom v6 (to add), Tailwind CSS 3.4.1 (014-vite-migration) -- N/A — frontend only; all persistence is in the backend (014-vite-migration) -- TypeScript 5.4 (frontend), Rust 1.75+ (Tauri shell), Swift/Kotlin (Capacitor native bridge — generated) (015-native-app-targets) -- No new storage layer — session cookies persisted by native WebView OS cookie jar; `@capacitor/preferences` for lightweight native-only flags (e.g., last-seen notification timestamp) (015-native-app-targets) -- Redis (existing) — new `oauth:state:{value}` key namespace with 5-min TTL (016-native-auth-fixes) -- TypeScript 5.4 (frontend + backend), Rust 1.75+ (Tauri shell — unaffected) + Fastify 4, Prisma ORM, React 18, Vite 5, Vitest — all existing; no new dependencies (017-task-rename-polish) -- PostgreSQL (existing `SyncOverride` table — adding one new enum value); no schema migrations beyond enum update (017-task-rename-polish) -- TypeScript 5.4 (frontend), Node 20 (CI runners) (018-e2e-testing) -- N/A (tests are read-only; no test data written to persistent storage) (018-e2e-testing) -- TypeScript 5.4 / React 18.2 + React Router DOM v6, Capacitor 8 (iOS/Android), Tauri 2 (macOS/Windows), Vite, Vitest, Playwright (019-task-timeline-view) -- No new storage — `FeedItem[]` from existing `useFeed` hook; view preference via existing `NativePrefs` pattern (`@capacitor/preferences` → `localStorage` fallback) (019-task-timeline-view) -- New `frontend/src/utils/dateUtils.ts`: shared timezone-safe date helpers — `isAllDayDate`, `toLocalMidnight`, `formatRelativeDay`, `formatLocalTime`, `toLocalDateTimeInput`, `toLocalDateInput`; imported by `useTimeline`, `FeedItemRow`, `EditTaskModal` (019-task-timeline-view) -- All-day calendar events use UTC noon sentinel (`T12:00:00.000Z`). Use `isAllDayDate()` to detect; use `toLocalMidnight()` for bucket/day comparison — do NOT call `setHours(0,0,0,0)` directly on dates from external sources. For display, use `formatLocalTime()` (returns `""` for all-day) and `toLocalDateInput()` / `toLocalDateTimeInput()` for form inputs (019-task-timeline-view) -- Apple Calendar events may have `dueAt: null`; always use `dueAt ?? startAt` as the date key for bucketing and display (019-task-timeline-view) -- TypeScript 5.x (frontend + backend) + Next.js 14 (frontend), Fastify 4 (backend API), Prisma (ORM), (001-mvp-core) +- Node.js (TypeScript) — pnpm monorepo; hook scripts in Bash + Copilot CLI agent/skill/hook system; GitHub MCP; `gh` CLI fallback; `jq` (Bash hooks); `git` (020-speckit-workflow) ## Project Structure @@ -52,13 +19,11 @@ npm test && npm run lint ## Code Style -TypeScript 5.x (frontend + backend): Follow standard conventions +Node.js (TypeScript) — pnpm monorepo; hook scripts in Bash: Follow standard conventions ## Recent Changes -- 019-task-timeline-view: Added timeline view components, useTimeline hook, dateUtils.ts (toLocalMidnight/isAllDayDate/formatLocalTime), Apple Calendar dueAt fix, UTC-midnight all-day display fixes -- 018-e2e-testing: Added TypeScript 5.4 (frontend), Node 20 (CI runners) -- 017-task-rename-polish: Added TypeScript 5.4 (frontend + backend), Rust 1.75+ (Tauri shell — unaffected) + Fastify 4, Prisma ORM, React 18, Vite 5, Vitest — all existing; no new dependencies +- 020-speckit-workflow: Added Node.js (TypeScript) — pnpm monorepo; hook scripts in Bash + Copilot CLI agent/skill/hook system; GitHub MCP; `gh` CLI fallback; `jq` (Bash hooks); `git` diff --git a/.github/agents/issue-triage.agent.md b/.github/agents/issue-triage.agent.md new file mode 100644 index 0000000..d8f5e76 --- /dev/null +++ b/.github/agents/issue-triage.agent.md @@ -0,0 +1,171 @@ +--- +description: Analyze all open GitHub issues for a repository, group related issues by theme, and produce a prioritized triage report with actionable recommendations. +tools: ['github/github-mcp-server/list_issues', 'github/github-mcp-server/issue_read', 'github/github-mcp-server/search_issues'] +--- + +## User Input + +```text +$ARGUMENTS +``` + +You **MUST** consider the user input before proceeding. The user may specify: +- A specific repository (`owner/repo`) — if not provided, detect from `git config --get remote.origin.url` +- A focus area or label filter to narrow scope +- A maximum number of issues to analyze (default: all open issues, up to 200) + +## Goal + +Fetch all open issues for the target repository, semantically cluster them into related groups, score each issue for priority, and produce a compact triage report the team can act on immediately. + +## Operating Constraints + +**READ-ONLY**: Do **not** create, edit, close, or label any issues. Output a structured report only. + +**Repository Safety**: Confirm the target repository before fetching. If the user did not specify a repo, derive it from the Git remote and display it before proceeding. + +## Execution Steps + +### 1. Resolve Target Repository + +If the user provided `owner/repo`, use it directly. Otherwise, run: + +```bash +git config --get remote.origin.url +``` + +Parse the output to extract `owner` and `repo`. Display: `Analyzing issues for: owner/repo` before proceeding. + +> [!CAUTION] +> Never fetch or create issues in a repository that does not match the user's intent. Confirm with the user if ambiguous. + +### 2. Fetch Open Issues + +Use the GitHub MCP `list_issues` tool with `state: OPEN`. Page through results until all open issues are collected (respect the 200-issue cap unless the user overrides). For each issue capture: + +- Issue number, title, body (first 300 chars), labels, assignees, created_at, updated_at, comment count, reactions count + +If the user specified a label filter, apply it during the fetch. + +### 3. Build Semantic Clusters + +Group issues by **theme** using the following signals (in priority order): + +1. **Explicit labels** — issues sharing the same label are strong candidates for the same cluster +2. **Title keyword overlap** — extract noun phrases; issues sharing 2+ key terms belong together +3. **Body reference overlap** — issues mentioning the same file paths, component names, API endpoints, or error messages +4. **Cross-references** — issues that link to each other (`#NNN` mentions) are in the same cluster + +Produce clusters with: +- A short **cluster name** (3–5 words, title case) +- A one-sentence **theme description** +- The list of issue numbers belonging to the cluster +- A `SINGLETON` marker for issues that don't cluster with anything + +Limit clusters to a maximum of 15 (merge the smallest clusters into an `Other` bucket if needed). + +### 4. Score Each Issue for Priority + +Assign a **priority score** (1–10, higher = more urgent) using this weighted rubric: + +| Signal | Weight | Notes | +|--------|--------|-------| +| Age (days open) | 20% | >90 days = max signal | +| Reaction count (👍, ❤️, 🚀) | 25% | Proxy for user demand | +| Comment count | 15% | High engagement = high interest | +| Recency of last update | 15% | Recently touched = in-flight work | +| Label severity | 25% | `bug` > `enhancement` > `question`; `critical`/`P0` labels = max | + +Round score to one decimal. Break ties by reaction count. + +Within each cluster, rank issues by score descending. + +### 5. Identify Cross-Cutting Concerns + +After clustering, scan for these patterns and call them out explicitly: + +- **Blocking relationships**: Issues where one references another as a dependency or blocker +- **Duplicates**: Issues with near-identical titles or bodies (>80% semantic overlap) — flag as `POSSIBLE DUPLICATE of #NNN` +- **Stale issues**: Open >180 days with 0 comments and 0 reactions — flag as `STALE` +- **Needs triage**: Issues with no labels assigned + +### 6. Produce the Triage Report + +Output a Markdown report with the following structure: + +--- + +## Issue Triage Report — `owner/repo` + +**Generated**: [timestamp] +**Open Issues Analyzed**: N +**Clusters Identified**: N + +--- + +### Priority Queue (Top 10 Issues Across All Clusters) + +| Rank | # | Title | Cluster | Score | Age | 👍 | Labels | +|------|---|-------|---------|-------|-----|----|--------| + +--- + +### Clusters + +For each cluster (sorted by highest issue score descending): + +#### [Cluster Name] +> [Theme description] + +| # | Title | Score | Age | 👍 | Labels | Assignee | +|---|-------|-------|-----|----|--------|----------| + +--- + +### Cross-Cutting Concerns + +**Blocking Chains** (if any): +- #NNN → #NNN → #NNN + +**Possible Duplicates** (if any): +- #NNN may duplicate #NNN — [reason] + +**Stale Issues** (if any): +- #NNN — [title] (open NNN days, 0 activity) + +**Needs Triage** (no labels): +- #NNN — [title] + +--- + +### Metrics Summary + +| Metric | Value | +|--------|-------| +| Total open issues | N | +| Clusters | N | +| Singletons | N | +| Possible duplicates | N | +| Stale (>180d, no activity) | N | +| Needs triage (no labels) | N | +| Avg issue age (days) | N | + +--- + +### Recommended Next Actions + +Based on the analysis, suggest 3–5 concrete, prioritized actions such as: +- "Close or merge duplicates #NNN and #NNN" +- "Add labels to N unlabeled issues before next sprint planning" +- "Cluster `[name]` has N high-priority bugs — consider a dedicated bug bash" +- "Issues #NNN and #NNN should be linked as a blocking dependency" + +--- + +## Operating Principles + +- **Never modify issues** — this is a read-only analysis +- **Cite evidence** for every grouping decision (e.g., "shares label `auth`, mentions `session.ts`") +- **Prefer signal over volume** — a short, accurate report beats an exhaustive one +- **Graceful degradation** — if the repo has <5 open issues, skip clustering and just produce a prioritized list +- **Transparency** — if pagination was cut off at the 200-issue cap, note how many were not analyzed diff --git a/.github/prompts/issue-triage.prompt.md b/.github/prompts/issue-triage.prompt.md new file mode 100644 index 0000000..ec8b00a --- /dev/null +++ b/.github/prompts/issue-triage.prompt.md @@ -0,0 +1,3 @@ +--- +agent: issue-triage +--- diff --git a/.specify/memory/issues-backlog.md b/.specify/memory/issues-backlog.md new file mode 100644 index 0000000..1d2b769 --- /dev/null +++ b/.specify/memory/issues-backlog.md @@ -0,0 +1,52 @@ +# Issues Backlog: Upcoming Feature Specs + +**Purpose**: Track GitHub issues that represent upcoming or in-progress feature work. +**Updated By**: `/speckit.specify` (on issue linkage), manually, or via `gh issue list` + +This file maps GitHub issues to spec branches so the spec-kit workflow stays aligned +with the project's GitHub backlog. It is the single source of truth for "what's next." + +--- + +## How to Use + +1. **During `/speckit.specify`**: When a GitHub issue is provided, the agent adds a row here + linking the issue to the created branch and updates the spec.md header. + +2. **Reviewing the backlog**: Run `gh issue list --repo jwill824/ordrctrl --state open` to + sync open issues with this file. + +3. **Closing issues**: When a PR is merged for a spec, update the Status to "Merged" and + move the row to the Archived section below. + +4. **Issue format in branch names**: Branches are named `NNN-short-name` and the issue + reference lives in `spec.md` header as `**GitHub Issue**: #N`. + PRs MUST close the linked issue with `Closes #N` in the PR body. + +--- + +## Active Issues → Specs + +| Issue # | Title | Priority | Spec Branch | Status | GitHub URL | +|---------|-------|----------|-------------|--------|------------| +| #31 | Update our spec-kit workflow | High | `021-speckit-workflow` | In Progress | https://github.com/jwill824/ordrctrl/issues/31 | + +--- + +## Unassigned Open Issues + +> Issues that have not yet been converted to a spec branch. +> Review periodically and promote to Active when work begins. + +Run to refresh: +```bash +gh issue list --repo jwill824/ordrctrl --state open --json number,title,labels,createdAt +``` + +--- + +## Archived (Merged / Closed) + +| Issue # | Title | Spec Branch | PR # | Closed Date | +|---------|-------|-------------|------|-------------| +| - | - | - | - | - | diff --git a/.specify/memory/stack.md b/.specify/memory/stack.md new file mode 100644 index 0000000..b5df08f --- /dev/null +++ b/.specify/memory/stack.md @@ -0,0 +1,127 @@ +# ordrctrl Project Stack + +**Last Updated**: 2026-03-22 +**Updated By**: speckit.constitution (v1.1.0 amendment) + +> This file is the authoritative reference for project tooling and stack constraints. +> All spec-kit agents MUST read this file when generating technical tasks or plans. +> Update this file via `/speckit.constitution` when the stack changes (paradigm shift). + +## Packaging + +- **Tool**: pnpm (workspace monorepo) +- **Workspace file**: `pnpm-workspace.yaml` +- **Lock file**: `pnpm-lock.yaml` +- **Install command**: `pnpm install` +- **Add dependency**: `pnpm add --filter ` (e.g., `--filter backend`) + +## Version Constraints + +- **Node.js**: See `engines` field in root `package.json` or `.nvmrc` +- **pnpm**: See `packageManager` field in root `package.json` +- **TypeScript**: See `tsconfig.json` in each workspace + +## Linting + +- **Tool**: ESLint +- **Config**: `eslint.config.*` per workspace +- **Lint command (root)**: `pnpm lint` +- **Auto-fix (root)**: `pnpm lint:fix` +- **Lint backend only**: `cd backend && pnpm lint` +- **Lint frontend only**: `cd frontend && pnpm lint` + +## Testing + +### Backend + +- **Framework**: Vitest +- **Run all**: `cd backend && pnpm test` +- **Watch mode**: `cd backend && pnpm test:watch` +- **Contract tests only**: `cd backend && pnpm test:contract` +- **Single file**: `cd backend && pnpm vitest run ` +- **Test directories**: + - Contract: `backend/tests/contract/` + - Unit: `backend/tests/unit/` + +### Frontend + +- **Unit**: Vitest — `cd frontend && pnpm test` +- **E2E**: Playwright — `cd frontend && pnpm test:e2e` + - ⚠️ Requires both servers running (`pnpm dev` from root) +- **Single e2e file**: `cd frontend && pnpm playwright test ` + +### Root (Both Workspaces) + +```bash +pnpm test # backend unit + contract tests +pnpm test:e2e # frontend Playwright e2e (requires servers) +``` + +## Regression Test Commands + +Run these after every implementation phase to verify no regressions: + +```bash +# Step 1: Lint check +pnpm lint + +# Step 2: Backend unit + contract tests +pnpm test + +# Step 3: E2E (only if UI changes; requires `docker compose up -d` + `pnpm dev`) +# cd frontend && pnpm test:e2e +``` + +## Build + +- **Build all (root)**: `pnpm build` +- **Backend build**: `cd backend && pnpm build` +- **Frontend build**: `cd frontend && pnpm build` + +## Infrastructure (Local Dev) + +```bash +docker compose up -d # Start PostgreSQL 16 + Redis 7 (required) +pnpm dev # Start backend (port 4000) + frontend (port 3000) concurrently +``` + +## Database + +- **ORM**: Prisma (client imported from `backend/src/lib/db.ts`) +- **Schema**: `backend/prisma/schema.prisma` +- **Migrate**: `cd backend && pnpm prisma:migrate` +- **Generate client**: `cd backend && pnpm prisma:generate` +- ⚠️ Never edit existing migrations — always create new ones + +## Best Practices Reference + +- Constitution: `.specify/memory/constitution.md` +- Copilot Instructions: `.github/copilot-instructions.md` +- Development Guide: `docs/development.md` +- Architecture Reference: `docs/architecture.md` + +## Commit Message Convention + +Format: `(): ` + +| Type | Usage | +|------|-------| +| `feat` | New feature or capability | +| `fix` | Bug fix | +| `chore` | Maintenance, tooling, deps | +| `docs` | Documentation only | +| `refactor` | Code restructure, no behavior change | +| `test` | Test-only changes | +| `perf` | Performance improvement | + +**Spec-Kit Phase Commit Messages**: + +| Phase | Message format | +|-------|---------------| +| `/speckit.specify` | `docs(spec): initialize NNN-feature-name spec` | +| `/speckit.plan` | `docs(plan): add implementation plan for NNN-feature-name` | +| `/speckit.tasks` | `docs(tasks): generate task breakdown for NNN-feature-name` | +| `/speckit.implement` (per phase) | `feat(NNN): implement ` | +| `/speckit.implement` (final) | `feat(NNN): complete NNN-feature-name implementation` | +| `/speckit.analyze` | `docs(analyze): add consistency report for NNN-feature-name` | +| `/speckit.constitution` | `docs: amend constitution to vX.Y.Z ()` | diff --git a/.specify/scripts/bash/create-new-feature.sh b/.specify/scripts/bash/create-new-feature.sh index 5469702..a09949d 100755 --- a/.specify/scripts/bash/create-new-feature.sh +++ b/.specify/scripts/bash/create-new-feature.sh @@ -5,6 +5,7 @@ set -e JSON_MODE=false SHORT_NAME="" BRANCH_NUMBER="" +ISSUE_NUMBER="" ARGS=() i=1 while [ $i -le $# ]; do @@ -40,18 +41,34 @@ while [ $i -le $# ]; do fi BRANCH_NUMBER="$next_arg" ;; + --issue) + if [ $((i + 1)) -gt $# ]; then + echo 'Error: --issue requires a value' >&2 + exit 1 + fi + i=$((i + 1)) + next_arg="${!i}" + if [[ "$next_arg" == --* ]]; then + echo 'Error: --issue requires a value' >&2 + exit 1 + fi + # Strip leading # if present (e.g., --issue "#31" → "31") + ISSUE_NUMBER="${next_arg#\#}" + ;; --help|-h) - echo "Usage: $0 [--json] [--short-name ] [--number N] " + echo "Usage: $0 [--json] [--short-name ] [--number N] [--issue N] " echo "" echo "Options:" echo " --json Output in JSON format" echo " --short-name Provide a custom short name (2-4 words) for the branch" echo " --number N Specify branch number manually (overrides auto-detection)" + echo " --issue N Link a GitHub issue number (appended to branch name as -ghN)" echo " --help, -h Show this help message" echo "" echo "Examples:" echo " $0 'Add user authentication system' --short-name 'user-auth'" echo " $0 'Implement OAuth2 integration for API' --number 5" + echo " $0 'Fix payment timeout' --issue 42" exit 0 ;; *) @@ -241,6 +258,11 @@ else BRANCH_SUFFIX=$(generate_branch_name "$FEATURE_DESCRIPTION") fi +# Append GitHub issue number to branch suffix if provided +if [ -n "$ISSUE_NUMBER" ]; then + BRANCH_SUFFIX="${BRANCH_SUFFIX}-gh${ISSUE_NUMBER}" +fi + # Determine branch number if [ -z "$BRANCH_NUMBER" ]; then if [ "$HAS_GIT" = true ]; then @@ -304,10 +326,11 @@ if [ -f "$TEMPLATE" ]; then cp "$TEMPLATE" "$SPEC_FILE"; else touch "$SPEC_FILE" export SPECIFY_FEATURE="$BRANCH_NAME" if $JSON_MODE; then - printf '{"BRANCH_NAME":"%s","SPEC_FILE":"%s","FEATURE_NUM":"%s"}\n' "$BRANCH_NAME" "$SPEC_FILE" "$FEATURE_NUM" + printf '{"BRANCH_NAME":"%s","SPEC_FILE":"%s","FEATURE_NUM":"%s","ISSUE_NUMBER":"%s"}\n' "$BRANCH_NAME" "$SPEC_FILE" "$FEATURE_NUM" "$ISSUE_NUMBER" else echo "BRANCH_NAME: $BRANCH_NAME" echo "SPEC_FILE: $SPEC_FILE" echo "FEATURE_NUM: $FEATURE_NUM" + [ -n "$ISSUE_NUMBER" ] && echo "ISSUE_NUMBER: $ISSUE_NUMBER" echo "SPECIFY_FEATURE environment variable set to: $BRANCH_NAME" fi diff --git a/.specify/templates/spec-template.md b/.specify/templates/spec-template.md index c67d914..f7cdbde 100644 --- a/.specify/templates/spec-template.md +++ b/.specify/templates/spec-template.md @@ -3,8 +3,19 @@ **Feature Branch**: `[###-feature-name]` **Created**: [DATE] **Status**: Draft +**GitHub Issue**: N/A **Input**: User description: "$ARGUMENTS" + + ## User Scenarios & Testing *(mandatory)*