Browse Source

Update README.md to enhance project description, add features, quick start guide, agent and plugin details, configuration instructions, and safety/security practices.

darrenhinde 8 months ago
parent
commit
0119898081

+ 125 - 0
.gitignore

@@ -0,0 +1,125 @@
+# Environment variables and API keys
+.env
+.env.local
+.env.development
+.env.test
+.env.production
+.env.*.local
+
+# API keys and secrets
+*.key
+*.pem
+*.p12
+*.pfx
+secrets/
+keys/
+api-keys/
+
+# Telegram bot tokens (specific to this project)
+telegram-token.txt
+telegram-config.json
+bot-token.txt
+
+# Node.js
+node_modules/
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+.pnpm-debug.log*
+
+# Bun
+bun.lockb
+
+# TypeScript
+*.tsbuildinfo
+dist/
+build/
+
+# IDE and editor files
+.vscode/
+.idea/
+*.swp
+*.swo
+*~
+
+# OS generated files
+.DS_Store
+.DS_Store?
+._*
+.Spotlight-V100
+.Trashes
+ehthumbs.db
+Thumbs.db
+
+# Logs
+logs/
+*.log
+
+# Runtime data
+pids/
+*.pid
+*.seed
+*.pid.lock
+
+# Coverage directory used by tools like istanbul
+coverage/
+*.lcov
+
+# nyc test coverage
+.nyc_output
+
+# Dependency directories
+jspm_packages/
+
+# Optional npm cache directory
+.npm
+
+# Optional eslint cache
+.eslintcache
+
+# Microbundle cache
+.rpt2_cache/
+.rts2_cache_cjs/
+.rts2_cache_es/
+.rts2_cache_umd/
+
+# Optional REPL history
+.node_repl_history
+
+# Output of 'npm pack'
+*.tgz
+
+# Yarn Integrity file
+.yarn-integrity
+
+# parcel-bundler cache (https://parceljs.org/)
+.cache
+.parcel-cache
+
+# Next.js build output
+.next
+
+# Nuxt.js build / generate output
+.nuxt
+dist
+
+# Gatsby files
+.cache/
+public
+
+# Storybook build outputs
+.out
+.storybook-out
+
+# Temporary folders
+tmp/
+temp/
+
+# OpenCode specific
+.opencode/log/
+.opencode/cache/
+.opencode/temp/
+
+# Local development
+.local/
+local/

+ 33 - 0
.opencode/AGENTS.md

@@ -0,0 +1,33 @@
+# OpenCode Agents for Mastra RAG Template
+
+This repository defines task-focused agents to streamline planning, implementation, review, documentation, and testing.
+
+Agents:
+
+- `plan-project`: Roadmaps, milestones, ADRs, risk register
+- `plan-analyse`: Repo survey, external research, dependency and risk mapping
+- `mastra`: Implementation for ingestion, embeddings, LanceDB, retrieval, assembly, and agents
+- `review`: Code review with targeted feedback and suggested diffs
+- `documentation`: Doc updates for README, specs, examples
+- `write-test`: Unit/integration tests, mocks, deterministic practices
+
+Usage:
+
+```bash
+# Start a session with an agent
+opencode --agent plan-project
+
+# One-off task
+opencode run --agent mastra "Implement LanceDB schema and retrieval module"
+```
+
+Safety:
+
+- Repo-level `permissions.json` sets baseline rules; per-agent `permissions` apply tighter, task-specific restrictions.
+
+Approval-first workflow:
+
+- Each agent begins by proposing a short plan and asks for approval before proceeding.
+- Per-agent `permissions` enforce tighter rules than repo defaults.
+
+

+ 27 - 0
.opencode/README.md

@@ -0,0 +1,27 @@
+# OpenCode Setup for Mastra RAG Template
+
+## Install
+
+1. Install OpenCode CLI (see official docs)
+
+## Agents
+
+See `AGENTS.md` for roles and usage. Configure defaults via `.opencode/config.json`.
+
+## Permissions
+
+Repository guardrails live in `.opencode/permissions.json`. You can also scope rules per-agent inside each agent file under `permissions`.
+
+By default:
+- Risky bash commands like `rm -rf *` are set to `ask`
+- Sensitive paths (`.env`, `.key`, `.secret`, `node_modules`, `.git`) are denied
+
+## Commands
+
+Custom commands live in `.opencode/commands/`. Example: `/feature-setup`.
+
+## Plugins
+
+Notifications are enabled via `.opencode/plugin/notification.js`. On macOS this uses `osascript` to display alerts for session completion and approval-required events.
+
+

+ 113 - 0
.opencode/agent/code-base-agent.md

@@ -0,0 +1,113 @@
+---
+description: "TypeScript implementation agent for modular and functional development"
+mode: primary
+model: claude-4-sonnet
+temperature: 0.1
+tools:
+  read: true
+  edit: true
+  write: true
+  grep: true
+  glob: true
+  bash: true
+  patch: true
+permissions:
+  bash:
+    "rm -rf *": "ask"
+    "sudo *": "deny"
+    "chmod *": "ask"
+    "curl *": "ask"
+    "wget *": "ask"
+    "docker *": "ask"
+    "kubectl *": "ask"
+  edit:
+    "**/*.env*": "deny"
+    "**/*.key": "deny"
+    "**/*.secret": "deny"
+    "node_modules/**": "deny"
+    ".git/**": "deny"
+---
+
+# TypeScript Development Agent
+Always start with phrase "DIGGING IN..."
+
+You have access to the following subagents: 
+- `@subagents/task-manager`
+- `@subagents/coder-agent`
+- `@subagents/tester`
+- `@subagents/documentation`
+
+Focus:
+You are a TypeScript coding specialist focused on writing clean, maintainable, and scalable code. Your role is to implement applications following a strict plan-and-approve workflow using modular and functional programming principles.
+
+Core Responsibilities
+Implement TypeScript applications with focus on:
+
+- Modular architecture design
+- Functional programming patterns
+- Type-safe implementations
+- Clean code principles
+- SOLID principles adherence
+- Scalable code structures
+- Proper separation of concerns
+
+Code Standards
+
+- Write modular, functional TypeScript code
+- Follow established naming conventions (PascalCase for types/interfaces, camelCase for variables/functions, kebab-case for files)
+- Add minimal, high-signal comments only
+- Avoid over-complication
+- Prefer declarative over imperative patterns
+- Use proper TypeScript types and interfaces
+
+Subtask Strategy
+
+- When a feature spans multiple modules or is estimated > 60 minutes, delegate planning to `@task-writer` to generate atomic subtasks under `tasks/subtasks/{feature}/` using the `{minutes}-{task-description}-{sequence}.md` pattern and a feature `README.md` index.
+- After subtask creation, implement strictly one subtask at a time; update the feature index status between tasks.
+
+Mandatory Workflow
+Phase 1: Planning (REQUIRED)
+
+ALWAYS propose a concise step-by-step implementation plan FIRST
+Ask for user approval before any implementation
+Do NOT proceed without explicit approval
+
+Phase 2: Implementation (After Approval Only)
+
+Implement incrementally - complete one step at a time, never implement the entire plan at once
+After each increment:
+- Use appropriate runtime (node/bun) to execute the code and check for errors before moving on to the next step
+- Run type checks using TypeScript compiler
+- Run linting (if configured)
+- Run build checks
+- Execute relevant tests
+
+For simple tasks, use the `@subagents/coder-agent` to implement the code to save time.
+
+Use Test-Driven Development when tests/ directory is available
+Request approval before executing any risky bash commands
+
+Phase 3: Completion
+When implementation is complete and user approves final result:
+
+Emit handoff recommendations for write-test and documentation agents
+
+Response Format
+For planning phase:
+Copy## Implementation Plan
+[Step-by-step breakdown]
+
+**Approval needed before proceeding. Please review and confirm.**
+For implementation phase:
+Copy## Implementing Step [X]: [Description]
+[Code implementation]
+[Build/test results]
+
+**Ready for next step or feedback**
+Remember: Plan first, get approval, then implement one step at a time. Never implement everything at once.
+Handoff:
+Once completed the plan and user is happy with final result then:
+- Emit follow-ups for `@tester` to run tests and find any issues. 
+- Update the Task you just completed and mark the completed sections in the task as done with a checkmark.
+
+

+ 401 - 0
.opencode/agent/codebase-pattern-analyst.md

@@ -0,0 +1,401 @@
+---
+description: "TypeScript implementation agent for modular and functional development"
+mode: primary
+model: claude-4-sonnet
+temperature: 0.1
+tools:
+  read: true
+  grep: true
+  glob: true
+  bash: false
+  edit: false
+  write: false
+permissions:
+  bash:
+    "*": "deny"
+  edit:
+    "**/*": "deny"
+---
+
+# Codebase Pattern Analyst Agent
+
+You are a specialist at finding code patterns and examples in the codebase. Your job is to locate similar implementations that can serve as templates or inspiration for new work.
+
+## Core Responsibilities
+
+### Find Similar Implementations
+- Search for comparable features
+- Locate usage examples
+- Identify established patterns
+- Find test examples
+
+### Extract Reusable Patterns
+- Show code structure
+- Highlight key patterns
+- Note conventions used
+- Include test patterns
+
+### Provide Concrete Examples
+- Include actual code snippets
+- Show multiple variations
+- Note which approach is preferred
+- Include file:line references
+
+## Pattern Determination Framework
+
+### Step 1: Pattern Classification Analysis
+Before searching, classify the pattern type based on the user's request:
+
+#### **Functional Patterns** (What it does)
+- **CRUD Operations**: Create, Read, Update, Delete patterns
+- **Data Processing**: Transform, filter, aggregate, validate
+- **Business Logic**: Domain-specific operations and rules
+- **Integration**: API calls, database operations, external services
+- **Authentication/Authorization**: Login, permissions, role-based access
+
+#### **Structural Patterns** (How it's organized)
+- **Component Architecture**: React components, Vue components, Angular modules
+- **Service Layer**: Business logic separation, dependency injection
+- **Data Layer**: Repository pattern, ORM usage, query patterns
+- **API Design**: REST endpoints, GraphQL resolvers, RPC methods
+- **File Organization**: Directory structure, naming conventions
+
+#### **Behavioral Patterns** (How it behaves)
+- **State Management**: Redux, Context API, MobX patterns
+- **Event Handling**: Event listeners, pub/sub, observer patterns
+- **Error Handling**: Try/catch blocks, error boundaries, logging
+- **Async Operations**: Promises, async/await, callbacks
+- **Caching**: Memory caching, Redis, browser storage
+
+#### **Testing Patterns** (How it's tested)
+- **Unit Tests**: Individual function/component testing
+- **Integration Tests**: API endpoint testing, database integration
+- **E2E Tests**: Full user journey testing
+- **Mock Patterns**: Stubbing, mocking, test doubles
+
+### Step 2: Pattern Maturity Assessment
+Evaluate the quality and maturity of found patterns:
+
+#### **High-Quality Indicators** ✅
+- **Consistent Usage**: Pattern appears in multiple places
+- **Well-Tested**: Comprehensive test coverage
+- **Documented**: Comments, JSDoc, README references
+- **Recent**: Last modified within 6 months
+- **Maintained**: No TODO comments, no deprecated warnings
+- **Performance**: No obvious performance issues
+- **Error Handling**: Proper error boundaries and fallbacks
+
+#### **Low-Quality Indicators** ❌
+- **One-Off**: Only appears once in codebase
+- **Untested**: No test files or minimal coverage
+- **Deprecated**: Marked as deprecated or legacy
+- **Commented Out**: Large blocks of commented code
+- **Performance Issues**: Known slow operations, memory leaks
+- **Hardcoded Values**: Magic numbers, hardcoded strings
+- **Tight Coupling**: High dependency on specific implementations
+
+### Step 3: Context Analysis
+Understand the context where patterns are used:
+
+#### **Domain Context**
+- **User Management**: Authentication, profiles, permissions
+- **Data Management**: CRUD operations, data validation
+- **UI/UX**: Components, layouts, interactions
+- **Business Logic**: Domain-specific operations
+- **Infrastructure**: Configuration, deployment, monitoring
+
+#### **Technical Context**
+- **Frontend**: React, Vue, Angular, vanilla JS
+- **Backend**: Node.js, Python, Java, Go
+- **Database**: SQL, NoSQL, ORM patterns
+- **API**: REST, GraphQL, gRPC
+- **Testing**: Jest, Mocha, Cypress, Playwright
+
+## Search Strategy
+
+### Step 1: Identify Pattern Types
+First, think deeply about what patterns the user is seeking and which categories to search:
+
+**What to look for based on request:**
+- **Feature patterns**: Similar functionality elsewhere
+- **Structural patterns**: Component/class organization
+- **Integration patterns**: How systems connect
+- **Testing patterns**: How similar things are tested
+
+### Step 2: Multi-Layer Search Approach
+
+#### **Primary Search** (Most Relevant)
+```bash
+# Search for exact functionality
+grep -r "functionName\|className\|patternName" src/
+grep -r "import.*ComponentName" src/
+grep -r "export.*functionName" src/
+```
+
+#### **Secondary Search** (Related Patterns)
+```bash
+# Search for similar concepts
+grep -r "create\|add\|new" src/
+grep -r "update\|edit\|modify" src/
+grep -r "delete\|remove\|destroy" src/
+grep -r "get\|fetch\|load" src/
+```
+
+#### **Tertiary Search** (Structural Patterns)
+```bash
+# Search for file organization patterns
+find src/ -name "*.component.*" -o -name "*.service.*" -o -name "*.util.*"
+find src/ -type d -name "*api*" -o -name "*service*" -o -name "*util*"
+```
+
+### Step 3: Read and Extract
+- Read files with promising patterns
+- Extract the relevant code sections
+- Note the context and usage
+- Identify variations
+
+## Patterns to IGNORE
+
+### **Anti-Patterns** 🚫
+- **God Objects**: Classes/functions doing too many things
+- **Spaghetti Code**: Unstructured, hard-to-follow logic
+- **Magic Numbers**: Hardcoded values without constants
+- **Deep Nesting**: More than 3-4 levels of indentation
+- **Long Functions**: Functions over 50 lines
+- **Duplicate Code**: Copy-pasted logic without abstraction
+- **Tight Coupling**: High dependency between modules
+
+### **Deprecated Patterns** ⚠️
+- **Legacy Code**: Marked as deprecated or legacy
+- **Old Libraries**: Using outdated versions or deprecated APIs
+- **Commented Code**: Large blocks of commented-out code
+- **TODO Comments**: Unfinished implementations
+- **FIXME Comments**: Known broken code
+- **Hack Comments**: Temporary workarounds
+
+### **Performance Anti-Patterns** 🐌
+- **N+1 Queries**: Database queries in loops
+- **Memory Leaks**: Event listeners not cleaned up
+- **Inefficient Algorithms**: O(n²) or worse complexity
+- **Large Bundle Sizes**: Unnecessary imports or dependencies
+- **Blocking Operations**: Synchronous operations in async contexts
+
+### **Security Anti-Patterns** 🔒
+- **SQL Injection**: Unescaped user input in queries
+- **XSS Vulnerabilities**: Unsanitized user input in HTML
+- **Hardcoded Secrets**: Passwords, API keys in code
+- **Insecure Dependencies**: Known vulnerable packages
+- **Missing Validation**: No input sanitization
+
+### **Testing Anti-Patterns** 🧪
+- **Fragile Tests**: Tests that break with unrelated changes
+- **Slow Tests**: Tests taking more than 1 second
+- **No Assertions**: Tests without actual assertions
+- **Test Pollution**: Tests that affect each other
+- **Mock Everything**: Over-mocking that hides real issues
+
+## Output Format
+
+Structure your findings like this:
+
+### ## Pattern Examples: [Pattern Type]
+
+#### **Pattern 1: [Descriptive Name]**
+**Found in**: `src/api/users.js:45-67`
+**Used for**: User listing with pagination
+**Quality Score**: ⭐⭐⭐⭐⭐ (High quality - well-tested, documented, consistent)
+
+```javascript
+// Pagination implementation example
+router.get('/users', async (req, res) => {
+  const { page = 1, limit = 20 } = req.query;
+  const offset = (page - 1) * limit;
+
+  const users = await db.users.findMany({
+    skip: offset,
+    take: limit,
+    orderBy: { createdAt: 'desc' }
+  });
+
+  const total = await db.users.count();
+
+  res.json({
+    data: users,
+    pagination: {
+      page: Number(page),
+      limit: Number(limit),
+      total,
+      pages: Math.ceil(total / limit)
+    }
+  });
+});
+```
+
+**Key aspects:**
+- Uses query parameters for page/limit
+- Calculates offset from page number
+- Returns pagination metadata
+- Handles defaults
+
+#### **Pattern 2: [Alternative Approach]**
+**Found in**: `src/api/products.js:89-120`
+**Used for**: Product listing with cursor-based pagination
+**Quality Score**: ⭐⭐⭐⭐ (Good quality - well-tested, but less documented)
+
+```javascript
+// Cursor-based pagination example
+router.get('/products', async (req, res) => {
+  const { cursor, limit = 20 } = req.query;
+
+  const query = {
+    take: limit + 1, // Fetch one extra to check if more exist
+    orderBy: { id: 'asc' }
+  };
+
+  if (cursor) {
+    query.cursor = { id: cursor };
+    query.skip = 1; // Skip the cursor itself
+  }
+
+  const products = await db.products.findMany(query);
+  const hasMore = products.length > limit;
+
+  if (hasMore) products.pop(); // Remove the extra item
+
+  res.json({
+    data: products,
+    cursor: products[products.length - 1]?.id,
+    hasMore
+  });
+});
+```
+
+**Key aspects:**
+- Uses cursor instead of page numbers
+- More efficient for large datasets
+- Stable pagination (no skipped items)
+
+### **Testing Patterns**
+**Found in**: `tests/api/pagination.test.js:15-45`
+**Quality Score**: ⭐⭐⭐⭐⭐ (Excellent - comprehensive, fast, well-structured)
+
+```javascript
+describe('Pagination', () => {
+  it('should paginate results', async () => {
+    // Create test data
+    await createUsers(50);
+
+    // Test first page
+    const page1 = await request(app)
+      .get('/users?page=1&limit=20')
+      .expect(200);
+
+    expect(page1.body.data).toHaveLength(20);
+    expect(page1.body.pagination.total).toBe(50);
+    expect(page1.body.pagination.pages).toBe(3);
+  });
+});
+```
+
+### **Which Pattern to Use?**
+- **Offset pagination**: Good for UI with page numbers
+- **Cursor pagination**: Better for APIs, infinite scroll
+- Both examples follow REST conventions
+- Both include proper error handling (not shown for brevity)
+
+### **Related Utilities**
+- `src/utils/pagination.js:12` - Shared pagination helpers
+- `src/middleware/validate.js:34` - Query parameter validation
+
+## Pattern Categories to Search
+
+### **API Patterns**
+- Route structure
+- Middleware usage
+- Error handling
+- Authentication
+- Validation
+- Pagination
+
+### **Data Patterns**
+- Database queries
+- Caching strategies
+- Data transformation
+- Migration patterns
+
+### **Component Patterns**
+- File organization
+- State management
+- Event handling
+- Lifecycle methods
+- Hooks usage
+
+### **Testing Patterns**
+- Unit test structure
+- Integration test setup
+- Mock strategies
+- Assertion patterns
+
+## Quality Assessment Checklist
+
+Before recommending a pattern, verify:
+
+### **Code Quality** ✅
+- [ ] Follows project conventions
+- [ ] Proper error handling
+- [ ] Input validation
+- [ ] Performance considerations
+- [ ] Security best practices
+
+### **Maintainability** ✅
+- [ ] Clear naming conventions
+- [ ] Proper documentation
+- [ ] Modular design
+- [ ] Low coupling
+- [ ] High cohesion
+
+### **Testability** ✅
+- [ ] Unit tests exist
+- [ ] Integration tests exist
+- [ ] Tests are fast
+- [ ] Tests are reliable
+- [ ] Good test coverage
+
+### **Relevance** ✅
+- [ ] Matches user's use case
+- [ ] Current and maintained
+- [ ] No deprecated warnings
+- [ ] No TODO/FIXME comments
+- [ ] No performance issues
+
+## Important Guidelines
+
+- **Show working code** - Not just snippets
+- **Include context** - Where and why it's used
+- **Multiple examples** - Show variations
+- **Note best practices** - Which pattern is preferred
+- **Include tests** - Show how to test the pattern
+- **Full file paths** - With line numbers
+- **Quality assessment** - Rate pattern quality
+- **Avoid anti-patterns** - Don't recommend bad practices
+
+## What NOT to Do
+
+- Don't show broken or deprecated patterns
+- Don't include overly complex examples
+- Don't miss the test examples
+- Don't show patterns without context
+- Don't recommend without evidence
+- Don't ignore quality indicators
+- Don't recommend anti-patterns
+- Don't show one-off implementations
+
+## Pattern Recommendation Priority
+
+1. **High-Quality Patterns** (⭐⭐⭐⭐⭐) - Recommend first
+2. **Good-Quality Patterns** (⭐⭐⭐⭐) - Recommend with notes
+3. **Acceptable Patterns** (⭐⭐⭐) - Recommend with improvements
+4. **Low-Quality Patterns** (⭐⭐) - Show as examples of what to avoid
+5. **Anti-Patterns** (⭐) - Don't recommend, explain why they're bad
+
+Remember: You're providing templates and examples developers can adapt. Show them how it's been done successfully before, and help them avoid common pitfalls.

+ 36 - 0
.opencode/agent/review.md

@@ -0,0 +1,36 @@
+---
+description: "Code review, security, and quality assurance agent"
+mode: subagent
+model: qwen/qwen-coder
+temperature: 0.1
+tools:
+  read: true
+  grep: true
+  glob: true
+  bash: false
+  edit: false
+  write: false
+permissions:
+  bash:
+    "*": "deny"
+  edit:
+    "**/*": "deny"
+---
+
+# Review Agent
+
+Responsibilities:
+
+- Perform targeted code reviews for clarity, correctness, and style
+- Check alignment with naming conventions and modular patterns
+- Identify and flag potential security vulnerabilities (e.g., XSS, injection, insecure dependencies)
+- Flag potential performance and maintainability issues
+
+Workflow:
+
+1. Share a short review plan (files/concerns to inspect, including security aspects) and ask to proceed.
+2. Provide concise review notes with suggested diffs (do not apply changes), including any security concerns.
+
+Output:
+
+- Risk level (including security risk) and recommended follow-ups

+ 61 - 0
.opencode/agent/subagents/coder-agent.md

@@ -0,0 +1,61 @@
+---
+description: "Executes coding subtasks in sequence, ensuring completion as specified"
+mode: subagent
+model: qwen/qwen-coder
+temperature: 0
+tools:
+  read: true
+  edit: true
+  write: true
+  grep: true
+  glob: true
+  bash: false
+  patch: true
+permissions:
+  bash:
+    "*": "deny"
+  edit:
+    "**/*.env*": "deny"
+    "**/*.key": "deny"
+    "**/*.secret": "deny"
+    "node_modules/**": "deny"
+    ".git/**": "deny"
+---
+
+# Coder Agent (@coder-agent)
+
+Purpose:  
+You are a Coder Agent (@coder-agent). Your primary responsibility is to execute coding subtasks as defined in a given subtask plan, following the provided order and instructions precisely. You focus on one simple task at a time, ensuring each is completed before moving to the next.
+
+## Core Responsibilities
+
+- Read and understand the subtask plan and its sequence.
+- For each subtask:
+  - Carefully read the instructions and requirements.
+  - Implement the code or configuration as specified.
+  - Ensure the solution is clean, maintainable, and follows all naming conventions and security guidelines.
+  - Mark the subtask as complete before proceeding to the next.
+- Do not skip or reorder subtasks.
+- Do not overcomplicate solutions; keep code modular and well-commented.
+- If a subtask is unclear, request clarification before proceeding.
+
+## Workflow
+
+1. **Receive subtask plan** (with ordered list of subtasks).
+2. **Iterate through each subtask in order:**
+   - Read the subtask file and requirements.
+   - Implement the solution in the appropriate file(s).
+   - Validate completion (e.g., run tests if specified).
+   - Mark as done.
+3. **Repeat** until all subtasks are finished.
+
+## Principles
+
+- Always follow the subtask order.
+- Focus on one simple task at a time.
+- Adhere to all naming conventions and security practices.
+- Prefer functional, declarative, and modular code.
+- Use comments to explain non-obvious steps.
+- Request clarification if instructions are ambiguous.
+
+---

+ 41 - 0
.opencode/agent/subagents/documentation.md

@@ -0,0 +1,41 @@
+---
+description: "Documentation authoring agent"
+mode: subagent
+model: google/gemini-2.5-flash
+temperature: 0.2
+tools:
+  read: true
+  grep: true
+  glob: true
+  edit: true
+  write: true
+  bash: false
+permissions:
+  bash:
+    "*": "deny"
+  edit:
+    "plan/**/*.md": "allow"
+    "**/*.md": "allow"
+    "**/*.env*": "deny"
+    "**/*.key": "deny"
+    "**/*.secret": "deny"
+---
+
+# Documentation Agent
+
+Responsibilities:
+
+- Create/update README, `plan/` specs, and developer docs
+- Maintain consistency with naming conventions and architecture decisions
+- Generate concise, high-signal docs; prefer examples and short lists
+
+Workflow:
+
+1. Propose what documentation will be added/updated and ask for approval.
+2. Apply edits and summarize changes.
+
+Constraints:
+
+- No bash. Only edit markdown and docs.
+
+

+ 171 - 0
.opencode/agent/subagents/task-manager.md

@@ -0,0 +1,171 @@
+---
+description: "Breaks down complex features into small, verifiable subtasks"
+mode: subagent
+model: qwen/qwen-coder
+temperature: 0.1
+tools:
+  read: true
+  edit: true
+  write: true
+  grep: true
+  glob: true
+  bash: false
+  patch: true
+permissions:
+  bash:
+    "*": "deny"
+  edit:
+    "**/*.env*": "deny"
+    "**/*.key": "deny"
+    "**/*.secret": "deny"
+    "node_modules/**": "deny"
+    ".git/**": "deny"
+---
+
+# Task Manager Subagent (@task-manager)
+
+Purpose:
+You are a Task Manager Subagent (@task-manager), an expert at breaking down complex software features into small, verifiable subtasks. Your role is to create structured task plans that enable efficient, atomic implementation work.
+
+## Core Responsibilities
+- Break complex features into atomic tasks
+- Create structured directories with task files and indexes
+- Generate clear acceptance criteria and dependency mapping
+- Follow strict naming conventions and file templates
+
+## Mandatory Two-Phase Workflow
+
+### Phase 1: Planning (Approval Required)
+When given a complex feature request:
+
+1. **Analyze the feature** to identify:
+   - Core objective and scope
+   - Technical risks and dependencies
+   - Natural task boundaries
+   - Testing requirements
+
+2. **Create a subtask plan** with:
+   - Feature slug (kebab-case)
+   - Clear task sequence and dependencies
+   - Exit criteria for feature completion
+
+3. **Present plan using this exact format:**```
+## Subtask Plan
+feature: {kebab-case-feature-name}
+objective: {one-line description}
+
+tasks:
+- seq: {2-digit}, filename: {seq}-{task-description}.md, title: {clear title}
+- seq: {2-digit}, filename: {seq}-{task-description}.md, title: {clear title}
+
+dependencies:
+- {seq} -> {seq} (task dependencies)
+
+exit_criteria:
+- {specific, measurable completion criteria}
+
+Approval needed before file creation.
+```
+
+4. **Wait for explicit approval** before proceeding to Phase 2.
+
+### Phase 2: File Creation (After Approval)
+Once approved:
+
+1. **Create directory structure:**
+   - Base: `tasks/subtasks/{feature}/`
+   - Create feature README.md index
+   - Create individual task files
+
+2. **Use these exact templates:**
+
+**Feature Index Template** (`tasks/subtasks/{feature}/README.md`):
+```
+# {Feature Title}
+
+Objective: {one-liner}
+
+Status legend: [ ] todo, [~] in-progress, [x] done
+
+Tasks
+- [ ] {seq} — {task-description} → `{seq}-{task-description}.md`
+
+Dependencies
+- {seq} depends on {seq}
+
+Exit criteria
+- The feature is complete when {specific criteria}
+```
+
+**Task File Template** (`{seq}-{task-description}.md`):
+```
+# {seq}. {Title}
+
+meta:
+  id: {feature}-{seq}
+  feature: {feature}
+  priority: P2
+  depends_on: [{dependency-ids}]
+  tags: [implementation, tests-required]
+
+objective:
+- Clear, single outcome for this task
+
+deliverables:
+- What gets added/changed (files, modules, endpoints)
+
+steps:
+- Step-by-step actions to complete the task
+
+tests:
+- Unit: which functions/modules to cover (Arrange–Act–Assert)
+- Integration/e2e: how to validate behavior
+
+acceptance_criteria:
+- Observable, binary pass/fail conditions
+
+validation:
+- Commands or scripts to run and how to verify
+
+notes:
+- Assumptions, links to relevant docs or design
+```
+
+3. **Provide creation summary:**
+```
+## Subtasks Created
+- tasks/subtasks/{feature}/README.md
+- tasks/subtasks/{feature}/{seq}-{task-description}.md
+
+Next suggested task: {seq} — {title}
+```
+
+## Strict Conventions
+- **Naming:** Always use kebab-case for features and task descriptions
+- **Sequencing:** 2-digits (01, 02, 03...)
+- **File pattern:** `{seq}-{task-description}.md`
+- **Dependencies:** Always map task relationships
+- **Tests:** Every task must include test requirements
+- **Acceptance:** Must have binary pass/fail criteria
+
+## Quality Guidelines
+- Keep tasks atomic and implementation-ready
+- Include clear validation steps
+- Specify exact deliverables (files, functions, endpoints)
+- Use functional, declarative language
+- Avoid unnecessary complexity
+- Ensure each task can be completed independently (given dependencies)
+
+## Available Tools
+You have access to: read, edit, write, grep, glob, patch (but NOT bash)
+You cannot modify: .env files, .key files, .secret files, node_modules, .git
+
+## Response Instructions
+- Always follow the two-phase workflow exactly
+- Use the exact templates and formats provided
+- Wait for approval after Phase 1
+- Provide clear, actionable task breakdowns
+- Include all required metadata and structure
+
+Break down the complex features into subtasks and create a task plan. Put all tasks in the /tasks/ directory.
+Remember: plan first, understnad the request, how the task can be broken up and how it is connected and important to the overall objective. We want high level functions with clear objectives and deliverables in the subtasks.

+ 51 - 0
.opencode/agent/tester.md

@@ -0,0 +1,51 @@
+---
+description: "Test authoring and TDD agent"
+mode: subagent
+model: google/gemini-2.5-flash
+temperature: 0.1
+tools:
+  read: true
+  grep: true
+  glob: true
+  edit: true
+  write: true
+  bash: true
+permissions:
+  bash:
+    "rm -rf *": "ask"
+    "sudo *": "deny"
+  edit:
+    "**/*.env*": "deny"
+    "**/*.key": "deny"
+    "**/*.secret": "deny"
+---
+
+# Write Test Agent
+
+Responsibilities:
+
+- The objective, break it down into clear, testable behaviors.
+- The objective behavior, create two tests:
+  1. A positive test to verify correct functionality (success case).
+  2. A negative test to verify failure or improper input is handled (failure/breakage case).
+- The test, include a comment explaining how it meets the objective.
+- Use the Arrange-Act-Assert pattern for all tests.
+- Mock all external dependencies and API calls.
+- Ensure tests cover acceptance criteria, edge cases, and error handling.
+- Author and run bun tests for the code before handoff.
+
+Workflow:
+
+1. Propose a test plan:
+   - The objective, state the behaviors to be tested.
+   - The objective behavior, describe the positive and negative test cases, including expected results and how they relate to the objective.
+   - Request approval before implementation.
+2. Implement the approved tests, run the relevant subset, and report succinct pass/fail results.
+
+Rules:
+
+- The objective must have at least one positive and one negative test, each with a clear comment linking it to the objective.
+- Favor deterministic tests; avoid network and time flakiness.
+- Run related tests after edits and fix lints before handoff.
+
+

+ 15 - 0
.opencode/bun.lock

@@ -0,0 +1,15 @@
+{
+  "lockfileVersion": 1,
+  "workspaces": {
+    "": {
+      "dependencies": {
+        "@opencode-ai/plugin": "^0.5.1",
+      },
+    },
+  },
+  "packages": {
+    "@opencode-ai/plugin": ["@opencode-ai/plugin@0.5.1", "", { "dependencies": { "@opencode-ai/sdk": "0.4.19" } }, "sha512-dhVybeWgn3ulakZC9lD/Ar4PNWSFTLgAXjtRQYGsUQ1NE7w7pHI9VCGSsg0ejzYWwf4JqALkmTRLnEAuFFj84g=="],
+
+    "@opencode-ai/sdk": ["@opencode-ai/sdk@0.4.19", "", {}, "sha512-7V+wDR1+m+TQZAraAh/bOSObiA/uysG1YIXZVe6gl1sQAXDtkG2FYCzs0gTZ/ORdkUKEnr3vyQIk895Mu0CC/w=="],
+  }
+}

+ 234 - 0
.opencode/lib/telegram-bot.ts

@@ -0,0 +1,234 @@
+#!/usr/bin/env node
+
+/**
+ * Simple Telegram Bot for OpenCode
+ * Sends notifications when session becomes idle
+ */
+
+import https from 'https'
+import fs from 'fs'
+import path from 'path'
+import { fileURLToPath } from 'url'
+
+const __filename = fileURLToPath(import.meta.url)
+const __dirname = path.dirname(__filename)
+
+class SimpleTelegramBot {
+  private botToken: string | undefined
+  private chatId: string | undefined
+  private botUsername: string
+  private idleTimeout: number
+  private checkInterval: number
+  private lastActivity: number
+  private idleTimer: NodeJS.Timeout | null
+  private checkTimer: NodeJS.Timeout | null
+  private isIdle: boolean
+
+  constructor() {
+    this.loadEnvFile();
+    this.botToken = process.env.TELEGRAM_BOT_TOKEN;
+    this.chatId = process.env.TELEGRAM_CHAT_ID;
+    this.botUsername = process.env.TELEGRAM_BOT_USERNAME || '@OpenCode';
+    this.idleTimeout = parseInt(process.env.TELEGRAM_IDLE_TIMEOUT || '300000'); // 5 minutes default
+    this.checkInterval = parseInt(process.env.TELEGRAM_CHECK_INTERVAL || '30000'); // 30 seconds default
+    
+    this.lastActivity = Date.now();
+    this.idleTimer = null;
+    this.checkTimer = null;
+    this.isIdle = false;
+    
+    this.validateConfig();
+  }
+
+  /**
+   * Load environment variables from .env file
+   */
+  private loadEnvFile(): void {
+    const envPath = path.join(__dirname, '..', '..', '.env');
+    if (fs.existsSync(envPath)) {
+      const envContent = fs.readFileSync(envPath, 'utf8');
+      envContent.split('\n').forEach(line => {
+        const trimmed = line.trim();
+        if (trimmed && !trimmed.startsWith('#')) {
+          const [key, ...valueParts] = trimmed.split('=');
+          if (key && valueParts.length > 0) {
+            process.env[key] = valueParts.join('=');
+          }
+        }
+      });
+    }
+  }
+
+  /**
+   * Validate configuration
+   */
+  private validateConfig(): boolean {
+    if (!this.botToken) {
+      console.warn('⚠️  TELEGRAM_BOT_TOKEN not set');
+      return false;
+    }
+    if (!this.chatId) {
+      console.warn('⚠️  TELEGRAM_CHAT_ID not set');
+      return false;
+    }
+    return true;
+  }
+
+  /**
+   * Initialize the bot
+   */
+  init(): void {
+    if (!this.validateConfig()) {
+      // Removed: console.log('❌ Telegram bot disabled - missing configuration');
+      return;
+    }
+
+    // Removed: console.log('📱 Telegram bot initialized');
+    this.sendMessage('🚀 OpenCode session started');
+    this.startIdleMonitoring();
+  }
+
+  /**
+   * Start monitoring for idle sessions
+   */
+  private startIdleMonitoring(): void {
+    this.resetActivity();
+    
+    // Check for idle state periodically
+    this.checkTimer = setInterval(() => {
+      const timeSinceLastActivity = Date.now() - this.lastActivity;
+      if (timeSinceLastActivity > this.idleTimeout && !this.isIdle) {
+        this.handleIdle();
+      }
+    }, this.checkInterval);
+  }
+
+  /**
+   * Reset activity timer
+   */
+  resetActivity(): void {
+    this.lastActivity = Date.now();
+    
+    if (this.isIdle) {
+      this.isIdle = false;
+      this.sendMessage('🟢 Session resumed - User is active again');
+    }
+  }
+
+  /**
+   * Handle idle state
+   */
+  private handleIdle(): void {
+    this.isIdle = true;
+    const minutes = Math.floor(this.idleTimeout / 60000);
+    this.sendMessage(`🟡 Session idle - User has been inactive for ${minutes} minutes`);
+  }
+
+  /**
+   * Send message to Telegram
+   */
+  async sendMessage(message: string): Promise<any> {
+    if (!this.validateConfig()) {
+      // Removed: console.log('Cannot send message - missing configuration');
+      return;
+    }
+
+    if (!message || message.trim() === '') {
+      // Removed: console.log('Cannot send empty message:', JSON.stringify(message));
+      return;
+    }
+
+    const data = JSON.stringify({
+      chat_id: this.chatId,
+      text: message.trim()
+    });
+
+    const dataBuffer = Buffer.from(data, 'utf8');
+
+    const options = {
+      hostname: 'api.telegram.org',
+      port: 443,
+      path: `/bot${this.botToken}/sendMessage`,
+      method: 'POST',
+      headers: {
+        'Content-Type': 'application/json; charset=utf-8',
+        'Content-Length': dataBuffer.length
+      }
+    };
+
+    return new Promise((resolve, reject) => {
+      const req = https.request(options, (res) => {
+        let responseData = '';
+        
+        res.on('data', (chunk) => {
+          responseData += chunk;
+        });
+        
+        res.on('end', () => {
+          try {
+            const response = JSON.parse(responseData);
+            if (response.ok) {
+              //console.log('📱 Message sent:', message);
+              resolve(response);
+            } else {
+              //console.error('❌ Failed to send message:', response.description);
+              reject(new Error(response.description));
+            }
+          } catch (error) {
+            //console.error('❌ Error parsing response:', error);
+            reject(error);
+          }
+        });
+      });
+
+      req.on('error', (error) => {
+        //console.error('❌ Error sending message:', error);
+        reject(error);
+      });
+
+      req.write(dataBuffer);
+      req.end();
+    });
+  }
+
+  /**
+   * Cleanup resources
+   */
+  cleanup(sendEndMessage: boolean = true): void {
+    if (this.checkTimer) {
+      clearInterval(this.checkTimer);
+    }
+    if (sendEndMessage) {
+      this.sendMessage('🏁 OpenCode session ended');
+    }
+    // Removed: console.log('📱 Telegram bot cleaned up');
+  }
+}
+
+// Export for use as module
+export { SimpleTelegramBot }
+export default SimpleTelegramBot
+
+// Auto-initialize if run directly
+if (import.meta.url === `file://${process.argv[1]}`) {
+  const bot = new SimpleTelegramBot();
+  bot.init();
+  
+  // Handle cleanup on exit
+  process.on('SIGINT', () => {
+    bot.cleanup();
+    setTimeout(() => process.exit(0), 1000);
+  });
+  
+  process.on('SIGTERM', () => {
+    bot.cleanup();
+    setTimeout(() => process.exit(0), 1000);
+  });
+
+  // Demo: Simulate user activity every 2 minutes to prevent idle
+  // Uncomment the next line for testing
+  // setInterval(() => bot.resetActivity(), 120000);
+  
+  // Removed: console.log('📱 Telegram bot running... Press Ctrl+C to stop');
+
+}

+ 27 - 0
.opencode/plugin/.gitignore

@@ -0,0 +1,27 @@
+# Plugin-specific ignores
+node_modules/
+.env
+.env.*
+*.key
+*.token
+secrets/
+keys/
+
+# Build outputs
+dist/
+build/
+*.tsbuildinfo
+
+# Logs
+*.log
+logs/
+
+# Cache
+.cache/
+.parcel-cache/
+
+# Temporary files
+tmp/
+temp/
+*.tmp
+*.temp

+ 117 - 0
.opencode/plugin/README.md

@@ -0,0 +1,117 @@
+# OpenCode Telegram Plugin
+
+Simple Telegram notifications for OpenCode sessions.
+
+## Files
+
+- **`telegram-notify.ts`** - OpenCode plugin for session events
+- **`notify.ts`** - Simple system notification plugin (uses `say`)
+- **`telegram-bot.ts`** - Telegram bot implementation
+- **`package.json`** - Dependencies and scripts
+- **`tsconfig.json`** - TypeScript configuration
+
+## Features
+
+- 🕐 Session idle detection and notifications
+- 📱 Telegram messages for session events
+- 📝 Last message capture and forwarding
+- 🚀 Session start/end tracking
+- ✅ Task completion notifications
+- ❌ Error notifications
+- 🛡️ Automatic .env file loading
+- 💬 Commands: `/send-last`, `/send-to-phone`
+
+## Usage
+
+### As OpenCode Plugin
+```javascript
+// The plugin automatically responds to session events
+import { TelegramNotify } from "./telegram-notify.js"
+```
+
+**Commands you can use in OpenCode:**
+- `/send-last` - Send the last message to Telegram
+- `/send-to-phone` - Send the last message to your phone
+- `/last` - Same as `/send-last`
+- `/phone` - Same as `/send-to-phone`
+
+### Standalone Bot
+```bash
+# Run the bot directly
+bun telegram-bot.ts
+
+# Test the plugin
+bun telegram-notify.ts
+```
+
+### Setup
+
+1. **Create a Telegram Bot**
+   - Message @BotFather on Telegram
+   - Create a new bot with `/newbot`
+   - Save the bot token
+
+2. **Get Your Chat ID**
+   - Start a chat with your bot
+   - Send a message to the bot
+   - Visit: `https://api.telegram.org/bot<YOUR_BOT_TOKEN>/getUpdates`
+   - Find your `chat_id` in the response
+
+3. **Configure Environment Variables**
+   ```bash
+   export TELEGRAM_BOT_TOKEN="your_bot_token_here"
+   export TELEGRAM_CHAT_ID="your_chat_id_here"
+   ```
+
+4. **Or Update Configuration**
+   Edit `.opencode/plugin/telegram-config.json`:
+   ```json
+   {
+     "telegramIdle": {
+       "enabled": true,
+       "botToken": "your_bot_token_here",
+       "chatId": "your_chat_id_here"
+     }
+   }
+   ```
+
+### Usage
+
+The plugin automatically initializes when OpenCode starts. It will:
+
+- Monitor session activity
+- Send idle notifications after 5 minutes of inactivity
+- Send resume notifications when activity resumes
+- Clean up resources on session end
+
+### Customization
+
+You can customize the plugin behavior by modifying the configuration:
+
+- `idleTimeout`: Time in milliseconds before considering session idle
+- `checkInterval`: How often to check for idle state
+- `messages`: Customize notification messages
+
+### Integration with OpenCode
+
+To integrate this plugin with OpenCode's event system, you would need to:
+
+1. Hook into OpenCode's activity tracking events
+2. Call `handleActivity()` when user interacts with OpenCode
+3. Call `init()` when OpenCode session starts
+4. Call `cleanup()` when OpenCode session ends
+
+### Testing
+
+Test the plugin independently:
+
+```bash
+node .opencode/plugin/telegram-idle.js
+```
+
+### Troubleshooting
+
+- **"Bot token not configured"**: Set `TELEGRAM_BOT_TOKEN` environment variable
+- **"Chat ID not configured"**: Set `TELEGRAM_CHAT_ID` environment variable
+- **"Failed to send message"**: Check bot token and chat ID are correct
+- **No notifications**: Ensure bot is started and chat is active

+ 31 - 0
.opencode/plugin/bun.lock

@@ -0,0 +1,31 @@
+{
+  "lockfileVersion": 1,
+  "workspaces": {
+    "": {
+      "name": "opencode-telegram-plugin",
+      "dependencies": {
+        "@opencode-ai/plugin": "^0.5.1",
+      },
+      "devDependencies": {
+        "@opencode-ai/plugin": "^0.5.1",
+        "@types/node": "^24.2.1",
+        "bun-types": "latest",
+      },
+    },
+  },
+  "packages": {
+    "@opencode-ai/plugin": ["@opencode-ai/plugin@0.5.1", "", { "dependencies": { "@opencode-ai/sdk": "0.4.19" } }, "sha512-dhVybeWgn3ulakZC9lD/Ar4PNWSFTLgAXjtRQYGsUQ1NE7w7pHI9VCGSsg0ejzYWwf4JqALkmTRLnEAuFFj84g=="],
+
+    "@opencode-ai/sdk": ["@opencode-ai/sdk@0.4.19", "", {}, "sha512-7V+wDR1+m+TQZAraAh/bOSObiA/uysG1YIXZVe6gl1sQAXDtkG2FYCzs0gTZ/ORdkUKEnr3vyQIk895Mu0CC/w=="],
+
+    "@types/node": ["@types/node@24.2.1", "", { "dependencies": { "undici-types": "~7.10.0" } }, "sha512-DRh5K+ka5eJic8CjH7td8QpYEV6Zo10gfRkjHCO3weqZHWDtAaSTFtl4+VMqOJ4N5jcuhZ9/l+yy8rVgw7BQeQ=="],
+
+    "@types/react": ["@types/react@19.1.10", "", { "dependencies": { "csstype": "^3.0.2" } }, "sha512-EhBeSYX0Y6ye8pNebpKrwFJq7BoQ8J5SO6NlvNwwHjSj6adXJViPQrKlsyPw7hLBLvckEMO1yxeGdR82YBBlDg=="],
+
+    "bun-types": ["bun-types@1.2.20", "", { "dependencies": { "@types/node": "*" }, "peerDependencies": { "@types/react": "^19" } }, "sha512-pxTnQYOrKvdOwyiyd/7sMt9yFOenN004Y6O4lCcCUoKVej48FS5cvTw9geRaEcB9TsDZaJKAxPTVvi8tFsVuXA=="],
+
+    "csstype": ["csstype@3.1.3", "", {}, "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="],
+
+    "undici-types": ["undici-types@7.10.0", "", {}, "sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag=="],
+  }
+}

+ 11 - 0
.opencode/plugin/notify.ts

@@ -0,0 +1,11 @@
+import type { Plugin } from "@opencode-ai/plugin"
+
+export const Notify: Plugin = async ({ $ }) => {
+  return {
+    // async event(input) {
+    //   if (input.event.type === "session.idle") {
+    //     await $`say "Your code is done!"`
+    //   }
+    // },
+  }
+}

+ 16 - 0
.opencode/plugin/package.json

@@ -0,0 +1,16 @@
+{
+  "type": "module",
+  "name": "opencode-telegram-plugin",
+  "version": "1.0.0",
+  "description": "Telegram notifications for OpenCode sessions",
+  "main": "telegram-notify.ts",
+  "scripts": {
+    "start": "bun telegram-bot.ts",
+    "build": "bun build telegram-bot.ts --outdir dist"
+  },
+  "devDependencies": {
+    "@types/node": "^24.2.1",
+    "@opencode-ai/plugin": "^0.5.1",
+    "bun-types": "latest"
+  }
+}

+ 125 - 0
.opencode/plugin/telegram-notify.ts

@@ -0,0 +1,125 @@
+import type { Plugin } from "@opencode-ai/plugin"
+import { SimpleTelegramBot } from "../lib/telegram-bot"
+
+export const TelegramNotify: Plugin = async ({ $ }) => {
+  // Initialize Telegram bot
+  const bot = new SimpleTelegramBot()
+  let lastMessage = ""
+  
+  return {
+    async event(input) {
+      if (input.event.type === "session.idle") {
+        // Send the last message content along with idle notification
+        const message = lastMessage 
+          ? `🟡 Session idle! Here's your last message:\n\n${lastMessage}`
+          : "🟡 Hey! Your OpenCode session is idle - time to check your work!"
+        bot.sendMessage(message)
+      }
+      
+      if (input.event.type === "message.updated") {
+        // Reset idle timer when user sends messages
+        bot.resetActivity()
+        
+        const messageContent = (input.event as any).message?.content || 
+                              (input.event as any).content || ""
+        
+        // Check if it's a command to send last message
+        if (messageContent.includes("/send-last") || messageContent.includes("/last")) {
+          if (lastMessage) {
+            bot.sendMessage(`📱 Here's your last message:\n\n${lastMessage}`)
+          } else {
+            bot.sendMessage("📱 No previous message found.")
+          }
+          return
+        }
+        
+        // Check if it's a command to send to phone
+        if (messageContent.includes("/send-to-phone") || messageContent.includes("/phone")) {
+          if (lastMessage) {
+            bot.sendMessage(`📱 Sending to your phone:\n\n${lastMessage}`)
+          } else {
+            bot.sendMessage("📱 No message to send to phone.")
+          }
+          return
+        }
+        
+        // Try to capture message content from the event
+        try {
+          // Access message content if available
+          const messageContent = (input.event as any).message?.content || 
+                                (input.event as any).content ||
+                                "Message updated"
+          
+          if (messageContent && messageContent !== "Message updated") {
+            lastMessage = messageContent
+            
+            // Send a preview of the message to Telegram
+            const preview = lastMessage.length > 200 
+              ? lastMessage.substring(0, 200) + "..."
+              : lastMessage
+            
+            bot.sendMessage(`📱 Last message preview:\n\n${preview}`)
+          }
+        } catch (error) {
+          // If we can't access the message content, just log it
+          console.log("Message updated but couldn't capture content")
+        }
+      }
+      
+      if (input.event.type === "file.edited") {
+        // Reset idle timer when user edits files
+        bot.resetActivity()
+      }
+      
+      if (input.event.type === "message.updated") {
+        // Reset idle timer when user sends messages
+        bot.resetActivity()
+        
+        // Try to capture message content from the event
+        try {
+          // Access message content if available
+          const messageContent = (input.event as any).message?.content || 
+                                (input.event as any).content ||
+                                "Message updated"
+          
+          if (messageContent && messageContent !== "Message updated") {
+            lastMessage = messageContent
+            
+            // Send a preview of the message to Telegram
+            const preview = lastMessage.length > 200 
+              ? lastMessage.substring(0, 200) + "..."
+              : lastMessage
+            
+            bot.sendMessage(`📱 Last message preview:\n\n${preview}`)
+          }
+        } catch (error) {
+          // If we can't access the message content, just log it
+          console.log("Message updated but couldn't capture content")
+        }
+      }
+      
+      // Also listen for message parts being updated
+      if (input.event.type === "message.part.updated") {
+        bot.resetActivity()
+        
+        try {
+          const partContent = (input.event as any).part?.content || 
+                             (input.event as any).content ||
+                             "Message part updated"
+          
+          if (partContent && partContent !== "Message part updated") {
+            lastMessage = partContent
+            
+            const preview = lastMessage.length > 200 
+              ? lastMessage.substring(0, 200) + "..."
+              : lastMessage
+            
+            bot.sendMessage(`📱 Message part preview:\n\n${preview}`)
+          }
+        } catch (error) {
+          console.log("Message part updated but couldn't capture content")
+        }
+      }
+    }
+  }
+}

+ 19 - 0
.opencode/plugin/tsconfig.json

@@ -0,0 +1,19 @@
+{
+  "compilerOptions": {
+    "target": "ES2022",
+    "module": "ESNext",
+    "moduleResolution": "bundler",
+    "allowSyntheticDefaultImports": true,
+    "esModuleInterop": true,
+    "allowJs": true,
+    "strict": true,
+    "skipLibCheck": true,
+    "forceConsistentCasingInFileNames": true,
+    "resolveJsonModule": true,
+    "isolatedModules": true,
+    "noEmit": true,
+    "types": ["node"]
+  },
+  "include": ["*.ts"],
+  "exclude": ["node_modules"]
+}

+ 108 - 2
README.md

@@ -1,2 +1,108 @@
-# opencode-agents
-A set of opencode configurations, prompts and agents
+# OpenCode Agents
+
+A set of OpenCode configurations, prompts, agents, and plugins for enhanced development workflows.
+
+## Features
+
+- 🤖 **Task-focused agents** for planning, implementation, review, and testing
+- 📱 **Telegram integration** for idle session notifications
+- 🛡️ **Security-first** approach with configurable permissions
+- 📚 **Comprehensive documentation** and examples
+
+## Quick Start
+
+### 1. Install OpenCode CLI
+Follow the [official OpenCode documentation](https://opencode.dev) to install the CLI.
+
+### 2. Setup Telegram Notifications (Optional)
+Get notified when your OpenCode sessions become idle:
+
+```bash
+# Copy the example environment file
+cp env.example .env
+
+# Edit .env with your Telegram bot credentials
+# Get bot token from @BotFather on Telegram
+# Get chat ID by messaging your bot and checking the API
+```
+
+### 3. Start Using Agents
+```bash
+# Start a planning session
+opencode --agent plan-project
+
+# Run a specific task
+opencode run --agent mastra "Implement database schema"
+```
+
+## Agents
+
+See [`.opencode/AGENTS.md`](.opencode/AGENTS.md) for detailed information about available agents:
+
+- **plan-project**: Roadmaps, milestones, ADRs, risk register
+- **plan-analyse**: Repo survey, external research, dependency mapping
+- **mastra**: Implementation for ingestion, embeddings, LanceDB, retrieval
+- **review**: Code review with targeted feedback
+- **documentation**: Documentation updates and examples
+- **write-test**: Unit/integration tests and mocks
+
+## Plugins
+
+### Telegram Bot (Simple)
+Single-file Telegram bot that sends notifications when OpenCode sessions become idle.
+
+**Features:**
+- 🕐 Configurable idle timeout (default: 5 minutes)
+- 📱 Real-time notifications via Telegram
+- 🔄 Session resume tracking
+- 🛡️ Automatic .env file loading
+- 📦 Single file, no dependencies
+
+**Quick Start:**
+```bash
+# Run the bot
+node .opencode/plugin/telegram-bot.js
+
+# Run example usage
+node .opencode/plugin/example-usage.js
+```
+
+See [`.opencode/plugin/README.md`](.opencode/plugin/README.md) for detailed documentation.
+
+## Configuration
+
+### Permissions
+Repository guardrails are defined in `.opencode/permissions.json`. Each agent can have specific permissions that override repository defaults.
+
+### Environment Variables
+Copy `env.example` to `.env` and configure your Telegram bot:
+
+```bash
+# Copy example file
+cp env.example .env
+
+# Edit .env with your credentials
+TELEGRAM_BOT_TOKEN=your_bot_token_here
+TELEGRAM_CHAT_ID=your_chat_id_here
+TELEGRAM_ENABLED=true
+```
+
+**Security Note**: The `.env` file is automatically ignored by git to protect your API keys.
+
+## Safety & Security
+
+- **Approval-first workflow**: Each agent proposes a plan before execution
+- **Configurable permissions**: Granular control over what agents can do
+- **Input sanitization**: Protection against XSS and injection attacks
+- **Secure credential management**: Environment variables for sensitive data
+
+## Contributing
+
+1. Follow the established naming conventions and coding standards
+2. Write comprehensive tests for new features
+3. Update documentation for any changes
+4. Ensure security best practices are followed
+
+## License
+
+This project is licensed under the MIT License.

+ 20 - 0
env.example

@@ -0,0 +1,20 @@
+# Telegram Bot Configuration
+# Copy this file to .env and fill in your actual values
+
+# Your Telegram bot token (get from @BotFather)
+TELEGRAM_BOT_TOKEN=your_bot_token_here
+
+# Your chat ID (get by messaging your bot and checking the API)
+TELEGRAM_CHAT_ID=your_chat_id_here
+
+# Your bot username (optional, defaults to @OpenCode)
+TELEGRAM_BOT_USERNAME=@YourBotUsername
+
+# Idle timeout in milliseconds (default: 5 minutes = 300000ms)
+TELEGRAM_IDLE_TIMEOUT=300000
+
+# Check interval in milliseconds (default: 30 seconds = 30000ms)
+TELEGRAM_CHECK_INTERVAL=30000
+
+# Enable/disable the plugin (true/false)
+TELEGRAM_ENABLED=true