@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.
@@ -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.