@kodrunhq/opencode-autopilot 1.10.0 → 1.11.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/assets/commands/oc-review-agents.md +103 -0
- package/assets/skills/coding-standards/SKILL.md +313 -0
- package/assets/skills/csharp-patterns/SKILL.md +327 -0
- package/assets/skills/frontend-design/SKILL.md +433 -0
- package/assets/skills/java-patterns/SKILL.md +258 -0
- package/assets/templates/cli-tool.md +49 -0
- package/assets/templates/fullstack.md +71 -0
- package/assets/templates/library.md +49 -0
- package/assets/templates/web-api.md +60 -0
- package/package.json +1 -1
- package/src/agents/debugger.ts +329 -0
- package/src/agents/index.ts +12 -3
- package/src/agents/planner.ts +563 -0
- package/src/agents/reviewer.ts +270 -0
- package/src/installer.ts +11 -3
- package/src/registry/model-groups.ts +4 -1
- package/src/review/stack-gate.ts +2 -0
- package/src/skills/adaptive-injector.ts +47 -2
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Review and improve your project's agents.md file with structure validation and prompt quality feedback
|
|
3
|
+
argument-hint: "[path-to-agents.md]"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Review and score the project's agents.md file. Follow every step below in order.
|
|
7
|
+
|
|
8
|
+
## Step 1: Locate the agents.md file
|
|
9
|
+
|
|
10
|
+
- If `$ARGUMENTS` is provided and non-empty, use that path
|
|
11
|
+
- Otherwise, check `.opencode/agents.md` in the project root
|
|
12
|
+
- Then check `agents.md` in the project root
|
|
13
|
+
- If not found, tell the user no agents.md was found and suggest:
|
|
14
|
+
1. Create one manually
|
|
15
|
+
2. Copy a starter template from `~/.config/opencode/templates/` (available types: web-api, cli-tool, library, fullstack)
|
|
16
|
+
- Show the copy command: `cp ~/.config/opencode/templates/<type>.md .opencode/agents.md`
|
|
17
|
+
- Stop here — do not continue with the review
|
|
18
|
+
|
|
19
|
+
## Step 2: Read and parse the file
|
|
20
|
+
|
|
21
|
+
Read the located file and parse each agent block:
|
|
22
|
+
|
|
23
|
+
- Look for level-2 headings (`## Agent:` or `## <name>`) as agent delimiters
|
|
24
|
+
- For each agent, extract:
|
|
25
|
+
- **Name** — the heading text
|
|
26
|
+
- **Description** — any text immediately following the heading
|
|
27
|
+
- **System prompt** — the main instruction body for the agent
|
|
28
|
+
- **Tool permissions** — any allow/deny lists for tools
|
|
29
|
+
- **Model assignment** — any model field if present
|
|
30
|
+
|
|
31
|
+
## Step 3: Validate structure (0-3 per agent)
|
|
32
|
+
|
|
33
|
+
Score each agent's structure:
|
|
34
|
+
|
|
35
|
+
| Points | Criterion |
|
|
36
|
+
|--------|-----------|
|
|
37
|
+
| +1 | Has a clear name and description |
|
|
38
|
+
| +1 | Has a system prompt with specific (not generic) instructions |
|
|
39
|
+
| +1 | Has explicit tool permissions (allow or deny lists) |
|
|
40
|
+
|
|
41
|
+
Deductions:
|
|
42
|
+
- -1 for missing description entirely
|
|
43
|
+
- -1 for empty or placeholder system prompt
|
|
44
|
+
- -1 for no tool configuration at all
|
|
45
|
+
|
|
46
|
+
Minimum score is 0.
|
|
47
|
+
|
|
48
|
+
## Step 4: Assess prompt quality (0-4 per agent)
|
|
49
|
+
|
|
50
|
+
Score each agent's prompt quality:
|
|
51
|
+
|
|
52
|
+
| Points | Criterion |
|
|
53
|
+
|--------|-----------|
|
|
54
|
+
| +1 | **Role clarity** — prompt defines WHO the agent is (role, expertise, personality) |
|
|
55
|
+
| +1 | **Task specificity** — prompt defines WHAT the agent does with concrete instructions, not vague directives |
|
|
56
|
+
| +1 | **Guardrails** — prompt defines what NOT to do, boundaries, or constraints |
|
|
57
|
+
| +1 | **Output format** — prompt specifies HOW to format responses (structure, sections, style) |
|
|
58
|
+
|
|
59
|
+
## Step 5: Check coverage for project type
|
|
60
|
+
|
|
61
|
+
- Read project manifest files to detect type:
|
|
62
|
+
- `package.json` — check for framework indicators (express, fastify, next, react, vue, svelte)
|
|
63
|
+
- `pom.xml`, `build.gradle` — Java project
|
|
64
|
+
- `Cargo.toml` — Rust project
|
|
65
|
+
- `go.mod` — Go project
|
|
66
|
+
- `pyproject.toml`, `setup.py` — Python project
|
|
67
|
+
- Classify as: web-api, cli-tool, library, fullstack, or unknown
|
|
68
|
+
- Compare the agents found against recommended agents for that project type
|
|
69
|
+
- Note missing agent roles that would benefit the project
|
|
70
|
+
- Reference starter templates in `~/.config/opencode/templates/` for comparison
|
|
71
|
+
|
|
72
|
+
## Step 6: Output the review
|
|
73
|
+
|
|
74
|
+
Format your review exactly like this:
|
|
75
|
+
|
|
76
|
+
```
|
|
77
|
+
## agents.md Review
|
|
78
|
+
|
|
79
|
+
**File:** {path}
|
|
80
|
+
**Agents found:** {count}
|
|
81
|
+
**Overall Score:** {total}/{max} ({percentage}%)
|
|
82
|
+
|
|
83
|
+
### Per-Agent Assessment
|
|
84
|
+
|
|
85
|
+
#### {agent-name}
|
|
86
|
+
- Structure: {score}/3 — {brief notes}
|
|
87
|
+
- Prompt Quality: {score}/4 — {brief notes}
|
|
88
|
+
- Suggestions:
|
|
89
|
+
- {specific actionable improvement}
|
|
90
|
+
|
|
91
|
+
### Coverage Analysis
|
|
92
|
+
- Project type detected: {type}
|
|
93
|
+
- Recommended agents for this type: {list}
|
|
94
|
+
- Missing: {list with brief explanation of why each would help}
|
|
95
|
+
- Starter template: {if type is web-api, cli-tool, library, or fullstack: `Run cat ~/.config/opencode/templates/{type}.md to see a reference`; otherwise: `No starter template available for this project type`}
|
|
96
|
+
|
|
97
|
+
### Top 3 Improvements
|
|
98
|
+
1. {Most impactful improvement with specific guidance}
|
|
99
|
+
2. {Second most impactful improvement}
|
|
100
|
+
3. {Third most impactful improvement}
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
The overall score is the sum of all per-agent structure + prompt quality scores. The max is `agent_count * 7`. Report the percentage rounded to the nearest whole number.
|
|
@@ -325,3 +325,316 @@ MAX_REQUESTS_PER_MINUTE = 80
|
|
|
325
325
|
// Set the max requests to 80
|
|
326
326
|
MAX_REQUESTS_PER_MINUTE = 80
|
|
327
327
|
```
|
|
328
|
+
|
|
329
|
+
## 11. OOP Principles (SOLID)
|
|
330
|
+
|
|
331
|
+
The SOLID principles guide class and module design toward maintainability. Each principle reduces a specific coupling or fragility problem. Apply them when designing components, services, or modules in any object-oriented or module-oriented language.
|
|
332
|
+
|
|
333
|
+
### Single Responsibility Principle (SRP)
|
|
334
|
+
|
|
335
|
+
A class (or module) should have exactly one reason to change. If a change in database schema AND a change in email formatting both require editing the same class, that class has two responsibilities.
|
|
336
|
+
|
|
337
|
+
**DO:** Split distinct responsibilities into distinct units:
|
|
338
|
+
|
|
339
|
+
```
|
|
340
|
+
// Separate concerns
|
|
341
|
+
class UserValidator {
|
|
342
|
+
validate(user) { ... } // validation logic only
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
class UserRepository {
|
|
346
|
+
save(user) { ... } // persistence logic only
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
class WelcomeMailer {
|
|
350
|
+
send(user) { ... } // email logic only
|
|
351
|
+
}
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
**DON'T:** Combine unrelated behaviors in a single class:
|
|
355
|
+
|
|
356
|
+
```
|
|
357
|
+
// God class -- changes for validation, persistence, AND email reasons
|
|
358
|
+
class UserManager {
|
|
359
|
+
validate(user) { ... }
|
|
360
|
+
saveToDatabase(user) { ... }
|
|
361
|
+
sendWelcomeEmail(user) { ... }
|
|
362
|
+
}
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
### Open/Closed Principle (OCP)
|
|
366
|
+
|
|
367
|
+
Modules should be open for extension but closed for modification. When requirements change, you should add new code rather than editing existing, tested code.
|
|
368
|
+
|
|
369
|
+
**DO:** Use polymorphism or strategy pattern to extend behavior:
|
|
370
|
+
|
|
371
|
+
```
|
|
372
|
+
// Adding a new discount type requires adding a new class, not editing existing ones
|
|
373
|
+
interface DiscountStrategy {
|
|
374
|
+
calculate(order): number
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
class SeasonalDiscount implements DiscountStrategy {
|
|
378
|
+
calculate(order) { return order.total * 0.1 }
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
class LoyaltyDiscount implements DiscountStrategy {
|
|
382
|
+
calculate(order) { return order.total * 0.15 }
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
// New discounts: just add a new class
|
|
386
|
+
class BulkDiscount implements DiscountStrategy {
|
|
387
|
+
calculate(order) { return order.total * 0.2 }
|
|
388
|
+
}
|
|
389
|
+
```
|
|
390
|
+
|
|
391
|
+
**DON'T:** Modify existing switch/if chains every time a new variant appears:
|
|
392
|
+
|
|
393
|
+
```
|
|
394
|
+
// Every new discount type requires editing this function
|
|
395
|
+
function calculateDiscount(order, type) {
|
|
396
|
+
if (type === "seasonal") return order.total * 0.1
|
|
397
|
+
if (type === "loyalty") return order.total * 0.15
|
|
398
|
+
if (type === "bulk") return order.total * 0.2 // must edit to add
|
|
399
|
+
}
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
### Liskov Substitution Principle (LSP)
|
|
403
|
+
|
|
404
|
+
Any subtype must be usable wherever its base type is expected, without breaking correctness. If substituting a subclass causes surprising behavior, the hierarchy is wrong.
|
|
405
|
+
|
|
406
|
+
**DO:** Ensure subclass contracts honor parent contracts:
|
|
407
|
+
|
|
408
|
+
```
|
|
409
|
+
class Shape {
|
|
410
|
+
area(): number { ... }
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
class Rectangle extends Shape {
|
|
414
|
+
constructor(width, height) { ... }
|
|
415
|
+
area() { return this.width * this.height }
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
class Circle extends Shape {
|
|
419
|
+
constructor(radius) { ... }
|
|
420
|
+
area() { return Math.PI * this.radius ** 2 }
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
// Any Shape works correctly in calculateTotal
|
|
424
|
+
function calculateTotal(shapes: Shape[]) {
|
|
425
|
+
return shapes.reduce((sum, s) => sum + s.area(), 0)
|
|
426
|
+
}
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
**DON'T:** Create subclasses that violate parent expectations:
|
|
430
|
+
|
|
431
|
+
```
|
|
432
|
+
// Square extends Rectangle but breaks setWidth/setHeight contract
|
|
433
|
+
class Square extends Rectangle {
|
|
434
|
+
setWidth(w) {
|
|
435
|
+
this.width = w
|
|
436
|
+
this.height = w // surprise: setting width also changes height
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
// Code expecting Rectangle behavior gets wrong area calculations
|
|
440
|
+
```
|
|
441
|
+
|
|
442
|
+
### Interface Segregation Principle (ISP)
|
|
443
|
+
|
|
444
|
+
Clients should not be forced to depend on methods they do not use. Many small, focused interfaces are better than one large, general-purpose interface.
|
|
445
|
+
|
|
446
|
+
**DO:** Split interfaces by client needs:
|
|
447
|
+
|
|
448
|
+
```
|
|
449
|
+
interface Readable {
|
|
450
|
+
read(): string
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
interface Writable {
|
|
454
|
+
write(data: string): void
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
interface Closable {
|
|
458
|
+
close(): void
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
// Compose only what each consumer needs
|
|
462
|
+
class FileReader implements Readable, Closable {
|
|
463
|
+
read() { ... }
|
|
464
|
+
close() { ... }
|
|
465
|
+
}
|
|
466
|
+
```
|
|
467
|
+
|
|
468
|
+
**DON'T:** Force implementors to provide methods they don't need:
|
|
469
|
+
|
|
470
|
+
```
|
|
471
|
+
interface IFileHandler {
|
|
472
|
+
read(): string
|
|
473
|
+
write(data: string): void
|
|
474
|
+
delete(): void
|
|
475
|
+
rename(name: string): void
|
|
476
|
+
compress(): void
|
|
477
|
+
encrypt(): void
|
|
478
|
+
// Every implementor must handle all 6 methods
|
|
479
|
+
}
|
|
480
|
+
```
|
|
481
|
+
|
|
482
|
+
### Dependency Inversion Principle (DIP)
|
|
483
|
+
|
|
484
|
+
High-level modules should depend on abstractions, not on low-level implementation details. Business logic should never directly instantiate infrastructure.
|
|
485
|
+
|
|
486
|
+
**DO:** Inject abstractions through constructors:
|
|
487
|
+
|
|
488
|
+
```
|
|
489
|
+
interface UserStore {
|
|
490
|
+
findById(id: string): User
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
class UserService {
|
|
494
|
+
constructor(private store: UserStore) {}
|
|
495
|
+
|
|
496
|
+
getUser(id: string) {
|
|
497
|
+
return this.store.findById(id)
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
// Inject at composition root
|
|
502
|
+
const service = new UserService(new PostgresUserStore(db))
|
|
503
|
+
// For testing:
|
|
504
|
+
const testService = new UserService(new InMemoryUserStore())
|
|
505
|
+
```
|
|
506
|
+
|
|
507
|
+
**DON'T:** Hard-code dependencies inside business logic:
|
|
508
|
+
|
|
509
|
+
```
|
|
510
|
+
class UserService {
|
|
511
|
+
getUser(id: string) {
|
|
512
|
+
// Tightly coupled to PostgreSQL -- cannot test without a database
|
|
513
|
+
const db = new PostgresDatabase("connection-string")
|
|
514
|
+
return db.query("SELECT * FROM users WHERE id = ?", [id])
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
```
|
|
518
|
+
|
|
519
|
+
## 12. Composition and Architecture
|
|
520
|
+
|
|
521
|
+
Patterns for structuring systems at the module and application level. These complement SOLID by addressing how components connect and how dependencies flow.
|
|
522
|
+
|
|
523
|
+
### Composition over Inheritance
|
|
524
|
+
|
|
525
|
+
Prefer composing behaviors via delegation and interfaces over deep inheritance hierarchies. Inheritance creates tight coupling -- a change to the parent ripples through all children.
|
|
526
|
+
|
|
527
|
+
**DO:** Compose behaviors via delegation:
|
|
528
|
+
|
|
529
|
+
```
|
|
530
|
+
class EmailNotifier {
|
|
531
|
+
notify(user, message) { ... }
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
class SlackNotifier {
|
|
535
|
+
notify(user, message) { ... }
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
class OrderService {
|
|
539
|
+
constructor(private notifiers: Notifier[]) {}
|
|
540
|
+
|
|
541
|
+
placeOrder(order) {
|
|
542
|
+
// ... business logic
|
|
543
|
+
for (const n of this.notifiers) {
|
|
544
|
+
n.notify(order.user, "Order placed")
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
```
|
|
549
|
+
|
|
550
|
+
**DON'T:** Build deep inheritance chains:
|
|
551
|
+
|
|
552
|
+
```
|
|
553
|
+
// Fragile hierarchy -- 3+ levels of inheritance
|
|
554
|
+
class Animal { ... }
|
|
555
|
+
class Mammal extends Animal { ... }
|
|
556
|
+
class Dog extends Mammal { ... }
|
|
557
|
+
class GuideDog extends Dog { ... }
|
|
558
|
+
// Change to Animal breaks everything down the chain
|
|
559
|
+
```
|
|
560
|
+
|
|
561
|
+
**Rule of thumb:** If your inheritance tree exceeds 2 levels, refactor to composition.
|
|
562
|
+
|
|
563
|
+
### Dependency Injection
|
|
564
|
+
|
|
565
|
+
Pass dependencies through constructors rather than reaching into global singletons or static service locators. This makes dependencies explicit, testable, and swappable.
|
|
566
|
+
|
|
567
|
+
**DO:** Declare dependencies in the constructor:
|
|
568
|
+
|
|
569
|
+
```
|
|
570
|
+
class ReportGenerator {
|
|
571
|
+
constructor(
|
|
572
|
+
private dataSource: DataSource,
|
|
573
|
+
private formatter: Formatter,
|
|
574
|
+
private logger: Logger,
|
|
575
|
+
) {}
|
|
576
|
+
|
|
577
|
+
generate(query) {
|
|
578
|
+
const data = this.dataSource.fetch(query)
|
|
579
|
+
this.logger.info("Generating report", { query })
|
|
580
|
+
return this.formatter.format(data)
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
```
|
|
584
|
+
|
|
585
|
+
**DON'T:** Use static service locators or hidden globals:
|
|
586
|
+
|
|
587
|
+
```
|
|
588
|
+
class ReportGenerator {
|
|
589
|
+
generate(query) {
|
|
590
|
+
// Hidden dependencies -- caller has no idea what this needs
|
|
591
|
+
const data = ServiceLocator.get(DataSource).fetch(query)
|
|
592
|
+
const formatted = ServiceLocator.get(Formatter).format(data)
|
|
593
|
+
GlobalLogger.info("Done")
|
|
594
|
+
return formatted
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
```
|
|
598
|
+
|
|
599
|
+
### Clean Architecture Layers
|
|
600
|
+
|
|
601
|
+
Organize code in concentric layers where dependencies always point inward. Inner layers know nothing about outer layers.
|
|
602
|
+
|
|
603
|
+
**DO:** Structure as Domain -> Application -> Infrastructure:
|
|
604
|
+
|
|
605
|
+
```
|
|
606
|
+
// Domain layer (innermost): entities and business rules
|
|
607
|
+
// No imports from Application or Infrastructure
|
|
608
|
+
class Order {
|
|
609
|
+
calculateTotal() { return this.items.reduce((s, i) => s + i.price, 0) }
|
|
610
|
+
canBeCancelled() { return this.status === "pending" }
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
// Application layer: use cases that orchestrate domain objects
|
|
614
|
+
// Imports from Domain only
|
|
615
|
+
class PlaceOrderUseCase {
|
|
616
|
+
constructor(private orderRepo: OrderRepository) {}
|
|
617
|
+
execute(items) { ... }
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
// Infrastructure layer (outermost): databases, HTTP, frameworks
|
|
621
|
+
// Imports from Application and Domain
|
|
622
|
+
class PostgresOrderRepository implements OrderRepository {
|
|
623
|
+
save(order) { ... }
|
|
624
|
+
}
|
|
625
|
+
```
|
|
626
|
+
|
|
627
|
+
**DON'T:** Let infrastructure leak into domain logic:
|
|
628
|
+
|
|
629
|
+
```
|
|
630
|
+
// Domain entity importing from infrastructure -- inverted dependency
|
|
631
|
+
import { prisma } from "../db/client"
|
|
632
|
+
|
|
633
|
+
class Order {
|
|
634
|
+
async save() {
|
|
635
|
+
await prisma.order.create({ data: this }) // infrastructure in domain
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
```
|
|
639
|
+
|
|
640
|
+
**Layer rule:** Domain has zero external imports. Application imports Domain. Infrastructure imports both but neither imports Infrastructure.
|