Thank you for your interest in contributing to the OpenCode Shannon Plugin! This guide will help you get started.
- Bun v1.3.0 or higher (NOT npm or yarn)
- OpenCode v1.0.150 or higher
- Git for version control
-
Clone the repository:
git clone https://github.com/your-org/opencode-shannon-plugin.git cd opencode-shannon-plugin -
Install dependencies:
bun install
-
Build the plugin:
bun run build
-
Run tests:
bun test
This plugin follows the oh-my-opencode modular architecture pattern:
src/
├── index.ts # Plugin entry point (hook registration, tool wiring)
├── types.ts # Shared type definitions
├── config/ # Zod schema for Shannon settings
├── shared/ # Reusable modules (executor, adapters, utilities)
├── tools/ # 5 Shannon tools (scan, recon, vuln, exploit, report)
├── hooks/ # 3 lifecycle hooks (auth, progress, session)
├── commands/ # Slash commands (/shannon-scan, /shannon-recon, /shannon-report)
└── skills/ # shannon-pentest.md skill definition
CRITICAL: These rules are MANDATORY and non-negotiable.
-
200 LOC Hard Limit:
- Every file MUST be under 200 lines (excluding prompt strings)
- If a file exceeds 200 LOC, split it into smaller modules
- This is a code smell indicator, not a suggestion
-
Single Responsibility Principle:
- Each file has ONE clear, nameable responsibility
- No catch-all
utils.ts,helpers.ts, orservice.tsfiles - Name files by their specific purpose (e.g.,
message-adapter.ts,provider-detector.ts)
-
Module Structure: Each tool/hook follows this 4-file pattern:
feature-name/ ├── types.ts # Type definitions ├── constants.ts # Constants, configs, default values ├── hook.ts # Hook implementation (tools.ts for tools) └── index.ts # Barrel exports only -
index.ts is ENTRY POINT ONLY:
- Only re-exports from submodules
- Only factory function calls
- Only wiring/composition logic
- NO business logic, implementations, or heavy computation
-
Bun Only:
- NEVER use
npmoryarn - ALWAYS use
bunfor all operations - Use
bun-types(NOT@types/node)
- NEVER use
- Strict mode enabled (
strict: true) - No type suppression: Never use
as any,@ts-ignore,@ts-expect-error - Explicit return types for public functions
- Interface over type for object shapes
- Test-Driven Development (TDD) required for new features
- BDD comments for test structure:
test("should parse provider from model string", () => { //#given const modelString = "google/gemini-2.0-flash-thinking-exp" //#when const result = parseModelString(modelString) //#then expect(result.provider).toBe("google") expect(result.model).toBe("gemini-2.0-flash-thinking-exp") })
- Co-locate tests: Place
.test.tsfiles alongside source files - Test coverage: Aim for 80%+ coverage on core logic
- Files:
kebab-case.ts(e.g.,message-adapter.ts) - Directories:
kebab-case/(e.g.,shannon-scan/) - Functions:
camelCase(e.g.,parseModelString) - Factory functions:
createXXXHook,createXXXToolpattern - Types/Interfaces:
PascalCase(e.g.,ShannonExecutorConfig) - Constants:
SCREAMING_SNAKE_CASE(e.g.,KNOWN_PROVIDERS)
git checkout -b feature/your-feature-name# Create test file
touch src/shared/your-feature.test.ts
# Write failing test
bun test # Should FAIL (RED)# Write minimum implementation
touch src/shared/your-feature.ts
# Run tests
bun test # Should PASS (GREEN)# Clean up code while keeping tests passing
bun test # Should stay GREENbun run typecheck # 0 errors
bun run build # Successful bundlegit add .
git commit -m "feat: add your feature description"- Tests added/updated (TDD followed)
- All tests passing (
bun test) - TypeScript compiles with 0 errors (
bun run typecheck) - Build succeeds (
bun run build) - Files under 200 LOC limit (excluding prompt strings)
- No catch-all utility files created
- README updated (if applicable)
- CHANGELOG updated with changes
## What does this PR do?
Brief description of the feature/fix.
## Why is this change needed?
Explanation of the problem this solves.
## How was this tested?
- [ ] Unit tests added/updated
- [ ] Manual testing performed
- [ ] Integration tests (if applicable)
## Checklist
- [ ] Tests passing
- [ ] TypeScript compiles
- [ ] Build succeeds
- [ ] Documentation updated- Location: Co-locate with source files (e.g.,
message-adapter.test.ts) - Structure: Use BDD comments (
#given,#when,#then) - Coverage: Test happy paths, edge cases, and error conditions
- Manual testing: Test in real OpenCode environment
- End-to-end workflows: Test full shannon_scan with all phases
- Multi-provider testing: Test with different AI providers
bun test # Run all tests
bun test src/shared/ # Run tests in directory
bun test message-adapter # Run tests matching pattern-
Create tool directory:
mkdir src/tools/your-tool
-
Create 4-file structure:
touch src/tools/your-tool/{types,constants,tools,index}.ts -
Implement tool:
types.ts: Input/output typesconstants.ts: Default values, configstools.ts: Tool implementationindex.ts: Barrel export
-
Register in plugin:
- Add to
src/index.tstool registry - Export from
src/tools/index.ts
- Add to
-
Write tests:
touch src/tools/your-tool/tools.test.ts
-
Create hook directory:
mkdir src/hooks/your-hook
-
Create 4-file structure:
touch src/hooks/your-hook/{types,constants,hook,index}.ts -
Implement hook:
types.ts: Hook input/output typesconstants.ts: Hook constantshook.ts: Hook factory functionindex.ts: Barrel export
-
Register in plugin:
- Import in
src/index.ts - Add to hook chain in plugin interface
- Import in
-
Write tests:
touch src/hooks/your-hook/hook.test.ts
bun run typecheckbun run buildrm -rf dist/
bun run buildbun test message-adapter.test.tsSet environment variable:
export DEBUG=shannon:*-
Build fails with module errors:
- Check
tsconfig.jsonpaths - Verify all imports use relative paths
- Run
bun installto refresh dependencies
- Check
-
Tests fail after refactor:
- Verify exports in
index.tsfiles - Check for circular dependencies
- Run
bun run typecheckfirst
- Verify exports in
-
Hook not executing:
- Verify hook is imported in
src/index.ts - Check hook is registered in plugin interface
- Ensure hook handler signature matches OpenCode API
- Verify hook is imported in
-
Architecture compliance:
- 200 LOC limit enforced
- Single responsibility maintained
- No catch-all files
-
Type safety:
- No
anytypes - No type suppressions
- Explicit return types
- No
-
Test coverage:
- Tests exist for new code
- TDD process followed
- Edge cases covered
-
Documentation:
- README updated
- Code comments for complex logic
- Type definitions documented
This project is licensed under GNU AGPL-3.0. All contributions must:
- Be compatible with AGPL-3.0
- Include source code attribution
- Maintain AGPL-3.0 license for derivative works
See LICENSE for full text.
This plugin builds upon Shannon by KeygraphHQ, licensed under AGPL-3.0.
- Open an issue for bugs or feature requests
- Tag maintainers for urgent questions
- Check existing issues before creating new ones
- Be respectful and professional
- Provide constructive feedback
- Follow the architecture guidelines
- Test your code before submitting
- Document complex logic
Thank you for contributing! 🚀