Write great stories and create tickets. Transforms feature descriptions into well-structured stories with proper narrative, acceptance criteria, and ticket creation. Works standalone or as part of /ks-feature workflow.
How this skill is triggered — by the user, by Claude, or both
Slash command
/keller-solutions-core:plan <feature description><feature description>The summary Claude sees in its skill listing — used to decide when to auto-load this skill
Write great stories and create tickets that produce clean, reviewable code.
Write great stories and create tickets that produce clean, reviewable code.
Stories are promissory notes for conversations, not specifications.
The card captures what to discuss; the conversation reveals how to build it. Well-written stories produce well-scoped, reviewable pull requests.
Extract from the user's input:
Before writing, read what already defines the work:
Source material varies—sometimes polished wireframes and a design handoff, sometimes only a written spec, sometimes nothing but the description in the prompt. The method is the same regardless: break whatever material you have down to its key interactions, and card each as one context, one action, one outcome. Richer sources mean more verbatim Content and tighter References; thinner sources mean more decisions to make and log. What never changes is the decomposition—and the QA pass at the end to confirm you applied it consistently.
Read designs just in time: review the relevant screen in full immediately before writing its story—not from memory of an earlier skim.
When sources conflict, establish a precedence order (typically: most recent client-reviewed design > wireframes > written requirements) and flag material conflicts to the user.
Don't try to determine every question in advance; real questions surface while writing. When one arises:
If the initial description is too vague to start at all, ask focused questions first:
Before I write the story, I need to clarify a few things:
1. **Who is the primary user?** (e.g., first-time user, returning user, admin)
2. **What's the business value?** (Why does this matter?)
3. **Any specific requirements?** (Performance, accessibility, mobile)
Only ask questions that will change the story. Don't ask for the sake of asking.
Every feature story uses this format:
Title: [Who] [action] [where]
**In order to** [business value - WHY]
**As a** [specific persona in context - WHO]
**I want** [user-facing capability - WHAT]
## Acceptance Criteria
- [ ] [Observable outcome 1]
- [ ] [Observable outcome 2]
- [ ] [Observable outcome 3]
- [ ] [Observable outcome 4]
Order matters: In order to → As a → I want
This forces justification before description. If you can't articulate the value, the story shouldn't exist.
Express genuine business value, not restatement of the feature:
# Bad: restates the WHAT
In order to see a list of projects
# Good: expresses actual value
In order to quickly resume work on recent audits
Test: Delete the "I want" clause. Can you still understand why this matters?
Be specific. Use adjectives that illuminate context:
# Vague
As a user...
# Specific
As a first-time user unfamiliar with accessibility terminology...
As a busy consultant running audits for multiple clients...
As a developer reviewing scan results during a sprint...
Stay on the user's side of the glass. The persona is always someone using the product—never the developer building the feature, the platform itself, or a back-office system/vendor:
# Banned personas
As a developer... (building this feature)
As the platform...
As the system...
As a [your company] staff member... (when your company isn't the product's user)
(A developer is a legitimate persona only when developers are the product's end users.) If no honest user persona exists, the work is a Chore (see Story Types)—never invent a fake narrative. Frame groundwork as the user-visible capability it enables wherever honestly possible: a data sync exists so "a member sees up-to-date availability," not so "the system has a mirror."
Start with a verb describing what the user can do:
# User-centric (good)
I want to see my projects listed by last activity
I want to filter issues by severity
# System-centric (avoid)
I want the system to query the database
I want an API endpoint for projects
Guidelines:
# Good: observable outcomes (verifiable in browser)
- [ ] Projects header is visible
- [ ] Each project shows name and last scan date
- [ ] Projects are sorted by last activity (most recent first)
- [ ] Clicking a project navigates to the project detail page
# Bad: implementation details (requires reading code)
- [ ] Query uses ORDER BY updated_at DESC
- [ ] Projects are rendered using the ProjectCard component
The Browser Test: Can a non-developer accept or reject this story by using the application in their browser, the same way an end-user would? If verification requires reading code, database queries, or server logs, rewrite the criteria.
Annotations: For complex features, annotate criteria with (required), (optional), or (conditionally required) to clarify expectations. Use sparingly—most criteria are implicitly required.
A story describes a single user doing a single thing to achieve a single result.
Same action, different contexts = different stories:
Same context, different actions = different stories:
Same action, different outcomes = different stories:
If a story has more than 8 acceptance criteria, split it:
# Too large
Story: User manages projects
(What does "manages" mean? Create? Edit? Delete? Archive?)
# Split properly
Story 1: User creates a new project
Story 2: User renames a project
Story 3: User archives a project
Story 4: User deletes an archived project
Before finalizing, verify the story avoids these issues:
WHY is just WHAT in different words.
Story tries to do too much.
Describes technical work instead of user value.
References UI elements that don't exist yet.
Criteria that can't be objectively verified.
"As the platform" / "As the system" / "As a developer" (building the feature). If there's no honest user persona, it's a Chore.
A story with no acceptance criteria. If you can't state observable outcomes yet, you haven't finished the conversation the card promises.
Acceptance depends on a story that hasn't shipped yet (see Deliver Without Seeding).
Chores creeping past 10% of the story set—user value is being hidden in technical work. Reframe groundwork as the capability it enables.
The first story for a page builds every element the wireframe shows, with siblings linked to # "for now." Each element ships with the story that wires it up (see Elements Ship With Their Stories).
Use the managing-tickets skill: detect which tool the project uses (GitHub Issues, Jira, ClickUp, Linear), create the ticket with the full story as the body—narrative, acceptance criteria, Content, References, Developer Notes—and link it to its epic if one applies.
Present the created story: issue number, title, URL, the narrative, and the numbered acceptance criteria. Close with: "Ready to proceed with /ks-produce to implement this story."
When invoked directly (/ks-plan <description>):
When invoked as part of /ks-feature:
/ks-produceDeliver user-visible value. Use full narrative format.
Something that worked before is now broken.
Title: [Describes incorrect behavior]
**Steps to reproduce:**
1. Navigate to /scans/123/issues
2. Filter by severity: "critical"
3. Page 1 shows only critical issues (correct)
4. Click "Next" to page 2
5. Page 2 shows all issues (incorrect)
**Expected:** Page 2 shows only critical issues
Groundwork that genuinely cannot be framed as user-visible value verifiable in a browser. A chore gets a one-line purpose tied to the user value it unlocks and completion criteria a reviewer can check—no fake user narrative.
Title: Chore: Vendor data sync foundation
**Purpose:** every dashboard story reads from a local mirror of the
vendor's data; this lays the sync engine those stories stand on.
**Completion criteria**
- [ ] A recurring job mirrors vendor records locally
- [ ] Re-running the job is idempotent
- [ ] Each run records counts a reviewer can inspect
Keep chores under 10% of total stories. Above that, you're hiding user value in plumbing—reframe (see The Hidden Plumbing).
Every story should be acceptable using only what the application—as built by the stories before it—can produce. Seeding—console commands, fixtures, hand-created data—is a last resort, reserved for preconditions the application genuinely cannot produce (e.g., data only an external system can originate). The payoff comes at acceptance: a reviewer walks the story with the normal tools an average user has (a browser, not the Rails console).
This is why delivery order matters: each story creates the conditions the next one needs. A story may never depend on a later story.
CRUD is the everyday case. Order it add → index → detail → edit → delete: the Add story is how the reviewer gets a record to look at, so it ships first—even when "first" means the section is nothing but an Add button landing on a bare confirmation page. The index arrives in the next story. You can't edit what nothing created.
The same logic reaches well beyond CRUD:
The Seeding Test: Walk the acceptance criteria as the reviewer. For every precondition ("a project exists", "a request is pending"), can you create it in the browser using only earlier stories? If not, reorder. If no ordering can produce the precondition, seeding is the last resort—call it out in Developer Notes so the reviewer knows before they start.
Each mutating story should include confirmation feedback: "[Item name] was created/updated/deleted."
The flip side of Deliver Without Seeding: just as a story may not lean on later stories, it may not ship fragments of them either. A UI element appears only when the story that makes it work ships. Never add a placeholder button, nav item, or link to # because the design shows one—that's pre-optimization (Guiding Principle #3), and dead links get reported as bugs.
A wireframe or comp is a map of where future stories will land, not a checklist for the first story to touch that page. The screen accretes element by element as its stories ship.
Write stories knowing this and they describe elements differently: the story that delivers a destination also delivers its entry point, and an early criterion asserts the element appears. The classic example is the About page. The global-nav About link is not part of a "build the nav" story—it ships with the story that gives it somewhere to go:
Title: User visits the About Us page
**In order to** learn more about the company
**As a** user on any page in the site
**I want** to view the About Us page
## Acceptance Criteria
- [ ] About Us link is present in the global nav
- [ ] Clicking About Us takes me to the About Us page
- [ ] I see the About Us headline and copy with images specified in the copy doc
A second entry point is a second story (different context—see the Cardinal Rule):
Title: User visits the About Us page from the footer
**In order to** quickly access the About page without scrolling back to the top
**As a** user at the bottom of any page in the site
**I want** to visit the About Us page
## Acceptance Criteria
- [ ] About Us link is present in the footer nav
- [ ] Clicking About Us takes me to the About Us page
For a single feature, the phases above run once and end in a ticket. For a feature set—a new portal, a new client area, anything spanning multiple screens or producing a large batch of stories—switch to Story Map Mode and write the full map as markdown before any tickets exist. It adds: epics with continuous numbering, coverage tables (element/interaction → story ID, where an uncovered item is a gap), the architecture sync rule, a user checkpoint before carding begins, a drift-focused QA Pass, and tickets created only after the map is ratified.
Run that QA Pass whenever a session produces more than a handful of stories, even outside full story-map mode: long sessions drift, and the stories written last must obey the rules as strictly as the stories written first.
Title: [Who] [action] [where]
**In order to** [business value]
**As a** [specific persona in context]
**I want** [user-facing capability]
## Acceptance Criteria
- [ ] [Observable outcome 1]
- [ ] [Observable outcome 2]
- [ ] [Observable outcome 3]
- [ ] [Observable outcome 4]
## Content
[Only copy an acceptance criterion asserts verbatim—button labels,
headlines, error/empty-state/confirmation messages]
## References
[Specific artifact + location, e.g. "Wireframe B2 p.4", "Figma: Checkout / payment error state"]
## Developer Notes
[Technical guidance that doesn't belong in acceptance criteria]
Only copy that an acceptance criterion asserts verbatim—button labels, headlines, error/empty-state/confirmation messages. For everything else, point References at the design source instead of transcribing it. Content strings are externalized to locale/data files at build time.
Technical context that helps implementation but shouldn't pollute acceptance criteria. Keep criteria browser-verifiable; put implementation hints here.
Good: "Standard OneTrust implementation", "Card is sticky on scroll", "See patterns in app/views/dashboard/"
Not Developer Notes: Observable behavior like "Button is visible" belongs in criteria.
Include links to design assets when available—Figma, prototypes, spreadsheets with calculation logic. This keeps stories self-contained and reduces back-and-forth.
Cite the specific artifact and location, never a bare link or screen code: "Wireframe B2 p.4", "A3 Registrations — bulk add flow", "Figma: Checkout / payment error state".
For a single story, this checklist is the QA. When a session produces a batch of stories, also run the QA Pass (see Story Map Mode) to catch drift across the set.
Before creating the ticket, verify:
npx claudepluginhub keller-solutions/kslabs-marketplace --plugin keller-solutions-coreGuides creation, editing, and verification of skills for AI coding agents using test-driven development with subagent scenarios. Use when authoring or debugging skills.