Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
7a1ceb0
Add /ux-design workflow with research, prototyping, evaluation, and h…
adalton Aug 21, 2026
7cc98a6
Refine ux-design workflow: bare-skill deps, refine loop, provenance
adalton Aug 21, 2026
7889a17
ux-design: ingest upstream context and reality-check the handoff
adalton Aug 24, 2026
c5fb55c
Address CodeRabbit PR #108 feedback: quality, safety, and consistency…
adalton Aug 24, 2026
791e233
Remove product-specific coupling from ux-design controller
adalton Aug 24, 2026
3018a57
Address new CodeRabbit feedback: quality and portability improvements
adalton Aug 24, 2026
a5465cb
Fix CodeRabbit feedback and CI: consistency, portability, and versioning
adalton Aug 25, 2026
e678df2
ux-design: explicitly capture source-repository root before skill inv…
adalton Aug 25, 2026
d56d0a7
ux-design: use git rev-parse and relative path for --project
adalton Aug 25, 2026
372266e
ux-design: revalidate replacement config values before saving
adalton Aug 25, 2026
f520b9d
ux-design: validate repo root before cd and use bare skill name
adalton Aug 25, 2026
1f7d12f
ux-design: move example paths into fenced code block
adalton Aug 25, 2026
5b47504
Merge branch 'main' into andalton/ux-design-workflow
adalton Aug 26, 2026
fa9c0f5
Bump prd and design to 0.9.1 per shared-file version cascade
adalton Aug 26, 2026
eb1dba4
Merge remote-tracking branch 'origin/main' into andalton/ux-design-wo…
adalton Aug 26, 2026
e98115b
Bump triage to 0.4.1 per shared-file version cascade
adalton Aug 26, 2026
68b7a50
AGENTS.md: document ux-design as a provenance consumer
adalton Aug 26, 2026
19b5cd9
Merge remote-tracking branch 'origin/main' into andalton/ux-design-wo…
adalton Aug 27, 2026
8133aa7
Merge origin/main into andalton/ux-design-workflow
adalton Sep 2, 2026
89366a6
Merge remote-tracking branch 'origin/main' into andalton/ux-design-wo…
adalton Sep 10, 2026
80439cb
Address CodeRabbit review: correctness, safety, and consistency fixes
adalton Sep 10, 2026
bd7cea7
Merge origin/main into andalton/ux-design-workflow
adalton Sep 14, 2026
15a60fd
ux-design: move only selected handoff output
adalton Sep 14, 2026
7cf6053
Merge origin/main into andalton/ux-design-workflow
adalton Sep 22, 2026
a3d699f
Merge remote-tracking branch 'origin/main' into andalton/ux-design-wo…
adalton Sep 23, 2026
522389f
UXDOPS-2843: track ai-helpers main and refresh UXD integration
adalton Sep 25, 2026
354d704
Merge origin/main into andalton/ux-design-workflow
adalton Sep 25, 2026
4a2a619
fix: address UX design PR review feedback
adalton Sep 28, 2026
2a6830b
feat: support exploratory UX context enrichment
adalton Sep 28, 2026
cdbb58a
fix: address UX workflow review feedback
adalton Sep 28, 2026
bb28aaf
docs: clarify provenance CLI consumers
adalton Sep 28, 2026
b083f38
ux-design: support PRD-only ingest
adalton Sep 30, 2026
086eab9
ux-design: resolve docs repo path during publish
adalton Sep 30, 2026
eb512d2
ux-design: harden publish artifact and repo handling
adalton Sep 30, 2026
66c7738
ux-design: validate publish branch and destination
adalton Sep 30, 2026
b1a7d8a
ux-design: harden publish inputs and PR creation
adalton Sep 30, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ This repository contains reusable AI coding workflows and focused skills that ca
- **implement** — Story-to-code workflow (ingest, plan, revise, code, validate, publish, respond)
- **kcs** — KCS Solution article workflow (gather, draft, validate, handoff)
- **prd** — Requirements-to-PRD workflow (ingest, clarify, draft, revise, publish, respond)
- **ux-design** — UX design workflow (ingest, research, prototype, evaluate, handoff, revise, publish, respond)
- **rebase-stack** — Rebase a stacked-branch chain with conflict guidance, per-branch validation, and push (start, continue, validate, push)
- **sizing** — Pre-cycle Feature sizing with T-shirt sizes and team effort breakdowns (ingest, assess, apply)
- **skill-reviewer** — Meta-workflow that audits AI skill directories
Expand Down Expand Up @@ -83,7 +84,7 @@ _shared/
review-protocol.md # Shared code review criteria, finding format, severity definitions
sizing-rubric.md # Shared sizing definitions (T-shirt sizes, heuristics, team effort guidance)
scripts/
provenance.py # Capture/render CLI (used by prd and design provenance recipes)
provenance.py # Capture/render CLI (used by prd, design, and ux-design provenance recipes)
pr-comments.py # Deterministic PR comment operations (fetch, reply, log)
publish.py # Deterministic publish operations (push, PR/MR, metadata)
resolve-phase.py # Deterministic phase override resolution (file-existence check)
Expand All @@ -97,7 +98,7 @@ _shared/
validation-gate.md # Pre-commit build/test/lint discovery gate (used by bugfix)
```

Recipes are self-contained, parameterized procedures that packages reference via relative path (e.g., `../../_shared/recipes/self-review-gate.md` from a workflow phase). Workflows and simple skills may also reference shared files from guidelines, phases, references, templates, prompts, scripts, and other behavioral files — all such references count as consumers for the shared-file cascade (see Package Versioning). The **prd** and **design** workflows use the provenance recipes on `/draft`, `/revise`, `/respond` (capture) and `/publish` plus docs-sync paths (render). See `_shared/provenance-schema.md` for the published footer format.
Recipes are self-contained, parameterized procedures that packages reference via relative path (e.g., `../../_shared/recipes/self-review-gate.md` from a workflow phase). Workflows and simple skills may also reference shared files from guidelines, phases, references, templates, prompts, scripts, and other behavioral files — all such references count as consumers for the shared-file cascade (see Package Versioning). The **prd** and **design** workflows use the provenance recipes on `/draft`, `/revise`, `/respond` (capture) and `/publish` plus docs-sync paths (render). The **ux-design** workflow uses them on `/handoff`, `/revise`, `/respond` (capture) and `/publish` plus `/respond` (render). See `_shared/provenance-schema.md` for the published footer format.

### File Reference Conventions

Expand Down Expand Up @@ -236,7 +237,7 @@ ai-workflows/
│ ├── review-protocol.md # Shared code review criteria and finding format
│ ├── sizing-rubric.md # Shared sizing definitions and heuristics
│ ├── scripts/
│ │ ├── provenance.py # Capture/render CLI for prd/design provenance
│ │ ├── provenance.py # Capture/render CLI for prd/design/ux-design provenance
│ │ ├── pr-comments.py # Deterministic PR comment operations (fetch, reply, log)
│ │ ├── publish.py # Deterministic publish operations (push, PR/MR, metadata)
│ │ ├── resolve-phase.py # Deterministic phase override resolution
Expand Down Expand Up @@ -273,6 +274,7 @@ ai-workflows/
│ ├── references/
│ ├── scripts/
│ └── templates/
├── ux-design/
├── install.sh # Installer with auto-discovery
├── uninstall.sh # Removal script
├── AGENTS.md # AI assistant guidance (this file)
Expand Down
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,9 @@ Reusable AI coding workflows and focused skills a team member can install global
- **Skill Reviewer** -- Meta-workflow that audits AI skill directories against eight quality dimensions.
See [skill-reviewer/README.md](skill-reviewer/README.md).

- **UX Design** -- UX design workflow: ingest a feature request, conduct user research, generate prototypes, run heuristic evaluation, and produce a validated design handoff for the `ui-design` workflow.
See [ux-design/README.md](ux-design/README.md).

## How It Works

Each workflow is a top-level directory with a `SKILL.md`, while focused skills
Expand Down
6 changes: 3 additions & 3 deletions _shared/recipes/capture-provenance-event.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
name: capture-provenance-event
version: 0.1.1
version: 0.1.2
---
# Recipe: Capture Provenance Event

Expand All @@ -11,9 +11,9 @@ phase mutates the planning document. See `../provenance-schema.md`.

| Parameter | Required | Description |
|-----------|----------|-------------|
| WORKFLOW | Yes | `prd` or `design` |
| WORKFLOW | Yes | `prd`, `design`, or `ux-design` |
| ISSUE_KEY | Yes | Full Jira issue key including project prefix (e.g., `PROJ-1234`, not `1234`) |
| PHASE | Yes | `draft`, `revise`, or `respond` |
| PHASE | Yes | For `prd` and `design`: `draft`, `revise`, or `respond`. For `ux-design`: `handoff`, `revise`, or `respond` |
| AUTHORING_MODE | Yes | `skill` (default for phase skills) or `manual` |

## Procedure
Expand Down
4 changes: 2 additions & 2 deletions _shared/recipes/render-provenance-footer.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
name: render-provenance-footer
version: 0.2.0
version: 0.2.1
---
# Recipe: Render Provenance Footer

Expand All @@ -11,7 +11,7 @@ docs-repo copy before `git add`. See `../provenance-schema.md` for format.

| Parameter | Required | Description |
|-----------|----------|-------------|
| WORKFLOW | Yes | `prd` or `design` |
| WORKFLOW | Yes | `prd`, `design`, or `ux-design` |
| ISSUE_KEY | Yes | Full Jira issue key including project prefix (e.g., `PROJ-1234`, not `1234`) |
| TARGET_FILE | Yes | Absolute path to the local artifact or docs-repo file to render |
| ALLOW_MISSING | No | Set to `yes` only after the user explicitly declines provenance |
Expand Down
68 changes: 55 additions & 13 deletions _shared/scripts/provenance.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
"""Capture and render provenance for prd/design planning document workflows.
"""Capture and render provenance for prd/design/ux-design planning documents.

Exit codes:
0: Success (capture or render completed)
Expand All @@ -23,9 +23,29 @@
WORKFLOW_DOCS = {
"prd": "03-prd.md",
"design": "03-design.md",
"ux-design": "05-handoff.md",
}

AUTHORING_PHASES = frozenset({"draft", "revise", "respond", "manual-edit"})
# The phase that legitimately originates each workflow's document. prd/design
# originate from a template-checked /draft; ux-design assembles its handoff spec
# in /handoff (there is no template-from-origin step), so `handoff` is its
# origin. A first event other than this marks the phase history as untracked.
ORIGIN_PHASE = {
"prd": "draft",
"design": "draft",
"ux-design": "handoff",
}

AUTHORING_PHASES = frozenset(
{"draft", "handoff", "revise", "respond", "manual-edit"}
Comment thread
adalton marked this conversation as resolved.
)

# Per-workflow valid phases (for validation in capture_event)
WORKFLOW_PHASES = {
"prd": frozenset({"draft", "revise", "respond", "manual-edit", "commit"}),
"design": frozenset({"draft", "revise", "respond", "manual-edit", "commit"}),
"ux-design": frozenset({"handoff", "revise", "respond", "manual-edit", "commit"}),
}

DRIFT_FIELDS = (
"workflow_version",
Expand Down Expand Up @@ -56,10 +76,18 @@
COMMIT_ONLY_NOTE = (
"> Authoring phases not recorded this session (commit-time snapshot only)."
)
ORIGIN_UNTRACKED_NOTE = (
"> This document's phase history does not include an initial /draft — "
"structure was not verified against the template from origin."
)
def origin_untracked_note(workflow: str | None = None) -> str:
origin = ORIGIN_PHASE.get(workflow, "draft")
# ux-design has no template step; its /handoff assembles from scratch
if workflow == "ux-design":
return (
f"> This document's phase history does not include an initial /{origin} — "
"structure was not verified from origin."
)
return (
f"> This document's phase history does not include an initial /{origin} — "
"structure was not verified against the template from origin."
)


def repo_root(start: Path) -> Path | None:
Expand Down Expand Up @@ -260,12 +288,15 @@ def provenance_kind(events: list[dict[str, Any]]) -> str:
return "session"


def origin_untracked(events: list[dict[str, Any]]) -> bool:
def origin_untracked(
events: list[dict[str, Any]], workflow: str | None = None
) -> bool:
if not events:
return False
if provenance_kind(events) == "commit_only":
return False
return events[0].get("phase") != "draft"
origin = ORIGIN_PHASE.get(workflow, "draft")
return events[0].get("phase") != origin


def capture_event(
Expand All @@ -274,6 +305,14 @@ def capture_event(
phase: str,
authoring_mode: str,
) -> None:
# Validate phase is valid for this workflow
valid_phases = WORKFLOW_PHASES.get(workflow)
if valid_phases and phase not in valid_phases:
raise ValueError(
f"Phase '{phase}' is not valid for workflow '{workflow}'. "
f"Valid phases: {', '.join(sorted(valid_phases))}"
)

ai_root = ai_workflows_root()
ws_root = workspace_root()
path = provenance_path(workflow, issue)
Expand Down Expand Up @@ -352,6 +391,7 @@ def build_metrics_payload(data: dict[str, Any]) -> dict[str, Any]:
last = events[-1] if events else {}
drift = data.get("drift", {})
kind = provenance_kind(events)
workflow = data.get("workflow", "unknown")
return {
"schema_version": 1,
"provenance_kind": kind,
Expand All @@ -368,7 +408,7 @@ def build_metrics_payload(data: dict[str, Any]) -> dict[str, Any]:
{event.get("authoring_mode", "skill") for event in events}
),
"context_changed": drift.get("context_changed", False),
"origin_untracked": origin_untracked(events),
"origin_untracked": origin_untracked(events, workflow),
}


Expand Down Expand Up @@ -403,9 +443,9 @@ def build_footer(data: dict[str, Any]) -> str:
if len(phases) > 1:
lines.append(f"Phases: {', '.join(phases)}")

if origin_untracked(events):
if origin_untracked(events, workflow):
lines.append("")
lines.append(ORIGIN_UNTRACKED_NOTE)
lines.append(origin_untracked_note(workflow))

lines.append("")
lines.append(metrics_comment)
Expand Down Expand Up @@ -491,7 +531,9 @@ def render_footer(workflow: str, issue: str, target: Path, *, allow_missing: boo


def main() -> int:
parser = argparse.ArgumentParser(description="PRD/design provenance helper")
parser = argparse.ArgumentParser(
description="PRD/design/ux-design provenance helper"
)
sub = parser.add_subparsers(dest="command", required=True)

capture = sub.add_parser("capture", help="Append a provenance event")
Expand All @@ -500,7 +542,7 @@ def main() -> int:
capture.add_argument(
"--phase",
required=True,
choices=["draft", "revise", "respond", "manual-edit", "commit"],
choices=["draft", "handoff", "revise", "respond", "manual-edit", "commit"],
Comment thread
coderabbitai[bot] marked this conversation as resolved.
)
capture.add_argument(
"--authoring-mode",
Expand Down
40 changes: 40 additions & 0 deletions _shared/scripts/test_provenance.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,46 @@ def test_origin_untracked_false_when_all_events_are_commit(self) -> None:
self.assertEqual(provenance.provenance_kind(events), "commit_only")
self.assertFalse(provenance.origin_untracked(events))

def test_origin_untracked_false_for_ux_design_handoff_first(self) -> None:
# ux-design originates its document in /handoff (not /draft), so a
# handoff-first log is a tracked origin and must NOT be flagged.
events = [{"phase": "handoff"}, {"phase": "revise"}]
self.assertFalse(provenance.origin_untracked(events, "ux-design"))

def test_origin_untracked_true_for_ux_design_revise_first(self) -> None:
# ux-design entered at /revise with no prior /handoff is untracked.
events = [{"phase": "revise"}]
self.assertTrue(provenance.origin_untracked(events, "ux-design"))

def test_origin_untracked_true_for_prd_handoff_first(self) -> None:
# 'handoff' is not prd's origin phase, so a handoff-first prd log is
# still untracked -- the per-workflow origin must not leak across.
events = [{"phase": "handoff"}]
self.assertTrue(provenance.origin_untracked(events, "prd"))

def test_origin_untracked_note_names_workflow_origin_phase(self) -> None:
ux_note = provenance.origin_untracked_note("ux-design")
self.assertIn("/handoff", ux_note)
# ux-design has no template step, so note should not mention "template"
self.assertNotIn("template", ux_note)

prd_note = provenance.origin_untracked_note("prd")
self.assertIn("/draft", prd_note)
self.assertIn("template", prd_note) # prd/design DO have templates

self.assertIn("/draft", provenance.origin_untracked_note())

def test_workflow_phase_validation_rejects_invalid_combinations(self) -> None:
# prd/design don't have 'handoff' phase
with self.assertRaises(ValueError) as cm:
provenance.capture_event("prd", "TEST-123", "handoff", "skill")
self.assertIn("not valid for workflow 'prd'", str(cm.exception))

# ux-design doesn't have 'draft' phase
with self.assertRaises(ValueError) as cm:
provenance.capture_event("ux-design", "TEST-456", "draft", "skill")
self.assertIn("not valid for workflow 'ux-design'", str(cm.exception))

def test_build_metrics_payload_flags_origin_untracked(self) -> None:
data = {
"workflow": "prd",
Expand Down
2 changes: 1 addition & 1 deletion design/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
name: design
version: 0.11.3
version: 0.11.4
description: >-
Design-and-decompose workflow that takes a PRD, researches the problem space,
drafts a technical design document with a requirement-anchored testplan,
Expand Down
Loading
Loading