๐ŸŽฉ You're Invited:Meet the Socket team at Black Hat in Las Vegas, August 3-6.RSVP โ†’
Sign In

agents-opencode

Package Overview
Dependencies
Maintainers
1
Versions
19
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

agents-opencode - npm Package Compare versions

Comparing version
1.5.0
to
2.0.0
+182
.opencode/agents/legal-advisor.md
---
description: Legal research advisor for jurisdiction-aware analysis across case law, statutes, regulations, contracts, employment, corporate governance, and compliance frameworks
mode: all
temperature: 0.1
steps: 20
skill: true
permission:
"*": "deny"
edit: "allow"
read: "allow"
glob: "allow"
grep: "allow"
webfetch: "allow"
skill:
"*": "deny"
"legal-advisor": "allow"
task:
"*": "deny"
"explore": "allow"
---
# Legal Advisor Agent
Legal research and analysis advisor. Provides jurisdiction-aware guidance on legal questions, regulatory compliance, case analysis, and structured findings. Always includes a mandatory disclaimer.
## When to Use
- Legal research across jurisdictions (case law, statutes, regulations)
- Regulatory compliance analysis (GDPR, CCPA, HIPAA, financial, employment, etc.)
- Contract terms and agreement review
- License auditing and open-source compliance
- IP, copyright, and trademark analysis
- Export control and sanctions screening
- Structured legal findings for a specific case, situation, or country
## Mandatory Disclaimer
**Every response must begin with this exact disclaimer:**
> NOT LEGAL ADVICE: This analysis is provided for informational purposes only and does not constitute legal advice. Consult qualified legal counsel for specific legal guidance.
## Review Methodology
### 1. Scope Definition
Clarify with the user before starting:
- What is the specific legal question, case, or situation?
- Which country or jurisdiction applies?
- What is the relevant area of law (contract, regulatory, IP, employment, etc.)?
- What is the desired outcome (risk assessment, compliance gap analysis, options evaluation)?
### 2. Jurisdiction Identification
Determine the applicable legal framework:
- Common law (US, UK, Canada, Australia, India, etc.) โ€” case law and precedent driven
- Civil law (EU member states, Japan, Brazil, China, etc.) โ€” code and statute driven
- Mixed systems (South Africa, Scotland, Quebec, Louisiana, etc.)
- Religious law influences (Saudi Arabia, Iran, UAE, etc.)
- Federal vs. unitary vs. supranational (EU directives vs. national implementation)
Reference: `references/jurisdictions/` directory in the `legal-advisor` skill โ€” load the specific country file needed.
### 3. Legal Research (IRAC Framework)
Apply the IRAC methodology for structured analysis:
1. **Issue:** Identify the specific legal question or dispute
2. **Rule:** Find applicable statutes, regulations, case law, or legal principles
3. **Application:** Apply the rules to the specific facts or situation
4. **Conclusion:** Provide a reasoned assessment with confidence level
Reference: `references/research-methodology.md` in the `legal-advisor` skill.
For multi-jurisdiction questions (e.g., "compare GDPR vs CCPA"), apply IRAC per jurisdiction, then synthesize a comparative analysis highlighting key differences and areas of alignment.
### 4. Source Evaluation
Prioritize sources by authority:
- **Primary:** Statutes, regulations, court decisions, official gazettes
- **Secondary:** Regulatory guidance, law review articles, authoritative commentaries
- **Tertiary:** Legal news, industry analyses, practitioner summaries (use cautiously)
Use webfetch to access:
- Official government portals (legislation.gov.uk, eur-lex.europa.eu, congress.gov)
- Court databases (supremecourt.gov, bailii.org, curia.europa.eu)
- Regulatory bodies (ico.org.uk, oag.ca.gov, hhs.gov)
- International treaty sources (UN, WTO, WIPO)
Flag source limitations: outdated law, repealed statutes, overruled cases, jurisdictional variance.
### 5. License & Compliance Audit (Subset)
When the question involves software or IP:
1. Extract declared licenses from dependency manifests
2. Verify against SPDX identifiers and project source
3. Cross-reference against the license compatibility matrix
4. Document attribution requirements and copyleft obligations
5. Recommend alternatives for problematic dependencies
Reference: `references/license-matrix.md` and `references/privacy-checklists.md` in the `legal-advisor` skill.
### 6. Risk Assessment
Categorize findings by severity:
- **Critical ๐Ÿ”ด:** Legal violation likely, immediate action required
- **Warning ๐ŸŸก:** Potential exposure, proactive remediation recommended
- **Informational ๐ŸŸข:** Noteworthy but low immediate risk
Always note: jurisdictional assumptions, information gaps, areas requiring professional legal review.
## Output Standards
### Report Naming
Create files named `legal-review-<topic>-<YYYY-MM-DD>.md` in the project root or a designated `reports/` directory.
### Report Structure
```markdown
# Legal Review: [Topic]
**Date:** YYYY-MM-DD
**Research Date:** YYYY-MM-DD (findings current as of this date; laws may have changed since)
**Jurisdiction:** [Country / Region]
**Reviewer:** legal-advisor agent
> NOT LEGAL ADVICE: This analysis is provided for informational purposes only and does not constitute legal advice. Consult qualified legal counsel for specific legal guidance.
## Executive Summary
[2-3 sentence overview of findings and risk level]
## Applicable Law
- [Statute / regulation / case reference]
## Analysis (IRAC)
### Issue
[Specific legal question]
### Rule
[Applicable legal principles with source citations]
### Application
[How the rules apply to the specific facts]
### Conclusion
[Reasoned assessment with confidence level]
## Findings
### Critical Issues ๐Ÿ”ด
- [Issue] โ€” [Impact] โ€” [Recommendation]
### Warnings ๐ŸŸก
- [Issue] โ€” [Impact] โ€” [Recommendation]
### Informational ๐ŸŸข
- [Note] โ€” [Context]
## Recommendations
1. [Actionable recommendation with priority and rationale]
2. [Actionable recommendation with priority and rationale]
## References
- [Source citations with URLs and access dates]
```
### File Permissions
This agent may ONLY create `legal-review-*.md` files. Do NOT modify source code, configuration files, package manifests, or any file not matching the `legal-review-*` pattern.
## Skill Activation Policy
- Load the `legal-advisor` skill on activation for the research methodology framework, jurisdiction profiles, license matrix, and privacy checklists
- Use webfetch for official legal sources; prefer government portals and court databases over secondary summaries
- Cross-reference findings across multiple sources where possible
## Limitations
- This agent provides informational analysis only
- It cannot provide legal advice or replace qualified counsel
- Laws vary by jurisdiction and change over time โ€” findings may become outdated
- Source availability varies by country; some jurisdictions have limited online legal resources
- Users must independently verify all findings with qualified legal counsel
- The agent may not capture recent legislative changes or the most current case law
---
description: Review licenses, compliance, and data privacy
agent: legal-advisor
argument-hint: [dependency, file, or scope]
subtask: true
---
# Legal & Compliance Review
Perform a legal and compliance review of $ARGUMENTS.
## Review Scope
- Check license compatibility for all dependencies against the bundled matrix
- Identify open-source obligations (attribution, copyleft, source disclosure)
- Assess data privacy compliance (GDPR, CCPA/CPRA, HIPAA awareness)
- Screen for export control implications and geographic restrictions
- Flag IP and copyright concerns in the project
## Output
Save findings as `legal-review-<topic>-<date>.md`. Always begin the report with the mandatory legal disclaimer.
---
description: Extended reference for blogger content creation
---
# Blogger Agent Reference
Detailed templates, examples, and extended guidance for the blogger agent.
## Content Style Examples
```markdown
โŒ Bad: "In today's rapidly evolving technological landscape, developers are increasingly finding themselves needing to adapt to new frameworks and methodologies."
โœ… Good: "Tech changes fast. Developers must learn new tools. Stay current or fall behind."
```
## Blog Structure Templates
### Tech Posts
```markdown
# Title: Clear, Actionable, Under 60 Characters
## Problem
What problem does this solve?
## Solution
How to implement it. Step-by-step.
## Code Example
```language
// Working code here
```
## Benefits
Why this matters.
## Resources
- Link 1
- Link 2
```
### Finance Posts
```markdown
# Title: Specific Investment Strategy
## Strategy Overview
What it is. How it works.
## Risk Assessment
- Risk 1: Impact level
- Risk 2: Impact level
## Implementation Steps
1. Step one
2. Step two
## Performance Data
Source: [Link]
Expected returns: X%
Time horizon: Y years
```
### Leadership Posts
```markdown
# Title: One Leadership Principle
## The Principle
State it clearly.
## Why It Works
Evidence from experience.
## How to Apply
3-5 practical steps.
## Common Mistakes
What to avoid.
```
## YouTube Script Format
```
[0:00] HOOK - Grab attention in 15 seconds
[0:15] PROBLEM - What pain point to solve
[0:45] SOLUTION - Your approach
[2:00] DEMO/WALKTHROUGH - Show it working
[4:00] BENEFITS - Why this matters
[5:00] CONCLUSION - Call to action
```
## Quality Standards (Full Checklist)
### Every post must:
1. โœ… Be under 800 words
2. โœ… Have working code examples (tech)
3. โœ… Include 3+ source links
4. โœ… Pass fact validation
5. โœ… Use simple English
6. โœ… Have clear takeaways
### Every podcast idea:
1. โœ… Solve a specific problem
2. โœ… Include 3 discussion points
3. โœ… Have clear target audience
4. โœ… Include promotion angle
### Every YouTube script:
1. โœ… Include timestamps
2. โœ… Under 6 minutes when spoken
3. โœ… Have clear hook and CTA
4. โœ… Include visual cues
## Research Process (Extended)
### For Tech Posts:
1. Check official documentation
2. Read recent blog posts
3. Test code examples
4. Verify compatibility
### For Finance Posts:
1. Review SEC filings/data
2. Check multiple analysts
3. Include historical context
4. Note market conditions
### For Leadership Posts:
1. Draw from personal experience
2. Reference established research
3. Include real examples
4. Avoid generic advice
## SEO Optimization (Extended)
**Titles:** Action words + benefit + time
- "Master React in 30 Days"
- "10X Your Investment Returns"
- "Build Teams That Deliver"
**Headlines:** Question or number
- "Is AI Replacing Developers?"
- "5 Leadership Mistakes to Avoid"
**Meta descriptions:** Under 160 characters
- "Learn how to build scalable React apps with modern patterns. Complete guide with code examples."
---
description: Extended reference for brutal critic content review
---
# Brutal Critic Agent Reference
Extended examples, research resources, and detailed scoring guidance moved from the core file.
## Research Resources
- **YouTube Creators Guidelines**: https://www.youtube.com/creators/how-things-work/policies-guidelines/
- Content policies and community guidelines
- Monetization requirements and restrictions
- Copyright and fair use policies
- Ad suitability standards
## Scoring Guidelines (Detailed)
- **Content Quality:** /10 (factual accuracy, value delivery)
- **Structure:** /10 (organization, flow, pacing)
- **Engagement:** /10 (hook, retention, call-to-action)
- **Overall:** /10 (holistic assessment)
**Scoring scale:**
- 9-10: Exceptional - meets all framework requirements
- 7-8: Good - minor improvements needed
- 5-6: Average - significant work required
- 3-4: Poor - major structural issues
- 1-2: Unacceptable - fundamental problems
## Feedback Style Examples
```markdown
โŒ Vague: "This needs work."
โœ… Specific: "Title is too generic. Change 'Getting Started with React' to 'Master React Components in 30 Minutes'. Current title doesn't convey urgency or specific benefit."
```
```markdown
โŒ Sugarcoated: "This is pretty good, but maybe consider..."
โœ… Direct: "Opening is boring. Start with a shocking statistic or personal story. Current intro puts readers to sleep within 10 seconds."
```
## Common Issues & Fixes (Extended)
### Hook Problems
**Issue:** Weak or missing hook
**Fix:** Start with surprising fact, urgent question, or relatable pain point
**Example:** "Did you know 70% of developers quit within 3 years? Here's why..."
### Pacing Issues
**Issue:** Information dump without breaks
**Fix:** Add pattern breaks, questions, or transitions every 20-40 seconds
**Example:** "Let's take a coffee break and review what we've learned so far..."
### Value Delivery
**Issue:** Theory without application
**Fix:** Include specific steps, code examples, or actionable takeaways
**Example:** Replace "Use best practices" with "Run 'npm install --save-dev eslint' then add this config..."
### Call-to-Action Weakness
**Issue:** Vague or missing CTA
**Fix:** Specific, urgent action with clear benefit
**Example:** "Download the template now - it saves 2 hours of setup time."
---
description: Extended reference for .NET Clean Architecture and C# best practices
---
# .NET Clean Architecture Reference
Detailed code examples and extended guidance for the .NET Clean Architecture instruction set.
## C# Coding Standards
### Async/Await
```csharp
public async Task<User> GetUserAsync(int id, CancellationToken cancellationToken)
{
return await _context.Users
.FirstOrDefaultAsync(u => u.Id == id, cancellationToken);
}
```
### Nullable Reference Types
```csharp
// In .csproj
<Nullable>enable</Nullable>
// Non-nullable
public string Email { get; set; } = string.Empty;
// Nullable
public string? PhoneNumber { get; set; }
```
### Dependency Injection
```csharp
public class UserService : IUserService
{
private readonly IUserRepository _repository;
private readonly ILogger<UserService> _logger;
public UserService(
IUserRepository repository,
ILogger<UserService> logger)
{
_repository = repository;
_logger = logger;
}
}
```
## Entity Framework Core
### Entity Configuration
```csharp
public class UserConfiguration : IEntityTypeConfiguration<User>
{
public void Configure(EntityTypeBuilder<User> builder)
{
builder.ToTable("Users");
builder.HasKey(u => u.Id);
builder.Property(u => u.Email).IsRequired().HasMaxLength(255);
builder.HasIndex(u => u.Email).IsUnique();
}
}
```
### Optimized Queries
```csharp
// โœ… Project early, use AsNoTracking for read-only
var users = await _context.Users
.AsNoTracking()
.Select(u => new UserDto { Id = u.Id, Email = u.Email })
.ToListAsync(cancellationToken);
// โŒ Avoid loading full entities if not needed
```
## Testing Standards
```csharp
public class UserServiceTests
{
private readonly Mock<IUserRepository> _mockRepo;
private readonly UserService _sut;
public UserServiceTests()
{
_mockRepo = new Mock<IUserRepository>();
_sut = new UserService(_mockRepo.Object);
}
[Fact]
public async Task GetUserAsync_ExistingUser_ReturnsUser()
{
// Arrange
var user = new User { Id = 1, Email = "test@example.com" };
_mockRepo.Setup(r => r.GetByIdAsync(1, default))
.ReturnsAsync(user);
// Act
var result = await _sut.GetUserAsync(1, default);
// Assert
result.Should().NotBeNull();
result.Email.Should().Be(user.Email);
}
}
```
## Repository Pattern
```csharp
// Interface in Application layer
public interface IUserRepository
{
Task<User?> GetByIdAsync(int id, CancellationToken cancellationToken);
Task<User> AddAsync(User user, CancellationToken cancellationToken);
}
// Implementation in Infrastructure layer
public class UserRepository : IUserRepository
{
private readonly ApplicationDbContext _context;
public UserRepository(ApplicationDbContext context)
{
_context = context;
}
public async Task<User?> GetByIdAsync(int id, CancellationToken cancellationToken)
{
return await _context.Users
.FirstOrDefaultAsync(u => u.Id == id, cancellationToken);
}
}
```
## Controller Pattern
```csharp
[ApiController]
[Route("api/[controller]")]
public class UsersController : ControllerBase
{
private readonly IUserService _userService;
public UsersController(IUserService userService)
{
_userService = userService;
}
[HttpGet("{id}")]
[ProducesResponseType(typeof(UserDto), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task<ActionResult<UserDto>> GetUser(
int id,
CancellationToken cancellationToken)
{
var user = await _userService.GetUserByIdAsync(id, cancellationToken);
return user is not null ? Ok(user) : NotFound();
}
}
```
---
description: Extended reference for Java Spring Boot best practices
---
# Java Spring Boot Reference
Detailed code examples and extended guidance for the Java Spring Boot instruction set.
## Dependency Injection
### Constructor Injection (Recommended)
```java
@Service
public class UserService {
private final UserRepository userRepository;
private final PasswordEncoder passwordEncoder;
public UserService(UserRepository userRepository, PasswordEncoder passwordEncoder) {
this.userRepository = userRepository;
this.passwordEncoder = passwordEncoder;
}
}
```
### Avoid Field Injection
```java
// โŒ Bad
@Autowired
private UserRepository userRepository;
// โœ… Good - Constructor injection
```
## Entity Design
```java
@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false, unique = true)
private String email;
@Column(nullable = false)
private String password;
@CreationTimestamp
private LocalDateTime createdAt;
// Constructors, getters, setters
}
```
## DTOs and Records
```java
// Java 14+ record
public record UserDto(
Long id,
String email,
String name,
LocalDateTime createdAt
) {
// Automatic constructor, getters, equals, hashCode, toString
}
// For complex DTOs
public record CreateUserRequest(
@NotBlank @Email String email,
@NotBlank @Size(min = 8) String password,
@NotBlank String name
) {}
```
## Validation
```java
@RestController
@RequestMapping("/api/users")
@Validated
public class UserController {
@PostMapping
public ResponseEntity<UserDto> createUser(@Valid @RequestBody CreateUserRequest request) {
User user = userService.createUser(request);
return ResponseEntity.created(uri).body(userMapper.toDto(user));
}
@GetMapping("/{id}")
public ResponseEntity<UserDto> getUser(@PathVariable @Min(1) Long id) {
return userService.findById(id)
.map(userMapper::toDto)
.map(ResponseEntity::ok)
.orElse(ResponseEntity.notFound().build());
}
}
```
## Error Handling
```java
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(UserNotFoundException.class)
public ResponseEntity<ErrorResponse> handleUserNotFound(UserNotFoundException ex) {
return ResponseEntity.status(HttpStatus.NOT_FOUND)
.body(new ErrorResponse("User not found", ex.getMessage()));
}
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<ErrorResponse> handleValidationErrors(MethodArgumentNotValidException ex) {
Map<String, String> errors = ex.getBindingResult()
.getFieldErrors()
.stream()
.collect(Collectors.toMap(
FieldError::getField,
FieldError::getDefaultMessage
));
return ResponseEntity.badRequest()
.body(new ErrorResponse("Validation failed", errors));
}
}
```
## Testing
```java
@SpringBootTest
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
class UserServiceTest {
@Autowired
private UserService userService;
@Autowired
private UserRepository userRepository;
@Test
void shouldCreateUserSuccessfully() {
// Given
CreateUserRequest request = new CreateUserRequest(
"test@example.com", "password123", "Test User"
);
// When
User user = userService.createUser(request);
// Then
assertThat(user.getId()).isNotNull();
assertThat(user.getEmail()).isEqualTo("test@example.com");
}
@Test
void shouldThrowExceptionWhenUserNotFound() {
// When & Then
assertThatThrownBy(() -> userService.findById(999L))
.isInstanceOf(UserNotFoundException.class)
.hasMessage("User not found with id: 999");
}
}
```
## Repository Pattern
```java
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
Optional<User> findByEmail(String email);
@Query("SELECT u FROM User u WHERE u.createdAt > :since")
List<User> findRecentUsers(@Param("since") LocalDateTime since);
@Modifying
@Query("UPDATE User u SET u.lastLoginAt = :now WHERE u.id = :id")
int updateLastLogin(@Param("id") Long id, @Param("now") LocalDateTime now);
}
```
## Configuration
```yaml
spring:
datasource:
url: jdbc:postgresql://localhost:5432/myapp
username: ${DB_USERNAME}
password: ${DB_PASSWORD}
jpa:
hibernate:
ddl-auto: validate
show-sql: false
logging:
level:
com.example.myapp: DEBUG
org.springframework.security: TRACE
```
## Security
```java
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
return http
.csrf(csrf -> csrf.disable()) // For APIs, consider enabling
.authorizeHttpRequests(auth -> auth
.requestMatchers("/api/auth/**").permitAll()
.requestMatchers("/api/admin/**").hasRole("ADMIN")
.anyRequest().authenticated()
)
.sessionManagement(session -> session
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
)
.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class)
.build();
}
}
```
---
description: Legal research patterns for jurisdiction-aware analysis, regulatory compliance, case evaluation, and structured legal findings
---
# Legal Advisor Instructions
## Core Methodology
1. **Scope:** Clarify jurisdiction, legal question, area of law, and desired outcome with the user
2. **Classify:** Determine the legal system category (common law, civil law, mixed, religious-influenced)
3. **Research:** Use webfetch to access official primary sources for the identified jurisdiction
4. **Analyze:** Apply IRAC framework (Issue, Rule, Application, Conclusion) for structured reasoning
5. **Report:** Write findings to `legal-review-<topic>-<date>.md`; never modify source code
## Key Patterns to Check
### General Legal Research
- Identify the governing law by jurisdiction before any analysis
- Distinguish binding from persuasive authority
- Check for recent amendments, repeals, or overruling decisions
- Note jurisdictional splits where applicable
- Flag areas where the law is unsettled or evolving
### Regulatory Compliance
- Identify the specific regulation and its enforcement body
- Check applicability thresholds (revenue, employee count, data volume, etc.)
- Note extraterritorial reach (e.g., GDPR applies to non-EU entities processing EU data)
- Check for registration, notification, or reporting requirements
- Assess penalties and enforcement history
### Contract & Agreement Review
- Identify governing law and dispute resolution provisions
- Check for unusual or one-sided terms (indemnification, limitation of liability, auto-renewal)
- Verify termination rights and notice periods
- Assess IP ownership and licensing provisions
- Flag missing essential terms (scope, payment, duration, confidentiality)
### License Metadata
- `package.json` โ†’ `license` field
- `Cargo.toml` โ†’ `license` field
- `go.mod` โ†’ no built-in field; check repo LICENSE file
- `pom.xml` โ†’ `<licenses><license>` block
- `*.csproj` โ†’ `<PackageLicenseExpression>` or `<PackageLicenseFile>`
- `Gemfile` โ†’ check each gem's gemspec or LICENSE
- `requirements.txt` / `pyproject.toml` โ†’ check PyPI metadata per package
### Red Flags
- No license declared on a dependency the project critically depends on
- GPL/AGPL in a proprietary or SaaS product
- SSPL or Elastic-2.0 if providing managed services
- Cross-border data flows without documented transfer mechanisms
- Cryptographic libraries without ECCN review for internationally distributed products
- Deprecated or unmaintained packages with stale or ambiguous licensing
### Privacy Signals
- PII fields in data models: `email`, `phone`, `ssn`, `dob`, `passport`, `credit_card`
- Unencrypted storage of sensitive data in logs, databases, or caches
- Analytics/tracking SDKs without consent management mechanisms
- Cookie usage without consent banner implementation
## When to Escalate
Escalate to the user (do not decide independently) when:
- The legal question involves criminal liability or significant financial exposure
- The analysis requires interpretation of an ambiguous or untested area of law
- A recommended action could block a release, contract, or business decision
- The jurisdiction's primary sources are not accessible online
- The question requires professional judgment beyond informational analysis
## Research Sources
### General Legal
- **Eur-Lex (EU):** eur-lex.europa.eu
- **Legislation.gov.uk (UK):** legislation.gov.uk
- **Congress.gov (US):** congress.gov
- **CanLII (Canada):** canlii.org
- **BAILII (UK/Ireland):** bailii.org
- **AustLII (Australia):** austlii.org
- **WIPO Lex:** wipo.int/wipolex/
- **UN Treaty Collection:** treaties.un.org
### License Verification
- **SPDX License List:** spdx.org/licenses/
- **OSI Approved Licenses:** opensource.org/licenses/
- **ChooseALicense (GitHub):** choosealicense.com/
### Privacy Regulations
- **GDPR:** gdpr-info.eu
- **CCPA/CPRA:** oag.ca.gov/privacy/ccpa
- **HIPAA:** hhs.gov/hipaa/
- **ICO (UK):** ico.org.uk
### Export Control
- **BIS EAR (US):** bis.doc.gov
- **DDTC ITAR (US):** pmddtc.state.gov
## Output Standards
- Every response begins with the mandatory disclaimer
- Reports saved as `legal-review-<topic>-<YYYY-MM-DD>.md`
- Never modify source code, config files, or package manifests
- Include source citations with URLs and access dates
- State confidence level (high / moderate / tentative) for each finding
- Provide actionable recommendations with priority levels
---
description: Orchestrator reference โ€” planning templates, agent selection guide, coordination patterns, and progress tracking
---
# Orchestrator Reference
Loaded on demand when the orchestrator needs to create plans, delegate tasks, or track progress.
## Planning Template
Use this format when creating a multi-phase plan:
```markdown
## Orchestration Plan
### Phases
1. **[Phase Name]** (@agent-name)
- Tasks: [What needs to be done]
- Dependencies: [What must be complete first]
- Deliverables: [Expected outputs]
2. **[Phase Name]** (@agent-name)
- Tasks: [What needs to be done]
- Dependencies: [Phase 1 completion]
- Deliverables: [Expected outputs]
### Validation Steps
- [ ] [Validation step 1]
- [ ] [Validation step 2]
### Success Criteria
- [Criterion 1]
- [Criterion 2]
```
## Agent Selection Guide
**@codebase** - Use for:
- Feature implementation
- Bug fixes
- Code refactoring
- Test creation
**@docs** - Use for:
- README updates
- API documentation
- Architecture docs
- User guides
**@review** - Use for:
- Security audits
- Performance reviews
- Code quality checks
- Best practices validation
**@planner** - Use for:
- Read-only codebase analysis
- Detailed implementation planning
- Risk assessment before implementation
**@em-advisor** - Use for:
- Engineering leadership guidance
- Stakeholder communication strategy
- Team execution and prioritization support
**@blogger** - Use for:
- Blog post creation
- YouTube script writing
- Podcast outline brainstorming
**@brutal-critic** - Use for:
- Content quality reviews
- Framework-based scoring
- Pre-publish validation
**@legal-advisor** - Use for:
- Legal research across jurisdictions
- Regulatory compliance analysis
- License auditing and open-source compliance
- Data privacy and export control review
- Contract and agreement evaluation
## Coordination Patterns
### Pattern 1: Implementation Cycle
```
orchestrator โ†’ @codebase (implement)
โ†’ @review (validate)
โ†’ @codebase (fix issues)
โ†’ @docs (document)
```
### Pattern 2: Documentation Refresh
```
orchestrator โ†’ @codebase (analyze changes)
โ†’ @docs (update docs)
โ†’ @review (verify accuracy)
```
### Pattern 3: Full Feature Delivery
```
orchestrator โ†’ @codebase (implement + tests)
โ†’ @review (security + performance)
โ†’ @codebase (address issues)
โ†’ @docs (API docs + README)
โ†’ @review (final validation)
```
### Pattern 4: Legal Review Cycle
```
orchestrator โ†’ @legal-advisor (legal research / compliance analysis)
โ†’ @review (validate findings)
โ†’ @codebase (remediate issues / apply recommendations)
```
## Progress Tracking for Long-Running Work
For complex or multi-phase tasks, include and maintain a status table in updates.
Use this format:
```markdown
## Workstream Status
| ID | Initiative | Impact / Effort | Status | Notes |
|---|---|---|---|---|
| S1 | [Initiative] | [High/Medium/Low] / [High/Medium/Low] | [โœ… Done / ๐Ÿ”„ In Progress / โณ Planned / โ›” Blocked] | [Short note] |
```
Update cadence:
- Include the table at plan start for long-running/complex tasks.
- Update status after each completed phase or loop cycle.
- Keep exactly one active item as `๐Ÿ”„ In Progress` where possible.
- Reflect blockers immediately with `โ›” Blocked` and mitigation options.
{
"name": ".opencode",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"dependencies": {
"@opencode-ai/plugin": "1.14.39"
}
},
"node_modules/@msgpackr-extract/msgpackr-extract-darwin-arm64": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-arm64/-/msgpackr-extract-darwin-arm64-3.0.3.tgz",
"integrity": "sha512-QZHtlVgbAdy2zAqNA9Gu1UpIuI8Xvsd1v8ic6B2pZmeFnFcMWiPLfWXh7TVw4eGEZ/C9TH281KwhVoeQUKbyjw==",
"cpu": [
"arm64"
],
"license": "MIT",
"optional": true,
"os": [
"darwin"
]
},
"node_modules/@msgpackr-extract/msgpackr-extract-darwin-x64": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-x64/-/msgpackr-extract-darwin-x64-3.0.3.tgz",
"integrity": "sha512-mdzd3AVzYKuUmiWOQ8GNhl64/IoFGol569zNRdkLReh6LRLHOXxU4U8eq0JwaD8iFHdVGqSy4IjFL4reoWCDFw==",
"cpu": [
"x64"
],
"license": "MIT",
"optional": true,
"os": [
"darwin"
]
},
"node_modules/@msgpackr-extract/msgpackr-extract-linux-arm": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm/-/msgpackr-extract-linux-arm-3.0.3.tgz",
"integrity": "sha512-fg0uy/dG/nZEXfYilKoRe7yALaNmHoYeIoJuJ7KJ+YyU2bvY8vPv27f7UKhGRpY6euFYqEVhxCFZgAUNQBM3nw==",
"cpu": [
"arm"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@msgpackr-extract/msgpackr-extract-linux-arm64": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm64/-/msgpackr-extract-linux-arm64-3.0.3.tgz",
"integrity": "sha512-YxQL+ax0XqBJDZiKimS2XQaf+2wDGVa1enVRGzEvLLVFeqa5kx2bWbtcSXgsxjQB7nRqqIGFIcLteF/sHeVtQg==",
"cpu": [
"arm64"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@msgpackr-extract/msgpackr-extract-linux-x64": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-x64/-/msgpackr-extract-linux-x64-3.0.3.tgz",
"integrity": "sha512-cvwNfbP07pKUfq1uH+S6KJ7dT9K8WOE4ZiAcsrSes+UY55E/0jLYc+vq+DO7jlmqRb5zAggExKm0H7O/CBaesg==",
"cpu": [
"x64"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@msgpackr-extract/msgpackr-extract-win32-x64": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-win32-x64/-/msgpackr-extract-win32-x64-3.0.3.tgz",
"integrity": "sha512-x0fWaQtYp4E6sktbsdAqnehxDgEc/VwM7uLsRCYWaiGu0ykYdZPiS8zCWdnjHwyiumousxfBm4SO31eXqwEZhQ==",
"cpu": [
"x64"
],
"license": "MIT",
"optional": true,
"os": [
"win32"
]
},
"node_modules/@opencode-ai/plugin": {
"version": "1.14.39",
"resolved": "https://registry.npmjs.org/@opencode-ai/plugin/-/plugin-1.14.39.tgz",
"integrity": "sha512-h3p3qCZLjodiKquCI9/YSDxgUoHTQ0/AK7t71tLWkUpEUicPZWsixdn3lk53/uLU+Wh+qp5FV+GTZWAXkKmAkw==",
"license": "MIT",
"dependencies": {
"@opencode-ai/sdk": "1.14.39",
"effect": "4.0.0-beta.59",
"zod": "4.1.8"
},
"peerDependencies": {
"@opentui/core": ">=0.2.2",
"@opentui/solid": ">=0.2.2"
},
"peerDependenciesMeta": {
"@opentui/core": {
"optional": true
},
"@opentui/solid": {
"optional": true
}
}
},
"node_modules/@opencode-ai/sdk": {
"version": "1.14.39",
"resolved": "https://registry.npmjs.org/@opencode-ai/sdk/-/sdk-1.14.39.tgz",
"integrity": "sha512-hguOA5huhys7zwCR3ESbSHyQNuJBNtfrxUxYZF/s/6trRW+imqGmDtC/RsOSNuk7GE06ZnvOTwb4T2WhXYIBxw==",
"license": "MIT",
"dependencies": {
"cross-spawn": "7.0.6"
}
},
"node_modules/@standard-schema/spec": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz",
"integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==",
"license": "MIT"
},
"node_modules/cross-spawn": {
"version": "7.0.6",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
"integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
"license": "MIT",
"dependencies": {
"path-key": "^3.1.0",
"shebang-command": "^2.0.0",
"which": "^2.0.1"
},
"engines": {
"node": ">= 8"
}
},
"node_modules/detect-libc": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz",
"integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==",
"license": "Apache-2.0",
"optional": true,
"engines": {
"node": ">=8"
}
},
"node_modules/effect": {
"version": "4.0.0-beta.59",
"resolved": "https://registry.npmjs.org/effect/-/effect-4.0.0-beta.59.tgz",
"integrity": "sha512-xyUDLeHSe8d6lWGOvR6Fgn2HL6gYeTZ/S4Jzk9uc4ZUxMPPsNZlNXrvk0C7/utQFzeX7uAWcVnG2BjbA0SRoAA==",
"license": "MIT",
"dependencies": {
"@standard-schema/spec": "^1.1.0",
"fast-check": "^4.6.0",
"find-my-way-ts": "^0.1.6",
"ini": "^6.0.0",
"kubernetes-types": "^1.30.0",
"msgpackr": "^1.11.9",
"multipasta": "^0.2.7",
"toml": "^4.1.1",
"uuid": "^13.0.0",
"yaml": "^2.8.3"
}
},
"node_modules/fast-check": {
"version": "4.7.0",
"resolved": "https://registry.npmjs.org/fast-check/-/fast-check-4.7.0.tgz",
"integrity": "sha512-NsZRtqvSSoCP0HbNjUD+r1JH8zqZalyp6gLY9e7OYs7NK9b6AHOs2baBFeBG7bVNsuoukh89x2Yg3rPsul8ziQ==",
"funding": [
{
"type": "individual",
"url": "https://github.com/sponsors/dubzzz"
},
{
"type": "opencollective",
"url": "https://opencollective.com/fast-check"
}
],
"license": "MIT",
"dependencies": {
"pure-rand": "^8.0.0"
},
"engines": {
"node": ">=12.17.0"
}
},
"node_modules/find-my-way-ts": {
"version": "0.1.6",
"resolved": "https://registry.npmjs.org/find-my-way-ts/-/find-my-way-ts-0.1.6.tgz",
"integrity": "sha512-a85L9ZoXtNAey3Y6Z+eBWW658kO/MwR7zIafkIUPUMf3isZG0NCs2pjW2wtjxAKuJPxMAsHUIP4ZPGv0o5gyTA==",
"license": "MIT"
},
"node_modules/ini": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/ini/-/ini-6.0.0.tgz",
"integrity": "sha512-IBTdIkzZNOpqm7q3dRqJvMaldXjDHWkEDfrwGEQTs5eaQMWV+djAhR+wahyNNMAa+qpbDUhBMVt4ZKNwpPm7xQ==",
"license": "ISC",
"engines": {
"node": "^20.17.0 || >=22.9.0"
}
},
"node_modules/isexe": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
"integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
"license": "ISC"
},
"node_modules/kubernetes-types": {
"version": "1.30.0",
"resolved": "https://registry.npmjs.org/kubernetes-types/-/kubernetes-types-1.30.0.tgz",
"integrity": "sha512-Dew1okvhM/SQcIa2rcgujNndZwU8VnSapDgdxlYoB84ZlpAD43U6KLAFqYo17ykSFGHNPrg0qry0bP+GJd9v7Q==",
"license": "Apache-2.0"
},
"node_modules/msgpackr": {
"version": "1.11.12",
"resolved": "https://registry.npmjs.org/msgpackr/-/msgpackr-1.11.12.tgz",
"integrity": "sha512-RBdJ1Un7yGlXWajrkxcSa93nvQ0w4zBf60c0yYv7YtBelP8H2FA7XsfBbMHtXKXUMUxH7zV3Zuozh+kUQWhHvg==",
"license": "MIT",
"optionalDependencies": {
"msgpackr-extract": "^3.0.2"
}
},
"node_modules/msgpackr-extract": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/msgpackr-extract/-/msgpackr-extract-3.0.3.tgz",
"integrity": "sha512-P0efT1C9jIdVRefqjzOQ9Xml57zpOXnIuS+csaB4MdZbTdmGDLo8XhzBG1N7aO11gKDDkJvBLULeFTo46wwreA==",
"hasInstallScript": true,
"license": "MIT",
"optional": true,
"dependencies": {
"node-gyp-build-optional-packages": "5.2.2"
},
"bin": {
"download-msgpackr-prebuilds": "bin/download-prebuilds.js"
},
"optionalDependencies": {
"@msgpackr-extract/msgpackr-extract-darwin-arm64": "3.0.3",
"@msgpackr-extract/msgpackr-extract-darwin-x64": "3.0.3",
"@msgpackr-extract/msgpackr-extract-linux-arm": "3.0.3",
"@msgpackr-extract/msgpackr-extract-linux-arm64": "3.0.3",
"@msgpackr-extract/msgpackr-extract-linux-x64": "3.0.3",
"@msgpackr-extract/msgpackr-extract-win32-x64": "3.0.3"
}
},
"node_modules/multipasta": {
"version": "0.2.7",
"resolved": "https://registry.npmjs.org/multipasta/-/multipasta-0.2.7.tgz",
"integrity": "sha512-KPA58d68KgGil15oDqXjkUBEBYc00XvbPj5/X+dyzeo/lWm9Nc25pQRlf1D+gv4OpK7NM0J1odrbu9JNNGvynA==",
"license": "MIT"
},
"node_modules/node-gyp-build-optional-packages": {
"version": "5.2.2",
"resolved": "https://registry.npmjs.org/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.2.2.tgz",
"integrity": "sha512-s+w+rBWnpTMwSFbaE0UXsRlg7hU4FjekKU4eyAih5T8nJuNZT1nNsskXpxmeqSK9UzkBl6UgRlnKc8hz8IEqOw==",
"license": "MIT",
"optional": true,
"dependencies": {
"detect-libc": "^2.0.1"
},
"bin": {
"node-gyp-build-optional-packages": "bin.js",
"node-gyp-build-optional-packages-optional": "optional.js",
"node-gyp-build-optional-packages-test": "build-test.js"
}
},
"node_modules/path-key": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
"integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
"license": "MIT",
"engines": {
"node": ">=8"
}
},
"node_modules/pure-rand": {
"version": "8.4.0",
"resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-8.4.0.tgz",
"integrity": "sha512-IoM8YF/jY0hiugFo/wOWqfmarlE6J0wc6fDK1PhftMk7MGhVZl88sZimmqBBFomLOCSmcCCpsfj7wXASCpvK9A==",
"funding": [
{
"type": "individual",
"url": "https://github.com/sponsors/dubzzz"
},
{
"type": "opencollective",
"url": "https://opencollective.com/fast-check"
}
],
"license": "MIT"
},
"node_modules/shebang-command": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
"integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
"license": "MIT",
"dependencies": {
"shebang-regex": "^3.0.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/shebang-regex": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
"integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
"license": "MIT",
"engines": {
"node": ">=8"
}
},
"node_modules/toml": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/toml/-/toml-4.1.1.tgz",
"integrity": "sha512-EBJnVBr3dTXdA89WVFoAIPUqkBjxPMwRqsfuo1r240tKFHXv3zgca4+NJib/h6TyvGF7vOawz0jGuryJCdNHrw==",
"license": "MIT",
"engines": {
"node": ">=20"
}
},
"node_modules/uuid": {
"version": "13.0.2",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-13.0.2.tgz",
"integrity": "sha512-vzi9uRZ926x4XV73S/4qQaTwPXM2JBj6/6lI/byHH1jOpCzb0zDbfytgA9LcN/hzb2l7WQSQnxITOVx5un/wGw==",
"funding": [
"https://github.com/sponsors/broofa",
"https://github.com/sponsors/ctavan"
],
"license": "MIT",
"bin": {
"uuid": "dist-node/bin/uuid"
}
},
"node_modules/which": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
"integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
"license": "ISC",
"dependencies": {
"isexe": "^2.0.0"
},
"bin": {
"node-which": "bin/node-which"
},
"engines": {
"node": ">= 8"
}
},
"node_modules/yaml": {
"version": "2.8.4",
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.4.tgz",
"integrity": "sha512-ml/JPOj9fOQK8RNnWojA67GbZ0ApXAUlN2UQclwv2eVgTgn7O9gg9o7paZWKMp4g0H3nTLtS9LVzhkpOFIKzog==",
"license": "ISC",
"bin": {
"yaml": "bin.mjs"
},
"engines": {
"node": ">= 14.6"
},
"funding": {
"url": "https://github.com/sponsors/eemeli"
}
},
"node_modules/zod": {
"version": "4.1.8",
"resolved": "https://registry.npmjs.org/zod/-/zod-4.1.8.tgz",
"integrity": "sha512-5R1P+WwQqmmMIEACyzSvo4JXHY5WiAFHRMg+zBZKgKS+Q1viRa0C1hmUKtHltoIFKtIdki3pRxkmpP74jnNYHQ==",
"license": "MIT",
"funding": {
"url": "https://github.com/sponsors/colinhacks"
}
}
}
}
import type { Plugin } from "@opencode-ai/plugin";
const PACKAGE_VERSION = "2.0.0";
export const AgentsOpencodePlugin: Plugin = async ({
client,
project,
directory,
worktree,
$,
}) => {
await client.app.log({
body: {
service: "agents-opencode",
level: "info",
message: `Agents Opencode v${PACKAGE_VERSION} loaded โ€” 9 agents, 18 skills, 14 commands available`,
},
});
return {
/**
* Inject agent-specific state into compaction so critical context
* survives context window truncation.
*/
"experimental.session.compacting": async (input, output) => {
output.context.push(`## Agents Opencode Context
You are operating with the agents-opencode v${PACKAGE_VERSION} agent pack.
Available agents (invoke via @mention):
- @codebase โ€” Multi-language development with profile detection
- @orchestrator โ€” Strategic planning and complex workflow coordination
- @planner โ€” Read-only analysis and implementation planning
- @review โ€” Code review for security, performance, and best practices
- @docs โ€” Documentation creation and maintenance
- @blogger โ€” Content creation for blogging, podcasting, YouTube
- @brutal-critic โ€” Content quality review with framework-based scoring
- @em-advisor โ€” Engineering management guidance
- @legal-advisor โ€” License auditing, compliance, and regulatory guidance
Active skills: 18 language/domain/utility skill packs loadable via skill tool.
Active commands: 14 slash commands (type / to see autocomplete).
Memory: state/session-state.json and handoff/latest.md preserve working state.
Context persistence: AGENTS.md tracks project milestones across sessions.`);
// Persist critical state markers
output.context.push(`## Session State Reminder
- Current phase: Read state/session-state.json for working memory
- Check handoff/latest.md for continuation context
- Review AGENTS.md for recent milestones and patterns`);
},
/**
* Safety hook: block agents from reading sensitive files.
*/
"tool.execute.before": async (input, output) => {
if (input.tool === "read") {
const filePath = output.args?.filePath;
if (typeof filePath === "string") {
const basename = filePath.split(/[/\\]/).pop()?.toLowerCase() || "";
const blockedPatterns = [
".env",
"credentials.json",
"secrets.yaml",
"id_rsa",
"id_ed25519",
".pem",
];
for (const pattern of blockedPatterns) {
if (basename === pattern || basename.endsWith(pattern)) {
throw new Error(
`[agents-opencode] Blocked reading sensitive file: ${filePath}. Do not read credential or secret files.`
);
}
}
}
}
},
/**
* Inject package version into shell environment for script awareness.
*/
"shell.env": async (input, output) => {
output.env["AGENTS_OPENCODE_VERSION"] = PACKAGE_VERSION;
},
};
};
# Export Control Guidance
Reference for evaluating export control implications in software projects.
## ECCN Classification
Encryption-related code and certain technologies may require Export Control Classification Number
(ECCN) review under the U.S. Commerce Control List (CCL).
### Encryption Items (ECCN 5A002 / 5D002)
- [ ] Identify cryptographic libraries and their ECCN classification
- [ ] Check if the project calls encryption functions beyond basic DRM/authentication
- [ ] Determine if encryption source code is publicly available (EAR 742.15(b) exception)
- [ ] Note mass-market encryption commodity exceptions where applicable
### Non-Encryption Controlled Technologies
- [ ] Check for restricted/sanctioned technologies (e.g., surveillance, military, dual-use)
- [ ] Verify no EAR99 items are re-exported to sanctioned destinations
- [ ] Review for ITAR-controlled defense articles (if applicable)
## Sanctioned Destinations and Parties
- [ ] Screen against OFAC SDN List for restricted entities
- [ ] Check geographic distribution restrictions (Cuba, Iran, North Korea, Syria, Crimea)
- [ ] Verify no denied parties in the supply chain
## Open-Source Considerations
- [ ] Confirm that publicly available source code qualifies for EAR exception
- [ ] Verify no encryption registration is required for open-source publication
- [ ] Note: contribution from sanctioned countries may require legal review
## Recommended Actions
- [ ] File encryption registration (BIS semi-annual) if required
- [ ] Add EAR classification to export/README for downstream consumers
- [ ] Consult export control counsel for ambiguous classifications
# Australia (Federal)
- **System:** Common law, federal system
- **Sources:** Commonwealth legislation, state legislation, High Court decisions
- **Key portals:** legislation.gov.au, austlii.edu.au
- **Notes:** Strong regulatory framework; ACCC, ASIC, APRA for specific sectors
# Brazil (Federal)
- **System:** Civil law, federal system
- **Sources:** Federal Constitution, Cรณdigo Civil, federal/state legislation, STF decisions
- **Key portals:** planalto.gov.br/legislacao, stf.jus.br
- **Notes:** LGPD (General Data Protection Law) closely modeled on GDPR
# Canada (Federal)
- **System:** Common law (except Quebec โ€” civil law), federal system
- **Sources:** Constitution Act, federal/provincial statutes, Supreme Court of Canada decisions
- **Key portals:** laws-lois.justice.gc.ca, canlii.org, scc-csc.ca
- **Notes:** Quebec uses civil law for private law matters; bijuralism applies federally
# China
- **System:** Civil law with socialist characteristics, unitary
- **Sources:** Constitution, national laws, State Council regulations, SPC interpretations
- **Key portals:** npc.gov.cn, court.gov.cn (limited English availability)
- **Notes:** SPC judicial interpretations are quasi-legislative; cybersecurity and data laws evolving rapidly
# European Union
- **System:** Supranational โ€” regulations (directly applicable) and directives (require national implementation)
- **Sources:** Treaties (TEU, TFEU), regulations, directives, CJEU decisions
- **Key portals:** eur-lex.europa.eu, curia.europa.eu
- **Notes:** GDPR (Regulation 2016/679) is directly applicable in all member states
# France
- **System:** Civil law, unitary (with some devolution)
- **Sources:** Constitution, Code Civil, Code de Commerce, Conseil Constitutionnel decisions
- **Key portals:** legifrance.gouv.fr, conseil-constitutionnel.fr
- **Notes:** Administrative law handled by Conseil d'ร‰tat, separate from judicial courts
# Germany
- **System:** Civil law, federal system
- **Sources:** Grundgesetz (Basic Law), BGB (Civil Code), federal/state legislation, BVerfG decisions
- **Key portals:** gesetze-im-internet.de, bundesverfassungsgericht.de
- **Notes:** Strong data protection tradition; BDSG supplements GDPR
# India (Federal)
- **System:** Common law, federal system with unitary features
- **Sources:** Constitution of India, central/state acts, Supreme Court decisions
- **Key portals:** indiacode.nic.in, main.sci.gov.in, indiankanoon.org
- **Notes:** Personal laws (family, inheritance) may follow religious traditions
# International Resources
- **UN Treaty Collection:** treaties.un.org
- **WTO Legal Texts:** wto.org/english/docs_e/legal_e/legal_e.htm
- **WIPO Lex:** wipo.int/wipolex/
- **Council of Europe (ECHR):** coe.int, hudoc.echr.coe.int
- **ICJ (International Court of Justice):** icj-cij.org
# Japan
- **System:** Civil law (German-influenced), unitary
- **Sources:** Constitution, Six Codes (Civil, Commercial, Criminal, etc.), Supreme Court decisions
- **Key portals:** japaneselawtranslation.go.jp, courts.go.jp
- **Notes:** Limited case law precedent compared to common law systems
# Malaysia
- **System:** Common law (English-influenced) with Islamic law for Muslim personal matters
- **Sources:** Federal Constitution (supreme), Acts of Parliament, State Enactments, Federal Court decisions
- **Key portals:** lom.agc.gov.my (Federal Legislation), judiciary.kl.kehakiman.gov.my, cljlaw.com
- **Notes:** Dual court system โ€” civil courts for general law, Syariah courts for Muslims (family, inheritance). PDPA 2010 for personal data. Strong English common law precedent still persuasive.
# Quebec (Canada)
- **System:** Civil law for private law; common law for public law
- **Sources:** Civil Code of Quebec, federal/provincial statutes, SCC and QCCA decisions
- **Key portals:** legisquebec.gouv.qc.ca, canlii.org
- **Notes:** Only Canadian province with civil law; Bill 64 (Law 25) for privacy
# Saudi Arabia
- **System:** Islamic law (Sharia) based, with royal decrees and regulations
- **Sources:** Quran and Sunnah as primary; royal orders, Council of Ministers resolutions
- **Key portals:** boe.gov.sa (limited English), moi.gov.sa
- **Notes:** PDPL (Personal Data Protection Law) effective 2023; evolving regulatory landscape
# Scotland
- **System:** Mixed โ€” civil law roots + common law influences
- **Sources:** Acts of Scottish Parliament, UK Parliament acts, Court of Session decisions
- **Key portals:** legislation.gov.uk, scotcourts.gov.uk
- **Notes:** Distinct from England & Wales in property, contract, and criminal law
# South Africa
- **System:** Mixed โ€” Roman-Dutch civil law + English common law + customary law
- **Sources:** Constitution (supreme), legislation, judicial precedent, customary law
- **Key portals:** gov.za/documents/acts, saflii.org, concourt.org.za
- **Notes:** POPIA (Protection of Personal Information Act) for data privacy
# United Arab Emirates
- **System:** Civil law with Islamic law influences; free zones may apply different rules
- **Sources:** Federal laws, Emirate-level laws, DIFC/ADGM courts (common law enclaves)
- **Key portals:** uaecabinet.ae, moj.gov.ae
- **Notes:** DIFC and ADGM operate English common law systems within their jurisdictions
# United Kingdom
- **System:** Common law, unitary (with devolution to Scotland, Wales, NI)
- **Sources:** Acts of Parliament, statutory instruments, Supreme Court decisions, retained EU law
- **Key portals:** legislation.gov.uk, bailii.org, supremecourt.uk
- **Notes:** England & Wales share a system; Scotland has a distinct mixed legal system
# United States (Federal)
- **System:** Common law, federal system (50 states + federal)
- **Sources:** US Constitution, USC (federal statutes), CFR (regulations), Supreme Court decisions, Circuit Court decisions
- **Key portals:** congress.gov, supremecourt.gov, ecfr.gov, uscode.house.gov
- **Notes:** Federal law preempts conflicting state law; circuit splits create jurisdictional variance. Each state has its own statutes, regulations, and court system.
# License Compatibility Matrix
Comprehensive reference for open-source license obligations, compatibility, and typical use cases. All identifiers follow SPDX.
## Permissive Licenses
### MIT
- **SPDX ID:** MIT
- **Category:** Permissive
- **Key Obligations:** Include copyright notice and permission notice in all copies
- **Compatibility:** Compatible with all licenses including proprietary; can relicense under any terms
- **Typical Use:** Libraries, frameworks, developer tools, npm ecosystem default
- **Risk Level:** Low
### Apache-2.0
- **SPDX ID:** Apache-2.0
- **Category:** Permissive (with patent grant)
- **Key Obligations:** Include copyright notice, license text, and NOTICE file; state changes made to files; explicit patent grant
- **Compatibility:** Compatible with GPL-3.0-only (one-way); NOT compatible with GPL-2.0-only due to patent clause
- **Typical Use:** Enterprise projects, Kubernetes, Android, Apache Foundation projects
- **Risk Level:** Low
### BSD-2-Clause
- **SPDX ID:** BSD-2-Clause
- **Category:** Permissive
- **Key Obligations:** Include copyright notice, conditions list, and disclaimer in source and binary forms
- **Compatibility:** Compatible with all licenses including proprietary
- **Typical Use:** Minimal permissive; popular in Go ecosystem, FreeBSD components
- **Risk Level:** Low
### BSD-3-Clause
- **SPDX ID:** BSD-3-Clause
- **Category:** Permissive
- **Key Obligations:** Same as BSD-2-Clause plus prohibition on using contributor names for endorsement without permission
- **Compatibility:** Compatible with all licenses including proprietary
- **Typical Use:** Widely used; React, Go standard library parts, NumPy
- **Risk Level:** Low
### ISC
- **SPDX ID:** ISC
- **Category:** Permissive
- **Key Obligations:** Include copyright notice and permission notice
- **Compatibility:** Functionally equivalent to MIT; compatible with all licenses
- **Typical Use:** OpenBSD, npm packages, Node.js ecosystem
- **Risk Level:** Low
### Artistic-2.0
- **SPDX ID:** Artistic-2.0
- **Category:** Permissive
- **Key Obligations:** Source availability for modifications when distributed; allows relicensing under different terms
- **Compatibility:** Compatible with GPL (via relicensing clause); broadly compatible with permissive licenses
- **Typical Use:** Perl ecosystem, CPAN modules
- **Risk Level:** Low
## Public Domain Dedications
### Unlicense
- **SPDX ID:** Unlicense
- **Category:** Public domain dedication
- **Key Obligations:** No obligations; dedicates work to public domain with fallback permissive license
- **Compatibility:** Compatible with all licenses; may not be recognized in all jurisdictions (e.g., Germany)
- **Typical Use:** Small utilities, example code, reference implementations
- **Risk Level:** Low (jurisdictional caveat)
### CC0-1.0
- **SPDX ID:** CC0-1.0
- **Category:** Public domain dedication
- **Key Obligations:** No obligations; waives all copyright and related rights; no patent grant
- **Compatibility:** Compatible with all licenses; broadly recognized internationally
- **Typical Use:** Data, documentation, reference code, Creative Commons ecosystem
- **Risk Level:** Low (no patent grant)
## Copyleft Licenses
### GPL-2.0-only
- **SPDX ID:** GPL-2.0-only
- **Category:** Strong copyleft
- **Key Obligations:** Derivative works must be licensed under GPL-2.0; source code must be provided with binary distribution
- **Compatibility:** Compatible with GPL-3.0-only (via "or later" clause), LGPL-2.0; INCOMPATIBLE with Apache-2.0, MPL-2.0
- **Typical Use:** Linux kernel, MySQL, older GNU projects
- **Risk Level:** High for proprietary products
### GPL-3.0-only
- **SPDX ID:** GPL-3.0-only
- **Category:** Strong copyleft
- **Key Obligations:** Same as GPL-2.0 with added patent grant, anti-tivoization, and anti-DRM provisions
- **Compatibility:** Compatible with Apache-2.0 (one-way), LGPL-3.0; INCOMPATIBLE with GPL-2.0-only (without "or later")
- **Typical Use:** Modern GNU projects, Bash, GIMP, GCC (with exception)
- **Risk Level:** High for proprietary products
### AGPL-3.0-only
- **SPDX ID:** AGPL-3.0-only
- **Category:** Strong copyleft (network clause)
- **Key Obligations:** Same as GPL-3.0 plus source disclosure when software is accessed over a network (SaaS/cloud trigger)
- **Compatibility:** Compatible with GPL-3.0-only; INCOMPATIBLE with GPL-2.0-only
- **Typical Use:** MongoDB (pre-SSPL), Grafana, MinIO, network-facing services
- **Risk Level:** Critical for SaaS products
### LGPL-3.0-only
- **SPDX ID:** LGPL-3.0-only
- **Category:** Weak copyleft (library)
- **Key Obligations:** Copyleft applies only to the library itself; proprietary applications may dynamically link; modifications to library source must be shared
- **Compatibility:** Compatible with GPL-3.0-only, proprietary (via dynamic linking); static linking may trigger copyleft
- **Typical Use:** GUI toolkits (GTK), audio codecs (FFmpeg), system libraries
- **Risk Level:** Medium (linking mode matters)
## Weak Copyleft Licenses
### MPL-2.0
- **SPDX ID:** MPL-2.0
- **Category:** Weak copyleft (file-level)
- **Key Obligations:** Copyleft applies only to the original MPL-licensed files; modifications to those files must be shared; new files may be proprietary
- **Compatibility:** Compatible with GPL (via secondary licensing clause), Apache-2.0; file-level copyleft is less restrictive than GPL
- **Typical Use:** Mozilla Firefox, LibreOffice components, Rust standard library parts
- **Risk Level:** Medium
### EPL-2.0
- **SPDX ID:** EPL-2.0
- **Category:** Weak copyleft (module-level)
- **Key Obligations:** Copyleft applies to the module/plug-in level; separate modules may be proprietary; patent grant included
- **Compatibility:** Compatible with GPL (via secondary licensing); INCOMPATIBLE with pure GPL without secondary license clause
- **Typical Use:** Eclipse IDE, Java ecosystem tools, Clojure
- **Risk Level:** Medium
## Source-Available Licenses
### BSL (Business Source License)
- **SPDX ID:** BUSL-1.1 (non-standard SPDX)
- **Category:** Source-available (time-delayed)
- **Key Obligations:** Source available but restricted use; automatically converts to open-source (typically GPL or Apache-2.0) after specified period (usually 3-4 years); production use may require commercial license during restricted period
- **Compatibility:** NOT open-source during restricted period; compatible with target license after conversion date
- **Typical Use:** CockroachDB, MariaDB MaxScale, Sentry
- **Risk Level:** High (timing-dependent; commercial license needed for production)
### SSPL (Server Side Public License)
- **SPDX ID:** SSPL-1.0 (not OSI approved)
- **Category:** Source-available (broad copyleft)
- **Key Obligations:** Same as AGPL-3.0 plus must release ALL software used to operate the service (management, orchestration, monitoring, etc.); far broader than AGPL
- **Compatibility:** NOT OSI approved; effectively incompatible with proprietary use as SaaS
- **Typical Use:** MongoDB (since 2018), Elasticsearch (transitioned from Apache-2.0)
- **Risk Level:** Critical for SaaS products
### Elastic-2.0
- **SPDX ID:** Elastic-2.0 (not OSI approved)
- **Category:** Source-available (use restriction)
- **Key Obligations:** Free use except for providing the software as a managed service; cannot offer "Elasticsearch as a Service"; otherwise permissive
- **Compatibility:** NOT OSI approved; compatible for non-competing use
- **Typical Use:** Elasticsearch, Kibana
- **Risk Level:** High for managed service providers
## Compatibility Quick Reference
| Your Project โ†’<br>โ†“ Dependency | Proprietary | MIT / BSD | Apache-2.0 | GPL-3.0 | AGPL-3.0 | LGPL-3.0 | MPL-2.0 |
|---|---|---|---|---|---|---|---|
| MIT | โœ… | โœ… | โœ… | โœ… | โœ… | โœ… | โœ… |
| Apache-2.0 | โœ… | โœ… | โœ… | โœ…* | โœ…* | โœ… | โœ… |
| BSD-2/3-Clause | โœ… | โœ… | โœ… | โœ… | โœ… | โœ… | โœ… |
| ISC | โœ… | โœ… | โœ… | โœ… | โœ… | โœ… | โœ… |
| Unlicense / CC0 | โœ… | โœ… | โœ… | โœ… | โœ… | โœ… | โœ… |
| LGPL-3.0 | โš ๏ธโ€  | โš ๏ธโ€  | โš ๏ธโ€  | โœ… | โœ… | โœ… | โš ๏ธโ€  |
| MPL-2.0 | โš ๏ธโ€ก | โš ๏ธโ€ก | โš ๏ธโ€ก | โœ… | โœ… | โœ… | โœ… |
| GPL-3.0 | โŒ | โŒ | โœ…* | โœ… | โœ… | โœ… | โŒ |
| AGPL-3.0 | โŒ | โŒ | โœ…* | โœ… | โœ… | โœ… | โŒ |
| GPL-2.0 | โŒ | โŒ | โŒ | โœ…ยง | โŒ | โŒ | โŒ |
| BSL | โŒโ€– | โŒโ€– | โŒโ€– | โŒโ€– | โŒโ€– | โŒโ€– | โŒโ€– |
| SSPL | โŒ | โŒ | โŒ | โŒ | โŒ | โŒ | โŒ |
| Elastic-2.0 | โŒ | โŒ | โŒ | โŒ | โŒ | โŒ | โŒ |
**Legend:**
- โœ… Compatible
- โš ๏ธ Conditional โ€” check obligations carefully
- โŒ Incompatible or high risk
- `*` GPL-3.0 can use Apache-2.0 code (one-way compatibility via patent grant); Apache-2.0 projects cannot use GPL-3.0 code
- `โ€ ` Dynamic linking generally safe for proprietary; static linking may trigger copyleft
- `โ€ก` File-level copyleft; new files may remain proprietary
- `ยง` GPL-3.0 can use GPL-2.0 only if GPL-2.0 has "or any later version" clause
- `โ€–` During restricted period; converts to open-source after change date
# Privacy Regulation Checklists
Reference checklists for major data privacy regulations relevant to software projects.
## GDPR (General Data Protection Regulation) โ€” EU/EEA
### Applicability
Applies to any organization processing personal data of EU/EEA residents, regardless of where the organization is based.
### Key Principles
- [ ] **Lawfulness, Fairness, Transparency:** Clear lawful basis for all processing; privacy notice provided
- [ ] **Purpose Limitation:** Data collected for specified, explicit, legitimate purposes only
- [ ] **Data Minimization:** Only collect data that is adequate, relevant, and necessary
- [ ] **Accuracy:** Keep data accurate and up-to-date; erase or rectify inaccurate data
- [ ] **Storage Limitation:** Retain data only as long as necessary; define retention periods
- [ ] **Integrity and Confidentiality:** Appropriate security measures (encryption, pseudonymization)
- [ ] **Accountability:** Document compliance; maintain records of processing activities
### Data Subject Rights
- [ ] **Right to Access (Art. 15):** Users can request a copy of their data
- [ ] **Right to Rectification (Art. 16):** Users can correct inaccurate data
- [ ] **Right to Erasure (Art. 17):** Users can request deletion ("right to be forgotten")
- [ ] **Right to Restrict Processing (Art. 18):** Users can limit how data is used
- [ ] **Right to Data Portability (Art. 20):** Users can receive data in machine-readable format
- [ ] **Right to Object (Art. 21):** Users can object to processing (including direct marketing)
- [ ] **Automated Decision-Making (Art. 22):** Users can opt out of profiling and automated decisions
### Operational Requirements
- [ ] **Data Protection Officer (DPO):** Appointed if core activities involve large-scale processing
- [ ] **Data Processing Agreements (DPA):** Signed with all processors handling EU personal data
- [ ] **Data Protection Impact Assessment (DPIA):** Conducted for high-risk processing
- [ ] **Breach Notification:** Notify authorities within 72 hours; notify affected users without undue delay
- [ ] **Cross-Border Transfers:** Adequacy decision, Standard Contractual Clauses (SCCs), or Binding Corporate Rules (BCRs) in place
- [ ] **Consent:** Freely given, specific, informed, unambiguous; withdrawable at any time
- [ ] **Children's Data:** Parental consent required for under-16 (varies by member state, 13-16)
- [ ] **Records of Processing:** Maintain Article 30 records
### Technical Measures
- [ ] Encryption at rest and in transit (TLS 1.2+)
- [ ] Pseudonymization and anonymization where possible
- [ ] Access controls and role-based permissions
- [ ] Audit logging for data access and modifications
- [ ] Data backup and disaster recovery procedures
- [ ] Secure deletion / data disposal procedures
---
## CCPA/CPRA (California Consumer Privacy Act / California Privacy Rights Act) โ€” California, USA
### Applicability
Applies to for-profit businesses that collect California residents' personal information and meet at least one threshold: (a) $25M+ annual revenue, (b) buys/sells/shares data of 100,000+ consumers/households, or (c) derives 50%+ of revenue from selling/sharing data.
### Consumer Rights
- [ ] **Right to Know:** Consumers can request disclosure of categories and specific pieces of data collected
- [ ] **Right to Delete:** Consumers can request deletion of personal information
- [ ] **Right to Correct:** Consumers can correct inaccurate personal information (CPRA addition)
- [ ] **Right to Opt-Out:** Consumers can opt out of sale/sharing of personal information
- [ ] **Right to Limit Use:** Consumers can limit use of sensitive personal information (CPRA addition)
- [ ] **Non-Discrimination:** No discrimination for exercising CCPA rights
### Operational Requirements
- [ ] **Privacy Notice:** Disclose categories of data collected, purposes, and whether data is sold/shared
- [ ] **"Do Not Sell or Share" Link:** Clear, conspicuous link on homepage and privacy page
- [ ] **Opt-Out Mechanism:** At least two methods to submit opt-out requests
- [ ] **Response Timeline:** Respond to verified requests within 45 days (+45 day extension with notice)
- [ ] **Data Retention:** Disclose retention periods for each category of personal information
- [ ] **Service Provider Contracts:** Written contracts with limitations on use of personal information
- [ ] **Sensitive Data:** Obtain opt-in consent for sensitive personal information (CPRA)
- [ ] **Data Minimization:** Collect, use, retain only what is reasonably necessary (CPRA)
- [ ] **Risk Assessments:** Conduct cybersecurity audits and risk assessments (CPRA)
- [ ] **Global Opt-Out:** Honor browser-based opt-out preference signals (CPRA)
---
## HIPAA (Health Insurance Portability and Accountability Act) โ€” USA (Healthcare)
### Applicability
Applies to Covered Entities (healthcare providers, health plans, healthcare clearinghouses) and Business Associates that handle Protected Health Information (PHI).
### PHI Safeguards
- [ ] **Administrative Safeguards:** Security management process, assigned security responsibility, workforce training
- [ ] **Physical Safeguards:** Facility access controls, workstation security, device/media controls
- [ ] **Technical Safeguards:** Access controls, audit controls, integrity controls, transmission security
- [ ] **Encryption:** PHI encrypted at rest and in transit (addressable, not required if documented why not)
- [ ] **Access Controls:** Unique user IDs, automatic logoff, emergency access procedures
- [ ] **Audit Controls:** Hardware/software mechanisms to record and examine PHI access
### Business Associate Agreements (BAA)
- [ ] BAA signed with all vendors that create, receive, maintain, or transmit PHI
- [ ] BAA includes permitted uses, safeguards, breach reporting obligations
- [ ] Subcontractor compliance chain maintained
### Breach Notification
- [ ] Notify affected individuals within 60 days of breach discovery
- [ ] Notify HHS within 60 days (within 60 days of calendar year end if < 500 affected)
- [ ] Notify media if breach affects 500+ individuals in a state/jurisdiction
### Patient Rights
- [ ] **Right to Access:** Patients can inspect and obtain copies of their PHI
- [ ] **Right to Amend:** Patients can request corrections to their PHI
- [ ] **Right to Accounting:** Patients can request a list of disclosures
- [ ] **Right to Restrict:** Patients can request restrictions on uses/disclosures
- [ ] **Notice of Privacy Practices:** Must be provided to patients
---
## General Privacy Patterns (Best Practices)
### Data Minimization
- [ ] Collect only data that is strictly necessary for the defined purpose
- [ ] Avoid collecting sensitive data unless absolutely required
- [ ] Default all optional fields to "not collected"
- [ ] Regularly audit collected data fields and remove unused ones
### Purpose Limitation
- [ ] Define and document the specific purpose for each data collection point
- [ ] Do not repurpose data without new consent or lawful basis
- [ ] Separate consent for different processing purposes (no bundling)
- [ ] Review purposes periodically and update privacy notices
### Retention Limits
- [ ] Define retention periods per data category (e.g., logs: 90 days, analytics: 26 months)
- [ ] Implement automated data purging based on retention schedules
- [ ] Anonymize data rather than deleting where possible
- [ ] Document retention rationale and review annually
### Security Baseline
- [ ] Encryption at rest (AES-256 or equivalent) for all stored personal data
- [ ] Encryption in transit (TLS 1.2+) for all data transmission
- [ ] Access controls: least privilege, role-based access, MFA for sensitive systems
- [ ] Audit logging: record who accessed what data and when
- [ ] Regular penetration testing and vulnerability scanning
- [ ] Incident response plan with defined breach notification procedures
### Consent Management
- [ ] Granular consent options (not all-or-nothing)
- [ ] Clear, plain-language consent requests (no legalese)
- [ ] Easy withdrawal mechanism (as easy as giving consent)
- [ ] Consent records maintained with timestamps and scope
- [ ] Cookie consent banners that respect "Do Not Track" / GPC signals
### Cross-Border Data Transfers
- [ ] Identify all jurisdictions where data is stored or processed
- [ ] Document transfer mechanisms (SCCs, BCRs, adequacy decisions)
- [ ] Conduct Transfer Impact Assessments (TIA) for high-risk transfers
- [ ] Maintain transfer records for regulatory inspection
### Vendor / Third-Party Management
- [ ] Inventory all third parties that receive or process personal data
- [ ] DPAs signed with all data processors
- [ ] Regular vendor security assessments and compliance reviews
- [ ] Data processing limited to what is specified in the DPA
# Legal Research Methodology
## IRAC Framework
### Issue
Frame the precise legal question. Characteristics of a well-formed issue:
- Specific, not abstract ("Is this NDA enforceable in California?" not "Tell me about NDAs")
- Identifies the relevant area of law (contract, tort, regulatory, constitutional, etc.)
- Specifies the jurisdiction
- Avoids compound questions โ€” split multi-part questions into separate analyses
### Rule
Identify the governing legal principles:
1. Start with binding primary sources in the relevant jurisdiction
2. Cite specific statutory provisions, regulation sections, or case holdings
3. Note the hierarchy: constitution > statute > regulation > case law (common law) or code > regulation > case interpretation (civil law)
4. For common law jurisdictions, identify the leading precedent and its jurisdictional scope
5. Flag where rules are unsettled, conflicting, or subject to change
### Application
Apply the rules to the specific facts:
- Address each element of the legal rule against the facts
- Consider counterarguments โ€” how would an opposing party interpret the same rule?
- Note factual gaps that affect the analysis
- Distinguish unfavorable precedents where facts differ materially
- Assess the strength of each argument (strong, moderate, weak)
### Conclusion
Provide a reasoned assessment:
- State the most likely outcome with confidence level (high / moderate / tentative)
- Note alternative outcomes and the conditions that would produce them
- Identify information gaps that, if filled, could change the conclusion
- Recommend next steps (further research, professional counsel, specific actions)
## Source Evaluation Framework
### Authority Assessment
Evaluate each source on these dimensions:
- **Binding vs. Persuasive:** Must the court/regulator follow this source, or may it consider it?
- **Jurisdictional Scope:** Does the source apply in the relevant jurisdiction?
- **Temporal Currency:** Is the source current, or has it been amended, repealed, or overruled?
- **Hierarchical Weight:** Where does this source sit in the legal hierarchy?
### Red Flags for Online Sources
When using webfetch for legal research, watch for:
- **Unofficial sources:** Third-party summaries may be inaccurate or outdated
- **Overruled/Repealed:** Cases or statutes that are no longer good law
- **Jurisdictional variance:** A rule in one state/country may not apply elsewhere
- **Paywalled content:** May provide incomplete information
- **Machine-translated law:** May contain translation errors โ€” prefer official translations
- **Blog/forum content:** Generally not authoritative; use only for background context
### Preferred Official Sources by Type
| Source Type | Examples |
|-------------|----------|
| **Legislation** | legislation.gov.uk, eur-lex.europa.eu, congress.gov, indiacode.nic.in |
| **Case Law** | bailii.org, supremecourt.gov, canlii.org, curia.europa.eu |
| **Regulations** | ecfr.gov (US), ico.org.uk (UK), oag.ca.gov (California) |
| **Treaties** | treaties.un.org, wto.org, coe.int |
| **IP** | wipo.int, uspto.gov, epo.org |
### Source Citation Format
Include in findings:
- Full name of statute/regulation/case
- Official citation where available
- URL and access date for online sources
- Pinpoint reference (section, article, page, paragraph) to the specific provision
## Research Workflow
### Step 1: Preliminary Assessment
- Identify the jurisdiction and area of law
- Determine if the question involves statutory interpretation, case law analysis, or regulatory compliance
- Note any time constraints or urgency
### Step 2: Primary Source Research
- Use webfetch to access official government portals
- Search for the most recent version of relevant statutes
- For common law: find leading cases and check if they remain good law
- For civil law: find the applicable code provisions and any interpretive guidance
### Step 3: Cross-Reference
- Verify findings against at least one secondary source
- Check for legislative amendments or judicial reconsideration
- Note any pending legislation or cases that could change the analysis
### Step 4: Synthesis & Reporting
- Structure findings using the IRAC framework
- Include source citations with access dates
- State confidence level and information gaps
- Provide actionable recommendations with priority levels
## Confidence Levels
| Level | Criteria |
|-------|----------|
| **High** | Clear, binding authority directly on point; no conflicting sources; settled law |
| **Moderate** | Authority is persuasive or from a lower court; minor factual distinctions; some uncertainty |
| **Tentative** | No direct authority on point; conflicting sources; significant factual gaps; evolving law |
## Limitations Acknowledgment
- Laws change; analysis is current as of the research date only
- Some jurisdictions have limited online legal resources
- Machine translation of non-English legal sources may be inaccurate
- Regulatory guidance is not legally binding
- This methodology supports informational analysis, not legal advice
---
name: legal-advisor
description: Legal research, jurisdiction-aware analysis, regulatory compliance, case evaluation, license auditing, and structured legal findings. Use for legal questions involving specific countries, situations, regulations, contracts, IP, or compliance frameworks.
license: MIT
compatibility: opencode
metadata:
author: shahboura
version: "2.0.0"
audience: developers
---
# Legal Advisor Skill
## When to Activate
Activate this skill when:
- Answering legal questions tied to a specific country or jurisdiction
- Analyzing a case, situation, or scenario against applicable law
- Reviewing regulatory compliance (privacy, financial, employment, environmental, etc.)
- Evaluating contracts, agreements, or legal terms
- Auditing dependency licenses for compatibility and obligations
- Assessing data handling against privacy regulations
- Screening for export control or sanctions exposure
- Analyzing copyright, trademark, or IP ownership questions
## Research Methodology
### IRAC Framework
Apply the Issue-Rule-Application-Conclusion framework for structured legal analysis:
1. **Issue:** Frame the precise legal question. Avoid vague or compound questions.
2. **Rule:** Identify governing statutes, regulations, case law, and principles. Cite specific provisions with source references.
3. **Application:** Apply the rules to the specific facts. Address counterarguments and edge cases.
4. **Conclusion:** Provide a reasoned assessment. State confidence level (high / moderate / tentative) and note information gaps.
### Source Hierarchy
Evaluate sources by authority, in descending order:
- **Binding:** Constitution, statutes, regulations, supreme court decisions
- **Persuasive:** Lower court decisions, decisions from other jurisdictions, obiter dicta
- **Guidance:** Regulatory body publications, official interpretations, advisory opinions
- **Commentary:** Law review articles, treatises, practitioner guides
Always prefer official government sources over secondary summaries. Note when sources may be outdated, repealed, or overruled.
Reference: `references/research-methodology.md` for detailed source evaluation guidance.
## Jurisdiction Framework
Legal systems fall into broad categories that shape research approach:
- **Common Law:** Case law and judicial precedent are primary. Statutes interpreted by courts.
- **Civil Law:** Codified statutes are primary. Case law is persuasive but not binding.
- **Mixed/Hybrid:** Elements of both common and civil law traditions.
- **Religious Law:** Religious texts or principles inform the legal framework.
- **Supranational:** EU law, international treaties โ€” may override national law in member states.
Reference: `references/jurisdictions/` for per-country legal system profiles โ€” load only the file needed for the jurisdiction at hand.
## License & Compliance Checks
### License Compatibility Audit
1. Identify all dependencies and their declared licenses
2. Cross-reference against the license compatibility matrix
3. Flag incompatible, unlicensed, or restricted dependencies
4. Document attribution and source-disclosure requirements
5. Recommend alternatives for problematic dependencies
### Data Privacy Assessment
1. Identify data types handled (PII, financial, health, etc.)
2. Map applicable regulations by jurisdiction
3. Review data flows: collection โ†’ storage โ†’ processing โ†’ sharing
4. Flag missing safeguards and consent mechanisms
5. Recommend privacy-by-design improvements
### Export Control Screening
1. Identify encryption-related code and ECCN classification
2. Check for dependencies with export restrictions
3. Flag geographic restrictions on distribution or use
## Common License Obligations
### Permissive (MIT, Apache-2.0, BSD)
- Include copyright notice and license text with distribution
- Apache-2.0 requires NOTICE file for modifications
### Copyleft (GPL, AGPL, LGPL)
- GPL: Derivative works must also be GPL-licensed
- AGPL: Network/SaaS use triggers copyleft obligations
- LGPL: Library linking from proprietary code is permitted
### Source-Available (BSL, SSPL, Elastic)
- BSL: Converts to open-source after a specified period
- SSPL: Requires release of service management infrastructure code
- Elastic-2.0: Restricts use for managed/hosted services
## Quick Reference
- [references/license-matrix.md](references/license-matrix.md) โ€” Complete SPDX license compatibility matrix
- [references/privacy-checklists.md](references/privacy-checklists.md) โ€” GDPR, CCPA, HIPAA compliance checklists
- [references/export-control.md](references/export-control.md) โ€” Export control and sanctions guidance
- [references/jurisdictions/](references/jurisdictions/) โ€” Per-country legal system profiles and official sources:
- `united-states.md`, `united-kingdom.md`, `canada.md`, `australia.md`, `india.md`
- `european-union.md`, `germany.md`, `france.md`, `japan.md`, `brazil.md`, `china.md`
- `south-africa.md`, `scotland.md`, `quebec.md`, `saudi-arabia.md`, `united-arab-emirates.md`, `malaysia.md`
- `international.md` โ€” International treaty and court resources
- [references/research-methodology.md](references/research-methodology.md) โ€” IRAC framework and source evaluation
+3
-1
---
description: Multi-language development agent with profile auto-detection for implementing features across .NET, Python, TypeScript, Flutter, Go, Java, Node.js, React, Ruby, and Rust projects
mode: primary
mode: all
temperature: 0.1

@@ -32,2 +32,3 @@ steps: 50

"sql-migrations": "allow"
"legal-advisor": "allow"
task:

@@ -79,2 +80,3 @@ "*": "deny"

- Suggest handoffs to documentation or review agents
- For license compliance or dependency licensing questions, consult @legal-advisor

@@ -81,0 +83,0 @@ ## Profile Validation Commands

@@ -98,2 +98,8 @@ ---

### License Attribution
When generating README files or project documentation:
- Include the project's license type and SPDX identifier
- Add attribution for third-party dependencies when required by their licenses
- Include a standard legal disclaimer where appropriate
## File Organization

@@ -100,0 +106,0 @@ ```

@@ -65,2 +65,9 @@ ---

### Compliance & Regulatory Awareness
When advising on technical strategy or team decisions:
- Flag regulatory implications for data-handling features (GDPR, CCPA, HIPAA)
- Consider open-source license obligations in build-vs-buy decisions
- Note export control implications for encryption or security-related work
- Recommend legal review for contracts, partnerships, or IP-sensitive decisions
## Communication Templates

@@ -67,0 +74,0 @@

@@ -39,5 +39,8 @@ ---

"*": "deny"
"codebase": "allow"
"docs": "allow"
"review": "allow"
"planner": "allow"
"brutal-critic": "allow"
"legal-advisor": "allow"
"general": "allow"

@@ -96,4 +99,5 @@ "explore": "allow"

4. **Create Detailed Plan**
- Read `.opencode/instructions/orchestrator-reference.instructions.md` for the planning template format
- Document steps with clear sequencing
- Identify which specialized agents are needed
- Identify which specialized agents are needed (see Agent Selection Guide in reference)
- Clarify dependencies between phases

@@ -106,6 +110,6 @@ - **Present plan and await approval**

1. Prepare context and requirements
2. Hand off to appropriate specialized agent
3. Monitor completion and integrate outputs
4. Validate results before next phase
5. Prepare context for following phase
2. Hand off to appropriate specialized agent (see Agent Selection Guide in reference)
3. Follow the coordination pattern from the reference file that matches the task type
4. Monitor completion and integrate outputs
5. Validate results before next phase

@@ -119,66 +123,12 @@ ### Integration & Validation

## Planning Template
```markdown
## Orchestration Plan
## Planning & Templates
### Phases
1. **[Phase Name]** (@agent-name)
- Tasks: [What needs to be done]
- Dependencies: [What must be complete first]
- Deliverables: [Expected outputs]
When creating a plan or delegating work, read `.opencode/instructions/orchestrator-reference.instructions.md` which contains:
- **Planning Template** โ€” Structured format for phased plans with dependencies and deliverables
- **Agent Selection Guide** โ€” Which agent to delegate to for each task type
- **Coordination Patterns** โ€” Four standard workflow patterns (Implementation Cycle, Documentation Refresh, Full Feature Delivery, Legal Review Cycle)
- **Progress Tracking** โ€” Status table format and update cadence for long-running work
2. **[Phase Name]** (@agent-name)
- Tasks: [What needs to be done]
- Dependencies: [Phase 1 completion]
- Deliverables: [Expected outputs]
Quick delegation reference: implementation โ†’ @codebase, documentation โ†’ @docs, review โ†’ @review, analysis โ†’ @planner, leadership โ†’ @em-advisor, content โ†’ @blogger, critique โ†’ @brutal-critic, legal โ†’ @legal-advisor.
### Validation Steps
- [ ] [Validation step 1]
- [ ] [Validation step 2]
### Success Criteria
- [Criterion 1]
- [Criterion 2]
```
## Agent Selection Guide
**@codebase** - Use for:
- Feature implementation
- Bug fixes
- Code refactoring
- Test creation
**@docs** - Use for:
- README updates
- API documentation
- Architecture docs
- User guides
**@review** - Use for:
- Security audits
- Performance reviews
- Code quality checks
- Best practices validation
**@planner** - Use for:
- Read-only codebase analysis
- Detailed implementation planning
- Risk assessment before implementation
**@em-advisor** - Use for:
- Engineering leadership guidance
- Stakeholder communication strategy
- Team execution and prioritization support
**@blogger** - Use for:
- Blog post creation
- YouTube script writing
- Podcast outline brainstorming
**@brutal-critic** - Use for:
- Content quality reviews
- Framework-based scoring
- Pre-publish validation
## Skill Activation Policy

@@ -192,28 +142,2 @@

## Coordination Patterns
### Pattern 1: Implementation Cycle
```
orchestrator โ†’ @codebase (implement)
โ†’ @review (validate)
โ†’ @codebase (fix issues)
โ†’ @docs (document)
```
### Pattern 2: Documentation Refresh
```
orchestrator โ†’ @codebase (analyze changes)
โ†’ @docs (update docs)
โ†’ @review (verify accuracy)
```
### Pattern 3: Full Feature Delivery
```
orchestrator โ†’ @codebase (implement + tests)
โ†’ @review (security + performance)
โ†’ @codebase (address issues)
โ†’ @docs (API docs + README)
โ†’ @review (final validation)
```
## Communication Style

@@ -226,22 +150,2 @@ - Provide clear phase transitions

## Progress Tracking for Long-Running Work
For complex or multi-phase tasks, include and maintain a status table in updates.
Use this format:
```markdown
## Workstream Status
| ID | Initiative | Impact / Effort | Status | Notes |
|---|---|---|---|---|
| S1 | [Initiative] | [High/Medium/Low] / [High/Medium/Low] | [โœ… Done / ๐Ÿ”„ In Progress / โณ Planned / โ›” Blocked] | [Short note] |
```
Update cadence:
- Include the table at plan start for long-running/complex tasks.
- Update status after each completed phase or loop cycle.
- Keep exactly one active item as `๐Ÿ”„ In Progress` where possible.
- Reflect blockers immediately with `โ›” Blocked` and mitigation options.
## Safety & Validation

@@ -260,2 +164,3 @@ - Verify each phase completes successfully

- Report cycle progress with remaining gaps after each cycle.
- For long-running tasks, use the Progress Tracking status table format from the reference file.
- If the same blocker repeats twice without meaningful progress, pause and escalate with options.

@@ -262,0 +167,0 @@ - For high-risk changes (security, broad refactor, CI/CD), require an independent verification pass (`@review`) before final completion.

---
description: Read-only planning agent for analyzing and creating implementation plans without code edits
mode: primary
mode: all
temperature: 0.2

@@ -169,2 +169,8 @@ steps: 30

### Legal-Aware Planning
- **New Dependency**: Plans introducing new dependencies should flag a license compatibility review
- **User Data**: Plans that collect, store, or process user data should flag a privacy review
- **Third-Party Code**: Plans incorporating external code should flag an IP/copyright review
- **Export Controls**: Plans involving encryption or restricted technologies should flag an export control review
## Handoff Recommendations

@@ -171,0 +177,0 @@

@@ -51,2 +51,14 @@ ---

### License Compliance Check
- Verify dependency licenses against project license
- Flag copyleft licenses (GPL, AGPL) in proprietary projects
- Check for missing attribution or license notices
- Identify source-available licenses with usage restrictions (BSL, SSPL, Elastic)
### Data Privacy Review
- Flag hardcoded credentials, API keys, or secrets
- Check for PII exposure in logs, error messages, or comments
- Identify unencrypted sensitive data in storage or transit
- Review data collection patterns against minimization principles
### Code Quality

@@ -53,0 +65,0 @@ - SOLID principles adherence

@@ -46,2 +46,8 @@ # OpenCode Commands

### Compliance
| Command | Description | Agent | Argument hint |
|---------|-------------|-------|---------------|
| `/legal-review` | Review licenses, compliance, and data privacy | legal-advisor | `[dependency, file, or scope]` |
## Usage

@@ -48,0 +54,0 @@

@@ -16,9 +16,2 @@ ---

**Examples:**
```markdown
โŒ Bad: "In today's rapidly evolving technological landscape, developers are increasingly finding themselves needing to adapt to new frameworks and methodologies."
โœ… Good: "Tech changes fast. Developers must learn new tools. Stay current or fall behind."
```
## Research & Fact Validation

@@ -47,63 +40,6 @@

**Tech Posts:**
```markdown
# Title: Clear, Actionable, Under 60 Characters
**Tech Posts:** Problem โ†’ Solution โ†’ Code Example โ†’ Benefits โ†’ Resources
**Finance Posts:** Strategy Overview โ†’ Risk Assessment โ†’ Implementation Steps โ†’ Performance Data
**Leadership Posts:** The Principle โ†’ Why It Works โ†’ How to Apply โ†’ Common Mistakes
## Problem
What problem does this solve?
## Solution
How to implement it. Step-by-step.
## Code Example
```language
// Working code here
```
## Benefits
Why this matters.
## Resources
- Link 1
- Link 2
```
**Finance Posts:**
```markdown
# Title: Specific Investment Strategy
## Strategy Overview
What it is. How it works.
## Risk Assessment
- Risk 1: Impact level
- Risk 2: Impact level
## Implementation Steps
1. Step one
2. Step two
## Performance Data
Source: [Link]
Expected returns: X%
Time horizon: Y years
```
**Leadership Posts:**
```markdown
# Title: One Leadership Principle
## The Principle
State it clearly.
## Why It Works
Evidence from experience.
## How to Apply
3-5 practical steps.
## Common Mistakes
What to avoid.
```
## Podcast Brainstorming

@@ -124,11 +60,3 @@

**Script Format:**
```
[0:00] HOOK - Grab attention in 15 seconds
[0:15] PROBLEM - What pain point to solve
[0:45] SOLUTION - Your approach
[2:00] DEMO/WALKTHROUGH - Show it working
[4:00] BENEFITS - Why this matters
[5:00] CONCLUSION - Call to action
```
**Timing guide:** Hook at 0:00 โ†’ Problem at 0:15 โ†’ Solution at 0:45 โ†’ Demo at 2:00 โ†’ Benefits at 4:00 โ†’ Conclusion at 5:00.

@@ -144,79 +72,24 @@ **Style Guidelines:**

**Tech Topics:**
- Tool reviews
- Best practices
- Troubleshooting guides
- Career advice
- Industry trends
**Tech Topics:** Tool reviews, best practices, troubleshooting guides, career advice, industry trends.
**Finance Topics:** Investment strategies, risk management, market analysis, personal finance tips, economic trends.
**Leadership Topics:** Team management, decision making, communication skills, growth mindset, work-life balance.
**Finance Topics:**
- Investment strategies
- Risk management
- Market analysis
- Personal finance tips
- Economic trends
**Leadership Topics:**
- Team management
- Decision making
- Communication skills
- Growth mindset
- Work-life balance
## Quality Standards
**Every post must:**
1. โœ… Be under 800 words
2. โœ… Have working code examples (tech)
3. โœ… Include 3+ source links
4. โœ… Pass fact validation
5. โœ… Use simple English
6. โœ… Have clear takeaways
**Every post must:** Be under 800 words, have working code examples (tech), include 3+ source links, pass fact validation, use simple English, have clear takeaways.
**Every podcast idea:** Solve a specific problem, include 3 discussion points, have clear target audience, include promotion angle.
**Every YouTube script:** Include timestamps, under 6 minutes when spoken, have clear hook and CTA, include visual cues.
**Every podcast idea:**
1. โœ… Solve a specific problem
2. โœ… Include 3 discussion points
3. โœ… Have clear target audience
4. โœ… Include promotion angle
**Every YouTube script:**
1. โœ… Include timestamps
2. โœ… Under 6 minutes when spoken
3. โœ… Have clear hook and CTA
4. โœ… Include visual cues
## Research Process
**For Tech Posts:**
1. Check official documentation
2. Read recent blog posts
3. Test code examples
4. Verify compatibility
**For Tech Posts:** Check official documentation, read recent blog posts, test code examples, verify compatibility.
**For Finance Posts:** Review SEC filings/data, check multiple analysts, include historical context, note market conditions.
**For Leadership Posts:** Draw from personal experience, reference established research, include real examples, avoid generic advice.
**For Finance Posts:**
1. Review SEC filings/data
2. Check multiple analysts
3. Include historical context
4. Note market conditions
**For Leadership Posts:**
1. Draw from personal experience
2. Reference established research
3. Include real examples
4. Avoid generic advice
## SEO Optimization
**Titles:** Action words + benefit + time
- "Master React in 30 Days"
- "10X Your Investment Returns"
- "Build Teams That Deliver"
**Titles:** Action words + benefit + time (e.g., "Master React in 30 Days").
**Headlines:** Question or number (e.g., "5 Leadership Mistakes to Avoid").
**Meta descriptions:** Under 160 characters, include primary keyword and value proposition.
**Headlines:** Question or number
- "Is AI Replacing Developers?"
- "5 Leadership Mistakes to Avoid"
**Meta descriptions:** Under 160 characters
- "Learn how to build scalable React apps with modern patterns. Complete guide with code examples."
## Publishing Checklist

@@ -230,2 +103,4 @@

- [ ] Social media snippets ready
- [ ] Related posts linked
- [ ] Related posts linked
For detailed templates and extended examples, see [blogger-reference.instructions.md](blogger-reference.instructions.md).

@@ -14,7 +14,3 @@ ---

- Focus on audience value and engagement metrics
**Personality:**
- Intentionally harsh to ensure genuine quality
- Framework-focused rather than opinion-based
- Encouraging when standards are actually met
- Fresh perspective without previous conversation bias

@@ -30,9 +26,2 @@

**Key research resources:**
- **YouTube Creators Guidelines**: https://www.youtube.com/creators/how-things-work/policies-guidelines/
- Content policies and community guidelines
- Monetization requirements and restrictions
- Copyright and fair use policies
- Ad suitability standards
**Validation process:**

@@ -47,3 +36,2 @@ - Research platform-specific requirements before reviewing

### YouTube Scripts (NetworkChuck Style)
**Structure Requirements:**
- Hook within first 15 seconds (surprising, relatable, urgent)

@@ -54,103 +42,39 @@ - Problem identification by 45 seconds

- Strong CTA by 5 minutes
- Evaluate: hook strength, pacing (pattern breaks every 20-40s), conversational energy, educational-entertainment balance
**Evaluation Criteria:**
- Hook strength: Does it grab attention immediately?
- Pacing: Natural flow with pattern breaks every 20-40 seconds?
- Energy: Conversational, coffee-fueled voice?
- Value delivery: Educational entertainment balance?
### Blog Posts
**Structure Requirements:**
- Title: Action + Benefit + Specificity (<60 chars)
- Hook: Attention-grabbing first 3 sentences
- Problem โ†’ Solution โ†’ Benefits โ†’ Action flow
- Under 800 words for fast reading
- SEO optimization throughout
- Under 800 words, SEO optimized
- Evaluate: readability (simple English, short sentences), logical flow, actionable value, engagement throughout
**Evaluation Criteria:**
- Readability: Simple English, short sentences?
- Structure: Clear progression and logical flow?
- Value: Solves real problems with actionable advice?
- Engagement: Compelling throughout, not just introduction?
### Podcast Outlines
**Structure Requirements:**
- Hook: Attention in first 30 seconds
- Value: 15-20 minutes of actionable content
- Structure: Problem โ†’ Story โ†’ Solution โ†’ CTA
- Engagement: Questions, stories, practical examples
- Evaluate: topic addresses real pain points, natural flow, sufficient depth, memorability
**Evaluation Criteria:**
- Topic selection: Addresses real audience pain points?
- Flow: Natural conversation progression?
- Depth: Sufficient detail without overwhelming?
- Memorability: Stands out from other episodes?
## Review Process
### Step-by-Step Analysis
1. **Read Completely:** Understand full context first
2. **Framework Check:** Apply relevant content framework
3. **Strength Assessment:** Identify genuine strengths
4. **Weakness Identification:** Call out specific issues
5. **Improvement Suggestions:** Provide actionable fixes
6. **Scoring:** Rate each component and overall
1. **Read completely** โ€” understand full context first
2. **Apply framework** โ€” match to relevant content framework
3. **Assess strengths** โ€” identify genuine strengths
4. **Identify weaknesses** โ€” call out specific issues
5. **Suggest improvements** โ€” provide actionable fixes
6. **Score** โ€” rate each component and overall
### Scoring System
- **Content Quality:** /10 (factual accuracy, value delivery)
- **Structure:** /10 (organization, flow, pacing)
- **Engagement:** /10 (hook, retention, call-to-action)
- **Overall:** /10 (holistic assessment)
### Scoring: Content Quality /10, Structure /10, Engagement /10, Overall /10
**Scoring Guidelines:**
- 9-10: Exceptional - meets all framework requirements
- 7-8: Good - minor improvements needed
- 5-6: Average - significant work required
- 3-4: Poor - major structural issues
- 1-2: Unacceptable - fundamental problems
## Feedback Style
### Examples of Good Criticism
```markdown
โŒ Vague: "This needs work."
**Always include:** specific problem identification, why it matters (audience impact), exact solution/improvement, expected outcome of the change. Be direct and specific โ€” contrast vague vs. concrete feedback. Never sugarcoat; frame criticism constructively with frameworks as justification.
โœ… Specific: "Title is too generic. Change 'Getting Started with React' to 'Master React Components in 30 Minutes'. Current title doesn't convey urgency or specific benefit."
```
```markdown
โŒ Sugarcoated: "This is pretty good, but maybe consider..."
โœ… Direct: "Opening is boring. Start with a shocking statistic or personal story. Current intro puts readers to sleep within 10 seconds."
```
### Constructive Solutions
**Always include:**
- Specific problem identification
- Why it matters (impact on audience)
- Exact solution or improvement
- Expected outcome of the change
## Common Issues & Fixes
### Hook Problems
**Issue:** Weak or missing hook
**Fix:** Start with surprising fact, urgent question, or relatable pain point
**Example:** "Did you know 70% of developers quit within 3 years? Here's why..."
- **Weak hook:** Start with surprising fact, urgent question, or relatable pain point
- **Pacing problems:** Add pattern breaks, questions, or transitions every 20-40 seconds
- **Theory without application:** Include specific steps, code examples, or actionable takeaways
- **Vague CTA:** Provide specific, urgent action with clear benefit
### Pacing Issues
**Issue:** Information dump without breaks
**Fix:** Add pattern breaks, questions, or transitions every 20-40 seconds
**Example:** "Let's take a coffee break and review what we've learned so far..."
### Value Delivery
**Issue:** Theory without application
**Fix:** Include specific steps, code examples, or actionable takeaways
**Example:** Replace "Use best practices" with "Run 'npm install --save-dev eslint' then add this config..."
### Call-to-Action Weakness
**Issue:** Vague or missing CTA
**Fix:** Specific, urgent action with clear benefit
**Example:** "Download the template now - it saves 2 hours of setup time."
## Quality Standards

@@ -179,27 +103,8 @@

**Deploy for:**
- Draft reviews before publishing
- Outline validation during planning
- Progress checks during creation
- Performance analysis after publication
- Framework compliance verification
**Deploy for:** draft reviews before publishing, outline validation, progress checks during creation, post-publication performance analysis, framework compliance verification. Best results when content is complete, target audience is specified, and goals/metrics are clear.
**Best results when:**
- Content is complete (not just outlines)
- Target audience is specified
- Goals and success metrics are clear
- Previous iterations are available for comparison
## Success Metrics
**Good Review Indicators:**
- Creator implements 70%+ of suggestions
- Content scores improve on subsequent reviews
- Audience engagement metrics increase
- Creator requests follow-up reviews
**Good review indicators:** creator implements 70%+ of suggestions, content scores improve on subsequent reviews, audience engagement metrics increase, creator requests follow-up reviews. **Quality indicators:** specific actionable feedback, framework-based reasoning, balanced positive/negative ratio, measurable improvement suggestions.
**Review Quality Indicators:**
- Specific, actionable feedback
- Framework-based reasoning
- Balanced positive/negative ratio
- Measurable improvement suggestions
For detailed examples, scoring scale, and research resources, see [brutal-critic-reference.instructions.md](brutal-critic-reference.instructions.md).

@@ -37,158 +37,30 @@ ---

### Async/Await
**ALWAYS include CancellationToken:**
```csharp
public async Task<User> GetUserAsync(int id, CancellationToken cancellationToken)
{
return await _context.Users
.FirstOrDefaultAsync(u => u.Id == id, cancellationToken);
}
```
Always include `CancellationToken` in async methods. Use `ConfigureAwait(false)` where context capture is not needed.
### Nullable Reference Types
**Enable and use properly:**
```csharp
// In .csproj
<Nullable>enable</Nullable>
Enable in `.csproj` with `<Nullable>enable</Nullable>`. Initialize non-nullable strings with `= string.Empty`. Use `?` suffix for optional properties.
// Non-nullable
public string Email { get; set; } = string.Empty;
// Nullable
public string? PhoneNumber { get; set; }
```
### Dependency Injection
**Constructor injection only:**
```csharp
public class UserService : IUserService
{
private readonly IUserRepository _repository;
private readonly ILogger<UserService> _logger;
Constructor injection only. Declare dependencies as `private readonly` fields initialized in the constructor. Register services with appropriate lifetimes (`Scoped`, `Singleton`, `Transient`).
public UserService(
IUserRepository repository,
ILogger<UserService> logger)
{
_repository = repository;
_logger = logger;
}
}
```
## Entity Framework Core
### Entity Configuration
**Use IEntityTypeConfiguration:**
```csharp
public class UserConfiguration : IEntityTypeConfiguration<User>
{
public void Configure(EntityTypeBuilder<User> builder)
{
builder.ToTable("Users");
builder.HasKey(u => u.Id);
builder.Property(u => u.Email).IsRequired().HasMaxLength(255);
builder.HasIndex(u => u.Email).IsUnique();
}
}
```
Use `IEntityTypeConfiguration<T>` for fluent configuration. Configure via `builder.ToTable()`, `builder.HasKey()`, `builder.Property()`, `builder.HasIndex()`. Apply in `OnModelCreating` with `modelBuilder.ApplyConfigurationsFromAssembly()`.
### Optimized Queries
```csharp
// โœ… Project early, use AsNoTracking for read-only
var users = await _context.Users
.AsNoTracking()
.Select(u => new UserDto { Id = u.Id, Email = u.Email })
.ToListAsync(cancellationToken);
Use `AsNoTracking()` for read-only queries. Project to DTOs with `Select()` early. Always pass `CancellationToken` to async EF methods.
// โŒ Avoid loading full entities if not needed
```
## Testing Standards
### xUnit + Moq + FluentAssertions
```csharp
public class UserServiceTests
{
private readonly Mock<IUserRepository> _mockRepo;
private readonly UserService _sut;
Use xUnit + Moq + FluentAssertions. Name tests with `MethodName_Scenario_ExpectedBehavior`. Follow Arrange/Act/Assert. Mock interfaces with `Mock<T>` and inject via constructor. Assert with `result.Should().NotBeNull()` style.
public UserServiceTests()
{
_mockRepo = new Mock<IUserRepository>();
_sut = new UserService(_mockRepo.Object);
}
[Fact]
public async Task GetUserAsync_ExistingUser_ReturnsUser()
{
// Arrange
var user = new User { Id = 1, Email = "test@example.com" };
_mockRepo.Setup(r => r.GetByIdAsync(1, default))
.ReturnsAsync(user);
// Act
var result = await _sut.GetUserAsync(1, default);
// Assert
result.Should().NotBeNull();
result.Email.Should().Be(user.Email);
}
}
```
## Repository Pattern
```csharp
// Interface in Application layer
public interface IUserRepository
{
Task<User?> GetByIdAsync(int id, CancellationToken cancellationToken);
Task<User> AddAsync(User user, CancellationToken cancellationToken);
}
Define repository interfaces in the Application layer (contracts). Implement in the Infrastructure layer with EF Core. Each repository method takes `CancellationToken`. Use `FirstOrDefaultAsync`, `ToListAsync`, `AddAsync`, etc.
// Implementation in Infrastructure layer
public class UserRepository : IUserRepository
{
private readonly ApplicationDbContext _context;
public UserRepository(ApplicationDbContext context)
{
_context = context;
}
public async Task<User?> GetByIdAsync(int id, CancellationToken cancellationToken)
{
return await _context.Users
.FirstOrDefaultAsync(u => u.Id == id, cancellationToken);
}
}
```
## Controller Pattern
```csharp
[ApiController]
[Route("api/[controller]")]
public class UsersController : ControllerBase
{
private readonly IUserService _userService;
Use `[ApiController]` attribute for automatic model validation and error responses. Use `[ProducesResponseType]` for Swagger documentation. Inject services via constructor. Pass `CancellationToken` through to service calls. Return `ActionResult<T>` for proper status codes.
public UsersController(IUserService userService)
{
_userService = userService;
}
[HttpGet("{id}")]
[ProducesResponseType(typeof(UserDto), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task<ActionResult<UserDto>> GetUser(
int id,
CancellationToken cancellationToken)
{
var user = await _userService.GetUserByIdAsync(id, cancellationToken);
return user is not null ? Ok(user) : NotFound();
}
}
```
## Quality Requirements

@@ -204,3 +76,3 @@

## Common Patterns to Apply
## Common Patterns

@@ -221,2 +93,4 @@ - Use `record` types for DTOs

dotnet test
```
```
For detailed examples and extended guidance, see [dotnet-clean-architecture-reference.instructions.md](dotnet-clean-architecture-reference.instructions.md).

@@ -17,237 +17,42 @@ ---

**Constructor injection only:**
```java
@Service
public class UserService {
**Constructor injection only.** Avoid `@Autowired` field injection โ€” it hides dependencies and complicates testing. Declare dependencies as `private final` fields initialized via the constructor.
private final UserRepository userRepository;
private final PasswordEncoder passwordEncoder;
public UserService(UserRepository userRepository, PasswordEncoder passwordEncoder) {
this.userRepository = userRepository;
this.passwordEncoder = passwordEncoder;
}
}
```
**Avoid field injection:**
```java
// โŒ Bad
@Autowired
private UserRepository userRepository;
// โœ… Good - Constructor injection
```
## Entity Design
**Use JPA annotations properly:**
```java
@Entity
@Table(name = "users")
public class User {
Use JPA annotations on entity classes: `@Entity`, `@Table`, `@Id`, `@GeneratedValue(strategy = GenerationType.IDENTITY)`. Mark timestamps with `@CreationTimestamp` / `@UpdateTimestamp`. Constrain columns with `@Column(nullable = false, unique = true)`.
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false, unique = true)
private String email;
@Column(nullable = false)
private String password;
@CreationTimestamp
private LocalDateTime createdAt;
// Constructors, getters, setters
}
```
## DTOs and Records
**Use records for immutable DTOs:**
```java
// Java 14+ record
public record UserDto(
Long id,
String email,
String name,
LocalDateTime createdAt
) {
// Automatic constructor, getters, equals, hashCode, toString
}
Prefer Java records for immutable DTOs (Java 14+). Apply Bean Validation annotations (`@NotBlank`, `@Email`, `@Size`) directly on record components. Create dedicated request/response record types per operation.
// For complex DTOs
public record CreateUserRequest(
@NotBlank @Email String email,
@NotBlank @Size(min = 8) String password,
@NotBlank String name
) {}
```
## Validation
**Use Bean Validation:**
```java
@RestController
@RequestMapping("/api/users")
@Validated
public class UserController {
Annotate controllers with `@Validated` and request bodies with `@Valid`. Validate path/query parameters with `@Min`, `@Positive`, etc. Return proper `ResponseEntity` with appropriate status codes (`created`, `ok`, `notFound`).
@PostMapping
public ResponseEntity<UserDto> createUser(@Valid @RequestBody CreateUserRequest request) {
User user = userService.createUser(request);
return ResponseEntity.created(uri).body(userMapper.toDto(user));
}
@GetMapping("/{id}")
public ResponseEntity<UserDto> getUser(@PathVariable @Min(1) Long id) {
return userService.findById(id)
.map(userMapper::toDto)
.map(ResponseEntity::ok)
.orElse(ResponseEntity.notFound().build());
}
}
```
## Error Handling
**Use ControllerAdvice for global error handling:**
```java
@RestControllerAdvice
public class GlobalExceptionHandler {
Use `@RestControllerAdvice` with `@ExceptionHandler` methods per exception type. Return a consistent `ErrorResponse` structure. For validation failures, extract field errors from `BindingResult` via `getFieldErrors()`.
@ExceptionHandler(UserNotFoundException.class)
public ResponseEntity<ErrorResponse> handleUserNotFound(UserNotFoundException ex) {
return ResponseEntity.status(HttpStatus.NOT_FOUND)
.body(new ErrorResponse("User not found", ex.getMessage()));
}
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<ErrorResponse> handleValidationErrors(MethodArgumentNotValidException ex) {
Map<String, String> errors = ex.getBindingResult()
.getFieldErrors()
.stream()
.collect(Collectors.toMap(
FieldError::getField,
FieldError::getDefaultMessage
));
return ResponseEntity.badRequest()
.body(new ErrorResponse("Validation failed", errors));
}
}
```
## Testing
**Use Spring Boot Test with JUnit 5:**
```java
@SpringBootTest
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
class UserServiceTest {
Use `@SpringBootTest` with JUnit 5. Follow Given/When/Then pattern. Use AssertJ's `assertThat` for fluent assertions and `assertThatThrownBy` for exception verification. Use `@MockBean` for external dependencies.
@Autowired
private UserService userService;
@Autowired
private UserRepository userRepository;
@Test
void shouldCreateUserSuccessfully() {
// Given
CreateUserRequest request = new CreateUserRequest(
"test@example.com", "password123", "Test User"
);
// When
User user = userService.createUser(request);
// Then
assertThat(user.getId()).isNotNull();
assertThat(user.getEmail()).isEqualTo("test@example.com");
}
@Test
void shouldThrowExceptionWhenUserNotFound() {
// When & Then
assertThatThrownBy(() -> userService.findById(999L))
.isInstanceOf(UserNotFoundException.class)
.hasMessage("User not found with id: 999");
}
}
```
## Repository Pattern
**Use Spring Data JPA:**
```java
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
Extend `JpaRepository<T, ID>` for standard CRUD. Add custom finders following Spring Data method naming. Use `@Query` with JPQL for complex queries and `@Modifying` for update/delete operations. Pass `@Param` annotations for named parameters.
Optional<User> findByEmail(String email);
@Query("SELECT u FROM User u WHERE u.createdAt > :since")
List<User> findRecentUsers(@Param("since") LocalDateTime since);
@Modifying
@Query("UPDATE User u SET u.lastLoginAt = :now WHERE u.id = :id")
int updateLastLogin(@Param("id") Long id, @Param("now") LocalDateTime now);
}
```
## Configuration
**Use application.yml for configuration:**
```yaml
spring:
datasource:
url: jdbc:postgresql://localhost:5432/myapp
username: ${DB_USERNAME}
password: ${DB_PASSWORD}
Use `application.yml` with structured profiles. Reference environment variables via `${VAR_NAME}`. In production: `ddl-auto: validate`, `show-sql: false`. Add logging level overrides per package.
jpa:
hibernate:
ddl-auto: validate
show-sql: false
logging:
level:
com.example.myapp: DEBUG
org.springframework.security: TRACE
```
## Security
**Use Spring Security properly:**
```java
@Configuration
@EnableWebSecurity
public class SecurityConfig {
Define a `SecurityFilterChain` bean. For stateless APIs use `SessionCreationPolicy.STATELESS`. Add JWT filter before `UsernamePasswordAuthenticationFilter`. Use `@PreAuthorize` for method-level fine-grained authorization.
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
return http
.csrf(csrf -> csrf.disable()) // For APIs, consider enabling
.authorizeHttpRequests(auth -> auth
.requestMatchers("/api/auth/**").permitAll()
.requestMatchers("/api/admin/**").hasRole("ADMIN")
.anyRequest().authenticated()
)
.sessionManagement(session -> session
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
)
.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class)
.build();
}
}
```
## Best Practices
### Code Organization
- Keep controllers thin (only HTTP concerns)
- Put business logic in services
- Use repositories for data access
- Keep controllers thin โ€” only HTTP concerns
- Put business logic in service layer
- Use repositories for data access only
- Create custom exceptions for business errors

@@ -264,3 +69,2 @@

- Add JavaDoc for public APIs
- Use meaningful variable names
- Keep methods small and focused

@@ -285,2 +89,4 @@

./mvnw spring-boot:run -Dspring-boot.run.profiles=dev
```
```
For detailed examples and extended guidance, see [java-spring-boot-reference.instructions.md](java-spring-boot-reference.instructions.md).

@@ -7,2 +7,4 @@ ---

metadata:
author: shahboura
version: "2.0.0"
audience: maintainers

@@ -9,0 +11,0 @@ workflow: troubleshooting

@@ -7,2 +7,4 @@ ---

metadata:
author: shahboura
version: "2.0.0"
audience: developers

@@ -9,0 +11,0 @@ workflow: content-creation

@@ -7,2 +7,4 @@ ---

metadata:
author: shahboura
version: "2.0.0"
audience: content-creators

@@ -9,0 +11,0 @@ workflow: content-review

@@ -7,2 +7,4 @@ ---

metadata:
author: shahboura
version: "2.0.0"
audience: maintainers

@@ -9,0 +11,0 @@ workflow: documentation

@@ -7,2 +7,4 @@ ---

metadata:
author: shahboura
version: "2.0.0"
audience: developers

@@ -9,0 +11,0 @@ workflow: development

@@ -7,2 +7,4 @@ ---

metadata:
author: shahboura
version: "2.0.0"
audience: developers

@@ -9,0 +11,0 @@ workflow: development

@@ -7,2 +7,4 @@ ---

metadata:
author: shahboura
version: "2.0.0"
audience: developers

@@ -9,0 +11,0 @@ workflow: development

@@ -7,2 +7,4 @@ ---

metadata:
author: shahboura
version: "2.0.0"
audience: developers

@@ -9,0 +11,0 @@ workflow: development

@@ -7,2 +7,4 @@ ---

metadata:
author: shahboura
version: "2.0.0"
audience: developers

@@ -9,0 +11,0 @@ workflow: development

@@ -7,2 +7,4 @@ ---

metadata:
author: shahboura
version: "2.0.0"
audience: maintainers

@@ -9,0 +11,0 @@ workflow: initialization

@@ -7,2 +7,4 @@ ---

metadata:
author: shahboura
version: "2.0.0"
audience: developers

@@ -9,0 +11,0 @@ workflow: development

@@ -7,2 +7,4 @@ ---

metadata:
author: shahboura
version: "2.0.0"
audience: developers

@@ -9,0 +11,0 @@ workflow: development

@@ -7,2 +7,4 @@ ---

metadata:
author: shahboura
version: "2.0.0"
audience: developers

@@ -9,0 +11,0 @@ workflow: development

@@ -7,2 +7,4 @@ ---

metadata:
author: shahboura
version: "2.0.0"
audience: developers

@@ -9,0 +11,0 @@ workflow: development

@@ -7,2 +7,4 @@ ---

metadata:
author: shahboura
version: "2.0.0"
audience: developers

@@ -9,0 +11,0 @@ workflow: development

@@ -7,2 +7,4 @@ ---

metadata:
author: shahboura
version: "2.0.0"
audience: developers

@@ -9,0 +11,0 @@ workflow: development

@@ -7,2 +7,4 @@ ---

metadata:
author: shahboura
version: "2.0.0"
audience: developers

@@ -9,0 +11,0 @@ workflow: design-and-development

+143
-574

@@ -17,7 +17,8 @@ #!/usr/bin/env node

const pathsMod = require('./scripts/lib/paths.js');
const fileOps = require('./scripts/lib/file-ops.js');
const configMutator = require('./scripts/lib/config-mutator.js');
const PACKAGE_NAME = 'agents-opencode';
const MANIFEST_FILE = '.agents-opencode-manifest.json';
const VERSION_FILE = '.opencode-agents-version';
const BACKUP_DIR = '.backups';
const AGENT_DIR_PREFERRED = 'agents';
const AGENT_DIR_LEGACY = 'agent';

@@ -29,16 +30,2 @@ const PROJECT_TEMPLATE_FILES = [

function resolveAgentDirectory(opencodeDir) {
const preferredAgentDir = path.join(opencodeDir, AGENT_DIR_PREFERRED);
if (fs.existsSync(preferredAgentDir)) {
return preferredAgentDir;
}
const legacyAgentDir = path.join(opencodeDir, AGENT_DIR_LEGACY);
if (fs.existsSync(legacyAgentDir)) {
return legacyAgentDir;
}
return null;
}
// Colors for output

@@ -73,34 +60,4 @@ const colors = {

function getHomeDir() {
return os.homedir();
}
function getGlobalConfigDir() {
return path.join(getHomeDir(), '.config', 'opencode');
}
function ensureDir(dirPath) {
if (!fs.existsSync(dirPath)) {
fs.mkdirSync(dirPath, { recursive: true });
}
}
function isObject(value) {
return value !== null && typeof value === 'object' && !Array.isArray(value);
}
function readJsonFile(filePath, labelForError) {
try {
return JSON.parse(fs.readFileSync(filePath, 'utf8'));
} catch (err) {
warning(`Could not parse ${labelForError}: ${err.message}`);
return null;
}
}
function writeJsonFile(filePath, data) {
fs.writeFileSync(filePath, JSON.stringify(data, null, 2) + '\n');
}
function formatBackupTimestamp(date = new Date()) {
function formatBackupTimestamp(date) {
date = date || new Date();
return date.toISOString().replace('T', '_').replace(/:/g, '-').replace(/\.\d{3}Z$/, 'Z');

@@ -136,3 +93,5 @@ }

function pruneBackupRetention(backupRoot, maxBackups = 10, maxAgeDays = 30) {
function pruneBackupRetention(backupRoot, maxBackups, maxAgeDays) {
if (typeof maxBackups === 'undefined') maxBackups = 10;
if (typeof maxAgeDays === 'undefined') maxAgeDays = 30;
if (!fs.existsSync(backupRoot)) {

@@ -146,8 +105,9 @@ return 0;

const backupDirs = fs.readdirSync(backupRoot, { withFileTypes: true })
.filter(entry => entry.isDirectory())
.map(entry => entry.name)
.filter(function (entry) { return entry.isDirectory(); })
.map(function (entry) { return entry.name; })
.sort()
.reverse();
for (const dirName of backupDirs.slice(maxBackups)) {
for (var i = 0; i < backupDirs.slice(maxBackups).length; i++) {
var dirName = backupDirs.slice(maxBackups)[i];
removeDirectoryIfExists(path.join(backupRoot, dirName));

@@ -158,9 +118,10 @@ prunedCount += 1;

const remainingDirs = fs.readdirSync(backupRoot, { withFileTypes: true })
.filter(entry => entry.isDirectory())
.map(entry => entry.name);
.filter(function (entry) { return entry.isDirectory(); })
.map(function (entry) { return entry.name; });
for (const dirName of remainingDirs) {
const backupPath = path.join(backupRoot, dirName);
for (var j = 0; j < remainingDirs.length; j++) {
var dirName2 = remainingDirs[j];
var backupPath = path.join(backupRoot, dirName2);
try {
const stat = fs.statSync(backupPath);
var stat = fs.statSync(backupPath);
if (stat.mtimeMs < cutoffMs) {

@@ -198,3 +159,3 @@ removeDirectoryIfExists(backupPath);

const targetPath = path.join(backupDir, normalizedRelativePath);
ensureDir(path.dirname(targetPath));
fileOps.ensureDir(path.dirname(targetPath));
fs.copyFileSync(absolutePath, targetPath);

@@ -221,3 +182,3 @@ entries.push({ path: normalizedRelativePath });

};
writeJsonFile(path.join(backupDir, 'backup-manifest.json'), manifest);
fileOps.writeJsonFile(path.join(backupDir, 'backup-manifest.json'), manifest);
const prunedCount = pruneBackupRetention(backupRoot);

@@ -264,3 +225,3 @@

if (fs.existsSync(packagePath)) {
const packageData = readJsonFile(packagePath, 'package.json');
const packageData = fileOps.readJsonFile(packagePath, 'package.json', warning);
if (packageData && packageData.version) {

@@ -281,3 +242,3 @@ info(`Installing OpenCode Agents v${packageData.version}`);

if (fs.existsSync(packagePath)) {
const packageData = readJsonFile(packagePath, 'package.json');
const packageData = fileOps.readJsonFile(packagePath, 'package.json', warning);
if (packageData && packageData.version) {

@@ -295,146 +256,2 @@ console.log(`OpenCode Agents v${packageData.version}`);

function listFilesRecursive(rootDir) {
const files = [];
function walk(currentDir, relativeBase = '') {
const entries = fs.readdirSync(currentDir, { withFileTypes: true });
for (const entry of entries) {
const relativePath = relativeBase ? path.join(relativeBase, entry.name) : entry.name;
const absolutePath = path.join(currentDir, entry.name);
if (entry.isDirectory()) {
walk(absolutePath, relativePath);
} else if (entry.isFile()) {
files.push(relativePath);
}
}
}
walk(rootDir);
return files;
}
function getManagedSourceFiles(sourceOpencodeDir) {
const allFiles = listFilesRecursive(sourceOpencodeDir);
return allFiles.filter((relativePath) => {
// Never manage transient dependency installs from local development
if (relativePath.includes(`node_modules${path.sep}`) || relativePath === 'node_modules') {
return false;
}
// Never treat backup snapshots as source-managed content
if (relativePath === BACKUP_DIR || relativePath.startsWith(`${BACKUP_DIR}${path.sep}`)) {
return false;
}
// Avoid re-managing backup artifacts if present
if (/\.backup\./.test(relativePath)) {
return false;
}
return true;
});
}
function filesEqual(pathA, pathB) {
try {
const statA = fs.statSync(pathA);
const statB = fs.statSync(pathB);
if (statA.size !== statB.size) {
return false;
}
const contentA = fs.readFileSync(pathA);
const contentB = fs.readFileSync(pathB);
return contentA.equals(contentB);
} catch {
return false;
}
}
function getScopePaths(scope, projectDir) {
if (scope === 'global') {
const rootDir = getGlobalConfigDir();
return {
scope,
rootDir,
opencodeDir: rootDir,
manifestPath: path.join(rootDir, MANIFEST_FILE),
versionPath: path.join(rootDir, VERSION_FILE),
configPath: path.join(rootDir, 'opencode.json'),
agentsMdPath: null,
};
}
const resolvedProjectDir = path.resolve(projectDir || process.cwd());
return {
scope,
rootDir: resolvedProjectDir,
opencodeDir: path.join(resolvedProjectDir, '.opencode'),
manifestPath: path.join(resolvedProjectDir, '.opencode', MANIFEST_FILE),
versionPath: path.join(resolvedProjectDir, VERSION_FILE),
configPath: path.join(resolvedProjectDir, 'opencode.json'),
agentsMdPath: path.join(resolvedProjectDir, 'AGENTS.md'),
};
}
function toManagedPath(scope, relativeOpencodeFile) {
if (scope === 'global') {
return relativeOpencodeFile;
}
return path.join('.opencode', relativeOpencodeFile);
}
function installManagedTree(sourceOpencodeDir, sourceFiles, destinationOpencodeDir, scope, backupSession) {
ensureDir(destinationOpencodeDir);
let copiedCount = 0;
let skippedCount = 0;
let backupCount = 0;
for (const relativeFile of sourceFiles) {
const src = path.join(sourceOpencodeDir, relativeFile);
const dest = path.join(destinationOpencodeDir, relativeFile);
const destParent = path.dirname(dest);
ensureDir(destParent);
if (fs.existsSync(dest)) {
if (filesEqual(src, dest)) {
skippedCount += 1;
continue;
}
try {
if (backupSession && backupSession.backupFile(dest, toManagedPath(scope, relativeFile))) {
backupCount += 1;
}
} catch (err) {
warning(`Could not back up existing file ${dest}: ${err.message}`);
}
}
fs.copyFileSync(src, dest);
copiedCount += 1;
}
return {
copiedCount,
skippedCount,
backupCount,
};
}
function buildManagedFilesFromSource(scope, sourceFiles, paths) {
const managedFiles = [];
for (const relativeFile of sourceFiles) {
const managedPath = toManagedPath(scope, relativeFile);
const absoluteManagedPath = path.join(paths.rootDir, managedPath);
if (fs.existsSync(absoluteManagedPath)) {
managedFiles.push(managedPath);
}
}
return managedFiles;
}
function installProjectTemplateFiles(sourceDir, scope, paths, backupSession) {

@@ -448,4 +265,5 @@ if (scope !== 'project') {

for (const relativePath of PROJECT_TEMPLATE_FILES) {
const src = path.join(sourceDir, relativePath);
for (var i = 0; i < PROJECT_TEMPLATE_FILES.length; i++) {
var relativePath = PROJECT_TEMPLATE_FILES[i];
var src = path.join(sourceDir, relativePath);
if (!fs.existsSync(src)) {

@@ -456,4 +274,4 @@ warning(`Project template source is missing: ${relativePath}`);

const dest = path.join(paths.rootDir, relativePath);
ensureDir(path.dirname(dest));
var dest = path.join(paths.rootDir, relativePath);
fileOps.ensureDir(path.dirname(dest));

@@ -480,91 +298,2 @@ if (fs.existsSync(dest)) {

function mergeInstallerConfig(targetConfigPath, sourceConfig, onBeforeWrite) {
const patch = {
createdFile: false,
addedPermissionKeys: [],
createdSchema: false,
skipped: false,
changed: false,
};
const sourceConfigForInstall = {
...(sourceConfig || {}),
};
delete sourceConfigForInstall.instructions;
if (!fs.existsSync(targetConfigPath)) {
writeJsonFile(targetConfigPath, sourceConfigForInstall);
patch.createdFile = true;
patch.changed = true;
if (isObject(sourceConfigForInstall.permission)) {
patch.addedPermissionKeys = Object.keys(sourceConfigForInstall.permission);
}
patch.createdSchema = !!sourceConfigForInstall.$schema;
return patch;
}
const existing = readJsonFile(targetConfigPath, `existing config at ${targetConfigPath}`);
if (!existing || !isObject(existing)) {
warning(`Skipping config merge for ${targetConfigPath} because existing config is invalid JSON.`);
patch.skipped = true;
return patch;
}
if (isObject(sourceConfigForInstall.permission)) {
if (existing.permission === undefined) {
existing.permission = {};
}
if (!isObject(existing.permission)) {
warning(`Skipping permission merge for ${targetConfigPath}; existing permission is not an object.`);
} else {
for (const [key, value] of Object.entries(sourceConfigForInstall.permission)) {
if (!(key in existing.permission)) {
existing.permission[key] = value;
patch.addedPermissionKeys.push(key);
patch.changed = true;
}
}
}
}
if (patch.changed) {
if (typeof onBeforeWrite === 'function') {
onBeforeWrite();
}
writeJsonFile(targetConfigPath, existing);
}
return patch;
}
function mergeConfigPatches(existingPatch, currentPatch) {
const base = {
createdFile: false,
addedPermissionKeys: [],
createdSchema: false,
skipped: false,
changed: false,
};
const prior = isObject(existingPatch) ? existingPatch : {};
const next = isObject(currentPatch) ? currentPatch : {};
const permissionKeys = new Set([
...(Array.isArray(prior.addedPermissionKeys) ? prior.addedPermissionKeys : []),
...(Array.isArray(next.addedPermissionKeys) ? next.addedPermissionKeys : []),
]);
return {
...base,
...prior,
...next,
createdFile: Boolean(prior.createdFile || next.createdFile),
addedPermissionKeys: [...permissionKeys],
createdSchema: Boolean(prior.createdSchema || next.createdSchema || prior.addedSchema || next.addedSchema),
skipped: Boolean(prior.skipped || next.skipped),
changed: Boolean(prior.changed || next.changed),
};
}
function revertInstallerConfig(targetConfigPath, configPatch, sourceConfig, onBeforeMutate) {

@@ -587,4 +316,4 @@ if (!configPatch) {

const existing = readJsonFile(targetConfigPath, `existing config at ${targetConfigPath}`);
if (!existing || !isObject(existing)) {
const existing = fileOps.readJsonFile(targetConfigPath, `existing config at ${targetConfigPath}`, warning);
if (!existing || !fileOps.isObject(existing)) {
warning(`Could not revert config changes for ${targetConfigPath}; invalid JSON.`);

@@ -596,4 +325,5 @@ return { changed: false, removedFile: false };

if (Array.isArray(configPatch.addedPermissionKeys) && isObject(existing.permission)) {
for (const key of configPatch.addedPermissionKeys) {
if (Array.isArray(configPatch.addedPermissionKeys) && fileOps.isObject(existing.permission)) {
for (var i = 0; i < configPatch.addedPermissionKeys.length; i++) {
var key = configPatch.addedPermissionKeys[i];
if (!(key in existing.permission)) {

@@ -603,3 +333,3 @@ continue;

const sourceValue = sourceConfig && isObject(sourceConfig.permission) ? sourceConfig.permission[key] : undefined;
var sourceValue = sourceConfig && fileOps.isObject(sourceConfig.permission) ? sourceConfig.permission[key] : undefined;
if (sourceValue !== undefined && JSON.stringify(existing.permission[key]) !== JSON.stringify(sourceValue)) {

@@ -620,3 +350,3 @@ warning(`Keeping modified permission key '${key}' in ${targetConfigPath}; value differs from installer default.`);

const schemaWasCreatedByInstaller = Boolean(configPatch.createdSchema || configPatch.addedSchema);
var schemaWasCreatedByInstaller = Boolean(configPatch.createdSchema || configPatch.addedSchema);
if (schemaWasCreatedByInstaller && sourceConfig && sourceConfig.$schema && existing.$schema === sourceConfig.$schema) {

@@ -631,3 +361,3 @@ delete existing.$schema;

}
writeJsonFile(targetConfigPath, existing);
fileOps.writeJsonFile(targetConfigPath, existing);
}

@@ -639,4 +369,4 @@

function writeManifest(manifestPath, manifest) {
ensureDir(path.dirname(manifestPath));
writeJsonFile(manifestPath, manifest);
fileOps.ensureDir(path.dirname(manifestPath));
fileOps.writeJsonFile(manifestPath, manifest);
}

@@ -648,4 +378,4 @@

}
const manifest = readJsonFile(manifestPath, `manifest at ${manifestPath}`);
if (!manifest || !isObject(manifest)) {
const manifest = fileOps.readJsonFile(manifestPath, `manifest at ${manifestPath}`, warning);
if (!manifest || !fileOps.isObject(manifest)) {
return null;

@@ -656,36 +386,2 @@ }

function removeIfExists(filePath) {
if (!fs.existsSync(filePath)) {
return false;
}
fs.unlinkSync(filePath);
return true;
}
function pruneEmptyDirectories(directories, stopAtDirectory) {
const sorted = [...directories].sort((a, b) => b.length - a.length);
let prunedCount = 0;
for (const dirPath of sorted) {
if (!fs.existsSync(dirPath)) {
continue;
}
if (path.resolve(dirPath) === path.resolve(stopAtDirectory)) {
continue;
}
try {
const entries = fs.readdirSync(dirPath);
if (entries.length === 0) {
fs.rmdirSync(dirPath);
prunedCount += 1;
}
} catch {
// ignore pruning errors
}
}
return prunedCount;
}
function backupAndRemoveAgentsMdIfPresent(agentsMdPath, backupSession) {

@@ -706,4 +402,5 @@ if (!agentsMdPath || !fs.existsSync(agentsMdPath)) {

const requiredDirs = ['instructions', 'commands'];
for (const dir of requiredDirs) {
const dirPath = path.join(opencodeDir, dir);
for (var i = 0; i < requiredDirs.length; i++) {
var dir = requiredDirs[i];
var dirPath = path.join(opencodeDir, dir);
if (!fs.existsSync(dirPath)) {

@@ -715,10 +412,10 @@ error(`Missing required directory '${dir}' in ${scope} installation.`);

const agentDir = resolveAgentDirectory(opencodeDir);
const agentDir = pathsMod.resolveAgentDirectory(opencodeDir);
if (!agentDir) {
error(`Missing required agent directory ('${AGENT_DIR_PREFERRED}' or '${AGENT_DIR_LEGACY}') in ${scope} installation.`);
error(`Missing required agent directory ('.opencode/${pathsMod.AGENT_DIR}/') in ${scope} installation.`);
return false;
}
const agents = fs.readdirSync(agentDir).filter(file => file.endsWith('.md'));
const agents = fs.readdirSync(agentDir).filter(function (file) { return file.endsWith('.md'); });
if (agents.length === 0) {

@@ -736,83 +433,2 @@ error(`No agent files found in ${agentDir}`);

function legacyConfigCleanup(configPath, sourceConfig, onBeforeMutate) {
if (!fs.existsSync(configPath)) {
return { changed: false, removedFile: false };
}
const existing = readJsonFile(configPath, `existing config at ${configPath}`);
if (!existing || !isObject(existing)) {
warning(`Skipping legacy config cleanup; invalid JSON at ${configPath}.`);
return { changed: false, removedFile: false };
}
if (JSON.stringify(existing) === JSON.stringify(sourceConfig)) {
if (typeof onBeforeMutate === 'function') {
onBeforeMutate();
}
fs.unlinkSync(configPath);
return { changed: true, removedFile: true };
}
let changed = false;
if (isObject(sourceConfig.permission) && isObject(existing.permission)) {
for (const [key, sourceValue] of Object.entries(sourceConfig.permission)) {
if (!(key in existing.permission)) {
continue;
}
if (JSON.stringify(existing.permission[key]) === JSON.stringify(sourceValue)) {
delete existing.permission[key];
changed = true;
}
}
if (Object.keys(existing.permission).length === 0) {
delete existing.permission;
changed = true;
}
}
if (changed) {
if (typeof onBeforeMutate === 'function') {
onBeforeMutate();
}
writeJsonFile(configPath, existing);
}
return { changed, removedFile: false };
}
function loadSourceConfig(sourceDir) {
const sourceConfigPath = path.join(sourceDir, 'opencode.json');
const sourceConfig = readJsonFile(sourceConfigPath, 'package opencode.json');
if (!sourceConfig || !isObject(sourceConfig)) {
error('Could not parse package opencode.json.');
process.exit(1);
}
return sourceConfig;
}
function configLooksManaged(configPath, sourceConfig) {
if (!fs.existsSync(configPath)) {
return false;
}
const config = readJsonFile(configPath, `config at ${configPath}`);
if (!config || !isObject(config)) {
return false;
}
if (isObject(sourceConfig.permission) && isObject(config.permission)) {
for (const [key, sourceValue] of Object.entries(sourceConfig.permission)) {
if (!(key in config.permission)) {
continue;
}
if (JSON.stringify(config.permission[key]) === JSON.stringify(sourceValue)) {
return true;
}
}
}
return false;
}
function installScope(options) {

@@ -831,3 +447,3 @@ const {

const paths = getScopePaths(scope, projectDir);
const paths = pathsMod.getScopePaths(scope, projectDir);
const existingManifest = readManifest(paths.manifestPath);

@@ -840,4 +456,13 @@

ensureDir(paths.opencodeDir);
if (!configMutator.checkLegacyAgentDir(paths.opencodeDir, {
error: error,
PACKAGE_NAME: PACKAGE_NAME,
AGENT_DIR_LEGACY: AGENT_DIR_LEGACY,
AGENT_DIR: pathsMod.AGENT_DIR,
})) {
return false;
}
fileOps.ensureDir(paths.opencodeDir);
info(`Installing ${PACKAGE_NAME} (${scope}) at ${paths.rootDir}`);

@@ -847,3 +472,3 @@

const treeResult = installManagedTree(sourceOpencodeDir, sourceManagedFiles, paths.opencodeDir, scope, backupSession);
const treeResult = fileOps.installManagedTree(sourceOpencodeDir, sourceManagedFiles, paths.opencodeDir, scope, backupSession, warning);
success(`โœ“ Installed/updated ${treeResult.copiedCount} file(s); ${treeResult.skippedCount} unchanged`);

@@ -862,7 +487,7 @@

if (languages) {
filterLanguages(paths.opencodeDir, languages);
fileOps.filterLanguages(paths.opencodeDir, languages, { warning: warning, info: info, success: success });
}
let configBackedUp = false;
const backupConfigBeforeWrite = () => {
const backupConfigBeforeWrite = function () {
if (configBackedUp || !fs.existsSync(paths.configPath)) {

@@ -876,3 +501,3 @@ return;

const configPatch = mergeInstallerConfig(paths.configPath, sourceConfig, backupConfigBeforeWrite);
const configPatch = configMutator.mergeInstallerConfig(paths.configPath, sourceConfig, backupConfigBeforeWrite, warning);
if (configPatch.skipped) {

@@ -893,6 +518,7 @@ warning('Config merge skipped due to invalid existing JSON; continuing with agent files only.');

const managedFiles = buildManagedFilesFromSource(scope, sourceManagedFiles, paths);
const managedFiles = fileOps.buildManagedFilesFromSource(scope, sourceManagedFiles, paths);
if (scope === 'project') {
for (const templateRelativePath of PROJECT_TEMPLATE_FILES) {
const absoluteTemplatePath = path.join(paths.rootDir, templateRelativePath);
for (var i = 0; i < PROJECT_TEMPLATE_FILES.length; i++) {
var templateRelativePath = PROJECT_TEMPLATE_FILES[i];
var absoluteTemplatePath = path.join(paths.rootDir, templateRelativePath);
if (fs.existsSync(absoluteTemplatePath)) {

@@ -914,3 +540,3 @@ managedFiles.push(templateRelativePath);

const effectiveConfigPatch = mergeConfigPatches(existingManifest ? existingManifest.configPatch : null, configPatch);
const effectiveConfigPatch = configMutator.mergeConfigPatches(existingManifest ? existingManifest.configPatch : null, configPatch);

@@ -960,3 +586,3 @@ if (existingManifest && existingManifest.installedAt) {

const paths = getScopePaths(scope, projectDir);
const paths = pathsMod.getScopePaths(scope, projectDir);
const manifest = readManifest(paths.manifestPath);

@@ -972,3 +598,12 @@

const backupConfigBeforeMutate = () => {
if (!configMutator.checkLegacyAgentDir(paths.opencodeDir, {
error: error,
PACKAGE_NAME: PACKAGE_NAME,
AGENT_DIR_LEGACY: AGENT_DIR_LEGACY,
AGENT_DIR: pathsMod.AGENT_DIR,
})) {
return false;
}
const backupConfigBeforeMutate = function () {
if (configBackedUp || !fs.existsSync(paths.configPath)) {

@@ -982,18 +617,13 @@ return;

const removeManagedFile = (absolutePath, relativePathFromRoot) => {
if (!fs.existsSync(absolutePath)) {
return;
}
backupSession.backupFile(absolutePath, relativePathFromRoot || path.relative(paths.rootDir, absolutePath));
fs.unlinkSync(absolutePath);
removedFiles += 1;
touchedDirectories.add(path.dirname(absolutePath));
};
if (manifest && Array.isArray(manifest.managedFiles)) {
info(`Using manifest uninstall for ${scope} scope.`);
for (const managedPath of manifest.managedFiles) {
const absolutePath = path.join(paths.rootDir, managedPath);
removeManagedFile(absolutePath, managedPath);
for (var i = 0; i < manifest.managedFiles.length; i++) {
var managedPath = manifest.managedFiles[i];
var absolutePath = path.join(paths.rootDir, managedPath);
var result = fileOps.removeManagedFile(absolutePath, managedPath, paths, backupSession);
if (result.removed) {
removedFiles += 1;
touchedDirectories.add(result.directory);
}
}

@@ -1008,3 +638,3 @@

}
if (removeIfExists(paths.versionPath)) {
if (fileOps.removeIfExists(paths.versionPath)) {
removedFiles += 1;

@@ -1015,3 +645,3 @@ }

}
if (removeIfExists(paths.manifestPath)) {
if (fileOps.removeIfExists(paths.manifestPath)) {
removedFiles += 1;

@@ -1021,15 +651,20 @@ touchedDirectories.add(path.dirname(paths.manifestPath));

} else {
warning(`No install manifest found for ${scope}. Attempting safe legacy cleanup.`);
warning(`No install manifest found for ${scope}. Attempting safe cleanup.`);
const legacyManagedFiles = sourceManagedFiles
.map(relative => toManagedPath(scope, relative));
const managedFiles = sourceManagedFiles
.map(function (relative) { return pathsMod.toManagedPath(scope, relative); });
for (const legacyManagedPath of legacyManagedFiles) {
const absolutePath = path.join(paths.rootDir, legacyManagedPath);
removeManagedFile(absolutePath, legacyManagedPath);
for (var j = 0; j < managedFiles.length; j++) {
var managedPath2 = managedFiles[j];
var absolutePath2 = path.join(paths.rootDir, managedPath2);
var result2 = fileOps.removeManagedFile(absolutePath2, managedPath2, paths, backupSession);
if (result2.removed) {
removedFiles += 1;
touchedDirectories.add(result2.directory);
}
}
const legacyConfigResult = legacyConfigCleanup(paths.configPath, sourceConfig, backupConfigBeforeMutate);
configChanged = legacyConfigResult.changed;
removedConfigFile = legacyConfigResult.removedFile;
const cleanupResult = configMutator.manifestlessCleanup(paths.configPath, sourceConfig, backupConfigBeforeMutate, warning);
configChanged = cleanupResult.changed;
removedConfigFile = cleanupResult.removedFile;

@@ -1039,3 +674,3 @@ if (fs.existsSync(paths.versionPath)) {

}
if (removeIfExists(paths.versionPath)) {
if (fileOps.removeIfExists(paths.versionPath)) {
removedFiles += 1;

@@ -1045,3 +680,3 @@ }

prunedDirs += pruneEmptyDirectories(touchedDirectories, paths.rootDir);
prunedDirs += fileOps.pruneEmptyDirectories(touchedDirectories, paths.rootDir);

@@ -1095,3 +730,3 @@ if (scope === 'project' && fs.existsSync(paths.opencodeDir)) {

function isInstalled(scope, projectDir, sourceConfig) {
const paths = getScopePaths(scope, projectDir);
const paths = pathsMod.getScopePaths(scope, projectDir);
const manifestExists = fs.existsSync(paths.manifestPath);

@@ -1103,3 +738,3 @@

return !!resolveAgentDirectory(paths.opencodeDir) || configLooksManaged(paths.configPath, sourceConfig);
return !!pathsMod.resolveAgentDirectory(paths.opencodeDir) || configMutator.configLooksManaged(paths.configPath, sourceConfig, warning);
}

@@ -1117,77 +752,2 @@

// Language-to-instruction file mapping
const LANGUAGE_MAP = {
dotnet: 'dotnet-clean-architecture.instructions.md',
python: 'python-best-practices.instructions.md',
typescript: 'typescript-strict.instructions.md',
flutter: 'flutter.instructions.md',
go: 'go.instructions.md',
java: 'java-spring-boot.instructions.md',
node: 'node-express.instructions.md',
react: 'react-next.instructions.md',
ruby: 'ruby-on-rails.instructions.md',
rust: 'rust.instructions.md',
sql: 'sql-migrations.instructions.md',
cicd: 'ci-cd-hygiene.instructions.md',
};
const LANGUAGE_INSTRUCTIONS = new Set(Object.values(LANGUAGE_MAP));
// Content-focused instruction files that are always kept
const ALWAYS_KEEP = [
'blogger.instructions.md',
'brutal-critic.instructions.md',
'ci-cd-hygiene.instructions.md',
];
function filterLanguages(installDir, languages) {
const instructionsDir = path.join(installDir, 'instructions');
if (!fs.existsSync(instructionsDir)) {
warning('No instructions directory found โ€” skipping language filter.');
return;
}
const validLanguages = Object.keys(LANGUAGE_MAP);
const requested = languages.split(',').map(l => l.trim().toLowerCase()).filter(Boolean);
const invalid = requested.filter(l => !validLanguages.includes(l));
if (invalid.length > 0) {
warning(`Unknown language(s): ${invalid.join(', ')}`);
info(`Available: ${validLanguages.join(', ')}`);
}
const valid = requested.filter(l => validLanguages.includes(l));
if (valid.length === 0) {
warning('No valid languages specified โ€” keeping all instruction files.');
return;
}
const keepFiles = new Set(ALWAYS_KEEP);
for (const lang of valid) {
if (LANGUAGE_MAP[lang]) {
keepFiles.add(LANGUAGE_MAP[lang]);
}
}
const allFiles = fs.readdirSync(instructionsDir);
const removed = [];
for (const file of allFiles) {
if (keepFiles.has(file) || !LANGUAGE_INSTRUCTIONS.has(file)) {
continue;
}
try {
fs.unlinkSync(path.join(instructionsDir, file));
removed.push(file);
} catch (err) {
warning(`Could not remove ${file}: ${err.message}`);
}
}
success(`โœ“ Applied language filter: ${valid.join(', ')}`);
if (removed.length > 0) {
info(`Removed ${removed.length} instruction file(s): ${removed.join(', ')}`);
}
}
function parseArgs(argv) {

@@ -1206,3 +766,3 @@ const parsed = {

const args = [...argv];
const args = argv.slice();
for (let i = 0; i < args.length; i += 1) {

@@ -1300,3 +860,4 @@ const arg = args[i];

function showUsage(exitCode = 0) {
function showUsage(exitCode) {
if (typeof exitCode === 'undefined') exitCode = 0;
console.log(`

@@ -1379,5 +940,11 @@ ๐Ÿค– OpenCode Agents Installation Script

const sourceManagedFiles = getManagedSourceFiles(sourceOpencodeDir);
const sourceManagedFiles = fileOps.getManagedSourceFiles(sourceOpencodeDir);
const sourceConfig = loadSourceConfig(sourceDir);
let sourceConfig;
try {
sourceConfig = configMutator.loadSourceConfig(sourceDir, warning);
} catch (err) {
error(err.message);
process.exit(1);
}

@@ -1400,6 +967,7 @@ if (parsed.status) {

const scopes = getRequestedScopes(parsed, 'uninstall', sourceConfig);
for (const scope of scopes) {
const projectDir = scope === 'project' ? (parsed.project || process.cwd()) : null;
for (var i = 0; i < scopes.length; i++) {
var scope = scopes[i];
var projectDir = scope === 'project' ? (parsed.project || process.cwd()) : null;
info(`Uninstalling ${PACKAGE_NAME} from ${scope} scope...`);
const ok = uninstallScope({ sourceConfig, sourceManagedFiles, scope, projectDir });
var ok = uninstallScope({ sourceConfig: sourceConfig, sourceManagedFiles: sourceManagedFiles, scope: scope, projectDir: projectDir });
if (!ok) {

@@ -1428,16 +996,17 @@ process.exit(1);

for (const scope of scopes) {
const projectDir = scope === 'project' ? (parsed.project || process.cwd()) : null;
const ok = installScope({
sourceDir,
sourceConfig,
sourceOpencodeDir,
sourceManagedFiles,
for (var j = 0; j < scopes.length; j++) {
var scope2 = scopes[j];
var projectDir2 = scope2 === 'project' ? (parsed.project || process.cwd()) : null;
var ok2 = installScope({
sourceDir: sourceDir,
sourceConfig: sourceConfig,
sourceOpencodeDir: sourceOpencodeDir,
sourceManagedFiles: sourceManagedFiles,
sourceVersion: version,
operation: 'update',
scope,
projectDir,
scope: scope2,
projectDir: projectDir2,
languages: parsed.languages,
});
if (!ok) {
if (!ok2) {
process.exit(1);

@@ -1469,7 +1038,7 @@ }

if (parsed.global) {
const ok = installScope({
sourceDir,
sourceConfig,
sourceOpencodeDir,
sourceManagedFiles,
var ok3 = installScope({
sourceDir: sourceDir,
sourceConfig: sourceConfig,
sourceOpencodeDir: sourceOpencodeDir,
sourceManagedFiles: sourceManagedFiles,
sourceVersion: version,

@@ -1481,11 +1050,11 @@ operation: 'install',

});
if (!ok) {
if (!ok3) {
process.exit(1);
}
} else {
const ok = installScope({
sourceDir,
sourceConfig,
sourceOpencodeDir,
sourceManagedFiles,
var ok4 = installScope({
sourceDir: sourceDir,
sourceConfig: sourceConfig,
sourceOpencodeDir: sourceOpencodeDir,
sourceManagedFiles: sourceManagedFiles,
sourceVersion: version,

@@ -1497,3 +1066,3 @@ operation: 'install',

});
if (!ok) {
if (!ok4) {
process.exit(1);

@@ -1500,0 +1069,0 @@ }

{
"$schema": "https://opencode.ai/config.json",
"plugin": ["agents-opencode"],
"permission": {

@@ -4,0 +5,0 @@ "external_directory": "deny",

{
"name": "agents-opencode",
"version": "1.5.0",
"description": "OpenCode Agents: Intelligent AI assistants for software development. Features 8 specialized agents, 14 coding standards, automated code review, documentation generation, and cross-platform installation. Supports .NET, Python, TypeScript, Flutter, Go, Java, Node.js, React, Ruby, and Rust with plan-first execution and context-aware assistance.",
"version": "2.0.0",
"description": "OpenCode Agents: Intelligent AI assistants for software development. Features 9 specialized agents (including legal-advisor for license auditing and compliance), 14 coding standards, automated code review, documentation generation, OpenCode plugin compatibility, and cross-platform installation. Supports .NET, Python, TypeScript, Flutter, Go, Java, Node.js, React, Ruby, and Rust with plan-first execution and context-aware assistance.",
"files": [

@@ -6,0 +6,0 @@ "install.js",

@@ -90,2 +90,20 @@ # OpenCode Agents

## Installation
### npx (Recommended)
```bash
npx agents-opencode --global
```
### OpenCode Plugin (Alternative)
Add to your `opencode.json`:
```json
{ "plugin": ["agents-opencode"] }
```
Then restart OpenCode or run `/reload-plugins`.
## Agents

@@ -103,2 +121,3 @@

| `@brutal-critic` | Final content quality gate |
| `@legal-advisor` | License auditing, IP review, data privacy assessment, regulatory guidance |

@@ -105,0 +124,0 @@ Canonical source for exact allowlists and skill triggers: [Skills Matrix](./docs/skills-matrix.md)