Journey 2 — Frontend Screen Happy Path
Purpose: Walk one concrete Page work item from open to merged pull request, command by command. Reading time: ~15 minutes · Audience: a developer running their first real screen on Swifter, with no prior system knowledge · This journey assumes Journey 1 — Setting Up the Swifter Project is done.
This journey is the one a team repeats most often on a Swifter engagement, and the one that should feel routine by the end of week one. Every step is one exact agent call or one exact click — no "or" branches the reader has to disambiguate — followed by the inline verification that proves the step worked.
Worked example we will walk through
We continue the acme-crm example from Journey 1.
| Aspect | Value |
|---|---|
| Project | acme-crm |
| Module | crm-fe (Frontend, React) |
| Work Item | 0042 Customers list — read-only table |
| Page name | customers-list |
| Route | /customers |
| Figma | A single page frame with two pre-shipped child components: customer-row (one customer per row) and status-badge (used inside customer-row) |
| Out of scope | API integration — "Use mocked data. The Integration WI comes later in Journey 3." |
Work-item codes are zero-padded numbers assigned by Swifter (
0001,0042, …). We use0042for the page and0038/0039/0040for the pre-shipped siblings below; your project's codes will differ.
By the end of this journey the work item is Done, the PR is merged into main, and the Customers list renders on a session-branch Preview from mocked data.
The Work Item text — paste this into your tracker
This is what 0042 actually contains. Copy it, replace the placeholders, run it.
## Page
customers-list
## User story
As a CRM operator, I open the Customers list so that I can scan recent customers, see each customer's status, and click through to a detail screen later.
## Sibling reference
Use the approach and patterns of 0040 (Customers landing page header) — already shipped.
## Components on this page
- customer-row, 0038 — already shipped (one customer per row: avatar, name, status badge, last-payment date)
- status-badge, 0039 — already shipped (the badge used inside customer-row)
## Display rules
IF customers list is empty THEN show empty-state message "No customers yet"
IF row.status = OVERDUE THEN status badge colour = red, label = "Overdue"
IF row.status = ACTIVE THEN status badge colour = green, label = "Active"
IF row.status = CLOSED THEN status badge colour = grey, label = "Closed"
## Mock-data shape
List of Customer rows. Each row carries:
- id (string)
- name (string)
- status (enum: ACTIVE / OVERDUE / CLOSED)
- principal (number)
- paid (number)
- payments[] (array of { date: ISO string, amount: number })
## Scope-out
API integration is out of scope. Use mocked data. Request params: none.
Authentication is out of scope; assume the user is logged in.
Real-time updates are out of scope; static load only.
## Figma
https://figma.com/file/AcmeCRM/customers-list-frame?node-id=42-0 (replace with your project's specific frame URL)
## Implementation Hints (optional)
- Use existing components: customer-row, status-badge — do not re-onboard or re-create them.
- Storybook linkage: stories must import and render the real customers-list page component, providing mock data via the page's mock service. Do not create inline wrapper components that duplicate the page's logic.
Acceptance criteria are not authored in the WI body — /swifter-frontend-analyst:generate-acceptance-criteria derives them in Step 5 from the user story, scope-out, and display rules above. The Sibling reference and Breadcrumb blocks are optional; in this WI we include the sibling (because 0040 exists and shares the page family) but omit the breadcrumb (it adds no signal beyond the route name). See Work-Item Description Composition for the full guidance.
The two components (customer-row, status-badge) are pre-shipped as separate Component WIs before the Page WI opens; this journey only walks the Page WI itself.
Journey at a glance
Eighteen numbered steps follow. Each step has the same shape:
- Action — exactly what to click or type.
- Why this step exists — one sentence on what the agent will do or what state it puts the project in.
- Verification — an inline checklist the operator can confirm against the on-disk artefact or the UI.
- If a check fails — the resume command, or the step to return to.
Step 1 — Open WI 0042 in the Reqs tab
Action. In the Swifter sidebar, open project acme-crm → click Reqs. Find 0042 Customers list — read-only table. Click it.
Why this step exists. The Reqs tab is the work item's home. The work item already has an Origin session and chat (created with the WI); opening the WI is how you reach them.
Verification.
- URL ends with
/projects/acme-crm/work-items/0042(or the equivalent for your project). - The work item header shows status BACKLOG (or READY if its predecessors are satisfied) and a Start button.
- The WI body matches the markdown above —
## Pageheading, user story, four display rules, scope-out line, Figma link. No## Acceptance criteriablock (it would be overwritten by Step 5).
If a check fails: the WI code is wrong, the WI was already started (status IN_PROGRESS/REVIEW, and the Origin chat shows prior messages), or the body is empty. Either fix the WI text in the Reqs tab or back out and look up the correct code.
Step 2 — Confirm the work item is ready before pressing Start
Action. In the WI body, walk the readiness checklist below. Do not press Start until every box is checked.
Why this step exists. A Page WI missing a Figma frame, sibling reference, or mock-data shape will burn a session producing a spec you have to throw away.
Verification.
- Type in the WI body says
## Page(exactly — not "Task" or "Story"). - User story is one paragraph, role + action + outcome.
- Display rules (if the page has conditional rendering) are written in the conditional-logic format from Work-Item Description Composition § Principle 4 — one parseable rule per line. Without these the agent paraphrases the Figma into prose and the AC step has nothing to anchor on.
- Figma line points at one frame, not a whole file. For a new page,
define-page-spec(CREATE mode) needs a Figma URL and validates that it containsfigma.com. A frame-specificnode-id=is strongly recommended — a file-root URL caches the whole file and balloons the work — though the command does not currently reject a missingnode-id. - Sibling reference is present if a sibling exists; if no useful sibling exists for the page, omit the block entirely (placeholders like "no sibling exists" add noise without signal).
- Scope-out explicitly says
API integration is out of scope. Use mocked data. - Mock-data shape lists every field the page renders, with types.
- No
## Acceptance criteriablock. AC are generated in Step 5 from the user story + scope-out + display rules; authoring drafts here causes them to be overwritten.
If a check fails: edit the WI text in the Reqs tab. The WI body is plain markdown — paste corrections directly. Re-walk the checklist when done.
Step 3 — Press Start to activate the session
Action. In the WI header, press Start.
Why this step exists. The Origin work-session and its chat already exist (they were created atomically with the work item). Start activates that session and turns the App / Dev / Test tabs from greyed-out to live. The session flips to IN_PROGRESS on the first agent message, and a session branch named feature/0042_Origin is created once the agent pushes its first commit.
Verification.
- WI status moves from BACKLOG/READY to IN_PROGRESS (it transitions on the first agent message in this session).
- The session header shows the
Originchat. - App tab and Dev tab become clickable. App tab is empty for now; the Dev tab shows the branch-base (
main) content. - A branch
feature/0042_Originwill appear in the Dev tab header once the agent has pushed a commit — it may not exist yet immediately after Start.
If a check fails: Start may have been pressed already in a previous session. Look at the Origin chat for existing messages. If you genuinely need to restart, see Troubleshooting → Session-Naming Artefact.
Step 4 — Pick the Frontend Analyst in the agent picker
Action. In the Origin chat, open the Select agent picker, choose Frontend Analyst, then Confirm.
Why this step exists. For a Page WI with no spec yet, analysis precedes implementation. The Frontend Analyst is the agent that converts Figma + the WI body into a spec the developer agent can build from.
Verification.
- The chat header shows
Frontend Analystas the active agent. - Typing
/in the chat input surfaces the analyst's commands under the/swifter-frontend-analyst:namespace. - The session-status panel lists the active agent and the WI code together.
If a check fails: the chat may still be on the default agent. Reopen the Select agent picker from the chat header.
Step 5 — Run /swifter-frontend-analyst:generate-acceptance-criteria
Action. In the Origin chat input, type exactly:
/swifter-frontend-analyst:generate-acceptance-criteria
Press Enter. No arguments — the command reads the WI body directly.
Why this step exists. Acceptance criteria are not authored in the WI body — they are derived here from the user story, scope-out, and display rules. The command produces acceptance-criteria.yaml: a numbered, machine-readable, testable list every later step keys off (the spec, the developer code, the QA agent). Authoring AC upstream is duplicate work the command overwrites.
Verification.
- The agent reports
acceptance-criteria.yamlwas written to.swifter/work-item-artifacts/0042/acceptance-criteria/(the agent prints the exact path). - It contains 4–10 entries.
- Each entry has an
id(a short generated identifier in the form<5-char>-<n>, e.g.a7k9m-1), adescription, and anexpected_outcome(non-empty array). - None of the descriptions mention frameworks, hooks, CSS classes, or API endpoints — criteria must read as user-observable assertions.
If a check fails: re-run the same command. Do not edit the YAML by hand — the file is regenerated on every run and hand edits will be overwritten.
Step 6 — Run /swifter-frontend-analyst:define-page-spec
Action. In the same Origin chat, type:
/swifter-frontend-analyst:define-page-spec
Press Enter. No arguments needed — the command reads the page name, Figma link, and route from the work item first. Positional arguments [page_name] [figma_url] [route_path] are optional overrides; supply one only to override what's in the WI (e.g. the route, if the WI body doesn't state it).
Why this step exists. This is the analyst's entry point for a Page WI. In CREATE mode it does two things: it delegates the whole component pipeline to /define-component-spec (which internally caches Figma, matches style tokens, generates vanilla HTML/CSS, refreshes framework + Storybook knowledge, writes a placeholder component, onboards it, and verifies the Storybook build), then it attaches the ## Routing section to the page MDX and switches the Storybook preview tag to page_preview. Every later step depends on the artefacts that pipeline writes.
Verification. Under .swifter/specs/crm-fe/components/customers-list/:
-
component-implementation.mdexists and is non-empty (it records the placeholder component's path, main file, and import statement). -
template.htmlexists — semantic HTML5 with no framework directives (*ngIf,v-if,{condition && …}, JSXclassName, etc.). -
styles.cssexists and usesvar(--token-name)references for every value matched in the style mapping. -
preview.htmlexists and opens without console errors. -
mapping-used.jsonexists (the summary of which token mappings were applied). - One or more
*.stories.*files exist. - One
*.mdxfile exists and contains a## Routingsection withPath: /customersand aType:line (staticfor this WI). -
metadata.yamlexists (read via thework-with-component-library-toolsetskill — never rawRead). - Under
.swifter/cache/figma/:customers-list.json,customers-list.meta.json,customers-list.style-mapping.jsonall exist with acachedAtfrom this run. - The agent's final report includes "Storybook build: green".
In the App tab: the new component appears under App → Components → customers-list, and its stories are visible in the App tab's Storybook view, rendering against mocked data.
If a check fails: the command prints a resume command for the failing sub-step — paste back exactly what it printed (the argument it expects varies by command — e.g. fetch-figma-data takes a Figma URL, the others take a cache/component name). The sub-steps you may be resumed into are:
fetch-figma-data— re-cache the Figma frame.match-figma-styles— re-walk the style mapping (interactive — confirm any low-confidence tokens).generate-figma-html-css— re-rendertemplate.html/styles.cssfrom the cache.onboard-component— re-register the component in the library.
If no resume command appears, re-run /swifter-frontend-analyst:define-page-spec (the command above).
Step 7 — Review the spec in the App tab
Action. Open the App tab. The App tab's left panel has these sub-views: Pages, Data model, Logic, API Library, Components, Styles — plus a separate Storybook view. Walk these, in order:
- Storybook view. Click each named state (empty, populated, error). Each state must match the corresponding Figma frame.
- Data model. Confirm every column the Figma shows traces to a
data_model.yamlattribute. Computed columns (e.g.remaining = principal - paid) must be flagged as computed with the formula stated. - Logic. Display and validation rules must match the conditional-logic block authored in the WI body — each one independently parseable, not collapsed into a narrative paragraph. Behaviours (click handlers) must match the design's interaction model.
Why this step exists. This is the last review checkpoint before the spec is turned into code in the developer steps — the place to catch drift between the Figma / WI and the generated spec.
Verification.
- Every state Figma defines has a matching Storybook story (empty / populated / error at minimum).
- Every visible Figma value has a data-model attribute or is explicitly marked computed.
- Display rules in the spec match the conditional logic written in the WI body — each rule is independently parseable, not collapsed into a narrative paragraph.
- The routing section in the MDX matches the WI: path
/customers.
If a check fails: type a refinement in the same chat — e.g. Add an explicit OVERDUE state to the badge stories; the customerName field is computed as first + last, mark it as such. For structural changes (a new state, a new column) re-run /swifter-frontend-analyst:define-page-spec; for prop or rule tweaks, the next two steps will pick them up.
Step 8 — Run /swifter-frontend-analyst:work-on-component-data-model
Action. Same Origin chat:
/swifter-frontend-analyst:work-on-component-data-model
Press Enter. No arguments — the command reads the page-component from the WI context. Wait for the explicit Approve gate the command raises before any write.
Why this step exists. Generates data_model.yaml declaring the typed entities, fields, and enums the page renders. The developer agent in Step 12 will import these types — without them, types get re-invented inline and drift between page and consumers.
Verification. Read via the work-with-data-model-toolset skill — never raw Read on the YAML:
-
data_model.yaml(or equivalent entries under adata_model/directory) exists forcustomers-list. - Every column in the Figma frame maps to a field; field types match the WI's mock-data shape (
status: ACTIVE | OVERDUE | CLOSEDis an enum, not a string). - Cross-component references (e.g.
customer-rowalready-shipped sibling) annotate the owning component on first mention. - No fabricated values — fields without source data are left empty and called out in the activity log.
If a check fails: re-open with the agent in chat (e.g. "the status field came back as a string — convert to the enum ACTIVE | OVERDUE | CLOSED"). Do not raw-Write / Edit the file; the toolset skill is the only sanctioned write path.
Step 9 — Run /swifter-frontend-analyst:work-on-component-logic
Action. Same Origin chat:
/swifter-frontend-analyst:work-on-component-logic
Press Enter. No arguments. Wait for the explicit Approve gate before any write.
Why this step exists. Generates display rules, validation rules, and function signatures. Each conditional-logic line from the WI body — status → badge colour/label, empty list → empty-state message — becomes a display rule the agent can later compile into framework code. The developer agent in Step 12 imports these as standalone modules.
Verification. Read via the work-with-logic-specifications-toolset skill — never raw Read on the YAMLs:
- At least one of
validation_rules/validation_rules.yaml,display_rules/display_rules.yaml,functions/functions.yamlexists under the page's spec folder. - The four display rules from the WI body (empty-state message, OVERDUE/ACTIVE/CLOSED colour and label) appear in
display_rules.yaml, each as a parseable rule. - Custom-over-built-in: the logic refers to already-onboarded project-specific components (
customer-row,status-badge) when equivalents exist. - No fabricated values — empties flagged in the activity log.
If a check fails: re-run the command. If a rule was missed because the AC was ambiguous, refine the AC source (user story / display rules) in the WI body first, then re-run Step 5 (generate-acceptance-criteria) and Step 9 together.
Step 10 — Approve the spec and open a development chat
Action. Type Approve in the Origin chat to release the last gate the analyst is waiting on. Then open a new chat: in the chat sidebar of the WI header, click + New chat → name it development (or accept Swifter's auto-generated name).
Why this step exists. Origin carries the analyst's full context — Figma cache, style mapping, the whole component pipeline's state. The developer agent needs none of that and benefits from a clean chat (smaller context, fewer hallucinations).
Verification.
- The
Originchat shows the analyst's final report with paths to all generated artefacts and "Approved" or equivalent on the last gate. - A new chat appears in the chat sidebar, attached to the same WI
0042. - The new chat is empty and shows the agent picker again.
If a check fails: the + New chat button is sometimes hidden behind the session-status panel — collapse the panel and try again.
Step 11 — Switch the new chat to Frontend Developer
Action. In the development chat, click the agent picker → select Frontend Developer → Confirm.
Why this step exists. The developer agent has different commands, different skills (toolsets for reading the analyst's YAMLs), and different model defaults. Running developer commands while the chat is still on Frontend Analyst will either fail or produce spec-like text instead of code.
Verification.
- Chat header shows
Frontend Developer. - Chat input hint includes
/swifter-frontend-developer:.
If a check fails: reopen the picker.
Step 12 — Run /swifter-frontend-developer:work-on-component-logic customers-list all
Action. In the development chat:
/swifter-frontend-developer:work-on-component-logic customers-list all
Press Enter. The first argument is the page name (kebab-case). The second argument all generates types, validators, display-rule utilities, and function modules together.
Why this step exists. The analyst produced spec YAMLs; this command turns them into real source files (.ts / .tsx for React, .ts for Angular, etc.). Types are emitted first because the component implementation in Step 13 imports them. Running logic before the component avoids the typical drift of inlined types that then need extracting on every refactor.
Verification. Under PROJECT_GIT_ROOT/<logic-modules-dir>/customers-list/:
-
customers-list.types.ts(or framework-equivalent extension) exists. Every entity, field, and enum fromdata_model.yamlis reflected. Enums are expressed as the framework's idiomatic enum/union form, not strings scattered through the code. -
customers-list.display-rules.tsexists (because Step 9 produced display rules). -
customers-list.validation.tsexists if Step 9 produced any validation rules. -
customers-list.logic.tsexists if Step 9 declared any functions. -
index.ts(barrel export) re-exports only the modules that were generated — no dangling exports. - Every generated file carries a generation-metadata comment at the top (timestamp + source spec path + scope).
- Spot-check that these stay presentation-side modules — flag any import of an HTTP client, a store, a page, or a route.
Under .swifter/specs/crm-fe/components/customers-list/:
-
logic-mapping.jsonexists withscope: all, the list of generated files, framework + validation-library versions, and agenerated_attimestamp from this run.
Build: the command runs the project build and reports green. If red, the command runs up to three fix-and-retry cycles automatically.
If a check fails: the agent emits a resume command (/swifter-frontend-developer:work-on-component-logic customers-list <narrower-scope> such as data_model, validation, display_rules, or functions). Paste it back. Do not edit the logic modules by hand.
Step 13 — Run /swifter-frontend-developer:generate-page customers-list
Action. Same development chat:
/swifter-frontend-developer:generate-page customers-list
Press Enter. The command reads the ## Routing section from customers-list.mdx, the logic modules from Step 12, the framework knowledge cache, and produces the page wrapper. If the page's underlying component implementation doesn't yet exist (it usually doesn't — Step 6 only wrote a placeholder), the command will ask via AskUserQuestion: "Component specification found but implementation not generated. Should I generate the component implementation now before proceeding?" — answer Yes, generate component first (Recommended).
Why this step exists. This is the step that replaces the analyst's placeholder with framework-native code. The page wrapper extracts route parameters and applies guards; the component implementation renders the mocked data; then the project build runs.
Verification. Under SOURCE_DIR/customers-list/:
- Main implementation file replaces the placeholder — the Step-6 placeholder marker comment is gone, and the new file carries its own generation-metadata comment.
- Prop interface imports types from
customers-list.types. - Display rules and validators are imported from the Step-12 modules — not re-implemented inline.
- Template uses only HTML elements or already-onboarded project-specific components (
customer-row,status-badgefrom the sibling WIs). No rawmat-*,<MuiButton>,<v-btn>, etc.
Under the framework's pages/views directory (location depends on framework — app/customers/page.tsx for Next.js App Router, src/pages/customers-list.vue for Vue, src/app/customers-list/customers-list.component.ts + a routing-module entry for Angular):
- Page wrapper file exists.
- Route definition appears in the project's routing config, or is implicit via file-system routing.
Under .swifter/specs/crm-fe/components/customers-list/:
-
page-mapping.jsonexists (route path, route type, parameter mappings, decisions, spec artefacts applied). -
component-mapping.jsonexists only ifgenerate-pagehad to generate the component implementation first (theAskUserQuestionbranch above) — it lists the onboarded components used and the mapping decisions. If the implementation already existed, this file won't be (re)written bygenerate-page.
Build:
- Project build: green (reported in chat).
If a check fails: the command's own self-recovery handles common build errors (imports, type mismatches). If it surfaces an unfixable failure, the resume command is /swifter-frontend-developer:generate-page customers-list — re-run after addressing the root cause in the same chat. Do not open a new chat — keep iterating in the same development chat so the developer keeps its full context.
Step 14 — Review the generated code in the Dev tab
Action. Open the Dev tab — a code browser with a file tree. Open the page wrapper file, the component implementation, and each logic module from the tree, and scan each for the checks below.
Why this step exists. A second review checkpoint, now over the generated code. The developer agent honoured the spec, but it could have added an unauthorised dependency, mis-routed an import, or skipped a Storybook story.
Verification.
- Imports come from the project's component library where one exists (e.g. the project's grid wrapper, not raw
ag-grid-react). -
package.jsonand the lockfile are unchanged unless the WI explicitly authorised a new dependency. Open them from the file tree and confirm no dependency was added. - Storybook MDX renders against the new implementation (Storybook build was green in Step 13; spot-check by opening the story file).
- If the project's WI template requires Playwright stubs for new pages, they are present at the expected path.
If a check fails: return to the development chat and ask the agent to fix the specific issue (e.g. package.json gained a new dependency — remove it and replace with the project's existing X library). Same chat, not a new one.
Step 15 — Walk the page states in Preview
Action. Click the Preview button in the work-item header. It opens the running app from the session branch in an overlay panel with a path field — enter /customers to navigate. Walk these four states by editing the mock service inputs the Step-13 generated code reads from:
- Empty. Mock returns
[]→ empty-state message "No customers yet" appears. - Populated. Mock returns 5 rows → all 5 render with name, status badge, and last-payment date.
- Status colours. One row of each status → badge colours: ACTIVE green, OVERDUE red, CLOSED grey.
- Error. Mock throws → page renders the error boundary (a generic message; the spec did not require a custom one for this WI).
Why this step exists. Storybook and the App tab show the component in isolation. Preview shows it in the full application shell — including the breadcrumb, the routing, and the parent layout. The states Storybook defined must be reachable from Preview, or the page does not actually work end-to-end.
Verification.
- Each AC in
acceptance-criteria.yaml(generated in Step 5) is observably true in Preview. - The breadcrumb the app shell renders matches the route (e.g.
Home > Customersfor/customers). - No console errors appear in Preview's developer tools while walking the states.
If a check fails: identify which AC failed, return to the development chat, and describe what you saw vs. what the AC says. Do not edit Preview-only mock data permanently — the WI's ## Mock-data shape is the source of truth and downstream WIs will key off it.
Step 16 — Press Create pull request
Action. In the WI header (Reqs tab), press Create pull request.
Why this step exists. Pressing the button immediately opens the PR from the session branch into main against the configured version-control provider (ADO / GitHub / GitLab) with a server-generated title and description, and surfaces the PR URL in the header.
Verification.
- The WI header shows a PR number and a clickable PR URL.
- Clicking the PR URL opens the merge proposal in the provider's UI; source branch is
feature/0042_Origin(or the developer session's branch), target ismain. - The auto-generated PR description reflects the work; edit it in the provider's UI if anything needs changing before review.
If a check fails: the most common causes are that the branch has only artifact commits (artifact-only commits don't count toward "Create pull request"), or Step 15 left the branch dirty (a mock-data edit you forgot to revert). Return to the development chat, ask the agent to commit real outstanding changes, then re-press Create pull request.
Step 17 — Check pull request status until CI is green
Action. Press Check pull request status in the WI header. Swifter polls the provider and refreshes the latest review state and CI status into the WI.
Why this step exists. Complete is blocked until CI passes and required reviews are approved. Pressing Check pull request status is the cheap way to refresh the WI's status badges; manually opening the provider UI works too but doesn't push the new state back into Swifter.
Verification.
- WI status panel shows
CI: green(or the provider's equivalent label). - Required reviewer count is met.
- No outstanding
Changes requestedreviews.
If a check fails: open the PR in the provider UI, look at the failed CI job's log, and return to the same development chat. Share the failure log. The agent iterates against the same branch — do not open a new session, and do not open a new chat.
Step 18 — Press Complete
Action. In the WI header, press Complete.
Why this step exists. Complete merges the PR into main, closes the session, and moves the WI to DONE. The parent feature's Children section updates automatically.
Verification.
- WI status is DONE.
- PR shows Merged in the provider UI.
- Session branch is merged (and, per project policy, deleted).
- Storybook on
mainbuilds; Preview onmainrenders/customers.
If a check fails: Complete is blocked when CI is not green or required reviews are missing — return to Step 17. If Origin shows ABANDONED but the development session shows DONE, that is the project baseline pattern — see Troubleshooting → Session-Naming Artefact.
Exit conditions
A clean exit looks like this:
- Work item status is DONE on the WI detail page.
- The parent feature's
Childrensection reflects the new status; if this was the last child, the feature itself may move to Done. - The project overview shows the WI in the shipped list with the PR link.
- The session is closed; the session branch is merged and (per project policy) deleted.
- Storybook on
mainbuilds; Preview onmainrenders the new screen.