gaia-framework 1.66.0 → 1.87.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/commands/gaia-create-stakeholder.md +20 -0
- package/.claude/commands/gaia-test-gap-analysis.md +17 -0
- package/CLAUDE.md +87 -1
- package/README.md +2 -2
- package/_gaia/_config/global.yaml +5 -1
- package/_gaia/_config/lifecycle-sequence.yaml +20 -0
- package/_gaia/_config/skill-manifest.csv +2 -0
- package/_gaia/_config/workflow-manifest.csv +3 -1
- package/_gaia/core/engine/workflow.xml +5 -1
- package/_gaia/core/workflows/party-mode/steps/step-01-agent-loading.md +60 -9
- package/_gaia/creative/workflows/problem-solving/checklist.md +64 -14
- package/_gaia/creative/workflows/problem-solving/instructions.xml +367 -22
- package/_gaia/creative/workflows/problem-solving/workflow.yaml +31 -1
- package/_gaia/dev/agents/_base-dev.md +13 -2
- package/_gaia/dev/skills/_skill-index.yaml +15 -0
- package/_gaia/dev/skills/figma-integration.md +498 -0
- package/_gaia/lifecycle/templates/brownfield-scan-security-prompt.md +228 -0
- package/_gaia/lifecycle/templates/gap-entry-schema.md +39 -4
- package/_gaia/lifecycle/templates/story-template.md +29 -1
- package/_gaia/lifecycle/workflows/2-planning/create-ux-design/instructions.xml +96 -3
- package/_gaia/lifecycle/workflows/4-implementation/code-review/instructions.xml +10 -0
- package/_gaia/lifecycle/workflows/4-implementation/create-stakeholder/checklist.md +25 -0
- package/_gaia/lifecycle/workflows/4-implementation/create-stakeholder/instructions.xml +79 -0
- package/_gaia/lifecycle/workflows/4-implementation/create-stakeholder/workflow.yaml +22 -0
- package/_gaia/lifecycle/workflows/4-implementation/create-story/instructions.xml +10 -0
- package/_gaia/lifecycle/workflows/4-implementation/dev-story/instructions.xml +10 -0
- package/_gaia/lifecycle/workflows/4-implementation/retrospective/instructions.xml +3 -3
- package/_gaia/lifecycle/workflows/4-implementation/validate-story/instructions.xml +11 -0
- package/_gaia/lifecycle/workflows/anytime/brownfield-onboarding/instructions.xml +11 -7
- package/_gaia/testing/workflows/test-gap-analysis/checklist.md +8 -0
- package/_gaia/testing/workflows/test-gap-analysis/instructions.xml +53 -0
- package/_gaia/testing/workflows/test-gap-analysis/workflow.yaml +38 -0
- package/bin/gaia-framework.js +36 -2
- package/bin/helpers/derive-bump-label.js +41 -0
- package/bin/helpers/validate-bump-labels.js +38 -0
- package/gaia-install.sh +71 -4
- package/package.json +1 -1
- package/_gaia/_memory/tier2-results/.gitkeep +0 -0
- package/_gaia/_memory/tier2-results/checkpoint-resume-2026-03-24.yaml +0 -6
- package/_gaia/_memory/tier2-results/engine-scenarios-2026-03-22.yaml +0 -14
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
> Brownfield deep analysis scan subagent. Detects security gaps in API endpoints and infrastructure security configurations.
|
|
4
4
|
> Reference: Architecture ADR-021, Section 10.15.2, Section 10.15.5, ADR-022 §10.16.5
|
|
5
5
|
> Infra-awareness: E12-S6 — applies infra-specific patterns when project_type is infrastructure or platform.
|
|
6
|
+
> Non-REST protocols: E11-S17 — GraphQL and gRPC endpoint detection and security gap scanning.
|
|
6
7
|
|
|
7
8
|
## Objective
|
|
8
9
|
|
|
@@ -51,6 +52,89 @@ Apply framework-specific patterns based on {tech_stack}:
|
|
|
51
52
|
|
|
52
53
|
If no API endpoints are detected, output a summary note and zero gap entries for the application phase.
|
|
53
54
|
|
|
55
|
+
## Phase 1b: GraphQL Endpoint Discovery
|
|
56
|
+
|
|
57
|
+
Catalog all GraphQL endpoints. For each endpoint, record: operation type (query/mutation/subscription), resolver function, authentication directives, authorization checks.
|
|
58
|
+
|
|
59
|
+
### Schema-First Detection Patterns
|
|
60
|
+
|
|
61
|
+
- `.graphql` and `.gql` schema files
|
|
62
|
+
- `type Query { ... }` and `type Mutation { ... }` blocks in schema files
|
|
63
|
+
- `typeDefs` variable definitions in JS/TS files (template literals with SDL)
|
|
64
|
+
|
|
65
|
+
### Code-First Detection Patterns
|
|
66
|
+
|
|
67
|
+
- `@Resolver()` decorators (NestJS, TypeGraphQL)
|
|
68
|
+
- `@Query()` and `@Mutation()` decorators
|
|
69
|
+
- `resolvers` objects exported from modules
|
|
70
|
+
- Python class-based resolvers (Strawberry `@strawberry.type`, Ariadne `@query_type.field`)
|
|
71
|
+
- Go resolver structs (gqlgen `resolver.go` files)
|
|
72
|
+
|
|
73
|
+
### GraphQL Framework Variants
|
|
74
|
+
|
|
75
|
+
Apply framework-specific patterns based on detected GraphQL library:
|
|
76
|
+
|
|
77
|
+
| Framework | Language | Detection Pattern |
|
|
78
|
+
|---|---|---|
|
|
79
|
+
| Apollo Server | Node/TS | `ApolloServer`, `@apollo/server`, Apollo plugins |
|
|
80
|
+
| GraphQL Yoga | Node/TS | `createYoga`, `@graphql-yoga/node` |
|
|
81
|
+
| Mercurius | Node/TS (Fastify) | `mercurius`, `app.graphql` |
|
|
82
|
+
| Strawberry | Python | `strawberry.Schema`, `@strawberry.type` |
|
|
83
|
+
| gqlgen | Go | `gqlgen.yml`, `generated.go`, resolver structs |
|
|
84
|
+
| Ariadne | Python | `ariadne`, `make_executable_schema` |
|
|
85
|
+
| NestJS GraphQL | Node/TS | `@nestjs/graphql`, `@Resolver()`, `@Query()`, `@Mutation()` |
|
|
86
|
+
|
|
87
|
+
### GraphQL Middleware Chain Detection
|
|
88
|
+
|
|
89
|
+
- `graphql-shield` rule trees (`const permissions = shield({ ... })`)
|
|
90
|
+
- `@UseGuards(AuthGuard)` decorators (NestJS)
|
|
91
|
+
- Apollo Server plugins (`ApolloServerPlugin` implementing `requestDidStart`)
|
|
92
|
+
- Yoga plugins (`useAuth`, custom `envelop` plugins)
|
|
93
|
+
- Custom context resolvers setting `context.user` from auth headers
|
|
94
|
+
|
|
95
|
+
### Graceful Exit — No GraphQL Endpoints
|
|
96
|
+
|
|
97
|
+
If no GraphQL schema files, resolver definitions, or GraphQL framework imports are detected, skip Phase 1b and Phase 2b entirely. Output a summary note and zero gap entries for GraphQL.
|
|
98
|
+
|
|
99
|
+
## Phase 1c: gRPC Endpoint Discovery
|
|
100
|
+
|
|
101
|
+
Catalog all gRPC endpoints. For each endpoint, record: service name, RPC method name, request/response message types, streaming type (unary/server/client/bidirectional), interceptor chain.
|
|
102
|
+
|
|
103
|
+
### Proto Service Parsing
|
|
104
|
+
|
|
105
|
+
- `.proto` files with `service` blocks defining `rpc` methods
|
|
106
|
+
- `stream` annotations on request or response types (server streaming, client streaming, bidirectional streaming)
|
|
107
|
+
- `package` declarations for service namespace
|
|
108
|
+
|
|
109
|
+
### Server Interceptor Detection
|
|
110
|
+
|
|
111
|
+
| Language | Interceptor Pattern |
|
|
112
|
+
|---|---|
|
|
113
|
+
| Java | `ServerInterceptor` interface, `@GrpcService` (Spring gRPC), interceptor registry |
|
|
114
|
+
| Go | `grpc.UnaryInterceptor()`, `grpc.StreamInterceptor()`, `grpc.ChainUnaryInterceptor()` |
|
|
115
|
+
| Python | `grpc.server_interceptor`, `intercept_service()` |
|
|
116
|
+
| Node/TS | `addService()` calls, `@GrpcMethod` decorators (NestJS), `grpc-js` server options |
|
|
117
|
+
|
|
118
|
+
### gRPC Middleware Chain Detection
|
|
119
|
+
|
|
120
|
+
- Interceptor chains in server setup (ordered middleware)
|
|
121
|
+
- `@GrpcMethod` decorators with guard annotations (NestJS)
|
|
122
|
+
- Metadata extractors for authentication tokens
|
|
123
|
+
- Health check service registration (`grpc.health.v1`)
|
|
124
|
+
|
|
125
|
+
### Graceful Exit — No gRPC Endpoints
|
|
126
|
+
|
|
127
|
+
If no `.proto` files, gRPC server setup, or gRPC framework imports are detected, skip Phase 1c and Phase 2c entirely. Output a summary note and zero gap entries for gRPC.
|
|
128
|
+
|
|
129
|
+
## Phase 1d: Mixed-Protocol Detection
|
|
130
|
+
|
|
131
|
+
A single codebase may expose REST + GraphQL + gRPC endpoints simultaneously. When multiple protocols are detected:
|
|
132
|
+
|
|
133
|
+
1. Scan all three protocols independently
|
|
134
|
+
2. Identify shared authentication middleware (e.g., a JWT validator used by both Express routes and Apollo context)
|
|
135
|
+
3. Do not double-count shared middleware as separate gaps — if auth middleware covers both REST and GraphQL, count it once
|
|
136
|
+
4. Note in findings when multiple protocols share infrastructure
|
|
137
|
+
|
|
54
138
|
## Phase 2: Security Gap Detection — Application Rules
|
|
55
139
|
|
|
56
140
|
### 1. Missing Authentication Middleware (AC3a)
|
|
@@ -82,6 +166,99 @@ Sensitive data exposure is `high` severity.
|
|
|
82
166
|
|
|
83
167
|
Detect POST/PUT/PATCH/DELETE endpoints that accept a request body but have no input validation. Missing input validation is `high` severity.
|
|
84
168
|
|
|
169
|
+
## Phase 2b: GraphQL Security Gap Detection
|
|
170
|
+
|
|
171
|
+
### 1. Queries/Mutations Missing Auth Directives
|
|
172
|
+
|
|
173
|
+
Detect GraphQL operations missing authentication. Look for:
|
|
174
|
+
- Resolvers without `@auth`, `@authenticated`, `@HasPermission`, or `@UseGuards(AuthGuard)` directives
|
|
175
|
+
- Schema types without `@auth` directive when other types have it (inconsistent protection)
|
|
176
|
+
- Mutation resolvers with no authorization checks are `critical` severity
|
|
177
|
+
- Query resolvers returning non-public data without auth are `high` severity
|
|
178
|
+
|
|
179
|
+
### 2. Introspection Enabled in Production
|
|
180
|
+
|
|
181
|
+
Detect GraphQL introspection configuration that may leak schema in production:
|
|
182
|
+
- `introspection: true` in Apollo Server config without `NODE_ENV` conditional
|
|
183
|
+
- Missing introspection disable in production configuration
|
|
184
|
+
- Yoga/Mercurius default introspection without explicit disable
|
|
185
|
+
|
|
186
|
+
Introspection in production is `medium` severity.
|
|
187
|
+
|
|
188
|
+
### 3. Mutations Without Authorization Checks
|
|
189
|
+
|
|
190
|
+
Detect mutation resolvers that lack authorization logic:
|
|
191
|
+
- Mutation handlers with no permission checks, guard decorators, or authorization middleware
|
|
192
|
+
- `graphql-shield` rules that allow mutations without role checks
|
|
193
|
+
- NestJS mutations without `@UseGuards()` when other mutations have guards
|
|
194
|
+
|
|
195
|
+
Missing mutation authorization is `critical` severity.
|
|
196
|
+
|
|
197
|
+
### 4. Field-Level Authorization Gaps
|
|
198
|
+
|
|
199
|
+
Detect sensitive fields exposed without field-level auth controls:
|
|
200
|
+
- Fields named `email`, `password`, `ssn`, `token`, `secret`, `creditCard` without `@Authorized` or field-level resolvers
|
|
201
|
+
- Resolver types exposing sensitive nested objects without per-field permission checks
|
|
202
|
+
- User types exposing admin-only fields to all authenticated users
|
|
203
|
+
|
|
204
|
+
Field-level authorization gaps are `high` severity.
|
|
205
|
+
|
|
206
|
+
### 5. GraphQL Federation and Schema Stitching
|
|
207
|
+
|
|
208
|
+
When Apollo Federation or schema stitching is detected:
|
|
209
|
+
- Note gateway-level auth that may mask per-service gaps
|
|
210
|
+
- Flag subgraph services that rely solely on gateway auth without their own validation
|
|
211
|
+
- Detect `@external` fields without authorization in the owning subgraph
|
|
212
|
+
|
|
213
|
+
Federation auth gaps are `medium` severity with a note about gateway-level coverage.
|
|
214
|
+
|
|
215
|
+
## Phase 2c: gRPC Security Gap Detection
|
|
216
|
+
|
|
217
|
+
### 1. Services Missing Auth Interceptors
|
|
218
|
+
|
|
219
|
+
Detect gRPC server setup without authentication interceptors:
|
|
220
|
+
- Server initialization without `AuthInterceptor` or equivalent in the interceptor chain
|
|
221
|
+
- Services registered via `addService` with no auth middleware applied
|
|
222
|
+
- Spring gRPC services without `@GrpcService` security configuration
|
|
223
|
+
|
|
224
|
+
Missing auth interceptor is `critical` severity.
|
|
225
|
+
|
|
226
|
+
### 2. Unary RPCs Without Authorization Metadata
|
|
227
|
+
|
|
228
|
+
Detect unary RPC methods that do not validate authorization metadata:
|
|
229
|
+
- `rpc` method handlers that do not extract or validate `metadata` authorization headers
|
|
230
|
+
- Handler functions that skip token/credential validation from gRPC metadata
|
|
231
|
+
- Methods that do not check caller identity or roles from request context
|
|
232
|
+
|
|
233
|
+
Missing unary authorization is `high` severity.
|
|
234
|
+
|
|
235
|
+
### 3. Streaming RPCs Without Per-Message Auth
|
|
236
|
+
|
|
237
|
+
Detect bidirectional and server streaming RPCs without per-message authentication:
|
|
238
|
+
- Stream handlers that authenticate only at connection start but not per-message
|
|
239
|
+
- Bidirectional streams without per-message auth validation
|
|
240
|
+
- Server streaming RPCs that do not re-validate authorization on long-lived connections
|
|
241
|
+
|
|
242
|
+
Missing stream auth is `high` severity.
|
|
243
|
+
|
|
244
|
+
### 4. TLS Configuration Gaps
|
|
245
|
+
|
|
246
|
+
Detect insecure gRPC transport configuration:
|
|
247
|
+
- `grpc.insecure_port` usage in non-development configuration
|
|
248
|
+
- `ServerCredentials.createInsecure()` in production server setup
|
|
249
|
+
- Missing TLS certificate configuration in production gRPC servers
|
|
250
|
+
- Plaintext gRPC channels in production client configuration
|
|
251
|
+
|
|
252
|
+
Insecure TLS is `critical` severity.
|
|
253
|
+
|
|
254
|
+
### 5. gRPC Reflection Enabled in Production
|
|
255
|
+
|
|
256
|
+
Detect gRPC reflection service that may expose service definitions:
|
|
257
|
+
- `grpc.reflection.v1alpha` or `grpc.reflection.v1` service registered without environment guard
|
|
258
|
+
- Reflection service enabled unconditionally (similar risk to GraphQL introspection)
|
|
259
|
+
|
|
260
|
+
Reflection in production is `medium` severity.
|
|
261
|
+
|
|
85
262
|
## Phase 3: False-Positive Mitigation — Inherited Auth
|
|
86
263
|
|
|
87
264
|
Before flagging an endpoint as "missing authentication middleware," trace the middleware chain upward:
|
|
@@ -106,6 +283,18 @@ Before flagging an endpoint as "missing authentication middleware," trace the mi
|
|
|
106
283
|
- `r.Use(JWTAuth())` — app-level
|
|
107
284
|
- `group := r.Group("/api"); group.Use(AuthMiddleware())` — group-level
|
|
108
285
|
|
|
286
|
+
#### GraphQL Inherited Auth
|
|
287
|
+
- Apollo Server `context` function that validates JWT and sets `context.user` — app-level
|
|
288
|
+
- `graphql-shield` rule tree applied via `applyMiddleware` — schema-level
|
|
289
|
+
- NestJS `@UseGuards(AuthGuard)` on resolver class — class-level
|
|
290
|
+
- Apollo Federation gateway-level auth that validates before routing to subgraphs — gateway-level
|
|
291
|
+
|
|
292
|
+
#### gRPC Inherited Auth
|
|
293
|
+
- Global auth interceptor registered via `grpc.UnaryInterceptor(authInterceptor)` — server-level
|
|
294
|
+
- `ServerInterceptor` added to server builder interceptor chain — server-level
|
|
295
|
+
- Per-service interceptor applied at `addService` — service-level
|
|
296
|
+
- TLS mutual authentication (mTLS) at transport level — transport-level
|
|
297
|
+
|
|
109
298
|
## Phase 4: Infrastructure Security Patterns (E12-S6)
|
|
110
299
|
|
|
111
300
|
**Apply ONLY when {project_type} is `infrastructure` or `platform`.**
|
|
@@ -180,11 +369,50 @@ gap:
|
|
|
180
369
|
evidence:
|
|
181
370
|
file: "relative/path/to/file"
|
|
182
371
|
line: 42
|
|
372
|
+
protocol: "rest"
|
|
183
373
|
recommendation: "Actionable fix — add middleware, validate input, filter response"
|
|
184
374
|
verified_by: "machine-detected"
|
|
185
375
|
confidence: "{high|medium|low}"
|
|
186
376
|
```
|
|
187
377
|
|
|
378
|
+
**Protocol field:** Every gap entry MUST include a `protocol` field in the evidence section indicating which API protocol the finding applies to: `rest`, `graphql`, or `grpc`. This enables downstream consumers to filter and route findings by protocol.
|
|
379
|
+
|
|
380
|
+
#### GraphQL Gap Example
|
|
381
|
+
|
|
382
|
+
```yaml
|
|
383
|
+
gap:
|
|
384
|
+
id: "GAP-SECURITY-015"
|
|
385
|
+
category: "security-endpoint"
|
|
386
|
+
severity: "critical"
|
|
387
|
+
title: "Mutation resolver missing authorization checks"
|
|
388
|
+
description: "createUser mutation has no @auth directive or guard. Any authenticated user can create accounts."
|
|
389
|
+
evidence:
|
|
390
|
+
file: "src/graphql/resolvers/user.resolver.ts"
|
|
391
|
+
line: 42
|
|
392
|
+
protocol: "graphql"
|
|
393
|
+
recommendation: "Add @UseGuards(AuthGuard, RolesGuard) or @auth directive to the createUser mutation."
|
|
394
|
+
verified_by: "machine-detected"
|
|
395
|
+
confidence: "high"
|
|
396
|
+
```
|
|
397
|
+
|
|
398
|
+
#### gRPC Gap Example
|
|
399
|
+
|
|
400
|
+
```yaml
|
|
401
|
+
gap:
|
|
402
|
+
id: "GAP-SECURITY-022"
|
|
403
|
+
category: "security-endpoint"
|
|
404
|
+
severity: "critical"
|
|
405
|
+
title: "gRPC server missing auth interceptor in production config"
|
|
406
|
+
description: "Server setup uses grpc.insecure_port without TLS. No auth interceptor in interceptor chain."
|
|
407
|
+
evidence:
|
|
408
|
+
file: "cmd/server/main.go"
|
|
409
|
+
line: 58
|
|
410
|
+
protocol: "grpc"
|
|
411
|
+
recommendation: "Add TLS credentials and an auth interceptor to the gRPC server configuration."
|
|
412
|
+
verified_by: "machine-detected"
|
|
413
|
+
confidence: "high"
|
|
414
|
+
```
|
|
415
|
+
|
|
188
416
|
### Confidence Classification
|
|
189
417
|
|
|
190
418
|
- **high** — exact pattern match (e.g., no auth decorator/annotation on a `@PostMapping` handler)
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# Gap Entry Schema
|
|
2
2
|
|
|
3
|
-
> **Version:** 1.
|
|
4
|
-
> **Story:** E11-S1, E12-S5
|
|
3
|
+
> **Version:** 1.2.0
|
|
4
|
+
> **Story:** E11-S1, E12-S5, E11-S18
|
|
5
5
|
> **Traces to:** FR-111, FR-123, US-38, ADR-021, ADR-022
|
|
6
6
|
>
|
|
7
7
|
> Standardized output schema for brownfield scan subagents (E11).
|
|
@@ -22,6 +22,7 @@ description: "<string>"
|
|
|
22
22
|
evidence:
|
|
23
23
|
file: "<relative-path>"
|
|
24
24
|
line: <number-or-range>
|
|
25
|
+
protocol: "<string>" # Optional
|
|
25
26
|
recommendation: "<string>"
|
|
26
27
|
verified_by: "<agent-id>"
|
|
27
28
|
confidence: "<enum>"
|
|
@@ -36,7 +37,7 @@ confidence: "<enum>"
|
|
|
36
37
|
| `severity` | enum | yes | Impact level — must be one of the 5 allowed values (see Severity Enum) |
|
|
37
38
|
| `title` | string | yes | Short summary of the gap (max 80 characters) |
|
|
38
39
|
| `description` | string | yes | Detailed explanation of the gap, what it means, and why it matters |
|
|
39
|
-
| `evidence` | object | yes | Source code evidence (see Evidence Object) |
|
|
40
|
+
| `evidence` | object | yes | Source code evidence with required `file` and `line` sub-fields, plus optional `protocol` sub-field (see Evidence Object) |
|
|
40
41
|
| `recommendation` | string | yes | Actionable fix or remediation guidance |
|
|
41
42
|
| `verified_by` | string | yes | ID of the scan agent that produced this finding (e.g., `dead-code-analyzer`, `config-scanner`) |
|
|
42
43
|
| `confidence` | enum | yes | Agent's confidence in the finding accuracy (see Confidence Enum) |
|
|
@@ -95,6 +96,7 @@ The `evidence` field is a composite object grouping source location data:
|
|
|
95
96
|
evidence:
|
|
96
97
|
file: "src/services/auth.ts" # Relative path from project root (non-empty string)
|
|
97
98
|
line: 42 # Single line number
|
|
99
|
+
protocol: "rest" # Optional. Protocol type
|
|
98
100
|
```
|
|
99
101
|
|
|
100
102
|
Or with a line range:
|
|
@@ -105,10 +107,19 @@ evidence:
|
|
|
105
107
|
line: "15-28" # Line range (start-end)
|
|
106
108
|
```
|
|
107
109
|
|
|
110
|
+
Or without the optional protocol field (backward compatible):
|
|
111
|
+
|
|
112
|
+
```yaml
|
|
113
|
+
evidence:
|
|
114
|
+
file: "src/utils/helper.ts"
|
|
115
|
+
line: 10
|
|
116
|
+
```
|
|
117
|
+
|
|
108
118
|
| Sub-field | Type | Required | Constraints |
|
|
109
119
|
|-----------|------|----------|-------------|
|
|
110
120
|
| `file` | string | yes | Relative path from project root. Must be non-empty. |
|
|
111
121
|
| `line` | number or string | yes | Single line number (integer) or range as `"start-end"` string |
|
|
122
|
+
| `protocol` | string | no | Optional. One of `rest`, `graphql`, `grpc`, `websocket`, or any custom string. Omit if not applicable. When present, must be a non-empty string. |
|
|
112
123
|
|
|
113
124
|
## ID Format
|
|
114
125
|
|
|
@@ -138,10 +149,17 @@ All fields listed in the Field Reference are **required** — a gap entry with a
|
|
|
138
149
|
- `evidence.line` must be a positive integer or a range string matching `^\d+-\d+$`
|
|
139
150
|
- `title` should not exceed 80 characters
|
|
140
151
|
- `verified_by` must be a non-empty string identifying the scan agent
|
|
152
|
+
- `evidence.protocol` when present, must be a non-empty string
|
|
141
153
|
|
|
142
154
|
### Required vs Optional
|
|
143
155
|
|
|
144
|
-
All 9 fields (`id`, `category`, `severity`, `title`, `description`, `evidence`, `recommendation`, `verified_by`, `confidence`) are **required**. There are no optional fields in the base schema.
|
|
156
|
+
All 9 top-level fields (`id`, `category`, `severity`, `title`, `description`, `evidence`, `recommendation`, `verified_by`, `confidence`) are **required**. There are no optional top-level fields in the base schema.
|
|
157
|
+
|
|
158
|
+
The `evidence` object contains one optional sub-field: `protocol`. This is the first optional sub-field in the schema. Existing gap entries that omit `protocol` remain fully valid.
|
|
159
|
+
|
|
160
|
+
### Optional Field Validation
|
|
161
|
+
|
|
162
|
+
The `protocol` sub-field of the `evidence` object is not enum-validated. It accepts any non-empty string when present. Recommended canonical values are `rest`, `graphql`, `grpc`, and `websocket`, but custom strings (e.g., `mqtt`, `soap`, `amqp`) are also accepted without schema changes. When `protocol` is omitted entirely, the gap entry remains valid (backward compatible). When present, an empty string is invalid.
|
|
145
163
|
|
|
146
164
|
## Budget Control
|
|
147
165
|
|
|
@@ -174,6 +192,23 @@ verified_by: "config-scanner"
|
|
|
174
192
|
confidence: "high"
|
|
175
193
|
```
|
|
176
194
|
|
|
195
|
+
### Application Category Example with Protocol
|
|
196
|
+
|
|
197
|
+
```yaml
|
|
198
|
+
id: "GAP-security-endpoint-001"
|
|
199
|
+
category: "security-endpoint"
|
|
200
|
+
severity: "high"
|
|
201
|
+
title: "Unprotected admin route exposes user management API"
|
|
202
|
+
description: "The /api/admin/users endpoint has no authentication middleware applied."
|
|
203
|
+
evidence:
|
|
204
|
+
file: "src/routes/admin.ts"
|
|
205
|
+
line: 15
|
|
206
|
+
protocol: "rest"
|
|
207
|
+
recommendation: "Add authentication middleware to all /api/admin/* routes."
|
|
208
|
+
verified_by: "security-scanner"
|
|
209
|
+
confidence: "high"
|
|
210
|
+
```
|
|
211
|
+
|
|
177
212
|
### Infrastructure Category Examples
|
|
178
213
|
|
|
179
214
|
```yaml
|
|
@@ -12,11 +12,20 @@ points: "{story_points}"
|
|
|
12
12
|
risk: "{high/medium/low}"
|
|
13
13
|
sprint_id: null
|
|
14
14
|
priority_flag: null
|
|
15
|
+
origin: null
|
|
16
|
+
origin_ref: null
|
|
15
17
|
depends_on: []
|
|
16
18
|
blocks: []
|
|
17
19
|
traces_to: []
|
|
18
20
|
date: "{creation_date}"
|
|
19
21
|
author: "{agent_name}"
|
|
22
|
+
# Optional: Figma design metadata — enables dev agents to extract design tokens and component specs via MCP.
|
|
23
|
+
# Omit this block entirely if the story does not reference Figma designs.
|
|
24
|
+
# figma:
|
|
25
|
+
# file_key: "{figma_file_key}" # Figma file identifier (from URL)
|
|
26
|
+
# pages: ["{page_name}"] # List of page names to extract from
|
|
27
|
+
# node_ids: ["{node_id}"] # List of specific Figma node IDs
|
|
28
|
+
# design_version: null # Populated by dev agent after first consumption (lastModified hash)
|
|
20
29
|
---
|
|
21
30
|
|
|
22
31
|
# Story: {story_title}
|
|
@@ -116,4 +125,23 @@ As a {role}, I want to {action}, so that {benefit}.
|
|
|
116
125
|
|
|
117
126
|
## Definition of Done
|
|
118
127
|
|
|
119
|
-
|
|
128
|
+
### Acceptance
|
|
129
|
+
|
|
130
|
+
- [ ] All acceptance criteria verified and checked off
|
|
131
|
+
- [ ] All subtasks marked complete
|
|
132
|
+
|
|
133
|
+
### Testing
|
|
134
|
+
|
|
135
|
+
- [ ] All tests pass (unit, integration, e2e as applicable)
|
|
136
|
+
- [ ] No linting or formatting errors
|
|
137
|
+
|
|
138
|
+
### Code Quality & CI
|
|
139
|
+
|
|
140
|
+
- [ ] Code compiles / builds without errors
|
|
141
|
+
- [ ] Code follows project conventions
|
|
142
|
+
- [ ] No hardcoded secrets or credentials
|
|
143
|
+
- [ ] PR merged to staging with all CI checks passing
|
|
144
|
+
|
|
145
|
+
### Documentation
|
|
146
|
+
|
|
147
|
+
- [ ] Documentation updated (if applicable)
|
|
@@ -32,12 +32,105 @@
|
|
|
32
32
|
<action>Plan keyboard navigation, screen reader support</action>
|
|
33
33
|
<action>Define color contrast and text sizing standards</action>
|
|
34
34
|
</step>
|
|
35
|
-
<step n="7" title="
|
|
35
|
+
<step n="7" title="Figma MCP Detection and Mode Selection">
|
|
36
|
+
<action>Probe for available Figma MCP server. Load figma-integration.md detection section JIT to determine if a design tool adapter is available.</action>
|
|
37
|
+
<action if="figma_mcp_available">Present mode selection to user: [Generate] Create Figma frames alongside ux-design.md | [Import] Import existing Figma designs (read-only) | [Skip] Text-only UX spec, no Figma integration</action>
|
|
38
|
+
<action if="not figma_mcp_available">Skip Figma integration — proceed with text-only UX design output. Log: "No Figma MCP server detected. Generating markdown-only ux-design.md."</action>
|
|
39
|
+
</step>
|
|
40
|
+
<step n="8" title="Generate Mode — UI Kit Page Creation" if="figma_mcp_available AND user_selected_generate">
|
|
41
|
+
<critical>
|
|
42
|
+
<mandate>Generate mode is the ONLY mode that performs write operations to Figma (FR-140). All other modes are read-only. Write operations: create pages, create frames, create component instances. Minimum required Figma API scopes: files:read + file_content:read + files:write.</mandate>
|
|
43
|
+
</critical>
|
|
44
|
+
<action>Load figma-integration.md frames section JIT from _gaia/dev/skills/figma-integration.md</action>
|
|
45
|
+
<action>Create a UI Kit page named "UI Kit — Generated" in the Figma design file via MCP</action>
|
|
46
|
+
<action>Extract design tokens from {planning_artifacts}/design-system/design-tokens.json (W3C DTCG format)</action>
|
|
47
|
+
<action>Create color styles with semantic aliases from token definitions (e.g., color.surface.primary, color.text.primary)</action>
|
|
48
|
+
<action>Create typography styles from composite token specs (heading-1, heading-2, body, caption)</action>
|
|
49
|
+
<action>Create spacing grid tokens and base components with state variants (default, hover, active, disabled, focus)</action>
|
|
50
|
+
<action>Error handling: on HTTP 429 rate limit, perform a single retry after backoff. If 429 persists, graceful fallback to markdown-only flow — log warning and skip remaining Figma operations.</action>
|
|
51
|
+
</step>
|
|
52
|
+
<step n="9" title="Generate Mode — Per-Screen Frame Generation" if="figma_mcp_available AND user_selected_generate">
|
|
53
|
+
<action>Parse PRD user journeys to determine screens needing frames</action>
|
|
54
|
+
<action>For each screen, generate frames at 6 viewports: 280px (foldable inner, FR-174), 375px (mobile), 600px (foldable outer, FR-174), 768px (tablet portrait), 1024px (tablet landscape, FR-174), 1280px (desktop)</action>
|
|
55
|
+
<action>Compose frames using UI Kit components from the previous step — apply auto-layout with responsive constraints from component specs</action>
|
|
56
|
+
<action>Label frames using naming convention: {ScreenName}/{Viewport} (e.g., Dashboard/Desktop, Login/Mobile)</action>
|
|
57
|
+
<action>Collect all generated Figma node IDs for downstream recording in ux-design.md</action>
|
|
58
|
+
</step>
|
|
59
|
+
<step n="10" title="Generate Mode — Prototype Flow Setup" if="figma_mcp_available AND user_selected_generate">
|
|
60
|
+
<action>Map PRD user journey steps to the generated screen frames</action>
|
|
61
|
+
<action>Create prototype flow connections between frames via Figma MCP, linking screens in the order defined by each user journey</action>
|
|
62
|
+
<action>Validate flow completeness: every user journey step must map to a generated frame. Flag any unmapped journey steps as warnings.</action>
|
|
63
|
+
</step>
|
|
64
|
+
<step n="11" title="Generate Mode — Asset Export Configuration" if="figma_mcp_available AND user_selected_generate">
|
|
65
|
+
<action>Configure PNG export at 1x, 2x, 3x densities for raster assets (images, illustrations)</action>
|
|
66
|
+
<action>Configure SVG export for icon components</action>
|
|
67
|
+
<action>Generate platform-specific asset catalogs per FR-175: iOS .xcassets catalog structure with Contents.json manifests, Android drawable-mdpi/drawable-hdpi/drawable-xhdpi/drawable-xxhdpi/drawable-xxxhdpi directories</action>
|
|
68
|
+
<action>Write export configuration and asset manifest to {planning_artifacts}/design-system/assets/ directory</action>
|
|
69
|
+
<action>Check {project-path}/.figma-cache/ for cached responses (1h TTL) before making MCP read calls — use cached data if fresh, fetch and cache if stale or missing</action>
|
|
70
|
+
</step>
|
|
71
|
+
<step n="12" title="Generate Mode — Record Figma Node IDs and Enhance ux-design.md" if="figma_mcp_available AND user_selected_generate">
|
|
72
|
+
<action>Build Screen-to-Frame mapping table from all generated Figma node IDs: columns Screen Name | Viewport | Figma Node ID | Page</action>
|
|
73
|
+
<action>Add figma: YAML frontmatter block to ux-design.md containing: file_key, pages array with node IDs for each generated page, and last_synced ISO 8601 timestamp</action>
|
|
74
|
+
<action>Add Design Tokens reference section linking to {planning_artifacts}/design-system/design-tokens.json with token category summary</action>
|
|
75
|
+
<action>Add Component Inventory section listing all generated UI Kit components with their Figma node IDs, variant counts, and state definitions</action>
|
|
76
|
+
<action>Add Screen-to-Frame mapping table with all generated frames across all viewports</action>
|
|
77
|
+
<action>Ensure backward compatibility: existing text-only ux-design.md content is preserved. Figma sections are additive — they appear after the standard UX design sections.</action>
|
|
78
|
+
</step>
|
|
79
|
+
<step n="13" title="Import Mode — File Key Entry and Validation" if="figma_mcp_available AND user_selected_import">
|
|
80
|
+
<critical>
|
|
81
|
+
<mandate>Import mode is strictly READ-ONLY. Only get_file, get_file_nodes, and get_image MCP calls are permitted. Zero write operations to Figma. Minimum required Figma API scopes: files:read + file_content:read.</mandate>
|
|
82
|
+
</critical>
|
|
83
|
+
<action>JIT-load figma-integration:import-detection section from _gaia/dev/skills/figma-integration.md</action>
|
|
84
|
+
<ask>Enter the Figma file URL (e.g., https://www.figma.com/file/abc123/Design-Name) or raw file key:</ask>
|
|
85
|
+
<action>Parse input: extract file key from URL format, or accept raw key directly</action>
|
|
86
|
+
<action>Validate key via lightweight figma/get_file MCP call with depth=1 (metadata only)</action>
|
|
87
|
+
<action>Handle errors: invalid key format (client-side rejection), 404 not found, 403 permission denied, 429 rate limited (single retry after 1s delay), 5-second timeout (abort gracefully per E13-S1)</action>
|
|
88
|
+
</step>
|
|
89
|
+
<step n="14" title="Import Mode — Page and Frame Discovery" if="figma_mcp_available AND user_selected_import">
|
|
90
|
+
<action>JIT-load figma-integration:import-discovery section</action>
|
|
91
|
+
<action>Call figma/get_file with full depth to retrieve the complete document tree</action>
|
|
92
|
+
<action>Parse response: extract pages (top-level CANVAS nodes) and frames (FRAME nodes within each page)</action>
|
|
93
|
+
<action>Build Page → Frames hierarchy with metadata (name, nodeId, absoluteBoundingBox dimensions)</action>
|
|
94
|
+
<action>Classify frames by viewport width: mobile (≤480px), tablet (481–1024px), desktop (>1024px)</action>
|
|
95
|
+
<action>Cache response in {project-path}/.figma-cache/ with 1-hour TTL per ADR-024</action>
|
|
96
|
+
<action>Handle partial access: if some pages/frames are inaccessible, continue with warnings and proceed with accessible content</action>
|
|
97
|
+
</step>
|
|
98
|
+
<step n="15" title="Import Mode — Design Token Extraction" if="figma_mcp_available AND user_selected_import">
|
|
99
|
+
<action>JIT-load figma-integration:import-tokens section</action>
|
|
100
|
+
<action>Extract color styles from file's styles and document nodes, resolving fill/stroke references to RGBA values</action>
|
|
101
|
+
<action>Extract typography styles: font family, size, weight, line height, letter spacing</action>
|
|
102
|
+
<action>Extract effect styles: drop-shadow and inner-shadow parameters</action>
|
|
103
|
+
<action>Extract spacing values from auto-layout frames: itemSpacing, paddingLeft/Right/Top/Bottom</action>
|
|
104
|
+
<action>Map all extracted tokens to W3C DTCG format with semantic alias support (e.g., Primary/500 → color.primary.500)</action>
|
|
105
|
+
<action>Write design-tokens.json to {planning_artifacts}/design-system/ with schema_version field</action>
|
|
106
|
+
</step>
|
|
107
|
+
<step n="16" title="Import Mode — Screen Inventory" if="figma_mcp_available AND user_selected_import">
|
|
108
|
+
<action>JIT-load figma-integration:import-screens section</action>
|
|
109
|
+
<action>Group frames by page from the discovered hierarchy</action>
|
|
110
|
+
<action>Build per-frame metadata: name, nodeId, width, height, viewport classification</action>
|
|
111
|
+
<action>Extract component instances used in each frame — map to component-specs.yaml format (name, props, layout type)</action>
|
|
112
|
+
<action>Generate structured screen-to-frame mapping with tracked nodeIds for downstream dev agent consumption (E13-S5)</action>
|
|
113
|
+
<action>Write component-specs.yaml to {planning_artifacts}/design-system/</action>
|
|
114
|
+
</step>
|
|
115
|
+
<step n="17" title="Import Mode — Generate ux-design.md Content" if="figma_mcp_available AND user_selected_import">
|
|
116
|
+
<action>JIT-load figma-integration:import-generate section</action>
|
|
117
|
+
<action>Prepare figma: YAML frontmatter block containing: file_key, pages array, node_ids array, imported_at ISO 8601 timestamp, import_mode: true</action>
|
|
118
|
+
<action>Prepare Design Tokens section with token path references (e.g., {color.primary}, {spacing.4})</action>
|
|
119
|
+
<action>Prepare Component Inventory section listing all components discovered from frame extraction with props and variants</action>
|
|
120
|
+
<action>Prepare Screen Descriptions section with per-screen: frame name, node ID, viewport classification, component list, layout description</action>
|
|
121
|
+
<action>Verify read-only guarantee: audit all MCP calls made during steps 13-17 — confirm only get_file, get_file_nodes, and get_image were used. Zero write operations. Abort and report if any write operation is detected.</action>
|
|
122
|
+
</step>
|
|
123
|
+
<step n="18" title="Generate Output">
|
|
36
124
|
<template-output file="{planning_artifacts}/ux-design.md">
|
|
37
|
-
Generate UX design document with: personas, information architecture, wireframe descriptions, interaction patterns, component specifications, accessibility plan,
|
|
125
|
+
Generate UX design document with: personas, information architecture, wireframe descriptions, interaction patterns, component specifications, accessibility plan, FR-to-Screen Mapping table (FR ID | Screen/Page | Wireframe Section). If Generate mode was active: include figma: frontmatter block, Design Tokens section, Component Inventory with Figma node IDs, and Screen-to-Frame mapping table. If Import mode was active: include figma: frontmatter block (file_key, pages, node_ids, imported_at, import_mode: true), Design Tokens section with token references, Component Inventory, and Screen Descriptions.
|
|
38
126
|
</template-output>
|
|
39
127
|
</step>
|
|
40
|
-
<step n="
|
|
128
|
+
<step n="19" title="FR-140 Compliance Check" if="figma_mcp_available AND user_selected_generate">
|
|
129
|
+
<action>Audit all MCP calls executed during Generate mode: classify each as READ (get_file, get_styles, get_components, get_images, get_frames) or WRITE (create_frame, create_component_instance, create_page)</action>
|
|
130
|
+
<action>Verify FR-140 constraint: write operations only occurred during Generate mode steps (8–12). Import mode and Skip mode must have zero write calls.</action>
|
|
131
|
+
<action>Document minimum required Figma API scopes: files:read + file_content:read (default for all modes), files:write (Generate mode only)</action>
|
|
132
|
+
</step>
|
|
133
|
+
<step n="20" title="Optional: Accessibility Review">
|
|
41
134
|
<ask>Would you like to review the UX design for WCAG 2.1 accessibility compliance? This spawns a subagent in a separate context. Recommended for user-facing applications. (yes / skip)</ask>
|
|
42
135
|
<action>If yes: spawn a subagent using the Agent tool: "Load {project-root}/_gaia/core/tasks/review-accessibility.xml. Read its entire contents. Target: {planning_artifacts}/ux-design.md. Follow the flow steps EXACTLY. Generate accessibility findings report."</action>
|
|
43
136
|
<action>If skip: accessibility review can be run anytime later with /gaia-review-a11y</action>
|
|
@@ -25,6 +25,16 @@
|
|
|
25
25
|
</action>
|
|
26
26
|
<action>Include an "Architecture Conformance" section in findings with PASS/FAIL per check</action>
|
|
27
27
|
</step>
|
|
28
|
+
<step n="3c" title="Design Fidelity Check">
|
|
29
|
+
<action>Read story file YAML frontmatter — check if a `figma:` block exists</action>
|
|
30
|
+
<action if="story_has_figma_block">Load the `figma-integration:fidelity` section JIT from `_gaia/dev/skills/figma-integration.md`</action>
|
|
31
|
+
<action if="story_has_figma_block">Run the fidelity comparison: extract token references from changed code files, compare against `{planning_artifacts}/design-system/design-tokens.json`, classify as matched/drifted/missing</action>
|
|
32
|
+
<action if="story_has_figma_block">Calculate per-category drift percentages (color, typography, spacing, borders)</action>
|
|
33
|
+
<action if="story_has_figma_block">Save fidelity report to `{implementation_artifacts}/reviews/{story_key}/fidelity-report.md`</action>
|
|
34
|
+
<action if="story_has_figma_block">Write `figma.fidelity_drift_pct` to story file frontmatter</action>
|
|
35
|
+
<action if="story_has_figma_block">Include fidelity results in code review findings: PASS (0% drift), WARNING (any category exceeds 10%), or BLOCKED (any category exceeds 25%)</action>
|
|
36
|
+
<action if="no figma block">Skip fidelity check — story does not use Figma design tokens</action>
|
|
37
|
+
</step>
|
|
28
38
|
<step n="4" title="Generate Findings">
|
|
29
39
|
<action>List issues by severity: critical, warning, suggestion</action>
|
|
30
40
|
</step>
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: 'Create Stakeholder Validation'
|
|
3
|
+
validation-target: 'Stakeholder file'
|
|
4
|
+
---
|
|
5
|
+
## Structure
|
|
6
|
+
- [ ] workflow.yaml present with agent: orchestrator
|
|
7
|
+
- [ ] instructions.xml present with sequential steps
|
|
8
|
+
- [ ] checklist.md present
|
|
9
|
+
- [ ] Registered in workflow-manifest.csv
|
|
10
|
+
- [ ] Slash command file exists at .claude/commands/gaia-create-stakeholder.md
|
|
11
|
+
## Input Collection
|
|
12
|
+
- [ ] Required fields prompted: name, role, expertise, personality
|
|
13
|
+
- [ ] Optional fields prompted: perspective, tags
|
|
14
|
+
- [ ] Required field validation (non-empty check)
|
|
15
|
+
## Validation Guards
|
|
16
|
+
- [ ] 50-file cap enforced before file creation
|
|
17
|
+
- [ ] Case-insensitive duplicate name detection against existing stakeholder name frontmatter
|
|
18
|
+
- [ ] custom/stakeholders/ directory auto-created if missing
|
|
19
|
+
## Output
|
|
20
|
+
- [ ] Filename is kebab-case slug of name with .md extension
|
|
21
|
+
- [ ] File written to custom/stakeholders/{slug}.md
|
|
22
|
+
- [ ] YAML frontmatter includes all required fields
|
|
23
|
+
- [ ] Optional fields included only when provided
|
|
24
|
+
- [ ] Markdown body with ## Background section
|
|
25
|
+
- [ ] File does not exceed 100 lines
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
<workflow name="create-stakeholder">
|
|
2
|
+
<critical>
|
|
3
|
+
<mandate>Stakeholder files are written to custom/stakeholders/ — never to _gaia/</mandate>
|
|
4
|
+
<mandate>The 50-file cap and 100-line limit are hard gates (FR-164)</mandate>
|
|
5
|
+
<mandate>Duplicate name detection is case-insensitive against the name frontmatter field (FR-157)</mandate>
|
|
6
|
+
</critical>
|
|
7
|
+
|
|
8
|
+
<step n="1" title="Ensure Directory Exists">
|
|
9
|
+
<action>Check if {project-root}/custom/stakeholders/ directory exists</action>
|
|
10
|
+
<action if="directory does not exist">Create {project-root}/custom/stakeholders/ directory (and {project-root}/custom/ if needed)</action>
|
|
11
|
+
<action>Confirm directory is ready for writing</action>
|
|
12
|
+
</step>
|
|
13
|
+
|
|
14
|
+
<step n="2" title="Collect Required Inputs">
|
|
15
|
+
<ask>Provide the following required fields for the new stakeholder:
|
|
16
|
+
|
|
17
|
+
**Name** (display name, e.g., "Maria Santos"):
|
|
18
|
+
**Role** (title/function, e.g., "Housekeeper Manager"):
|
|
19
|
+
**Expertise** (domain skills, e.g., "Room turnover logistics"):
|
|
20
|
+
**Personality** (traits, e.g., "Pragmatic, detail-oriented"):
|
|
21
|
+
</ask>
|
|
22
|
+
<check if="any required field is empty">HALT: All four fields (name, role, expertise, personality) are required. Please provide all values.</check>
|
|
23
|
+
</step>
|
|
24
|
+
|
|
25
|
+
<step n="3" title="Collect Optional Inputs">
|
|
26
|
+
<ask>Optionally provide these additional fields (press Enter to skip):
|
|
27
|
+
|
|
28
|
+
**Perspective** (viewpoint/biases, e.g., "Focuses on operational efficiency"):
|
|
29
|
+
**Tags** (comma-separated, e.g., "operations, hospitality"):
|
|
30
|
+
</ask>
|
|
31
|
+
</step>
|
|
32
|
+
|
|
33
|
+
<step n="4" title="Validate Against Cap and Duplicates">
|
|
34
|
+
<action>Count existing .md files in {project-root}/custom/stakeholders/ directory</action>
|
|
35
|
+
<check if="count >= 50">HALT: The 50-file cap has been reached in custom/stakeholders/ (FR-164). There are already {count} stakeholder files. Remove unused stakeholders before creating new ones.</check>
|
|
36
|
+
<action>Scan all existing stakeholder files in custom/stakeholders/*.md — read the name field from each file's YAML frontmatter</action>
|
|
37
|
+
<action>Compare each existing name against the new stakeholder name using case-insensitive comparison</action>
|
|
38
|
+
<check if="duplicate name found (case-insensitive match)">HALT: A stakeholder with the name "{existing_name}" already exists at custom/stakeholders/{existing_file}. Name collision detected (case-insensitive). Choose a different name.</check>
|
|
39
|
+
</step>
|
|
40
|
+
|
|
41
|
+
<step n="5" title="Generate Filename Slug">
|
|
42
|
+
<action>Convert the stakeholder name to a kebab-case slug:
|
|
43
|
+
1. Convert to lowercase
|
|
44
|
+
2. Replace spaces with hyphens
|
|
45
|
+
3. Strip all characters that are not alphanumeric or hyphens
|
|
46
|
+
4. Collapse multiple consecutive hyphens into a single hyphen
|
|
47
|
+
5. Trim leading/trailing hyphens
|
|
48
|
+
6. Append .md extension
|
|
49
|
+
</action>
|
|
50
|
+
<action>Example: "Maria Santos" → "maria-santos.md", "Jean-Pierre O'Brien III" → "jean-pierre-obrien-iii.md"</action>
|
|
51
|
+
<action>Set output path: {project-root}/custom/stakeholders/{slug}.md</action>
|
|
52
|
+
<check if="file already exists at output path">HALT: File custom/stakeholders/{slug}.md already exists. This may indicate a slug collision from a different display name. Choose a different name or remove the existing file.</check>
|
|
53
|
+
</step>
|
|
54
|
+
|
|
55
|
+
<step n="6" title="Generate and Write Stakeholder File">
|
|
56
|
+
<action>Generate the stakeholder file with YAML frontmatter and Markdown body:
|
|
57
|
+
|
|
58
|
+
```
|
|
59
|
+
---
|
|
60
|
+
name: "{name}"
|
|
61
|
+
role: "{role}"
|
|
62
|
+
expertise: "{expertise}"
|
|
63
|
+
personality: "{personality}"
|
|
64
|
+
perspective: "{perspective}" # Only include if provided
|
|
65
|
+
tags: [{tags_as_yaml_array}] # Only include if provided
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
## Background
|
|
69
|
+
|
|
70
|
+
{A 2-3 sentence description synthesized from the provided fields, describing this stakeholder's viewpoint and discussion style.}
|
|
71
|
+
```
|
|
72
|
+
</action>
|
|
73
|
+
<action>Verify the generated file does not exceed 100 lines. If it does, trim the Background section to fit within the limit.</action>
|
|
74
|
+
<action>Write the file to {project-root}/custom/stakeholders/{slug}.md</action>
|
|
75
|
+
<template-output file="{project-root}/custom/stakeholders/{slug}.md">
|
|
76
|
+
Stakeholder file with YAML frontmatter (name, role, expertise, personality, and optionally perspective and tags) plus a Markdown Background section.
|
|
77
|
+
</template-output>
|
|
78
|
+
</step>
|
|
79
|
+
</workflow>
|