omgkit 2.1.0 → 2.2.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/package.json +1 -1
- package/plugin/skills/SKILL_STANDARDS.md +743 -0
- package/plugin/skills/databases/mongodb/SKILL.md +797 -28
- package/plugin/skills/databases/postgresql/SKILL.md +494 -18
- package/plugin/skills/databases/prisma/SKILL.md +776 -30
- package/plugin/skills/databases/redis/SKILL.md +885 -25
- package/plugin/skills/devops/aws/SKILL.md +686 -28
- package/plugin/skills/devops/docker/SKILL.md +466 -18
- package/plugin/skills/devops/github-actions/SKILL.md +684 -29
- package/plugin/skills/devops/kubernetes/SKILL.md +621 -24
- package/plugin/skills/frameworks/django/SKILL.md +920 -20
- package/plugin/skills/frameworks/express/SKILL.md +1361 -35
- package/plugin/skills/frameworks/fastapi/SKILL.md +1260 -33
- package/plugin/skills/frameworks/laravel/SKILL.md +1244 -31
- package/plugin/skills/frameworks/nestjs/SKILL.md +1005 -26
- package/plugin/skills/frameworks/nextjs/SKILL.md +407 -44
- package/plugin/skills/frameworks/rails/SKILL.md +594 -28
- package/plugin/skills/frameworks/react/SKILL.md +1006 -32
- package/plugin/skills/frameworks/spring/SKILL.md +528 -35
- package/plugin/skills/frameworks/vue/SKILL.md +1296 -27
- package/plugin/skills/frontend/accessibility/SKILL.md +1108 -34
- package/plugin/skills/frontend/frontend-design/SKILL.md +1304 -26
- package/plugin/skills/frontend/responsive/SKILL.md +847 -21
- package/plugin/skills/frontend/shadcn-ui/SKILL.md +976 -38
- package/plugin/skills/frontend/tailwindcss/SKILL.md +831 -35
- package/plugin/skills/frontend/threejs/SKILL.md +1298 -29
- package/plugin/skills/languages/javascript/SKILL.md +935 -31
- package/plugin/skills/languages/python/SKILL.md +489 -25
- package/plugin/skills/languages/typescript/SKILL.md +379 -30
- package/plugin/skills/methodology/brainstorming/SKILL.md +597 -23
- package/plugin/skills/methodology/defense-in-depth/SKILL.md +832 -34
- package/plugin/skills/methodology/dispatching-parallel-agents/SKILL.md +665 -31
- package/plugin/skills/methodology/executing-plans/SKILL.md +556 -24
- package/plugin/skills/methodology/finishing-development-branch/SKILL.md +595 -25
- package/plugin/skills/methodology/problem-solving/SKILL.md +429 -61
- package/plugin/skills/methodology/receiving-code-review/SKILL.md +536 -24
- package/plugin/skills/methodology/requesting-code-review/SKILL.md +632 -21
- package/plugin/skills/methodology/root-cause-tracing/SKILL.md +641 -30
- package/plugin/skills/methodology/sequential-thinking/SKILL.md +262 -3
- package/plugin/skills/methodology/systematic-debugging/SKILL.md +571 -32
- package/plugin/skills/methodology/test-driven-development/SKILL.md +779 -24
- package/plugin/skills/methodology/testing-anti-patterns/SKILL.md +691 -29
- package/plugin/skills/methodology/token-optimization/SKILL.md +598 -29
- package/plugin/skills/methodology/verification-before-completion/SKILL.md +543 -22
- package/plugin/skills/methodology/writing-plans/SKILL.md +590 -18
- package/plugin/skills/omega/omega-architecture/SKILL.md +838 -39
- package/plugin/skills/omega/omega-coding/SKILL.md +636 -39
- package/plugin/skills/omega/omega-sprint/SKILL.md +855 -48
- package/plugin/skills/omega/omega-testing/SKILL.md +940 -41
- package/plugin/skills/omega/omega-thinking/SKILL.md +703 -50
- package/plugin/skills/security/better-auth/SKILL.md +1065 -28
- package/plugin/skills/security/oauth/SKILL.md +968 -31
- package/plugin/skills/security/owasp/SKILL.md +894 -33
- package/plugin/skills/testing/playwright/SKILL.md +764 -38
- package/plugin/skills/testing/pytest/SKILL.md +873 -36
- package/plugin/skills/testing/vitest/SKILL.md +980 -35
|
@@ -1,64 +1,871 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: omega-sprint
|
|
3
|
-
description:
|
|
3
|
+
description: AI-native sprint management with autonomous agent orchestration and continuous delivery cycles
|
|
4
|
+
category: omega
|
|
5
|
+
triggers:
|
|
6
|
+
- omega sprint
|
|
7
|
+
- sprint planning
|
|
8
|
+
- AI team management
|
|
9
|
+
- agent orchestration
|
|
10
|
+
- sprint execution
|
|
11
|
+
- autonomous development
|
|
12
|
+
- team coordination
|
|
4
13
|
---
|
|
5
14
|
|
|
6
|
-
# Omega Sprint
|
|
15
|
+
# Omega Sprint
|
|
7
16
|
|
|
8
|
-
|
|
17
|
+
Execute **AI-native sprint management** with autonomous agent orchestration, intelligent task routing, and continuous delivery cycles. This skill provides frameworks for running high-velocity development sprints with AI teams.
|
|
18
|
+
|
|
19
|
+
## Purpose
|
|
20
|
+
|
|
21
|
+
Master AI-native sprint execution:
|
|
22
|
+
|
|
23
|
+
- Plan and execute sprints with AI agent teams
|
|
24
|
+
- Route tasks to optimal agents automatically
|
|
25
|
+
- Achieve continuous delivery with zero-friction releases
|
|
26
|
+
- Maintain quality through automated gates
|
|
27
|
+
- Learn and improve sprint-over-sprint
|
|
28
|
+
- Scale development capacity infinitely
|
|
29
|
+
- Coordinate human-AI collaboration seamlessly
|
|
30
|
+
|
|
31
|
+
## Features
|
|
32
|
+
|
|
33
|
+
### 1. AI-Native Sprint Lifecycle
|
|
34
|
+
|
|
35
|
+
```markdown
|
|
36
|
+
## The Omega Sprint Cycle
|
|
37
|
+
|
|
38
|
+
┌─────────────────────────────────────────────────────────────────────────┐
|
|
39
|
+
│ OMEGA SPRINT LIFECYCLE │
|
|
40
|
+
├─────────────────────────────────────────────────────────────────────────┤
|
|
41
|
+
│ │
|
|
42
|
+
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
|
|
43
|
+
│ │ VISION │────→│ PLAN │────→│ EXECUTE │────→│ DELIVER │ │
|
|
44
|
+
│ └────┬────┘ └────┬────┘ └────┬────┘ └────┬────┘ │
|
|
45
|
+
│ │ │ │ │ │
|
|
46
|
+
│ ▼ ▼ ▼ ▼ │
|
|
47
|
+
│ Define what Break into AI agents Ship to │
|
|
48
|
+
│ success looks agent-ready work in production │
|
|
49
|
+
│ like tasks parallel │
|
|
50
|
+
│ │ │ │ │ │
|
|
51
|
+
│ └───────────────┴───────────────┴───────────────┘ │
|
|
52
|
+
│ │ │
|
|
53
|
+
│ ▼ │
|
|
54
|
+
│ ┌─────────────┐ │
|
|
55
|
+
│ │ RETROSPECT │ │
|
|
56
|
+
│ └──────┬──────┘ │
|
|
57
|
+
│ │ │
|
|
58
|
+
│ ▼ │
|
|
59
|
+
│ Learn, adapt, improve │
|
|
60
|
+
│ Feed into next sprint │
|
|
61
|
+
│ │
|
|
62
|
+
└─────────────────────────────────────────────────────────────────────────┘
|
|
63
|
+
|
|
64
|
+
Key Differences from Traditional Sprints:
|
|
65
|
+
- Tasks sized for AI execution (hours, not days)
|
|
66
|
+
- Parallel execution by agent swarm
|
|
67
|
+
- Continuous integration throughout
|
|
68
|
+
- Automated quality gates
|
|
69
|
+
- Zero context-switching cost
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### 2. Vision Setting Framework
|
|
73
|
+
|
|
74
|
+
```typescript
|
|
75
|
+
/**
|
|
76
|
+
* Sprint Vision: Define what success looks like
|
|
77
|
+
* Clear vision enables autonomous agent decision-making
|
|
78
|
+
*/
|
|
79
|
+
|
|
80
|
+
interface SprintVision {
|
|
81
|
+
// What are we building?
|
|
82
|
+
objective: string;
|
|
83
|
+
|
|
84
|
+
// Why does it matter?
|
|
85
|
+
businessValue: string;
|
|
86
|
+
|
|
87
|
+
// How do we know we're done?
|
|
88
|
+
successCriteria: SuccessCriterion[];
|
|
89
|
+
|
|
90
|
+
// What are the boundaries?
|
|
91
|
+
scope: ScopeDefinition;
|
|
92
|
+
|
|
93
|
+
// What quality standards apply?
|
|
94
|
+
qualityGates: QualityGate[];
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
interface SuccessCriterion {
|
|
98
|
+
metric: string;
|
|
99
|
+
target: string | number;
|
|
100
|
+
measurement: 'automated' | 'manual';
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
interface ScopeDefinition {
|
|
104
|
+
included: string[];
|
|
105
|
+
excluded: string[];
|
|
106
|
+
assumptions: string[];
|
|
107
|
+
risks: Risk[];
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Vision Template
|
|
111
|
+
const sprintVision: SprintVision = {
|
|
112
|
+
objective: "Implement user authentication with OAuth2 providers",
|
|
113
|
+
|
|
114
|
+
businessValue: "Enable users to sign in with existing accounts, reducing signup friction by 60%",
|
|
115
|
+
|
|
116
|
+
successCriteria: [
|
|
117
|
+
{
|
|
118
|
+
metric: "OAuth providers supported",
|
|
119
|
+
target: 3, // Google, GitHub, Discord
|
|
120
|
+
measurement: "automated"
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
metric: "Auth flow completion rate",
|
|
124
|
+
target: "95%",
|
|
125
|
+
measurement: "automated"
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
metric: "Security audit passed",
|
|
129
|
+
target: "OWASP compliance",
|
|
130
|
+
measurement: "manual"
|
|
131
|
+
}
|
|
132
|
+
],
|
|
133
|
+
|
|
134
|
+
scope: {
|
|
135
|
+
included: [
|
|
136
|
+
"OAuth2 provider integration",
|
|
137
|
+
"Session management",
|
|
138
|
+
"User profile creation",
|
|
139
|
+
"Token refresh logic"
|
|
140
|
+
],
|
|
141
|
+
excluded: [
|
|
142
|
+
"Password-based auth",
|
|
143
|
+
"2FA implementation",
|
|
144
|
+
"Admin user management"
|
|
145
|
+
],
|
|
146
|
+
assumptions: [
|
|
147
|
+
"Database schema already supports user records",
|
|
148
|
+
"Frontend auth UI components exist"
|
|
149
|
+
],
|
|
150
|
+
risks: [
|
|
151
|
+
{
|
|
152
|
+
description: "OAuth provider API changes",
|
|
153
|
+
probability: "low",
|
|
154
|
+
impact: "medium",
|
|
155
|
+
mitigation: "Use official SDKs with version pinning"
|
|
156
|
+
}
|
|
157
|
+
]
|
|
158
|
+
},
|
|
159
|
+
|
|
160
|
+
qualityGates: [
|
|
161
|
+
{ type: 'coverage', threshold: 80 },
|
|
162
|
+
{ type: 'security-scan', threshold: 'no-critical' },
|
|
163
|
+
{ type: 'performance', threshold: 'p99 < 200ms' }
|
|
164
|
+
]
|
|
165
|
+
};
|
|
9
166
|
```
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
167
|
+
|
|
168
|
+
### 3. Intelligent Task Breakdown
|
|
169
|
+
|
|
170
|
+
```typescript
|
|
171
|
+
/**
|
|
172
|
+
* Break vision into agent-executable tasks
|
|
173
|
+
* Tasks should be atomic, testable, and independent
|
|
174
|
+
*/
|
|
175
|
+
|
|
176
|
+
interface SprintTask {
|
|
177
|
+
id: string;
|
|
178
|
+
title: string;
|
|
179
|
+
description: string;
|
|
180
|
+
type: TaskType;
|
|
181
|
+
priority: 'critical' | 'high' | 'medium' | 'low';
|
|
182
|
+
estimatedTokens: number; // AI work estimation
|
|
183
|
+
dependencies: string[];
|
|
184
|
+
acceptanceCriteria: string[];
|
|
185
|
+
suggestedAgent: AgentType;
|
|
186
|
+
testStrategy: TestStrategy;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
type TaskType =
|
|
190
|
+
| 'feature' // New functionality
|
|
191
|
+
| 'bugfix' // Fix existing issues
|
|
192
|
+
| 'refactor' // Improve code quality
|
|
193
|
+
| 'test' // Add/improve tests
|
|
194
|
+
| 'docs' // Documentation
|
|
195
|
+
| 'research' // Investigation/spike
|
|
196
|
+
| 'config'; // Configuration changes
|
|
197
|
+
|
|
198
|
+
// Task breakdown algorithm
|
|
199
|
+
class TaskBreaker {
|
|
200
|
+
async breakdownFeature(feature: string): Promise<SprintTask[]> {
|
|
201
|
+
const analysis = await this.analyzeFeature(feature);
|
|
202
|
+
|
|
203
|
+
return [
|
|
204
|
+
// Layer 1: Foundation
|
|
205
|
+
...this.generateFoundationTasks(analysis),
|
|
206
|
+
// Layer 2: Core implementation
|
|
207
|
+
...this.generateImplementationTasks(analysis),
|
|
208
|
+
// Layer 3: Integration
|
|
209
|
+
...this.generateIntegrationTasks(analysis),
|
|
210
|
+
// Layer 4: Quality
|
|
211
|
+
...this.generateQualityTasks(analysis)
|
|
212
|
+
];
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
private generateFoundationTasks(analysis: FeatureAnalysis): SprintTask[] {
|
|
216
|
+
return [
|
|
217
|
+
{
|
|
218
|
+
id: 'foundation-types',
|
|
219
|
+
title: 'Define TypeScript interfaces and types',
|
|
220
|
+
description: 'Create type definitions for all new entities and operations',
|
|
221
|
+
type: 'feature',
|
|
222
|
+
priority: 'critical',
|
|
223
|
+
estimatedTokens: 5000,
|
|
224
|
+
dependencies: [],
|
|
225
|
+
acceptanceCriteria: [
|
|
226
|
+
'All interfaces exported',
|
|
227
|
+
'JSDoc comments on all types',
|
|
228
|
+
'Strict mode compliant'
|
|
229
|
+
],
|
|
230
|
+
suggestedAgent: 'architect',
|
|
231
|
+
testStrategy: { type: 'type-check', coverage: 100 }
|
|
232
|
+
},
|
|
233
|
+
{
|
|
234
|
+
id: 'foundation-schema',
|
|
235
|
+
title: 'Create database schema migrations',
|
|
236
|
+
description: 'Add necessary tables/columns for the feature',
|
|
237
|
+
type: 'feature',
|
|
238
|
+
priority: 'critical',
|
|
239
|
+
estimatedTokens: 3000,
|
|
240
|
+
dependencies: ['foundation-types'],
|
|
241
|
+
acceptanceCriteria: [
|
|
242
|
+
'Migration runs without errors',
|
|
243
|
+
'Rollback tested',
|
|
244
|
+
'Indexes added for query patterns'
|
|
245
|
+
],
|
|
246
|
+
suggestedAgent: 'fullstack-developer',
|
|
247
|
+
testStrategy: { type: 'migration-test', rollback: true }
|
|
248
|
+
}
|
|
249
|
+
];
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
private generateImplementationTasks(analysis: FeatureAnalysis): SprintTask[] {
|
|
253
|
+
// Generate implementation tasks based on feature analysis
|
|
254
|
+
return analysis.components.map(component => ({
|
|
255
|
+
id: `impl-${component.name}`,
|
|
256
|
+
title: `Implement ${component.name}`,
|
|
257
|
+
description: component.description,
|
|
258
|
+
type: 'feature' as TaskType,
|
|
259
|
+
priority: 'high',
|
|
260
|
+
estimatedTokens: component.complexity * 2000,
|
|
261
|
+
dependencies: component.dependencies,
|
|
262
|
+
acceptanceCriteria: component.acceptance,
|
|
263
|
+
suggestedAgent: this.selectAgent(component),
|
|
264
|
+
testStrategy: { type: 'unit', coverage: 80 }
|
|
265
|
+
}));
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// Example: OAuth feature breakdown
|
|
270
|
+
const oauthTasks: SprintTask[] = [
|
|
271
|
+
{
|
|
272
|
+
id: 'oauth-types',
|
|
273
|
+
title: 'Define OAuth type definitions',
|
|
274
|
+
type: 'feature',
|
|
275
|
+
priority: 'critical',
|
|
276
|
+
estimatedTokens: 3000,
|
|
277
|
+
dependencies: [],
|
|
278
|
+
suggestedAgent: 'architect',
|
|
279
|
+
// ... rest of task definition
|
|
280
|
+
},
|
|
281
|
+
{
|
|
282
|
+
id: 'oauth-google',
|
|
283
|
+
title: 'Implement Google OAuth provider',
|
|
284
|
+
type: 'feature',
|
|
285
|
+
priority: 'high',
|
|
286
|
+
estimatedTokens: 8000,
|
|
287
|
+
dependencies: ['oauth-types'],
|
|
288
|
+
suggestedAgent: 'fullstack-developer',
|
|
289
|
+
// ... rest of task definition
|
|
290
|
+
},
|
|
291
|
+
// Additional parallel tasks...
|
|
292
|
+
];
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
### 4. Agent Routing System
|
|
296
|
+
|
|
297
|
+
```typescript
|
|
298
|
+
/**
|
|
299
|
+
* Route tasks to optimal agents based on capabilities
|
|
300
|
+
* Enables parallel execution and specialization
|
|
301
|
+
*/
|
|
302
|
+
|
|
303
|
+
interface AgentProfile {
|
|
304
|
+
type: AgentType;
|
|
305
|
+
capabilities: string[];
|
|
306
|
+
specializations: string[];
|
|
307
|
+
maxConcurrentTasks: number;
|
|
308
|
+
averageTokensPerHour: number;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
type AgentType =
|
|
312
|
+
| 'architect' // System design, interfaces
|
|
313
|
+
| 'fullstack-developer' // Feature implementation
|
|
314
|
+
| 'frontend-developer' // UI/UX implementation
|
|
315
|
+
| 'backend-developer' // API/server implementation
|
|
316
|
+
| 'debugger' // Bug investigation and fixes
|
|
317
|
+
| 'tester' // Test creation and QA
|
|
318
|
+
| 'docs-manager' // Documentation
|
|
319
|
+
| 'oracle' // Research and analysis
|
|
320
|
+
| 'reviewer'; // Code review
|
|
321
|
+
|
|
322
|
+
const agentProfiles: Map<AgentType, AgentProfile> = new Map([
|
|
323
|
+
['architect', {
|
|
324
|
+
type: 'architect',
|
|
325
|
+
capabilities: ['system-design', 'api-design', 'type-definition'],
|
|
326
|
+
specializations: ['distributed-systems', 'performance'],
|
|
327
|
+
maxConcurrentTasks: 2,
|
|
328
|
+
averageTokensPerHour: 15000
|
|
329
|
+
}],
|
|
330
|
+
['fullstack-developer', {
|
|
331
|
+
type: 'fullstack-developer',
|
|
332
|
+
capabilities: ['feature-implementation', 'integration', 'crud'],
|
|
333
|
+
specializations: ['react', 'node', 'database'],
|
|
334
|
+
maxConcurrentTasks: 3,
|
|
335
|
+
averageTokensPerHour: 20000
|
|
336
|
+
}],
|
|
337
|
+
['debugger', {
|
|
338
|
+
type: 'debugger',
|
|
339
|
+
capabilities: ['bug-investigation', 'root-cause-analysis', 'hotfix'],
|
|
340
|
+
specializations: ['performance', 'memory', 'race-conditions'],
|
|
341
|
+
maxConcurrentTasks: 2,
|
|
342
|
+
averageTokensPerHour: 12000
|
|
343
|
+
}],
|
|
344
|
+
['tester', {
|
|
345
|
+
type: 'tester',
|
|
346
|
+
capabilities: ['unit-tests', 'integration-tests', 'e2e-tests'],
|
|
347
|
+
specializations: ['test-strategy', 'mocking', 'coverage'],
|
|
348
|
+
maxConcurrentTasks: 4,
|
|
349
|
+
averageTokensPerHour: 18000
|
|
350
|
+
}]
|
|
351
|
+
]);
|
|
352
|
+
|
|
353
|
+
class AgentRouter {
|
|
354
|
+
private taskQueue: PriorityQueue<SprintTask>;
|
|
355
|
+
private agentPool: Map<AgentType, Agent[]>;
|
|
356
|
+
|
|
357
|
+
async routeTask(task: SprintTask): Promise<Agent> {
|
|
358
|
+
// 1. Find capable agents
|
|
359
|
+
const capableAgents = this.findCapableAgents(task);
|
|
360
|
+
|
|
361
|
+
// 2. Score agents by fit
|
|
362
|
+
const scoredAgents = capableAgents.map(agent => ({
|
|
363
|
+
agent,
|
|
364
|
+
score: this.calculateFitScore(agent, task)
|
|
365
|
+
}));
|
|
366
|
+
|
|
367
|
+
// 3. Select best available agent
|
|
368
|
+
const best = scoredAgents
|
|
369
|
+
.filter(a => a.agent.isAvailable())
|
|
370
|
+
.sort((a, b) => b.score - a.score)[0];
|
|
371
|
+
|
|
372
|
+
if (!best) {
|
|
373
|
+
// Queue for next available
|
|
374
|
+
await this.queueForAgent(task, scoredAgents[0].agent.type);
|
|
375
|
+
return this.waitForAgent(task);
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
return best.agent;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
private calculateFitScore(agent: Agent, task: SprintTask): number {
|
|
382
|
+
let score = 0;
|
|
383
|
+
|
|
384
|
+
// Base capability match
|
|
385
|
+
const profile = agentProfiles.get(agent.type)!;
|
|
386
|
+
const capabilityMatch = this.matchCapabilities(profile, task);
|
|
387
|
+
score += capabilityMatch * 40;
|
|
388
|
+
|
|
389
|
+
// Specialization bonus
|
|
390
|
+
const specializationMatch = this.matchSpecializations(profile, task);
|
|
391
|
+
score += specializationMatch * 30;
|
|
392
|
+
|
|
393
|
+
// Current load factor
|
|
394
|
+
const loadFactor = 1 - (agent.currentTasks / profile.maxConcurrentTasks);
|
|
395
|
+
score += loadFactor * 20;
|
|
396
|
+
|
|
397
|
+
// Context continuity bonus (same feature = less context switching)
|
|
398
|
+
if (agent.hasContextFor(task.relatedFeature)) {
|
|
399
|
+
score += 10;
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
return score;
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
// Routing configuration by task type
|
|
407
|
+
const routingRules: Record<TaskType, AgentType[]> = {
|
|
408
|
+
feature: ['fullstack-developer', 'frontend-developer', 'backend-developer'],
|
|
409
|
+
bugfix: ['debugger', 'fullstack-developer'],
|
|
410
|
+
refactor: ['architect', 'fullstack-developer'],
|
|
411
|
+
test: ['tester'],
|
|
412
|
+
docs: ['docs-manager'],
|
|
413
|
+
research: ['oracle', 'architect'],
|
|
414
|
+
config: ['fullstack-developer', 'backend-developer']
|
|
415
|
+
};
|
|
416
|
+
```
|
|
417
|
+
|
|
418
|
+
### 5. Autonomy Levels & Checkpoints
|
|
419
|
+
|
|
420
|
+
```typescript
|
|
421
|
+
/**
|
|
422
|
+
* Define autonomy levels for sprint execution
|
|
423
|
+
* Balance speed with human oversight
|
|
424
|
+
*/
|
|
425
|
+
|
|
426
|
+
type AutonomyLevel = 'full-auto' | 'semi-auto' | 'supervised' | 'manual';
|
|
427
|
+
|
|
428
|
+
interface AutonomyConfig {
|
|
429
|
+
level: AutonomyLevel;
|
|
430
|
+
checkpoints: Checkpoint[];
|
|
431
|
+
escalationRules: EscalationRule[];
|
|
432
|
+
approvalRequired: ApprovalTrigger[];
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
interface Checkpoint {
|
|
436
|
+
trigger: CheckpointTrigger;
|
|
437
|
+
action: 'pause' | 'notify' | 'review';
|
|
438
|
+
timeout?: number; // Auto-continue after timeout
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
type CheckpointTrigger =
|
|
442
|
+
| 'task-complete'
|
|
443
|
+
| 'phase-complete'
|
|
444
|
+
| 'error-threshold'
|
|
445
|
+
| 'token-threshold'
|
|
446
|
+
| 'time-threshold'
|
|
447
|
+
| 'security-concern'
|
|
448
|
+
| 'breaking-change';
|
|
449
|
+
|
|
450
|
+
const autonomyConfigs: Record<AutonomyLevel, AutonomyConfig> = {
|
|
451
|
+
'full-auto': {
|
|
452
|
+
level: 'full-auto',
|
|
453
|
+
checkpoints: [
|
|
454
|
+
{ trigger: 'phase-complete', action: 'notify' },
|
|
455
|
+
{ trigger: 'error-threshold', action: 'pause' }
|
|
456
|
+
],
|
|
457
|
+
escalationRules: [
|
|
458
|
+
{ condition: 'security-vulnerability', action: 'pause-and-alert' }
|
|
459
|
+
],
|
|
460
|
+
approvalRequired: ['production-deploy', 'breaking-api-change']
|
|
461
|
+
},
|
|
462
|
+
|
|
463
|
+
'semi-auto': {
|
|
464
|
+
level: 'semi-auto',
|
|
465
|
+
checkpoints: [
|
|
466
|
+
{ trigger: 'task-complete', action: 'notify' },
|
|
467
|
+
{ trigger: 'phase-complete', action: 'review', timeout: 3600 }
|
|
468
|
+
],
|
|
469
|
+
escalationRules: [
|
|
470
|
+
{ condition: 'test-failure', action: 'pause' },
|
|
471
|
+
{ condition: 'coverage-drop', action: 'notify' }
|
|
472
|
+
],
|
|
473
|
+
approvalRequired: ['merge-to-main', 'production-deploy']
|
|
474
|
+
},
|
|
475
|
+
|
|
476
|
+
'supervised': {
|
|
477
|
+
level: 'supervised',
|
|
478
|
+
checkpoints: [
|
|
479
|
+
{ trigger: 'task-complete', action: 'review' }
|
|
480
|
+
],
|
|
481
|
+
escalationRules: [
|
|
482
|
+
{ condition: 'any-error', action: 'pause' }
|
|
483
|
+
],
|
|
484
|
+
approvalRequired: ['all-merges', 'all-deploys']
|
|
485
|
+
},
|
|
486
|
+
|
|
487
|
+
'manual': {
|
|
488
|
+
level: 'manual',
|
|
489
|
+
checkpoints: [
|
|
490
|
+
{ trigger: 'task-complete', action: 'pause' }
|
|
491
|
+
],
|
|
492
|
+
escalationRules: [],
|
|
493
|
+
approvalRequired: ['every-action']
|
|
494
|
+
}
|
|
495
|
+
};
|
|
496
|
+
|
|
497
|
+
// Sprint execution with autonomy control
|
|
498
|
+
class SprintExecutor {
|
|
499
|
+
private autonomy: AutonomyConfig;
|
|
500
|
+
private agents: AgentRouter;
|
|
501
|
+
|
|
502
|
+
async executeSprint(
|
|
503
|
+
tasks: SprintTask[],
|
|
504
|
+
autonomyLevel: AutonomyLevel
|
|
505
|
+
): Promise<SprintResult> {
|
|
506
|
+
this.autonomy = autonomyConfigs[autonomyLevel];
|
|
507
|
+
|
|
508
|
+
// Sort tasks by dependency graph
|
|
509
|
+
const orderedTasks = this.topologicalSort(tasks);
|
|
510
|
+
|
|
511
|
+
// Group into parallelizable batches
|
|
512
|
+
const batches = this.createParallelBatches(orderedTasks);
|
|
513
|
+
|
|
514
|
+
const results: TaskResult[] = [];
|
|
515
|
+
|
|
516
|
+
for (const batch of batches) {
|
|
517
|
+
// Execute batch in parallel
|
|
518
|
+
const batchResults = await Promise.all(
|
|
519
|
+
batch.map(task => this.executeTask(task))
|
|
520
|
+
);
|
|
521
|
+
|
|
522
|
+
results.push(...batchResults);
|
|
523
|
+
|
|
524
|
+
// Check for phase checkpoint
|
|
525
|
+
if (this.isPhaseComplete(batch)) {
|
|
526
|
+
await this.handleCheckpoint('phase-complete', batchResults);
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
return this.compileSprintResult(results);
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
private async handleCheckpoint(
|
|
534
|
+
trigger: CheckpointTrigger,
|
|
535
|
+
context: unknown
|
|
536
|
+
): Promise<void> {
|
|
537
|
+
const checkpoint = this.autonomy.checkpoints.find(
|
|
538
|
+
cp => cp.trigger === trigger
|
|
539
|
+
);
|
|
540
|
+
|
|
541
|
+
if (!checkpoint) return;
|
|
542
|
+
|
|
543
|
+
switch (checkpoint.action) {
|
|
544
|
+
case 'pause':
|
|
545
|
+
await this.pauseAndWaitForApproval(trigger, context);
|
|
546
|
+
break;
|
|
547
|
+
case 'review':
|
|
548
|
+
const approved = await this.requestReview(trigger, context);
|
|
549
|
+
if (!approved && !checkpoint.timeout) {
|
|
550
|
+
await this.pauseAndWaitForApproval(trigger, context);
|
|
551
|
+
}
|
|
552
|
+
break;
|
|
553
|
+
case 'notify':
|
|
554
|
+
await this.sendNotification(trigger, context);
|
|
555
|
+
break;
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
}
|
|
13
559
|
```
|
|
14
560
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
561
|
+
### 6. Sprint Metrics & Analytics
|
|
562
|
+
|
|
563
|
+
```typescript
|
|
564
|
+
/**
|
|
565
|
+
* Track sprint performance for continuous improvement
|
|
566
|
+
*/
|
|
567
|
+
|
|
568
|
+
interface SprintMetrics {
|
|
569
|
+
// Velocity
|
|
570
|
+
tasksCompleted: number;
|
|
571
|
+
tasksPlanned: number;
|
|
572
|
+
velocityRatio: number;
|
|
573
|
+
|
|
574
|
+
// Quality
|
|
575
|
+
bugsIntroduced: number;
|
|
576
|
+
testCoverage: number;
|
|
577
|
+
codeQualityScore: number;
|
|
578
|
+
|
|
579
|
+
// Efficiency
|
|
580
|
+
totalTokensUsed: number;
|
|
581
|
+
tokensPerTask: number;
|
|
582
|
+
parallelizationRatio: number;
|
|
583
|
+
|
|
584
|
+
// Time
|
|
585
|
+
cycleTime: Duration;
|
|
586
|
+
leadTime: Duration;
|
|
587
|
+
blockedTime: Duration;
|
|
588
|
+
|
|
589
|
+
// Agent performance
|
|
590
|
+
agentUtilization: Map<AgentType, number>;
|
|
591
|
+
agentEfficiency: Map<AgentType, number>;
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
class SprintAnalytics {
|
|
595
|
+
async generateSprintReport(sprintId: string): Promise<SprintReport> {
|
|
596
|
+
const sprint = await this.getSprint(sprintId);
|
|
597
|
+
const tasks = await this.getSprintTasks(sprintId);
|
|
598
|
+
const metrics = await this.calculateMetrics(sprint, tasks);
|
|
599
|
+
|
|
600
|
+
return {
|
|
601
|
+
summary: this.generateSummary(metrics),
|
|
602
|
+
metrics,
|
|
603
|
+
insights: this.generateInsights(metrics, sprint),
|
|
604
|
+
recommendations: this.generateRecommendations(metrics)
|
|
605
|
+
};
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
private generateInsights(
|
|
609
|
+
metrics: SprintMetrics,
|
|
610
|
+
sprint: Sprint
|
|
611
|
+
): SprintInsight[] {
|
|
612
|
+
const insights: SprintInsight[] = [];
|
|
613
|
+
|
|
614
|
+
// Velocity insights
|
|
615
|
+
if (metrics.velocityRatio < 0.8) {
|
|
616
|
+
insights.push({
|
|
617
|
+
type: 'velocity',
|
|
618
|
+
severity: 'warning',
|
|
619
|
+
message: 'Sprint velocity below target',
|
|
620
|
+
analysis: this.analyzeVelocityDrop(metrics, sprint),
|
|
621
|
+
suggestion: 'Consider smaller task breakdown or capacity adjustment'
|
|
622
|
+
});
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
// Quality insights
|
|
626
|
+
if (metrics.bugsIntroduced > sprint.previousBugs) {
|
|
627
|
+
insights.push({
|
|
628
|
+
type: 'quality',
|
|
629
|
+
severity: 'warning',
|
|
630
|
+
message: 'Bug introduction rate increased',
|
|
631
|
+
analysis: this.analyzeBugPatterns(sprint),
|
|
632
|
+
suggestion: 'Review test coverage in affected areas'
|
|
633
|
+
});
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
// Efficiency insights
|
|
637
|
+
if (metrics.parallelizationRatio < 0.6) {
|
|
638
|
+
insights.push({
|
|
639
|
+
type: 'efficiency',
|
|
640
|
+
severity: 'info',
|
|
641
|
+
message: 'Low parallelization achieved',
|
|
642
|
+
analysis: 'Many tasks have sequential dependencies',
|
|
643
|
+
suggestion: 'Break down tasks further to enable parallel execution'
|
|
644
|
+
});
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
return insights;
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
private generateRecommendations(
|
|
651
|
+
metrics: SprintMetrics
|
|
652
|
+
): SprintRecommendation[] {
|
|
653
|
+
return [
|
|
654
|
+
// Task sizing recommendations
|
|
655
|
+
...this.taskSizingRecommendations(metrics),
|
|
656
|
+
// Agent allocation recommendations
|
|
657
|
+
...this.agentAllocationRecommendations(metrics),
|
|
658
|
+
// Process improvement recommendations
|
|
659
|
+
...this.processRecommendations(metrics)
|
|
660
|
+
];
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
// Real-time sprint dashboard
|
|
665
|
+
interface SprintDashboard {
|
|
666
|
+
currentPhase: SprintPhase;
|
|
667
|
+
progress: ProgressMetrics;
|
|
668
|
+
activeAgents: ActiveAgent[];
|
|
669
|
+
blockers: Blocker[];
|
|
670
|
+
timeline: TimelineEvent[];
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
const dashboardTemplate = `
|
|
674
|
+
┌─────────────────────────────────────────────────────────────────────────┐
|
|
675
|
+
│ SPRINT DASHBOARD: ${sprintName} │
|
|
676
|
+
├─────────────────────────────────────────────────────────────────────────┤
|
|
677
|
+
│ │
|
|
678
|
+
│ PROGRESS QUALITY AGENTS │
|
|
679
|
+
│ ═════════ ═══════ ══════ │
|
|
680
|
+
│ ████████░░ 80% Coverage: 87% 🟢 arch: idle │
|
|
681
|
+
│ 24/30 tasks Bugs: 2 🔵 dev-1: working │
|
|
682
|
+
│ Security: ✓ 🔵 dev-2: working │
|
|
683
|
+
│ CURRENT PHASE: Execute Perf: ✓ 🟡 tester: queued │
|
|
684
|
+
│ │
|
|
685
|
+
│ TIMELINE │
|
|
686
|
+
│ ════════ │
|
|
687
|
+
│ 09:00 ───●─── Sprint started │
|
|
688
|
+
│ 09:15 ───●─── Foundation phase complete │
|
|
689
|
+
│ 11:30 ───●─── Implementation 60% │
|
|
690
|
+
│ 12:00 ───○─── NOW │
|
|
691
|
+
│ 14:00 ───○─── Integration phase (est.) │
|
|
692
|
+
│ 16:00 ───○─── Sprint end (target) │
|
|
693
|
+
│ │
|
|
694
|
+
└─────────────────────────────────────────────────────────────────────────┘
|
|
695
|
+
`;
|
|
22
696
|
```
|
|
23
697
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
2. Select tasks for sprint
|
|
27
|
-
3. Estimate (optional)
|
|
28
|
-
4. Assign to agents
|
|
29
|
-
|
|
30
|
-
## AI Team Execution
|
|
31
|
-
|
|
32
|
-
### Autonomy Levels
|
|
33
|
-
- **Full-Auto**: No human intervention
|
|
34
|
-
- **Semi-Auto**: Review at checkpoints
|
|
35
|
-
- **Manual**: Approve each step
|
|
36
|
-
|
|
37
|
-
### Agent Routing
|
|
38
|
-
| Task Type | Agent |
|
|
39
|
-
|-----------|-------|
|
|
40
|
-
| feature | fullstack-developer |
|
|
41
|
-
| bugfix | debugger |
|
|
42
|
-
| research | oracle |
|
|
43
|
-
| docs | docs-manager |
|
|
44
|
-
| test | tester |
|
|
45
|
-
|
|
46
|
-
## Retrospective
|
|
698
|
+
### 7. Retrospective Framework
|
|
699
|
+
|
|
47
700
|
```markdown
|
|
48
|
-
##
|
|
49
|
-
|
|
701
|
+
## Omega Sprint Retrospective
|
|
702
|
+
|
|
703
|
+
### Sprint Summary
|
|
704
|
+
- Sprint: [Name/Number]
|
|
705
|
+
- Duration: [Start] - [End]
|
|
706
|
+
- Velocity: [X/Y tasks, Z%]
|
|
707
|
+
- Quality: [Coverage %, Bugs introduced]
|
|
708
|
+
|
|
709
|
+
### What Went Well (WWW)
|
|
710
|
+
Document successes to replicate:
|
|
711
|
+
|
|
712
|
+
1. **[Success Title]**
|
|
713
|
+
- What happened: [Description]
|
|
714
|
+
- Why it worked: [Analysis]
|
|
715
|
+
- How to replicate: [Action]
|
|
50
716
|
|
|
51
|
-
|
|
52
|
-
|
|
717
|
+
### What Could Improve (WCI)
|
|
718
|
+
Document challenges to address:
|
|
719
|
+
|
|
720
|
+
1. **[Challenge Title]**
|
|
721
|
+
- What happened: [Description]
|
|
722
|
+
- Root cause: [Analysis]
|
|
723
|
+
- Proposed solution: [Action]
|
|
724
|
+
|
|
725
|
+
### Agent Performance Review
|
|
726
|
+
|
|
727
|
+
| Agent | Tasks | Tokens | Efficiency | Notes |
|
|
728
|
+
|-------|-------|--------|------------|-------|
|
|
729
|
+
| architect | 5 | 45K | 95% | Excellent type definitions |
|
|
730
|
+
| fullstack-1 | 12 | 180K | 87% | Context switches costly |
|
|
731
|
+
| tester | 8 | 72K | 92% | Good coverage strategy |
|
|
732
|
+
|
|
733
|
+
### Action Items for Next Sprint
|
|
734
|
+
|
|
735
|
+
| Action | Owner | Priority | Due |
|
|
736
|
+
|--------|-------|----------|-----|
|
|
737
|
+
| [Action 1] | [Who] | High | Sprint+1 |
|
|
738
|
+
| [Action 2] | [Who] | Medium | Sprint+1 |
|
|
739
|
+
|
|
740
|
+
### Sprint-over-Sprint Trends
|
|
53
741
|
|
|
54
|
-
|
|
55
|
-
|
|
742
|
+
```
|
|
743
|
+
Velocity: ▅▆▇█▇ (trending up)
|
|
744
|
+
Quality: ▇▇▇▇█ (stable high)
|
|
745
|
+
Efficiency:▄▅▆▇█ (improving)
|
|
56
746
|
```
|
|
57
747
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
/team:run --mode semi-auto
|
|
63
|
-
/sprint:end
|
|
748
|
+
### Key Learnings
|
|
749
|
+
1. [Learning that applies to future sprints]
|
|
750
|
+
2. [Pattern to encode in agent prompts]
|
|
751
|
+
3. [Process improvement to implement]
|
|
64
752
|
```
|
|
753
|
+
|
|
754
|
+
## Use Cases
|
|
755
|
+
|
|
756
|
+
### Feature Development Sprint
|
|
757
|
+
|
|
758
|
+
```typescript
|
|
759
|
+
/**
|
|
760
|
+
* Complete sprint for building a new feature
|
|
761
|
+
*/
|
|
762
|
+
|
|
763
|
+
async function runFeatureSprint(feature: FeatureRequest): Promise<void> {
|
|
764
|
+
const sprintManager = new SprintManager();
|
|
765
|
+
|
|
766
|
+
// Phase 1: Vision
|
|
767
|
+
const vision = await sprintManager.defineVision({
|
|
768
|
+
objective: feature.description,
|
|
769
|
+
successCriteria: feature.acceptance,
|
|
770
|
+
scope: await sprintManager.analyzeScope(feature)
|
|
771
|
+
});
|
|
772
|
+
|
|
773
|
+
// Phase 2: Plan
|
|
774
|
+
const tasks = await sprintManager.breakdownTasks(vision);
|
|
775
|
+
await sprintManager.validateDependencies(tasks);
|
|
776
|
+
await sprintManager.estimateCapacity(tasks);
|
|
777
|
+
|
|
778
|
+
// Phase 3: Execute
|
|
779
|
+
const result = await sprintManager.executeSprint(tasks, {
|
|
780
|
+
autonomyLevel: 'semi-auto',
|
|
781
|
+
qualityGates: [
|
|
782
|
+
{ type: 'test-coverage', threshold: 80 },
|
|
783
|
+
{ type: 'no-critical-bugs' },
|
|
784
|
+
{ type: 'performance-regression', threshold: '10%' }
|
|
785
|
+
]
|
|
786
|
+
});
|
|
787
|
+
|
|
788
|
+
// Phase 4: Deliver
|
|
789
|
+
if (result.allGatesPassed) {
|
|
790
|
+
await sprintManager.deployToStaging();
|
|
791
|
+
await sprintManager.runSmokeTests();
|
|
792
|
+
await sprintManager.deployToProduction();
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
// Phase 5: Retrospect
|
|
796
|
+
const retro = await sprintManager.generateRetrospective(result);
|
|
797
|
+
await sprintManager.applyLearnings(retro);
|
|
798
|
+
}
|
|
799
|
+
```
|
|
800
|
+
|
|
801
|
+
### Bug Fix Sprint
|
|
802
|
+
|
|
803
|
+
```typescript
|
|
804
|
+
/**
|
|
805
|
+
* Rapid bug fix sprint with debugging focus
|
|
806
|
+
*/
|
|
807
|
+
|
|
808
|
+
async function runBugFixSprint(bugs: Bug[]): Promise<void> {
|
|
809
|
+
const sprint = new SprintManager();
|
|
810
|
+
|
|
811
|
+
// Prioritize by severity
|
|
812
|
+
const prioritized = bugs.sort((a, b) =>
|
|
813
|
+
severityScore(b.severity) - severityScore(a.severity)
|
|
814
|
+
);
|
|
815
|
+
|
|
816
|
+
// Route to debugger agents
|
|
817
|
+
const tasks = prioritized.map(bug => ({
|
|
818
|
+
id: `fix-${bug.id}`,
|
|
819
|
+
title: `Fix: ${bug.title}`,
|
|
820
|
+
type: 'bugfix' as TaskType,
|
|
821
|
+
priority: mapSeverityToPriority(bug.severity),
|
|
822
|
+
suggestedAgent: 'debugger' as AgentType,
|
|
823
|
+
acceptanceCriteria: [
|
|
824
|
+
'Bug no longer reproducible',
|
|
825
|
+
'Regression test added',
|
|
826
|
+
'No new bugs introduced'
|
|
827
|
+
]
|
|
828
|
+
}));
|
|
829
|
+
|
|
830
|
+
// Execute with higher oversight for critical bugs
|
|
831
|
+
await sprint.executeSprint(tasks, {
|
|
832
|
+
autonomyLevel: hasCriticalBugs(bugs) ? 'supervised' : 'semi-auto'
|
|
833
|
+
});
|
|
834
|
+
}
|
|
835
|
+
```
|
|
836
|
+
|
|
837
|
+
## Best Practices
|
|
838
|
+
|
|
839
|
+
### Do's
|
|
840
|
+
|
|
841
|
+
- **Define clear success criteria** before starting the sprint
|
|
842
|
+
- **Break tasks small enough** for single-agent execution
|
|
843
|
+
- **Enable maximum parallelization** through loose coupling
|
|
844
|
+
- **Set appropriate autonomy levels** based on risk
|
|
845
|
+
- **Track metrics consistently** for improvement
|
|
846
|
+
- **Run retrospectives** after every sprint
|
|
847
|
+
- **Encode learnings** into agent prompts
|
|
848
|
+
- **Use quality gates** to prevent regressions
|
|
849
|
+
- **Maintain sprint rhythm** for predictability
|
|
850
|
+
- **Celebrate wins** to build momentum
|
|
851
|
+
|
|
852
|
+
### Don'ts
|
|
853
|
+
|
|
854
|
+
- Don't start without clear vision and scope
|
|
855
|
+
- Don't create tasks with circular dependencies
|
|
856
|
+
- Don't skip quality gates under time pressure
|
|
857
|
+
- Don't ignore retrospective insights
|
|
858
|
+
- Don't over-commit capacity
|
|
859
|
+
- Don't context-switch agents unnecessarily
|
|
860
|
+
- Don't deploy without automated tests
|
|
861
|
+
- Don't skip the retrospective phase
|
|
862
|
+
- Don't let blockers sit unaddressed
|
|
863
|
+
- Don't forget to update documentation
|
|
864
|
+
|
|
865
|
+
## References
|
|
866
|
+
|
|
867
|
+
- [Agile Manifesto](https://agilemanifesto.org/)
|
|
868
|
+
- [Scrum Guide](https://scrumguides.org/)
|
|
869
|
+
- [Shape Up](https://basecamp.com/shapeup)
|
|
870
|
+
- [Accelerate (DORA Metrics)](https://itrevolution.com/book/accelerate/)
|
|
871
|
+
- [Team Topologies](https://teamtopologies.com/)
|