fraim 2.0.165 → 2.0.167

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.
Files changed (55) hide show
  1. package/dist/src/ai-hub/catalog.js +20 -27
  2. package/dist/src/ai-hub/server.js +418 -2
  3. package/dist/src/ai-hub/word-sideload.js +95 -0
  4. package/dist/src/cli/commands/org.js +40 -0
  5. package/dist/src/cli/commands/test-mcp.js +171 -0
  6. package/dist/src/cli/fraim.js +2 -0
  7. package/dist/src/cli/setup/first-run.js +242 -0
  8. package/dist/src/cli/utils/org-publish.js +98 -0
  9. package/dist/src/config/ai-manager-hiring.js +121 -0
  10. package/dist/src/config/compat.js +16 -0
  11. package/dist/src/config/feature-flags.js +25 -0
  12. package/dist/src/config/persona-capability-bundles.js +273 -0
  13. package/dist/src/config/persona-hiring.js +270 -0
  14. package/dist/src/config/portfolio-slug-overrides.js +17 -0
  15. package/dist/src/config/pricing.js +37 -0
  16. package/dist/src/config/stripe.js +43 -0
  17. package/dist/src/core/config-loader.js +9 -5
  18. package/dist/src/core/config-writer.js +75 -0
  19. package/dist/src/core/fraim-config-schema.generated.js +0 -21
  20. package/dist/src/core/utils/job-aliases.js +47 -0
  21. package/dist/src/core/utils/local-registry-resolver.js +8 -1
  22. package/dist/src/core/utils/workflow-parser.js +174 -0
  23. package/index.js +1 -1
  24. package/package.json +5 -1
  25. package/public/ai-hub/index.html +81 -0
  26. package/public/ai-hub/powerpoint-taskpane/index.html +236 -236
  27. package/public/ai-hub/powerpoint-taskpane/manifest.xml +29 -29
  28. package/public/ai-hub/review.css +13 -0
  29. package/public/ai-hub/script.js +414 -4
  30. package/public/ai-hub/styles.css +56 -0
  31. package/public/first-run/styles.css +73 -73
  32. package/public/portfolio/ashley.html +523 -0
  33. package/public/portfolio/auditya.html +83 -0
  34. package/public/portfolio/banke.html +83 -0
  35. package/public/portfolio/beza.html +659 -0
  36. package/public/portfolio/careena.html +632 -0
  37. package/public/portfolio/casey.html +568 -0
  38. package/public/portfolio/celia.html +490 -0
  39. package/public/portfolio/deidre.html +642 -0
  40. package/public/portfolio/gautam.html +597 -0
  41. package/public/portfolio/hari.html +469 -0
  42. package/public/portfolio/huxley.html +1354 -0
  43. package/public/portfolio/index.html +741 -0
  44. package/public/portfolio/maestro.html +518 -0
  45. package/public/portfolio/mandy.html +590 -0
  46. package/public/portfolio/mona.html +597 -0
  47. package/public/portfolio/pam.html +887 -0
  48. package/public/portfolio/procella.html +107 -0
  49. package/public/portfolio/qasm.html +569 -0
  50. package/public/portfolio/ricardo.html +489 -0
  51. package/public/portfolio/sade.html +560 -0
  52. package/public/portfolio/sam.html +654 -0
  53. package/public/portfolio/sechar.html +580 -0
  54. package/public/portfolio/sreya.html +599 -0
  55. package/public/portfolio/swen.html +601 -0
@@ -0,0 +1,590 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en" data-theme="light">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>MANdy · AI Manager · FRAIM Portfolio</title>
7
+ <link rel="preconnect" href="https://fonts.googleapis.com">
8
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
9
+ <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&family=JetBrains+Mono:wght@400;600&display=swap" rel="stylesheet">
10
+ <style>
11
+ :root {
12
+ --accent: #8b5cf6;
13
+ --accent-2: #7c3aed;
14
+ --accent-light: #ede9fe;
15
+ --text: #0a2240;
16
+ --text-2: #334155;
17
+ --muted: #64748b;
18
+ --bg: #f5f3ff;
19
+ --surface: #ffffff;
20
+ --surface-2: #f8fafc;
21
+ --border: #e2e8f0;
22
+ --shadow: 0 4px 24px rgba(10,34,64,.08);
23
+ --shadow-lg: 0 12px 40px rgba(10,34,64,.14);
24
+ --radius: 18px;
25
+ --radius-sm: 10px;
26
+ --green: #10b981;
27
+ --amber: #f59e0b;
28
+ --red: #ef4444;
29
+ --code-bg: #0f172a;
30
+ --code-border: #1e293b;
31
+ }
32
+ [data-theme="dark"] {
33
+ --text: #e2e8f0; --text-2: #cbd5e1; --muted: #94a3b8;
34
+ --bg: #130f1f; --surface: #1a1229; --surface-2: #211831;
35
+ --border: #2d1f4a; --shadow: 0 4px 24px rgba(0,0,0,.35);
36
+ --shadow-lg: 0 12px 40px rgba(0,0,0,.5); --accent-light: #2e1065;
37
+ --code-bg: #08050f; --code-border: #1a1229;
38
+ }
39
+ * { box-sizing: border-box; margin: 0; padding: 0; }
40
+ body { font-family: 'Inter', sans-serif; background: var(--bg); color: var(--text); min-height: 100vh; transition: background .3s, color .3s; }
41
+ code, pre, .mono { font-family: 'JetBrains Mono', 'Fira Code', monospace; }
42
+
43
+ .site-header { position: sticky; top: 0; z-index: 100; display: flex; align-items: center; justify-content: space-between; padding: 14px 32px; background: var(--surface); border-bottom: 1px solid var(--border); }
44
+ .brand { display: flex; align-items: center; gap: 10px; text-decoration: none; }
45
+ .brand-logo { width: 32px; height: 32px; border-radius: 8px; background: linear-gradient(135deg, #10b981, #059669); display: flex; align-items: center; justify-content: center; font-weight: 800; font-size: 14px; color: #fff; }
46
+ .brand-name { font-weight: 700; font-size: 15px; color: var(--text); }
47
+ .header-actions { display: flex; align-items: center; gap: 12px; }
48
+ .theme-btn { background: var(--surface-2); border: 1px solid var(--border); color: var(--muted); cursor: pointer; border-radius: 8px; padding: 7px 10px; font-size: 16px; }
49
+
50
+ .hero { max-width: 900px; margin: 56px auto 0; padding: 0 24px; text-align: center; }
51
+ .avatar-ring { display: inline-flex; align-items: center; justify-content: center; width: 96px; height: 96px; border-radius: 50%; background: linear-gradient(135deg, #8b5cf6, #6366f1, #0ea5e9); margin-bottom: 24px; box-shadow: 0 0 0 6px var(--accent-light); overflow: hidden; }
52
+ .avatar-initials { font-size: 28px; font-weight: 800; color: #fff; letter-spacing: -1px; font-family: 'JetBrains Mono', monospace; }
53
+ .role-chip { display: inline-block; background: var(--accent-light); color: var(--accent-2); border-radius: 999px; padding: 4px 14px; font-size: 12px; font-weight: 600; letter-spacing: .04em; margin-bottom: 16px; }
54
+ .hero h1 { font-size: clamp(32px, 5vw, 52px); font-weight: 800; color: var(--text); letter-spacing: -1.5px; line-height: 1.1; margin-bottom: 16px; }
55
+ .hero h1 span { color: var(--accent); }
56
+ .hero p { font-size: 17px; color: var(--muted); max-width: 560px; margin: 0 auto 32px; line-height: 1.7; }
57
+
58
+ .section-label { max-width: 900px; margin: 64px auto 0; padding: 0 24px; display: flex; align-items: center; gap: 12px; }
59
+ .section-label h2 { font-size: 13px; font-weight: 700; color: var(--muted); letter-spacing: .08em; text-transform: uppercase; }
60
+ .section-divider { flex: 1; height: 1px; background: var(--border); }
61
+
62
+ .cards-grid { max-width: 900px; margin: 24px auto 0; padding: 0 24px 80px; display: flex; flex-direction: column; gap: 20px; }
63
+ .card { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); box-shadow: var(--shadow); overflow: hidden; transition: box-shadow .2s; }
64
+ .card:hover { box-shadow: var(--shadow-lg); }
65
+ .card-header { display: flex; align-items: flex-start; gap: 16px; padding: 24px; cursor: pointer; user-select: none; }
66
+ .card-icon { width: 48px; height: 48px; border-radius: 12px; display: flex; align-items: center; justify-content: center; font-size: 22px; flex-shrink: 0; }
67
+ .card-meta { flex: 1; min-width: 0; }
68
+ .card-tag { font-size: 11px; font-weight: 700; letter-spacing: .08em; text-transform: uppercase; margin-bottom: 6px; }
69
+ .card-title { font-size: 18px; font-weight: 700; color: var(--text); line-height: 1.25; margin-bottom: 6px; }
70
+ .card-subtitle { font-size: 13px; color: var(--muted); }
71
+ .card-toggle { font-size: 22px; color: var(--muted); transition: transform .3s; flex-shrink: 0; align-self: center; }
72
+ .card.open .card-toggle { transform: rotate(90deg); }
73
+ .card-body { display: none; border-top: 1px solid var(--border); padding: 28px; }
74
+ .card.open .card-body { display: block; }
75
+
76
+ .card-context { font-size: 13px; color: var(--muted); font-style: italic; margin-bottom: 20px; line-height: 1.6; border-left: 3px solid var(--accent-light); padding-left: 14px; }
77
+
78
+ .narrative { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 16px; margin-bottom: 28px; }
79
+ @media (max-width: 640px) { .narrative { grid-template-columns: 1fr; } }
80
+ .narrative-step { background: var(--surface-2); border-radius: var(--radius-sm); padding: 16px; }
81
+ .step-label { font-size: 10px; font-weight: 700; letter-spacing: .1em; text-transform: uppercase; color: var(--muted); margin-bottom: 6px; }
82
+ .step-text { font-size: 13px; color: var(--text-2); line-height: 1.6; }
83
+ .artifact-label { font-size: 11px; font-weight: 700; letter-spacing: .08em; text-transform: uppercase; color: var(--muted); margin-bottom: 14px; display: flex; align-items: center; gap: 8px; }
84
+ .artifact-label::before { content: ''; display: block; width: 20px; height: 2px; background: var(--accent); border-radius: 2px; }
85
+ .source-ref { margin-top: 16px; font-size: 12px; color: var(--muted); }
86
+ .source-ref a { color: var(--accent); text-decoration: none; }
87
+ .source-ref a:hover { text-decoration: underline; }
88
+
89
+ /* ══ ARTIFACT 1 — Multi-Agent Orchestration Diagram ══ */
90
+ .orch-diagram {
91
+ background: var(--surface-2);
92
+ border: 1px solid var(--border);
93
+ border-radius: 14px;
94
+ padding: 24px;
95
+ }
96
+ .orch-center-wrap { display: flex; justify-content: center; align-items: center; margin-bottom: 24px; position: relative; }
97
+ .orch-svg-wrap { width: 100%; max-width: 500px; }
98
+ .orch-stats { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; margin-top: 4px; }
99
+ .orch-stat { background: var(--surface); border: 1px solid var(--border); border-radius: 10px; padding: 12px; text-align: center; }
100
+ .orch-stat-val { font-size: 16px; font-weight: 800; color: var(--accent); margin-bottom: 2px; }
101
+ .orch-stat-label { font-size: 10px; font-weight: 700; color: var(--muted); text-transform: uppercase; letter-spacing: .05em; }
102
+
103
+ /* ══ ARTIFACT 2 — Governance Checklist ══ */
104
+ .gov-panel {
105
+ background: #0f172a;
106
+ border: 1px solid #1e293b;
107
+ border-radius: 14px;
108
+ overflow: hidden;
109
+ }
110
+ .gov-topbar {
111
+ background: #1e293b;
112
+ padding: 12px 18px;
113
+ display: flex; align-items: center; justify-content: space-between;
114
+ border-bottom: 1px solid #334155;
115
+ }
116
+ .gov-topbar-title { font-size: 13px; font-weight: 600; color: #e2e8f0; font-family: 'JetBrains Mono', monospace; }
117
+ .gov-items { padding: 16px; display: flex; flex-direction: column; gap: 7px; }
118
+ .gov-item { display: flex; align-items: center; gap: 10px; padding: 8px 10px; border-radius: 8px; background: #1e293b; }
119
+ .gov-icon { font-size: 14px; width: 20px; text-align: center; flex-shrink: 0; }
120
+ .gov-text { font-size: 13px; color: #cbd5e1; flex: 1; }
121
+ .gov-spin { display: inline-block; animation: spin 1.5s linear infinite; }
122
+ @keyframes spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }
123
+ .gov-footer { border-top: 1px solid #1e293b; padding: 14px 18px; }
124
+ .gov-progress-label { display: flex; justify-content: space-between; align-items: center; margin-bottom: 8px; }
125
+ .gov-progress-text { font-size: 12px; color: #64748b; }
126
+ .gov-progress-pct { font-size: 13px; font-weight: 700; color: #4ade80; font-family: 'JetBrains Mono', monospace; }
127
+ .gov-progress-bar { background: #1e293b; border-radius: 999px; height: 6px; overflow: hidden; }
128
+ .gov-progress-fill { height: 100%; background: linear-gradient(90deg, #8b5cf6, #4ade80); border-radius: 999px; }
129
+
130
+ /* ══ ARTIFACT 3 — Sprint Gantt ══ */
131
+ .gantt-wrap {
132
+ border: 1px solid var(--border);
133
+ border-radius: 14px;
134
+ overflow: hidden;
135
+ }
136
+ .gantt-table { width: 100%; border-collapse: collapse; font-size: 12px; }
137
+ .gantt-table th {
138
+ background: var(--surface-2);
139
+ padding: 8px 10px;
140
+ text-align: center;
141
+ font-size: 10px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase;
142
+ color: var(--muted);
143
+ border-bottom: 1px solid var(--border);
144
+ }
145
+ .gantt-table th.row-header { text-align: left; }
146
+ .gantt-table td {
147
+ padding: 6px 4px;
148
+ border-bottom: 1px solid var(--border);
149
+ text-align: center;
150
+ }
151
+ .gantt-table td.row-label {
152
+ padding: 6px 12px;
153
+ text-align: left;
154
+ font-weight: 600;
155
+ color: var(--text-2);
156
+ font-size: 12px;
157
+ white-space: nowrap;
158
+ border-right: 1px solid var(--border);
159
+ }
160
+ .gantt-table tr:last-child td { border-bottom: none; }
161
+ .gantt-block {
162
+ display: block;
163
+ height: 22px;
164
+ border-radius: 5px;
165
+ opacity: .85;
166
+ margin: 0 2px;
167
+ }
168
+ .gantt-block.empty { background: transparent; }
169
+ .gantt-crit { background: #1e293b; }
170
+ .gantt-crit td { background: #0f172a; color: #94a3b8; font-size: 11px; }
171
+ .gantt-crit td.row-label { color: #8b5cf6; font-weight: 700; }
172
+ .week-group-header { font-size: 9px; font-weight: 700; letter-spacing: .08em; color: var(--muted); text-transform: uppercase; }
173
+
174
+ /* Footer */
175
+ .portfolio-footer { background: var(--surface); border-top: 1px solid var(--border); padding: 40px 24px; text-align: center; }
176
+ .footer-sub { margin-top: 20px; font-size: 12px; color: var(--muted); }
177
+ .footer-sub a { color: var(--accent); text-decoration: none; }
178
+
179
+ @media (max-width: 640px) {
180
+ .site-header { padding: 12px 16px; }
181
+ .hero { margin-top: 36px; }
182
+ .cards-grid { padding: 0 16px 60px; }
183
+ .card-header { padding: 18px; }
184
+ .card-body { padding: 18px; }
185
+ .section-label { margin-top: 40px; padding: 0 16px; }
186
+ .orch-stats { grid-template-columns: repeat(3, 1fr); }
187
+ .gantt-wrap { overflow-x: auto; }
188
+ }
189
+ </style>
190
+ </head>
191
+ <body>
192
+
193
+ <header class="site-header">
194
+ <a class="brand" href="/">
195
+ <div class="brand-logo">F</div>
196
+ <span class="brand-name">FRAIM</span>
197
+ </a>
198
+ <div class="header-actions">
199
+ <button class="theme-btn" onclick="toggleTheme()" title="Toggle dark mode">☾</button>
200
+ </div>
201
+ </header>
202
+
203
+ <section class="hero">
204
+ <div class="avatar-ring">
205
+ <img src="https://api.dicebear.com/9.x/notionists/svg?seed=MANDY-manager&backgroundColor=ede9fe&radius=50" width="96" height="96" alt="MANDY-manager avatar" style="border-radius:50%;">
206
+ </div>
207
+ <div class="role-chip">AI Manager</div>
208
+ <h1>Orchestrates the team.<br>Delivers the <span>result</span>.</h1>
209
+ <p>Orchestrates the team. Delivers the result. Asks for nothing in return.</p>
210
+ </section>
211
+
212
+ <div class="section-label">
213
+ <h2>Selected Work</h2>
214
+ <div class="section-divider"></div>
215
+ </div>
216
+
217
+ <div class="cards-grid">
218
+
219
+ <!-- Card 1: Multi-Agent Sprint Orchestration -->
220
+ <div class="card open" id="card1">
221
+ <div class="card-header" onclick="toggleCard(1)">
222
+ <div class="card-icon" style="background:#ede9fe;">🕸️</div>
223
+ <div class="card-meta">
224
+ <div class="card-tag" style="color:#8b5cf6;">Team Orchestration</div>
225
+ <div class="card-title">4-employee sprint delivered in parallel</div>
226
+ <div class="card-subtitle">FRAIM · feat/455-portfolio-pages · multi-agent-execution</div>
227
+ </div>
228
+ <div class="card-toggle">›</div>
229
+ </div>
230
+ <div class="card-body">
231
+ <div class="card-context">A 3-person startup needed to ship portfolio pages for 18 AI employees — spec, design, implementation, and QA — in a single sprint.</div>
232
+
233
+ <div class="narrative">
234
+ <div class="narrative-step">
235
+ <div class="step-label">Problem</div>
236
+ <div class="step-text">Single-threaded execution would have taken 3 weeks. The bottleneck wasn't capability — it was sequencing. Spec had to finish before design could start, design before implementation, implementation before QA.</div>
237
+ </div>
238
+ <div class="narrative-step">
239
+ <div class="step-label">What MANdy Did</div>
240
+ <div class="step-text">MANdy decomposed the work into a dependency graph, identified the parallel-safe work streams, and dispatched PaM (spec), hUXley (design), SWEn (implementation), and QAsm (validation) simultaneously. She tracked blockers in real time, resolved one dependency conflict when hUXley's mock diverged from PaM's spec, and merged all streams into a single PR.</div>
241
+ </div>
242
+ <div class="narrative-step">
243
+ <div class="step-label">The Outcome</div>
244
+ <div class="step-text">The full sprint completed in 4 hours of wall-clock time vs. an estimated 18 hours sequential. The startup shipped their first public portfolio pages the same day.</div>
245
+ </div>
246
+ </div>
247
+
248
+ <div class="artifact-label">Live Artifact — Multi-Agent Orchestration Diagram</div>
249
+
250
+ <div class="orch-diagram">
251
+ <div class="orch-center-wrap">
252
+ <div class="orch-svg-wrap">
253
+ <svg viewBox="0 0 500 320" xmlns="http://www.w3.org/2000/svg" style="width:100%;height:auto;">
254
+ <!-- Connecting lines -->
255
+ <line x1="250" y1="160" x2="130" y2="80" stroke="#8b5cf6" stroke-width="2" stroke-dasharray="5,3" opacity="0.6"/>
256
+ <line x1="250" y1="160" x2="370" y2="80" stroke="#6366f1" stroke-width="2" stroke-dasharray="5,3" opacity="0.6"/>
257
+ <line x1="250" y1="160" x2="130" y2="240" stroke="#0ea5e9" stroke-width="2" stroke-dasharray="5,3" opacity="0.6"/>
258
+ <line x1="250" y1="160" x2="370" y2="240" stroke="#10b981" stroke-width="2" stroke-dasharray="5,3" opacity="0.6"/>
259
+
260
+ <!-- Status labels on lines -->
261
+ <text x="168" y="108" font-size="10" fill="#8b5cf6" font-family="Inter,sans-serif" font-weight="600">✓ Spec done</text>
262
+ <text x="290" y="108" font-size="10" fill="#6366f1" font-family="Inter,sans-serif" font-weight="600">✓ Design done</text>
263
+ <text x="148" y="215" font-size="10" fill="#0ea5e9" font-family="Inter,sans-serif" font-weight="600">✓ Code done</text>
264
+ <text x="282" y="215" font-size="10" fill="#10b981" font-family="Inter,sans-serif" font-weight="600">⟳ Validating...</text>
265
+
266
+ <!-- MANdy center hexagon -->
267
+ <polygon points="250,130 278,145 278,175 250,190 222,175 222,145" fill="#8b5cf6" opacity="0.9"/>
268
+ <text x="250" y="162" font-size="13" fill="#fff" font-family="Inter,sans-serif" font-weight="800" text-anchor="middle">MANdy</text>
269
+
270
+ <!-- PaM node -->
271
+ <circle cx="110" cy="68" r="34" fill="#6366f1" opacity="0.9"/>
272
+ <text x="110" y="64" font-size="12" fill="#fff" font-family="Inter,sans-serif" font-weight="700" text-anchor="middle">PaM</text>
273
+ <text x="110" y="79" font-size="10" fill="#e0e7ff" font-family="Inter,sans-serif" text-anchor="middle">Spec</text>
274
+
275
+ <!-- hUXley node -->
276
+ <circle cx="390" cy="68" r="34" fill="#10b981" opacity="0.9"/>
277
+ <text x="390" y="64" font-size="10" fill="#fff" font-family="Inter,sans-serif" font-weight="700" text-anchor="middle">hUXley</text>
278
+ <text x="390" y="79" font-size="10" fill="#d1fae5" font-family="Inter,sans-serif" text-anchor="middle">Design</text>
279
+
280
+ <!-- SWEn node -->
281
+ <circle cx="110" cy="252" r="34" fill="#0ea5e9" opacity="0.9"/>
282
+ <text x="110" y="248" font-size="12" fill="#fff" font-family="Inter,sans-serif" font-weight="700" text-anchor="middle">SWEn</text>
283
+ <text x="110" y="263" font-size="10" fill="#e0f2fe" font-family="Inter,sans-serif" text-anchor="middle">Code</text>
284
+
285
+ <!-- QAsm node -->
286
+ <circle cx="390" cy="252" r="34" fill="#10b981" opacity="0.75"/>
287
+ <text x="390" y="248" font-size="12" fill="#fff" font-family="Inter,sans-serif" font-weight="700" text-anchor="middle">QAsm</text>
288
+ <text x="390" y="263" font-size="10" fill="#d1fae5" font-family="Inter,sans-serif" text-anchor="middle">QA</text>
289
+ </svg>
290
+ </div>
291
+ </div>
292
+ <div class="orch-stats">
293
+ <div class="orch-stat">
294
+ <div class="orch-stat-val">4</div>
295
+ <div class="orch-stat-label">Agents dispatched</div>
296
+ </div>
297
+ <div class="orch-stat">
298
+ <div class="orch-stat-val">1</div>
299
+ <div class="orch-stat-label">Conflict resolved</div>
300
+ </div>
301
+ <div class="orch-stat">
302
+ <div class="orch-stat-val" style="color:#10b981;">18h → 4h</div>
303
+ <div class="orch-stat-label">Wall-clock time</div>
304
+ </div>
305
+ </div>
306
+ </div>
307
+
308
+ <div class="source-ref">
309
+ 📎 Source: <a href="#">FRAIM · feat/455-portfolio-pages · fraim/ai-manager/jobs/feature-implementation.md</a>
310
+ </div>
311
+ </div>
312
+ </div>
313
+
314
+ <!-- Card 2: Delivery Governance Review -->
315
+ <div class="card" id="card2">
316
+ <div class="card-header" onclick="toggleCard(2)">
317
+ <div class="card-icon" style="background:#ede9fe;">✅</div>
318
+ <div class="card-meta">
319
+ <div class="card-tag" style="color:#8b5cf6;">Quality Gate</div>
320
+ <div class="card-title">PR ready for merge — or it isn't</div>
321
+ <div class="card-subtitle">FRAIM · delivery-governance-review · sprint-governance</div>
322
+ </div>
323
+ <div class="card-toggle">›</div>
324
+ </div>
325
+ <div class="card-body">
326
+ <div class="card-context">A Series-A engineering team was merging PRs that passed CI but failed real-world UX validation — the gap between "tests pass" and "the feature actually works."</div>
327
+
328
+ <div class="narrative">
329
+ <div class="narrative-step">
330
+ <div class="step-label">Problem</div>
331
+ <div class="step-text">CI gates caught syntax errors and unit test regressions. They didn't catch: hire CTAs still pointing to href="#", mobile viewport overflow, dark mode tokens missing from new components, or security findings buried in log output.</div>
332
+ </div>
333
+ <div class="narrative-step">
334
+ <div class="step-label">What MANdy Can Build</div>
335
+ <div class="step-text">MANdy implemented a delivery governance review gate. Before any PR is marked ready, she runs a structured checklist: build clean, tests green, UI validated in a real browser, security review findings triaged, architecture doc updated, traceability matrix complete. Each gate has evidence — not just a checkbox.</div>
336
+ </div>
337
+ <div class="narrative-step">
338
+ <div class="step-label">Possible Outcome</div>
339
+ <div class="step-text">With MANdy's delivery governance gate, teams can expect "passes CI but fails review" PR rejection rates to fall from around 34% to 6% within a quarter. Lead time from "code done" to "merged" can improve by 40% as ambiguous PRs get resolved earlier in the process.</div>
340
+ </div>
341
+ </div>
342
+
343
+ <div class="artifact-label">Live Artifact — Delivery Gate Checklist</div>
344
+
345
+ <div class="gov-panel">
346
+ <div class="gov-topbar">
347
+ <span class="gov-topbar-title">Delivery Gate — PR #457</span>
348
+ <span style="font-size:11px;color:#64748b;">MANdy · Governance</span>
349
+ </div>
350
+ <div class="gov-items">
351
+ <div class="gov-item">
352
+ <span class="gov-icon">✅</span>
353
+ <span class="gov-text">TypeScript build clean</span>
354
+ </div>
355
+ <div class="gov-item">
356
+ <span class="gov-icon">✅</span>
357
+ <span class="gov-text">7/7 tests pass</span>
358
+ </div>
359
+ <div class="gov-item">
360
+ <span class="gov-icon">✅</span>
361
+ <span class="gov-text">UI validated (Playwright)</span>
362
+ </div>
363
+ <div class="gov-item">
364
+ <span class="gov-icon">✅</span>
365
+ <span class="gov-text">Security: 0 findings</span>
366
+ </div>
367
+ <div class="gov-item">
368
+ <span class="gov-icon">✅</span>
369
+ <span class="gov-text">Traceability: 20/20 Met</span>
370
+ </div>
371
+ <div class="gov-item">
372
+ <span class="gov-icon">✅</span>
373
+ <span class="gov-text">Architecture doc updated</span>
374
+ </div>
375
+ <div class="gov-item">
376
+ <span class="gov-icon">✅</span>
377
+ <span class="gov-text">Feedback file: 5/5 ADDRESSED</span>
378
+ </div>
379
+ <div class="gov-item">
380
+ <span class="gov-icon"><span class="gov-spin">⟳</span></span>
381
+ <span class="gov-text" style="color:#94a3b8;">PR approved (awaiting)</span>
382
+ </div>
383
+ </div>
384
+ <div class="gov-footer">
385
+ <div class="gov-progress-label">
386
+ <span class="gov-progress-text">7/8 gates passed</span>
387
+ <span class="gov-progress-pct">87.5%</span>
388
+ </div>
389
+ <div class="gov-progress-bar">
390
+ <div class="gov-progress-fill" style="width:87.5%;"></div>
391
+ </div>
392
+ </div>
393
+ </div>
394
+
395
+ <div class="source-ref">
396
+ 📎 Source: <a href="#">FRAIM · delivery-governance-review · fraim/ai-manager/jobs/delivery-governance-review.md</a>
397
+ </div>
398
+ </div>
399
+ </div>
400
+
401
+ <!-- Card 3: Sprint Planning -->
402
+ <div class="card" id="card3">
403
+ <div class="card-header" onclick="toggleCard(3)">
404
+ <div class="card-icon" style="background:#ede9fe;">📅</div>
405
+ <div class="card-meta">
406
+ <div class="card-tag" style="color:#8b5cf6;">Capacity Planning</div>
407
+ <div class="card-title">3-week roadmap, no surprises</div>
408
+ <div class="card-subtitle">FRAIM · sprint-planning · fraim/ai-manager/jobs/sprint-planning.md</div>
409
+ </div>
410
+ <div class="card-toggle">›</div>
411
+ </div>
412
+ <div class="card-body">
413
+ <div class="card-context">A product team of 6 AI employees was missing sprint commitments by 30% — not because of capability gaps, but because work was scoped without dependency mapping.</div>
414
+
415
+ <div class="narrative">
416
+ <div class="narrative-step">
417
+ <div class="step-label">Problem</div>
418
+ <div class="step-text">Sprint planning was a list of tickets assigned by gut feel. Dependencies between the employees' outputs were implicit. When SWEn's implementation blocked on PaM's spec, nobody had flagged the dependency upfront.</div>
419
+ </div>
420
+ <div class="narrative-step">
421
+ <div class="step-label">What MANdy Can Build</div>
422
+ <div class="step-text">MANdy built a sprint plan by first extracting all cross-employee dependencies from the backlog, computing the critical path, and auto-assigning work so parallel-safe tasks started simultaneously. She left 20% buffer on each employee's capacity for unplanned asks.</div>
423
+ </div>
424
+ <div class="narrative-step">
425
+ <div class="step-label">Possible Outcome</div>
426
+ <div class="step-text">Teams running MANdy's dependency-aware sprint plans can expect completion rates to rise from 68% to 94% within 6 weeks. Any remaining slip is typically a documented scope change — carried forward cleanly rather than quietly dropped.</div>
427
+ </div>
428
+ </div>
429
+
430
+ <div class="artifact-label">Live Artifact — Sprint Timeline (Gantt)</div>
431
+
432
+ <div class="gantt-wrap">
433
+ <table class="gantt-table">
434
+ <thead>
435
+ <tr>
436
+ <th class="row-header" style="width:80px;">Employee</th>
437
+ <th colspan="5" class="week-group-header">Week 1</th>
438
+ <th colspan="5" class="week-group-header">Week 2</th>
439
+ <th colspan="5" class="week-group-header">Week 3</th>
440
+ </tr>
441
+ </thead>
442
+ <tbody>
443
+ <tr>
444
+ <td class="row-label">PaM</td>
445
+ <td><span class="gantt-block" style="background:#6366f1;"></span></td>
446
+ <td><span class="gantt-block" style="background:#6366f1;"></span></td>
447
+ <td><span class="gantt-block" style="background:#6366f1;"></span></td>
448
+ <td><span class="gantt-block empty"></span></td>
449
+ <td><span class="gantt-block empty"></span></td>
450
+ <td><span class="gantt-block" style="background:#6366f1;opacity:.5;"></span></td>
451
+ <td><span class="gantt-block" style="background:#6366f1;opacity:.5;"></span></td>
452
+ <td><span class="gantt-block empty"></span></td>
453
+ <td><span class="gantt-block empty"></span></td>
454
+ <td><span class="gantt-block empty"></span></td>
455
+ <td><span class="gantt-block empty"></span></td>
456
+ <td><span class="gantt-block empty"></span></td>
457
+ <td><span class="gantt-block empty"></span></td>
458
+ <td><span class="gantt-block empty"></span></td>
459
+ <td><span class="gantt-block empty"></span></td>
460
+ </tr>
461
+ <tr>
462
+ <td class="row-label">hUXley</td>
463
+ <td><span class="gantt-block empty"></span></td>
464
+ <td><span class="gantt-block" style="background:#10b981;"></span></td>
465
+ <td><span class="gantt-block" style="background:#10b981;"></span></td>
466
+ <td><span class="gantt-block" style="background:#10b981;"></span></td>
467
+ <td><span class="gantt-block empty"></span></td>
468
+ <td><span class="gantt-block" style="background:#10b981;opacity:.5;"></span></td>
469
+ <td><span class="gantt-block empty"></span></td>
470
+ <td><span class="gantt-block empty"></span></td>
471
+ <td><span class="gantt-block empty"></span></td>
472
+ <td><span class="gantt-block empty"></span></td>
473
+ <td><span class="gantt-block empty"></span></td>
474
+ <td><span class="gantt-block empty"></span></td>
475
+ <td><span class="gantt-block empty"></span></td>
476
+ <td><span class="gantt-block empty"></span></td>
477
+ <td><span class="gantt-block empty"></span></td>
478
+ </tr>
479
+ <tr>
480
+ <td class="row-label">SWEn</td>
481
+ <td><span class="gantt-block empty"></span></td>
482
+ <td><span class="gantt-block empty"></span></td>
483
+ <td><span class="gantt-block" style="background:#0ea5e9;"></span></td>
484
+ <td><span class="gantt-block" style="background:#0ea5e9;"></span></td>
485
+ <td><span class="gantt-block" style="background:#0ea5e9;"></span></td>
486
+ <td><span class="gantt-block" style="background:#0ea5e9;"></span></td>
487
+ <td><span class="gantt-block" style="background:#0ea5e9;"></span></td>
488
+ <td><span class="gantt-block" style="background:#0ea5e9;opacity:.6;"></span></td>
489
+ <td><span class="gantt-block empty"></span></td>
490
+ <td><span class="gantt-block empty"></span></td>
491
+ <td><span class="gantt-block" style="background:#0ea5e9;opacity:.4;"></span></td>
492
+ <td><span class="gantt-block" style="background:#0ea5e9;opacity:.4;"></span></td>
493
+ <td><span class="gantt-block empty"></span></td>
494
+ <td><span class="gantt-block empty"></span></td>
495
+ <td><span class="gantt-block empty"></span></td>
496
+ </tr>
497
+ <tr>
498
+ <td class="row-label">QAsm</td>
499
+ <td><span class="gantt-block empty"></span></td>
500
+ <td><span class="gantt-block empty"></span></td>
501
+ <td><span class="gantt-block empty"></span></td>
502
+ <td><span class="gantt-block empty"></span></td>
503
+ <td><span class="gantt-block empty"></span></td>
504
+ <td><span class="gantt-block empty"></span></td>
505
+ <td><span class="gantt-block" style="background:#10b981;opacity:.8;"></span></td>
506
+ <td><span class="gantt-block" style="background:#10b981;opacity:.8;"></span></td>
507
+ <td><span class="gantt-block" style="background:#10b981;opacity:.8;"></span></td>
508
+ <td><span class="gantt-block empty"></span></td>
509
+ <td><span class="gantt-block" style="background:#10b981;opacity:.5;"></span></td>
510
+ <td><span class="gantt-block" style="background:#10b981;opacity:.5;"></span></td>
511
+ <td><span class="gantt-block" style="background:#10b981;opacity:.5;"></span></td>
512
+ <td><span class="gantt-block empty"></span></td>
513
+ <td><span class="gantt-block empty"></span></td>
514
+ </tr>
515
+ <tr>
516
+ <td class="row-label">AshLey</td>
517
+ <td><span class="gantt-block" style="background:#f59e0b;opacity:.6;"></span></td>
518
+ <td><span class="gantt-block empty"></span></td>
519
+ <td><span class="gantt-block empty"></span></td>
520
+ <td><span class="gantt-block" style="background:#f59e0b;opacity:.6;"></span></td>
521
+ <td><span class="gantt-block empty"></span></td>
522
+ <td><span class="gantt-block empty"></span></td>
523
+ <td><span class="gantt-block empty"></span></td>
524
+ <td><span class="gantt-block" style="background:#f59e0b;opacity:.6;"></span></td>
525
+ <td><span class="gantt-block empty"></span></td>
526
+ <td><span class="gantt-block empty"></span></td>
527
+ <td><span class="gantt-block empty"></span></td>
528
+ <td><span class="gantt-block" style="background:#f59e0b;opacity:.6;"></span></td>
529
+ <td><span class="gantt-block empty"></span></td>
530
+ <td><span class="gantt-block empty"></span></td>
531
+ <td><span class="gantt-block empty"></span></td>
532
+ </tr>
533
+ <tr style="background:var(--surface-2);">
534
+ <td class="row-label" style="color:#8b5cf6;font-weight:700;font-size:10px;letter-spacing:.05em;text-transform:uppercase;">Critical path</td>
535
+ <td><span class="gantt-block" style="background:#8b5cf6;opacity:.4;height:8px;margin-top:7px;"></span></td>
536
+ <td><span class="gantt-block" style="background:#8b5cf6;opacity:.6;height:8px;margin-top:7px;"></span></td>
537
+ <td><span class="gantt-block" style="background:#8b5cf6;opacity:.8;height:8px;margin-top:7px;"></span></td>
538
+ <td><span class="gantt-block" style="background:#8b5cf6;opacity:.8;height:8px;margin-top:7px;"></span></td>
539
+ <td><span class="gantt-block" style="background:#8b5cf6;opacity:.8;height:8px;margin-top:7px;"></span></td>
540
+ <td><span class="gantt-block" style="background:#8b5cf6;opacity:.8;height:8px;margin-top:7px;"></span></td>
541
+ <td><span class="gantt-block" style="background:#8b5cf6;opacity:.8;height:8px;margin-top:7px;"></span></td>
542
+ <td><span class="gantt-block" style="background:#8b5cf6;opacity:.7;height:8px;margin-top:7px;"></span></td>
543
+ <td><span class="gantt-block" style="background:#8b5cf6;opacity:.6;height:8px;margin-top:7px;"></span></td>
544
+ <td><span class="gantt-block" style="background:#8b5cf6;opacity:.5;height:8px;margin-top:7px;"></span></td>
545
+ <td><span class="gantt-block" style="background:#8b5cf6;opacity:.4;height:8px;margin-top:7px;"></span></td>
546
+ <td><span class="gantt-block" style="background:#8b5cf6;opacity:.3;height:8px;margin-top:7px;"></span></td>
547
+ <td><span class="gantt-block" style="background:#8b5cf6;opacity:.2;height:8px;margin-top:7px;"></span></td>
548
+ <td><span class="gantt-block" style="background:#8b5cf6;opacity:.2;height:8px;margin-top:7px;"></span></td>
549
+ <td><span class="gantt-block" style="background:#8b5cf6;opacity:.2;height:8px;margin-top:7px;"></span></td>
550
+ </tr>
551
+ </tbody>
552
+ </table>
553
+ </div>
554
+
555
+ <div class="source-ref">
556
+ 📎 Source: <a href="#">FRAIM · sprint-planning · fraim/ai-manager/jobs/sprint-planning.md</a>
557
+ </div>
558
+ </div>
559
+ </div>
560
+
561
+ </div>
562
+
563
+ <footer class="portfolio-footer">
564
+ <div class="footer-sub">
565
+ Part of the <a href="/">FRAIM</a> · 18 AI employees available ·
566
+ <a href="/">View all employees</a>
567
+ </div>
568
+ </footer>
569
+
570
+ <script>
571
+ function toggleTheme() {
572
+ const html = document.documentElement;
573
+ const isDark = html.getAttribute('data-theme') === 'dark';
574
+ html.setAttribute('data-theme', isDark ? 'light' : 'dark');
575
+ document.querySelector('.theme-btn').textContent = isDark ? '☾' : '☀';
576
+ }
577
+ if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
578
+ document.documentElement.setAttribute('data-theme', 'dark');
579
+ document.querySelector('.theme-btn').textContent = '☀';
580
+ }
581
+ function toggleCard(num) {
582
+ const card = document.getElementById('card' + num);
583
+ const isOpen = card.classList.contains('open');
584
+ document.querySelectorAll('.card').forEach(c => c.classList.remove('open'));
585
+ if (!isOpen) { card.classList.add('open'); card.scrollIntoView({ behavior: 'smooth', block: 'nearest' }); }
586
+ }
587
+ </script>
588
+
589
+ </body>
590
+ </html>