to-spec
Turn the current conversation into a spec and publish it to the project issue tracker. No interview, just synthesis of what you've already discussed.
Files2
View on GitHubSKILL.mdskills/first-party/pvmalove/to-spec/SKILL.md
GitHubObjective: Synthesize the current conversation context and codebase understanding into a final specification. Strict Rule: Do NOT interview the user or start a new grilling round. If information feels missing, it means the previous grilling was incomplete; synthesize the spec using only the known facts and explicit assumptions.
The issue tracker and triage label vocabulary should have been provided to you in docs/agents/issue-tracker.md and docs/agents/triage-labels.md. If either file is missing, tell the user to run harness update, which seeds both from the harness templates.
Execution in Two Phases
You must execute this skill in two distinct phases to ensure the user agrees with the testing strategy before you write the final document.
Phase 1: Exploration & Seam Proposal
- Explore the Codebase: Use the project's domain glossary (
CONTEXT.md) and respect any ADRs in the touched area. - Define Seams: Sketch out the seams at which the feature will be tested.
- Prefer existing seams over new ones.
- Use the highest seam possible.
- Ideal state: exactly one seam for the whole feature.
- STOP AND ASK: Present your proposed seams and one integration branch name in the form
integration/<service-or-team>. Derive the slug from explicit project/domain language; never guess it. Ask the user to approve both. Do not proceed to Phase 2 until the user confirms.
Phase 2: Drafting & Publishing (After User Approval)
- Draft the File: Write the spec using the
<spec-template>below, at the root of its own folder underdocs/tasks/— that folder also reservestickets/(one file per child ticket, filled in later by/to-tickets) andartifacts/(the/grillingLive Artifact).- Naming convention: If the issue ID is known, use it. If not, use a descriptive slug (e.g.,
docs/tasks/add-user-auth/add-user-auth.md) and rename both the folder and file later once the ID is generated — seedocs/agents/artifacts.mdfor the full convention, including the epic-folder grouping and thetickets//artifacts/subfolders. - Take the final Discovery Context file list from that same folder's
artifacts/discovery-context.md(written by/grilling's Persisted List step); if that file doesn't exist because artifact tracking never ran, take the approved-paths list from the final Trunk summary instead. Append it in the template's final## Relevant Files (Discovery Context)section. Preserve every path and any supplied context; do not rediscover or replace that list while drafting.
- Naming convention: If the issue ID is known, use it. If not, use a descriptive slug (e.g.,
- Publish to Tracker: Publish the issue with the configured tracker's CLI:
- GitHub:
gh issue create --body-file <path>. - GitLab:
glab issue create -R <project-url> --title '<title>' --description-file <path> --yes. Keep<title>in single quotes and write each apostrophe in it as'\''in a POSIX shell or as''in PowerShell.<project-url>and the other GitLab placeholders (<host>,<project-id>) are defined indocs/agents/issue-tracker.md→ GitLab → Conventions. The epic's number is the last segment of the issue URL the command prints. - Do not pass the body inline with
--body/--descriptionor a heredoc: spec bodies contain nested quotes and backticks that break shell quoting.
- GitHub:
- Apply Labels: This published issue acts as the feature's epic. Apply the following labels (see
docs/agents/triage-labels.mdfor the full taxonomy):type::bugORtype::featurestatus::specs(Do NOT usestatus::readyas it requires decomposition first).task-report::required(unless told to skip).- GitLab:
glab issue update <epic> -R <project-url> --label 'type::feature,status::specs,task-report::required'(type::bugfor a bug; droptask-report::requiredwhen told to skip it). A label the project doesn't have yet is silently created with GitLab's default color instead of failing, so run/setup-labelsbefore the first epic. - Note: Do NOT create ad-hoc
epic::<slug>labels./to-ticketslinks the tickets to this epic later through the tracker's parent link — GitHub sub-issues, or on GitLab a## Parent: #<epic>section plus arelates_toissue link — seedocs/agents/issue-tracker.md#wayfinding-operationsfor the mechanism.
- Ensure the selected integration branch exists after the epic issue succeeds:
- Read the required
base_branchfrom.harness/project.json; if it is absent, stop and report the invalid project config. This is the release/base branch from which the epic integration branch starts. - Record the grill docs that changed in the current worktree:
git status --porcelain --untracked-files=all -- CONTEXT-MAP.md ':(glob)**/CONTEXT.md' ':(glob)**/docs/adr/**'./grill-with-docsand/domain-modelingwrite these files. Record each path; for a rename (old -> new), record both paths. The list can be empty. - Fetch the base ref. Create
integration/<service-or-team>withgit branchfromorigin/<base_branch>when a remote exists, otherwise from the local base branch. Do not usegit switch -corgit checkout -b: the branch-name hook allows them only for names that matchbranch_pattern. - If the integration branch already exists locally or remotely, reuse it without resetting, force-updating, or deleting it. If publication succeeds but branch creation fails, report the partial state and the exact recovery action; do not recreate the epic issue.
- If the branch already exists on the remote, do not commit to it and do not switch the
current worktree. If the grill docs list is not empty, report that these docs stay
uncommitted in the current worktree. Give the recovery action: commit them on an issue
branch from
integration/<service-or-team>, for example the first child ticket's branch, and merge them through its PR. - If the branch is absent on the remote and the grill docs list is empty, do not switch the current worktree; it may contain unrelated changes.
- If the branch is absent on the remote and the grill docs list is not empty, commit the docs
to the branch before you push it. Do not create a separate worktree:
- Switch the current worktree with
git switch integration/<service-or-team>. Uncommitted changes move with the worktree. Ifgit switchrefuses because of a conflict with uncommitted changes, stop. Do not use--force,--discard-changes,--merge, or a reset: they can overwrite changes. Report the git error and the recovery action: put the changes aside withgit stash push --include-untracked, rungit switch integration/<service-or-team>, restore them withgit stash pop, resolve any conflict, and continue from sub-step 2. - Stage only the recorded grill docs, each path named explicitly:
git add -- <path>.... Do not usegit add -A,git add ., orgit commit -a. Other changes stay uncommitted in the working tree. - Run the commit as a standalone command, without
&&,;, a pipe, or a variable:git commit -m 'docs: <short epic summary>'. Write the message by the commit rules indocs/agents/git-workflow.md. Theblock-direct-masterhook allows a commit on anintegration/*branch only in this form, only when the index contains only grill docs paths, and only when the branch is absent onorigin. - If the hook blocks the commit, stop and do not push. Report the hook message and that
the docs stay staged in the current worktree. Give the recovery action: remove the
cause, for example a staged path outside the grill docs or no access to
origin, and repeat sub-step 3.
- Switch the current worktree with
- Push a branch that is absent on the remote with
git push -u origin integration/<service-or-team>. After a grill docs commit, the current worktree stays on the integration branch, with unrelated changes uncommitted. - For a local tracker, make the grill docs commit as above, but do not push; report that the branch was not pushed. In a repository without a remote, create the local branch and do not commit or push. Report that the branch was not pushed and that the grill docs stay uncommitted.
- Read the required
<spec-template>
Problem Statement
The problem that the user is facing, from the user's perspective.
Solution
The solution to the problem, from the user's perspective.
User Stories
A numbered list of user stories that covers every behavior of the feature.
Format: 1. As an <actor>, I want a <feature>, so that <benefit>
(Example: As a bank customer, I want to see my balance, so that I can make informed spending decisions).
Implementation Decisions
A list of modules to build/modify, interface changes, technical clarifications, architectural decisions, schema changes, API contracts, and specific interactions.
- DO NOT include specific file paths or generic code snippets (they outdate quickly).
- Exception: If a prototype produced a snippet that encodes a decision perfectly (state machine, schema, type shape), inline it and note it came from a prototype. Trim it to the decision-rich parts only.
Testing Decisions
- Description of what makes a good test here (test external behavior, not implementation details).
- Which modules will be tested.
- Prior art (similar existing tests in the codebase).
Out of Scope
A strict list of things that will NOT be done. This is your insurance policy against over-engineering. Be explicit about boundaries so future agents do not build more than requested.
Integration Branch
- Branch:
integration/<service-or-team> - Created from:
base_branchin.harness/project.json - Child issue branches start from this integration branch and open PRs back to it.
Further Notes
Any remaining context or constraints.
Relevant Files (Discovery Context)
The final Discovery Context file list captured in the session's Live Artifact, or in the final Trunk summary when artifact publishing is unavailable, including each path and any supplied context.