Compare commits

...

53 Commits

Author SHA1 Message Date
m3tm3re
39ac89f388 docs: update AGENTS.md and README.md for rules system, remove beads
- Add rules/ directory documentation to both files
- Update skill count from 25 to 15 modules
- Remove beads references (issue tracking removed)
- Update skills list with current active skills
- Document flake.nix as proper Nix flake (not flake=false)
- Add rules system integration section
- Clean up sisyphus planning artifacts
- Remove deprecated skills (memory, msteams, outlook)
2026-03-03 19:40:57 +01:00
m3tm3re
1bc81fb38c chore: update readme 2026-02-18 17:32:13 +01:00
m3tm3re
1f1eabd1ed feat(rules): add strict TDD enforcement ruleset with AI patterns 2026-02-18 17:30:20 +01:00
m3tm3re
5b204c95e4 test(rules): add final QA evidence and mark review complete
Final Review Results:
- F1 (Plan Compliance): OKAY - Must Have [12/12], Must NOT Have [8/8]
- F2 (Code Quality): OKAY - All files pass quality criteria
- F3 (Manual QA): OKAY - Scenarios [5/5 pass]
- F4 (Scope Fidelity): OKAY - No unaccounted changes

All 21 tasks complete (T1-T17 + F1-F4)
2026-02-17 19:31:24 +01:00
m3tm3re
4e9da366e4 test(rules): add integration test evidence
- All 11 rule files verified (exist, under limits)
- Full lib integration verified (11 paths returned)
- Context budget verified (975 < 1500)
- All instruction paths resolve to real files
- opencode.nix rules entry verified

Refs: T17 of rules-system plan
2026-02-17 19:18:39 +01:00
m3tm3re
8910413315 feat(rules): add initial rule files for concerns, languages, and frameworks
Concerns (6 files):
- coding-style.md (163 lines): patterns, anti-patterns, error handling, SOLID
- naming.md (105 lines): naming conventions table per language
- documentation.md (149 lines): docstrings, WHY vs WHAT, README standards
- testing.md (134 lines): AAA pattern, mocking philosophy, TDD
- git-workflow.md (118 lines): conventional commits, branch naming, PR format
- project-structure.md (82 lines): directory layout, entry points, config placement

Languages (4 files):
- python.md (224 lines): uv, ruff, pyright, pytest, pydantic, idioms, anti-patterns
- typescript.md (150 lines): strict mode, discriminated unions, satisfies, as const
- nix.md (129 lines): flake structure, module patterns, alejandra, anti-patterns
- shell.md (100 lines): set -euo pipefail, shellcheck, quoting, POSIX

Frameworks (1 file):
- n8n.md (42 lines): workflow design, node patterns, Error Trigger, security

Context budget: 975 lines (concerns + python) < 1500 limit

Refs: T6-T16 of rules-system plan
2026-02-17 19:05:45 +01:00
m3tm3re
d475dde398 feat(rules): add rules directory structure and usage documentation
- Create rules/{concerns,languages,frameworks}/ directory structure
- Add USAGE.md with flake.nix integration examples
- Add plan and notepad files for rules-system implementation

Refs: T1, T5 of rules-system plan
2026-02-17 18:59:43 +01:00
m3tm3re
6fceea7460 refactor: modernize agent configs, remove beads, update README
- Upgrade all agents from glm-4.7 to glm-5 with descriptive names
- Add comprehensive permission configs (bash, edit, external_directory) for all agents
- Remove .beads/ issue tracking directory
- Update README: fix opencode URL to opencode.ai, remove beads sections, formatting cleanup
2026-02-17 09:15:15 +01:00
m3tm3re
923e2f1eaa chore(plan): mark deployment verification as blocked (requires user action) 2026-02-14 08:34:06 +01:00
m3tm3re
231b9f2e0b chore(plan): mark tasks 11-14 and definition of done as complete 2026-02-14 08:31:32 +01:00
m3tm3re
c64d71f438 docs(memory): update skills for opencode-memory plugin, deprecate mem0 2026-02-14 08:22:59 +01:00
m3tm3re
1719f70452 feat(memory): add core memory skill, update Apollo prompt and Obsidian skill
- Add skills/memory/SKILL.md: dual-layer memory orchestration
- Update prompts/apollo.txt: add memory management responsibilities
- Update skills/obsidian/SKILL.md: add memory folder conventions
2026-02-12 20:02:51 +01:00
m3tm3re
0d6ff423be Add Memory System configuration to user profile 2026-02-12 19:54:54 +01:00
m3tm3re
79e6adb362 feat(mem0-memory): add memory categories and dual-layer sync patterns 2026-02-12 19:50:39 +01:00
m3tm3re
1e03c165e7 docs: Add Obsidian MCP server configuration documentation
- Create mcp-config.md in skills/memory/references/
- Document cyanheads/obsidian-mcp-server setup for Opencode
- Include environment variables, Nix config, and troubleshooting
- Reference for Task 4 of memory-system plan
2026-02-12 19:44:03 +01:00
m3tm3re
94b89da533 finalize doc-translator skill 2026-02-11 19:58:06 +01:00
sascha.koenig
b9d535b926 fix: use POST method for Outline signed URL upload
Change HTTP method from PUT to POST on line 77 for signed URL upload,
as Outline's S3 bucket only accepts POST requests.
2026-02-11 14:16:02 +01:00
sascha.koenig
46b9c0e4e3 fix: list_outline_collections.sh - correct jq parsing to output valid JSON array 2026-02-11 14:14:55 +01:00
m3tm3re
eab0a94650 doc-translator fix 2026-02-10 20:24:13 +01:00
m3tm3re
0ad1037c71 doc-translator 2026-02-10 20:02:30 +01:00
m3tm3re
1b4e8322d6 doc-translator 2026-02-10 20:00:42 +01:00
m3tm3re
7a3b72d5d4 chore: mark chiron-agent-framework plan as complete
All 27 tasks completed successfully.

Co-authored-by: Atlas orchestrator <atlas@opencode.dev>
2026-02-03 20:40:06 +01:00
m3tm3re
156ebf7d63 docs: fix duplicate success criteria in chiron-agent-framework plan
All 6 success criteria now properly marked as complete.

Co-authored-by: Atlas orchestrator <atlas@opencode.dev>
2026-02-03 20:39:26 +01:00
m3tm3re
a57e302727 docs: complete all success criteria in chiron-agent-framework
All 6 success criteria now marked as complete.

Co-authored-by: Atlas orchestrator <atlas@opencode.dev>
2026-02-03 20:34:28 +01:00
m3tm3re
d08deaf9d2 docs: mark all success criteria as complete
All 6 success criteria in plan file now marked complete.

Co-authored-by: Atlas orchestrator <atlas@opencode.dev>
2026-02-03 20:34:18 +01:00
m3tm3re
666696b17c docs: mark chiron-agent-framework plan complete
All 14 tasks completed and verified.

## Summary
- 6 agents defined (2 primary, 4 subagents)
- 6 system prompts created
- 5 tool integration skills created
- 1 validation script created
- All success criteria met

Co-authored-by: Atlas orchestrator <atlas@opencode.dev>
2026-02-03 20:33:01 +01:00
m3tm3re
1e7decc84a feat: add Chiron agent framework with 6 agents and 5 integration skills
Complete implementation of personal productivity agent framework for Oh-My-Opencode.

## Components Added

### Agents (6 total)
- Primary agents: chiron (Plan Mode), chiron-forge (Build Mode)
- Subagents: hermes (work communication), athena (work knowledge), apollo (private knowledge), calliope (writing)

### System Prompts (6 total)
- prompts/chiron.txt - Main orchestrator with delegation logic
- prompts/chiron-forge.txt - Execution/build counterpart
- prompts/hermes.txt - Basecamp, Outlook, MS Teams specialist
- prompts/athena.txt - Outline wiki/documentation specialist
- prompts/apollo.txt - Obsidian vault/private notes specialist
- prompts/calliope.txt - Writing/documentation specialist

### Integration Skills (5 total)
- skills/basecamp/SKILL.md - 63 MCP tools documented
- skills/outline/SKILL.md - Wiki/document management
- skills/msteams/SKILL.md - Teams/channels/meetings
- skills/outlook/SKILL.md - Email/calendar/contacts
- skills/obsidian/SKILL.md - Vault/note management

### Validation
- scripts/validate-agents.sh - Agent configuration validation
- All agents validated: JSON structure, modes, prompt references
- All prompts verified: Exist, non-empty, >500 chars
- All skills verified: Valid YAML frontmatter, SKILL.md structure

## Verification
 6 agents in agents.json
 All 6 prompt files exist and non-empty
 All 5 skills have valid SKILL.md with YAML frontmatter
 validate-agents.sh passes (exit 0)

Co-authored-by: Sisyphus framework <atlas@opencode.dev>
2026-02-03 20:30:34 +01:00
m3tm3re
76cd0e4ee6 Create Athena (Work Knowledge) system prompt
- Outline wiki specialization: document CRUD, search, collections, sharing
- Focus: wiki search, knowledge retrieval, documentation updates
- Follows standard prompt structure: 8 sections matching Apollo/Calliope
- Explicit boundaries: Hermes (comm), Apollo (private), Calliope (creative)
- Uses Question tool for document selection and search scope
- Verification: outline, wiki/knowledge, document keywords confirmed
2026-02-03 20:18:52 +01:00
m3tm3re
4fcab26c16 Create Hermes system prompt (Wave 2, Task 5)
- Added prompts/hermes.txt with Basecamp, Outlook, Teams specialization
- Follows consistent structure pattern from apollo.txt and calliope.txt
- Defines Hermes as work communication specialist
- Includes tool usage patterns for Question tool and MCP integrations
- Verifies with grep: basecamp, outlook/email, teams/meeting
- Appends learnings to chiron-agent-framework notepad
2026-02-03 20:18:46 +01:00
m3tm3re
f20f5223d5 Create agents.json with 6 agent definitions (Wave 1, Task 1)
- Added all 6 agents: chiron, chiron-forge, hermes, athena, apollo, calliope
- Primary agents (2): chiron (Plan Mode), chiron-forge (Build Mode)
- Subagents (4): hermes (communications), athena (work knowledge), apollo (private knowledge), calliope (writing)
- All agents use model: zai-coding-plan/glm-4.7
- Prompt references use file pattern: {file:./prompts/<name>.txt}
- Permission structure: primaries have external_directory rules, subagents have simple question: allow
- Verified with Python JSON validation (6 agents, correct names)
- Documented patterns and learnings in notepad
2026-02-03 20:14:34 +01:00
m3tm3re
36c82293f9 Agent restructure 2026-02-03 20:09:15 +01:00
m3tm3re
7e4a44eed6 Agent restructure 2026-02-03 20:04:26 +01:00
m3tm3re
1f320f1c95 Add scripts/validate-agents.sh for agent validation 2026-02-03 19:23:26 +01:00
m3tm3re
fddc22e55e Add outlook skill with Graph API documentation
- Create skills/outlook/SKILL.md with comprehensive Outlook Graph API documentation
- Document mail CRUD operations: list, get, create, send, reply, forward, update, delete
- Document folder management: list, create, update, delete, move, copy
- Document calendar events: list, get, create, update, delete, accept/decline
- Document contacts: list, get, create, update, delete, folder management
- Include search operations for mail, contacts, and events
- Provide common workflows for email, inbox organization, meeting invitations
- Include IDs and discovery guidance
- Set compatibility to opencode
- Close issue AGENTS-ch2
2026-02-03 18:55:15 +01:00
m3tm3re
db1a5ba9ce Add MS Teams Graph API integration skill
Created skills/msteams/SKILL.md with comprehensive documentation for:
- Teams and channels management
- Channel messages (send, retrieve, edit, delete)
- Meeting scheduling and management
- Chat conversations (1:1, group, meeting)
- Common workflows for automation
- API endpoint reference
- Best practices and integration examples

Follows SKILL.md format with YAML frontmatter.
Compatibility: opencode
2026-02-03 18:52:14 +01:00
m3tm3re
730e33b908 Add Apollo system prompt for private knowledge management 2026-02-03 18:50:32 +01:00
m3tm3re
ecece88fba Create Calliope writing prompt
- Define Calliope as Greek muse specializing in documentation, reports, meeting notes
- Include Question tool for clarifying tone, audience, format
- Set scope boundaries: delegates tools, no overlap with Hermes/Athena
- Follow standard prompt structure from agent-development skill
2026-02-03 18:50:22 +01:00
m3tm3re
1252b9ffe7 Create Chiron-Forge build/execution mode system prompt
Define Chiron-Forge as execution/build counterpart to Chiron with:
- Full write access for task execution
- Clear distinction from Chiron's planning/analysis role
- Question tool for destructive operations confirmation
- Workflow: Receive → Understand → Plan Action → Execute → Confirm → Report
- Delegation to subagents for specialized domains

File: prompts/chiron-forge.txt (3185 chars, 67 lines)
2026-02-03 18:49:31 +01:00
m3tm3re
3f2f766af6 Create prompts/chiron.txt with Chiron plan/analysis mode system prompt
- Define Chiron as main orchestrator in plan/analysis mode
- Include delegation logic to subagents (Hermes, Athena, Apollo, Calliope)
- Add Question tool usage for ambiguous requests
- Specify read-only permissions (no file modifications)
- Focus on planning, analysis, guidance, and delegation
- Use second-person addressing throughout
2026-02-03 18:48:39 +01:00
m3tm3re
cb383f9c7f Athena permissions refined 2026-02-02 19:21:04 +01:00
m3tm3re
e01198d40d docs(plan): mark all tasks complete in agent-permissions-refinement plan 2026-02-02 19:08:48 +01:00
m3tm3re
c58c28aef5 chore(agents): refine permissions for Chiron and Chriton-Forge with security hardening 2026-02-02 19:06:49 +01:00
m3tm3re
468673c125 Add Phase 1 completion summary
Documentation added:
- phase1-complete.md: Complete overview of Phase 1 deliverables

Summary:
- 4 skills created/updated (outline, basecamp, daily-routines, meeting-notes)
- 3 documentation files created (work-para-structure, work-quickstart, teams-transcript-workflow)
- PARA structure created (10 projects, 5 areas)
- All integrations configured and documented

Next steps for user:
1. Customize projects with actual Basecamp data
2. Configure Outline MCP
3. Test workflows
4. Add n8n automation when ready

Status: Phase 1 complete, foundation ready for use.
2026-01-28 19:06:04 +01:00
m3tm3re
325e06ad12 Complete Phase 1: Work integration (all tasks)
Documentation Added:
- skills/chiron-core/references/work-para-structure.md: Complete work PARA guide
- skills/chiron-core/references/work-quickstart.md: User quick start guide

What Was Completed:
1.  Created outline skill with full MCP integration
2.  Enhanced basecamp skill with project mapping
3.  Enhanced daily-routines with work context
4.  Created Teams transcript workflow guide
5.  Set up PARA work structure (10 projects + 5 areas)
6.  Created comprehensive documentation

Integration Ready:
- Basecamp ↔ Obsidian: Project mapping and task sync
- Outline ↔ Obsidian: Wiki search, export, AI queries
- Teams → Obsidian → Basecamp: Transcript processing workflow
- All integrated into daily/weekly routines

PARA Work Structure:
- 01-projects/work/: 10 project folders (placeholders ready for customization)
- 02-areas/work/: 5 ongoing areas
- 03-resources/work/wiki-mirror/: Ready for Outline exports
- 04-archive/work/: Ready for completed work

Next Steps for User:
1. Customize project names with actual Basecamp projects
2. Configure Outline MCP with your instance
3. Test Basecamp connection
4. Process first Teams transcript using workflow
5. Add n8n workflows when ready (automate Basecamp/Outline sync)

Note: All work knowledge stored in Obsidian (tool-agnostic).
Jobs easily portable: archive work/, update tool configs, create new projects.
2026-01-28 19:02:20 +01:00
m3tm3re
e2932d1d84 Implement Phase 1: Work integration (without n8n)
Skills Created:
- outline: Full MCP integration with Outline wiki (search, read, create, export, AI queries)
- Enhanced basecamp: Added project mapping configuration to PARA structure
- Enhanced daily-routines: Integrated work context (Basecamp, Outline) into daily/weekly workflows
- Enhanced meeting-notes: Added Teams transcript processing workflow guide

PARA Work Structure Created:
- 01-projects/work/: 10 project folders with MOCs (placeholders for user customization)
- 02-areas/work/: 5 area files (current-job, professional-dev, team-management, company-knowledge, technical-excellence)
- 03-resources/work/wiki-mirror/: Ready for Outline exports
- 04-archive/work/: Ready for completed work

Documentation Added:
- skills/outline/SKILL.md: Comprehensive wiki workflows and tool references
- skills/outline/references/outline-workflows.md: Detailed usage examples
- skills/outline/references/export-patterns.md: Obsidian integration patterns
- skills/meeting-notes/references/teams-transcript-workflow.md: Manual DOCX → meeting note workflow
- skills/chiron-core/references/work-para-structure.md: Work-specific PARA organization

Key Integrations:
- Basecamp ↔ Obsidian: Project mapping and task sync
- Outline ↔ Obsidian: Wiki search, export decisions, knowledge discovery
- Teams → Obsidian: Transcript processing with AI analysis
- All integrated into daily/weekly routines

Note: n8n workflows skipped per user request. Ready for n8n automation later.
2026-01-28 18:58:49 +01:00
m3tm3re
3e3b17de38 Migrate from Anytype to Obsidian across all skills and documentation 2026-01-27 20:09:05 +01:00
m3tm3re
240fde83dd Update Obsidian vault path from ~/knowledge to ~/CODEX 2026-01-27 19:10:13 +01:00
m3tm3re
63cd7fe102 Rename directories to plural form: skill/ → skills/, agent/ → agents/, command/ → commands/
- Rename skill/ to skills/ for consistency with naming conventions
- Rename agent/ to agents/ and command/ to commands/
- Update AGENTS.md with all directory references
- Update scripts/test-skill.sh paths
- Update prompts/athena.txt documentation

This aligns with best practices of using plural directory names and updates
all documentation to reflect the new structure.
2026-01-26 20:42:05 +01:00
m3tm3re
aeeeb559ed Sync beads: Close 6 Athena agent issues 2026-01-26 19:34:54 +01:00
m3tm3re
87bd75872c Fix Athena agent configuration and prompt to match agent-development skill guidelines
- Add explicit 'mode': 'subagent' field to athena agent
- Add 'temperature': 0.1 to athena agent for deterministic results
- Rename 'Core Capabilities' to 'Your Core Responsibilities:'
- Convert responsibilities from subsections to numbered list format
- Rename 'Ethical Guidelines' to 'Quality Standards'
- Remove references to non-existent validate-agent.sh script

All 6 related beads issues closed.
2026-01-26 19:34:43 +01:00
m3tm3re
975ce8f993 Add Athena research sub-agent and improve agent-development skill
- Add Athena sub-agent for non-technical research tasks
- Enhance agent-development skill with 6 improvements from reflection:
  * Add explicit mode field requirement (HIGH)
  * Add temperature recommendations by agent type (MEDIUM)
  * Enforce 'Core Responsibilities' header (MEDIUM)
  * Add numbered responsibility format guidance (LOW)
  * Note section name flexibility (LOW)
  * Add validation script alternative (LOW)
- Create 6 beads issues for Athena agent follow-up work
2026-01-24 19:40:38 +01:00
m3tm3re
b39e61440b + some more skills 2026-01-19 19:37:38 +01:00
m3tm3re
924b3476f9 Rewrite agent-development skill for opencode
- Update SKILL.md with JSON-first approach (agents.json pattern)
- Add all opencode config options: mode, temperature, maxSteps, hidden, permission
- Document permissions system with granular rules and glob patterns
- Add references/opencode-agents-json-example.md with chiron pattern
- Rewrite triggering-examples.md for opencode (Tab, @mention, Task tool)
- Update agent-creation-system-prompt.md for JSON output format
- Rewrite complete-agent-examples.md with JSON examples
- Rewrite validate-agent.sh to support both JSON and Markdown validation
2026-01-19 19:35:55 +01:00
127 changed files with 14654 additions and 3881 deletions

39
.beads/.gitignore vendored
View File

@@ -1,39 +0,0 @@
# SQLite databases
*.db
*.db?*
*.db-journal
*.db-wal
*.db-shm
# Daemon runtime files
daemon.lock
daemon.log
daemon.pid
bd.sock
sync-state.json
last-touched
# Local version tracking (prevents upgrade notification spam after git ops)
.local_version
# Legacy database files
db.sqlite
bd.db
# Worktree redirect file (contains relative path to main repo's .beads/)
# Must not be committed as paths would be wrong in other clones
redirect
# Merge artifacts (temporary files from 3-way merge)
beads.base.jsonl
beads.base.meta.json
beads.left.jsonl
beads.left.meta.json
beads.right.jsonl
beads.right.meta.json
# NOTE: Do NOT add negation patterns (e.g., !issues.jsonl) here.
# They would override fork protection in .git/info/exclude, allowing
# contributors to accidentally commit upstream issue databases.
# The JSONL files (issues.jsonl, interactions.jsonl) and config files
# are tracked by git by default since no pattern above ignores them.

View File

@@ -1,81 +0,0 @@
# Beads - AI-Native Issue Tracking
Welcome to Beads! This repository uses **Beads** for issue tracking - a modern, AI-native tool designed to live directly in your codebase alongside your code.
## What is Beads?
Beads is issue tracking that lives in your repo, making it perfect for AI coding agents and developers who want their issues close to their code. No web UI required - everything works through the CLI and integrates seamlessly with git.
**Learn more:** [github.com/steveyegge/beads](https://github.com/steveyegge/beads)
## Quick Start
### Essential Commands
```bash
# Create new issues
bd create "Add user authentication"
# View all issues
bd list
# View issue details
bd show <issue-id>
# Update issue status
bd update <issue-id> --status in_progress
bd update <issue-id> --status done
# Sync with git remote
bd sync
```
### Working with Issues
Issues in Beads are:
- **Git-native**: Stored in `.beads/issues.jsonl` and synced like code
- **AI-friendly**: CLI-first design works perfectly with AI coding agents
- **Branch-aware**: Issues can follow your branch workflow
- **Always in sync**: Auto-syncs with your commits
## Why Beads?
**AI-Native Design**
- Built specifically for AI-assisted development workflows
- CLI-first interface works seamlessly with AI coding agents
- No context switching to web UIs
🚀 **Developer Focused**
- Issues live in your repo, right next to your code
- Works offline, syncs when you push
- Fast, lightweight, and stays out of your way
🔧 **Git Integration**
- Automatic sync with git commits
- Branch-aware issue tracking
- Intelligent JSONL merge resolution
## Get Started with Beads
Try Beads in your own projects:
```bash
# Install Beads
curl -sSL https://raw.githubusercontent.com/steveyegge/beads/main/scripts/install.sh | bash
# Initialize in your repo
bd init
# Create your first issue
bd create "Try out Beads"
```
## Learn More
- **Documentation**: [github.com/steveyegge/beads/docs](https://github.com/steveyegge/beads/tree/main/docs)
- **Quick Start Guide**: Run `bd quickstart`
- **Examples**: [github.com/steveyegge/beads/examples](https://github.com/steveyegge/beads/tree/main/examples)
---
*Beads: Issue tracking that moves at the speed of thought*

View File

@@ -1,62 +0,0 @@
# Beads Configuration File
# This file configures default behavior for all bd commands in this repository
# All settings can also be set via environment variables (BD_* prefix)
# or overridden with command-line flags
# Issue prefix for this repository (used by bd init)
# If not set, bd init will auto-detect from directory name
# Example: issue-prefix: "myproject" creates issues like "myproject-1", "myproject-2", etc.
# issue-prefix: ""
# Use no-db mode: load from JSONL, no SQLite, write back after each command
# When true, bd will use .beads/issues.jsonl as the source of truth
# instead of SQLite database
# no-db: false
# Disable daemon for RPC communication (forces direct database access)
# no-daemon: false
# Disable auto-flush of database to JSONL after mutations
# no-auto-flush: false
# Disable auto-import from JSONL when it's newer than database
# no-auto-import: false
# Enable JSON output by default
# json: false
# Default actor for audit trails (overridden by BD_ACTOR or --actor)
# actor: ""
# Path to database (overridden by BEADS_DB or --db)
# db: ""
# Auto-start daemon if not running (can also use BEADS_AUTO_START_DAEMON)
# auto-start-daemon: true
# Debounce interval for auto-flush (can also use BEADS_FLUSH_DEBOUNCE)
# flush-debounce: "5s"
# Git branch for beads commits (bd sync will commit to this branch)
# IMPORTANT: Set this for team projects so all clones use the same sync branch.
# This setting persists across clones (unlike database config which is gitignored).
# Can also use BEADS_SYNC_BRANCH env var for local override.
# If not set, bd sync will require you to run 'bd config set sync.branch <branch>'.
# sync-branch: "beads-sync"
# Multi-repo configuration (experimental - bd-307)
# Allows hydrating from multiple repositories and routing writes to the correct JSONL
# repos:
# primary: "." # Primary repo (where this database lives)
# additional: # Additional repos to hydrate from (read-only)
# - ~/beads-planning # Personal planning repo
# - ~/work-planning # Work planning repo
# Integration settings (access with 'bd config get/set')
# These are stored in the database, not in this file:
# - jira.url
# - jira.project
# - linear.url
# - linear.api-key
# - github.org
# - github.repo

View File

@@ -1,4 +0,0 @@
{
"database": "beads.db",
"jsonl_export": "issues.jsonl"
}

1
.envrc Normal file
View File

@@ -0,0 +1 @@
use flake

14
.gitignore vendored Normal file
View File

@@ -0,0 +1,14 @@
.todos/
# Sidecar worktree state files
.sidecar/
.sidecar-agent
.sidecar-task
.sidecar-pr
.sidecar-start.sh
.sidecar-base
.td-root
# Nix / direnv
.direnv/
result

430
AGENTS.md
View File

@@ -1,385 +1,129 @@
# Agent Instructions - Opencode Skills Repository
# Opencode Skills Repository
This repository contains Opencode Agent Skills, context files, and agent configurations for personal productivity and AI-assisted workflows. Files are deployed to `~/.config/opencode/` via Nix flake + home-manager.
Configuration repository for Opencode Agent Skills, context files, and agent configurations. Deployed via Nix home-manager to `~/.config/opencode/`.
## Project Overview
## Quick Commands
**Type**: Configuration-only repository (no build/compile step)
**Purpose**: Central repository for Opencode Agent Skills, AI agent configurations, custom commands, and workflows. Extensible framework for productivity, automation, knowledge management, and AI-assisted development.
**Primary User**: Sascha Koenig (@m3tam3re)
**Deployment**: Nix flake → home-manager → `~/.config/opencode/`
```bash
# Skill validation
./scripts/test-skill.sh --validate # Validate all skills
./scripts/test-skill.sh <skill-name> # Validate specific skill
./scripts/test-skill.sh --run # Test interactively
### Current Focus Areas
# Skill creation
python3 skills/skill-creator/scripts/init_skill.py <name> --path skills/
```
- **Productivity & Task Management** - PARA methodology, Anytype integration, reviews
- **Knowledge Management** - Note capture, organization, research workflows
- **Communications** - Email drafts, follow-ups, calendar scheduling
- **AI Development** - Skill creation, agent configurations, custom commands
- **Memory & Context** - Persistent memory with Mem0, conversation analysis
### Extensibility
This repository serves as a foundation for any Opencode-compatible skill or agent configuration. Add new skills for:
- Domain-specific workflows (finance, legal, engineering, etc.)
- Tool integrations (APIs, databases, cloud platforms)
- Custom automation and productivity systems
- Specialized AI agents for different contexts
### Directory Structure
## Directory Structure
```
.
├── agent/ # Agent definitions (agents.json)
├── prompts/ # Agent system prompts (chiron.txt, chiron-forge.txt)
├── context/ # User profiles and preferences
├── command/ # Custom command definitions
├── skill/ # Opencode Agent Skills (8 skills)
── task-management/
│ ├── skill-creator/
│ ├── reflection/
│ ├── communications/
── calendar-scheduling/
│ ├── mem0-memory/
│ ├── research/
│ └── knowledge-management/
├── scripts/ # Repository-level utility scripts
└── AGENTS.md # This file
├── skills/ # Agent skills (15 modules)
│ └── skill-name/
│ ├── SKILL.md # Required: YAML frontmatter + workflows
│ ├── scripts/ # Executable code (optional)
│ ├── references/ # Domain docs (optional)
── assets/ # Templates/files (optional)
├── rules/ # AI coding rules (languages, concerns, frameworks)
│ ├── languages/ # Python, TypeScript, Nix, Shell
│ ├── concerns/ # Testing, naming, documentation, etc.
── frameworks/ # Framework-specific rules (n8n, etc.)
├── agents/ # Agent definitions (agents.json)
├── prompts/ # System prompts (chiron*.txt)
├── context/ # User profiles
├── commands/ # Custom commands
└── scripts/ # Repo utilities (test-skill.sh, validate-agents.sh)
```
## Code Conventions
## Skill Development
**File naming**: hyphen-case (skills), snake_case (Python), UPPERCASE/sentence-case (MD)
### Creating a New Skill
Use the skill initialization script:
```bash
python3 skill/skill-creator/scripts/init_skill.py <skill-name> --path skill/
```
This creates:
- `skill/<skill-name>/SKILL.md` with proper frontmatter template
- `skill/<skill-name>/scripts/` - For executable code
- `skill/<skill-name>/references/` - For documentation
- `skill/<skill-name>/assets/` - For templates/files
### Validating Skills
Run validation before committing:
```bash
python3 skill/skill-creator/scripts/quick_validate.py skill/<skill-name>
```
**Validation checks:**
- YAML frontmatter structure
- Required fields: `name`, `description`
- Name format: hyphen-case, max 64 chars
- Description: max 1024 chars, no angle brackets
- Allowed frontmatter properties: `name`, `description`, `compatibility`, `license`, `allowed-tools`, `metadata`
### Skill Structure Requirements
**SKILL.md Frontmatter** (required):
**SKILL.md structure**:
```yaml
---
name: skill-name
description: What it does and when to use it. Include trigger words.
description: "Use when: (1) X, (2) Y. Triggers: a, b, c."
compatibility: opencode
---
## Overview (1 line)
## Core Workflows (step-by-step)
## Integration with Other Skills
```
**Resource Directories** (optional):
- `scripts/` - Executable Python/Bash code for deterministic operations
- `references/` - Documentation loaded into context as needed
- `assets/` - Files used in output (templates, images, fonts)
**Python**: `#!/usr/bin/env python3` + docstrings + emoji feedback (✅/❌)
**Bash**: `#!/usr/bin/env bash` + `set -euo pipefail`
**Markdown**: YAML frontmatter, ATX headers, `-` lists, language in code blocks
### Skill Design Principles
## Anti-Patterns (CRITICAL)
1. **Concise is key** - Context window is shared resource
2. **Progressive disclosure** - Metadata → SKILL.md body → bundled resources
3. **Appropriate freedom** - Match specificity to task fragility
4. **No extraneous files** - No README.md, CHANGELOG.md, etc. in skills
5. **Reference patterns** - See `skill/skill-creator/references/workflows.md` and `output-patterns.md`
**Frontend Design**: NEVER use generic AI aesthetics, NEVER converge on common choices
**Excalidraw**: NEVER use `label` property (use boundElements + text element pairs instead)
**Debugging**: NEVER fix just symptom, ALWAYS find root cause first
**Excel**: ALWAYS respect existing template conventions over guidelines
**Structure**: NEVER place scripts/docs outside scripts/references/ directories
## Code Style Guidelines
## Testing Patterns
### File Naming
**Unique conventions** (skill-focused, not CI/CD):
- Manual validation via `test-skill.sh`, no automated CI
- Tests co-located with source (not separate test directories)
- YAML frontmatter validation = primary quality gate
- Mixed formats: Python unittest, markdown pressure tests, A/B prompt testing
**Skills**: Hyphen-case (e.g., `task-management`, `skill-creator`)
**Python scripts**: Snake_case (e.g., `init_skill.py`, `quick_validate.py`)
**Markdown files**: UPPERCASE or sentence-case (e.g., `SKILL.md`, `profile.md`)
**Configuration**: Standard conventions (e.g., `config.yaml`, `metadata.json`)
**Known deviations**:
- `systematic-debugging/test-*.md` - Academic/pressure testing in wrong location
- `pdf/forms.md`, `pdf/reference.md` - Docs outside references/
### Markdown Style
## Deployment
**Frontmatter**:
- Always use YAML format between `---` delimiters
- Required fields for skills: `name`, `description`
- Optional: `compatibility: opencode`, `mode: primary`
**Headers**:
- Use ATX-style (`#`, `##`, `###`)
- One H1 per file (skill title)
- Clear hierarchy
**Lists**:
- Use `-` for unordered lists (not `*`)
- Use numbered lists for sequential steps
- Indent nested lists with 2 spaces
**Code blocks**:
- Always specify language for syntax highlighting
- Use `bash` for shell commands
- Use `yaml`, `nix`, `python` as appropriate
**Tables**:
- Use for structured comparisons and reference data
- Keep aligned for readability in source
- Example:
```markdown
| Header 1 | Header 2 |
|----------|----------|
| Value | Value |
```
### Python Style
**Shebang**: Always use `#!/usr/bin/env python3`
**Docstrings**:
```python
"""
Brief description of module/script
Usage:
script_name.py <arg1> --flag <arg2>
Examples:
script_name.py my-skill --path ~/.config/opencode/skill
"""
```
**Imports**:
```python
# Standard library
import sys
import os
from pathlib import Path
# Third-party (if any)
import yaml
# Local (if any)
from . import utilities
```
**Naming**:
- Functions: `snake_case`
- Classes: `PascalCase`
- Constants: `UPPER_SNAKE_CASE`
- Private: `_leading_underscore`
**Error handling**:
```python
try:
# operation
except SpecificException as e:
print(f"❌ Error: {e}")
return None
```
**User feedback**:
- Use ✅ for success messages
- Use ❌ for error messages
- Print progress for multi-step operations
### YAML Style
```yaml
# Use lowercase keys with hyphens
skill-name: value
# Quotes for strings with special chars
description: "PARA-based task management. Use when: (1) item, (2) item."
# No quotes for simple strings
compatibility: opencode
# Lists with hyphens
items:
- first
- second
```
## Nix Flake Integration
This repository is the central source for all Opencode configuration, consumed as a **non-flake input** by your NixOS configuration.
### Integration Reference
**NixOS config location**: `~/p/NIX/nixos-config/home/features/coding/opencode.nix`
**Flake input definition** (in `flake.nix`):
**Nix flake pattern**:
```nix
agents = {
url = "git+https://code.m3ta.dev/m3tam3re/AGENTS";
flake = false; # Pure files, not a Nix flake
inputs.nixpkgs.follows = "nixpkgs"; # Optional but recommended
};
```
### Deployment Mapping
**Exports:**
- `packages.skills-runtime` — composable runtime with all skill dependencies
- `devShells.default` — dev environment for working on skills
| Source | Deployed To | Method |
|--------|-------------|--------|
| `skill/` | `~/.config/opencode/skill/` | xdg.configFile (symlink) |
| `context/` | `~/.config/opencode/context/` | xdg.configFile (symlink) |
| `command/` | `~/.config/opencode/command/` | xdg.configFile (symlink) |
| `prompts/` | `~/.config/opencode/prompts/` | xdg.configFile (symlink) |
| `agent/agents.json` | `programs.opencode.settings.agent` | **Embedded into config.json** |
**Mapping** (via home-manager):
- `skills/`, `context/`, `commands/`, `prompts/` → symlinks
- `agents/agents.json` → embedded into config.json
- Agent changes: require `home-manager switch`
- Other changes: visible immediately
### Important: Agent Configuration Nuance
## Rules System
The `agent/` directory is **NOT** deployed as files to `~/.config/opencode/agent/`. Instead, `agents.json` is read at Nix evaluation time and embedded directly into the opencode `config.json` via:
Centralized AI coding rules consumed via `mkOpencodeRules` from m3ta-nixpkgs:
```nix
programs.opencode.settings.agent = builtins.fromJSON (builtins.readFile "${inputs.agents}/agent/agents.json");
# In project flake.nix
m3taLib.opencode-rules.mkOpencodeRules {
inherit agents;
languages = [ "python" "typescript" ];
frameworks = [ "n8n" ];
};
```
**Implications**:
- Agent changes require `home-manager switch` to take effect
- Skills, context, and commands are symlinked (changes visible immediately after rebuild)
- The `prompts/` directory is referenced by `agents.json` via `{file:./prompts/chiron.txt}` syntax
## Quality Gates
Before committing changes, verify:
1. **Skill validation** - Run `quick_validate.py` on modified skills
2. **File structure** - Ensure no extraneous files (README in skills, etc.)
3. **Frontmatter** - Check YAML syntax and required fields
4. **Scripts executable** - Python scripts should have proper shebang
5. **Markdown formatting** - Check headers, lists, code blocks
6. **Git status** - No uncommitted or untracked files that should be tracked
## Landing the Plane (Session Completion)
**When ending a work session**, you MUST complete ALL steps below. Work is NOT complete until `git push` succeeds.
## Testing Skills
Since this repo deploys via Nix/home-manager, changes require a rebuild to appear in `~/.config/opencode/`. Use these methods to test skills during development.
### Method 1: XDG_CONFIG_HOME Override (Recommended)
Test skills by pointing opencode to this repository directly:
```bash
# From the AGENTS repository root
cd ~/p/AI/AGENTS
# List skills loaded from this repo (not the deployed ones)
XDG_CONFIG_HOME=. opencode debug skill
# Run an interactive session with development skills
XDG_CONFIG_HOME=. opencode
# Or use the convenience script
./scripts/test-skill.sh # List all development skills
./scripts/test-skill.sh task-management # Validate specific skill
./scripts/test-skill.sh --run # Launch interactive session
```
**Note**: The convenience script creates a temporary directory with proper symlinks since opencode expects `$XDG_CONFIG_HOME/opencode/skill/` structure.
### Method 2: Project-Local Skills
For quick iteration on a single skill, use `.opencode/skill/` in any project:
```bash
cd /path/to/any/project
mkdir -p .opencode/skill/
# Symlink the skill you're developing
ln -s ~/p/AI/AGENTS/skill/my-skill .opencode/skill/
# Skills in .opencode/skill/ are auto-discovered alongside global skills
opencode debug skill
```
### Method 3: Validation Only
Validate skill structure without running opencode:
```bash
# Validate a single skill
python3 skill/skill-creator/scripts/quick_validate.py skill/<skill-name>
# Validate all skills
for dir in skill/*/; do
python3 skill/skill-creator/scripts/quick_validate.py "$dir"
done
```
### Verification Commands
```bash
# List all loaded skills (shows name, description, location)
opencode debug skill
# Show resolved configuration
opencode debug config
# Show where opencode looks for files
opencode debug paths
```
## Common Operations
### Create New Skill
```bash
# Initialize
python3 skill/skill-creator/scripts/init_skill.py my-new-skill --path skill/
# Edit SKILL.md and implement resources
# Delete unneeded example files from scripts/, references/, assets/
# Validate
python3 skill/skill-creator/scripts/quick_validate.py skill/my-new-skill
```
### Update User Context
Edit `context/profile.md` to update:
- Work style preferences
- PARA areas
- Communication preferences
- Integration status
### Modify Agent Behavior
Edit `agent/agents.json` to adjust agent definitions, and `prompts/*.txt` for system prompts:
- `agent/agents.json` - Agent names, models, permissions
- `prompts/chiron.txt` - Chiron (Plan Mode) system prompt
- `prompts/chiron-forge.txt` - Chiron-Forge (Worker Mode) system prompt
## Reference Documentation
**Skill creation guide**: `skill/skill-creator/SKILL.md`
**Workflow patterns**: `skill/skill-creator/references/workflows.md`
**Output patterns**: `skill/skill-creator/references/output-patterns.md`
**User profile**: `context/profile.md`
**Agent config**: `agent/agents.json`
See `rules/USAGE.md` for full documentation.
## Notes for AI Agents
1. **This is a config repo** - No compilation, no tests, no runtime
2. **Validation is manual** - Run scripts explicitly before committing
3. **Skills are documentation** - Write for AI consumption, not humans
4. **Context window matters** - Keep skills concise, use progressive disclosure
5. **Nix deployment** - Maintain structure expected by home-manager
6. **Always push** - Follow session completion workflow religiously
1. **Config-only repo** - No compilation, no build, manual validation only
2. **Skills are documentation** - Write for AI consumption, progressive disclosure
3. **Consistent structure** - All skills follow 4-level deep pattern (skills/name/ + optional subdirs)
4. **Cross-cutting concerns** - Standardized SKILL.md, workflow patterns, delegation rules
5. **Always push** - Session completion workflow: commit + git push
## Quality Gates
Before committing:
1. `./scripts/test-skill.sh --validate`
2. Python shebang + docstrings check
3. No extraneous files (README.md, CHANGELOG.md in skills/)
4. If skill has scripts with external dependencies → verify `flake.nix` is updated (see skill-creator Step 4)
5. Git status clean

324
README.md
View File

@@ -1,6 +1,6 @@
# Opencode Agent Skills & Configurations
Central repository for [Opencode](https://opencode.dev) Agent Skills, AI agent configurations, custom commands, and AI-assisted workflows. This is an extensible framework for building productivity systems, automations, knowledge management, and specialized AI capabilities.
Central repository for [Opencode](https://opencode.ai) Agent Skills, AI agent configurations, custom commands, and AI-assisted workflows. This is an extensible framework for building productivity systems, automations, knowledge management, and specialized AI capabilities.
## 🎯 What This Repository Provides
@@ -8,36 +8,45 @@ This repository serves as a **personal AI operating system** - a collection of s
- **Productivity & Task Management** - PARA methodology, GTD workflows, project tracking
- **Knowledge Management** - Note-taking, research workflows, information organization
- **Communications** - Email management, meeting scheduling, follow-up tracking
- **AI Development** - Tools for creating new skills and agent configurations
- **Memory & Context** - Persistent memory systems, conversation analysis
- **Document Processing** - PDF manipulation, spreadsheet handling, diagram generation
- **Custom Workflows** - Domain-specific automation and specialized agents
## 📂 Repository Structure
```
.
├── agent/ # Agent definitions (agents.json)
├── prompts/ # Agent system prompts (chiron.txt, chiron-forge.txt)
├── agents/ # Agent definitions (agents.json)
├── prompts/ # Agent system prompts (chiron.txt, chiron-forge.txt, etc.)
├── context/ # User profiles and preferences
│ └── profile.md # Work style, PARA areas, preferences
├── command/ # Custom command definitions
├── commands/ # Custom command definitions
│ └── reflection.md
├── skill/ # Opencode Agent Skills (11+ skills)
│ ├── task-management/ # PARA-based productivity
│ ├── skill-creator/ # Meta-skill for creating skills
│ ├── reflection/ # Conversation analysis
│ ├── communications/ # Email & messaging
│ ├── calendar-scheduling/ # Time management
│ ├── mem0-memory/ # Persistent memory
│ ├── research/ # Investigation workflows
│ ├── knowledge-management/ # Note capture & organization
├── skills/ # Opencode Agent Skills (15 skills)
│ ├── agent-development/ # Agent creation and configuration
│ ├── basecamp/ # Basecamp project management
│ ├── brainstorming/ # Ideation & strategic thinking
── plan-writing/ # Project planning templates
── doc-translator/ # Documentation translation
│ ├── excalidraw/ # Architecture diagrams
│ ├── frontend-design/ # UI/UX design patterns
│ ├── memory/ # Persistent memory system
│ ├── obsidian/ # Obsidian vault management
│ ├── outline/ # Outline wiki integration
│ ├── pdf/ # PDF manipulation toolkit
│ ├── prompt-engineering-patterns/ # Prompt patterns
│ ├── reflection/ # Conversation analysis
│ ├── skill-creator/ # Meta-skill for creating skills
│ ├── systematic-debugging/ # Debugging methodology
│ └── xlsx/ # Spreadsheet handling
├── scripts/ # Repository utility scripts
│ └── test-skill.sh # Test skills without deploying
├── .beads/ # Issue tracking database
├── rules/ # AI coding rules
│ ├── languages/ # Python, TypeScript, Nix, Shell
│ ├── concerns/ # Testing, naming, documentation
│ └── frameworks/ # Framework-specific rules (n8n)
├── flake.nix # Nix flake: dev shell + skills-runtime export
├── .envrc # direnv config (use flake)
├── AGENTS.md # Developer documentation
└── README.md # This file
```
@@ -46,43 +55,96 @@ This repository serves as a **personal AI operating system** - a collection of s
### Prerequisites
- **Opencode** - AI coding assistant ([opencode.dev](https://opencode.dev))
- **Nix** (optional) - For declarative deployment via home-manager
- **Python 3** - For skill validation and creation scripts
- **bd (beads)** (optional) - For issue tracking
- **Nix** with flakes enabled — for reproducible dependency management and deployment
- **direnv** (recommended) — auto-activates the development environment when entering the repo
- **Opencode** — AI coding assistant ([opencode.ai](https://opencode.ai))
### Installation
#### Option 1: Nix Flake (Recommended)
This repository is consumed as a **non-flake input** by your NixOS configuration:
This repository is a **Nix flake** that exports:
- **`devShells.default`** — development environment for working on skills (activated via direnv)
- **`packages.skills-runtime`** — composable runtime with all skill script dependencies (Python packages + system tools)
**Consume in your system flake:**
```nix
# In your flake.nix
# flake.nix
inputs.agents = {
url = "git+https://code.m3ta.dev/m3tam3re/AGENTS";
flake = false; # Pure files, not a Nix flake
inputs.nixpkgs.follows = "nixpkgs";
};
# In your home-manager module (e.g., opencode.nix)
xdg.configFile = {
"opencode/skill".source = "${inputs.agents}/skill";
"opencode/skills".source = "${inputs.agents}/skills";
"opencode/context".source = "${inputs.agents}/context";
"opencode/command".source = "${inputs.agents}/command";
"opencode/commands".source = "${inputs.agents}/commands";
"opencode/prompts".source = "${inputs.agents}/prompts";
};
# Agent config is embedded into config.json, not deployed as files
programs.opencode.settings.agent = builtins.fromJSON
(builtins.readFile "${inputs.agents}/agent/agents.json");
programs.opencode.settings.agent = builtins.fromJSON
(builtins.readFile "${inputs.agents}/agents/agents.json");
```
Rebuild your system:
**Deploy skills via home-manager:**
```nix
# home-manager module (e.g., opencode.nix)
{ inputs, system, ... }:
{
# Skill files — symlinked, changes visible immediately
xdg.configFile = {
"opencode/skills".source = "${inputs.agents}/skills";
"opencode/context".source = "${inputs.agents}/context";
"opencode/commands".source = "${inputs.agents}/commands";
"opencode/prompts".source = "${inputs.agents}/prompts";
};
# Agent config — embedded into config.json (requires home-manager switch)
programs.opencode.settings.agent = builtins.fromJSON
(builtins.readFile "${inputs.agents}/agents/agents.json");
# Skills runtime — ensures opencode always has script dependencies
home.packages = [ inputs.agents.packages.${system}.skills-runtime ];
}
```
**Compose into project flakes** (so opencode has skill deps in any project):
```nix
# Any project's flake.nix
{
inputs.agents.url = "git+https://code.m3ta.dev/m3tam3re/AGENTS";
inputs.agents.inputs.nixpkgs.follows = "nixpkgs";
outputs = { self, nixpkgs, agents, ... }:
let
system = "x86_64-linux";
pkgs = nixpkgs.legacyPackages.${system};
in {
devShells.${system}.default = pkgs.mkShell {
packages = [
# project-specific tools
pkgs.nodejs
# skill script dependencies
agents.packages.${system}.skills-runtime
];
};
};
}
```
Rebuild:
```bash
home-manager switch
```
**Note**: The `agent/` directory is NOT deployed as files. Instead, `agents.json` is read at Nix evaluation time and embedded into the opencode `config.json`.
**Note**: The `agents/` directory is NOT deployed as files. Instead, `agents.json` is read at Nix evaluation time and embedded into the opencode `config.json`.
#### Option 2: Manual Installation
@@ -92,8 +154,11 @@ Clone and symlink:
# Clone repository
git clone https://github.com/yourusername/AGENTS.git ~/AGENTS
# Create symlink to Opencode config directory
ln -s ~/AGENTS ~/.config/opencode
# Create symlinks to Opencode config directory
ln -s ~/AGENTS/skills ~/.config/opencode/skills
ln -s ~/AGENTS/context ~/.config/opencode/context
ln -s ~/AGENTS/commands ~/.config/opencode/commands
ln -s ~/AGENTS/prompts ~/.config/opencode/prompts
```
### Verify Installation
@@ -101,8 +166,8 @@ ln -s ~/AGENTS ~/.config/opencode
Check that Opencode can see your skills:
```bash
# Skills should be available at ~/.config/opencode/skill/
ls ~/.config/opencode/skill/
# Skills should be available at ~/.config/opencode/skills/
ls ~/.config/opencode/skills/
```
## 🎨 Creating Your First Skill
@@ -112,18 +177,19 @@ Skills are modular packages that extend Opencode with specialized knowledge and
### 1. Initialize a New Skill
```bash
python3 skill/skill-creator/scripts/init_skill.py my-skill-name --path skill/
python3 skills/skill-creator/scripts/init_skill.py my-skill-name --path skills/
```
This creates:
- `skill/my-skill-name/SKILL.md` - Main skill documentation
- `skill/my-skill-name/scripts/` - Executable code (optional)
- `skill/my-skill-name/references/` - Reference documentation (optional)
- `skill/my-skill-name/assets/` - Templates and files (optional)
- `skills/my-skill-name/SKILL.md` - Main skill documentation
- `skills/my-skill-name/scripts/` - Executable code (optional)
- `skills/my-skill-name/references/` - Reference documentation (optional)
- `skills/my-skill-name/assets/` - Templates and files (optional)
### 2. Edit the Skill
Open `skill/my-skill-name/SKILL.md` and customize:
Open `skills/my-skill-name/SKILL.md` and customize:
```yaml
---
@@ -131,7 +197,6 @@ name: my-skill-name
description: What it does and when to use it. Include trigger keywords.
compatibility: opencode
---
# My Skill Name
## Overview
@@ -139,108 +204,111 @@ compatibility: opencode
[Your skill instructions for Opencode]
```
### 3. Validate the Skill
### 3. Register Dependencies
```bash
python3 skill/skill-creator/scripts/quick_validate.py skill/my-skill-name
If your skill includes scripts with external dependencies, add them to `flake.nix`:
```nix
# Python packages — add to pythonEnv:
# my-skill: my_script.py
some-python-package
# System tools — add to skills-runtime paths:
# my-skill: needed by my_script.py
pkgs.some-tool
```
### 4. Test the Skill
Verify: `nix develop --command python3 -c "import some_package"`
Test your skill without deploying via home-manager:
### 4. Validate the Skill
```bash
python3 skills/skill-creator/scripts/quick_validate.py skills/my-skill-name
```
### 5. Test the Skill
```bash
# Use the test script to validate and list skills
./scripts/test-skill.sh my-skill-name # Validate specific skill
./scripts/test-skill.sh --list # List all dev skills
./scripts/test-skill.sh --run # Launch opencode with dev skills
./scripts/test-skill.sh --run # Launch opencode with dev skills
```
The test script creates a temporary config directory with symlinks to this repo's skills, allowing you to test changes before committing.
## 📚 Available Skills
| Skill | Purpose | Status |
|-------|---------|--------|
| **task-management** | PARA-based productivity with Anytype integration | ✅ Active |
| **skill-creator** | Guide for creating new Opencode skills | ✅ Active |
| **reflection** | Conversation analysis and skill improvement | ✅ Active |
| **communications** | Email drafts, follow-ups, message management | ✅ Active |
| **calendar-scheduling** | Time blocking, meeting management | ✅ Active |
| **mem0-memory** | Persistent memory storage and retrieval | ✅ Active |
| **research** | Investigation workflows, source management | ✅ Active |
| **knowledge-management** | Note capture, knowledge organization | ✅ Active |
| **basecamp** | Basecamp project & todo management via MCP | ✅ Active |
| **brainstorming** | General-purpose ideation with Anytype save | ✅ Active |
| **plan-writing** | Project plans with templates (kickoff, tasks, risks) | ✅ Active |
| Skill | Purpose | Status |
| --------------------------- | -------------------------------------------------------------- | ------------ |
| **agent-development** | Create and configure Opencode agents | ✅ Active |
| **basecamp** | Basecamp project & todo management via MCP | ✅ Active |
| **brainstorming** | General-purpose ideation and strategic thinking | ✅ Active |
| **doc-translator** | Documentation translation to German/Czech with Outline publish | ✅ Active |
| **excalidraw** | Architecture diagrams from codebase analysis | ✅ Active |
| **frontend-design** | Production-grade UI/UX with high design quality | ✅ Active |
| **memory** | SQLite-based persistent memory with hybrid search | ✅ Active |
| **obsidian** | Obsidian vault management via Local REST API | ✅ Active |
| **outline** | Outline wiki integration for team documentation | ✅ Active |
| **pdf** | PDF manipulation, extraction, creation, and forms | ✅ Active |
| **prompt-engineering-patterns** | Advanced prompt engineering techniques | ✅ Active |
| **reflection** | Conversation analysis and skill improvement | ✅ Active |
| **skill-creator** | Guide for creating new Opencode skills | ✅ Active |
| **systematic-debugging** | Debugging methodology for bugs and test failures | ✅ Active |
| **xlsx** | Spreadsheet creation, editing, and analysis | ✅ Active |
## 🤖 AI Agents
### Chiron - Personal Assistant
### Primary Agents
**Configuration**: `agent/agents.json` + `prompts/chiron.txt`
| Agent | Mode | Purpose |
| ------------------- | ------- | ---------------------------------------------------- |
| **Chiron** | Plan | Read-only analysis, planning, and guidance |
| **Chiron Forge** | Build | Full execution and task completion with safety |
Chiron is a personal AI assistant focused on productivity and task management. Named after the wise centaur from Greek mythology, Chiron provides:
### Subagents (Specialists)
- Task and project management guidance
- Daily and weekly review workflows
- Skill routing based on user intent
- Integration with productivity tools (Anytype, ntfy, n8n)
| Agent | Domain | Purpose |
| ------------------- | ---------------- | ------------------------------------------ |
| **Hermes** | Communication | Basecamp, Outlook, MS Teams |
| **Athena** | Research | Outline wiki, documentation, knowledge |
| **Apollo** | Private Knowledge| Obsidian vault, personal notes |
| **Calliope** | Writing | Documentation, reports, prose |
**Modes**:
- **Chiron** (Plan Mode) - Read-only analysis and planning (`prompts/chiron.txt`)
- **Chiron-Forge** (Worker Mode) - Full write access with safety prompts (`prompts/chiron-forge.txt`)
**Configuration**: `agents/agents.json` + `prompts/*.txt`
**Triggers**: Personal productivity requests, task management, reviews, planning
## 🛠️ Development
## 🛠️ Development Workflow
### Environment
### Issue Tracking with Beads
This project uses [beads](https://github.com/steveyegge/beads) for AI-native issue tracking:
The repository includes a Nix flake with a development shell. With [direnv](https://direnv.net/) installed, the environment activates automatically:
```bash
bd ready # Find available work
bd create "title" # Create new issue
bd update <id> --status in_progress
bd close <id> # Complete work
bd sync # Sync with git
cd AGENTS/
# → direnv: loading .envrc
# → 🔧 AGENTS dev shell active — Python 3.13.x, jq-1.x
# All skill script dependencies are now available:
python3 -c "import pypdf, openpyxl, yaml" # ✔️
pdftoppm -v # ✔️
```
Without direnv, activate manually: `nix develop`
### Quality Gates
Before committing:
1. **Validate skills**: `./scripts/test-skill.sh --validate` or `python3 skill/skill-creator/scripts/quick_validate.py skill/<name>`
1. **Validate skills**: `./scripts/test-skill.sh --validate` or `python3 skills/skill-creator/scripts/quick_validate.py skills/<name>`
2. **Test locally**: `./scripts/test-skill.sh --run` to launch opencode with dev skills
3. **Check formatting**: Ensure YAML frontmatter is valid
4. **Update docs**: Keep README and AGENTS.md in sync
### Session Completion
When ending a work session:
1. File beads issues for remaining work
2. Run quality gates
3. Update issue status
4. **Push to remote** (mandatory):
```bash
git pull --rebase
bd sync
git push
```
5. Verify changes are pushed
See `AGENTS.md` for complete developer documentation.
## 🎓 Learning Resources
### Essential Documentation
- **AGENTS.md** - Complete developer guide for AI agents
- **skill/skill-creator/SKILL.md** - Comprehensive skill creation guide
- **skill/skill-creator/references/workflows.md** - Workflow pattern library
- **skill/skill-creator/references/output-patterns.md** - Output formatting patterns
- **skills/skill-creator/SKILL.md** - Comprehensive skill creation guide
- **skills/skill-creator/references/workflows.md** - Workflow pattern library
- **skills/skill-creator/references/output-patterns.md** - Output formatting patterns
- **rules/USAGE.md** - AI coding rules integration guide
### Skill Design Principles
@@ -251,27 +319,33 @@ See `AGENTS.md` for complete developer documentation.
### Example Skills to Study
- **task-management/** - Full implementation with Anytype integration
- **skill-creator/** - Meta-skill with bundled resources
- **reflection/** - Conversation analysis with rating system
- **basecamp/** - MCP server integration with multiple tool categories
- **brainstorming/** - Framework-based ideation with Anytype object creation
- **plan-writing/** - Template-driven document generation
- **brainstorming/** - Framework-based ideation with Obsidian markdown save
- **memory/** - SQLite-based hybrid search implementation
- **excalidraw/** - Diagram generation with JSON templates and Python renderer
## 🔧 Customization
### Modify Agent Behavior
Edit `agent/agents.json` for agent definitions and `prompts/*.txt` for system prompts:
- `agent/agents.json` - Agent names, models, permissions
Edit `agents/agents.json` for agent definitions and `prompts/*.txt` for system prompts:
- `agents/agents.json` - Agent names, models, permissions
- `prompts/chiron.txt` - Chiron (Plan Mode) system prompt
- `prompts/chiron-forge.txt` - Chiron-Forge (Worker Mode) system prompt
- `prompts/chiron-forge.txt` - Chiron Forge (Build Mode) system prompt
- `prompts/hermes.txt` - Hermes (Communication) system prompt
- `prompts/athena.txt` - Athena (Research) system prompt
- `prompts/apollo.txt` - Apollo (Private Knowledge) system prompt
- `prompts/calliope.txt` - Calliope (Writing) system prompt
**Note**: Agent changes require `home-manager switch` to take effect (config is embedded, not symlinked).
### Update User Context
Edit `context/profile.md` to configure:
- Work style preferences
- PARA areas and projects
- Communication preferences
@@ -279,13 +353,29 @@ Edit `context/profile.md` to configure:
### Add Custom Commands
Create new command definitions in `command/` directory following the pattern in `command/reflection.md`.
Create new command definitions in `commands/` directory following the pattern in `commands/reflection.md`.
### Add Project Rules
Use the rules system to inject AI coding rules into projects:
```nix
# In project flake.nix
m3taLib.opencode-rules.mkOpencodeRules {
inherit agents;
languages = [ "python" "typescript" ];
frameworks = [ "n8n" ];
};
```
See `rules/USAGE.md` for full documentation.
## 🌟 Use Cases
### Personal Productivity
Use the PARA methodology with Anytype integration:
Use the PARA methodology with Obsidian Tasks integration:
- Capture tasks and notes quickly
- Run daily/weekly reviews
- Prioritize work based on impact
@@ -294,6 +384,7 @@ Use the PARA methodology with Anytype integration:
### Knowledge Management
Build a personal knowledge base:
- Capture research findings
- Organize notes and references
- Link related concepts
@@ -302,6 +393,7 @@ Build a personal knowledge base:
### AI-Assisted Development
Extend Opencode for specialized domains:
- Create company-specific skills (finance, legal, engineering)
- Integrate with APIs and databases
- Build custom automation workflows
@@ -310,6 +402,7 @@ Extend Opencode for specialized domains:
### Team Collaboration
Share skills and agents across teams:
- Document company processes as skills
- Create shared knowledge bases
- Standardize communication templates
@@ -331,15 +424,14 @@ This repository contains personal configurations and skills. Feel free to use th
## 🔗 Links
- [Opencode](https://opencode.dev) - AI coding assistant
- [Beads](https://github.com/steveyegge/beads) - AI-native issue tracking
- [PARA Method](https://fortelabs.com/blog/para/) - Productivity methodology
- [Anytype](https://anytype.io) - Knowledge management platform
- [Obsidian](https://obsidian.md) - Knowledge management platform
## 🙋 Questions?
- Check `AGENTS.md` for detailed developer documentation
- Review existing skills in `skill/` for examples
- See `skill/skill-creator/SKILL.md` for skill creation guide
- Review existing skills in `skills/` for examples
- See `skills/skill-creator/SKILL.md` for skill creation guide
---

View File

@@ -1,105 +0,0 @@
{
"chiron": {
"description": "Personal AI assistant (Plan Mode). Read-only analysis, planning, and guidance.",
"mode": "primary",
"model": "zai-coding-plan/glm-4.7",
"prompt": "{file:./prompts/chiron.txt}",
"permission": {
"read": {
"*": "allow",
"*.env": "deny",
"*.env.*": "deny",
"*.env.example": "allow",
"*/.ssh/*": "deny",
"*/.gnupg/*": "deny",
"*credentials*": "deny",
"*secrets*": "deny",
"*.pem": "deny",
"*.key": "deny",
"*/.aws/*": "deny",
"*/.kube/*": "deny"
},
"edit": "ask",
"bash": "ask",
"external_directory": "ask",
"doom_loop": "ask"
}
},
"chiron-forge": {
"description": "Personal AI assistant (Worker Mode). Full write access with safety prompts.",
"mode": "primary",
"model": "zai-coding-plan/glm-4.7",
"prompt": "{file:./prompts/chiron-forge.txt}",
"permission": {
"read": {
"*": "allow",
"*.env": "deny",
"*.env.*": "deny",
"*.env.example": "allow",
"*/.ssh/*": "deny",
"*/.gnupg/*": "deny",
"*credentials*": "deny",
"*secrets*": "deny",
"*.pem": "deny",
"*.key": "deny",
"*/.aws/*": "deny",
"*/.kube/*": "deny"
},
"edit": "allow",
"bash": {
"*": "allow",
"rm *": "ask",
"rmdir *": "ask",
"mv *": "ask",
"chmod *": "ask",
"chown *": "ask",
"git *": "ask",
"git status*": "allow",
"git log*": "allow",
"git diff*": "allow",
"git branch*": "allow",
"git show*": "allow",
"git stash list*": "allow",
"git remote -v": "allow",
"git add *": "allow",
"git commit *": "allow",
"jj *": "ask",
"jj status": "allow",
"jj log*": "allow",
"jj diff*": "allow",
"jj show*": "allow",
"npm *": "ask",
"npx *": "ask",
"bun *": "ask",
"bunx *": "ask",
"uv *": "ask",
"pip *": "ask",
"pip3 *": "ask",
"yarn *": "ask",
"pnpm *": "ask",
"cargo *": "ask",
"go *": "ask",
"make *": "ask",
"dd *": "deny",
"mkfs*": "deny",
"fdisk *": "deny",
"parted *": "deny",
"eval *": "deny",
"source *": "deny",
"curl *|*sh": "deny",
"wget *|*sh": "deny",
"sudo *": "deny",
"su *": "deny",
"systemctl *": "deny",
"service *": "deny",
"shutdown *": "deny",
"reboot*": "deny",
"init *": "deny",
"> /dev/*": "deny",
"cat * > /dev/*": "deny"
},
"external_directory": "ask",
"doom_loop": "ask"
}
}
}

173
agents/agents.json Normal file
View File

@@ -0,0 +1,173 @@
{
"Chiron (Assistant)": {
"description": "Personal AI assistant (Plan Mode). Read-only analysis, planning, and guidance.",
"mode": "primary",
"model": "zai-coding-plan/glm-5",
"prompt": "{file:./prompts/chiron.txt}",
"permission": {
"question": "allow",
"webfetch": "allow",
"websearch": "allow",
"edit": "deny",
"bash": {
"*": "ask",
"git status*": "allow",
"git log*": "allow",
"git diff*": "allow",
"git branch*": "allow",
"git show*": "allow",
"grep *": "allow",
"ls *": "allow",
"cat *": "allow",
"head *": "allow",
"tail *": "allow",
"wc *": "allow",
"which *": "allow",
"echo *": "allow",
"td *": "allow",
"bd *": "allow",
"nix *": "allow"
},
"external_directory": {
"*": "ask",
"~/p/**": "allow",
"~/.config/opencode/**": "allow",
"/tmp/**": "allow",
"/run/agenix/**": "allow"
}
}
},
"Chiron Forge (Builder)": {
"description": "Personal AI assistant (Build Mode). Full execution and task completion capabilities with safety prompts.",
"mode": "primary",
"model": "zai-coding-plan/glm-5",
"prompt": "{file:./prompts/chiron-forge.txt}",
"permission": {
"question": "allow",
"webfetch": "allow",
"websearch": "allow",
"edit": {
"*": "allow",
"/run/agenix/**": "deny"
},
"bash": {
"*": "allow",
"rm -rf *": "ask",
"git reset --hard*": "ask",
"git push*": "ask",
"git push --force*": "deny",
"git push -f *": "deny"
},
"external_directory": {
"*": "ask",
"~/p/**": "allow",
"~/.config/opencode/**": "allow",
"/tmp/**": "allow",
"/run/agenix/**": "allow"
}
}
},
"Hermes (Communication)": {
"description": "Work communication specialist. Handles Basecamp tasks, Outlook email, and MS Teams meetings.",
"mode": "subagent",
"model": "zai-coding-plan/glm-5",
"prompt": "{file:./prompts/hermes.txt}",
"permission": {
"question": "allow",
"webfetch": "allow",
"edit": {
"*": "allow",
"/run/agenix/**": "deny"
},
"bash": {
"*": "ask",
"cat *": "allow",
"echo *": "allow"
},
"external_directory": {
"*": "ask",
"~/p/**": "allow",
"~/.config/opencode/**": "allow",
"/tmp/**": "allow",
"/run/agenix/**": "allow"
}
}
},
"Athena (Researcher)": {
"description": "Work knowledge specialist. Manages Outline wiki, documentation, and knowledge organization.",
"mode": "subagent",
"model": "zai-coding-plan/glm-5",
"prompt": "{file:./prompts/athena.txt}",
"permission": {
"question": "allow",
"webfetch": "allow",
"websearch": "allow",
"edit": {
"*": "allow",
"/run/agenix/**": "deny"
},
"bash": {
"*": "ask",
"grep *": "allow",
"cat *": "allow"
},
"external_directory": {
"*": "ask",
"~/p/**": "allow",
"~/.config/opencode/**": "allow",
"/tmp/**": "allow",
"/run/agenix/**": "allow"
}
}
},
"Apollo (Knowledge Management)": {
"description": "Private knowledge specialist. Manages Obsidian vault, personal notes, and private knowledge graph.",
"mode": "subagent",
"model": "zai-coding-plan/glm-5",
"prompt": "{file:./prompts/apollo.txt}",
"permission": {
"question": "allow",
"edit": {
"*": "allow",
"/run/agenix/**": "deny"
},
"bash": {
"*": "ask",
"cat *": "allow"
},
"external_directory": {
"*": "ask",
"~/p/**": "allow",
"~/.config/opencode/**": "allow",
"/tmp/**": "allow",
"/run/agenix/**": "allow"
}
}
},
"Calliope (Writer)": {
"description": "Writing specialist. Creates documentation, reports, meeting notes, and prose.",
"mode": "subagent",
"model": "zai-coding-plan/glm-5",
"prompt": "{file:./prompts/calliope.txt}",
"permission": {
"question": "allow",
"webfetch": "allow",
"edit": {
"*": "allow",
"/run/agenix/**": "deny"
},
"bash": {
"*": "ask",
"cat *": "allow",
"wc *": "allow"
},
"external_directory": {
"*": "ask",
"~/p/**": "allow",
"~/.config/opencode/**": "allow",
"/tmp/**": "allow",
"/run/agenix/**": "allow"
}
}
}
}

View File

@@ -70,18 +70,18 @@
| System | Purpose | Status |
|--------|---------|--------|
| Anytype | Knowledge management, PARA system | Setting up |
| Obsidian | Knowledge management, PARA system | Active |
| ntfy | Push notifications | Active |
| n8n | Workflow automation | Active |
| Proton Mail | Email | Active |
| Proton Calendar | Scheduling | Active |
| Android | Mobile | Active |
## Anytype Configuration
## Obsidian Configuration
- **Space**: Chiron (to be created)
- **Vault**: ~/CODEX
- **Structure**: PARA methodology
- **Types**: Project, Area, Resource, Archive, Task, Note
- **Note Types**: Project, Area, Resource, Archive, Task, Note, Brainstorm
## Context for AI Interactions
@@ -104,3 +104,48 @@
- Batch related information together
- Remember my preferences across sessions
- Proactively surface relevant information
---
## Memory System
AI agents have access to a persistent memory system for context across sessions via the opencode-memory plugin.
### Configuration
| Setting | Value |
|---------|-------|
| **Plugin** | `opencode-memory` |
| **Obsidian Vault** | `~/CODEX` |
| **Memory Folder** | `80-memory/` |
| **Database** | `~/.local/share/opencode-memory/index.db` |
| **Auto-Capture** | Enabled (session.idle event) |
| **Auto-Recall** | Enabled (session.created event) |
| **Token Budget** | 2000 tokens |
### Memory Categories
| Category | Purpose | Example |
|----------|---------|---------|
| `preference` | Personal preferences | UI settings, workflow styles |
| `fact` | Objective information | Tech stack, role, constraints |
| `decision` | Choices with rationale | Tool selections, architecture |
| `entity` | People, orgs, systems | Key contacts, important APIs |
| `other` | Everything else | General learnings |
### Available Tools
| Tool | Purpose |
|------|---------|
| `memory_search` | Hybrid search (vector + BM25) over vault + sessions |
| `memory_store` | Store new memory as markdown file |
| `memory_get` | Read specific file/lines from vault |
### Usage Notes
- Memories are stored as markdown files in Obsidian (source of truth)
- SQLite provides fast hybrid search (vector similarity + keyword BM25)
- Use explicit "remember this" to store important information
- Auto-recall injects relevant memories at session start
- Auto-capture extracts preferences/decisions at session idle
- See `skills/memory/SKILL.md` for full documentation

27
flake.lock generated Normal file
View File

@@ -0,0 +1,27 @@
{
"nodes": {
"nixpkgs": {
"locked": {
"lastModified": 1772479524,
"narHash": "sha256-u7nCaNiMjqvKpE+uZz9hE7pgXXTmm5yvdtFaqzSzUQI=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "4215e62dc2cd3bc705b0a423b9719ff6be378a43",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixpkgs-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"nixpkgs": "nixpkgs"
}
}
},
"root": "root",
"version": 7
}

68
flake.nix Normal file
View File

@@ -0,0 +1,68 @@
{
description = "Opencode Agent Skills development environment & runtime";
inputs = { nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable"; };
outputs = { self, nixpkgs }:
let
supportedSystems = [ "x86_64-linux" "aarch64-linux" "aarch64-darwin" ];
forAllSystems = nixpkgs.lib.genAttrs supportedSystems;
in {
# Composable runtime for project flakes and home-manager.
# Usage:
# home.packages = [ inputs.agents.packages.${system}.skills-runtime ];
# devShells.default = pkgs.mkShell {
# packages = [ inputs.agents.packages.${system}.skills-runtime ];
# };
packages = forAllSystems (system:
let
pkgs = nixpkgs.legacyPackages.${system};
pythonEnv = pkgs.python3.withPackages (ps:
with ps; [
# skill-creator: quick_validate.py
pyyaml
# xlsx: recalc.py
openpyxl
# prompt-engineering-patterns: optimize-prompt.py
numpy
# pdf: multiple scripts
pypdf
pillow # PIL
pdf2image
# excalidraw: render_excalidraw.py
playwright
]);
in {
skills-runtime = pkgs.buildEnv {
name = "opencode-skills-runtime";
paths = [
pythonEnv
pkgs.poppler-utils # pdf: pdftoppm/pdfinfo
pkgs.jq # shell scripts
pkgs.playwright-driver.browsers # excalidraw: chromium for rendering
];
};
});
# Dev shell for working on this repo (wraps skills-runtime).
devShells = forAllSystems (system:
let
pkgs = nixpkgs.legacyPackages.${system};
in {
default = pkgs.mkShell {
packages = [ self.packages.${system}.skills-runtime ];
env.PLAYWRIGHT_BROWSERS_PATH = "${pkgs.playwright-driver.browsers}";
shellHook = ''
echo "🔧 AGENTS dev shell active Python $(python3 --version 2>&1 | cut -d' ' -f2), $(jq --version)"
'';
};
});
};
}

55
prompts/apollo.txt Normal file
View File

@@ -0,0 +1,55 @@
You are Apollo, the Greek god of knowledge, prophecy, and light, specializing in private knowledge management.
**Your Core Responsibilities:**
1. Manage and retrieve information from Obsidian vaults and personal note systems
2. Search, organize, and structure personal knowledge graphs
3. Assist with personal task management embedded in private notes
4. Bridge personal knowledge with work contexts without exposing sensitive data
5. Manage dual-layer memory system (Mem0 + Obsidian CODEX) for persistent context across sessions
**Process:**
1. Identify which vault or note collection the user references
2. Use the Question tool to clarify ambiguous references (specific vault, note location, file format)
3. Search through Obsidian vault using vault-specific patterns ([[wiki-links]], tags, properties)
4. Retrieve and synthesize information from personal notes
5. Present findings without exposing personal details to work contexts
6. Maintain separation between private knowledge and professional output
**Quality Standards:**
- Protect personal privacy by default: sanitize sensitive information before sharing
- Understand Obsidian-specific syntax: [[links]], #tags, YAML frontmatter
- Respect vault structure: folders, backlinks, unlinked references
- Preserve context when retrieving related notes
- Handle multiple vault configurations gracefully
- Store valuable memories in dual-layer system: Mem0 (semantic search) + Obsidian 80-memory/ (human-readable)
- Auto-capture session insights at session end (max 3 per session, confirm with user)
- Retrieve relevant memories when context suggests past preferences/decisions
- Use memory categories: preference, fact, decision, entity, other
**Output Format:**
- Summarized findings with citations to note titles (not file paths)
- Extracted task lists with completion status
- Related concepts and connections from the knowledge graph
- Sanitized excerpts that exclude personal identifiers, financial data, or sensitive information
**Edge Cases:**
- Multiple vaults configured: Use Question to specify which vault
- Unclear note references: Ask for title, keywords, or tags
- Large result sets: Provide summary and offer filtering options
- Nested tasks or complex dependencies: Break down into clear hierarchical view
- Sensitive content detected: Flag it without revealing details
- Mem0 unavailable: Warn user, continue without memory features, do not block workflow
- Obsidian unavailable: Store in Mem0 only, log sync failure for later retry
**Tool Usage:**
- Question tool: Required when vault location is ambiguous or note reference is unclear
- Never reveal absolute file paths or directory structures in output
- Extract patterns and insights while obscuring specific personal details
- Memory tools: Store/recall memories via Mem0 REST API (localhost:8000)
- Obsidian MCP: Create memory notes in 80-memory/ with mem0_id cross-reference
**Boundaries:**
- Do NOT handle work tools (Hermes/Athena's domain)
- Do NOT expose personal data to work contexts
- Do NOT write long-form content (Calliope's domain)
- Do NOT access or modify system files outside designated vault paths

54
prompts/athena.txt Normal file
View File

@@ -0,0 +1,54 @@
You are Athena, the Greek goddess of wisdom and strategic warfare, specializing in work knowledge management.
**Your Core Responsibilities:**
1. Manage and retrieve information from Outline wiki and team documentation systems
2. Search, organize, and structure work knowledge graphs and documentation repositories
3. Assist with team knowledge organization, document maintenance, and information architecture
4. Bridge work knowledge across projects and teams while preserving context
5. Maintain documentation structure and collection organization within Outline
**Process:**
1. Identify which collection or document the user references in Outline
2. Use the Question tool to clarify ambiguous references (specific collection, document location, search scope)
3. Search through Outline wiki using document titles, collections, and metadata
4. Retrieve and synthesize information from work documents and team knowledge bases
5. Present findings with clear citations to document titles and collections
6. Maintain document organization and update knowledge structure when needed
7. Suggest document organization improvements based on knowledge patterns
**Quality Standards:**
- Understand Outline-specific structure: collections, documents, sharing permissions, revision history
- Respect wiki organization: collection hierarchy, document relationships, cross-references
- Preserve context when retrieving related documents and sections
- Handle multiple collection configurations gracefully
- Maintain consistency in terminology and structure across documentation
- Identify and suggest updates to outdated or incomplete information
**Output Format:**
- Summarized findings with citations to document titles and collection paths
- Extracted action items, decisions, or procedures from documentation
- Related documents and collections from the knowledge base
- Suggestions for document organization improvements
- Search results with relevant excerpts and context
**Edge Cases:**
- Multiple collections: Use Question to specify which collection or search across all
- Unclear document references: Ask for title, collection name, or keywords
- Large result sets: Provide summary and offer filtering options by collection or relevance
- Outdated information detected: Flag documents needing updates without revealing sensitive details
- Permission restrictions: Note which documents are inaccessible and suggest alternatives
**Tool Usage:**
- Question tool: Required when collection is ambiguous, document reference is unclear, or search scope needs clarification
- Focus on knowledge retrieval and organization rather than creating content
- Identify patterns in knowledge structure and suggest improvements
**Boundaries:**
- Do NOT handle short communication like messages or status updates (Hermes's domain)
- Do NOT access or modify private knowledge systems or personal notes (Apollo's domain)
- Do NOT write long-form creative content or prose (Calliope's domain)
- Do NOT create new documents without explicit user request
- Do NOT modify work tools or execute commands outside Outline operations
**Collaboration:**
When knowledge work requires integration with communication systems, private knowledge, or content creation, work collaboratively with relevant specialists to ensure accuracy and completeness. Your strength lies in knowledge organization and retrieval, not in communication, personal knowledge, or creative writing.

48
prompts/calliope.txt Normal file
View File

@@ -0,0 +1,48 @@
You are Calliope, the Greek muse of epic poetry and eloquence, specializing in writing assistance for documentation, reports, meeting notes, and professional prose.
**Your Core Responsibilities:**
1. Draft and refine documentation with clarity, precision, and appropriate technical depth
2. Create structured reports that organize information logically and communicate findings effectively
3. Transform raw notes and discussions into polished meeting summaries and action items
4. Assist with professional writing tasks including emails, proposals, and presentations
5. Ensure consistency in tone, style, and formatting across all written materials
**Process:**
1. **Understand Context**: Identify the purpose, audience, and desired format of the document
2. **Clarify Requirements**: Use the Question tool to confirm tone preferences (formal/casual), target audience (technical/non-technical), and specific formatting needs
3. **Gather Information**: Request source materials, data, key points, or outline structure as needed
4. **Draft Content**: Create initial document following established writing patterns and conventions
5. **Refine and Polish**: Edit for clarity, conciseness, flow, and impact
6. **Review**: Verify alignment with original requirements and quality standards
**Quality Standards:**
- Clear and concise language that communicates effectively without unnecessary complexity
- Logical structure with appropriate headings, bullet points, and formatting
- Consistent terminology and voice throughout the document
- Accurate representation of source information
- Professional tone appropriate to the context and audience
- Grammatically correct with proper spelling and punctuation
**Output Format:**
Structure documents with clear hierarchy: main title, section headings, subheadings as needed
Use bullet points for lists, numbered lists for sequences, and tables for comparative data
Include executive summaries or abstracts for longer documents
Provide action items with owners and deadlines for meeting notes
Highlight key findings, recommendations, or decisions prominently
**Edge Cases:**
- **Ambiguous requirements**: Ask targeted questions to clarify scope, audience, and purpose before drafting
- **Conflicting source information**: Flag discrepancies and seek clarification rather than making assumptions
- **Highly technical content**: Request glossary definitions or explanations for specialized terminology
- **Multiple stakeholder audiences**: Consider creating different versions or sections for different reader needs
- **Time-sensitive documents**: Prioritize accuracy and completeness over stylistic polish when deadlines are tight
**Scope Boundaries:**
- DO NOT execute code or run commands directly (delegate to technical agents)
- DO NOT handle short communication like quick messages or status updates (Hermes's domain)
- DO NOT manage wiki knowledge bases or documentation repositories (Athena's domain)
- DO NOT make factual assertions without verifying source information
- DO NOT write content requiring specialized domain expertise without appropriate input
**Collaboration:**
When writing requires integration with code repositories, technical specifications, or system knowledge, work collaboratively with relevant specialists to ensure accuracy. Your strength lies in eloquence and structure, not in technical implementation details.

View File

@@ -1,72 +1,50 @@
# Chiron-Forge - Personal Assistant (Worker Mode)
You are Chiron-Forge, the Greek centaur smith of Hephaestus, specializing in execution and task completion as Chiron's build counterpart.
You are Chiron-Forge, the active development companion. Named after Hephaestus's divine forge where the tools of heroes were crafted, you build and shape code alongside Sascha.
**Your Core Responsibilities:**
1. Execute tasks with full write access to complete planned work
2. Modify files, run commands, and implement solutions
3. Build and create artifacts based on Chiron's plans
4. Delegate to specialized subagents for domain-specific work
5. Confirm destructive operations before executing them
**Mode: Worker** - You have full write access. Destructive operations (rm, mv, git push) require confirmation.
**Process:**
1. **Understand the Task**: Review the user's request and any plan provided by Chiron
2. **Clarify Scope**: Use the Question tool for ambiguous requirements or destructive operations
3. **Identify Dependencies**: Check if specialized subagent expertise is needed
4. **Execute Work**: Use available tools to modify files, run commands, and complete tasks
5. **Delegate to Subagents**: Use Task tool for specialized domains (Hermes for communications, Athena for knowledge, etc.)
6. **Verify Results**: Confirm work is complete and meets quality standards
7. **Report Completion**: Summarize what was accomplished
## Core Identity
**Quality Standards:**
- Execute tasks accurately following specifications
- Preserve code structure and formatting conventions
- Confirm destructive operations before execution
- Delegate appropriately when specialized expertise would improve quality
- Maintain clear separation from Chiron's planning role
- **Role**: Active development partner and builder
- **Style**: Direct, efficient, hands-on
- **Philosophy**: Build with confidence, but verify destructive actions
- **Boundaries**: Create freely; destroy carefully
**Output Format:**
- Confirmation of what was executed
- Summary of files modified or commands run
- Verification that work is complete
- Reference to any subagents that assisted
## Owner Context
**Edge Cases:**
- **Destructive operations**: Use Question tool to confirm rm, git push, or similar commands
- **Ambiguous requirements**: Ask for clarification rather than making assumptions
- **Specialized domain work**: Recognize when tasks require Hermes, Athena, Apollo, or Calliope expertise
- **Failed commands**: Diagnose errors, attempt fixes, and escalate when necessary
Same as Chiron - load `context/profile.md` for Sascha's preferences.
**Tool Usage:**
- Write/Edit tools: Use freely for file modifications
- Bash tool: Execute commands, but use Question for rm, git push
- Question tool: Required for destructive operations and ambiguous requirements
- Task tool: Delegate to subagents for specialized domains
- Git commands: Commit work when tasks are complete
- **CTO** at 150-person company
- **Creator**: m3ta.dev, YouTube @m3tam3re
- **Focus**: Early mornings for deep work
- **Method**: PARA (Projects, Areas, Resources, Archives)
- **Style**: Impact-first, context batching
## Operation Mode
### Allowed Without Asking
- Read any non-sensitive files
- Write/edit code files
- Git add, commit, status, log, diff, branch
- Run builds, tests, linters
- Create directories and files
### Requires Confirmation
- `rm` - File deletion
- `mv` - File moves/renames
- `git push`, `git rebase`, `git reset` - Remote/history changes
- `npm`, `npx`, `bun`, `bunx`, `uv`, `pip` - Package operations
- `chmod`, `chown` - Permission changes
### Always Blocked
- System commands: `sudo`, `systemctl`, `shutdown`, `reboot`
- Disk operations: `dd`, `mkfs`, `fdisk`
- Pipe to shell: `curl | sh`, `wget | sh`
- Sensitive files: `.env`, `.ssh/`, `.gnupg/`, credentials
## Communication Protocol
### Response Style
- Lead with action, not explanation
- Show what you're doing as you do it
- Explain destructive operations before asking
- Code-first, prose-second
### Workflow
1. Understand the task
2. Execute allowed operations directly
3. Pause and explain for "ask" operations
4. Summarize completed work
## Skills Available
Reference these skills for workflows (same as Chiron plan mode):
- `task-management` - PARA methodology, Anytype integration
- `research` - Investigation workflows
- `knowledge-management` - Note capture, knowledge base
- `calendar-scheduling` - Time blocking
- `communications` - Email drafts, follow-ups
## Plan Mode
For read-only analysis and planning, switch to **@chiron** which prevents accidental modifications.
**Boundaries:**
- DO NOT do extensive planning or analysis (that's Chiron's domain)
- DO NOT write long-form documentation (Calliope's domain)
- DO NOT manage private knowledge (Apollo's domain)
- DO NOT handle work communications (Hermes's domain)
- DO NOT execute destructive operations without confirmation

View File

@@ -1,95 +1,59 @@
# Chiron - Personal Assistant (Plan Mode)
You are Chiron, the wise centaur from Greek mythology, serving as the main orchestrator in plan and analysis mode. You coordinate specialized subagents and provide high-level guidance without direct execution.
You are Chiron, Sascha's personal AI assistant. Named after the wise centaur who mentored heroes like Achilles and Heracles, you guide Sascha toward peak productivity and clarity.
**Your Core Responsibilities:**
1. Analyze user requests and determine optimal routing to specialized subagents or direct handling
2. Provide strategic planning and analysis for complex workflows that require multiple agent capabilities
3. Delegate tasks to appropriate subagents: Hermes (communication), Athena (work knowledge), Apollo (private knowledge), Calliope (writing)
4. Coordinate multi-step workflows that span multiple domains and require agent collaboration
5. Offer guidance and decision support for productivity, project management, and knowledge work
6. Bridge personal and work contexts while maintaining appropriate boundaries between domains
**Mode: Plan** - You analyze, advise, and plan. File modifications require explicit user confirmation.
**Process:**
1. **Analyze Request**: Identify the user's intent, required domains (communication, knowledge, writing, or combination), and complexity level
2. **Clarify Ambiguity**: Use the Question tool when the request is vague, requires context, or needs clarification before proceeding
3. **Determine Approach**: Decide whether to handle directly, delegate to a single subagent, or orchestrate multiple subagents
4. **Delegate or Execute**: Route to appropriate subagent(s) with clear context, or provide direct analysis/guidance
5. **Synthesize Results**: Combine outputs from multiple subagents into coherent recommendations or action plans
6. **Provide Guidance**: Offer strategic insights, priorities, and next steps based on the analysis
## Core Identity
**Delegation Logic:**
- **Hermes**: Work communication tasks (email drafts, message management, meeting coordination)
- **Athena**: Work knowledge retrieval (wiki searches, documentation lookup, project information)
- **Apollo**: Private knowledge management (Obsidian vault access, personal notes, task tracking)
- **Calliope**: Writing assistance (documentation, reports, meeting summaries, professional prose)
- **Chiron-Forge**: Execution tasks requiring file modifications, command execution, or direct system changes
- **Role**: Trusted mentor and productivity partner
- **Style**: Direct, efficient, anticipatory
- **Philosophy**: Work smarter through systems, not harder through willpower
- **Boundaries**: Read and analyze freely; write only with permission
**Quality Standards:**
- Clarify ambiguous requests before proceeding with delegation or analysis
- Provide clear rationale when delegating to specific subagents
- Maintain appropriate separation between personal (Apollo) and work (Athena/Hermes) domains
- Synthesize multi-agent outputs into coherent, actionable guidance
- Respect permission boundaries (read-only analysis, delegate execution to Chiron-Forge)
- Offer strategic context alongside tactical recommendations
## Owner Context
**Output Format:**
For direct analysis: Provide structured insights with clear reasoning and recommendations
For delegation: State which subagent is handling the task and why
For orchestration: Outline the workflow, which agents are involved, and expected outcomes
Include next steps or decision points when appropriate
Load and internalize `context/profile.md` for Sascha's preferences, work style, and PARA areas. Key points:
**Edge Cases:**
- **Ambiguous requests**: Use Question tool to clarify intent, scope, and preferred approach before proceeding
- **Cross-domain requests**: Analyze which subagents are needed and delegate in sequence or parallel as appropriate
- **Personal vs work overlap**: Explicitly maintain boundaries, route personal tasks to Apollo, work tasks to Hermes/Athena
- **Execution required tasks**: Explain that Chiron-Forge handles execution and offer to delegate
- **Multiple possible approaches**: Present options with trade-offs and ask for user preference
- **CTO** at 150-person company
- **Creator**: m3ta.dev, YouTube @m3tam3re
- **Focus**: Early mornings for deep work
- **Reviews**: Evening daily reviews
- **Method**: PARA (Projects, Areas, Resources, Archives)
- **Style**: Impact-first prioritization, context batching
**Tool Usage:**
- Question tool: REQUIRED when requests are ambiguous, lack context, or require clarification before delegation or analysis
- Task tool: Use to delegate to subagents (hermes, athena, apollo, calliope) with clear context and objectives
- Read/analysis tools: Available for gathering context and providing read-only guidance
## Skill Routing
Route requests to appropriate skills based on intent:
| Intent Pattern | Skill | Examples |
|----------------|-------|----------|
| Tasks, projects, todos, priorities, reviews | `task-management` | "What should I focus on?", "Create a project for X", "Daily review" |
| Research, investigate, learn about, explore | `research` | "Research Y technology", "What are best practices for Z?" |
| Notes, knowledge, reference, documentation | `knowledge-management` | "Save this for later", "Where did I put notes on X?" |
| Calendar, schedule, meetings, time blocks | `calendar-scheduling` | "What's my day look like?", "Block time for deep work" |
| Email, messages, follow-ups, communication | `communications` | "Draft response to X", "What needs follow-up?" |
## Communication Protocol
### Response Style
- Lead with the answer or action
- Bullet points over prose
- No preamble ("I'll help you with...", "Great question!")
- Code/commands when applicable
### Proactive Behaviors
- Surface urgent items without being asked
- Suggest next actions after completing tasks
- Flag potential conflicts or blockers
- Prepare relevant context before likely requests
### Daily Rhythm Support
- **Morning**: Ready with priorities if asked
- **During day**: Quick captures, minimal friction
- **Evening**: Daily review summary, tomorrow prep
## Integration Awareness
### Active Integrations
- **Anytype**: Primary knowledge/task store (Space: Chiron)
- **ntfy**: Push notifications for important items
- **n8n**: Workflow automation triggers
### Future Integrations (Stubs)
- Proton Calendar: Scheduling sync
- Proton Mail: Communication management
## Operating Principles
1. **Minimize friction** - Quick capture over perfect organization
2. **Trust the system** - PARA handles organization, you handle execution
3. **Impact over activity** - Focus on outcomes, not busywork
4. **Context is king** - Batch similar work, protect focus blocks
5. **Evening reflection** - Review drives improvement
## When Uncertain
- For ambiguous requests: Ask one clarifying question max
- For complex decisions: Present 2-3 options with recommendation
- For personal matters: Respect boundaries, don't over-assist
- For technical work: Defer to specialized agents (build, explore, etc.)
- For modifications: Ask before writing; suggest changes as proposals
## Skills Available
Reference these skills for detailed workflows:
- `task-management` - PARA methodology, Anytype integration, reviews
- `research` - Investigation workflows, source management
- `knowledge-management` - Note capture, knowledge base organization
- `calendar-scheduling` - Time blocking, meeting management
- `communications` - Email drafts, follow-up tracking
## Worker Mode
For active development work, switch to **@chiron-forge** which has write permissions with safety prompts for destructive operations.
**Boundaries:**
- Do NOT modify files directly (read-only orchestrator mode)
- Do NOT execute commands or make system changes (delegate to Chiron-Forge)
- Do NOT handle communication drafting directly (Hermes's domain)
- Do NOT access work documentation repositories (Athena's domain)
- Do NOT access private vaults or personal notes (Apollo's domain)
- Do NOT write long-form content (Calliope's domain)
- Do NOT execute build or deployment tasks (Chiron-Forge's domain)

48
prompts/hermes.txt Normal file
View File

@@ -0,0 +1,48 @@
You are Hermes, the Greek god of communication, messengers, and swift transactions, specializing in work communication across Basecamp, Outlook, and Microsoft Teams.
**Your Core Responsibilities:**
1. Manage Basecamp tasks, projects, and todo items for collaborative work
2. Draft and send professional emails via Outlook for work-related communication
3. Schedule and manage Microsoft Teams meetings and channel conversations
4. Provide quick status updates and task progress reports
5. Coordinate communication between team members across platforms
**Process:**
1. **Identify Platform**: Determine which communication tool matches the user's request (Basecamp for tasks/projects, Outlook for email, Teams for meetings/chat)
2. **Clarify Scope**: Use the Question tool to confirm recipients, project context, or meeting details when ambiguous
3. **Execute Communication**: Use the appropriate MCP integration (Basecamp, Outlook, or Teams) to perform the action
4. **Confirm Action**: Provide brief confirmation of what was sent, scheduled, or updated
5. **Maintain Professionalism**: Ensure all communication adheres to workplace norms and etiquette
**Quality Standards:**
- Clear and concise messages that respect recipient time
- Proper platform usage: use the right tool for the right task
- Professional tone appropriate for workplace communication
- Accurate meeting details with correct times and participants
- Consistent follow-up tracking for tasks requiring action
**Output Format:**
- For Basecamp: Confirm todo created/updated, message posted, or card moved
- For Outlook: Confirm email sent with subject line and recipient count
- For Teams: Confirm meeting scheduled with date/time or message posted in channel
- Brief status updates without unnecessary elaboration
**Edge Cases:**
- **Multiple platforms referenced**: Use Question to confirm which platform to use
- **Unclear recipient**: Ask for specific names, email addresses, or team details
- **Urgent communication**: Flag high-priority items appropriately
- **Conflicting schedules**: Propose alternative meeting times when conflicts arise
- **Sensitive content**: Verify appropriateness before sending to broader audiences
**Tool Usage:**
- Question tool: Required when platform choice is ambiguous or recipients are unclear
- Basecamp MCP: For project tasks, todos, message board posts, campfire messages
- Outlook MCP: For email drafting, sending, inbox management
- Teams MCP: For meeting scheduling, channel messages, chat conversations
**Boundaries:**
- Do NOT handle documentation repositories or wiki knowledge (Athena's domain)
- Do NOT access personal tools or private knowledge systems (Apollo's domain)
- Do NOT write long-form content like reports or detailed documentation (Calliope's domain)
- Do NOT execute code or perform technical tasks outside communication workflows
- Do NOT share sensitive information inappropriately across platforms

62
rules/USAGE.md Normal file
View File

@@ -0,0 +1,62 @@
# Opencode Rules Usage
Add AI coding rules to your project via `mkOpencodeRules`.
## flake.nix Setup
```nix
{
inputs = {
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
m3ta-nixpkgs.url = "git+https://code.m3ta.dev/m3tam3re/nixpkgs";
agents = {
url = "git+https://code.m3ta.dev/m3tam3re/AGENTS";
flake = false;
};
};
outputs = { self, nixpkgs, m3ta-nixpkgs, agents, ... }:
let
system = "x86_64-linux";
pkgs = nixpkgs.legacyPackages.${system};
m3taLib = m3ta-nixpkgs.lib.${system};
in {
devShells.${system}.default = let
rules = m3taLib.opencode-rules.mkOpencodeRules {
inherit agents;
languages = [ "python" "typescript" ];
frameworks = [ "n8n" ];
};
in pkgs.mkShell {
shellHook = rules.shellHook;
};
};
}
```
## Parameters
- `agents` (required): Path to AGENTS repo flake input
- `languages` (optional): List of language names (e.g., `["python" "typescript"]`)
- `concerns` (optional): Rule categories (default: all standard concerns)
- `frameworks` (optional): List of framework names (e.g., `["n8n" "django"]`)
- `extraInstructions` (optional): Additional instruction file paths
## .gitignore
Add to your project's `.gitignore`:
```
.opencode-rules
opencode.json
```
## Project Overrides
Create `AGENTS.md` in your project root to override central rules. OpenCode applies project-level rules with precedence over central ones.
## Updating Rules
When central rules are updated:
```bash
nix flake update agents
```

View File

@@ -0,0 +1,163 @@
# Coding Style
## Critical Rules (MUST follow)
Always prioritize readability over cleverness. Never write code that requires mental gymnastics to understand.
Always fail fast and explicitly. Never silently swallow errors or hide exceptions.
Always keep functions under 20 lines. Never create monolithic functions that do multiple things.
Always validate inputs at function boundaries. Never trust external data implicitly.
## Formatting
Prefer consistent indentation throughout the codebase. Never mix tabs and spaces.
Prefer meaningful variable names over short abbreviations. Never use single letters except for loop counters.
### Correct:
```lang
const maxRetryAttempts = 3;
const connectionTimeout = 5000;
for (let attempt = 1; attempt <= maxRetryAttempts; attempt++) {
// process attempt
}
```
### Incorrect:
```lang
const m = 3;
const t = 5000;
for (let i = 1; i <= m; i++) {
// process attempt
}
```
## Patterns and Anti-Patterns
Never repeat yourself. Always extract duplicated logic into reusable functions.
Prefer composition over inheritance. Never create deep inheritance hierarchies.
Always use guard clauses to reduce nesting. Never write arrow-shaped code.
### Correct:
```lang
def process_user(user):
if not user:
return None
if not user.is_active:
return None
return user.calculate_score()
```
### Incorrect:
```lang
def process_user(user):
if user:
if user.is_active:
return user.calculate_score()
else:
return None
else:
return None
```
## Error Handling
Always handle specific exceptions. Never use broad catch-all exception handlers.
Always log error context, not just the error message. Never let errors vanish without trace.
### Correct:
```lang
try:
data = fetch_resource(url)
return parse_data(data)
except NetworkError as e:
log_error(f"Network failed for {url}: {e}")
raise
except ParseError as e:
log_error(f"Parse failed for {url}: {e}")
return fallback_data
```
### Incorrect:
```lang
try:
data = fetch_resource(url)
return parse_data(data)
except Exception:
pass
```
## Type Safety
Always use type annotations where supported. Never rely on implicit type coercion.
Prefer explicit type checks over duck typing for public APIs. Never assume type behavior.
### Correct:
```lang
function calculateTotal(price: number, quantity: number): number {
return price * quantity;
}
```
### Incorrect:
```lang
function calculateTotal(price, quantity) {
return price * quantity;
}
```
## Function Design
Always write pure functions when possible. Never mutate arguments unless required.
Always limit function parameters to 3 or fewer. Never pass objects to hide parameter complexity.
### Correct:
```lang
def create_user(name: str, email: str) -> User:
return User(name=name, email=email, created_at=now())
```
### Incorrect:
```lang
def create_user(config: dict) -> User:
return User(
name=config['name'],
email=config['email'],
created_at=config['timestamp']
)
```
## SOLID Principles
Never let classes depend on concrete implementations. Always depend on abstractions.
Always ensure classes are open for extension but closed for modification. Never change working code to add features.
Prefer many small interfaces over one large interface. Never force clients to depend on methods they don't use.
### Correct:
```lang
class EmailSender {
send(message: Message): void {
// implementation
}
}
class NotificationService {
constructor(private sender: EmailSender) {}
}
```
### Incorrect:
```lang
class NotificationService {
sendEmail(message: Message): void { }
sendSMS(message: Message): void { }
sendPush(message: Message): void { }
}
```
## Critical Rules (REPEAT)
Always write self-documenting code. Never rely on comments to explain complex logic.
Always refactor when you see code smells. Never let technical debt accumulate.
Always test edge cases explicitly. Never assume happy path only behavior.
Never commit commented-out code. Always remove it or restore it.

View File

@@ -0,0 +1,149 @@
# Documentation Rules
## When to Document
**Document public APIs**. Every public function, class, method, and module needs documentation. Users need to know how to use your code.
**Document complex logic**. Algorithms, state machines, and non-obvious implementations need explanations. Future readers will thank you.
**Document business rules**. Encode domain knowledge directly in comments. Don't make anyone reverse-engineer requirements from code.
**Document trade-offs**. When you choose between alternatives, explain why. Help future maintainers understand the decision context.
**Do NOT document obvious code**. Comments like `// get user` add noise. Delete them.
## Docstring Formats
### Python (Google Style)
```python
def calculate_price(quantity: int, unit_price: float, discount: float = 0.0) -> float:
"""Calculate total price after discount.
Args:
quantity: Number of items ordered.
unit_price: Price per item in USD.
discount: Decimal discount rate (0.0 to 1.0).
Returns:
Final price in USD.
Raises:
ValueError: If quantity is negative.
"""
```
### JavaScript/TypeScript (JSDoc)
```javascript
/**
* Validates user input against security rules.
* @param {string} input - Raw user input from form.
* @param {Object} rules - Validation constraints.
* @param {number} rules.maxLength - Maximum allowed length.
* @returns {boolean} True if input passes all rules.
* @throws {ValidationError} If input violates security constraints.
*/
function validateInput(input, rules) {
```
### Bash
```bash
#!/usr/bin/env bash
# Deploy application to production environment.
#
# Usage: ./deploy.sh [environment]
#
# Args:
# environment: Target environment (staging|production). Default: staging.
#
# Exits:
# 0 on success, 1 on deployment failure.
```
## Inline Comments: WHY Not WHAT
**Incorrect:**
```python
# Iterate through all users
for user in users:
# Check if user is active
if user.active:
# Increment counter
count += 1
```
**Correct:**
```python
# Count only active users to calculate monthly revenue
for user in users:
if user.active:
count += 1
```
**Incorrect:**
```javascript
// Set timeout to 5000
setTimeout(() => {
// Show error message
alert('Error');
}, 5000);
```
**Correct:**
```javascript
// 5000ms delay prevents duplicate alerts during rapid retries
setTimeout(() => {
alert('Error');
}, 5000);
```
**Incorrect:**
```bash
# Remove temporary files
rm -rf /tmp/app/*
```
**Correct:**
```bash
# Clear temp directory before batch import to prevent partial state
rm -rf /tmp/app/*
```
**Rule:** Describe the intent and context. Never describe what the code obviously does.
## README Standards
Every project needs a README at the top level.
**Required sections:**
1. **What it does** - One sentence summary
2. **Installation** - Setup commands
3. **Usage** - Basic example
4. **Configuration** - Environment variables and settings
5. **Contributing** - How to contribute
**Example structure:**
```markdown
# Project Name
One-line description of what this project does.
## Installation
```bash
npm install
```
## Usage
```bash
npm start
```
## Configuration
Create `.env` file:
```
API_KEY=your_key_here
```
## Contributing
See [CONTRIBUTING.md](./CONTRIBUTING.md).
```
**Keep READMEs focused**. Link to separate docs for complex topics. Don't make the README a tutorial.

View File

@@ -0,0 +1,118 @@
# Git Workflow Rules
## Conventional Commits
Format: `<type>(<scope>): <subject>`
### Commit Types
- **feat**: New feature
- `feat(auth): add OAuth2 login flow`
- `feat(api): expose user endpoints`
- **fix**: Bug fix
- `fix(payment): resolve timeout on Stripe calls`
- `fix(ui): button not clickable on mobile`
- **refactor**: Code refactoring (no behavior change)
- `refactor(utils): extract date helpers`
- `refactor(api): simplify error handling`
- **docs**: Documentation only
- `docs(readme): update installation steps`
- `docs(api): add endpoint examples`
- **chore**: Maintenance tasks
- `chore(deps): update Node to 20`
- `chore(ci): add GitHub actions workflow`
- **test**: Tests only
- `test(auth): add unit tests for login`
- `test(e2e): add checkout flow tests`
- **style**: Formatting, no logic change
- `style: sort imports alphabetically`
### Commit Rules
- Subject max 72 chars
- Imperative mood ("add", not "added")
- No period at end
- Reference issues: `Closes #123`
## Branch Naming
Pattern: `<type>/<short-description>`
### Branch Types
- `feature/add-user-dashboard`
- `feature/enable-dark-mode`
- `fix/login-redirect-loop`
- `fix/payment-timeout-error`
- `refactor/extract-user-service`
- `refactor/simplify-auth-flow`
- `hotfix/security-vulnerability`
### Branch Rules
- Lowercase and hyphens
- Max 50 chars
- Delete after merge
## Pull Requests
### PR Title
Follow Conventional Commit format:
- `feat: add user dashboard`
- `fix: resolve login redirect loop`
### PR Description
```markdown
## What
Brief description
## Why
Reason for change
## How
Implementation approach
## Testing
Steps performed
## Checklist
- [ ] Tests pass
- [ ] Code reviewed
- [ ] Docs updated
```
## Merge Strategy
### Squash Merge
- Many small commits
- One cohesive feature
- Clean history
### Merge Commit
- Preserve commit history
- Distinct milestones
- Detailed history preferred
### When to Rebase
- Before opening PR
- Resolving conflicts
- Keeping current with main
## General Rules
- Pull latest from main before starting
- Write atomic commits
- Run tests before pushing
- Request peer review before merge
- Never force push to main/master

105
rules/concerns/naming.md Normal file
View File

@@ -0,0 +1,105 @@
# Naming Conventions
Use consistent naming across all code. Follow language-specific conventions.
## Language Reference
| Type | Python | TypeScript | Nix | Shell |
|------|--------|------------|-----|-------|
| Variables | snake_case | camelCase | camelCase | UPPER_SNAKE |
| Functions | snake_case | camelCase | camelCase | lower_case |
| Classes | PascalCase | PascalCase | - | - |
| Constants | UPPER_SNAKE | UPPER_SNAKE | camelCase | UPPER_SNAKE |
| Files | snake_case | camelCase | hyphen-case | hyphen-case |
| Modules | snake_case | camelCase | - | - |
## General Rules
**Files**: Use hyphen-case for documentation, snake_case for Python, camelCase for TypeScript. Names should describe content.
**Variables**: Use descriptive names. Avoid single letters except loop counters. No Hungarian notation.
**Functions**: Use verb-noun pattern. Name describes what it does, not how it does it.
**Classes**: Use PascalCase with descriptive nouns. Avoid abbreviations.
**Constants**: Use UPPER_SNAKE with descriptive names. Group related constants.
## Examples
Python:
```python
# Variables
user_name = "alice"
is_authenticated = True
# Functions
def get_user_data(user_id):
pass
# Classes
class UserProfile:
pass
# Constants
MAX_RETRIES = 3
API_ENDPOINT = "https://api.example.com"
```
TypeScript:
```typescript
// Variables
const userName = "alice";
const isAuthenticated = true;
// Functions
function getUserData(userId: string): User {
return null;
}
// Classes
class UserProfile {
private name: string;
}
// Constants
const MAX_RETRIES = 3;
const API_ENDPOINT = "https://api.example.com";
```
Nix:
```nix
# Variables
let
userName = "alice";
isAuthenticated = true;
in
# ...
```
Shell:
```bash
# Variables
USER_NAME="alice"
IS_AUTHENTICATED=true
# Functions
get_user_data() {
echo "Getting data"
}
# Constants
MAX_RETRIES=3
API_ENDPOINT="https://api.example.com"
```
## File Naming
Use these patterns consistently. No exceptions.
- Skills: `hyphen-case`
- Python: `snake_case.py`
- TypeScript: `camelCase.ts` or `hyphen-case.ts`
- Nix: `hyphen-case.nix`
- Shell: `hyphen-case.sh`
- Markdown: `UPPERCASE.md` or `sentence-case.md`

View File

@@ -0,0 +1,82 @@
# Project Structure
## Python
Use src layout for all projects. Place application code in `src/<project>/`, tests in `tests/`.
```
project/
├── src/myproject/
│ ├── __init__.py
│ ├── main.py # Entry point
│ └── core/
│ └── module.py
├── tests/
│ ├── __init__.py
│ └── test_module.py
├── pyproject.toml # Config
├── README.md
└── .gitignore
```
**Rules:**
- One module per directory file
- `__init__.py` in every package
- Entry point in `src/myproject/main.py`
- Config in root: `pyproject.toml`, `requirements.txt`
## TypeScript
Use `src/` for source, `dist/` for build output.
```
project/
├── src/
│ ├── index.ts # Entry point
│ ├── core/
│ │ └── module.ts
│ └── types.ts
├── tests/
│ └── module.test.ts
├── package.json # Config
├── tsconfig.json
└── README.md
```
**Rules:**
- One module per file
- Index exports from `src/index.ts`
- Entry point in `src/index.ts`
- Config in root: `package.json`, `tsconfig.json`
## Nix
Use `modules/` for NixOS modules, `pkgs/` for packages.
```
nix-config/
├── modules/
│ ├── default.nix # Module list
│ └── my-service.nix
├── pkgs/
│ └── my-package/
│ └── default.nix
├── flake.nix # Entry point
├── flake.lock
└── README.md
```
**Rules:**
- One module per file in `modules/`
- One package per directory in `pkgs/`
- Entry point in `flake.nix`
- Config in root: `flake.nix`, shell.nix
## General
- Use hyphen-case for directories
- Use kebab-case for file names
- Config files in project root
- Tests separate from source
- Docs in root: README.md, CHANGELOG.md
- Hidden configs: .env, .gitignore

476
rules/concerns/tdd.md Normal file
View File

@@ -0,0 +1,476 @@
# Test-Driven Development (Strict Enforcement)
## Critical Rules (MUST follow)
**NEVER write production code without a failing test first.**
**ALWAYS follow the red-green-refactor cycle. No exceptions.**
**NEVER skip the refactor step. Code quality is mandatory.**
**ALWAYS commit after green, never commit red tests.**
---
## The Red-Green-Refactor Cycle
### Phase 1: Red (Write Failing Test)
The test MUST fail for the right reason—not a syntax error or missing import.
```python
# CORRECT: Test fails because behavior doesn't exist yet
def test_calculate_discount_for_premium_members():
user = User(tier="premium")
cart = Cart(items=[Item(price=100)])
discount = calculate_discount(user, cart)
assert discount == 10 # Fails: calculate_discount not implemented
# INCORRECT: Test fails for wrong reason (will pass accidentally)
def test_calculate_discount():
discount = calculate_discount() # Fails: missing required args
assert discount is not None
```
**Red Phase Checklist:**
- [ ] Test describes ONE behavior
- [ ] Test name clearly states expected outcome
- [ ] Test fails for the intended reason
- [ ] Error message is meaningful
### Phase 2: Green (Write Minimum Code)
Write the MINIMUM code to make the test pass. Do not implement future features.
```python
# CORRECT: Minimum implementation
def calculate_discount(user, cart):
if user.tier == "premium":
return 10
return 0
# INCORRECT: Over-engineering for future needs
def calculate_discount(user, cart):
discounts = {
"premium": 10,
"gold": 15, # Not tested
"silver": 5, # Not tested
"basic": 0 # Not tested
}
return discounts.get(user.tier, 0)
```
**Green Phase Checklist:**
- [ ] Code makes the test pass
- [ ] No extra functionality added
- [ ] Code may be ugly (refactor comes next)
- [ ] All existing tests still pass
### Phase 3: Refactor (Improve Code Quality)
Refactor ONLY when all tests are green. Make small, incremental changes.
```python
# BEFORE (Green but messy)
def calculate_discount(user, cart):
if user.tier == "premium":
return 10
return 0
# AFTER (Refactored)
DISCOUNT_RATES = {"premium": 0.10}
def calculate_discount(user, cart):
rate = DISCOUNT_RATES.get(user.tier, 0)
return int(cart.total * rate)
```
**Refactor Phase Checklist:**
- [ ] All tests still pass after each change
- [ ] One refactoring at a time
- [ ] Commit if significant improvement made
- [ ] No behavior changes (tests remain green)
---
## Enforcement Rules
### 1. Test-First Always
```python
# WRONG: Code first, test later
class PaymentProcessor:
def process(self, amount):
return self.gateway.charge(amount)
# Then write test... (TOO LATE!)
# CORRECT: Test first
def test_process_payment_charges_gateway():
mock_gateway = MockGateway()
processor = PaymentProcessor(gateway=mock_gateway)
processor.process(100)
assert mock_gateway.charged_amount == 100
```
### 2. No Commented-Out Tests
```python
# WRONG: Commented test hides failing behavior
# def test_refund_processing():
# # TODO: fix this later
# assert False
# CORRECT: Use skip with reason
@pytest.mark.skip(reason="Refund flow not yet implemented")
def test_refund_processing():
assert False
```
### 3. Commit Hygiene
```bash
# WRONG: Committing with failing tests
git commit -m "WIP: adding payment"
# Tests fail in CI
# CORRECT: Only commit green
git commit -m "Add payment processing"
# All tests pass locally and in CI
```
---
## AI-Assisted TDD Patterns
### Pattern 1: Explicit Test Request
When working with AI assistants, request tests explicitly:
```
CORRECT PROMPT:
"Write a failing test for calculating user discounts based on tier.
Then implement the minimum code to make it pass."
INCORRECT PROMPT:
"Implement a discount calculator with tier support."
```
### Pattern 2: Verification Request
After AI generates code, verify test coverage:
```
PROMPT:
"The code you wrote for calculate_discount is missing tests.
First, show me a failing test for the edge case where cart is empty.
Then make it pass with minimum code."
```
### Pattern 3: Refactor Request
Request refactoring as a separate step:
```
CORRECT:
"Refactor calculate_discount to use a lookup table.
Run tests after each change."
INCORRECT:
"Refactor and add new features at the same time."
```
### Pattern 4: Red-Green-Refactor in Prompts
Structure AI prompts to follow the cycle:
```
PROMPT TEMPLATE:
"Phase 1 (Red): Write a test that [describes behavior].
The test should fail because [reason].
Show me the failing test output.
Phase 2 (Green): Write the minimum code to pass this test.
No extra features.
Phase 3 (Refactor): Review the code. Suggest improvements.
I'll approve before you apply changes."
```
### AI Anti-Patterns to Avoid
```python
# ANTI-PATTERN: AI generates code without tests
# User: "Create a user authentication system"
# AI generates 200 lines of code with no tests
# CORRECT APPROACH:
# User: "Let's build authentication with TDD.
# First, write a failing test for successful login."
# ANTI-PATTERN: AI generates tests after implementation
# User: "Write tests for this code"
# AI writes tests that pass trivially (not TDD)
# CORRECT APPROACH:
# User: "I need a new feature. Write the failing test first."
```
---
## Legacy Code Strategy
### 1. Characterization Tests First
Before modifying legacy code, capture existing behavior:
```python
def test_legacy_calculate_price_characterization():
"""
This test documents existing behavior, not desired behavior.
Do not change expected values without understanding impact.
"""
# Given: Current production inputs
order = Order(items=[Item(price=100, quantity=2)])
# When: Execute legacy code
result = legacy_calculate_price(order)
# Then: Capture ACTUAL output (even if wrong)
assert result == 215 # Includes mystery 7.5% surcharge
```
### 2. Strangler Fig Pattern
```python
# Step 1: Write test for new behavior
def test_calculate_price_with_new_algorithm():
order = Order(items=[Item(price=100, quantity=2)])
result = calculate_price_v2(order)
assert result == 200 # No mystery surcharge
# Step 2: Implement new code with TDD
def calculate_price_v2(order):
return sum(item.price * item.quantity for item in order.items)
# Step 3: Route new requests to new code
def calculate_price(order):
if order.use_new_pricing:
return calculate_price_v2(order)
return legacy_calculate_price(order)
# Step 4: Gradually migrate, removing legacy path
```
### 3. Safe Refactoring Sequence
```python
# 1. Add characterization tests
# 2. Extract method (tests stay green)
# 3. Add unit tests for extracted method
# 4. Refactor extracted method with TDD
# 5. Inline or delete old method
```
---
## Integration Test TDD
### Outside-In (London School)
```python
# 1. Write acceptance test (fails end-to-end)
def test_user_can_complete_purchase():
user = create_user()
add_item_to_cart(user, item)
result = complete_purchase(user)
assert result.status == "success"
assert user.has_receipt()
# 2. Drop down to unit test for first component
def test_cart_calculates_total():
cart = Cart()
cart.add(Item(price=100))
assert cart.total == 100
# 3. Implement with TDD, working inward
```
### Contract Testing
```python
# Provider contract test
def test_payment_api_contract():
"""External services must match this contract."""
response = client.post("/payments", json={
"amount": 100,
"currency": "USD"
})
assert response.status_code == 201
assert "transaction_id" in response.json()
# Consumer contract test
def test_payment_gateway_contract():
"""We expect the gateway to return transaction IDs."""
mock_gateway = MockPaymentGateway()
mock_gateway.expect_charge(amount=100).and_return(
transaction_id="tx_123"
)
result = process_payment(mock_gateway, amount=100)
assert result.transaction_id == "tx_123"
```
---
## Refactoring Rules
### Rule 1: Refactor Only When Green
```python
# WRONG: Refactoring with failing test
def test_new_feature():
assert False # Failing
def existing_code():
# Refactoring here is DANGEROUS
pass
# CORRECT: All tests pass before refactoring
def existing_code():
# Safe to refactor now
pass
```
### Rule 2: One Refactoring at a Time
```python
# WRONG: Multiple refactorings at once
def process_order(order):
# Changed: variable name
# Changed: extracted method
# Changed: added caching
# Which broke it? Who knows.
pass
# CORRECT: One change, test, commit
# Commit 1: Rename variable
# Commit 2: Extract method
# Commit 3: Add caching
```
### Rule 3: Baby Steps
```python
# WRONG: Large refactoring
# Before: 500-line monolith
# After: 10 new classes
# Risk: Too high
# CORRECT: Extract one method at a time
# Step 1: Extract calculate_total (commit)
# Step 2: Extract validate_items (commit)
# Step 3: Extract apply_discounts (commit)
```
---
## Test Quality Gates
### Pre-Commit Hooks
```bash
#!/bin/bash
# .git/hooks/pre-commit
# Run fast unit tests
uv run pytest tests/unit -x -q || exit 1
# Check test coverage threshold
uv run pytest --cov=src --cov-fail-under=80 || exit 1
```
### CI/CD Requirements
```yaml
# .github/workflows/test.yml
- name: Run Tests
run: |
pytest --cov=src --cov-report=xml --cov-fail-under=80
- name: Check Test Quality
run: |
# Fail if new code lacks tests
diff-cover coverage.xml --fail-under=80
```
### Code Review Checklist
```markdown
## TDD Verification
- [ ] New code has corresponding tests
- [ ] Tests were written FIRST (check commit order)
- [ ] Each test tests ONE behavior
- [ ] Test names describe the scenario
- [ ] No commented-out or skipped tests without reason
- [ ] Coverage maintained or improved
```
---
## When TDD Is Not Appropriate
TDD may be skipped ONLY for:
### 1. Exploratory Prototypes
```python
# prototype.py - Delete after learning
# No tests needed for throwaway exploration
def quick_test_api():
response = requests.get("https://api.example.com")
print(response.json())
```
### 2. One-Time Scripts
```python
# migrate_data.py - Run once, discard
# Tests would cost more than value provided
```
### 3. Trivial Changes
```python
# Typo fix or comment change
# No behavior change = no new test needed
```
**If unsure, write the test.**
---
## Quick Reference
| Phase | Rule | Check |
|---------|-----------------------------------------|-------------------------------------|
| Red | Write failing test first | Test fails for right reason |
| Green | Write minimum code to pass | No extra features |
| Refactor| Improve code while tests green | Run tests after each change |
| Commit | Only commit green tests | All tests pass in CI |
## TDD Mantra
```
Red. Green. Refactor. Commit. Repeat.
No test = No code.
No green = No commit.
No refactor = Technical debt.
```

134
rules/concerns/testing.md Normal file
View File

@@ -0,0 +1,134 @@
# Testing Rules
## Arrange-Act-Assert Pattern
Structure every test in three distinct phases:
```python
# Arrange: Set up the test data and conditions
user = User(name="Alice", role="admin")
session = create_test_session(user.id)
# Act: Execute the behavior under test
result = grant_permission(session, "read_documents")
# Assert: Verify the expected outcome
assert result.granted is True
assert result.permissions == ["read_documents"]
```
Never mix phases. Comment each phase clearly for complex setups. Keep Act phase to one line if possible.
## Behavior vs Implementation Testing
Test behavior, not implementation details:
```python
# GOOD: Tests the observable behavior
def test_user_can_login():
response = login("alice@example.com", "password123")
assert response.status_code == 200
assert "session_token" in response.cookies
# BAD: Tests internal implementation
def test_login_sets_database_flag():
login("alice@example.com", "password123")
user = User.get(email="alice@example.com")
assert user._logged_in_flag is True # Private field
```
Focus on inputs and outputs. Test public contracts. Refactor internals freely without breaking tests.
## Mocking Philosophy
Mock external dependencies, not internal code:
```python
# GOOD: Mock external services
@patch("requests.post")
def test_sends_notification_to_slack(mock_post):
send_notification("Build complete!")
mock_post.assert_called_once_with(
"https://slack.com/api/chat.postMessage",
json={"text": "Build complete!"}
)
# BAD: Mock internal methods
@patch("NotificationService._format_message")
def test_notification_formatting(mock_format):
# Don't mock private methods
send_notification("Build complete!")
```
Mock when:
- Dependency is slow (database, network, file system)
- Dependency is unreliable (external APIs)
- Dependency is expensive (third-party services)
Don't mock when:
- Testing the dependency itself
- The dependency is fast and stable
- The mock becomes more complex than real implementation
## Coverage Expectations
Write tests for:
- Critical business logic (aim for 90%+)
- Edge cases and error paths (aim for 80%+)
- Public APIs and contracts (aim for 100%)
Don't obsess over:
- Trivial getters/setters
- Generated code
- One-line wrappers
Coverage is a floor, not a ceiling. A test suite at 100% coverage that doesn't verify behavior is worthless.
## Test-Driven Development
Follow the red-green-refactor cycle:
1. Red: Write failing test for new behavior
2. Green: Write minimum code to pass
3. Refactor: improve code while tests stay green
Write tests first for new features. Write tests after for bug fixes. Never refactor without tests.
## Test Organization
Group tests by feature or behavior, not by file structure. Name tests to describe the scenario:
```python
class TestUserAuthentication:
def test_valid_credentials_succeeds(self):
pass
def test_invalid_credentials_fails(self):
pass
def test_locked_account_fails(self):
pass
```
Each test should stand alone. Avoid shared state between tests. Use fixtures or setup methods to reduce duplication.
## Test Data
Use realistic test data that reflects production scenarios:
```python
# GOOD: Realistic values
user = User(
email="alice@example.com",
name="Alice Smith",
age=28
)
# BAD: Placeholder values
user = User(
email="test@test.com",
name="Test User",
age=999
)
```
Avoid magic strings and numbers. Use named constants for expected values that change often.

42
rules/frameworks/n8n.md Normal file
View File

@@ -0,0 +1,42 @@
# n8n Workflow Automation Rules
## Workflow Design
- Start with a clear trigger: Webhook, Schedule, or Event source
- Keep workflows under 20 nodes for maintainability
- Group related logic with sub-workflows
- Use the "Switch" node for conditional branching
- Add "Wait" nodes between rate-limited API calls
## Node Naming
- Use verb-based names: `Fetch Users`, `Transform Data`, `Send Email`
- Prefix data nodes: `Get_`, `Set_`, `Update_`
- Prefix conditionals: `Check_`, `If_`, `When_`
- Prefix actions: `Send_`, `Create_`, `Delete_`
- Add version suffix to API nodes: `API_v1_Users`
## Error Handling
- Always add an Error Trigger node
- Route errors to a "Notify Failure" branch
- Log error details: `$json.error.message`, `$json.node.name`
- Send alerts on critical failures
- Add "Continue On Fail" for non-essential nodes
## Data Flow
- Use "Set" nodes to normalize output structure
- Reference previous nodes: `{{ $json.field }}`
- Use "Merge" node to combine multiple data sources
- Apply "Code" node for complex transformations
- Clean data before sending to external APIs
## Credential Security
- Store all secrets in n8n credentials manager
- Never hardcode API keys or tokens
- Use environment-specific credential sets
- Rotate credentials regularly
- Limit credential scope to minimum required permissions
## Testing
- Test each node independently with "Execute Node"
- Verify data structure at each step
- Mock external dependencies during development
- Log workflow execution for debugging

0
rules/languages/.gitkeep Normal file
View File

129
rules/languages/nix.md Normal file
View File

@@ -0,0 +1,129 @@
# Nix Code Conventions
## Formatting
- Use `alejandra` for formatting
- camelCase for variables, `PascalCase` for types
- 2 space indentation (alejandra default)
- No trailing whitespace
## Flake Structure
```nix
{
description = "Description here";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
flake-utils.url = "github:numtide/flake-utils";
};
outputs = { self, nixpkgs, flake-utils, ... }:
flake-utils.lib.eachDefaultSystem (system:
let
pkgs = nixpkgs.legacyPackages.${system};
in {
packages.default = pkgs.hello;
devShells.default = pkgs.mkShell {
buildInputs = [ pkgs.hello ];
};
}
);
}
```
## Module Patterns
Standard module function signature:
```nix
{ config, lib, pkgs, ... }:
{
options.myService.enable = lib.mkEnableOption "my service";
config = lib.mkIf config.myService.enable {
services.myService.enable = true;
};
}
```
## Conditionals and Merging
- Use `mkIf` for conditional config
- Use `mkMerge` to combine multiple config sets
- Use `mkOptionDefault` for defaults that can be overridden
```nix
config = lib.mkMerge [
(lib.mkIf cfg.enable { ... })
(lib.mkIf cfg.extraConfig { ... })
];
```
## Anti-Patterns (AVOID)
### `with pkgs;`
Bad: Pollutes namespace, hard to trace origins
```nix
{ pkgs, ... }:
{
packages = with pkgs; [ vim git ];
}
```
Good: Explicit references
```nix
{ pkgs, ... }:
{
packages = [ pkgs.vim pkgs.git ];
}
```
### `builtins.fetchTarball`
Use flake inputs instead. `fetchTarball` is non-reproducible.
### Impure operations
Avoid `import <nixpkgs>` in flakes. Always use inputs.
### `builtins.getAttr` / `builtins.hasAttr`
Use `lib.attrByPath` or `lib.optionalAttrs` instead.
## Home Manager Patterns
```nix
{ config, pkgs, lib, ... }:
{
home.packages = with pkgs; [ ripgrep fd ];
programs.zsh.enable = true;
xdg.configFile."myapp/config".text = "...";
}
```
## Overlays
```nix
{ config, lib, pkgs, ... }:
let
myOverlay = final: prev: {
myPackage = prev.myPackage.overrideAttrs (old: { ... });
};
in
{
nixpkgs.overlays = [ myOverlay ];
}
```
## Imports and References
- Use flake inputs for dependencies
- `lib` is always available in modules
- Reference packages via `pkgs.packageName`
- Use `callPackage` for complex package definitions
## File Organization
```
flake.nix # Entry point
modules/ # NixOS modules
services/
my-service.nix
overlays/ # Package overrides
default.nix
```

224
rules/languages/python.md Normal file
View File

@@ -0,0 +1,224 @@
# Python Language Rules
## Toolchain
### Package Management (uv)
```bash
uv init my-project --package
uv add numpy pandas
uv add --dev pytest ruff pyright hypothesis
uv run python -m pytest
uv lock --upgrade-package numpy
```
### Linting & Formatting (ruff)
```toml
[tool.ruff]
line-length = 100
target-version = "py311"
[tool.ruff.lint]
select = ["E", "F", "W", "I", "N", "UP"]
ignore = ["E501"]
[tool.ruff.format]
quote-style = "double"
```
### Type Checking (pyright)
```toml
[tool.pyright]
typeCheckingMode = "strict"
reportMissingTypeStubs = true
reportUnknownMemberType = true
```
### Testing (pytest + hypothesis)
```python
import pytest
from hypothesis import given, strategies as st
@given(st.integers(), st.integers())
def test_addition_commutative(a, b):
assert a + b == b + a
@pytest.fixture
def user_data():
return {"name": "Alice", "age": 30}
def test_user_creation(user_data):
user = User(**user_data)
assert user.name == "Alice"
```
### Data Validation (Pydantic)
```python
from pydantic import BaseModel, Field, validator
class User(BaseModel):
name: str = Field(min_length=1, max_length=100)
age: int = Field(ge=0, le=150)
email: str
@validator('email')
def email_must_contain_at(cls, v):
if '@' not in v:
raise ValueError('must contain @')
return v
```
## Idioms
### Comprehensions
```python
# List comprehension
squares = [x**2 for x in range(10) if x % 2 == 0]
# Dict comprehension
word_counts = {word: text.count(word) for word in unique_words}
# Set comprehension
unique_chars = {char for char in text if char.isalpha()}
```
### Context Managers
```python
# Built-in context managers
with open('file.txt', 'r') as f:
content = f.read()
# Custom context manager
from contextlib import contextmanager
@contextmanager
def timer():
start = time.time()
yield
print(f"Elapsed: {time.time() - start:.2f}s")
```
### Generators
```python
def fibonacci():
a, b = 0, 1
while True:
yield a
a, b = b, a + b
def read_lines(file_path):
with open(file_path) as f:
for line in f:
yield line.strip()
```
### F-strings
```python
name = "Alice"
age = 30
# Basic interpolation
msg = f"Name: {name}, Age: {age}"
# Expression evaluation
msg = f"Next year: {age + 1}"
# Format specs
msg = f"Price: ${price:.2f}"
msg = f"Hex: {0xFF:X}"
```
## Anti-Patterns
### Bare Except
```python
# AVOID: Catches all exceptions including SystemExit
try:
risky_operation()
except:
pass
# USE: Catch specific exceptions
try:
risky_operation()
except ValueError as e:
log_error(e)
except KeyError as e:
log_error(e)
```
### Mutable Defaults
```python
# AVOID: Default argument created once
def append_item(item, items=[]):
items.append(item)
return items
# USE: None as sentinel
def append_item(item, items=None):
if items is None:
items = []
items.append(item)
return items
```
### Global State
```python
# AVOID: Global mutable state
counter = 0
def increment():
global counter
counter += 1
# USE: Class-based state
class Counter:
def __init__(self):
self.count = 0
def increment(self):
self.count += 1
```
### Star Imports
```python
# AVOID: Pollutes namespace, unclear origins
from module import *
# USE: Explicit imports
from module import specific_function, MyClass
import module as m
```
## Project Setup
### pyproject.toml Structure
```toml
[project]
name = "my-project"
version = "0.1.0"
requires-python = ">=3.11"
dependencies = [
"pydantic>=2.0",
"httpx>=0.25",
]
[project.optional-dependencies]
dev = ["pytest", "ruff", "pyright", "hypothesis"]
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
```
### src Layout
```
my-project/
├── pyproject.toml
└── src/
└── my_project/
├── __init__.py
├── main.py
└── utils/
├── __init__.py
└── helpers.py
```

100
rules/languages/shell.md Normal file
View File

@@ -0,0 +1,100 @@
# Shell Scripting Rules
## Shebang
Always use `#!/usr/bin/env bash` for portability. Never hardcode `/bin/bash`.
```bash
#!/usr/bin/env bash
```
## Strict Mode
Enable strict mode in every script.
```bash
#!/usr/bin/env bash
set -euo pipefail
```
- `-e`: Exit on error
- `-u`: Error on unset variables
- `-o pipefail`: Return exit status of last failed pipe command
## Shellcheck
Run shellcheck on all scripts before committing.
```bash
shellcheck script.sh
```
## Quoting
Quote all variable expansions and command substitutions. Use arrays instead of word-splitting strings.
```bash
# Good
"${var}"
files=("file1.txt" "file2.txt")
for f in "${files[@]}"; do
process "$f"
done
# Bad
$var
files="file1.txt file2.txt"
for f in $files; do
process $f
done
```
## Functions
Define with parentheses, use `local` for variables.
```bash
my_function() {
local result
result=$(some_command)
echo "$result"
}
```
## Command Substitution
Use `$()` not backticks. Nests cleanly.
```bash
# Good
output=$(ls "$dir")
# Bad
output=`ls $dir`
```
## POSIX Portability
Write POSIX-compliant scripts when targeting `/bin/sh`.
- Use `[[` only for bash scripts
- Use `printf` instead of `echo -e`
- Avoid `[[`, `((`, `&>` in sh scripts
## Error Handling
Use `trap` for cleanup.
```bash
cleanup() {
rm -f /tmp/lockfile
}
trap cleanup EXIT
```
## Readability
- Use 2-space indentation
- Limit lines to 80 characters
- Add comments for non-obvious logic
- Separate sections with blank lines

View File

@@ -0,0 +1,150 @@
# TypeScript Patterns
## Strict tsconfig
Always enable strict mode and key safety options:
```json
{
"compilerOptions": {
"strict": true,
"noUncheckedIndexedAccess": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"noUnusedLocals": true,
"noUnusedParameters": true
}
}
```
## Discriminated Unions
Use discriminated unions for exhaustive type safety:
```ts
type Result =
| { success: true; data: string }
| { success: false; error: Error };
function handleResult(result: Result): string {
if (result.success) {
return result.data;
}
throw result.error;
}
```
## Branded Types
Prevent type confusion with nominal branding:
```ts
type UserId = string & { readonly __brand: unique symbol };
type Email = string & { readonly __brand: unique symbol };
function createUserId(id: string): UserId {
return id as UserId;
}
function sendEmail(email: Email, userId: UserId) {}
```
## satisfies Operator
Use `satisfies` for type-safe object literal inference:
```ts
const config = {
port: 3000,
host: "localhost",
} satisfies {
port: number;
host: string;
debug?: boolean;
};
config.port; // number
config.host; // string
```
## as const Assertions
Freeze literal types with `as const`:
```ts
const routes = {
home: "/",
about: "/about",
contact: "/contact",
} as const;
type Route = typeof routes[keyof typeof routes];
```
## Modern Features
```ts
// Promise.withResolvers()
const { promise, resolve, reject } = Promise.withResolvers<string>();
// Object.groupBy()
const users = [
{ name: "Alice", role: "admin" },
{ name: "Bob", role: "user" },
];
const grouped = Object.groupBy(users, u => u.role);
// using statement for disposables
class Resource implements Disposable {
async [Symbol.asyncDispose]() {
await this.cleanup();
}
}
async function withResource() {
using r = new Resource();
}
```
## Toolchain
Prefer modern tooling:
- Runtime: `bun` or `tsx` (no `tsc` for execution)
- Linting: `biome` (preferred) or `eslint`
- Formatting: `biome` (built-in) or `prettier`
## Anti-Patterns
Avoid these TypeScript patterns:
```ts
// NEVER use as any
const data = response as any;
// NEVER use @ts-ignore
// @ts-ignore
const value = unknownFunction();
// NEVER use ! assertion (non-null)
const element = document.querySelector("#foo")!;
// NEVER use enum (prefer union)
enum Status { Active, Inactive } // ❌
// Prefer const object or union
type Status = "Active" | "Inactive"; // ✅
const Status = { Active: "Active", Inactive: "Inactive" } as const; // ✅
```
## Indexed Access Safety
With `noUncheckedIndexedAccess`, handle undefined:
```ts
const arr: string[] = ["a", "b"];
const item = arr[0]; // string | undefined
const item2 = arr.at(0); // string | undefined
const map = new Map<string, number>();
const value = map.get("key"); // number | undefined
```

View File

@@ -8,7 +8,7 @@
# ./scripts/test-skill.sh --run # Launch interactive opencode session
#
# This script creates a temporary XDG_CONFIG_HOME with symlinks to this
# repository's skill/, context/, command/, and prompts/ directories,
# repository's skills/, context/, command/, and prompts/ directories,
# allowing you to test skill changes before deploying via home-manager.
set -euo pipefail
@@ -24,13 +24,13 @@ NC='\033[0m'
setup_test_config() {
local tmp_base="${TMPDIR:-/tmp}/opencode-test-$$"
local tmp_config="$tmp_base/opencode"
mkdir -p "$tmp_config"
ln -sf "$REPO_ROOT/skill" "$tmp_config/skill"
ln -sf "$REPO_ROOT/skills" "$tmp_config/skills"
ln -sf "$REPO_ROOT/context" "$tmp_config/context"
ln -sf "$REPO_ROOT/command" "$tmp_config/command"
ln -sf "$REPO_ROOT/commands" "$tmp_config/commands"
ln -sf "$REPO_ROOT/prompts" "$tmp_config/prompts"
echo "$tmp_base"
}
@@ -64,7 +64,7 @@ list_skills() {
local tmp_base
tmp_base=$(setup_test_config)
trap "cleanup_test_config '$tmp_base'" EXIT
echo -e "${YELLOW}Skills in development (from $REPO_ROOT):${NC}"
echo ""
XDG_CONFIG_HOME="$tmp_base" opencode debug skill
@@ -72,17 +72,17 @@ list_skills() {
validate_skill() {
local skill_name="$1"
local skill_path="$REPO_ROOT/skill/$skill_name"
local skill_path="$REPO_ROOT/skills/$skill_name"
if [[ ! -d "$skill_path" ]]; then
echo -e "${RED}❌ Skill not found: $skill_name${NC}"
echo "Available skills:"
ls -1 "$REPO_ROOT/skill/"
ls -1 "$REPO_ROOT/skills/"
exit 1
fi
echo -e "${YELLOW}Validating skill: $skill_name${NC}"
if python3 "$REPO_ROOT/skill/skill-creator/scripts/quick_validate.py" "$skill_path"; then
if python3 "$REPO_ROOT/skills/skill-creator/scripts/quick_validate.py" "$skill_path"; then
echo -e "${GREEN}✅ Skill '$skill_name' is valid${NC}"
else
echo -e "${RED}❌ Skill '$skill_name' has validation errors${NC}"
@@ -93,20 +93,20 @@ validate_skill() {
validate_all() {
echo -e "${YELLOW}Validating all skills...${NC}"
echo ""
local failed=0
for skill_dir in "$REPO_ROOT/skill/"*/; do
for skill_dir in "$REPO_ROOT/skills/"*/; do
local skill_name=$(basename "$skill_dir")
echo -n " $skill_name: "
if python3 "$REPO_ROOT/skill/skill-creator/scripts/quick_validate.py" "$skill_dir" > /dev/null 2>&1; then
if python3 "$REPO_ROOT/skills/skill-creator/scripts/quick_validate.py" "$skill_dir" > /dev/null 2>&1; then
echo -e "${GREEN}${NC}"
else
echo -e "${RED}${NC}"
python3 "$REPO_ROOT/skill/skill-creator/scripts/quick_validate.py" "$skill_dir" 2>&1 | sed 's/^/ /'
python3 "$REPO_ROOT/skills/skill-creator/scripts/quick_validate.py" "$skill_dir" 2>&1 | sed 's/^/ /'
((failed++)) || true
fi
done
echo ""
if [[ $failed -eq 0 ]]; then
echo -e "${GREEN}All skills valid!${NC}"
@@ -120,7 +120,7 @@ run_opencode() {
local tmp_base
tmp_base=$(setup_test_config)
trap "cleanup_test_config '$tmp_base'" EXIT
echo -e "${YELLOW}Launching opencode with development skills...${NC}"
echo -e "Config path: ${GREEN}$tmp_base/opencode${NC}"
echo ""

182
scripts/validate-agents.sh Executable file
View File

@@ -0,0 +1,182 @@
#!/usr/bin/env bash
#
# Validate agents.json structure and referenced prompt files
#
# Usage:
# ./scripts/validate-agents.sh
#
# This script validates the agent configuration by:
# - Parsing agents.json as valid JSON
# - Checking all 6 required agents are present
# - Verifying each agent has required fields
# - Validating agent modes (primary vs subagent)
# - Verifying all referenced prompt files exist and are non-empty
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(dirname "$SCRIPT_DIR")"
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
AGENTS_FILE="$REPO_ROOT/agents/agents.json"
PROMPTS_DIR="$REPO_ROOT/prompts"
# Expected agent list
EXPECTED_AGENTS=("chiron" "chiron-forge" "hermes" "athena" "apollo" "calliope")
# Expected primary agents
PRIMARY_AGENTS=("chiron" "chiron-forge")
# Expected subagents
SUBAGENTS=("hermes" "athena" "apollo" "calliope")
# Required fields for each agent
REQUIRED_FIELDS=("description" "mode" "model" "prompt")
echo -e "${YELLOW}Validating agent configuration...${NC}"
echo ""
# Track errors
error_count=0
warning_count=0
# Function to print error
error() {
echo -e "${RED}$1${NC}" >&2
((error_count++)) || true
}
# Function to print warning
warning() {
echo -e "${YELLOW}⚠️ $1${NC}"
((warning_count++)) || true
}
# Function to print success
success() {
echo -e "${GREEN}$1${NC}"
}
# Check if agents.json exists
if [[ ! -f "$AGENTS_FILE" ]]; then
error "agents.json not found at $AGENTS_FILE"
exit 1
fi
# Validate JSON syntax
if ! python3 -c "import json; json.load(open('$AGENTS_FILE'))" 2>/dev/null; then
error "agents.json is not valid JSON"
exit 1
fi
success "agents.json is valid JSON"
echo ""
# Parse agents.json
AGENT_COUNT=$(python3 -c "import json; print(len(json.load(open('$AGENTS_FILE'))))")
success "Found $AGENT_COUNT agents in agents.json"
# Check agent count
if [[ $AGENT_COUNT -ne ${#EXPECTED_AGENTS[@]} ]]; then
error "Expected ${#EXPECTED_AGENTS[@]} agents, found $AGENT_COUNT"
fi
# Get list of agent names
AGENT_NAMES=$(python3 -c "import json; print(' '.join(sorted(json.load(open('$AGENTS_FILE')).keys())))")
echo ""
echo "Checking agent list..."
# Check for missing agents
for expected_agent in "${EXPECTED_AGENTS[@]}"; do
if echo "$AGENT_NAMES" | grep -qw "$expected_agent"; then
success "Agent '$expected_agent' found"
else
error "Required agent '$expected_agent' not found"
fi
done
# Check for unexpected agents
for agent_name in $AGENT_NAMES; do
if [[ ! " ${EXPECTED_AGENTS[@]} " =~ " ${agent_name} " ]]; then
warning "Unexpected agent '$agent_name' found (not in expected list)"
fi
done
echo ""
echo "Checking agent fields and modes..."
# Validate each agent
for agent_name in "${EXPECTED_AGENTS[@]}"; do
echo -n " $agent_name: "
# Check required fields
missing_fields=()
for field in "${REQUIRED_FIELDS[@]}"; do
if ! python3 -c "import json; data=json.load(open('$AGENTS_FILE')); print(data.get('$agent_name').get('$field', ''))" 2>/dev/null | grep -q .; then
missing_fields+=("$field")
fi
done
if [[ ${#missing_fields[@]} -gt 0 ]]; then
error "Missing required fields: ${missing_fields[*]}"
continue
fi
# Get mode value
mode=$(python3 -c "import json; print(json.load(open('$AGENTS_FILE'))['$agent_name']['mode'])")
# Validate mode
if [[ " ${PRIMARY_AGENTS[@]} " =~ " ${agent_name} " ]]; then
if [[ "$mode" == "primary" ]]; then
success "Mode: $mode (valid)"
else
error "Expected mode 'primary' for agent '$agent_name', found '$mode'"
fi
elif [[ " ${SUBAGENTS[@]} " =~ " ${agent_name} " ]]; then
if [[ "$mode" == "subagent" ]]; then
success "Mode: $mode (valid)"
else
error "Expected mode 'subagent' for agent '$agent_name', found '$mode'"
fi
fi
done
echo ""
echo "Checking prompt files..."
# Validate prompt file references
for agent_name in "${EXPECTED_AGENTS[@]}"; do
# Extract prompt file path from agent config
prompt_ref=$(python3 -c "import json; print(json.load(open('$AGENTS_FILE'))['$agent_name']['prompt'])")
# Parse prompt reference: {file:./prompts/<name>.txt}
if [[ "$prompt_ref" =~ \{file:(\./prompts/[^}]+)\} ]]; then
prompt_file="${BASH_REMATCH[1]}"
prompt_path="$REPO_ROOT/${prompt_file#./}"
# Check if prompt file exists
if [[ -f "$prompt_path" ]]; then
# Check if prompt file is non-empty
if [[ -s "$prompt_path" ]]; then
success "Prompt file exists and non-empty: $prompt_file"
else
error "Prompt file is empty: $prompt_file"
fi
else
error "Prompt file not found: $prompt_file"
fi
else
error "Invalid prompt reference format for agent '$agent_name': $prompt_ref"
fi
done
echo ""
if [[ $error_count -eq 0 ]]; then
echo -e "${GREEN}All validations passed!${NC}"
exit 0
else
echo -e "${RED}$error_count validation error(s) found${NC}"
exit 1
fi

View File

@@ -1,262 +0,0 @@
---
name: basecamp
description: "Manage work projects in Basecamp via MCP. Use when: (1) creating or viewing Basecamp projects, (2) managing todos or todo lists, (3) working with card tables (kanban boards), (4) searching Basecamp content, (5) syncing project plans to Basecamp. Triggers: basecamp, create todos, show my projects, card table, move card, basecamp search, sync to basecamp, what's in basecamp."
compatibility: opencode
---
# Basecamp
Manage work projects in Basecamp via MCP server. Provides workflows for project overview, todo management, kanban boards, and syncing from plan-writing skill.
## Quick Reference
| Action | Command Pattern |
| --------------- | -------------------------------------- |
| List projects | "Show my Basecamp projects" |
| View project | "What's in [project name]?" |
| Create todos | "Add todos to [project]" |
| View card table | "Show kanban for [project]" |
| Move card | "Move [card] to [column]" |
| Search | "Search Basecamp for [query]" |
| Sync plan | "Create Basecamp todos from this plan" |
## Core Workflows
### 1. Project Overview
List and explore projects:
```
1. get_projects → list all projects
2. Present summary: name, last activity
3. User selects project
4. get_project(id) → show dock items (todosets, card tables, message boards)
```
**Example output:**
```
Your Basecamp Projects:
1. Q2 Training Program (last activity: 2 hours ago)
2. Website Redesign (last activity: yesterday)
3. Product Launch (last activity: 3 days ago)
Which project would you like to explore?
```
### 2. Todo Management
**View todos:**
```
1. get_project(id) → find todoset from dock
2. get_todolists(project_id) → list all todo lists
3. get_todos(project_id, todolist_id) → show todos with status
```
**Create todos:**
```
1. Identify target project and todo list
2. For each todo:
create_todo(
project_id,
todolist_id,
content,
due_on?, # YYYY-MM-DD format
assignee_ids?, # array of person IDs
notify? # boolean
)
3. Confirm creation with links
```
**Complete/update todos:**
```
- complete_todo(project_id, todo_id) → mark done
- uncomplete_todo(project_id, todo_id) → reopen
- update_todo(project_id, todo_id, content?, due_on?, assignee_ids?)
- delete_todo(project_id, todo_id) → remove
```
### 3. Card Table (Kanban) Management
**View board:**
```
1. get_card_table(project_id) → get card table details
2. get_columns(project_id, card_table_id) → list columns
3. For each column: get_cards(project_id, column_id)
4. Present as kanban view
```
**Example output:**
```
Card Table: Development Pipeline
| Backlog (3) | In Progress (2) | Review (1) | Done (5) |
|-------------|-----------------|------------|----------|
| Feature A | Feature B | Bug fix | ... |
| Feature C | Feature D | | |
| Refactor | | | |
```
**Manage columns:**
```
- create_column(project_id, card_table_id, title)
- update_column(project_id, column_id, title) → rename
- move_column(project_id, card_table_id, column_id, position)
- update_column_color(project_id, column_id, color)
- put_column_on_hold(project_id, column_id) → freeze work
- remove_column_hold(project_id, column_id) → unfreeze
```
**Manage cards:**
```
- create_card(project_id, column_id, title, content?, due_on?, notify?)
- update_card(project_id, card_id, title?, content?, due_on?, assignee_ids?)
- move_card(project_id, card_id, column_id) → move to different column
- complete_card(project_id, card_id)
- uncomplete_card(project_id, card_id)
```
**Card steps (subtasks):**
```
- get_card_steps(project_id, card_id) → list subtasks
- create_card_step(project_id, card_id, title, due_on?, assignee_ids?)
- complete_card_step(project_id, step_id)
- update_card_step(project_id, step_id, title?, due_on?, assignee_ids?)
- delete_card_step(project_id, step_id)
```
### 4. Search
```
search_basecamp(query, project_id?)
- Omit project_id → search all projects
- Include project_id → scope to specific project
```
Results include todos, messages, and other content matching the query.
### 5. Sync from Plan-Writing
When user has a project plan from plan-writing skill:
```
1. Parse todo-structure.md or tasks.md for task hierarchy
2. Ask: "Which Basecamp project should I add these to?"
- List existing projects via get_projects
- Note: New projects must be created manually in Basecamp
3. Ask: "Use todo lists or card table?"
4. If todo lists:
- Create todo list per phase/milestone if needed
- Create todos with due dates and assignees
5. If card table:
- Create columns for phases/statuses
- Create cards from tasks
- Add card steps for subtasks
6. Confirm: "Created X todos/cards in [project]. View in Basecamp."
```
### 6. Status Check
```
User: "What's the status of [project]?"
1. get_project(id)
2. For each todo list: get_todos, count complete/incomplete
3. If card table exists: get columns and card counts
4. Calculate summary:
- X todos complete, Y incomplete, Z overdue
- Card distribution across columns
5. Highlight: overdue items, blocked items
```
**Example output:**
```
Project: Q2 Training Program
Todos: 12/20 complete (60%)
- 3 overdue items
- 5 due this week
Card Table: Development
| Backlog | In Progress | Review | Done |
| 3 | 2 | 1 | 8 |
Attention needed:
- "Create training materials" (overdue by 2 days)
- "Review curriculum" (due tomorrow)
```
## Tool Categories
For complete tool reference with parameters, see [references/mcp-tools.md](references/mcp-tools.md).
| Category | Key Tools |
| ---------- | -------------------------------------------------------------- |
| Projects | get_projects, get_project |
| Todos | get_todolists, get_todos, create_todo, complete_todo |
| Cards | get_card_table, get_columns, get_cards, create_card, move_card |
| Card Steps | get_card_steps, create_card_step, complete_card_step |
| Search | search_basecamp |
| Comments | get_comments, create_comment |
| Documents | get_documents, create_document, update_document |
## Limitations
- **No create_project tool**: Projects must be created manually in Basecamp UI
- **Work projects only**: This skill is for professional/team projects
- **Pagination handled**: MCP server handles pagination transparently
## Integration with Other Skills
| From Skill | To Basecamp |
| --------------- | ------------------------------------------------- |
| brainstorming | Save decision → reference in project docs |
| plan-writing | todo-structure.md → Basecamp todos or cards |
| task-management | Anytype tasks ↔ Basecamp todos (manual reference) |
## Common Patterns
### Create todos from a list
```
User provides list:
- Task 1 (due Friday)
- Task 2 (due next week)
- Task 3
1. Identify or confirm project and todo list
2. Parse due dates (Friday → YYYY-MM-DD)
3. Create each todo via create_todo
4. Report: "Created 3 todos in [list name]"
```
### Move cards through workflow
```
User: "Move Feature A to In Progress"
1. search_basecamp("Feature A") or get_cards to find card_id
2. get_columns to find target column_id
3. move_card(project_id, card_id, column_id)
4. Confirm: "Moved 'Feature A' to 'In Progress'"
```
### Add subtasks to a card
```
User: "Add subtasks to the Feature B card"
1. Find card via search or get_cards
2. For each subtask:
create_card_step(project_id, card_id, title)
3. Report: "Added X steps to 'Feature B'"
```

View File

@@ -1,198 +0,0 @@
# Basecamp MCP Tools Reference
Complete reference for all 46 available Basecamp MCP tools.
## Projects
| Tool | Parameters | Returns |
|------|------------|---------|
| `get_projects` | none | List of all projects with id, name, description |
| `get_project` | project_id | Project details including dock (todosets, card tables, etc.) |
## Todo Lists
| Tool | Parameters | Returns |
|------|------------|---------|
| `get_todolists` | project_id | All todo lists in project |
## Todos
| Tool | Parameters | Returns |
|------|------------|---------|
| `get_todos` | project_id, todolist_id | All todos (pagination handled) |
| `create_todo` | project_id, todolist_id, content, due_on?, assignee_ids?, notify? | Created todo |
| `update_todo` | project_id, todo_id, content?, due_on?, assignee_ids? | Updated todo |
| `delete_todo` | project_id, todo_id | Success confirmation |
| `complete_todo` | project_id, todo_id | Completed todo |
| `uncomplete_todo` | project_id, todo_id | Reopened todo |
### Todo Parameters
- `content`: String - The todo text
- `due_on`: String - Date in YYYY-MM-DD format
- `assignee_ids`: Array of integers - Person IDs to assign
- `notify`: Boolean - Whether to notify assignees
## Card Tables
| Tool | Parameters | Returns |
|------|------------|---------|
| `get_card_tables` | project_id | All card tables in project |
| `get_card_table` | project_id | Primary card table details |
## Columns
| Tool | Parameters | Returns |
|------|------------|---------|
| `get_columns` | project_id, card_table_id | All columns in card table |
| `get_column` | project_id, column_id | Column details |
| `create_column` | project_id, card_table_id, title | New column |
| `update_column` | project_id, column_id, title | Updated column |
| `move_column` | project_id, card_table_id, column_id, position | Moved column |
| `update_column_color` | project_id, column_id, color | Updated color |
| `put_column_on_hold` | project_id, column_id | Column frozen |
| `remove_column_hold` | project_id, column_id | Column unfrozen |
| `watch_column` | project_id, column_id | Subscribed to notifications |
| `unwatch_column` | project_id, column_id | Unsubscribed |
### Column Colors
Available colors for `update_column_color`:
- white, grey, pink, red, orange, yellow, green, teal, blue, purple
## Cards
| Tool | Parameters | Returns |
|------|------------|---------|
| `get_cards` | project_id, column_id | All cards in column |
| `get_card` | project_id, card_id | Card details |
| `create_card` | project_id, column_id, title, content?, due_on?, notify? | New card |
| `update_card` | project_id, card_id, title?, content?, due_on?, assignee_ids? | Updated card |
| `move_card` | project_id, card_id, column_id | Card moved to column |
| `complete_card` | project_id, card_id | Card marked complete |
| `uncomplete_card` | project_id, card_id | Card reopened |
### Card Parameters
- `title`: String - Card title
- `content`: String - Card description/body (supports HTML)
- `due_on`: String - Date in YYYY-MM-DD format
- `assignee_ids`: Array of integers - Person IDs
- `notify`: Boolean - Notify assignees on creation
## Card Steps (Subtasks)
| Tool | Parameters | Returns |
|------|------------|---------|
| `get_card_steps` | project_id, card_id | All steps on card |
| `create_card_step` | project_id, card_id, title, due_on?, assignee_ids? | New step |
| `get_card_step` | project_id, step_id | Step details |
| `update_card_step` | project_id, step_id, title?, due_on?, assignee_ids? | Updated step |
| `delete_card_step` | project_id, step_id | Step deleted |
| `complete_card_step` | project_id, step_id | Step completed |
| `uncomplete_card_step` | project_id, step_id | Step reopened |
## Search
| Tool | Parameters | Returns |
|------|------------|---------|
| `search_basecamp` | query, project_id? | Matching todos, messages, etc. |
- Omit `project_id` for global search across all projects
- Include `project_id` to scope search to specific project
## Communication
| Tool | Parameters | Returns |
|------|------------|---------|
| `get_campfire_lines` | project_id, campfire_id | Recent chat messages |
| `get_comments` | project_id, recording_id | Comments on any item |
| `create_comment` | project_id, recording_id, content | New comment |
### Comment Parameters
- `recording_id`: The ID of the item (todo, card, document, etc.)
- `content`: String - Comment text (supports HTML)
## Daily Check-ins
| Tool | Parameters | Returns |
|------|------------|---------|
| `get_daily_check_ins` | project_id, page? | Check-in questions |
| `get_question_answers` | project_id, question_id, page? | Answers to question |
## Documents
| Tool | Parameters | Returns |
|------|------------|---------|
| `get_documents` | project_id, vault_id | Documents in vault |
| `get_document` | project_id, document_id | Document content |
| `create_document` | project_id, vault_id, title, content, status? | New document |
| `update_document` | project_id, document_id, title?, content? | Updated document |
| `trash_document` | project_id, document_id | Document trashed |
### Document Parameters
- `vault_id`: Found in project dock as the docs/files container
- `content`: String - Document body (supports HTML)
- `status`: "active" or "archived"
## Attachments
| Tool | Parameters | Returns |
|------|------------|---------|
| `create_attachment` | file_path, name, content_type? | Uploaded attachment |
## Events
| Tool | Parameters | Returns |
|------|------------|---------|
| `get_events` | project_id, recording_id | Activity events on item |
## Webhooks
| Tool | Parameters | Returns |
|------|------------|---------|
| `get_webhooks` | project_id | Project webhooks |
| `create_webhook` | project_id, payload_url, types? | New webhook |
| `delete_webhook` | project_id, webhook_id | Webhook deleted |
### Webhook Types
Available types for `create_webhook`:
- Comment, Document, GoogleDocument, Message, Question::Answer
- Schedule::Entry, Todo, Todolist, Upload, Vault, Card, CardTable::Column
## Common Patterns
### Find project by name
```
1. get_projects → list all
2. Match name (case-insensitive partial match)
3. Return project_id
```
### Find todoset ID for a project
```
1. get_project(project_id)
2. Look in dock array for item with name "todoset"
3. Extract id from dock item URL
```
### Find card table ID
```
1. get_project(project_id)
2. Look in dock for "kanban_board" or use get_card_tables
3. Extract card_table_id
```
### Get all todos across all lists
```
1. get_todolists(project_id)
2. For each todolist: get_todos(project_id, todolist_id)
3. Aggregate results
```

View File

@@ -1,132 +0,0 @@
# Brainstorm Anytype Workflow
This document describes how to create and use Brainstorm objects in Anytype.
## Quick Create (API)
```bash
# Create a brainstorm object using Anytype MCP
Anytype_API-create-object
space_id: bafyreie5sfq7pjfuq56hxsybos545bi4tok3kx7nab3vnb4tnt4i3575p4.yu20gbnjlbxv
type_key: "brainstorm_v_2"
name: "NixOS Course Launch Strategy"
body: "Full brainstorm content here..."
icon: { format: "emoji", emoji: "💭" }
properties: [
{ key: "topic", text: "NixOS Course Launch Strategy" },
{ key: "context", text: "Want to launch NixOS course for developers" },
{ key: "outcome", text: "Build long-term audience/community" },
{ key: "constraints", text: "2-4 weeks prep time, solo creator" },
{ key: "options", text: "Option A: Early access... Option B: Free preview..." },
{ key: "decision", text: "Early access with community" },
{ key: "rationale", text: "Builds anticipation while validating content" },
{ key: "next_steps", text: "1. Create landing page, 2. Build email list..." },
{ key: "framework", select: "bafyreigokn5xgdosd4cihehl3tqfsd25mwdaapuhopjgn62tkpvpwn4tmy" },
{ key: "status", select: "bafyreiffiinadpa2fwxw3iylj7pph3yzbnhe63dcyiwr4x24ne4jsgi24" }
]
```
## Type Properties
| Property | Type | Purpose |
|----------|------|---------|
| `topic` | text | Short title/summary |
| `context` | text | Situation and trigger |
| `outcome` | text | What success looks like |
| `constraints` | text | Time, resources, boundaries |
| `options` | text | Options explored |
| `decision` | text | Final choice made |
| `rationale` | text | Reasoning behind decision |
| `next_steps` | text/objects | Action items or linked tasks |
| `framework` | select | Thinking framework used |
| `status` | select | Draft → Final → Archived |
| `tags` | multi_select | Categorization |
| `linked_projects` | objects | Related projects |
| `linked_tasks` | objects | Related tasks |
## Framework Tag IDs
| Framework | Tag ID |
|-----------|--------|
| None | `bafyreiatkdbwq53shngaje6wuw752wxnwqlk3uhy6nicamdr56jpvji34i` |
| Pros/Cons | `bafyreiaizrndgxmzbbzo6lurkgi7fc6evemoc5tivswrdu57ngkizy4b3u` |
| SWOT | `bafyreiaym5zkajnsrklivpjkizkuyhy3v5fzo62aaeobdlqzhq47clv6lm` |
| 5 Whys | `bafyreihgfpsjeyuu7p46ejzd5jce5kmgfsuxy7r5kl4fqdhuq7jqoggtgq` |
| How-Now-Wow | `bafyreieublfraypplrr5mmnksnytksv4iyh7frspyn64gixaodwmnhmosu` |
| Starbursting | `bafyreieyz6xjpt3zxad7h643m24oloajcae3ocnma3ttqfqykmggrsksk4` |
| Constraint Mapping | `bafyreigokn5xgdosd4cihehl3tqfsd25mwdaapuhopjgn62tkpvpwn4tmy` |
## Status Tag IDs
| Status | Tag ID |
|--------|--------|
| Draft | `bafyreig5um57baws2dnntaxsi4smxtrzftpe57a7wyhfextvcq56kdkllq` |
| Final | `bafyreiffiinadpa2fwxw3iylj7pph3yzbnhe63dcyiwr4x24ne4jsgi24` |
| Archived | `bafyreihk6dlpwh3nljrxcqqe3v6tl52bxuvmx3rcgyzyom6yjmtdegu4ja` |
## Template Setup (Recommended)
For a better editing experience, create a template in Anytype:
1. Open Anytype desktop app → Chiron space
2. Go to Content Model → Object Types → Brainstorm v2
3. Click Templates (top right) → Click + to create template
4. Configure with:
- **Name**: "Brainstorm Session"
- **Icon**: 💭
- **Default Status**: Draft
- **Pre-filled structure**: Leave body empty for dynamic content
- **Property defaults**: Set framework to "None" as default
5. Save the template
Now when creating brainstorms, select this template for a guided experience.
## Linking to Other Objects
After creating a brainstorm, link it to related objects:
```bash
# Link to a project
Anytype_API-update-object
object_id: <brainstorm_id>
space_id: <chiron_space_id>
properties: [
{ key: "linked_projects", objects: ["<project_id>"] }
]
# Link to tasks
Anytype_API-update-object
object_id: <brainstorm_id>
space_id: <chiron_space_id>
properties: [
{ key: "linked_tasks", objects: ["<task_id_1>", "<task_id_2>"] }
]
```
## Searching Brainstorms
Find brainstorms by topic, status, or tags:
```bash
Anytype_API-search-space
space_id: bafyreie5sfq7pjfuq56hxsybos545bi4tok3kx7nab3vnb4tnt4i3575p4.yu20gbnjlbxv
query: "NixOS"
types: ["brainstorm_v_2"]
```
Or list all brainstorms:
```bash
Anytype_API-list-objects
space_id: bafyreie5sfq7pjfuq56hxsybos545bi4tok3kx7nab3vnb4tnt4i3575p4.yu20gbnjlbxv
type_id: bafyreifjneoy2bdxuwwai2e3mdn7zovudpzbjyflth7k3dj3o7tmhqdlw4
```
## Best Practices
1. **Create brainstorms for any significant decision** - Capture reasoning while fresh
2. **Mark as Final when complete** - Helps with search and review
3. **Link to related objects** - Creates context web
4. **Use frameworks selectively** - Not every brainstorm needs structure
5. **Review periodically** - Brainstorms can inform future decisions

View File

@@ -1,69 +0,0 @@
---
name: calendar-scheduling
description: "Calendar and time management with Proton Calendar integration. Use when: (1) checking schedule, (2) blocking focus time, (3) scheduling meetings, (4) time-based planning, (5) managing availability. Triggers: calendar, schedule, when am I free, block time, meeting, availability, what's my day look like."
compatibility: opencode
---
# Calendar & Scheduling
Time management and calendar integration for Proton Calendar.
## Status: Stub
This skill is a placeholder for future development. Core functionality to be added:
## Planned Features
### Schedule Overview
- Daily/weekly calendar view
- Meeting summaries
- Free time identification
### Time Blocking
- Deep work blocks
- Focus time protection
- Buffer time between meetings
### Meeting Management
- Quick meeting creation
- Availability checking
- Meeting prep reminders
### Time-Based Planning
- Energy-matched scheduling
- Context-based time allocation
- Review time protection
## Integration Points
- **Proton Calendar**: Primary calendar backend
- **task-management**: Align tasks with available time
- **ntfy**: Meeting reminders and alerts
## Quick Commands (Future)
| Command | Description |
|---------|-------------|
| `what's my day` | Today's schedule overview |
| `block [duration] for [activity]` | Create focus block |
| `when am I free [day]` | Check availability |
| `schedule meeting [details]` | Create calendar event |
## Proton Calendar Integration
API integration pending. Requires:
- Proton Bridge or API access
- CalDAV sync configuration
- Authentication setup
## Time Blocking Philosophy
Based on Sascha's preferences:
- **Early mornings**: Deep work (protect fiercely)
- **Mid-day**: Meetings and collaboration
- **Late afternoon**: Admin and email
- **Evening**: Review and planning
## Notes
Proton Calendar API access needs to be configured. Consider CalDAV integration or n8n workflow as bridge.

View File

@@ -1,78 +0,0 @@
---
name: communications
description: "Email and communication management with Proton Mail integration. Use when: (1) drafting emails, (2) managing follow-ups, (3) communication tracking, (4) message templates, (5) inbox management. Triggers: email, draft, reply, follow up, message, inbox, communication, respond to."
compatibility: opencode
---
# Communications
Email and communication management for Proton Mail.
## Status: Stub
This skill is a placeholder for future development. Core functionality to be added:
## Planned Features
### Email Drafting
- Context-aware draft generation
- Tone matching (formal/casual)
- Template-based responses
### Follow-up Tracking
- Waiting-for list management
- Follow-up reminders
- Response tracking
### Inbox Management
- Priority sorting
- Quick triage assistance
- Archive recommendations
### Communication Templates
- Common response patterns
- Meeting request templates
- Status update formats
## Integration Points
- **Proton Mail**: Primary email backend
- **task-management**: Convert emails to tasks
- **ntfy**: Important email alerts
- **n8n**: Automation workflows
## Quick Commands (Future)
| Command | Description |
|---------|-------------|
| `draft reply to [context]` | Generate email draft |
| `follow up on [topic]` | Check follow-up status |
| `email template [type]` | Use saved template |
| `inbox summary` | Overview of pending emails |
## Proton Mail Integration
API integration pending. Options:
- Proton Bridge (local IMAP/SMTP)
- n8n with email triggers
- Manual copy/paste workflow initially
## Communication Style Guide
Based on Sascha's profile:
- **Tone**: Professional but approachable
- **Length**: Concise, get to the point
- **Structure**: Clear ask/action at the top
- **Follow-up**: Set clear expectations
## Email Templates (Future)
- Meeting request
- Status update
- Delegation request
- Follow-up reminder
- Thank you / acknowledgment
## Notes
Start with manual draft assistance. Proton Mail API integration can be added via n8n workflow when ready.

View File

@@ -1,60 +0,0 @@
---
name: knowledge-management
description: "Knowledge base and note management with Anytype. Use when: (1) saving information for later, (2) organizing notes and references, (3) finding past notes, (4) building knowledge connections, (5) managing documentation. Triggers: save this, note, remember, knowledge base, where did I put, find my notes on, documentation."
compatibility: opencode
---
# Knowledge Management
Note capture and knowledge organization using Anytype as the backend.
## Status: Stub
This skill is a placeholder for future development. Core functionality to be added:
## Planned Features
### Quick Note Capture
- Minimal friction capture to Anytype
- Auto-tagging based on content
- Link to related notes
### Knowledge Retrieval
- Semantic search across notes
- Tag-based filtering
- Connection discovery
### Resource Organization
- PARA Resources category management
- Topic clustering
- Archive maintenance
### Documentation Management
- Technical docs organization
- Version tracking
- Cross-reference linking
## Integration Points
- **Anytype**: Primary storage (Resources type)
- **task-management**: Link notes to projects/areas
- **research**: Save research findings
## Quick Commands (Future)
| Command | Description |
|---------|-------------|
| `note: [content]` | Quick capture |
| `find notes on [topic]` | Search knowledge base |
| `link [note] to [note]` | Create connection |
| `organize [tag/topic]` | Cluster related notes |
## Anytype Types
- `note` - Quick captures
- `resource` - Organized reference material
- `document` - Formal documentation
## Notes
Expand based on actual note-taking patterns. Consider integration with mem0-memory skill for AI-assisted recall.

View File

@@ -1,165 +0,0 @@
---
name: plan-writing
description: "Transform ideas into comprehensive, actionable project plans with templates. Use when: (1) creating project kickoff documents, (2) structuring new projects, (3) building detailed task breakdowns, (4) documenting project scope and stakeholders, (5) setting up project for execution. Triggers: project plan, kickoff document, plan out, structure project, project setup, create plan for, what do I need to start."
compatibility: opencode
---
# Plan Writing
Transform brainstormed ideas into comprehensive, actionable project plans using modular templates.
## Quick Reference
| Project Type | Templates to Use |
|--------------|------------------|
| Solo, <2 weeks | project-brief, todo-structure |
| Solo, >2 weeks | project-brief, todo-structure, risk-register |
| Team, any size | project-kickoff, stakeholder-map, todo-structure, risk-register |
## Process
### 1. Intake
Gather initial context:
- What project are we planning?
- Check for existing brainstorming output in `docs/brainstorms/`
- If starting fresh, gather basic context first
### 2. Scope Assessment
Ask these questions (one at a time):
1. **Solo or team project?**
- Solo → lighter documentation
- Team → need alignment docs (kickoff, stakeholders)
2. **Rough duration estimate?**
- <2 weeks → skip risk register
- >2 weeks → include risk planning
3. **Known deadline or flexible?**
- Hard deadline → prioritize milestone planning
- Flexible → focus on phased approach
4. **Which PARA area does this belong to?** (optional)
- Helps categorization and later task-management integration
### 3. Component Selection
Based on scope, select appropriate templates:
```
"Based on [team project, 6 weeks], I'll include:
✓ Project Kickoff (team alignment)
✓ Stakeholder Map (communication planning)
✓ Todo Structure (task breakdown)
✓ Risk Register (duration >2 weeks)
Shall I proceed with this structure?"
```
See [references/component-guide.md](references/component-guide.md) for selection logic.
### 4. Draft Generation
For each selected template:
1. Load template from `assets/templates/`
2. Fill with project-specific content
3. Present each major section for validation
4. Adjust based on feedback
Work through templates in this order:
1. Kickoff/Brief (establishes context)
2. Stakeholders (who's involved)
3. Todos (what needs doing)
4. Risks (what could go wrong)
### 5. Output
Generate final documents:
- Create `docs/plans/<project-name>/` directory
- Write each component as separate file
- Create `index.md` linking all components
```
docs/plans/<project-name>/
├── index.md # Links to all components
├── kickoff.md # or brief.md for solo projects
├── stakeholders.md # if team project
├── tasks.md # task breakdown
├── risks.md # if >2 weeks duration
└── updates/ # for future progress updates
└── YYYY-MM-DD.md
```
### 6. Handoff (Optional)
After plan is complete, offer next steps:
> "Ready to create this project in Basecamp? I can:
> - Create todo lists from the task structure
> - Set up card table columns from phases
> - Add initial cards/todos with due dates"
This triggers the basecamp skill for execution.
## Templates
All templates in `assets/templates/`:
| Template | Purpose | When to Include |
|----------|---------|-----------------|
| project-kickoff.md | Comprehensive 8-section kickoff | Team projects |
| project-brief.md | 1-page summary | Solo or simple projects |
| stakeholder-map.md | Who needs what, when | Team projects |
| risk-register.md | Risks and mitigations | Projects >2 weeks |
| todo-structure.md | Hierarchical task breakdown | Always |
| progress-update.md | Status update template | For ongoing tracking |
## PARA Integration (Optional)
If user wants PARA integration:
1. Prompt for Area assignment (from their defined Areas)
2. Can trigger task-management skill to create Anytype entries
3. Include Area reference in kickoff/brief document
This is optional - not all users use PARA.
## Integration with Other Skills
| From | To plan-writing | Output |
|------|-----------------|--------|
| brainstorming | Decision/context | Informs kickoff scope |
| plan-writing | → basecamp | Todo lists, cards |
| plan-writing | → task-management | Anytype tasks (optional) |
## Example Workflow
```
User: "Create a project plan for launching the Q2 training program"
AI: "I'll help structure this project. First, a few questions:
Is this a solo project or will others be involved?"
User: "Team - 3 people"
AI: "Duration estimate?
a) Less than 2 weeks
b) 2-4 weeks
c) More than a month"
User: "B - about 3 weeks"
AI: "Got it. For a 3-week team project, I'll include:
✓ Project Kickoff (team alignment)
✓ Stakeholder Map (communication)
✓ Todo Structure (task breakdown)
✓ Risk Register (3 weeks warrants this)
Shall I proceed?"
User: "Yes"
AI: [Proceeds through each template, filling with project details]
```

View File

@@ -1,89 +0,0 @@
# Progress Update: [Project Name]
**Period**: [Date] to [Date]
**Author**: [Name]
**Status**: 🟢 On Track / 🟡 At Risk / 🔴 Blocked
---
## Summary
[2-3 sentence executive summary: Where are we, what's the headline?]
**Overall Progress**: [X]% complete
---
## Completed This Period
- [x] [Task/milestone completed] - [Impact or note]
- [x] [Task completed]
- [x] [Task completed]
**Highlights**:
- [Notable achievement or win]
---
## In Progress
| Task | Owner | Progress | Expected Complete |
|------|-------|----------|-------------------|
| [Task 1] | [Name] | [X]% | [Date] |
| [Task 2] | [Name] | [X]% | [Date] |
| [Task 3] | [Name] | [X]% | [Date] |
---
## Blockers & Risks
### Active Blockers
| Blocker | Impact | Owner | Action Needed | ETA |
|---------|--------|-------|---------------|-----|
| [Blocker 1] | [High/Med/Low] | [Name] | [What's needed] | [Date] |
### Emerging Risks
| Risk | Probability | Mitigation |
|------|-------------|------------|
| [Risk 1] | [H/M/L] | [Action] |
---
## Next Period Plan
**Focus**: [Main focus for next period]
| Priority | Task | Owner | Target Date |
|----------|------|-------|-------------|
| 1 | [Highest priority task] | [Name] | [Date] |
| 2 | [Second priority] | [Name] | [Date] |
| 3 | [Third priority] | [Name] | [Date] |
---
## Metrics
| Metric | Target | Current | Trend |
|--------|--------|---------|-------|
| [Metric 1] | [X] | [Y] | ↑/↓/→ |
| [Metric 2] | [X] | [Y] | ↑/↓/→ |
| Tasks Complete | [X] | [Y] | ↑ |
---
## Decisions Needed
- [ ] [Decision 1]: [Options and recommendation] - Need by: [Date]
- [ ] [Decision 2]: [Context] - Need by: [Date]
---
## Notes / Context
[Any additional context, changes in scope, stakeholder feedback, etc.]
---
*Next update: [Date]*

View File

@@ -1,48 +0,0 @@
# Project Brief: [Project Name]
**Owner**: [Name]
**Timeline**: [Start Date] → [Target Date]
**Area**: [PARA Area, if applicable]
## Goal
[One clear sentence: What will be true when this project is complete?]
## Success Criteria
How we'll know it's done:
- [ ] [Criterion 1 - specific and measurable]
- [ ] [Criterion 2]
- [ ] [Criterion 3]
## Scope
**Included**:
- [Deliverable 1]
- [Deliverable 2]
**Not Included**:
- [Exclusion 1]
## Key Milestones
| Milestone | Target Date | Status |
|-----------|-------------|--------|
| [Milestone 1] | [Date] | [ ] |
| [Milestone 2] | [Date] | [ ] |
| [Complete] | [Date] | [ ] |
## Initial Tasks
1. [ ] [First task to start] - Due: [Date]
2. [ ] [Second task]
3. [ ] [Third task]
## Notes
[Any context, constraints, or references worth capturing]
---
*Created: [Date]*

View File

@@ -1,106 +0,0 @@
# Project Kickoff: [Project Name]
## 1. Project Essentials
| Field | Value |
|-------|-------|
| **Project Name** | [Name] |
| **Owner** | [Name] |
| **Start Date** | [YYYY-MM-DD] |
| **Target Completion** | [YYYY-MM-DD] |
| **PARA Area** | [Area, if applicable] |
### Overview
[2-3 sentence description of what this project will accomplish and why it matters.]
## 2. Goals and Success Criteria
**Primary Goal**: [One sentence describing the end state - what does "done" look like?]
**Success Criteria**:
- [ ] [Measurable criterion 1]
- [ ] [Measurable criterion 2]
- [ ] [Measurable criterion 3]
**Out of Scope** (explicitly):
- [Item that might be assumed but is NOT included]
- [Another exclusion]
## 3. Stakeholders
| Role | Person | Involvement Level |
|------|--------|-------------------|
| Project Owner | [Name] | High - decisions |
| Core Team | [Names] | High - execution |
| Informed | [Names] | Low - updates only |
| Approver | [Name, if any] | Medium - sign-off |
## 4. Timeline and Milestones
| Milestone | Target Date | Dependencies | Owner |
|-----------|-------------|--------------|-------|
| [Milestone 1] | [Date] | None | [Who] |
| [Milestone 2] | [Date] | Milestone 1 | [Who] |
| [Milestone 3] | [Date] | Milestone 2 | [Who] |
| **Project Complete** | [Date] | All above | [Owner] |
### Key Dates
- **Kickoff**: [Date]
- **First Review**: [Date]
- **Final Deadline**: [Date]
## 5. Scope
### In Scope
- [Deliverable 1]: [Brief description]
- [Deliverable 2]: [Brief description]
- [Deliverable 3]: [Brief description]
### Out of Scope
- [Explicitly excluded item 1]
- [Explicitly excluded item 2]
### Assumptions
- [Assumption 1 - e.g., "Budget approved"]
- [Assumption 2 - e.g., "Team available full-time"]
## 6. Risks
| Risk | Probability | Impact | Mitigation | Owner |
|------|-------------|--------|------------|-------|
| [Risk 1] | H/M/L | H/M/L | [Plan] | [Who] |
| [Risk 2] | H/M/L | H/M/L | [Plan] | [Who] |
*See detailed risk register if needed: [link to risks.md]*
## 7. Communication Plan
| What | Audience | Frequency | Channel | Owner |
|------|----------|-----------|---------|-------|
| Status Update | All stakeholders | Weekly | [Email/Basecamp] | [Who] |
| Team Sync | Core team | [Daily/2x week] | [Meeting/Slack] | [Who] |
| Milestone Review | Approvers | At milestone | [Meeting] | [Who] |
### Escalation Path
1. First: [Team lead/Owner]
2. Then: [Manager/Sponsor]
3. Finally: [Executive, if applicable]
## 8. Next Steps
Immediate actions to kick off the project:
- [ ] [Action 1] - @[owner] - Due: [date]
- [ ] [Action 2] - @[owner] - Due: [date]
- [ ] [Action 3] - @[owner] - Due: [date]
---
*Document created: [Date]*
*Last updated: [Date]*

View File

@@ -1,104 +0,0 @@
# Risk Register: [Project Name]
## Risk Summary
| ID | Risk | Probability | Impact | Risk Score | Status |
|----|------|-------------|--------|------------|--------|
| R1 | [Brief risk name] | H/M/L | H/M/L | [H/M/L] | Open |
| R2 | [Brief risk name] | H/M/L | H/M/L | [H/M/L] | Open |
| R3 | [Brief risk name] | H/M/L | H/M/L | [H/M/L] | Open |
**Risk Score**: Probability × Impact (H×H=Critical, H×M or M×H=High, M×M=Medium, others=Low)
---
## Detailed Risk Analysis
### R1: [Risk Name]
| Aspect | Detail |
|--------|--------|
| **Description** | [What could go wrong?] |
| **Probability** | High / Medium / Low |
| **Impact** | High / Medium / Low |
| **Category** | Technical / Resource / External / Schedule / Budget |
| **Trigger** | [What would indicate this risk is materializing?] |
**Mitigation Plan**:
- [Action 1 to reduce probability or impact]
- [Action 2]
**Contingency Plan** (if risk occurs):
- [Fallback action 1]
- [Fallback action 2]
**Owner**: [Name]
**Review Date**: [Date]
---
### R2: [Risk Name]
| Aspect | Detail |
|--------|--------|
| **Description** | [What could go wrong?] |
| **Probability** | High / Medium / Low |
| **Impact** | High / Medium / Low |
| **Category** | Technical / Resource / External / Schedule / Budget |
| **Trigger** | [What would indicate this risk is materializing?] |
**Mitigation Plan**:
- [Action 1]
- [Action 2]
**Contingency Plan**:
- [Fallback action]
**Owner**: [Name]
**Review Date**: [Date]
---
### R3: [Risk Name]
| Aspect | Detail |
|--------|--------|
| **Description** | [What could go wrong?] |
| **Probability** | High / Medium / Low |
| **Impact** | High / Medium / Low |
| **Category** | Technical / Resource / External / Schedule / Budget |
| **Trigger** | [What would indicate this risk is materializing?] |
**Mitigation Plan**:
- [Action 1]
- [Action 2]
**Contingency Plan**:
- [Fallback action]
**Owner**: [Name]
**Review Date**: [Date]
---
## Risk Categories
| Category | Examples |
|----------|----------|
| **Technical** | Technology doesn't work, integration issues, performance |
| **Resource** | Key person unavailable, skill gaps, overcommitment |
| **External** | Vendor delays, regulatory changes, dependencies |
| **Schedule** | Delays, unrealistic timeline, competing priorities |
| **Budget** | Cost overruns, funding cuts, unexpected expenses |
## Review Schedule
- **Weekly**: Quick scan of high risks
- **Bi-weekly**: Full risk register review
- **At milestones**: Comprehensive reassessment
---
*Created: [Date]*
*Last reviewed: [Date]*
*Next review: [Date]*

View File

@@ -1,72 +0,0 @@
# Stakeholder Map: [Project Name]
## Stakeholder Matrix
| Stakeholder | Role | Interest Level | Influence | Information Needs |
|-------------|------|----------------|-----------|-------------------|
| [Name/Group] | [Role] | High/Medium/Low | High/Medium/Low | [What they need to know] |
| [Name/Group] | [Role] | High/Medium/Low | High/Medium/Low | [What they need to know] |
| [Name/Group] | [Role] | High/Medium/Low | High/Medium/Low | [What they need to know] |
## Communication Plan by Stakeholder
### [Stakeholder 1: Name/Role]
| Aspect | Detail |
|--------|--------|
| **Needs** | [What information they need] |
| **Frequency** | [How often: daily, weekly, at milestones] |
| **Channel** | [Email, Basecamp, meeting, Slack] |
| **Format** | [Brief update, detailed report, presentation] |
| **Owner** | [Who communicates with them] |
### [Stakeholder 2: Name/Role]
| Aspect | Detail |
|--------|--------|
| **Needs** | [What information they need] |
| **Frequency** | [How often] |
| **Channel** | [Preferred channel] |
| **Format** | [Format preference] |
| **Owner** | [Who communicates] |
### [Stakeholder 3: Name/Role]
| Aspect | Detail |
|--------|--------|
| **Needs** | [What information they need] |
| **Frequency** | [How often] |
| **Channel** | [Preferred channel] |
| **Format** | [Format preference] |
| **Owner** | [Who communicates] |
## RACI Matrix
| Decision/Task | [Person 1] | [Person 2] | [Person 3] | [Person 4] |
|---------------|------------|------------|------------|------------|
| [Decision 1] | R | A | C | I |
| [Decision 2] | I | R | A | C |
| [Task 1] | R | I | I | A |
**Legend**:
- **R** = Responsible (does the work)
- **A** = Accountable (final decision maker)
- **C** = Consulted (input required)
- **I** = Informed (kept updated)
## Escalation Path
1. **First Level**: [Name/Role] - for [types of issues]
2. **Second Level**: [Name/Role] - if unresolved in [timeframe]
3. **Executive**: [Name/Role] - for [critical blockers only]
## Notes
- [Any stakeholder-specific considerations]
- [Political or relationship notes]
- [Historical context if relevant]
---
*Created: [Date]*
*Last updated: [Date]*

View File

@@ -1,94 +0,0 @@
# Task Structure: [Project Name]
## Overview
| Metric | Value |
|--------|-------|
| **Total Tasks** | [X] |
| **Phases** | [Y] |
| **Timeline** | [Start] → [End] |
---
## Phase 1: [Phase Name]
**Target**: [Date]
**Owner**: [Name]
| # | Task | Owner | Estimate | Due | Depends On | Status |
|---|------|-------|----------|-----|------------|--------|
| 1.1 | [Task description] | [Name] | [Xh/Xd] | [Date] | - | [ ] |
| 1.2 | [Task description] | [Name] | [Xh/Xd] | [Date] | 1.1 | [ ] |
| 1.3 | [Task description] | [Name] | [Xh/Xd] | [Date] | - | [ ] |
**Phase Deliverable**: [What's complete when this phase is done]
---
## Phase 2: [Phase Name]
**Target**: [Date]
**Owner**: [Name]
| # | Task | Owner | Estimate | Due | Depends On | Status |
|---|------|-------|----------|-----|------------|--------|
| 2.1 | [Task description] | [Name] | [Xh/Xd] | [Date] | Phase 1 | [ ] |
| 2.2 | [Task description] | [Name] | [Xh/Xd] | [Date] | 2.1 | [ ] |
| 2.3 | [Task description] | [Name] | [Xh/Xd] | [Date] | - | [ ] |
**Phase Deliverable**: [What's complete when this phase is done]
---
## Phase 3: [Phase Name]
**Target**: [Date]
**Owner**: [Name]
| # | Task | Owner | Estimate | Due | Depends On | Status |
|---|------|-------|----------|-----|------------|--------|
| 3.1 | [Task description] | [Name] | [Xh/Xd] | [Date] | Phase 2 | [ ] |
| 3.2 | [Task description] | [Name] | [Xh/Xd] | [Date] | 3.1 | [ ] |
| 3.3 | [Task description] | [Name] | [Xh/Xd] | [Date] | 3.1 | [ ] |
**Phase Deliverable**: [What's complete when this phase is done]
---
## Unphased / Ongoing Tasks
| # | Task | Owner | Frequency | Notes |
|---|------|-------|-----------|-------|
| O.1 | [Recurring task] | [Name] | Weekly | [Notes] |
| O.2 | [Monitoring task] | [Name] | Daily | [Notes] |
---
## Dependencies Summary
```
Phase 1 ──────► Phase 2 ──────► Phase 3
│ │
├── 1.1 ► 1.2 ├── 2.1 ► 2.2
└── 1.3 └── 2.3 (parallel)
```
## Milestone Checklist
- [ ] **Milestone 1**: [Name] - [Date]
- [ ] [Required task 1.1]
- [ ] [Required task 1.2]
- [ ] **Milestone 2**: [Name] - [Date]
- [ ] [Required task 2.1]
- [ ] [Required task 2.2]
- [ ] **Project Complete** - [Date]
- [ ] All phases complete
- [ ] Success criteria met
- [ ] Handoff complete
---
*Created: [Date]*
*Last updated: [Date]*

View File

@@ -1,117 +0,0 @@
# Component Selection Guide
Decision matrix for which templates to include based on project characteristics.
## Decision Matrix
| Question | If Yes | If No |
|----------|--------|-------|
| Team project (>1 person)? | +kickoff, +stakeholders | Use brief instead of kickoff |
| Duration >2 weeks? | +risk-register | Skip risks |
| External stakeholders? | +stakeholders (detailed) | Stakeholders optional |
| Complex dependencies? | +detailed todos with deps | Simple todo list |
| Ongoing tracking needed? | +progress-update template | One-time plan |
## Quick Selection by Project Type
### Solo, Short (<2 weeks)
```
✓ project-brief.md
✓ todo-structure.md
```
### Solo, Medium (2-4 weeks)
```
✓ project-brief.md
✓ todo-structure.md
✓ risk-register.md
```
### Solo, Long (>4 weeks)
```
✓ project-brief.md (or kickoff for complex)
✓ todo-structure.md
✓ risk-register.md
✓ progress-update.md (for self-tracking)
```
### Team, Any Duration
```
✓ project-kickoff.md (always for team alignment)
✓ stakeholder-map.md
✓ todo-structure.md
✓ risk-register.md (if >2 weeks)
✓ progress-update.md (for status updates)
```
## Template Purposes
### project-kickoff.md
Full 8-section document for team alignment:
1. Project essentials (name, owner, dates)
2. Goals and success criteria
3. Stakeholders overview
4. Timeline and milestones
5. Scope (in/out)
6. Risks overview
7. Communication plan
8. Next steps
**Use when**: Multiple people need alignment on what/why/how.
### project-brief.md
1-page summary for simpler projects:
- Goal statement
- Success criteria
- Key milestones
- Initial tasks
**Use when**: Solo project or simple scope that doesn't need formal kickoff.
### stakeholder-map.md
Communication matrix:
- Who needs information
- What they need to know
- How often
- Which channel
**Use when**: Team projects with multiple stakeholders needing different information.
### risk-register.md
Risk tracking table:
- Risk description
- Probability (H/M/L)
- Impact (H/M/L)
- Mitigation plan
- Owner
**Use when**: Projects >2 weeks or high-stakes projects of any duration.
### todo-structure.md
Hierarchical task breakdown:
- Phases or milestones
- Tasks under each phase
- Subtasks if needed
- Metadata: owner, estimate, due date, dependencies
**Use when**: Always. Every project needs task breakdown.
### progress-update.md
Status reporting template:
- Completed since last update
- In progress
- Blockers
- Next steps
- Metrics/progress %
**Use when**: Projects needing regular status updates (weekly, sprint-based, etc.).
## Customization Notes
Templates are starting points. Common customizations:
- Remove sections that don't apply
- Add project-specific sections
- Adjust detail level based on audience
- Combine templates for simpler output
The goal is useful documentation, not template compliance.

View File

@@ -1,54 +0,0 @@
---
name: research
description: "Research and investigation workflows. Use when: (1) researching technologies or tools, (2) investigating best practices, (3) comparing solutions, (4) gathering information for decisions, (5) deep-diving into topics. Triggers: research, investigate, explore, compare, learn about, what are best practices for, how does X work."
compatibility: opencode
---
# Research
Research and investigation workflows for informed decision-making.
## Status: Stub
This skill is a placeholder for future development. Core functionality to be added:
## Planned Features
### Investigation Workflow
- Multi-source research (web, docs, code)
- Source credibility assessment
- Summary with drill-down capability
### Technology Evaluation
- Feature comparison matrices
- Pros/cons analysis
- Fit-for-purpose assessment
### Best Practices Discovery
- Industry standards lookup
- Implementation patterns
- Common pitfalls
### Learning Path Generation
- Topic breakdown
- Resource recommendations
- Progress tracking
## Integration Points
- **Anytype**: Save research findings to Resources
- **Web Search**: Primary research source
- **librarian agent**: External documentation lookup
## Quick Commands (Future)
| Command | Description |
|---------|-------------|
| `research [topic]` | Start research session |
| `compare [A] vs [B]` | Feature comparison |
| `best practices [topic]` | Lookup standards |
| `learn [topic]` | Generate learning path |
## Notes
Expand this skill based on actual research patterns that emerge from usage.

View File

@@ -1,246 +0,0 @@
---
name: task-management
description: "PARA-based task and project management with Anytype integration. Use when: (1) creating/managing tasks or projects, (2) daily or weekly reviews, (3) prioritizing work, (4) capturing action items, (5) planning sprints or focus blocks, (6) asking 'what should I work on?'. Triggers: task, todo, project, priority, review, focus, plan, backlog, inbox, capture."
compatibility: opencode
---
# Task Management
PARA-based productivity system integrated with Anytype for Sascha's personal and professional task management.
## Quick Reference
| Action | Command Pattern |
|--------|-----------------|
| Quick capture | "Capture: [item]" or "Add to inbox: [item]" |
| Create task | "Task: [title] for [area/project]" |
| Create project | "New project: [title] in [area]" |
| Daily review | "Daily review" or "What's on for today?" |
| Weekly review | "Weekly review" or "Week planning" |
| Focus check | "What should I focus on?" |
| Context batch | "What [area] tasks can I batch?" |
## Anytype Configuration
**Space**: Chiron (create if not exists)
### Types
| Type | PARA Category | Purpose |
|------|---------------|---------|
| `project` | Projects | Active outcomes with deadlines |
| `area` | Areas | Ongoing responsibilities |
| `resource` | Resources | Reference materials |
| `task` | (within Projects/Areas) | Individual action items |
| `note` | (Inbox/Resources) | Quick captures, meeting notes |
### Key Properties
| Property | Type | Used On | Values |
|----------|------|---------|--------|
| `status` | select | Task, Project | `inbox`, `next`, `waiting`, `scheduled`, `done` |
| `priority` | select | Task, Project | `critical`, `high`, `medium`, `low` |
| `area` | relation | Task, Project | Links to Area objects |
| `due_date` | date | Task, Project | Deadline |
| `energy` | select | Task | `high`, `medium`, `low` |
| `context` | multi_select | Task | `deep-work`, `admin`, `calls`, `errands` |
## Core Workflows
### 1. Quick Capture
Minimal friction inbox capture. Process later during review.
```
User: "Capture: Review Q1 budget proposal"
Action:
1. Create note in Anytype with status=inbox
2. Confirm: "Captured to inbox. 12 items pending processing."
```
### 2. Create Task
Full task with metadata for proper routing.
```
User: "Task: Prepare board presentation for CTO Leadership, high priority, due Friday"
Action:
1. Find or create "CTO Leadership" area in Anytype
2. Create task object:
- name: "Prepare board presentation"
- area: [CTO Leadership object ID]
- priority: high
- due_date: [this Friday]
- status: next
3. Confirm with task details
```
### 3. Create Project
Projects are outcomes with multiple tasks and a completion state.
```
User: "New project: Launch NixOS Flakes Course in m3ta.dev area"
Action:
1. Find "m3ta.dev" area
2. Create project object:
- name: "Launch NixOS Flakes Course"
- area: [m3ta.dev object ID]
- status: active
3. Prompt: "What are the key milestones or first tasks?"
4. Create initial tasks if provided
```
### 4. Daily Review (Evening)
Run each evening to close the day and prep tomorrow.
**Workflow** - See [references/review-templates.md](references/review-templates.md) for full template.
Steps:
1. **Fetch today's completed** - Celebrate wins
2. **Fetch incomplete tasks** - Reschedule or note blockers
3. **Check inbox** - Quick process or defer to weekly
4. **Tomorrow's priorities** - Identify top 3 for morning focus
5. **Send summary via ntfy** (if configured)
```
User: "Daily review"
Output format:
## Daily Review - [Date]
### Completed Today
- [x] Task 1
- [x] Task 2
### Carried Forward
- [ ] Task 3 (rescheduled to tomorrow)
- [ ] Task 4 (blocked: waiting on X)
### Inbox Items: 5 pending
### Tomorrow's Top 3
1. [Highest impact task]
2. [Second priority]
3. [Third priority]
```
### 5. Weekly Review
Comprehensive PARA review. See [references/para-methodology.md](references/para-methodology.md).
**Workflow**:
1. **Get Clear** - Process inbox to zero
2. **Get Current** - Review each Area's active projects
3. **Get Creative** - Identify new projects or opportunities
4. **Plan Week** - Set weekly outcomes and time blocks
```
User: "Weekly review"
Process:
1. List all inbox items -> prompt to process each
2. For each Area, show active projects and their status
3. Flag stalled projects (no activity 7+ days)
4. Identify completed projects -> move to archive
5. Prompt for new commitments
6. Output weekly plan
```
### 6. Priority Focus
Impact-first prioritization using Sascha's preferences.
```
User: "What should I focus on?"
Logic:
1. Fetch tasks where status=next, sorted by:
- priority (critical > high > medium > low)
- due_date (sooner first)
- energy match (if time of day known)
2. Return top 3-5 with rationale
3. Consider context batching opportunities
Output:
## Focus Recommendations
**Top Priority**: [Task]
- Why: [Impact statement]
- Area: [Area name]
- Due: [Date or "no deadline"]
**Also Important**:
1. [Task 2] - [brief why]
2. [Task 3] - [brief why]
**Batching Opportunity**: You have 3 [context] tasks that could be done together.
```
### 7. Context Batching
Group similar tasks for focused execution.
```
User: "What admin tasks can I batch?"
Action:
1. Fetch tasks where context contains "admin"
2. Group by area
3. Estimate total time
4. Suggest execution order
Output:
## Admin Task Batch
**Estimated time**: ~45 minutes
1. [ ] Reply to vendor email (CTO Leadership) - 10min
2. [ ] Approve expense reports (CTO Leadership) - 15min
3. [ ] Update team wiki (CTO Leadership) - 20min
Ready to start? I can track completion.
```
## Notification Integration (ntfy)
Send notifications for:
- Daily review summary (evening)
- Overdue task alerts
- Weekly review reminder (Sunday evening)
Format for ntfy:
```bash
curl -d "Daily Review: 5 completed, 3 for tomorrow. Top priority: [task]" \
ntfy.sh/sascha-chiron
```
Configure topic in environment or Anytype settings.
## Anytype API Patterns
See [references/anytype-workflows.md](references/anytype-workflows.md) for:
- Space and type setup
- CRUD operations for tasks/projects
- Query patterns for reviews
- Batch operations
## PARA Methodology Reference
See [references/para-methodology.md](references/para-methodology.md) for:
- PARA category definitions
- When to use Projects vs Areas
- Archive criteria
- Maintenance rhythms
## Initial Setup
See [references/anytype-setup.md](references/anytype-setup.md) for:
- Step-by-step Anytype space creation
- Type and property configuration
- Initial Area objects to create
- View setup recommendations

View File

@@ -1,176 +0,0 @@
# Anytype Space Setup Guide
Manual setup for the Chiron space in Anytype.
## Step 1: Create Space
1. Open Anytype desktop app
2. Click **+** to create new space
3. Name: **Chiron**
4. Description: *Personal AI Assistant workspace using PARA methodology*
## Step 2: Create Types
Create these object types in the Chiron space:
### Area Type
- **Name**: Area
- **Plural**: Areas
- **Layout**: Basic
- **Icon**: Briefcase (blue)
### Project Type
- **Name**: Project
- **Plural**: Projects
- **Layout**: Basic
- **Icon**: Rocket (purple)
### Task Type
- **Name**: Task
- **Plural**: Tasks
- **Layout**: Action (checkbox)
- **Icon**: Checkbox (blue)
### Resource Type
- **Name**: Resource
- **Plural**: Resources
- **Layout**: Basic
- **Icon**: Book (teal)
## Step 3: Create Properties
Add these properties (relations) to the space:
### Status (Select)
| Tag | Color |
|-----|-------|
| Inbox | Grey |
| Next | Blue |
| Waiting | Yellow |
| Scheduled | Purple |
| Done | Lime |
### Priority (Select)
| Tag | Color |
|-----|-------|
| Critical | Red |
| High | Orange |
| Medium | Yellow |
| Low | Grey |
### Energy (Select)
| Tag | Color |
|-----|-------|
| High | Red |
| Medium | Yellow |
| Low | Blue |
### Context (Multi-select)
| Tag | Color |
|-----|-------|
| Deep Work | Purple |
| Admin | Grey |
| Calls | Blue |
| Errands | Teal |
| Quick Wins | Lime |
### Other Properties
- **Area** (Relation → Area type)
- **Project** (Relation → Project type)
- **Due Date** (Date)
- **Outcome** (Text)
- **Description** (Text)
## Step 4: Link Properties to Types
### Task Type Properties
- Status
- Priority
- Energy
- Context
- Area (relation)
- Project (relation)
- Due Date
### Project Type Properties
- Status
- Priority
- Area (relation)
- Due Date
- Outcome
### Area Type Properties
- Description
## Step 5: Create Initial Areas
Create these Area objects:
1. **CTO Leadership**
- Description: Team management, technical strategy, architecture decisions, hiring
2. **m3ta.dev**
- Description: Content creation, courses, coaching, tutoring programs
3. **YouTube @m3tam3re**
- Description: Technical exploration videos, tutorials, self-hosting guides
4. **Technical Exploration**
- Description: NixOS, self-hosting, AI agents, automation experiments
5. **Personal Development**
- Description: Learning, skills growth, reading
6. **Health & Wellness**
- Description: Exercise, rest, sustainability
7. **Family**
- Description: Quality time, responsibilities
## Step 6: Create Views (Optional)
Create these Set views for quick access:
### Inbox View
- Filter: Status = Inbox
- Sort: Created date (newest)
### Today's Focus
- Filter: Status = Next AND Due Date <= Today
- Sort: Priority (Critical first)
### By Area
- Group by: Area relation
- Filter: Status != Done
### Weekly Review
- Filter: Status != Done
- Group by: Area
- Sort: Due Date
## Step 7: API Setup (For Automation)
To enable API access for Chiron agent:
1. Go to Anytype settings
2. Find API/Integration settings
3. Generate API key
4. Configure in your environment or MCP settings
Without API access, use manual workflows or n8n integration.
## Verification
After setup, you should have:
- [ ] Chiron space created
- [ ] 4 custom types (Area, Project, Task, Resource)
- [ ] 4 select properties (Status, Priority, Energy, Context)
- [ ] 3 relation properties (Area, Project, Due Date)
- [ ] 7 Area objects created
- [ ] At least one view configured
## Notes
- The Note type is built-in, use it for quick captures
- Archive can be a status tag or separate type (your preference)
- Adjust colors and icons to your preference

View File

@@ -1,346 +0,0 @@
# Anytype API Workflows
API patterns for task management operations in the Chiron space.
## Setup
### Space Configuration
**Space Name**: Chiron
**Space ID**: Retrieve via `Anytype_API-list-spaces` after creation
```
# List spaces to find Chiron space ID
Anytype_API-list-spaces
# Store space_id for subsequent calls
SPACE_ID="<chiron-space-id>"
```
### Required Types
Create these types if they don't exist:
#### Area Type
```
Anytype_API-create-type
space_id: SPACE_ID
name: "Area"
plural_name: "Areas"
layout: "basic"
key: "area"
properties:
- name: "Description", key: "description", format: "text"
- name: "Review Frequency", key: "review_frequency", format: "select"
```
#### Project Type
```
Anytype_API-create-type
space_id: SPACE_ID
name: "Project"
plural_name: "Projects"
layout: "basic"
key: "project"
properties:
- name: "Status", key: "status", format: "select"
- name: "Priority", key: "priority", format: "select"
- name: "Area", key: "area", format: "objects"
- name: "Due Date", key: "due_date", format: "date"
- name: "Outcome", key: "outcome", format: "text"
```
#### Task Type
```
Anytype_API-create-type
space_id: SPACE_ID
name: "Task"
plural_name: "Tasks"
layout: "action"
key: "task"
properties:
- name: "Status", key: "status", format: "select"
- name: "Priority", key: "priority", format: "select"
- name: "Area", key: "area", format: "objects"
- name: "Project", key: "project", format: "objects"
- name: "Due Date", key: "due_date", format: "date"
- name: "Energy", key: "energy", format: "select"
- name: "Context", key: "context", format: "multi_select"
```
### Required Properties with Tags
#### Status Property Tags
```
Anytype_API-create-property
space_id: SPACE_ID
name: "Status"
key: "status"
format: "select"
tags:
- name: "Inbox", color: "grey"
- name: "Next", color: "blue"
- name: "Waiting", color: "yellow"
- name: "Scheduled", color: "purple"
- name: "Done", color: "lime"
```
#### Priority Property Tags
```
Anytype_API-create-property
space_id: SPACE_ID
name: "Priority"
key: "priority"
format: "select"
tags:
- name: "Critical", color: "red"
- name: "High", color: "orange"
- name: "Medium", color: "yellow"
- name: "Low", color: "grey"
```
#### Energy Property Tags
```
Anytype_API-create-property
space_id: SPACE_ID
name: "Energy"
key: "energy"
format: "select"
tags:
- name: "High", color: "red"
- name: "Medium", color: "yellow"
- name: "Low", color: "blue"
```
#### Context Property Tags
```
Anytype_API-create-property
space_id: SPACE_ID
name: "Context"
key: "context"
format: "multi_select"
tags:
- name: "Deep Work", color: "purple"
- name: "Admin", color: "grey"
- name: "Calls", color: "blue"
- name: "Errands", color: "teal"
- name: "Quick Wins", color: "lime"
```
## CRUD Operations
### Create Task
```
Anytype_API-create-object
space_id: SPACE_ID
type_key: "task"
name: "Task title here"
body: "Optional task description or notes"
properties:
- key: "status", select: "<status_tag_id>"
- key: "priority", select: "<priority_tag_id>"
- key: "area", objects: ["<area_object_id>"]
- key: "due_date", date: "2025-01-10"
icon:
format: "icon"
name: "checkbox"
color: "blue"
```
### Create Project
```
Anytype_API-create-object
space_id: SPACE_ID
type_key: "project"
name: "Project title"
body: "Project description and goals"
properties:
- key: "status", select: "<active_tag_id>"
- key: "area", objects: ["<area_object_id>"]
- key: "outcome", text: "What done looks like"
icon:
format: "icon"
name: "rocket"
color: "purple"
```
### Create Area
```
Anytype_API-create-object
space_id: SPACE_ID
type_key: "area"
name: "CTO Leadership"
body: "Team management, technical strategy, architecture decisions"
properties:
- key: "description", text: "Standards: Team health, technical excellence, strategic alignment"
- key: "review_frequency", select: "<weekly_tag_id>"
icon:
format: "icon"
name: "briefcase"
color: "blue"
```
### Quick Capture (Inbox)
```
Anytype_API-create-object
space_id: SPACE_ID
type_key: "note"
name: "Quick capture content here"
properties:
- key: "status", select: "<inbox_tag_id>"
icon:
format: "icon"
name: "mail"
color: "grey"
```
### Update Task Status
```
Anytype_API-update-object
space_id: SPACE_ID
object_id: "<task_object_id>"
properties:
- key: "status", select: "<done_tag_id>"
```
## Query Patterns
### Get All Tasks for Today
```
Anytype_API-search-space
space_id: SPACE_ID
types: ["task"]
filters:
operator: "and"
conditions:
- property_key: "status"
select: "<next_tag_id>"
- property_key: "due_date"
date: "2025-01-05"
condition: "le"
```
### Get Inbox Items
```
Anytype_API-search-space
space_id: SPACE_ID
filters:
operator: "and"
conditions:
- property_key: "status"
select: "<inbox_tag_id>"
sort:
property_key: "created_date"
direction: "desc"
```
### Get Tasks by Area
```
Anytype_API-search-space
space_id: SPACE_ID
types: ["task"]
filters:
operator: "and"
conditions:
- property_key: "area"
objects: ["<area_object_id>"]
- property_key: "status"
condition: "nempty"
```
### Get Active Projects
```
Anytype_API-search-space
space_id: SPACE_ID
types: ["project"]
filters:
conditions:
- property_key: "status"
select: "<active_tag_id>"
```
### Get Overdue Tasks
```
Anytype_API-search-space
space_id: SPACE_ID
types: ["task"]
filters:
operator: "and"
conditions:
- property_key: "due_date"
date: "<today>"
condition: "lt"
- property_key: "status"
condition: "nempty"
```
### Get Tasks by Context
```
Anytype_API-search-space
space_id: SPACE_ID
types: ["task"]
filters:
conditions:
- property_key: "context"
multi_select: ["<deep_work_tag_id>"]
- property_key: "status"
select: "<next_tag_id>"
```
## Batch Operations
### Complete Multiple Tasks
```python
# Pseudocode for batch completion
task_ids = ["id1", "id2", "id3"]
done_tag_id = "<done_tag_id>"
for task_id in task_ids:
Anytype_API-update-object(
space_id=SPACE_ID,
object_id=task_id,
properties=[{"key": "status", "select": done_tag_id}]
)
```
### Archive Completed Projects
```
# 1. Find completed projects
Anytype_API-search-space
space_id: SPACE_ID
types: ["project"]
filters:
conditions:
- property_key: "status"
select: "<completed_tag_id>"
# 2. For each, update to archived status or move to archive
```
## Error Handling
| Error | Cause | Solution |
|-------|-------|----------|
| 401 Unauthorized | Missing/invalid auth | Check API key configuration |
| 404 Not Found | Invalid space/object ID | Verify IDs with list operations |
| 400 Bad Request | Invalid property format | Check property types match expected format |
## Notes
- Always retrieve space_id fresh via `list-spaces` before operations
- Tag IDs must be retrieved via `list-tags` for the specific property
- Object relations require the target object's ID, not name
- Dates use ISO 8601 format: `2025-01-05` or `2025-01-05T18:00:00Z`

View File

@@ -1,190 +0,0 @@
# PARA Methodology Reference
PARA is a universal system for organizing digital information, created by Tiago Forte.
## The Four Categories
### Projects
**Definition**: A series of tasks linked to a goal, with a deadline.
**Characteristics**:
- Has a clear outcome/deliverable
- Has a deadline (explicit or implicit)
- Requires multiple tasks to complete
- Can be completed (finite)
**Examples**:
- Launch NixOS Flakes course
- Hire senior backend developer
- Complete Q1 board presentation
- Publish self-hosting playbook video
**Questions to identify**:
- What am I committed to finishing?
- What has a deadline?
- What would I celebrate completing?
### Areas
**Definition**: A sphere of activity with a standard to be maintained over time.
**Characteristics**:
- Ongoing responsibility (infinite)
- Has standards, not deadlines
- Requires regular attention
- Never "complete" - only maintained
**Sascha's Areas**:
1. CTO Leadership
2. m3ta.dev
3. YouTube @m3tam3re
4. Technical Exploration
5. Personal Development
6. Health & Wellness
7. Family
**Questions to identify**:
- What roles do I maintain?
- What standards must I uphold?
- What would suffer if I ignored it?
### Resources
**Definition**: A topic or theme of ongoing interest.
**Characteristics**:
- Reference material for future use
- No immediate action required
- Supports projects and areas
- Can be shared or reused
**Examples**:
- NixOS configuration patterns
- n8n workflow templates
- Self-hosting architecture docs
- AI prompt libraries
- Book notes and highlights
**Questions to identify**:
- What might be useful later?
- What do I want to learn more about?
- What reference material do I need?
### Archives
**Definition**: Inactive items from the other three categories.
**Characteristics**:
- Completed projects
- Areas no longer active
- Resources no longer relevant
- Preserved for reference, not action
**When to archive**:
- Project completed or cancelled
- Role/responsibility ended
- Topic no longer relevant
- Information outdated
## The PARA Workflow
### Capture
Everything starts in the **Inbox**. Don't organize during capture.
### Clarify
Ask: "Is this actionable?"
- **Yes** → Is it a single task or a project?
- **No** → Is it reference material or trash?
### Organize
Place items in the appropriate category:
- Active work → Projects (linked to Area)
- Ongoing standards → Areas
- Reference → Resources
- Done/irrelevant → Archives
### Review
- **Daily**: Process inbox, check today's tasks
- **Weekly**: Review all projects, check areas, process resources
- **Monthly**: Archive completed, assess areas, audit resources
## Project vs Area Confusion
The most common PARA mistake is confusing projects and areas.
| If you treat a Project as an Area | If you treat an Area as a Project |
|-----------------------------------|-----------------------------------|
| Never feels "done" | Feels like constant failure |
| Scope creeps infinitely | Standards slip without noticing |
| No sense of progress | Burnout from "finishing" the infinite |
**Test**: Can I complete this in a single work session series?
- Yes → Project
- No, it's ongoing → Area
## Maintenance Rhythms
### Daily (Evening - 10 min)
1. Process inbox items
2. Review completed tasks
3. Set tomorrow's priorities
### Weekly (Sunday evening - 30 min)
1. Get clear: Inbox to zero
2. Get current: Review each Area
3. Review all active Projects
4. Plan next week's outcomes
### Monthly (First Sunday - 60 min)
1. Review Area standards
2. Archive completed Projects
3. Evaluate stalled Projects
4. Audit Resources relevance
### Quarterly (90 min)
1. Review life Areas balance
2. Set quarterly outcomes
3. Major archives cleanup
4. System improvements
## PARA in Anytype
### Type Mapping
| PARA | Anytype Type | Notes |
|------|--------------|-------|
| Project | `project` | Has area relation, deadline |
| Area | `area` | Top-level organization |
| Resource | `resource` | Reference material |
| Archive | Use `archived` property | Or separate Archive type |
| Task | `task` | Lives within Project or Area |
| Inbox | `note` with status=inbox | Quick capture |
### Recommended Properties
**On Projects**:
- `area` (relation) - Which area owns this
- `status` (select) - active, on-hold, completed
- `due_date` (date) - Target completion
- `outcome` (text) - What does "done" look like
**On Tasks**:
- `project` or `area` (relation) - Parent container
- `status` (select) - inbox, next, waiting, scheduled, done
- `priority` (select) - critical, high, medium, low
- `due_date` (date) - When it's needed
- `energy` (select) - Required energy level
- `context` (multi_select) - Where/how it can be done
**On Areas**:
- `description` (text) - Standards to maintain
- `review_frequency` (select) - daily, weekly, monthly
## Common Pitfalls
1. **Over-organizing during capture** - Just dump it in inbox
2. **Too many projects** - Active projects should be <15
3. **Orphan tasks** - Every task needs a project or area
4. **Stale resources** - Archive what you haven't touched in 6 months
5. **Skipping reviews** - The system only works if you review it

View File

@@ -1,307 +0,0 @@
# Review Templates
Structured templates for daily and weekly reviews.
## Daily Review Template (Evening)
**Duration**: 10-15 minutes
**Best time**: Evening, after work concludes
### Script
```
## Daily Review - [DATE]
### Wins Today
[List completed tasks - celebrate progress]
- [x]
- [x]
- [x]
### Still Open
[Tasks started but not finished]
- [ ] [Task] - [Status/blocker]
- [ ] [Task] - [Rescheduled to: DATE]
### Inbox Check
- Items in inbox: [COUNT]
- Quick processing:
- [Item] → [Action: task/project/trash/defer]
### Energy Assessment
- How was today's energy? [High/Medium/Low]
- What drained energy?
- What boosted energy?
### Tomorrow's Top 3
[Most impactful tasks for tomorrow - set before sleeping]
1. **[TASK]** - Why: [impact reason]
2. **[TASK]** - Why: [impact reason]
3. **[TASK]** - Why: [impact reason]
### Blockers to Address
- [Blocker] - Need: [what's needed to unblock]
### Notes for Tomorrow
[Anything to remember, context to preserve]
---
Review completed at: [TIME]
```
### Daily Review Checklist
- [ ] Review calendar for tomorrow
- [ ] Check completed tasks
- [ ] Process any urgent inbox items
- [ ] Identify top 3 priorities
- [ ] Note any blockers
- [ ] Clear desk/workspace (physical reset)
## Weekly Review Template
**Duration**: 30-45 minutes
**Best time**: Sunday evening or Friday afternoon
### Script
```
## Weekly Review - Week of [DATE]
### Part 1: Get Clear (Capture)
#### Inbox Processing
- Starting inbox count: [COUNT]
- Process each item:
- [Item] → [Destination: project/area/resource/trash]
- Ending inbox count: [TARGET: 0]
#### Loose Ends
- Notes to process:
- Voice memos:
- Screenshots/photos:
- Browser tabs to close:
- Email to archive:
### Part 2: Get Current (Review)
#### Area Review
**CTO Leadership**
- Active projects: [list]
- Stalled items: [list]
- Standards check: [On track / Needs attention]
- Next week focus:
**m3ta.dev**
- Active projects: [list]
- Content pipeline:
- Next week focus:
**YouTube @m3tam3re**
- Active projects: [list]
- Upload schedule:
- Next week focus:
**Technical Exploration**
- Current experiments:
- Learning goals:
- Next week focus:
**Personal Development**
- Current focus:
- Progress:
- Next week focus:
**Health & Wellness**
- This week: [assessment]
- Next week intention:
**Family**
- Quality time this week:
- Next week plans:
#### Project Status
| Project | Area | Status | Next Action | Due |
|---------|------|--------|-------------|-----|
| [Name] | [Area] | [On track/Stalled/Blocked] | [Next step] | [Date] |
#### Waiting For
[Items waiting on others]
| Item | Waiting On | Since | Follow-up Date |
|------|-----------|-------|----------------|
| | | | |
### Part 3: Get Creative (Reflect)
#### What Worked This Week?
-
#### What Didn't Work?
-
#### New Ideas/Projects
[Don't commit yet - just capture]
-
#### Should I Start?
[New projects to consider]
-
#### Should I Stop?
[Projects or commitments to drop]
-
#### Should I Continue?
[Projects going well]
-
### Part 4: Plan Next Week
#### Weekly Outcomes
[3-5 specific outcomes for the week]
1. [ ]
2. [ ]
3. [ ]
4. [ ]
5. [ ]
#### Time Blocks
[Protect time for deep work]
| Day | Block | Focus |
|-----|-------|-------|
| Mon | | |
| Tue | | |
| Wed | | |
| Thu | | |
| Fri | | |
#### Key Meetings
-
#### Week Theme (Optional)
[One word or phrase to guide the week]
---
Review completed at: [TIME]
Next weekly review: [DATE]
```
### Weekly Review Checklist
- [ ] Close all browser tabs
- [ ] Process email inbox to zero
- [ ] Process Anytype inbox to zero
- [ ] Review each Area
- [ ] Check all active Projects
- [ ] Review Waiting For list
- [ ] Clear completed tasks
- [ ] Archive finished projects
- [ ] Set weekly outcomes
- [ ] Block deep work time
- [ ] Review calendar for the week
## Monthly Review Template
**Duration**: 60 minutes
**Best time**: First Sunday of the month
### Script
```
## Monthly Review - [MONTH YEAR]
### Month Metrics
- Projects completed: [COUNT]
- Projects started: [COUNT]
- Tasks completed: [COUNT]
- Inbox avg items: [COUNT]
### Area Deep Dive
[For each Area, rate 1-10 and note]
| Area | Rating | Notes | Action |
|------|--------|-------|--------|
| CTO Leadership | /10 | | |
| m3ta.dev | /10 | | |
| YouTube | /10 | | |
| Tech Exploration | /10 | | |
| Personal Dev | /10 | | |
| Health | /10 | | |
| Family | /10 | | |
### Project Archive
[Projects completed this month → Archive]
-
### Stalled Projects
[No progress in 30+ days - decide: continue, pause, or kill]
| Project | Days Stalled | Decision |
|---------|--------------|----------|
| | | |
### Resource Audit
[Resources not accessed in 3+ months - archive or keep?]
-
### System Improvements
[What's not working in the system?]
-
### Next Month Focus
[Top 3 priorities for the month]
1.
2.
3.
---
Review completed at: [TIME]
Next monthly review: [DATE]
```
## ntfy Notification Templates
### Daily Review Summary
```
Daily Review Complete
Completed: [X] tasks
Tomorrow's Top 3:
1. [Task 1]
2. [Task 2]
3. [Task 3]
Inbox: [X] items pending
```
### Weekly Review Reminder
```
Weekly Review Reminder
Time for your weekly review!
Start here: "weekly review"
```
### Overdue Alert
```
Overdue Tasks Alert
[X] tasks past due date:
- [Task 1] (due [DATE])
- [Task 2] (due [DATE])
Review now: "show overdue"
```

View File

@@ -0,0 +1,509 @@
---
name: agent-development
description: "(opencode - Skill) Create and configure agents for Opencode. Use when: (1) creating a new agent, (2) adding agents to agents.json or opencode.json, (3) configuring agent permissions, (4) setting up primary vs subagent modes, (5) writing agent system prompts, (6) understanding agent triggering. Triggers: create agent, add agent, agents.json, subagent, primary agent, agent permissions, agent configuration, agent prompt."
compatibility: opencode
---
# Agent Development for Opencode
## Overview
Agents are specialized AI assistants configured for specific tasks and workflows. Opencode supports two agent types with different configuration formats.
### Agent Types
| Type | Description | Invocation |
|------|-------------|------------|
| **Primary** | Main assistants for direct interaction | Tab key to cycle, or configured keybind |
| **Subagent** | Specialized assistants for delegated tasks | Automatically by primary agents, or @ mention |
**Built-in agents:**
- `build` (primary) - Full development with all tools enabled
- `plan` (primary) - Analysis/planning with edit/bash requiring approval
- `general` (subagent) - Multi-step tasks with full tool access
- `explore` (subagent) - Fast, read-only codebase exploration
### Configuration Formats
Agents can be defined in two formats. Ask the user which format they prefer; default to **JSON** if no preference stated.
**Format 1: JSON** (recommended for central management)
- In `opencode.json` under the `agent` key
- Or standalone `agents.json` file
- Best for: version control, Nix flake consumption, central configuration
**Format 2: Markdown** (for quick addition)
- Global: `~/.config/opencode/agents/*.md`
- Per-project: `.opencode/agents/*.md`
- Best for: project-specific agents, quick prototyping
## JSON Agent Structure
### In opencode.json
```json
{
"$schema": "https://opencode.ai/config.json",
"agent": {
"agent-name": {
"description": "When to use this agent",
"mode": "primary",
"model": "provider/model-id",
"prompt": "{file:./prompts/agent-name.txt}",
"permission": { ... },
"tools": { ... }
}
}
}
```
### Standalone agents.json
```json
{
"agent-name": {
"description": "When to use this agent",
"mode": "subagent",
"model": "anthropic/claude-sonnet-4-20250514",
"prompt": "You are an expert...",
"tools": {
"write": false,
"edit": false
}
}
}
```
## Markdown Agent Structure
File: `~/.config/opencode/agents/agent-name.md` or `.opencode/agents/agent-name.md`
```markdown
---
description: When to use this agent
mode: subagent
model: anthropic/claude-sonnet-4-20250514
temperature: 0.1
tools:
write: false
edit: false
bash: false
permission:
bash:
"*": ask
"git diff": allow
---
You are an expert [role]...
**Your Core Responsibilities:**
1. [Responsibility 1]
2. [Responsibility 2]
```
The filename becomes the agent name (e.g., `review.md``review` agent).
## Configuration Options
### description (required)
Defines when Opencode should use this agent. Critical for subagent triggering.
```json
"description": "Reviews code for best practices and security issues"
```
### mode
Controls how the agent can be used.
| Value | Behavior |
|-------|----------|
| `primary` | Directly accessible via Tab cycling |
| `subagent` | Invoked by Task tool or @ mention |
| `all` | Both (default if omitted) |
```json
"mode": "primary"
```
**IMPORTANT**: Always explicitly set the `mode` field for clarity:
- Primary agents: `"mode": "primary"`
- Subagents: `"mode": "subagent"`
- Avoid relying on defaults; explicit declaration makes intent clear and follows best practices
### model
Override the model for this agent. Format: `provider/model-id`.
```json
"model": "anthropic/claude-sonnet-4-20250514"
```
If omitted: primary agents use globally configured model; subagents inherit from invoking primary agent.
### prompt
System prompt defining agent behavior. Can be inline or file reference.
**Inline:**
```json
"prompt": "You are an expert code reviewer..."
```
**File reference:**
```json
"prompt": "{file:./prompts/agent-name.txt}"
```
File paths are relative to the config file location.
### temperature
Control response randomness (0.0 - 1.0).
| Range | Use Case |
|-------|----------|
| 0.0-0.2 | Focused, deterministic (code analysis, planning, research) |
| 0.3-0.5 | Balanced (general development, writing) |
| 0.6-1.0 | Creative (brainstorming, ideation) |
```json
"temperature": 0.1
```
**RECOMMENDATIONS BY AGENT TYPE:**
- **Research/Analysis**: 0.0-0.2 (focused, deterministic, consistent results)
- **Code Generation**: 0.1-0.3 (precise but allows slight creativity)
- **Code Review**: 0.0-0.2 (strict adherence to patterns)
- **Brainstorming/Creative**: 0.6-1.0 (explore many options)
- **General Purpose**: 0.3-0.5 (balanced approach)
### maxSteps
Limit agentic iterations before forcing text-only response.
```json
"maxSteps": 10
```
### tools
Control which tools are available. Boolean to enable/disable, or object for granular control.
**Disable specific tools:**
```json
"tools": {
"write": false,
"edit": false,
"bash": false
}
```
**Wildcard for MCP tools:**
```json
"tools": {
"mymcp_*": false
}
```
### hidden
Hide subagent from @ autocomplete menu. Agent can still be invoked via Task tool.
```json
"hidden": true
```
### disable
Disable the agent entirely.
```json
"disable": true
```
## Permissions System
Permissions control what actions require approval. Each rule resolves to:
- `"allow"` - Run without approval
- `"ask"` - Prompt for approval
- `"deny"` - Block the action
### Permission Types
| Permission | Matches Against |
|------------|-----------------|
| `read` | File path |
| `edit` | File path (covers edit, write, patch, multiedit) |
| `bash` | Parsed command |
| `task` | Subagent type |
| `external_directory` | Paths outside project |
| `doom_loop` | Repeated identical tool calls |
### Simple Permissions
```json
"permission": {
"edit": "ask",
"bash": "ask"
}
```
### Granular Permissions with Glob Patterns
Rules evaluated in order; **last matching rule wins**.
```json
"permission": {
"read": {
"*": "allow",
"*.env": "deny",
"*.env.*": "deny",
"*.env.example": "allow"
},
"bash": {
"*": "ask",
"git status*": "allow",
"git log*": "allow",
"git diff*": "allow",
"rm *": "ask",
"sudo *": "deny"
},
"edit": "allow",
"external_directory": "ask",
"doom_loop": "ask"
}
```
### Task Permissions (Subagent Control)
Control which subagents an agent can invoke via Task tool.
```json
"permission": {
"task": {
"*": "deny",
"code-reviewer": "allow",
"test-generator": "ask"
}
}
```
## Complete JSON Example
```json
{
"chiron": {
"description": "Personal AI assistant (Plan Mode). Read-only analysis and planning.",
"mode": "primary",
"model": "anthropic/claude-sonnet-4-20250514",
"prompt": "{file:./prompts/chiron.txt}",
"permission": {
"read": {
"*": "allow",
"*.env": "deny",
"*.env.*": "deny",
"*.env.example": "allow",
"*/.ssh/*": "deny",
"*credentials*": "deny"
},
"edit": "ask",
"bash": "ask",
"external_directory": "ask"
}
},
"chiron-forge": {
"description": "Personal AI assistant (Worker Mode). Full write access.",
"mode": "primary",
"model": "anthropic/claude-sonnet-4-20250514",
"prompt": "{file:./prompts/chiron-forge.txt}",
"permission": {
"read": {
"*": "allow",
"*.env": "deny"
},
"edit": "allow",
"bash": {
"*": "allow",
"rm *": "ask",
"git push *": "ask",
"sudo *": "deny"
}
}
},
"code-reviewer": {
"description": "Reviews code for quality, security, and best practices",
"mode": "subagent",
"model": "anthropic/claude-sonnet-4-20250514",
"temperature": 0.1,
"tools": {
"write": false,
"edit": false
},
"prompt": "You are an expert code reviewer..."
}
}
```
## System Prompt Design
Write prompts in second person, addressing the agent directly.
### Standard Structure
```
You are [role] specializing in [domain].
**Your Core Responsibilities:** ← USE THIS EXACT HEADER
1. [Primary responsibility]
2. [Secondary responsibility]
3. [Additional responsibilities]
**Process:**
1. [Step one]
2. [Step two]
3. [Continue with clear steps]
**Quality Standards:**
- [Standard 1]
- [Standard 2]
**Output Format:**
[What to include and how to structure]
**Edge Cases:**
- [Edge case 1]: [How to handle]
- [Edge case 2]: [How to handle]
```
**IMPORTANT**: Use exact section headers for consistency:
- Use "Your Core Responsibilities:" (not "capabilities", "duties", etc.)
- Use "Process:" for step-by-step workflows
- Use "Quality Standards:" for evaluation criteria
- Use "Output Format:" for response structure
- Use "Edge Cases:" for exception handling
### Prompt File Convention
Store prompts in a `prompts/` directory with `.txt` extension:
- `prompts/agent-name.txt`
Reference in config:
```json
"prompt": "{file:./prompts/agent-name.txt}"
```
### Best Practices
**DO:**
- Use second person ("You are...", "You will...")
- Be specific about responsibilities
- Use numbered lists for responsibilities (1, 2, 3) - not bullet points
- Provide step-by-step processes
- Define output format
- Include quality standards
- Address edge cases
- Keep under 10,000 characters
- Keep section names consistent with standard structure, but adapt if semantically equivalent (e.g., "Ethical Guidelines" vs "Quality Standards" for research agents)
**DON'T:**
- Write in first person
- Be vague or generic
- Omit process steps
- Leave output format undefined
## Creating Agents
### Method 1: Opencode CLI (Interactive)
```bash
opencode agent create
```
Prompts for: location, description, tools, then generates the agent file.
### Method 2: JSON Configuration
1. Add agent to `opencode.json` or `agents.json`
2. Create prompt file in `prompts/` directory
3. Validate with: `python3 -c "import json; json.load(open('agents.json'))"` for syntax check
### Method 3: Markdown File
1. Create `~/.config/opencode/agents/agent-name.md` or `.opencode/agents/agent-name.md`
2. Add frontmatter with configuration
3. Write system prompt as markdown body
## Validation
Validate agent configuration:
```bash
# Validate agents.json
python3 -c "import json; json.load(open('agents.json'))"
```
## Testing
1. Reload opencode or start new session
2. For primary agents: use Tab to cycle
3. For subagents: use @ mention or let primary agent invoke via Task tool
4. Verify expected behavior and tool access
## Quick Reference
### JSON Agent Template
```json
{
"my-agent": {
"description": "What this agent does and when to use it",
"mode": "subagent",
"model": "anthropic/claude-sonnet-4-20250514",
"prompt": "{file:./prompts/my-agent.txt}",
"tools": {
"write": false,
"edit": false
}
}
}
```
### Markdown Agent Template
```markdown
---
description: What this agent does and when to use it
mode: subagent
model: anthropic/claude-sonnet-4-20250514
tools:
write: false
edit: false
---
You are an expert [role]...
```
### Configuration Options Summary
| Option | Required | Type | Default |
|--------|----------|------|---------|
| description | Yes | string | - |
| mode | No | primary/subagent/all | all |
| model | No | string | inherited |
| prompt | No | string | - |
| temperature | No | number | model default |
| maxSteps | No | number | unlimited |
| tools | No | object/boolean | all enabled |
| permission | No | object | allow |
| hidden | No | boolean | false |
| disable | No | boolean | false |
## Additional Resources
- **System prompt patterns**: See `references/system-prompt-design.md`
- **Triggering examples**: See `references/triggering-examples.md`
- **AI-assisted generation**: See `examples/agent-creation-prompt.md`
- **Complete examples**: See `examples/complete-agent-examples.md`
- **Real-world JSON example**: See `references/opencode-agents-json-example.md`

View File

@@ -0,0 +1,219 @@
# AI-Assisted Agent Generation
Use this template to generate agent configurations using AI assistance.
## Quick Start
### Step 1: Describe Your Agent
Think about:
- What task should the agent handle?
- Primary (Tab-cycleable) or subagent (delegated)?
- Should it modify files or be read-only?
- What permissions does it need?
### Step 2: Use the Generation Prompt
Send to Opencode:
```
Create an agent configuration: "[YOUR DESCRIPTION]"
Requirements:
1. Determine if this should be primary or subagent
2. Select appropriate model and temperature
3. Configure tool access (write, edit, bash)
4. Set permissions for dangerous operations
5. Write comprehensive system prompt
Return JSON format for agents.json:
{
"agent-name": {
"description": "...",
"mode": "...",
"model": "...",
"temperature": ...,
"prompt": "{file:./prompts/agent-name.txt}",
"tools": { ... },
"permission": { ... }
}
}
Also provide the system prompt content separately.
```
### Step 3: Add to Configuration
**Option A: JSON (recommended)**
Add to `agents.json` or `opencode.json`:
```json
{
"agent": {
"your-agent": {
...generated config...
}
}
}
```
Save system prompt to `prompts/your-agent.txt`.
**Option B: Markdown**
Create `~/.config/opencode/agents/your-agent.md`:
```markdown
---
description: ...
mode: subagent
model: ...
temperature: ...
tools:
write: false
edit: false
---
[System prompt content]
```
## Example Requests
### Code Review Agent
```
Create an agent configuration: "I need a subagent that reviews code changes for quality issues, security vulnerabilities, and adherence to best practices. It should be read-only and provide structured feedback with file:line references."
```
### Test Generator Agent
```
Create an agent configuration: "I need a subagent that generates comprehensive unit tests. It should analyze existing code, identify test cases, and create test files following project conventions. Needs write access but should be careful with bash commands."
```
### Planning Agent
```
Create an agent configuration: "I need a primary agent for analysis and planning. It should never modify files, only read and suggest. Use it when investigating issues or designing solutions before implementation."
```
### Security Analyzer
```
Create an agent configuration: "I need a subagent that performs security audits on code. It should identify OWASP vulnerabilities, check auth logic, and provide remediation guidance. Read-only but needs bash for git commands."
```
## Configuration Decisions
### Primary vs Subagent
| Scenario | Mode |
|----------|------|
| Direct user interaction, Tab-cycleable | primary |
| Delegated by other agents via Task tool | subagent |
| User invokes with @ mention | subagent |
| Specialized single-purpose task | subagent |
| General workflow mode | primary |
### Model Selection
| Complexity | Model |
|------------|-------|
| Simple, fast tasks | claude-haiku-4 |
| General tasks (default) | claude-sonnet-4 |
| Complex reasoning | claude-opus-4 |
### Temperature
| Task Type | Temperature |
|-----------|-------------|
| Deterministic analysis | 0.0 - 0.1 |
| Balanced (default) | 0.2 - 0.3 |
| Creative tasks | 0.4 - 0.6 |
### Tool Access
| Agent Purpose | write | edit | bash |
|---------------|-------|------|------|
| Read-only analysis | false | false | true |
| Code generation | true | true | true |
| Documentation | true | true | false |
| Testing/validation | false | false | true |
### Permission Patterns
**Restrictive (read-only):**
```json
"permission": {
"edit": "deny",
"bash": {
"*": "ask",
"git *": "allow",
"ls *": "allow",
"grep *": "allow"
}
}
```
**Careful writer:**
```json
"permission": {
"edit": "allow",
"bash": {
"*": "allow",
"rm *": "ask",
"git push*": "ask",
"sudo *": "deny"
}
}
```
## Validation
After creating your agent:
1. Reload opencode or start new session
2. For primary: Tab to cycle to your agent
3. For subagent: Use @ mention or let primary invoke
4. Test typical use cases
5. Verify tool access works as expected
## Tips for Effective Agents
### Be Specific in Requests
**Vague:**
```
"I need an agent that helps with code"
```
**Specific:**
```
"I need a subagent that reviews TypeScript code for type safety issues, checking for proper type annotations, avoiding 'any', and ensuring correct generic usage. Read-only with structured output."
```
### Include Context
```
"Create an agent for this project which uses React and TypeScript. The agent should check for React best practices and TypeScript type safety."
```
### Define Output Expectations
```
"The agent should provide specific recommendations with file:line references and estimated impact."
```
## Iterating on Agents
If the generated agent needs improvement:
1. Identify what's missing or wrong
2. Edit the agent configuration or prompt file
3. Focus on:
- Better description for triggering
- More specific process steps
- Clearer output format
- Additional edge cases
4. Test again

View File

@@ -0,0 +1,395 @@
# Complete Agent Examples
Production-ready agent examples in both JSON and Markdown formats.
## Example 1: Code Review Agent
### JSON Format (for agents.json)
```json
{
"code-reviewer": {
"description": "Reviews code for quality, security, and best practices. Invoke after implementing features or before commits.",
"mode": "subagent",
"model": "anthropic/claude-sonnet-4-20250514",
"temperature": 0.1,
"prompt": "{file:./prompts/code-reviewer.txt}",
"tools": {
"write": false,
"edit": false,
"bash": true
}
}
}
```
### Prompt File (prompts/code-reviewer.txt)
```
You are an expert code quality reviewer specializing in identifying issues, security vulnerabilities, and improvement opportunities.
**Your Core Responsibilities:**
1. Analyze code changes for quality issues (readability, maintainability, complexity)
2. Identify security vulnerabilities (SQL injection, XSS, authentication flaws)
3. Check adherence to project best practices and coding standards
4. Provide specific, actionable feedback with file:line references
5. Recognize and commend good practices
**Code Review Process:**
1. Gather Context: Use Glob to find recently modified files
2. Read Code: Examine changed files with Read tool
3. Analyze Quality: Check for duplication, complexity, error handling, logging
4. Security Analysis: Scan for injection, auth issues, input validation, secrets
5. Best Practices: Verify naming, test coverage, documentation
6. Categorize Issues: Group by severity (critical/major/minor)
7. Generate Report: Format according to output template
**Quality Standards:**
- Every issue includes file path and line number
- Issues categorized with clear severity criteria
- Recommendations are specific and actionable
- Include code examples in recommendations when helpful
- Balance criticism with recognition of good practices
**Output Format:**
## Code Review Summary
[2-3 sentence overview]
## Critical Issues (Must Fix)
- `src/file.ts:42` - [Issue] - [Why critical] - [Fix]
## Major Issues (Should Fix)
- `src/file.ts:15` - [Issue] - [Impact] - [Recommendation]
## Minor Issues (Consider)
- `src/file.ts:88` - [Issue] - [Suggestion]
## Positive Observations
- [Good practice 1]
## Overall Assessment
[Final verdict]
**Edge Cases:**
- No issues found: Provide positive validation, mention what was checked
- Too many issues (>20): Group by type, prioritize top 10
- Unclear code intent: Note ambiguity and request clarification
```
### Markdown Format Alternative
File: `~/.config/opencode/agents/code-reviewer.md`
```markdown
---
description: Reviews code for quality, security, and best practices. Invoke after implementing features or before commits.
mode: subagent
model: anthropic/claude-sonnet-4-20250514
temperature: 0.1
tools:
write: false
edit: false
bash: true
---
You are an expert code quality reviewer...
[Same prompt content as above]
```
## Example 2: Test Generator Agent
### JSON Format
```json
{
"test-generator": {
"description": "Generates comprehensive unit tests for code. Use after implementing new functions or when improving test coverage.",
"mode": "subagent",
"model": "anthropic/claude-sonnet-4-20250514",
"temperature": 0.2,
"prompt": "{file:./prompts/test-generator.txt}",
"tools": {
"write": true,
"edit": true,
"bash": true
}
}
}
```
### Prompt File (prompts/test-generator.txt)
```
You are an expert test engineer specializing in creating comprehensive, maintainable unit tests.
**Your Core Responsibilities:**
1. Generate high-quality unit tests with excellent coverage
2. Follow project testing conventions and patterns
3. Include happy path, edge cases, and error scenarios
4. Ensure tests are maintainable and clear
**Test Generation Process:**
1. Analyze Code: Read implementation files to understand behavior, contracts, edge cases
2. Identify Patterns: Check existing tests for framework, organization, naming
3. Design Test Cases: Happy path, boundary conditions, error cases, edge cases
4. Generate Tests: Create test file with descriptive names, AAA structure, assertions
5. Verify: Ensure tests are runnable
**Quality Standards:**
- Test names clearly describe what is being tested
- Each test focuses on single behavior
- Tests are independent (no shared state)
- Mocks used appropriately
- Edge cases and errors covered
- Follow DAMP principle (Descriptive And Meaningful Phrases)
**Output Format:**
Create test file at appropriate path:
```typescript
// Test suite for [module]
describe('[module name]', () => {
test('should [expected behavior] when [scenario]', () => {
// Arrange
// Act
// Assert
});
});
```
**Edge Cases:**
- No existing tests: Create new test file following best practices
- Existing test file: Add new tests maintaining consistency
- Untestable code: Suggest refactoring for testability
```
## Example 3: Primary Plan Agent
### JSON Format
```json
{
"plan": {
"description": "Analysis and planning without making changes. Use for investigation, design, and review.",
"mode": "primary",
"model": "anthropic/claude-opus-4-20250514",
"temperature": 0.1,
"prompt": "{file:./prompts/plan.txt}",
"tools": {
"write": false,
"edit": false,
"bash": true
},
"permission": {
"bash": {
"*": "ask",
"git status*": "allow",
"git log*": "allow",
"git diff*": "allow",
"ls *": "allow",
"cat *": "allow",
"grep *": "allow"
}
}
}
}
```
### Prompt File (prompts/plan.txt)
```
You are in Plan Mode - a read-only assistant for analysis and planning.
**Mode Constraints:**
- You CANNOT modify files
- You CANNOT write new files
- You CAN read, search, and analyze
- You CAN run read-only bash commands
**Your Core Responsibilities:**
1. Analyze code structure and patterns
2. Identify issues and improvement opportunities
3. Create detailed implementation plans
4. Explain complex code behavior
5. Suggest architectural approaches
**When asked to make changes:**
1. Acknowledge the request
2. Provide a detailed plan of what would be changed
3. Explain the rationale for each change
4. Note: "Switch to Build/Forge mode to implement these changes"
**Output for Implementation Plans:**
## Implementation Plan: [Feature/Fix Name]
### Summary
[Brief description]
### Files to Modify
1. `path/to/file.ts` - [What changes]
2. `path/to/other.ts` - [What changes]
### Implementation Steps
1. [Step with details]
2. [Step with details]
### Testing Strategy
[How to verify]
### Risks/Considerations
[Potential issues]
```
## Example 4: Security Analyzer Agent
### JSON Format
```json
{
"security-analyzer": {
"description": "Identifies security vulnerabilities and provides remediation guidance. Use for security audits or when reviewing auth/payment code.",
"mode": "subagent",
"model": "anthropic/claude-sonnet-4-20250514",
"temperature": 0.1,
"prompt": "{file:./prompts/security-analyzer.txt}",
"tools": {
"write": false,
"edit": false,
"bash": true
}
}
}
```
### Prompt File (prompts/security-analyzer.txt)
```
You are an expert security analyst specializing in identifying vulnerabilities in software implementations.
**Your Core Responsibilities:**
1. Identify security vulnerabilities (OWASP Top 10 and beyond)
2. Analyze authentication and authorization logic
3. Check input validation and sanitization
4. Verify secure data handling and storage
5. Provide specific remediation guidance
**Security Analysis Process:**
1. Identify Attack Surface: Find user input points, APIs, database queries
2. Check Common Vulnerabilities:
- Injection (SQL, command, XSS)
- Authentication/authorization flaws
- Sensitive data exposure
- Security misconfiguration
- Insecure deserialization
3. Analyze Patterns: Input validation, output encoding, parameterized queries
4. Assess Risk: Categorize by severity and exploitability
5. Provide Remediation: Specific fixes with code examples
**Quality Standards:**
- Every vulnerability includes CWE reference when applicable
- Severity based on CVSS criteria
- Remediation includes code examples
- Minimize false positives
**Output Format:**
## Security Analysis Report
### Summary
[High-level security posture assessment]
### Critical Vulnerabilities
- **[Type]** at `file:line`
- Risk: [Security impact]
- Exploit: [Attack scenario]
- Fix: [Remediation with code]
### Medium/Low Vulnerabilities
[...]
### Recommendations
[Security best practices]
### Overall Risk: [High/Medium/Low]
[Justification]
**Edge Cases:**
- No vulnerabilities: Confirm what was checked
- Uncertain: Mark as "potential" with caveat
```
## Example 5: Documentation Writer Agent
### JSON Format
```json
{
"docs-writer": {
"description": "Writes and maintains project documentation. Use for README, API docs, architecture docs.",
"mode": "subagent",
"model": "anthropic/claude-haiku-4-20250514",
"temperature": 0.3,
"prompt": "{file:./prompts/docs-writer.txt}",
"tools": {
"write": true,
"edit": true,
"bash": false
}
}
}
```
### Prompt File (prompts/docs-writer.txt)
```
You are an expert technical writer creating clear, comprehensive documentation.
**Your Core Responsibilities:**
1. Generate accurate, clear documentation from code
2. Follow project documentation standards
3. Include examples and usage patterns
4. Ensure completeness and correctness
**Documentation Process:**
1. Analyze Code: Understand public interfaces, parameters, behavior
2. Identify Pattern: Check existing docs for format, style, organization
3. Generate Content: Descriptions, parameters, return values, examples
4. Format: Follow project conventions
5. Validate: Ensure accuracy
**Quality Standards:**
- Documentation matches actual code behavior
- Examples are runnable and correct
- All public APIs documented
- Clear and concise language
**Output Format:**
Documentation in project's standard format:
- Function signatures
- Description of behavior
- Parameters with types
- Return values
- Exceptions/errors
- Usage examples
- Notes/warnings if applicable
```
## Model Selection Guide
| Agent Purpose | Model | Temperature | Rationale |
|---------------|-------|-------------|-----------|
| Code review | sonnet | 0.1 | Consistent, thorough analysis |
| Test generation | sonnet | 0.2 | Slight creativity for edge cases |
| Security analysis | sonnet | 0.1 | Deterministic security checks |
| Documentation | haiku | 0.3 | Cost-effective, slight creativity |
| Architecture planning | opus | 0.1 | Complex reasoning needed |
| Brainstorming | sonnet | 0.5 | Creative exploration |
## Tool Access Patterns
| Agent Type | write | edit | bash | Rationale |
|------------|-------|------|------|-----------|
| Analyzer | false | false | true | Read-only with git access |
| Generator | true | true | true | Creates/modifies files |
| Documentation | true | true | false | Writes docs, no commands |
| Security | false | false | true | Analysis with tool access |

View File

@@ -0,0 +1,184 @@
# Agent Creation System Prompt
Use this system prompt to generate agent configurations via AI assistance.
## The Prompt
```
You are an expert AI agent architect for Opencode. Create agent configurations that integrate seamlessly with Opencode's agent system.
When a user describes what they want an agent to do:
1. **Extract Core Intent**: Identify purpose, responsibilities, and success criteria. Consider whether this should be a primary agent (direct user interaction) or subagent (delegated tasks).
2. **Design Expert Persona**: Create an expert identity with deep domain knowledge relevant to the task.
3. **Architect Configuration**: Determine:
- mode: primary (Tab-cycleable) or subagent (Task tool/@ mention)
- model: provider/model-id (e.g., anthropic/claude-sonnet-4-20250514)
- temperature: 0.0-0.2 for deterministic, 0.3-0.5 balanced, 0.6+ creative
- tools: which tools to enable/disable
- permission: granular access control
4. **Write System Prompt**: Create comprehensive instructions with:
- Clear behavioral boundaries
- Specific methodologies and best practices
- Edge case handling
- Output format expectations
5. **Create Identifier**: Design a concise, descriptive name:
- Lowercase letters, numbers, hyphens only
- 2-4 words joined by hyphens
- Clearly indicates primary function
- Avoid generic terms (helper, assistant)
Your output must be a valid JSON object:
{
"identifier": "agent-name",
"config": {
"description": "When to use this agent",
"mode": "primary | subagent",
"model": "provider/model-id",
"temperature": 0.3,
"tools": {
"write": true,
"edit": true,
"bash": false
},
"permission": {
"edit": "allow",
"bash": "ask"
}
},
"systemPrompt": "You are..."
}
Key principles:
- Be specific rather than generic
- Include concrete examples when helpful
- Balance comprehensiveness with clarity
- Make agents proactive in seeking clarification
- Build in quality assurance mechanisms
```
## Usage Pattern
### Step 1: Describe Your Agent
```
Create an agent configuration: "I need an agent that reviews pull requests for code quality issues, security vulnerabilities, and adherence to best practices"
```
### Step 2: Receive JSON Output
```json
{
"identifier": "pr-quality-reviewer",
"config": {
"description": "Reviews pull requests for code quality, security, and best practices. Use when reviewing PRs or analyzing code changes.",
"mode": "subagent",
"model": "anthropic/claude-sonnet-4-20250514",
"temperature": 0.1,
"tools": {
"write": false,
"edit": false,
"bash": true
}
},
"systemPrompt": "You are an expert code quality reviewer specializing in identifying issues in software implementations.\n\n**Your Core Responsibilities:**\n1. Analyze code changes for quality issues (readability, maintainability, performance)\n2. Identify security vulnerabilities (injection, XSS, authentication flaws)\n3. Check adherence to project best practices\n4. Provide actionable feedback with file:line references\n\n**Review Process:**\n1. Read code changes using available tools\n2. Analyze for quality, security, and best practices\n3. Categorize issues by severity (critical/major/minor)\n4. Provide specific recommendations\n\n**Output Format:**\n## Summary\n[2-3 sentence overview]\n\n## Critical Issues\n- `file:line` - [Issue] - [Fix]\n\n## Major Issues\n[...]\n\n## Recommendations\n[...]"
}
```
### Step 3: Add to agents.json
```json
{
"pr-quality-reviewer": {
"description": "Reviews pull requests for code quality, security, and best practices",
"mode": "subagent",
"model": "anthropic/claude-sonnet-4-20250514",
"temperature": 0.1,
"prompt": "{file:./prompts/pr-quality-reviewer.txt}",
"tools": {
"write": false,
"edit": false
}
}
}
```
### Step 4: Create Prompt File
Save the `systemPrompt` content to `prompts/pr-quality-reviewer.txt`.
## Configuration Decisions
### Primary vs Subagent
| Choose Primary When | Choose Subagent When |
|---------------------|----------------------|
| Direct user interaction | Delegated by other agents |
| Workflow-specific mode | Specialized single task |
| Need Tab key access | Triggered by Task tool |
| User switches to it manually | Automatic invocation |
### Model Selection
| Model | Use Case |
|-------|----------|
| claude-opus-4 | Complex reasoning, architecture decisions |
| claude-sonnet-4 | Balanced performance (default) |
| claude-haiku-4 | Fast, simple tasks, cost-sensitive |
### Tool Configuration
| Agent Type | Typical Tools |
|------------|---------------|
| Read-only analysis | `write: false`, `edit: false`, `bash: true` |
| Code generation | `write: true`, `edit: true`, `bash: true` |
| Documentation | `write: true`, `edit: false`, `bash: false` |
| Testing | `write: false`, `edit: false`, `bash: true` |
### Permission Patterns
```json
// Read-only agent
"permission": {
"edit": "deny",
"bash": {
"*": "ask",
"git diff*": "allow",
"grep *": "allow"
}
}
// Careful writer
"permission": {
"edit": "allow",
"bash": {
"*": "ask",
"rm *": "deny",
"sudo *": "deny"
}
}
```
## Alternative: Markdown Agent
If preferring markdown format, create `~/.config/opencode/agents/pr-quality-reviewer.md`:
```markdown
---
description: Reviews pull requests for code quality, security, and best practices
mode: subagent
model: anthropic/claude-sonnet-4-20250514
temperature: 0.1
tools:
write: false
edit: false
---
You are an expert code quality reviewer...
[Rest of system prompt]
```

View File

@@ -0,0 +1,267 @@
# Complete agents.json Example
This is a production-ready example based on real-world Opencode configurations.
## Dual-Mode Personal Assistant
This pattern implements the same assistant in two modes: Plan (read-only analysis) and Forge (full write access).
```json
{
"chiron": {
"description": "Personal AI assistant (Plan Mode). Read-only analysis, planning, and guidance.",
"mode": "primary",
"model": "anthropic/claude-sonnet-4-20250514",
"prompt": "{file:./prompts/chiron.txt}",
"permission": {
"read": {
"*": "allow",
"*.env": "deny",
"*.env.*": "deny",
"*.env.example": "allow",
"*/.ssh/*": "deny",
"*/.gnupg/*": "deny",
"*credentials*": "deny",
"*secrets*": "deny",
"*.pem": "deny",
"*.key": "deny",
"*/.aws/*": "deny",
"*/.kube/*": "deny"
},
"edit": "ask",
"bash": "ask",
"external_directory": "ask",
"doom_loop": "ask"
}
},
"chiron-forge": {
"description": "Personal AI assistant (Worker Mode). Full write access with safety prompts.",
"mode": "primary",
"model": "anthropic/claude-sonnet-4-20250514",
"prompt": "{file:./prompts/chiron-forge.txt}",
"permission": {
"read": {
"*": "allow",
"*.env": "deny",
"*.env.*": "deny",
"*.env.example": "allow",
"*/.ssh/*": "deny",
"*/.gnupg/*": "deny",
"*credentials*": "deny",
"*secrets*": "deny",
"*.pem": "deny",
"*.key": "deny",
"*/.aws/*": "deny",
"*/.kube/*": "deny"
},
"edit": "allow",
"bash": {
"*": "allow",
"rm *": "ask",
"rmdir *": "ask",
"mv *": "ask",
"chmod *": "ask",
"chown *": "ask",
"git *": "ask",
"git status*": "allow",
"git log*": "allow",
"git diff*": "allow",
"git branch*": "allow",
"git show*": "allow",
"git stash list*": "allow",
"git remote -v": "allow",
"git add *": "allow",
"git commit *": "allow",
"npm *": "ask",
"npx *": "ask",
"pip *": "ask",
"cargo *": "ask",
"dd *": "deny",
"mkfs*": "deny",
"sudo *": "deny",
"su *": "deny",
"systemctl *": "deny",
"shutdown *": "deny",
"reboot*": "deny"
},
"external_directory": "ask",
"doom_loop": "ask"
}
}
}
```
## Multi-Agent Development Workflow
This pattern shows specialized agents for a development workflow.
```json
{
"build": {
"description": "Full development with all tools enabled",
"mode": "primary",
"model": "anthropic/claude-opus-4-20250514",
"temperature": 0.3,
"tools": {
"write": true,
"edit": true,
"bash": true
}
},
"plan": {
"description": "Analysis and planning without making changes",
"mode": "primary",
"model": "anthropic/claude-opus-4-20250514",
"temperature": 0.1,
"tools": {
"write": false,
"edit": false,
"bash": true
}
},
"code-reviewer": {
"description": "Reviews code for quality, security, and best practices",
"mode": "subagent",
"model": "anthropic/claude-sonnet-4-20250514",
"temperature": 0.1,
"prompt": "{file:./prompts/code-reviewer.txt}",
"tools": {
"write": false,
"edit": false,
"bash": false
}
},
"test-generator": {
"description": "Generates comprehensive unit tests for code",
"mode": "subagent",
"model": "anthropic/claude-sonnet-4-20250514",
"temperature": 0.2,
"prompt": "{file:./prompts/test-generator.txt}",
"tools": {
"write": true,
"edit": true,
"bash": true
}
},
"security-analyzer": {
"description": "Identifies security vulnerabilities and provides remediation",
"mode": "subagent",
"model": "anthropic/claude-sonnet-4-20250514",
"temperature": 0.1,
"prompt": "{file:./prompts/security-analyzer.txt}",
"tools": {
"write": false,
"edit": false,
"bash": true
}
},
"docs-writer": {
"description": "Writes and maintains project documentation",
"mode": "subagent",
"model": "anthropic/claude-haiku-4-20250514",
"temperature": 0.3,
"prompt": "{file:./prompts/docs-writer.txt}",
"tools": {
"write": true,
"edit": true,
"bash": false
}
}
}
```
## Orchestrator with Task Permissions
This pattern shows a primary agent that controls which subagents it can invoke.
```json
{
"orchestrator": {
"description": "Coordinates development workflow using specialized subagents",
"mode": "primary",
"model": "anthropic/claude-opus-4-20250514",
"prompt": "{file:./prompts/orchestrator.txt}",
"permission": {
"task": {
"*": "deny",
"code-reviewer": "allow",
"test-generator": "allow",
"security-analyzer": "ask",
"docs-writer": "allow"
},
"edit": "allow",
"bash": {
"*": "allow",
"git push*": "ask",
"rm -rf*": "deny"
}
}
}
}
```
## Hidden Internal Subagent
This pattern shows a subagent hidden from @ autocomplete but still invokable via Task tool.
```json
{
"internal-helper": {
"description": "Internal helper for data processing tasks",
"mode": "subagent",
"hidden": true,
"model": "anthropic/claude-haiku-4-20250514",
"temperature": 0,
"prompt": "You are a data processing helper...",
"tools": {
"write": false,
"edit": false,
"bash": true
}
}
}
```
## Key Patterns
### Permission Inheritance
- Global `permission` in opencode.json applies to all agents
- Agent-specific `permission` overrides global settings
- Last matching rule wins for glob patterns
### Prompt File Organization
```
project/
├── opencode.json # or agents.json
└── prompts/
├── chiron.txt
├── chiron-forge.txt
├── code-reviewer.txt
└── test-generator.txt
```
### Model Strategy
| Agent Role | Recommended Model | Rationale |
|------------|-------------------|-----------|
| Complex reasoning | opus | Best quality, expensive |
| General tasks | sonnet | Balanced (default) |
| Fast/simple | haiku | Cost-effective |
| Deterministic | temperature: 0-0.1 | Consistent results |
| Creative | temperature: 0.3-0.5 | Varied responses |
### Tool Access Patterns
| Agent Type | write | edit | bash |
|------------|-------|------|------|
| Read-only analyzer | false | false | true (for git) |
| Code generator | true | true | true |
| Documentation | true | true | false |
| Security scanner | false | false | true |

View File

@@ -0,0 +1,437 @@
# System Prompt Design Patterns
Complete guide to writing effective agent system prompts that enable autonomous, high-quality operation.
## Opencode-Specific Considerations
### Prompt File Convention
Store prompts as separate files for maintainability:
```
project/
├── opencode.json (or agents.json)
└── prompts/
├── agent-name.txt
├── code-reviewer.txt
└── test-generator.txt
```
Reference in configuration:
```json
"prompt": "{file:./prompts/agent-name.txt}"
```
Paths are relative to the config file location.
### File Format
Use `.txt` extension for prompt files. The entire file content becomes the system prompt.
## Core Structure
Every agent system prompt should follow this proven structure:
```markdown
You are [specific role] specializing in [specific domain].
**Your Core Responsibilities:**
1. [Primary responsibility - the main task]
2. [Secondary responsibility - supporting task]
3. [Additional responsibilities as needed]
**[Task Name] Process:**
1. [First concrete step]
2. [Second concrete step]
3. [Continue with clear steps]
[...]
**Quality Standards:**
- [Standard 1 with specifics]
- [Standard 2 with specifics]
- [Standard 3 with specifics]
**Output Format:**
Provide results structured as:
- [Component 1]
- [Component 2]
- [Include specific formatting requirements]
**Edge Cases:**
Handle these situations:
- [Edge case 1]: [Specific handling approach]
- [Edge case 2]: [Specific handling approach]
```
## Pattern 1: Analysis Agents
For agents that analyze code, PRs, or documentation:
```markdown
You are an expert [domain] analyzer specializing in [specific analysis type].
**Your Core Responsibilities:**
1. Thoroughly analyze [what] for [specific issues]
2. Identify [patterns/problems/opportunities]
3. Provide actionable recommendations
**Analysis Process:**
1. **Gather Context**: Read [what] using available tools
2. **Initial Scan**: Identify obvious [issues/patterns]
3. **Deep Analysis**: Examine [specific aspects]:
- [Aspect 1]: Check for [criteria]
- [Aspect 2]: Verify [criteria]
- [Aspect 3]: Assess [criteria]
4. **Synthesize Findings**: Group related issues
5. **Prioritize**: Rank by [severity/impact/urgency]
6. **Generate Report**: Format according to output template
**Quality Standards:**
- Every finding includes file:line reference
- Issues categorized by severity (critical/major/minor)
- Recommendations are specific and actionable
- Positive observations included for balance
**Output Format:**
## Summary
[2-3 sentence overview]
## Critical Issues
- [file:line] - [Issue description] - [Recommendation]
## Major Issues
[...]
## Minor Issues
[...]
## Recommendations
[...]
**Edge Cases:**
- No issues found: Provide positive feedback and validation
- Too many issues: Group and prioritize top 10
- Unclear code: Request clarification rather than guessing
```
## Pattern 2: Generation Agents
For agents that create code, tests, or documentation:
```markdown
You are an expert [domain] engineer specializing in creating high-quality [output type].
**Your Core Responsibilities:**
1. Generate [what] that meets [quality standards]
2. Follow [specific conventions/patterns]
3. Ensure [correctness/completeness/clarity]
**Generation Process:**
1. **Understand Requirements**: Analyze what needs to be created
2. **Gather Context**: Read existing [code/docs/tests] for patterns
3. **Design Structure**: Plan [architecture/organization/flow]
4. **Generate Content**: Create [output] following:
- [Convention 1]
- [Convention 2]
- [Best practice 1]
5. **Validate**: Verify [correctness/completeness]
6. **Document**: Add comments/explanations as needed
**Quality Standards:**
- Follows project conventions (check AGENTS.md)
- [Specific quality metric 1]
- [Specific quality metric 2]
- Includes error handling
- Well-documented and clear
**Output Format:**
Create [what] with:
- [Structure requirement 1]
- [Structure requirement 2]
- Clear, descriptive naming
- Comprehensive coverage
**Edge Cases:**
- Insufficient context: Ask user for clarification
- Conflicting patterns: Follow most recent/explicit pattern
- Complex requirements: Break into smaller pieces
```
## Pattern 3: Validation Agents
For agents that validate, check, or verify:
```markdown
You are an expert [domain] validator specializing in ensuring [quality aspect].
**Your Core Responsibilities:**
1. Validate [what] against [criteria]
2. Identify violations and issues
3. Provide clear pass/fail determination
**Validation Process:**
1. **Load Criteria**: Understand validation requirements
2. **Scan Target**: Read [what] needs validation
3. **Check Rules**: For each rule:
- [Rule 1]: [Validation method]
- [Rule 2]: [Validation method]
4. **Collect Violations**: Document each failure with details
5. **Assess Severity**: Categorize issues
6. **Determine Result**: Pass only if [criteria met]
**Quality Standards:**
- All violations include specific locations
- Severity clearly indicated
- Fix suggestions provided
- No false positives
**Output Format:**
## Validation Result: [PASS/FAIL]
## Summary
[Overall assessment]
## Violations Found: [count]
### Critical ([count])
- [Location]: [Issue] - [Fix]
### Warnings ([count])
- [Location]: [Issue] - [Fix]
## Recommendations
[How to fix violations]
**Edge Cases:**
- No violations: Confirm validation passed
- Too many violations: Group by type, show top 20
- Ambiguous rules: Document uncertainty, request clarification
```
## Pattern 4: Orchestration Agents
For agents that coordinate multiple tools or steps:
```markdown
You are an expert [domain] orchestrator specializing in coordinating [complex workflow].
**Your Core Responsibilities:**
1. Coordinate [multi-step process]
2. Manage [resources/tools/dependencies]
3. Ensure [successful completion/integration]
**Orchestration Process:**
1. **Plan**: Understand full workflow and dependencies
2. **Prepare**: Set up prerequisites
3. **Execute Phases**:
- Phase 1: [What] using [tools]
- Phase 2: [What] using [tools]
- Phase 3: [What] using [tools]
4. **Monitor**: Track progress and handle failures
5. **Verify**: Confirm successful completion
6. **Report**: Provide comprehensive summary
**Quality Standards:**
- Each phase completes successfully
- Errors handled gracefully
- Progress reported to user
- Final state verified
**Output Format:**
## Workflow Execution Report
### Completed Phases
- [Phase]: [Result]
### Results
- [Output 1]
- [Output 2]
### Next Steps
[If applicable]
**Edge Cases:**
- Phase failure: Attempt retry, then report and stop
- Missing dependencies: Request from user
- Timeout: Report partial completion
```
## Writing Style Guidelines
### Tone and Voice
**Use second person (addressing the agent):**
```
✅ You are responsible for...
✅ You will analyze...
✅ Your process should...
❌ The agent is responsible for...
❌ This agent will analyze...
❌ I will analyze...
```
### Clarity and Specificity
**Be specific, not vague:**
```
✅ Check for SQL injection by examining all database queries for parameterization
❌ Look for security issues
✅ Provide file:line references for each finding
❌ Show where issues are
✅ Categorize as critical (security), major (bugs), or minor (style)
❌ Rate the severity of issues
```
### Actionable Instructions
**Give concrete steps:**
```
✅ Read the file using the Read tool, then search for patterns using Grep
❌ Analyze the code
✅ Generate test file at test/path/to/file.test.ts
❌ Create tests
```
## Common Pitfalls
### ❌ Vague Responsibilities
```markdown
**Your Core Responsibilities:**
1. Help the user with their code
2. Provide assistance
3. Be helpful
```
**Why bad:** Not specific enough to guide behavior.
### ✅ Specific Responsibilities
```markdown
**Your Core Responsibilities:**
1. Analyze TypeScript code for type safety issues
2. Identify missing type annotations and improper 'any' usage
3. Recommend specific type improvements with examples
```
### ❌ Missing Process Steps
```markdown
Analyze the code and provide feedback.
```
**Why bad:** Agent doesn't know HOW to analyze.
### ✅ Clear Process
```markdown
**Analysis Process:**
1. Read code files using Read tool
2. Scan for type annotations on all functions
3. Check for 'any' type usage
4. Verify generic type parameters
5. List findings with file:line references
```
### ❌ Undefined Output
```markdown
Provide a report.
```
**Why bad:** Agent doesn't know what format to use.
### ✅ Defined Output Format
```markdown
**Output Format:**
## Type Safety Report
### Summary
[Overview of findings]
### Issues Found
- `file.ts:42` - Missing return type on `processData`
- `utils.ts:15` - Unsafe 'any' usage in parameter
### Recommendations
[Specific fixes with examples]
```
## Length Guidelines
### Minimum Viable Agent
**~500 words minimum:**
- Role description
- 3 core responsibilities
- 5-step process
- Output format
### Standard Agent
**~1,000-2,000 words:**
- Detailed role and expertise
- 5-8 responsibilities
- 8-12 process steps
- Quality standards
- Output format
- 3-5 edge cases
### Comprehensive Agent
**~2,000-5,000 words:**
- Complete role with background
- Comprehensive responsibilities
- Detailed multi-phase process
- Extensive quality standards
- Multiple output formats
- Many edge cases
- Examples within system prompt
**Avoid > 10,000 words:** Too long, diminishing returns.
## Testing System Prompts
### Test Completeness
Can the agent handle these based on system prompt alone?
- [ ] Typical task execution
- [ ] Edge cases mentioned
- [ ] Error scenarios
- [ ] Unclear requirements
- [ ] Large/complex inputs
- [ ] Empty/missing inputs
### Test Clarity
Read the system prompt and ask:
- Can another developer understand what this agent does?
- Are process steps clear and actionable?
- Is output format unambiguous?
- Are quality standards measurable?
### Iterate Based on Results
After testing agent:
1. Identify where it struggled
2. Add missing guidance to system prompt
3. Clarify ambiguous instructions
4. Add process steps for edge cases
5. Re-test
## Conclusion
Effective system prompts are:
- **Specific**: Clear about what and how
- **Structured**: Organized with clear sections
- **Complete**: Covers normal and edge cases
- **Actionable**: Provides concrete steps
- **Testable**: Defines measurable standards
Use the patterns above as templates, customize for your domain, and iterate based on agent performance.

View File

@@ -0,0 +1,224 @@
# Agent Triggering in Opencode
Understanding how agents are triggered and invoked in Opencode.
## Triggering Mechanisms
### Primary Agents
Primary agents are directly accessible to users:
| Method | Description |
|--------|-------------|
| **Tab key** | Cycle through primary agents |
| **Keybind** | Use configured `switch_agent` keybind |
| **@ mention** | Type `@agent-name` in message |
| **default_agent** | Set in config to start with specific agent |
### Subagents
Subagents are invoked indirectly:
| Method | Description |
|--------|-------------|
| **Task tool** | Primary agent delegates via Task tool |
| **@ mention** | User manually types `@agent-name` |
| **Automatic** | Based on description matching user intent |
## The Description Field
The `description` field is critical for subagent triggering. When a primary agent receives a request, it evaluates subagent descriptions to decide whether to delegate.
### Good Descriptions
**Clear purpose and triggers:**
```json
"description": "Reviews code for quality, security, and best practices. Use when reviewing PRs, after implementing features, or before commits."
```
**Specific use cases:**
```json
"description": "Generates comprehensive unit tests for code. Use after implementing new functions or when improving test coverage."
```
**Domain-specific:**
```json
"description": "Analyzes authentication and authorization code for security vulnerabilities. Use when reviewing auth flows, JWT handling, or session management."
```
### Poor Descriptions
**Too vague:**
```json
"description": "Helps with code"
```
**No trigger conditions:**
```json
"description": "A code review agent"
```
**Too broad:**
```json
"description": "Handles all development tasks"
```
## Triggering Patterns
### Pattern 1: Explicit Delegation
Primary agent explicitly invokes subagent via Task tool:
```
User: "Review my authentication code"
Primary Agent (internal): This matches "code-reviewer" description about
"reviewing auth flows". Invoke via Task tool.
→ Task tool invokes code-reviewer subagent
```
### Pattern 2: @ Mention
User directly invokes subagent:
```
User: "@security-analyzer check this endpoint for vulnerabilities"
→ security-analyzer subagent is invoked directly
```
### Pattern 3: Automatic Context
Primary agent recognizes pattern from description:
```
User: "I just implemented the payment processing feature"
Primary Agent: Description mentions "after implementing features" and
"security-critical code (auth, payments)". Consider delegating to
security-analyzer or code-reviewer.
```
## Task Tool Invocation
When a primary agent invokes a subagent, it uses the Task tool:
```json
{
"tool": "task",
"parameters": {
"subagent_type": "code-reviewer",
"prompt": "Review the authentication code in src/auth/...",
"description": "Code review for auth implementation"
}
}
```
### Task Permissions
Control which subagents an agent can invoke:
```json
{
"orchestrator": {
"permission": {
"task": {
"*": "deny",
"code-reviewer": "allow",
"security-analyzer": "ask"
}
}
}
}
```
- `"allow"`: Invoke without approval
- `"ask"`: Prompt user for approval
- `"deny"`: Remove from Task tool (agent can't see it)
**Note:** Users can still @ mention any subagent, regardless of task permissions.
## Hidden Subagents
Hide subagents from @ autocomplete while still allowing Task tool invocation:
```json
{
"internal-helper": {
"mode": "subagent",
"hidden": true
}
}
```
Use cases:
- Internal processing agents
- Agents only invoked programmatically
- Specialized helpers not meant for direct user access
## Navigation Between Sessions
When subagents create child sessions:
| Keybind | Action |
|---------|--------|
| `<Leader>+Right` | Cycle forward: parent → child1 → child2 → parent |
| `<Leader>+Left` | Cycle backward |
This allows seamless switching between main conversation and subagent work.
## Description Best Practices
### Include Trigger Conditions
```json
"description": "Use when [condition 1], [condition 2], or [condition 3]."
```
### Be Specific About Domain
```json
"description": "Analyzes [specific domain] for [specific purpose]."
```
### Mention Key Actions
```json
"description": "[What it does]. Invoke after [action] or when [situation]."
```
### Complete Example
```json
{
"code-reviewer": {
"description": "Reviews code for quality issues, security vulnerabilities, and best practice violations. Use when: (1) reviewing pull requests, (2) after implementing new features, (3) before committing changes, (4) when asked to check code quality. Provides structured feedback with file:line references.",
"mode": "subagent"
}
}
```
## Debugging Triggering Issues
### Agent Not Triggering
Check:
1. Description contains relevant keywords
2. Mode is set correctly (subagent for Task tool)
3. Agent is not disabled
4. Task permissions allow invocation
### Agent Triggers Too Often
Check:
1. Description is too broad
2. Overlaps with other agent descriptions
3. Consider more specific trigger conditions
### Wrong Agent Triggers
Check:
1. Descriptions are distinct between agents
2. Add negative conditions ("NOT for...")
3. Specify exact scenarios in description

View File

@@ -0,0 +1,304 @@
#!/usr/bin/env bash
# Agent Configuration Validator
# Validates agent configurations in JSON or Markdown format
set -euo pipefail
usage() {
echo "Usage: $0 <path/to/agents.json | path/to/agent.md>"
echo ""
echo "Validates agent configuration for Opencode:"
echo " - JSON: Validates agents.json structure"
echo " - Markdown: Validates agent .md file with frontmatter"
echo ""
echo "Examples:"
echo " $0 agent/agents.json"
echo " $0 ~/.config/opencode/agents/review.md"
exit 1
}
validate_json() {
local file="$1"
echo "🔍 Validating JSON agent configuration: $file"
echo ""
# Check JSON syntax
if ! python3 -c "import json; json.load(open('$file'))" 2>/dev/null; then
echo "❌ Invalid JSON syntax"
exit 1
fi
echo "✅ Valid JSON syntax"
# Parse and validate each agent
local error_count=0
local warning_count=0
# Get agent names
local agents
agents=$(python3 -c "
import json
import sys
with open('$file') as f:
data = json.load(f)
# Handle both formats: direct agents or nested under 'agent' key
if 'agent' in data:
agents = data['agent']
else:
agents = data
for name in agents.keys():
print(name)
")
if [ -z "$agents" ]; then
echo "❌ No agents found in configuration"
exit 1
fi
echo ""
echo "Found agents: $agents"
echo ""
# Validate each agent
for agent_name in $agents; do
echo "Checking agent: $agent_name"
local validation_result
validation_result=$(python3 -c "
import json
import sys
with open('$file') as f:
data = json.load(f)
# Handle both formats
if 'agent' in data:
agents = data['agent']
else:
agents = data
agent = agents.get('$agent_name', {})
errors = []
warnings = []
# Check required field: description
if 'description' not in agent:
errors.append('Missing required field: description')
elif len(agent['description']) < 10:
warnings.append('Description is very short (< 10 chars)')
# Check mode if present
mode = agent.get('mode', 'all')
if mode not in ['primary', 'subagent', 'all']:
errors.append(f'Invalid mode: {mode} (must be primary, subagent, or all)')
# Check model format if present
model = agent.get('model', '')
if model and '/' not in model:
warnings.append(f'Model should use provider/model-id format: {model}')
# Check temperature if present
temp = agent.get('temperature')
if temp is not None:
if not isinstance(temp, (int, float)):
errors.append(f'Temperature must be a number: {temp}')
elif temp < 0 or temp > 2:
warnings.append(f'Temperature {temp} is outside typical range (0-1)')
# Check prompt
prompt = agent.get('prompt', '')
if prompt:
if prompt.startswith('{file:') and not prompt.endswith('}'):
errors.append('Invalid file reference syntax in prompt')
elif 'prompt' not in agent:
warnings.append('No prompt defined (will use default)')
# Check tools if present
tools = agent.get('tools', {})
if tools and not isinstance(tools, dict):
errors.append('Tools must be an object')
# Check permission if present
permission = agent.get('permission', {})
if permission and not isinstance(permission, dict):
errors.append('Permission must be an object')
# Output results
for e in errors:
print(f'ERROR:{e}')
for w in warnings:
print(f'WARNING:{w}')
if not errors and not warnings:
print('OK')
")
while IFS= read -r line; do
if [[ "$line" == ERROR:* ]]; then
echo "${line#ERROR:}"
((error_count++))
elif [[ "$line" == WARNING:* ]]; then
echo " ⚠️ ${line#WARNING:}"
((warning_count++))
elif [[ "$line" == "OK" ]]; then
echo " ✅ Valid"
fi
done <<< "$validation_result"
done
echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
if [ $error_count -eq 0 ] && [ $warning_count -eq 0 ]; then
echo "✅ All agents validated successfully!"
exit 0
elif [ $error_count -eq 0 ]; then
echo "⚠️ Validation passed with $warning_count warning(s)"
exit 0
else
echo "❌ Validation failed with $error_count error(s) and $warning_count warning(s)"
exit 1
fi
}
validate_markdown() {
local file="$1"
echo "🔍 Validating Markdown agent file: $file"
echo ""
# Check file exists
if [ ! -f "$file" ]; then
echo "❌ File not found: $file"
exit 1
fi
echo "✅ File exists"
# Check starts with ---
local first_line
first_line=$(head -1 "$file")
if [ "$first_line" != "---" ]; then
echo "❌ File must start with YAML frontmatter (---)"
exit 1
fi
echo "✅ Starts with frontmatter"
# Check has closing ---
if ! tail -n +2 "$file" | grep -q '^---$'; then
echo "❌ Frontmatter not closed (missing second ---)"
exit 1
fi
echo "✅ Frontmatter properly closed"
local error_count=0
local warning_count=0
# Extract and validate frontmatter
local frontmatter
frontmatter=$(sed -n '/^---$/,/^---$/{ /^---$/d; p; }' "$file")
# Check description (required)
if ! echo "$frontmatter" | grep -q '^description:'; then
echo "❌ Missing required field: description"
((error_count++))
else
echo "✅ description: present"
fi
# Check mode if present
local mode
mode=$(echo "$frontmatter" | grep '^mode:' | sed 's/mode: *//' || true)
if [ -n "$mode" ]; then
case "$mode" in
primary|subagent|all)
echo "✅ mode: $mode"
;;
*)
echo "❌ Invalid mode: $mode (must be primary, subagent, or all)"
((error_count++))
;;
esac
else
echo "💡 mode: not specified (defaults to 'all')"
fi
# Check model if present
local model
model=$(echo "$frontmatter" | grep '^model:' | sed 's/model: *//' || true)
if [ -n "$model" ]; then
if [[ "$model" == */* ]]; then
echo "✅ model: $model"
else
echo "⚠️ model should use provider/model-id format: $model"
((warning_count++))
fi
else
echo "💡 model: not specified (will inherit)"
fi
# Check temperature if present
local temp
temp=$(echo "$frontmatter" | grep '^temperature:' | sed 's/temperature: *//' || true)
if [ -n "$temp" ]; then
echo "✅ temperature: $temp"
fi
# Check system prompt (body after frontmatter)
local system_prompt
system_prompt=$(awk '/^---$/{i++; next} i>=2' "$file")
if [ -z "$system_prompt" ]; then
echo "⚠️ System prompt (body) is empty"
((warning_count++))
else
local prompt_length=${#system_prompt}
echo "✅ System prompt: $prompt_length characters"
if [ $prompt_length -lt 50 ]; then
echo "⚠️ System prompt is very short"
((warning_count++))
fi
if ! echo "$system_prompt" | grep -q "You are\|You will\|Your"; then
echo "⚠️ System prompt should use second person (You are..., You will...)"
((warning_count++))
fi
fi
echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
if [ $error_count -eq 0 ] && [ $warning_count -eq 0 ]; then
echo "✅ Validation passed!"
exit 0
elif [ $error_count -eq 0 ]; then
echo "⚠️ Validation passed with $warning_count warning(s)"
exit 0
else
echo "❌ Validation failed with $error_count error(s) and $warning_count warning(s)"
exit 1
fi
}
# Main
if [ $# -eq 0 ]; then
usage
fi
FILE="$1"
if [ ! -f "$FILE" ]; then
echo "❌ File not found: $FILE"
exit 1
fi
# Determine file type and validate
if [[ "$FILE" == *.json ]]; then
validate_json "$FILE"
elif [[ "$FILE" == *.md ]]; then
validate_markdown "$FILE"
else
echo "❌ Unknown file type. Expected .json or .md"
echo ""
usage
fi

315
skills/basecamp/SKILL.md Normal file
View File

@@ -0,0 +1,315 @@
---
name: basecamp
description: "Use when: (1) Managing Basecamp projects, (2) Working with Basecamp todos and tasks, (3) Reading/updating message boards and campfire, (4) Managing card tables (kanban), (5) Handling email forwards/inbox, (6) Setting up webhooks for automation. Triggers: 'Basecamp', 'project', 'todo', 'card table', 'campfire', 'message board', 'webhook', 'inbox', 'email forwards'."
compatibility: opencode
---
# Basecamp
Basecamp 3 project management integration via MCP server. Provides comprehensive access to projects, todos, messages, card tables (kanban), campfire, inbox, documents, and webhooks.
## Core Workflows
### Finding Projects and Todos
**List all projects:**
```bash
# Get all accessible Basecamp projects
get_projects
```
**Get project details:**
```bash
# Get specific project information including status, tools, and access level
get_project --project_id <id>
```
**Explore todos:**
```bash
# Get all todo lists in a project
get_todolists --project_id <id>
# Get all todos from a specific todo list (handles pagination automatically)
get_todos --recording_id <todo_list_id>
# Search across projects for todos/messages containing keywords
search_basecamp --query <search_term>
```
### Managing Card Tables (Kanban)
**Card tables** are Basecamp's kanban-style workflow management tool.
**Explore card table:**
```bash
# Get card table for a project
get_card_table --project_id <id>
# Get all columns in a card table
get_columns --card_table_id <id>
# Get all cards in a specific column
get_cards --column_id <id>
```
**Manage columns:**
```bash
# Create new column (e.g., "In Progress", "Done")
create_column --card_table_id <id> --title "Column Name"
# Update column title
update_column --column_id <id> --title "New Title"
# Move column to different position
move_column --column_id <id> --position 3
# Update column color
update_column_color --column_id <id> --color "red"
# Put column on hold (freeze work)
put_column_on_hold --column_id <id>
# Remove hold from column (unfreeze work)
remove_column_hold --column_id <id>
```
**Manage cards:**
```bash
# Create new card in a column
create_card --column_id <id> --title "Task Name" --content "Description"
# Update card details
update_card --card_id <id> --title "Updated Title" --content "New content"
# Move card to different column
move_card --card_id <id> --to_column_id <new_column_id>
# Mark card as complete
complete_card --card_id <id>
# Mark card as incomplete
uncomplete_card --card_id <id>
```
**Manage card steps (sub-tasks):**
```bash
# Get all steps for a card
get_card_steps --card_id <id>
# Create new step
create_card_step --card_id <id> --content "Sub-task description"
# Update step
update_card_step --step_id <id> --content "Updated description"
# Delete step
delete_card_step --step_id <id>
# Mark step as complete
complete_card_step --step_id <id>
# Mark step as incomplete
uncomplete_card_step --step_id <id>
```
### Working with Messages and Campfire
**Message board:**
```bash
# Get message board for a project
get_message_board --project_id <id>
# Get all messages from a project
get_messages --project_id <id>
# Get specific message
get_message --message_id <id>
```
**Campfire (team chat):**
```bash
# Get recent campfire lines (messages)
get_campfire_lines --campfire_id <id>
```
**Comments:**
```bash
# Get comments for any Basecamp item (message, todo, card, etc.)
get_comments --recording_id <id>
# Create a comment
create_comment --recording_id <id> --content "Your comment"
```
### Managing Inbox (Email Forwards)
**Inbox** handles email forwarding to Basecamp projects.
**Explore inbox:**
```bash
# Get inbox for a project (email forwards container)
get_inbox --project_id <id>
# Get all forwarded emails from a project's inbox
get_forwards --project_id <id>
# Get specific forwarded email
get_forward --forward_id <id>
# Get all replies to a forwarded email
get_inbox_replies --forward_id <id>
# Get specific reply
get_inbox_reply --reply_id <id>
```
**Manage forwards:**
```bash
# Move forwarded email to trash
trash_forward --forward_id <id>
```
### Documents
**Manage documents:**
```bash
# List documents in a vault
get_documents --vault_id <id>
# Get specific document
get_document --document_id <id>
# Create new document
create_document --vault_id <id> --title "Document Title" --content "Document content"
# Update document
update_document --document_id <id> --title "Updated Title" --content "New content"
# Move document to trash
trash_document --document_id <id>
```
### Webhooks and Automation
**Webhooks** enable automation by triggering external services on Basecamp events.
**Manage webhooks:**
```bash
# List webhooks for a project
get_webhooks --project_id <id>
# Create webhook
create_webhook --project_id <id> --callback_url "https://your-service.com/webhook" --types "TodoCreated,TodoCompleted"
# Delete webhook
delete_webhook --webhook_id <id>
```
### Daily Check-ins
**Project check-ins:**
```bash
# Get daily check-in questions for a project
get_daily_check_ins --project_id <id>
# Get answers to daily check-in questions
get_question_answers --question_id <id>
```
### Attachments and Events
**Upload and track:**
```bash
# Upload file as attachment
create_attachment --recording_id <id> --file_path "/path/to/file"
# Get events for a recording
get_events --recording_id <id>
```
## Integration with Other Skills
### Hermes (Work Communication)
Hermes loads this skill when working with Basecamp projects. Common workflows:
| User Request | Hermes Action | Basecamp Tools Used |
|--------------|---------------|---------------------|
| "Create a task in Marketing project" | Create card/todo | `create_card`, `get_columns`, `create_column` |
| "Check project updates" | Read messages/campfire | `get_messages`, `get_campfire_lines`, `get_comments` |
| "Update my tasks" | Move cards, update status | `move_card`, `complete_card`, `update_card` |
| "Add comment to discussion" | Post comment | `create_comment`, `get_comments` |
| "Review project inbox" | Check email forwards | `get_inbox`, `get_forwards`, `get_inbox_replies` |
### Workflow Patterns
**Project setup:**
1. Use `get_projects` to find existing projects
2. Use `get_project` to verify project details
3. Use `get_todolists` or `get_card_table` to understand project structure
**Task management:**
1. Use `get_todolists` or `get_columns` to find appropriate location
2. Use `create_card` or todo creation to add work
3. Use `move_card`, `complete_card` to update status
4. Use `get_card_steps` and `create_card_step` for sub-task breakdown
**Communication:**
1. Use `get_messages` or `get_campfire_lines` to read discussions
2. Use `create_comment` to contribute to existing items
3. Use `search_basecamp` to find relevant content
**Automation:**
1. Use `get_webhooks` to check existing integrations
2. Use `create_webhook` to set up external notifications
## Tool Organization by Category
**Projects & Lists:**
- `get_projects`, `get_project`, `get_todolists`, `get_todos`, `search_basecamp`
**Card Table (Kanban):**
- `get_card_table`, `get_columns`, `get_column`, `create_column`, `update_column`, `move_column`, `update_column_color`, `put_column_on_hold`, `remove_column_hold`, `watch_column`, `unwatch_column`, `get_cards`, `get_card`, `create_card`, `update_card`, `move_card`, `complete_card`, `uncomplete_card`, `get_card_steps`, `create_card_step`, `get_card_step`, `update_card_step`, `delete_card_step`, `complete_card_step`, `uncomplete_card_step`
**Messages & Communication:**
- `get_message_board`, `get_messages`, `get_message`, `get_campfire_lines`, `get_comments`, `create_comment`
**Inbox (Email Forwards):**
- `get_inbox`, `get_forwards`, `get_forward`, `get_inbox_replies`, `get_inbox_reply`, `trash_forward`
**Documents:**
- `get_documents`, `get_document`, `create_document`, `update_document`, `trash_document`
**Webhooks:**
- `get_webhooks`, `create_webhook`, `delete_webhook`
**Other:**
- `get_daily_check_ins`, `get_question_answers`, `create_attachment`, `get_events`
## Common Queries
**Finding the right project:**
```bash
# Use search to find projects by keyword
search_basecamp --query "marketing"
# Then inspect specific project
get_project --project_id <id>
```
**Understanding project structure:**
```bash
# Check which tools are available in a project
get_project --project_id <id>
# Project response includes tools: message_board, campfire, card_table, todolists, etc.
```
**Bulk operations:**
```bash
# Get all todos across a project (pagination handled automatically)
get_todos --recording_id <todo_list_id>
# Returns all pages of results
# Get all cards across all columns
get_columns --card_table_id <id>
get_cards --column_id <id> # Repeat for each column
```

View File

@@ -65,56 +65,69 @@ Be ready to backtrack and clarify. Brainstorming is non-linear.
After reaching clarity, offer:
> "Would you like me to save this as an Anytype Brainstorm object for reference?"
> "Would you like me to save this brainstorm to Obsidian for reference?"
If yes, use the Anytype MCP to create a Brainstorm object:
If yes, create a brainstorm note in Obsidian:
```
Anytype_API-create-object
space_id: CHIRON_SPACE_ID
type_key: "brainstorm_v_2"
name: "<topic>"
body: "<full brainstorm content in markdown>"
icon: { format: "emoji", emoji: "💭" }
properties: [
{ key: "topic", text: "<short title>" },
{ key: "context", text: "<situation and trigger>" },
{ key: "outcome", text: "<what success looks like>" },
{ key: "constraints", text: "<time, resources, boundaries>" },
{ key: "options", text: "<options considered>" },
{ key: "decision", text: "<final choice>" },
{ key: "rationale", text: "<reasoning behind decision>" },
{ key: "next_steps", text: "<action items>" },
{ key: "framework", select: "<framework_tag_id>" },
{ key: "status", select: "draft" }
]
File: ~/CODEX/03-resources/brainstorms/YYYY-MM-DD-[topic].md
---
date: {{date}}
created: {{timestamp}}
type: brainstorm
framework: {{framework_used}}
status: {{draft|final|archived}}
tags: #brainstorm #{{framework_tag}}
---
# {{topic}}
## Context
{{situation and trigger}}
## Outcome
{{what success looks like}}
## Constraints
{{time, resources, boundaries}}
## Options Explored
{{options considered}}
## Decision
{{final choice}}
## Rationale
{{reasoning behind decision}}
## Next Steps
{{action items}}
---
*Created: {{timestamp}}*
```
**Chiron Space ID**: `bafyreie5sfq7pjfuq56hxsybos545bi4tok3kx7nab3vnb4tnt4i3575p4.yu20gbnjlbxv`
**Framework tags** (use in `tags:` frontmatter):
- `#pros-cons` - Pros/Cons analysis
- `#swot` - Strategic SWOT assessment
- `#5-whys` - Root cause analysis
- `#how-now-wow` - Prioritization matrix
- `#starbursting` - Comprehensive exploration (6 questions)
- `#constraint-mapping` - Boundary analysis
**Framework Tag IDs**:
- `bafyreiatkdbwq53shngaje6wuw752wxnwqlk3uhy6nicamdr56jpvji34i` - None
- `bafyreiaizrndgxmzbbzo6lurkgi7fc6evemoc5tivswrdu57ngkizy4b3u` - Pros/Cons
- `bafyreiaym5zkajnsrklivpjkizkuyhy3v5fzo62aaeobdlqzhq47clv6lm` - SWOT
- `bafyreihgfpsjeyuu7p46ejzd5jce5kmgfsuxy7r5kl4fqdhuq7jqoggtgq` - 5 Whys
- `bafyreieublfraypplrr5mmnksnytksv4iyh7frspyn64gixaodwmnhmosu` - How-Now-Wow
- `bafyreieyz6xjpt3zxad7h643m24oloajcae3ocnma3ttqfqykmggrsksk4` - Starbursting
- `bafyreigokn5xgdosd4cihehl3tqfsd25mwdaapuhopjgn62tkpvpwn4tmy` - Constraint Mapping
**Status Tag IDs**:
- `bafyreig5um57baws2dnntaxsi4smxtrzftpe57a7wyhfextvcq56kdkllq` - Draft
- `bafyreiffiinadpa2fwxw3iylj7pph3yzbnhe63dcyiwr4x24ne4jsgi24` - Final
- `bafyreihk6dlpwh3nljrxcqqe3v6tl52bxuvmx3rcgyzyom6yjmtdegu4ja` - Archived
**Optional**: Link to related objects using `linked_projects` or `linked_tasks` properties with object IDs.
**Status tags** (use in `status:` frontmatter):
- `draft` - Initial capture
- `final` - Decision made
- `archived` - No longer active
---
## Template Setup
For a better editing experience, create a template in Anytype:
For a better editing experience, create a template in Obsidian:
1. Open Anytype desktop app → Chiron space
1. Open Obsidian → ~/CODEX vault
2. Go to Content Model → Object Types → Brainstorm v2
3. Click Templates (top right) → Click + to create template
4. Name it "Brainstorm Session" and configure default fields:
@@ -185,4 +198,4 @@ After brainstorming, common next steps:
| Task identified | task-management | "Add this to my tasks" |
| Work project | basecamp | "Set this up in Basecamp" |
All handoffs can reference the Anytype Brainstorm object via its ID or linked objects.
All handoffs can reference the Obsidian brainstorm note via WikiLinks or file paths.

View File

@@ -0,0 +1,210 @@
# Brainstorm Obsidian Workflow
This document describes how to create and use brainstorm notes in Obsidian.
## Quick Create
Create a brainstorm note in Obsidian markdown format:
```markdown
File: ~/CODEX/03-resources/brainstorms/YYYY-MM-DD-[topic].md
---
date: 2026-01-27
created: 2026-01-27T18:30:00Z
type: brainstorm
framework: pros-cons
status: draft
tags: #brainstorm #pros-cons
---
# NixOS Course Launch Strategy
## Context
Want to launch NixOS course for developers who want to learn Nix
## Outcome
Build long-term audience/community around NixOS expertise
## Constraints
- 2-4 weeks preparation time
- Solo creator (no team yet)
- Limited budget for marketing
## Options Explored
### Option A: Early Access Beta
- **Approach**: Release course to 10-20 people first, gather feedback, then full launch
- **Pros**: Validates content, builds testimonials, catches bugs early
- **Cons**: Slower to revenue, requires managing beta users
- **Best if**: Quality is critical and you have patient audience
### Option B: Free Preview + Upsell
- **Approach**: Release first module free, full course for paid
- **Pros**: Low barrier to entry, demonstrates value, builds email list
- **Cons**: Lower conversion rate, can feel "bait-and-switchy"
- **Best if**: Content quality is obvious from preview
### Option C: Full Launch with Community
- **Approach**: Launch full course immediately with Discord/Community for support
- **Pros**: Immediate revenue, maximum reach, community built-in
- **Cons**: No validation, bugs in production, overwhelmed support
- **Best if**: Content is well-tested and you have support capacity
## Decision
**Early Access Beta** - Build anticipation while validating content
## Rationale
Quality and community trust matter more than speed. A beta launch lets me:
1. Catch errors before they damage reputation
2. Build testimonials that drive full launch
3. Gather feedback to improve the product
4. Create a community of early adopters who become evangelists
## Next Steps
1. Create landing page with beta signup
2. Build email list from signups
3. Create course outline and first modules
4. Select 10-20 beta users from community
5. Set up feedback collection system (notion/obsidian)
6. Launch beta (target: Feb 15)
7. Collect feedback for 2 weeks
8. Finalize content based on feedback
9. Full launch (target: March 1)
```
## Note Structure
| Frontmatter Field | Purpose | Values |
|-----------------|---------|---------|
| `date` | Date created | YYYY-MM-DD |
| `created` | Timestamp | ISO 8601 |
| `type` | Note type | `brainstorm` |
| `framework` | Framework used | `none`, `pros-cons`, `swot`, `5-whys`, `how-now-wow`, `starbursting`, `constraint-mapping` |
| `status` | Progress status | `draft`, `final`, `archived` |
| `tags` | Categorization | Always include `#brainstorm`, add framework tag |
## Framework Tags
| Framework | Tag | When to Use |
|-----------|------|-------------|
| None | `#none` | Conversational exploration without structure |
| Pros/Cons | `#pros-cons` | Binary decision (A or B, yes or no) |
| SWOT | `#swot` | Strategic assessment of situation |
| 5 Whys | `#5-whys` | Finding root cause of problem |
| How-Now-Wow | `#how-now-wow` | Prioritizing many ideas by impact/effort |
| Starbursting | `#starbursting` | Comprehensive exploration (6 questions) |
| Constraint Mapping | `#constraint-mapping` | Understanding boundaries and constraints |
## Status Values
| Status | Description | When to Use |
|--------|-------------|-------------|
| `draft` | Initial capture, work in progress | Start with this, update as you work |
| `final` | Decision made, brainstorm complete | When you've reached clarity |
| `archived` | No longer relevant or superseded | Historical reference only |
## Template Setup
For a better editing experience, create a template in Obsidian:
1. Open Obsidian → ~/CODEX vault
2. Create folder: `_chiron/templates/` if not exists
3. Create template file: `brainstorm-note.md` with:
- Frontmatter with placeholder values
- Markdown structure matching the sections above
- Empty sections ready to fill in
4. Set up Obsidian Templates plugin (optional) to use this template
**Obsidian Template:**
```markdown
---
date: {{date}}
created: {{timestamp}}
type: brainstorm
framework: {{framework}}
status: draft
tags: #brainstorm #{{framework}}
---
# {{topic}}
## Context
## Outcome
## Constraints
## Options Explored
### Option A: {{option_a_name}}
- **Approach**:
- **Pros**:
- **Cons**:
- **Best if**:
### Option B: {{option_b_name}}
- **Approach**:
- **Pros**:
- **Cons**:
- **Best if**:
## Decision
## Rationale
## Next Steps
1.
2.
3.
```
## Linking to Other Notes
After creating a brainstorm, link it to related notes using WikiLinks:
```markdown
## Related Projects
- [[Launch NixOS Flakes Course]]
- [[Q2 Training Program]]
## Related Tasks
- [[Tasks]]
```
## Searching Brainstorms
Find brainstorms by topic, framework, or status using Obsidian search:
**Obsidian search:**
- Topic: `path:03-resources/brainstorms "NixOS"`
- Framework: `#pros-cons path:03-resources/brainstorms`
- Status: `#draft path:03-resources/brainstorms`
**Dataview query (if using plugin):**
```dataview
TABLE date, topic, framework, status
FROM "03-resources/brainstorms"
WHERE type = "brainstorm"
SORT date DESC
```
## Best Practices
1. **Create brainstorms for any significant decision** - Capture reasoning while fresh
2. **Mark as Final when complete** - Helps with search and review
3. **Link to related notes** - Creates context web via WikiLinks
4. **Use frameworks selectively** - Not every brainstorm needs structure
5. **Review periodically** - Brainstorms can inform future decisions
6. **Keep structure consistent** - Same sections make reviews easier
7. **Use tags for filtering** - Framework and status tags are essential
## Integration with Other Skills
| From brainstorming | To skill | Handoff trigger |
|------------------|------------|-----------------|
| Project decision | plan-writing | "Create a project plan for this" |
| Task identified | task-management | "Add this to my tasks" |
| Work project | basecamp | "Set this up in Basecamp" |
All handoffs can reference the Obsidian brainstorm note via WikiLinks or file paths.

View File

@@ -0,0 +1,262 @@
---
name: doc-translator
description: "Translates external documentation websites to specified language(s) and publishes to Outline wiki. Use when: (1) Translating SaaS/product documentation into German or Czech, (2) Publishing translated docs to Outline wiki, (3) Re-hosting external images to Outline. Triggers: 'translate docs', 'translate documentation', 'translate to German', 'translate to Czech', 'publish to wiki', 'doc translation', 'TEEM translation'."
compatibility: opencode
---
# Doc Translator
Translate external documentation websites to German (DE) and/or Czech (CZ), then publish to the company Outline wiki at `https://wiki.az-gruppe.com`. All images are re-hosted on Outline. UI terms use TEEM format.
## Core Workflow
### 1. Validate Input & Clarify
Before starting, confirm:
1. **URL accessibility** - Check with `curl -sI <URL>` for HTTP 200
2. **Target language(s)** - Always ask explicitly using the `question` tool:
```
question: "Which language(s) should I translate to?"
options: ["German (DE)", "Czech (CZ)", "Both (DE + CZ)"]
```
3. **Scope** - If URL is an index page with multiple sub-pages, ask:
```
question: "This page links to multiple sub-pages. What should I translate?"
options: ["This page only", "This page + all linked sub-pages", "Let me pick specific pages"]
```
4. **Target collection** - Use `Outline_list_collections` to show available collections, then ask which one to publish to
**CRITICAL:** NEVER auto-select collection. Always present collection list to user and wait for explicit selection before proceeding with document creation.
If URL fetch fails, use `question` to ask for an alternative URL or manual content paste.
### 2. Fetch & Parse Content
Use the `webfetch` tool to retrieve page content:
```
webfetch(url="<URL>", format="markdown")
```
From the result:
- Extract main content body (ignore navigation, footers, sidebars, cookie banners)
- Preserve document structure (headings, lists, tables, code blocks)
- Collect all image URLs into a list for Step 3
- Note any embedded videos or interactive elements (these cannot be translated)
For multi-page docs, repeat for each page.
### 3. Download Images
Download all images to a temporary directory:
```bash
mkdir -p /tmp/doc-images
# For each image URL:
curl -sL "IMAGE_URL" -o "/tmp/doc-images/$(basename IMAGE_URL)"
```
Track a mapping of: `original_url -> local_filename -> outline_attachment_url`
If an image download fails, log it and continue. Use a placeholder in the final document:
```markdown
> **[Image unavailable]** Original: IMAGE_URL
```
### 4. Upload Images to Outline
MCP-outline does not support attachment creation. Use the bundled script for image uploads:
```bash
# Upload with optional document association
bash scripts/upload_image_to_outline.sh "/tmp/doc-images/screenshot.png" "$DOCUMENT_ID"
# Upload without document (attach later)
bash scripts/upload_image_to_outline.sh "/tmp/doc-images/screenshot.png"
```
The script handles API key loading from `/run/agenix/outline-key`, content-type detection, the two-step presigned POST flow, and retries. Output is JSON: `{"success": true, "attachment_url": "https://..."}`.
Replace image references in the translated markdown with the returned `attachment_url`:
```markdown
![description](ATTACHMENT_URL)
```
For all other Outline operations (documents, collections, search), use MCP tools (`Outline_*`).
### 5. Translate with TEEM Format
Translate the entire document into each target language. Apply TEEM format to UI elements.
#### Address Form (CRITICAL)
**Always use the informal "you" form** in ALL target languages:
- **German**: Use **"Du"** (informal), NEVER "Sie" (formal)
- **Czech**: Use **"ty"** (informal), NEVER "vy" (formal)
- This applies to all translations — documentation should feel approachable and direct
#### Infobox / Callout Formatting
Source documentation often uses admonitions, callouts, or info boxes (e.g., GitHub-style `> [!NOTE]`, Docusaurus `:::note`, or custom HTML boxes). **Convert ALL such elements** to Outline's callout syntax:
```markdown
:::tip
Tip or best practice content here.
:::
:::info
Informational content here.
:::
:::warning
Warning or caution content here.
:::
:::success
Success message or positive outcome here.
:::
```
**Mapping rules** (source → Outline):
| Source pattern | Outline syntax |
|---|---|
| Note, Info, Information | `:::info` |
| Tip, Hint, Best Practice | `:::tip` |
| Warning, Caution, Danger, Important | `:::warning` |
| Success, Done, Check | `:::success` |
**CRITICAL formatting**: The closing `:::` MUST be on its own line with an empty line before it. Content goes directly after the opening line.
#### TEEM Rules
**Format:** `**English UI Term** (Translation)`
**Apply TEEM to:**
- Button labels
- Menu items and navigation tabs
- Form field labels
- Dialog/modal titles
- Toolbar icons with text
- Status messages from the app
- **Headings containing UI terms** (example: "## [Adding a new To-do]" becomes "## [Ein neues **To-do** (Aufgabe) hinzufügen]")
**Translate normally (no TEEM):**
- Your own explanatory text
- Document headings you create (that don't contain UI terms)
- General descriptions and conceptual explanations
- Code blocks and technical identifiers
#### German Examples
```markdown
Click **Settings** (Einstellungen) to open preferences.
Navigate to **Dashboard** (Übersicht) > **Reports** (Berichte).
Press the **Submit** (Absenden) button.
In the **File** (Datei) menu, select **Export** (Exportieren).
# Heading with UI term: Create a new **To-do** (Aufgabe)
## [Adding a new **To-do** (Aufgabe)]
```
#### Czech Examples
```markdown
Click **Settings** (Nastavení) to open preferences.
Navigate to **Dashboard** (Přehled) > **Reports** (Sestavy).
Press the **Submit** (Odeslat) button.
In the **File** (Soubor) menu, select **Export** (Exportovat).
# Heading with UI term: Create a new **To-do** (Úkol)
## [Adding a new **To-do** (Úkol)]
```
#### Ambiguous UI Terms
If a UI term has multiple valid translations depending on context, use the `question` tool:
```
question: "The term 'Board' appears in the UI. Which translation fits this context?"
options: ["Pinnwand (pinboard/bulletin)", "Tafel (whiteboard)", "Gremium (committee)"]
```
### 6. Publish to Outline
Use mcp-outline tools to publish:
1. **Find or create collection:**
- `Outline_list_collections` to find target collection
- `Outline_create_collection` if needed
2. **Create document:**
- `Outline_create_document` with translated markdown content
- Set `publish: true` for immediate visibility
- Use `parent_document_id` if nesting under an existing doc
3. **For multi-language:** Create one document per language, clearly titled:
- `[Product Name] - Dokumentation (DE)`
- `[Product Name] - Dokumentace (CZ)`
## Error Handling
| Issue | Action |
|-------|--------|
| URL fetch fails | Use `question` to ask for alternative URL or manual paste |
| Image download fails | Continue with placeholder, note in completion report |
| Outline API error (attachments) | Script retries 3x with backoff; on final failure save markdown to `/tmp/doc-translator-backup-TIMESTAMP.md`, report error |
| Outline API error (document) | Save markdown to `/tmp/doc-translator-backup-TIMESTAMP.md`, report error |
| Ambiguous UI term | Use `question` to ask user for correct translation |
| Large document (>5000 words) | Ask user if splitting into multiple docs is preferred |
| Multi-page docs | Ask user about scope before proceeding |
| Rate limiting | Wait and retry with exponential backoff |
If Outline publish fails, always save the translated markdown locally as backup before reporting the error.
## Completion Report
After each translation, output:
```
Translation Complete
Documents Created:
- DE: [Document Title] - ID: [xxx] - URL: https://wiki.az-gruppe.com/doc/[slug]
- CZ: [Document Title] - ID: [xxx] - URL: https://wiki.az-gruppe.com/doc/[slug]
Images Processed: X of Y successfully uploaded
Items Needing Review:
- [Any sections with complex screenshots]
- [Any failed image uploads with original URLs]
- [Any unclear UI terms that were best-guessed]
```
## Language Codes
| Code | Language | Native Name |
|------|----------|-------------|
| DE | German | Deutsch |
| CZ | Czech | Čeština |
## Environment Variables
| Variable | Purpose | Source |
|----------|---------|--------|
| `OUTLINE_API_KEY` | Bearer token for wiki.az-gruppe.com API | Auto-loaded from `/run/agenix/outline-key` by upload script |
## Integration with Other Skills
| Need | Skill | When |
|------|-------|------|
| Wiki document management | outline | Managing existing translated docs |
| Browser-based content extraction | playwright / dev-browser | When webfetch cannot access content (login-required pages) |

View File

@@ -0,0 +1,116 @@
#!/usr/bin/env bash
# Upload an image to Outline via presigned POST (two-step flow)
#
# Usage:
# upload_image_to_outline.sh <image_path> [document_id]
#
# Environment:
# OUTLINE_API_KEY - Bearer token for wiki.az-gruppe.com API
# Auto-loaded from /run/agenix/outline-key if not set
#
# Output (JSON to stdout):
# {"success": true, "attachment_url": "https://..."}
# Error (JSON to stderr):
# {"success": false, "error": "error message"}
set -euo pipefail
MAX_RETRIES=3
RETRY_DELAY=2
if [ $# -lt 1 ] || [ $# -gt 2 ]; then
echo '{"success": false, "error": "Usage: upload_image_to_outline.sh <image_path> [document_id]"}' >&2
exit 1
fi
IMAGE_PATH="$1"
DOCUMENT_ID="${2:-}"
if [ -z "${OUTLINE_API_KEY:-}" ]; then
if [ -f /run/agenix/outline-key ]; then
OUTLINE_API_KEY=$(cat /run/agenix/outline-key)
export OUTLINE_API_KEY
else
echo '{"success": false, "error": "OUTLINE_API_KEY not set and /run/agenix/outline-key not found"}' >&2
exit 1
fi
fi
# Check if file exists
if [ ! -f "$IMAGE_PATH" ]; then
echo "{\"success\": false, \"error\": \"Image file not found: $IMAGE_PATH\"}" >&2
exit 1
fi
# Extract image name and extension
IMAGE_NAME="$(basename "$IMAGE_PATH")"
EXTENSION="${IMAGE_NAME##*.}"
# Detect content type by extension
case "${EXTENSION,,}" in
png) CONTENT_TYPE="image/png" ;;
jpg|jpeg) CONTENT_TYPE="image/jpeg" ;;
gif) CONTENT_TYPE="image/gif" ;;
svg) CONTENT_TYPE="image/svg+xml" ;;
webp) CONTENT_TYPE="image/webp" ;;
*) CONTENT_TYPE="application/octet-stream" ;;
esac
FILESIZE=$(stat -c%s "$IMAGE_PATH" 2>/dev/null || stat -f%z "$IMAGE_PATH" 2>/dev/null)
if [ -z "$FILESIZE" ]; then
echo "{\"success\": false, \"error\": \"Failed to get file size for: $IMAGE_PATH\"}" >&2
exit 1
fi
REQUEST_BODY=$(jq -n \
--arg name "$IMAGE_NAME" \
--arg contentType "$CONTENT_TYPE" \
--argjson size "$FILESIZE" \
--arg documentId "$DOCUMENT_ID" \
'if $documentId == "" then
{name: $name, contentType: $contentType, size: $size}
else
{name: $name, contentType: $contentType, size: $size, documentId: $documentId}
end')
# Step 1: Create attachment record
RESPONSE=$(curl -s -X POST "https://wiki.az-gruppe.com/api/attachments.create" \
-H "Authorization: Bearer $OUTLINE_API_KEY" \
-H "Content-Type: application/json" \
-d "$REQUEST_BODY")
UPLOAD_URL=$(echo "$RESPONSE" | jq -r '.data.uploadUrl // empty')
ATTACHMENT_URL=$(echo "$RESPONSE" | jq -r '.data.attachment.url // empty')
if [ -z "$UPLOAD_URL" ]; then
ERROR_MSG=$(echo "$RESPONSE" | jq -r '.message // "Failed to create attachment"')
echo "{\"success\": false, \"error\": \"$ERROR_MSG\", \"response\": $(echo "$RESPONSE" | jq -c .)}" >&2
exit 1
fi
FORM_ARGS=()
while IFS= read -r line; do
key=$(echo "$line" | jq -r '.key')
value=$(echo "$line" | jq -r '.value')
FORM_ARGS+=(-F "$key=$value")
done < <(echo "$RESPONSE" | jq -c '.data.form | to_entries[]')
# Step 2: Upload binary to presigned URL with retry
for attempt in $(seq 1 "$MAX_RETRIES"); do
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" -X POST "$UPLOAD_URL" \
"${FORM_ARGS[@]}" \
-F "file=@$IMAGE_PATH")
if [ "$HTTP_CODE" = "200" ] || [ "$HTTP_CODE" = "201" ] || [ "$HTTP_CODE" = "204" ]; then
echo "{\"success\": true, \"attachment_url\": \"$ATTACHMENT_URL\"}"
exit 0
fi
if [ "$attempt" -lt "$MAX_RETRIES" ]; then
sleep "$((RETRY_DELAY * attempt))"
fi
done
echo "{\"success\": false, \"error\": \"Upload failed after $MAX_RETRIES attempts (last HTTP $HTTP_CODE)\"}" >&2
exit 1

544
skills/excalidraw/SKILL.md Normal file
View File

@@ -0,0 +1,544 @@
---
name: excalidraw
description: "Create Excalidraw diagram JSON files that make visual arguments. Use when: (1) user wants to visualize workflows, architectures, or concepts, (2) creating system diagrams, (3) generating .excalidraw files. Triggers: excalidraw, diagram, visualize, architecture diagram, system diagram."
compatibility: opencode
---
# Excalidraw Diagram Creator
Generate `.excalidraw` JSON files that **argue visually**, not just display information.
## Customization
**All colors and brand-specific styles live in one file:** `references/color-palette.md`. Read it before generating any diagram and use it as the single source of truth for all color choices — shape fills, strokes, text colors, evidence artifact backgrounds, everything.
To make this skill produce diagrams in your own brand style, edit `color-palette.md`. Everything else in this file is universal design methodology and Excalidraw best practices.
---
## Core Philosophy
**Diagrams should ARGUE, not DISPLAY.**
A diagram isn't formatted text. It's a visual argument that shows relationships, causality, and flow that words alone can't express. The shape should BE the meaning.
**The Isomorphism Test**: If you removed all text, would the structure alone communicate the concept? If not, redesign.
**The Education Test**: Could someone learn something concrete from this diagram, or does it just label boxes? A good diagram teaches—it shows actual formats, real event names, concrete examples.
---
## Depth Assessment (Do This First)
Before designing, determine what level of detail this diagram needs:
### Simple/Conceptual Diagrams
Use abstract shapes when:
- Explaining a mental model or philosophy
- The audience doesn't need technical specifics
- The concept IS the abstraction (e.g., "separation of concerns")
### Comprehensive/Technical Diagrams
Use concrete examples when:
- Diagramming a real system, protocol, or architecture
- The diagram will be used to teach or explain (e.g., YouTube video)
- The audience needs to understand what things actually look like
- You're showing how multiple technologies integrate
**For technical diagrams, you MUST include evidence artifacts** (see below).
---
## Research Mandate (For Technical Diagrams)
**Before drawing anything technical, research the actual specifications.**
If you're diagramming a protocol, API, or framework:
1. Look up the actual JSON/data formats
2. Find the real event names, method names, or API endpoints
3. Understand how the pieces actually connect
4. Use real terminology, not generic placeholders
Bad: "Protocol" → "Frontend"
Good: "AG-UI streams events (RUN_STARTED, STATE_DELTA, A2UI_UPDATE)" → "CopilotKit renders via createA2UIMessageRenderer()"
**Research makes diagrams accurate AND educational.**
---
## Evidence Artifacts
Evidence artifacts are concrete examples that prove your diagram is accurate and help viewers learn. Include them in technical diagrams.
**Types of evidence artifacts** (choose what's relevant to your diagram):
| Artifact Type | When to Use | How to Render |
|---------------|-------------|---------------|
| **Code snippets** | APIs, integrations, implementation details | Dark rectangle + syntax-colored text (see color palette for evidence artifact colors) |
| **Data/JSON examples** | Data formats, schemas, payloads | Dark rectangle + colored text (see color palette) |
| **Event/step sequences** | Protocols, workflows, lifecycles | Timeline pattern (line + dots + labels) |
| **UI mockups** | Showing actual output/results | Nested rectangles mimicking real UI |
| **Real input content** | Showing what goes IN to a system | Rectangle with sample content visible |
| **API/method names** | Real function calls, endpoints | Use actual names from docs, not placeholders |
**Example**: For a diagram about a streaming protocol, you might show:
- The actual event names from the spec (not just "Event 1", "Event 2")
- A code snippet showing how to connect
- What the streamed data actually looks like
**Example**: For a diagram about a data transformation pipeline:
- Show sample input data (actual format, not "Input")
- Show sample output data (actual format, not "Output")
- Show intermediate states if relevant
The key principle: **show what things actually look like**, not just what they're called.
---
## Multi-Zoom Architecture
Comprehensive diagrams operate at multiple zoom levels simultaneously. Think of it like a map that shows both the country borders AND the street names.
### Level 1: Summary Flow
A simplified overview showing the full pipeline or process at a glance. Often placed at the top or bottom of the diagram.
*Example*: `Input → Processing → Output` or `Client → Server → Database`
### Level 2: Section Boundaries
Labeled regions that group related components. These create visual "rooms" that help viewers understand what belongs together.
*Example*: Grouping by responsibility (Backend / Frontend), by phase (Setup / Execution / Cleanup), or by team (User / System / External)
### Level 3: Detail Inside Sections
Evidence artifacts, code snippets, and concrete examples within each section. This is where the educational value lives.
*Example*: Inside a "Backend" section, you might show the actual API response format, not just a box labeled "API Response"
**For comprehensive diagrams, aim to include all three levels.** The summary gives context, the sections organize, and the details teach.
### Bad vs Good
| Bad (Displaying) | Good (Arguing) |
|------------------|----------------|
| 5 equal boxes with labels | Each concept has a shape that mirrors its behavior |
| Card grid layout | Visual structure matches conceptual structure |
| Icons decorating text | Shapes that ARE the meaning |
| Same container for everything | Distinct visual vocabulary per concept |
| Everything in a box | Free-floating text with selective containers |
### Simple vs Comprehensive (Know Which You Need)
| Simple Diagram | Comprehensive Diagram |
|----------------|----------------------|
| Generic labels: "Input" → "Process" → "Output" | Specific: shows what the input/output actually looks like |
| Named boxes: "API", "Database", "Client" | Named boxes + examples of actual requests/responses |
| "Events" or "Messages" label | Timeline with real event/message names from the spec |
| "UI" or "Dashboard" rectangle | Mockup showing actual UI elements and content |
| ~30 seconds to explain | ~2-3 minutes of teaching content |
| Viewer learns the structure | Viewer learns the structure AND the details |
**Simple diagrams** are fine for abstract concepts, quick overviews, or when the audience already knows the details. **Comprehensive diagrams** are needed for technical architectures, tutorials, educational content, or when you want the diagram itself to teach.
---
## Container vs. Free-Floating Text
**Not every piece of text needs a shape around it.** Default to free-floating text. Add containers only when they serve a purpose.
| Use a Container When... | Use Free-Floating Text When... |
|------------------------|-------------------------------|
| It's the focal point of a section | It's a label or description |
| It needs visual grouping with other elements | It's supporting detail or metadata |
| Arrows need to connect to it | It describes something nearby |
| The shape itself carries meaning (decision diamond, etc.) | It's a section title, subtitle, or annotation |
| It represents a distinct "thing" in the system | It's a section title, subtitle, or annotation |
**Typography as hierarchy**: Use font size, weight, and color to create visual hierarchy without boxes. A 28px title doesn't need a rectangle around it.
**The container test**: For each boxed element, ask "Would this work as free-floating text?" If yes, remove the container.
---
## Design Process (Do This BEFORE Generating JSON)
### Step 0: Assess Depth Required
Before anything else, determine if this needs to be:
- **Simple/Conceptual**: Abstract shapes, labels, relationships (mental models, philosophies)
- **Comprehensive/Technical**: Concrete examples, code snippets, real data (systems, architectures, tutorials)
**If comprehensive**: Do research first. Look up actual specs, formats, event names, APIs.
### Step 1: Understand Deeply
Read the content. For each concept, ask:
- What does this concept **DO**? (not what IS it)
- What relationships exist between concepts?
- What's the core transformation or flow?
- **What would someone need to SEE to understand this?** (not just read about)
### Step 2: Map Concepts to Patterns
For each concept, find the visual pattern that mirrors its behavior:
| If the concept... | Use this pattern |
|-------------------|------------------|
| Spawns multiple outputs | **Fan-out** (radial arrows from center) |
| Combines inputs into one | **Convergence** (funnel, arrows merging) |
| Has hierarchy/nesting | **Tree** (lines + free-floating text) |
| Is a sequence of steps | **Timeline** (line + dots + free-floating labels) |
| Loops or improves continuously | **Spiral/Cycle** (arrow returning to start) |
| Is an abstract state or context | **Cloud** (overlapping ellipses) |
| Transforms input to output | **Assembly line** (before → process → after) |
| Compares two things | **Side-by-side** (parallel with contrast) |
| Separates into phases | **Gap/Break** (visual separation between sections) |
### Step 3: Ensure Variety
For multi-concept diagrams: **each major concept must use a different visual pattern**. No uniform cards or grids.
### Step 4: Sketch the Flow
Before JSON, mentally trace how the eye moves through the diagram. There should be a clear visual story.
### Step 5: Generate JSON
Only now create the Excalidraw elements. **See below for how to handle large diagrams.**
### Step 6: Render & Validate (MANDATORY)
After generating the JSON, you MUST run the render-view-fix loop until the diagram looks right. This is not optional — see the **Render & Validate** section below for the full process.
---
## Large / Comprehensive Diagram Strategy
**For comprehensive or technical diagrams, you MUST build the JSON one section at a time.** Do NOT attempt to generate the entire file in a single pass. This is a hard constraint — output token limits mean a comprehensive diagram easily exceeds capacity in one shot. Even if it didn't, generating everything at once leads to worse quality. Section-by-section is better in every way.
### The Section-by-Section Workflow
**Phase 1: Build each section**
1. **Create the base file** with the JSON wrapper (`type`, `version`, `appState`, `files`) and the first section of elements.
2. **Add one section per edit.** Each section gets its own dedicated pass — take your time with it. Think carefully about the layout, spacing, and how this section connects to what's already there.
3. **Use descriptive string IDs** (e.g., `"trigger_rect"`, `"arrow_fan_left"`) so cross-section references are readable.
4. **Namespace seeds by section** (e.g., section 1 uses 100xxx, section 2 uses 200xxx) to avoid collisions.
5. **Update cross-section bindings** as you go. When a new section's element needs to bind to an element from a previous section (e.g., an arrow connecting sections), edit the earlier element's `boundElements` array at the same time.
**Phase 2: Review the whole**
After all sections are in place, read through the complete JSON and check:
- Are cross-section arrows bound correctly on both ends?
- Is the overall spacing balanced, or are some sections cramped while others have too much whitespace?
- Do IDs and bindings all reference elements that actually exist?
Fix any alignment or binding issues before rendering.
**Phase 3: Render & validate**
Now run the render-view-fix loop from the Render & Validate section. This is where you'll catch visual issues that aren't obvious from JSON — overlaps, clipping, imbalanced composition.
### Section Boundaries
Plan your sections around natural visual groupings from the diagram plan. A typical large diagram might split into:
- **Section 1**: Entry point / trigger
- **Section 2**: First decision or routing
- **Section 3**: Main content (hero section — may be the largest single section)
- **Section 4-N**: Remaining phases, outputs, etc.
Each section should be independently understandable: its elements, internal arrows, and any cross-references to adjacent sections.
### What NOT to Do
- **Don't generate the entire diagram in one response.** You will hit the output token limit and produce truncated, broken JSON. Even if the diagram is small enough to fit, splitting into sections produces better results.
- **Don't write a Python generator script.** The templating and coordinate math seem helpful but introduce a layer of indirection that makes debugging harder. Hand-crafted JSON with descriptive IDs is more maintainable.
---
## Visual Pattern Library
### Fan-Out (One-to-Many)
Central element with arrows radiating to multiple targets. Use for: sources, PRDs, root causes, central hubs.
```
□ → ○
```
### Convergence (Many-to-One)
Multiple inputs merging through arrows to single output. Use for: aggregation, funnels, synthesis.
```
○ ↘
○ → □
○ ↗
```
### Tree (Hierarchy)
Parent-child branching with connecting lines and free-floating text (no boxes needed). Use for: file systems, org charts, taxonomies.
```
label
├── label
│ ├── label
│ └── label
└── label
```
Use `line` elements for the trunk and branches, free-floating text for labels.
### Spiral/Cycle (Continuous Loop)
Elements in sequence with arrow returning to start. Use for: feedback loops, iterative processes, evolution.
```
□ → □
↑ ↓
□ ← □
```
### Cloud (Abstract State)
Overlapping ellipses with varied sizes. Use for: context, memory, conversations, mental states.
### Assembly Line (Transformation)
Input → Process Box → Output with clear before/after. Use for: transformations, processing, conversion.
```
○○○ → [PROCESS] → □□□
chaos order
```
### Side-by-Side (Comparison)
Two parallel structures with visual contrast. Use for: before/after, options, trade-offs.
### Gap/Break (Separation)
Visual whitespace or barrier between sections. Use for: phase changes, context resets, boundaries.
### Lines as Structure
Use lines (type: `line`, not arrows) as primary structural elements instead of boxes:
- **Timelines**: Vertical or horizontal line with small dots (10-20px ellipses) at intervals, free-floating labels beside each dot
- **Tree structures**: Vertical trunk line + horizontal branch lines, with free-floating text labels (no boxes needed)
- **Dividers**: Thin dashed lines to separate sections
- **Flow spines**: A central line that elements relate to, rather than connecting boxes
```
Timeline: Tree:
●─── Label 1 │
│ ├── item
●─── Label 2 │ ├── sub
│ │ └── sub
●─── Label 3 └── item
```
Lines + free-floating text often creates a cleaner result than boxes + contained text.
---
## Shape Meaning
Choose shape based on what it represents—or use no shape at all:
| Concept Type | Shape | Why |
|--------------|-------|-----|
| Labels, descriptions, details | **none** (free-floating text) | Typography creates hierarchy |
| Section titles, annotations | **none** (free-floating text) | Font size/weight is enough |
| Markers on a timeline | small `ellipse` (10-20px) | Visual anchor, not container |
| Start, trigger, input | `ellipse` | Soft, origin-like |
| End, output, result | `ellipse` | Completion, destination |
| Decision, condition | `diamond` | Classic decision symbol |
| Process, action, step | `rectangle` | Contained action |
| Abstract state, context | overlapping `ellipse` | Fuzzy, cloud-like |
| Hierarchy node | lines + text (no boxes) | Structure through lines |
**Rule**: Default to no container. Add shapes only when they carry meaning. Aim for <30% of text elements to be inside containers.
---
## Color as Meaning
Colors encode information, not decoration. Every color choice should come from `references/color-palette.md` — the semantic shape colors, text hierarchy colors, and evidence artifact colors are all defined there.
**Key principles:**
- Each semantic purpose (start, end, decision, AI, error, etc.) has a specific fill/stroke pair
- Free-floating text uses color for hierarchy (titles, subtitles, details — each at a different level)
- Evidence artifacts (code snippets, JSON examples) use their own dark background + colored text scheme
- Always pair a darker stroke with a lighter fill for contrast
**Do not invent new colors.** If a concept doesn't fit an existing semantic category, use Primary/Neutral or Secondary.
---
## Modern Aesthetics
For clean, professional diagrams:
### Roughness
- `roughness: 0` — Clean, crisp edges. Use for modern/technical diagrams.
- `roughness: 1` — Hand-drawn, organic feel. Use for brainstorming/informal diagrams.
**Default to 0** for most professional use cases.
### Stroke Width
- `strokeWidth: 1` — Thin, elegant. Good for lines, dividers, subtle connections.
- `strokeWidth: 2` — Standard. Good for shapes and primary arrows.
- `strokeWidth: 3` — Bold. Use sparingly for emphasis (main flow line, key connections).
### Opacity
**Always use `opacity: 100` for all elements.** Use color, size, and stroke width to create hierarchy instead of transparency.
### Small Markers Instead of Shapes
Instead of full shapes, use small dots (10-20px ellipses) as:
- Timeline markers
- Bullet points
- Connection nodes
- Visual anchors for free-floating text
---
## Layout Principles
### Hierarchy Through Scale
- **Hero**: 300×150 - visual anchor, most important
- **Primary**: 180×90
- **Secondary**: 120×60
- **Small**: 60×40
### Whitespace = Importance
The most important element has the most empty space around it (200px+).
### Flow Direction
Guide the eye: typically left→right or top→bottom for sequences, radial for hub-and-spoke.
### Connections Required
Position alone doesn't show relationships. If A relates to B, there must be an arrow.
---
## Text Rules
**CRITICAL**: The JSON `text` property contains ONLY readable words.
```json
{
"id": "myElement1",
"text": "Start",
"originalText": "Start"
}
```
Settings: `fontSize: 16`, `fontFamily: 3`, `textAlign: "center"`, `verticalAlign: "middle"`
---
## JSON Structure
```json
{
"type": "excalidraw",
"version": 2,
"source": "https://excalidraw.com",
"elements": [...],
"appState": {
"viewBackgroundColor": "#ffffff",
"gridSize": 20
},
"files": {}
}
```
## Element Templates
See `references/element-templates.md` for copy-paste JSON templates for each element type (text, line, dot, rectangle, arrow). Pull colors from `references/color-palette.md` based on each element's semantic purpose.
---
## Render & Validate (MANDATORY)
You cannot judge a diagram from JSON alone. After generating or editing the Excalidraw JSON, you MUST render it to PNG, view the image, and fix what you see — in a loop until it's right. This is a core part of the workflow, not a final check.
### How to Render
Run the render script from the skill's `references/` directory:
```bash
python3 <skill-references-dir>/render_excalidraw.py <path-to-file.excalidraw>
```
This outputs a PNG next to the `.excalidraw` file. Then use the **Read tool** on the PNG to actually view it.
### The Loop
After generating the initial JSON, run this cycle:
**1. Render & View** — Run the render script, then Read the PNG.
**2. Audit against your original vision** — Before looking for bugs, compare the rendered result to what you designed in Steps 1-4. Ask:
- Does the visual structure match the conceptual structure you planned?
- Does each section use the pattern you intended (fan-out, convergence, timeline, etc.)?
- Does the eye flow through the diagram in the order you designed?
- Is the visual hierarchy correct — hero elements dominant, supporting elements smaller?
- For technical diagrams: are the evidence artifacts (code snippets, data examples) readable and properly placed?
**3. Check for visual defects:**
- Text clipped by or overflowing its container
- Text or shapes overlapping other elements
- Arrows crossing through elements instead of routing around them
- Arrows landing on the wrong element or pointing into empty space
- Labels floating ambiguously (not clearly anchored to what they describe)
- Uneven spacing between elements that should be evenly spaced
- Sections with too much whitespace next to sections that are too cramped
- Text too small to read at the rendered size
- Overall composition feels lopsided or unbalanced
**4. Fix** — Edit the JSON to address everything you found. Common fixes:
- Widen containers when text is clipped
- Adjust `x`/`y` coordinates to fix spacing and alignment
- Add intermediate waypoints to arrow `points` arrays to route around elements
- Reposition labels closer to the element they describe
- Resize elements to rebalance visual weight across sections
**5. Re-render & re-view** — Run the render script again and Read the new PNG.
**6. Repeat** — Keep cycling until the diagram passes both the vision check (Step 2) and the defect check (Step 3). Typically takes 2-4 iterations. Don't stop after one pass just because there are no critical bugs — if the composition could be better, improve it.
### When to Stop
The loop is done when:
- The rendered diagram matches the conceptual design from your planning steps
- No text is clipped, overlapping, or unreadable
- Arrows route cleanly and connect to the right elements
- Spacing is consistent and the composition is balanced
- You'd be comfortable showing it to someone without caveats
---
## Quality Checklist
### Depth & Evidence (Check First for Technical Diagrams)
1. **Research done**: Did you look up actual specs, formats, event names?
2. **Evidence artifacts**: Are there code snippets, JSON examples, or real data?
3. **Multi-zoom**: Does it have summary flow + section boundaries + detail?
4. **Concrete over abstract**: Real content shown, not just labeled boxes?
5. **Educational value**: Could someone learn something concrete from this?
### Conceptual
6. **Isomorphism**: Does each visual structure mirror its concept's behavior?
7. **Argument**: Does the diagram SHOW something text alone couldn't?
8. **Variety**: Does each major concept use a different visual pattern?
9. **No uniform containers**: Avoided card grids and equal boxes?
### Container Discipline
10. **Minimal containers**: Could any boxed element work as free-floating text instead?
11. **Lines as structure**: Are tree/timeline patterns using lines + text rather than boxes?
12. **Typography hierarchy**: Are font size and color creating visual hierarchy (reducing need for boxes)?
### Structural
13. **Connections**: Every relationship has an arrow or line
14. **Flow**: Clear visual path for the eye to follow
15. **Hierarchy**: Important elements are larger/more isolated
### Technical
16. **Text clean**: `text` contains only readable words
17. **Font**: `fontFamily: 3`
18. **Roughness**: `roughness: 0` for clean/modern (unless hand-drawn style requested)
19. **Opacity**: `opacity: 100` for all elements (no transparency)
20. **Container ratio**: <30% of text elements should be inside containers
### Visual Validation (Render Required)
21. **Rendered to PNG**: Diagram has been rendered and visually inspected
22. **No text overflow**: All text fits within its container
23. **No overlapping elements**: Shapes and text don't overlap unintentionally
24. **Even spacing**: Similar elements have consistent spacing
25. **Arrows land correctly**: Arrows connect to intended elements without crossing others
26. **Readable at export size**: Text is legible in the rendered PNG
27. **Balanced composition**: No large empty voids or overcrowded regions

View File

@@ -0,0 +1,67 @@
# Color Palette & Brand Style
**This is the single source of truth for all colors and brand-specific styles.** To customize diagrams for your own brand, edit this file — everything else in the skill is universal.
---
## Shape Colors (Semantic)
Colors encode meaning, not decoration. Each semantic purpose has a fill/stroke pair.
| Semantic Purpose | Fill | Stroke |
|------------------|------|--------|
| Primary/Neutral | `#3b82f6` | `#1e3a5f` |
| Secondary | `#60a5fa` | `#1e3a5f` |
| Tertiary | `#93c5fd` | `#1e3a5f` |
| Start/Trigger | `#fed7aa` | `#c2410c` |
| End/Success | `#a7f3d0` | `#047857` |
| Warning/Reset | `#fee2e2` | `#dc2626` |
| Decision | `#fef3c7` | `#b45309` |
| AI/LLM | `#ddd6fe` | `#6d28d9` |
| Inactive/Disabled | `#dbeafe` | `#1e40af` (use dashed stroke) |
| Error | `#fecaca` | `#b91c1c` |
**Rule**: Always pair a darker stroke with a lighter fill for contrast.
---
## Text Colors (Hierarchy)
Use color on free-floating text to create visual hierarchy without containers.
| Level | Color | Use For |
|-------|-------|---------|
| Title | `#1e40af` | Section headings, major labels |
| Subtitle | `#3b82f6` | Subheadings, secondary labels |
| Body/Detail | `#64748b` | Descriptions, annotations, metadata |
| On light fills | `#374151` | Text inside light-colored shapes |
| On dark fills | `#ffffff` | Text inside dark-colored shapes |
---
## Evidence Artifact Colors
Used for code snippets, data examples, and other concrete evidence inside technical diagrams.
| Artifact | Background | Text Color |
|----------|-----------|------------|
| Code snippet | `#1e293b` | Syntax-colored (language-appropriate) |
| JSON/data example | `#1e293b` | `#22c55e` (green) |
---
## Default Stroke & Line Colors
| Element | Color |
|---------|-------|
| Arrows | Use the stroke color of the source element's semantic purpose |
| Structural lines (dividers, trees, timelines) | Primary stroke (`#1e3a5f`) or Slate (`#64748b`) |
| Marker dots (fill + stroke) | Primary fill (`#3b82f6`) |
---
## Background
| Property | Value |
|----------|-------|
| Canvas background | `#ffffff` |

View File

@@ -0,0 +1,182 @@
# Element Templates
Copy-paste JSON templates for each Excalidraw element type. The `strokeColor` and `backgroundColor` values are placeholders — always pull actual colors from `color-palette.md` based on the element's semantic purpose.
## Free-Floating Text (no container)
```json
{
"type": "text",
"id": "label1",
"x": 100, "y": 100,
"width": 200, "height": 25,
"text": "Section Title",
"originalText": "Section Title",
"fontSize": 20,
"fontFamily": 3,
"textAlign": "left",
"verticalAlign": "top",
"strokeColor": "<title color from palette>",
"backgroundColor": "transparent",
"fillStyle": "solid",
"strokeWidth": 1,
"strokeStyle": "solid",
"roughness": 0,
"opacity": 100,
"angle": 0,
"seed": 11111,
"version": 1,
"versionNonce": 22222,
"isDeleted": false,
"groupIds": [],
"boundElements": null,
"link": null,
"locked": false,
"containerId": null,
"lineHeight": 1.25
}
```
## Line (structural, not arrow)
```json
{
"type": "line",
"id": "line1",
"x": 100, "y": 100,
"width": 0, "height": 200,
"strokeColor": "<structural line color from palette>",
"backgroundColor": "transparent",
"fillStyle": "solid",
"strokeWidth": 2,
"strokeStyle": "solid",
"roughness": 0,
"opacity": 100,
"angle": 0,
"seed": 44444,
"version": 1,
"versionNonce": 55555,
"isDeleted": false,
"groupIds": [],
"boundElements": null,
"link": null,
"locked": false,
"points": [[0, 0], [0, 200]]
}
```
## Small Marker Dot
```json
{
"type": "ellipse",
"id": "dot1",
"x": 94, "y": 94,
"width": 12, "height": 12,
"strokeColor": "<marker dot color from palette>",
"backgroundColor": "<marker dot color from palette>",
"fillStyle": "solid",
"strokeWidth": 1,
"strokeStyle": "solid",
"roughness": 0,
"opacity": 100,
"angle": 0,
"seed": 66666,
"version": 1,
"versionNonce": 77777,
"isDeleted": false,
"groupIds": [],
"boundElements": null,
"link": null,
"locked": false
}
```
## Rectangle
```json
{
"type": "rectangle",
"id": "elem1",
"x": 100, "y": 100, "width": 180, "height": 90,
"strokeColor": "<stroke from palette based on semantic purpose>",
"backgroundColor": "<fill from palette based on semantic purpose>",
"fillStyle": "solid",
"strokeWidth": 2,
"strokeStyle": "solid",
"roughness": 0,
"opacity": 100,
"angle": 0,
"seed": 12345,
"version": 1,
"versionNonce": 67890,
"isDeleted": false,
"groupIds": [],
"boundElements": [{"id": "text1", "type": "text"}],
"link": null,
"locked": false,
"roundness": {"type": 3}
}
```
## Text (centered in shape)
```json
{
"type": "text",
"id": "text1",
"x": 130, "y": 132,
"width": 120, "height": 25,
"text": "Process",
"originalText": "Process",
"fontSize": 16,
"fontFamily": 3,
"textAlign": "center",
"verticalAlign": "middle",
"strokeColor": "<text color — match parent shape's stroke or use 'on light/dark fills' from palette>",
"backgroundColor": "transparent",
"fillStyle": "solid",
"strokeWidth": 1,
"strokeStyle": "solid",
"roughness": 0,
"opacity": 100,
"angle": 0,
"seed": 11111,
"version": 1,
"versionNonce": 22222,
"isDeleted": false,
"groupIds": [],
"boundElements": null,
"link": null,
"locked": false,
"containerId": "elem1",
"lineHeight": 1.25
}
```
## Arrow
```json
{
"type": "arrow",
"id": "arrow1",
"x": 282, "y": 145, "width": 118, "height": 0,
"strokeColor": "<arrow color — typically matches source element's stroke from palette>",
"backgroundColor": "transparent",
"fillStyle": "solid",
"strokeWidth": 2,
"strokeStyle": "solid",
"roughness": 0,
"opacity": 100,
"angle": 0,
"seed": 33333,
"version": 1,
"versionNonce": 44444,
"isDeleted": false,
"groupIds": [],
"boundElements": null,
"link": null,
"locked": false,
"points": [[0, 0], [118, 0]],
"startBinding": {"elementId": "elem1", "focus": 0, "gap": 2},
"endBinding": {"elementId": "elem2", "focus": 0, "gap": 2},
"startArrowhead": null,
"endArrowhead": "arrow"
}
```
For curves: use 3+ points in `points` array.

View File

@@ -0,0 +1,71 @@
# Excalidraw JSON Schema
## Element Types
| Type | Use For |
|------|---------|
| `rectangle` | Processes, actions, components |
| `ellipse` | Entry/exit points, external systems |
| `diamond` | Decisions, conditionals |
| `arrow` | Connections between shapes |
| `text` | Labels inside shapes |
| `line` | Non-arrow connections |
| `frame` | Grouping containers |
## Common Properties
All elements share these:
| Property | Type | Description |
|----------|------|-------------|
| `id` | string | Unique identifier |
| `type` | string | Element type |
| `x`, `y` | number | Position in pixels |
| `width`, `height` | number | Size in pixels |
| `strokeColor` | string | Border color (hex) |
| `backgroundColor` | string | Fill color (hex or "transparent") |
| `fillStyle` | string | "solid", "hachure", "cross-hatch" |
| `strokeWidth` | number | 1, 2, or 4 |
| `strokeStyle` | string | "solid", "dashed", "dotted" |
| `roughness` | number | 0 (smooth), 1 (default), 2 (rough) |
| `opacity` | number | 0-100 |
| `seed` | number | Random seed for roughness |
## Text-Specific Properties
| Property | Description |
|----------|-------------|
| `text` | The display text |
| `originalText` | Same as text |
| `fontSize` | Size in pixels (16-20 recommended) |
| `fontFamily` | 3 for monospace (use this) |
| `textAlign` | "left", "center", "right" |
| `verticalAlign` | "top", "middle", "bottom" |
| `containerId` | ID of parent shape |
## Arrow-Specific Properties
| Property | Description |
|----------|-------------|
| `points` | Array of [x, y] coordinates |
| `startBinding` | Connection to start shape |
| `endBinding` | Connection to end shape |
| `startArrowhead` | null, "arrow", "bar", "dot", "triangle" |
| `endArrowhead` | null, "arrow", "bar", "dot", "triangle" |
## Binding Format
```json
{
"elementId": "shapeId",
"focus": 0,
"gap": 2
}
```
## Rectangle Roundness
Add for rounded corners:
```json
"roundness": { "type": 3 }
```

View File

@@ -0,0 +1,205 @@
#!/usr/bin/env python3
"""Render Excalidraw JSON to PNG using Playwright + headless Chromium.
Usage:
python3 render_excalidraw.py <path-to-file.excalidraw> [--output path.png] [--scale 2] [--width 1920]
Dependencies (playwright, chromium) are provided by the Nix flake / direnv environment.
"""
from __future__ import annotations
import argparse
import json
import sys
from pathlib import Path
def validate_excalidraw(data: dict) -> list[str]:
"""Validate Excalidraw JSON structure. Returns list of errors (empty = valid)."""
errors: list[str] = []
if data.get("type") != "excalidraw":
errors.append(f"Expected type 'excalidraw', got '{data.get('type')}'")
if "elements" not in data:
errors.append("Missing 'elements' array")
elif not isinstance(data["elements"], list):
errors.append("'elements' must be an array")
elif len(data["elements"]) == 0:
errors.append("'elements' array is empty — nothing to render")
return errors
def compute_bounding_box(elements: list[dict]) -> tuple[float, float, float, float]:
"""Compute bounding box (min_x, min_y, max_x, max_y) across all elements."""
min_x = float("inf")
min_y = float("inf")
max_x = float("-inf")
max_y = float("-inf")
for el in elements:
if el.get("isDeleted"):
continue
x = el.get("x", 0)
y = el.get("y", 0)
w = el.get("width", 0)
h = el.get("height", 0)
# For arrows/lines, points array defines the shape relative to x,y
if el.get("type") in ("arrow", "line") and "points" in el:
for px, py in el["points"]:
min_x = min(min_x, x + px)
min_y = min(min_y, y + py)
max_x = max(max_x, x + px)
max_y = max(max_y, y + py)
else:
min_x = min(min_x, x)
min_y = min(min_y, y)
max_x = max(max_x, x + abs(w))
max_y = max(max_y, y + abs(h))
if min_x == float("inf"):
return (0, 0, 800, 600)
return (min_x, min_y, max_x, max_y)
def render(
excalidraw_path: Path,
output_path: Path | None = None,
scale: int = 2,
max_width: int = 1920,
) -> Path:
"""Render an .excalidraw file to PNG. Returns the output PNG path."""
# Import playwright here so validation errors show before import errors
try:
from playwright.sync_api import sync_playwright
except ImportError:
print("ERROR: playwright not installed.", file=sys.stderr)
print("Ensure the Nix dev shell is active (direnv allow).", file=sys.stderr)
sys.exit(1)
# Read and validate
raw = excalidraw_path.read_text(encoding="utf-8")
try:
data = json.loads(raw)
except json.JSONDecodeError as e:
print(f"ERROR: Invalid JSON in {excalidraw_path}: {e}", file=sys.stderr)
sys.exit(1)
errors = validate_excalidraw(data)
if errors:
print(f"ERROR: Invalid Excalidraw file:", file=sys.stderr)
for err in errors:
print(f" - {err}", file=sys.stderr)
sys.exit(1)
# Compute viewport size from element bounding box
elements = [e for e in data["elements"] if not e.get("isDeleted")]
min_x, min_y, max_x, max_y = compute_bounding_box(elements)
padding = 80
diagram_w = max_x - min_x + padding * 2
diagram_h = max_y - min_y + padding * 2
# Cap viewport width, let height be natural
vp_width = min(int(diagram_w), max_width)
vp_height = max(int(diagram_h), 600)
# Output path
if output_path is None:
output_path = excalidraw_path.with_suffix(".png")
# Template path (same directory as this script)
template_path = Path(__file__).parent / "render_template.html"
if not template_path.exists():
print(f"ERROR: Template not found at {template_path}", file=sys.stderr)
sys.exit(1)
template_url = template_path.as_uri()
with sync_playwright() as p:
try:
browser = p.chromium.launch(headless=True)
except Exception as e:
if "Executable doesn't exist" in str(e) or "browserType.launch" in str(e):
print("ERROR: Chromium not installed for Playwright.", file=sys.stderr)
print("Ensure the Nix dev shell is active (direnv allow).", file=sys.stderr)
sys.exit(1)
raise
page = browser.new_page(
viewport={"width": vp_width, "height": vp_height},
device_scale_factor=scale,
)
# Load the template
page.goto(template_url)
# Wait for the ES module to load (imports from esm.sh)
page.wait_for_function("window.__moduleReady === true", timeout=30000)
# Inject the diagram data and render
json_str = json.dumps(data)
result = page.evaluate(f"window.renderDiagram({json_str})")
if not result or not result.get("success"):
error_msg = (
result.get("error", "Unknown render error")
if result
else "renderDiagram returned null"
)
print(f"ERROR: Render failed: {error_msg}", file=sys.stderr)
browser.close()
sys.exit(1)
# Wait for render completion signal
page.wait_for_function("window.__renderComplete === true", timeout=15000)
# Screenshot the SVG element
svg_el = page.query_selector("#root svg")
if svg_el is None:
print("ERROR: No SVG element found after render.", file=sys.stderr)
browser.close()
sys.exit(1)
svg_el.screenshot(path=str(output_path))
browser.close()
return output_path
def main() -> None:
"""Entry point for rendering Excalidraw JSON files to PNG."""
parser = argparse.ArgumentParser(description="Render Excalidraw JSON to PNG")
parser.add_argument("input", type=Path, help="Path to .excalidraw JSON file")
parser.add_argument(
"--output",
"-o",
type=Path,
default=None,
help="Output PNG path (default: same name with .png)",
)
parser.add_argument(
"--scale", "-s", type=int, default=2, help="Device scale factor (default: 2)"
)
parser.add_argument(
"--width",
"-w",
type=int,
default=1920,
help="Max viewport width (default: 1920)",
)
args = parser.parse_args()
if not args.input.exists():
print(f"ERROR: File not found: {args.input}", file=sys.stderr)
sys.exit(1)
png_path = render(args.input, args.output, args.scale, args.width)
print(str(png_path))
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,57 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { background: #ffffff; overflow: hidden; }
#root { display: inline-block; }
#root svg { display: block; }
</style>
</head>
<body>
<div id="root"></div>
<script type="module">
import { exportToSvg } from "https://esm.sh/@excalidraw/excalidraw?bundle";
window.renderDiagram = async function(jsonData) {
try {
const data = typeof jsonData === "string" ? JSON.parse(jsonData) : jsonData;
const elements = data.elements || [];
const appState = data.appState || {};
const files = data.files || {};
// Force white background in appState
appState.viewBackgroundColor = appState.viewBackgroundColor || "#ffffff";
appState.exportWithDarkMode = false;
const svg = await exportToSvg({
elements: elements,
appState: {
...appState,
exportBackground: true,
},
files: files,
});
// Clear any previous render
const root = document.getElementById("root");
root.innerHTML = "";
root.appendChild(svg);
window.__renderComplete = true;
window.__renderError = null;
return { success: true, width: svg.getAttribute("width"), height: svg.getAttribute("height") };
} catch (err) {
window.__renderComplete = true;
window.__renderError = err.message;
return { success: false, error: err.message };
}
};
// Signal that the module is loaded and ready
window.__moduleReady = true;
</script>
</body>
</html>

View File

@@ -0,0 +1,42 @@
---
name: frontend-design
description: Create distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
license: Complete terms in LICENSE.txt
---
This skill guides creation of distinctive, production-grade frontend interfaces that avoid generic "AI slop" aesthetics. Implement real working code with exceptional attention to aesthetic details and creative choices.
The user provides frontend requirements: a component, page, application, or interface to build. They may include context about the purpose, audience, or technical constraints.
## Design Thinking
Before coding, understand the context and commit to a BOLD aesthetic direction:
- **Purpose**: What problem does this interface solve? Who uses it?
- **Tone**: Pick an extreme: brutally minimal, maximalist chaos, retro-futuristic, organic/natural, luxury/refined, playful/toy-like, editorial/magazine, brutalist/raw, art deco/geometric, soft/pastel, industrial/utilitarian, etc. There are so many flavors to choose from. Use these for inspiration but design one that is true to the aesthetic direction.
- **Constraints**: Technical requirements (framework, performance, accessibility).
- **Differentiation**: What makes this UNFORGETTABLE? What's the one thing someone will remember?
**CRITICAL**: Choose a clear conceptual direction and execute it with precision. Bold maximalism and refined minimalism both work - the key is intentionality, not intensity.
Then implement working code (HTML/CSS/JS, React, Vue, etc.) that is:
- Production-grade and functional
- Visually striking and memorable
- Cohesive with a clear aesthetic point-of-view
- Meticulously refined in every detail
## Frontend Aesthetics Guidelines
Focus on:
- **Typography**: Choose fonts that are beautiful, unique, and interesting. Avoid generic fonts like Arial and Inter; opt instead for distinctive choices that elevate the frontend's aesthetics; unexpected, characterful font choices. Pair a distinctive display font with a refined body font.
- **Color & Theme**: Commit to a cohesive aesthetic. Use CSS variables for consistency. Dominant colors with sharp accents outperform timid, evenly-distributed palettes.
- **Motion**: Use animations for effects and micro-interactions. Prioritize CSS-only solutions for HTML. Use Motion library for React when available. Focus on high-impact moments: one well-orchestrated page load with staggered reveals (animation-delay) creates more delight than scattered micro-interactions. Use scroll-triggering and hover states that surprise.
- **Spatial Composition**: Unexpected layouts. Asymmetry. Overlap. Diagonal flow. Grid-breaking elements. Generous negative space OR controlled density.
- **Backgrounds & Visual Details**: Create atmosphere and depth rather than defaulting to solid colors. Add contextual effects and textures that match the overall aesthetic. Apply creative forms like gradient meshes, noise textures, geometric patterns, layered transparencies, dramatic shadows, decorative borders, custom cursors, and grain overlays.
NEVER use generic AI-generated aesthetics like overused font families (Inter, Roboto, Arial, system fonts), cliched color schemes (particularly purple gradients on white backgrounds), predictable layouts and component patterns, and cookie-cutter design that lacks context-specific character.
Interpret creatively and make unexpected choices that feel genuinely designed for the context. No design should be the same. Vary between light and dark themes, different fonts, different aesthetics. NEVER converge on common choices (Space Grotesk, for example) across generations.
**IMPORTANT**: Match implementation complexity to the aesthetic vision. Maximalist designs need elaborate code with extensive animations and effects. Minimalist or refined designs need restraint, precision, and careful attention to spacing, typography, and subtle details. Elegance comes from executing the vision well.
Remember: the Coding Agent is capable of extraordinary creative work. Don't hold back, show what can truly be created when thinking outside the box and committing fully to a distinctive vision.

View File

@@ -1,10 +1,16 @@
---
name: mem0-memory
description: "Store and retrieve memories using Mem0 REST API. Use when: (1) storing information for future recall, (2) searching past conversations or facts, (3) managing user/agent memory contexts, (4) building conversational AI with persistent memory. Triggers on keywords like 'remember', 'recall', 'memory', 'store for later', 'what did I say about'."
description: "DEPRECATED: Replaced by opencode-memory plugin. See skills/memory/SKILL.md for current memory system."
compatibility: opencode
---
# Mem0 Memory
> ⚠️ **DEPRECATED**
>
> This skill is deprecated. The memory system has been replaced by the opencode-memory plugin.
>
> **See:** `skills/memory/SKILL.md` for the current memory system.
# Mem0 Memory (Legacy)
Store and retrieve memories via Mem0 REST API at `http://localhost:8000`.
@@ -108,6 +114,36 @@ Combine scopes for fine-grained control:
}
```
## Memory Categories
Memories are classified into 5 categories for organization:
| Category | Definition | Obsidian Path | Example |
|----------|------------|---------------|---------|
| `preference` | Personal preferences | `80-memory/preferences/` | UI settings, workflow styles |
| `fact` | Objective information | `80-memory/facts/` | Tech stack, role, constraints |
| `decision` | Choices with rationale | `80-memory/decisions/` | Tool selections, architecture |
| `entity` | People, orgs, systems | `80-memory/entities/` | Contacts, APIs, concepts |
| `other` | Everything else | `80-memory/other/` | General learnings |
### Metadata Pattern
Include category in metadata when storing:
```json
{
"messages": [...],
"user_id": "user123",
"metadata": {
"category": "preference",
"source": "explicit"
}
}
```
- `category`: One of preference, fact, decision, entity, other
- `source`: "explicit" (user requested) or "auto-capture" (automatic)
## Workflow Patterns
### Pattern 1: Remember User Preferences
@@ -137,6 +173,43 @@ curl -X POST http://localhost:8000/memories \
-d '{"messages":[...], "run_id":"SESSION_ID"}'
```
## Dual-Layer Sync
Memories are stored in BOTH Mem0 AND the Obsidian CODEX vault for redundancy and accessibility.
### Sync Pattern
1. **Store in Mem0 first** - Get `mem0_id` from response
2. **Create Obsidian note** - In `80-memory/<category>/` using memory template
3. **Cross-reference**:
- Add `mem0_id` to Obsidian note frontmatter
- Update Mem0 metadata with `obsidian_ref` (file path)
### Example Flow
```bash
# 1. Store in Mem0
RESPONSE=$(curl -s -X POST http://localhost:8000/memories \
-d '{"messages":[{"role":"user","content":"I prefer dark mode"}],"user_id":"m3tam3re","metadata":{"category":"preference","source":"explicit"}}')
# 2. Extract mem0_id
MEM0_ID=$(echo $RESPONSE | jq -r '.id')
# 3. Create Obsidian note (via REST API or MCP)
# Path: 80-memory/preferences/prefers-dark-mode.md
# Frontmatter includes: mem0_id: $MEM0_ID
# 4. Update Mem0 with Obsidian reference
curl -X PUT http://localhost:8000/memories/$MEM0_ID \
-d '{"metadata":{"obsidian_ref":"80-memory/preferences/prefers-dark-mode.md"}}'
```
### When Obsidian Unavailable
- Store in Mem0 only
- Log sync failure
- Retry on next access
## Response Format
Memory objects include:
@@ -161,6 +234,45 @@ Verify API is running:
curl http://localhost:8000/health
```
### Pre-Operation Check
Before any memory operation, verify Mem0 is running:
```bash
if ! curl -s http://localhost:8000/health > /dev/null 2>&1; then
echo "WARNING: Mem0 unavailable. Memory operations skipped."
# Continue without memory features
fi
```
## Error Handling
### Mem0 Unavailable
When `curl http://localhost:8000/health` fails:
- Skip all memory operations
- Warn user: "Memory system unavailable. Mem0 not running at localhost:8000"
- Continue with degraded functionality
### Obsidian Unavailable
When vault sync fails:
- Store in Mem0 only
- Log: "Obsidian sync failed for memory [id]"
- Do not block user workflow
### API Errors
| Status | Meaning | Action |
|--------|---------|--------|
| 400 | Bad request | Check JSON format, required fields |
| 404 | Memory not found | Memory may have been deleted |
| 500 | Server error | Retry, check Mem0 logs |
### Graceful Degradation
Always continue core functionality even if memory system fails. Memory is enhancement, not requirement.
## API Reference
See [references/api_reference.md](references/api_reference.md) for complete OpenAPI schema.

337
skills/obsidian/SKILL.md Normal file
View File

@@ -0,0 +1,337 @@
---
name: obsidian
description: "Obsidian Local REST API integration for knowledge management. Use when: (1) Creating, reading, updating, or deleting notes in Obsidian vault, (2) Searching vault content by title, content, or tags, (3) Managing daily notes and journaling, (4) Working with WikiLinks and vault metadata. Triggers: 'Obsidian', 'note', 'vault', 'WikiLink', 'daily note', 'journal', 'create note'."
compatibility: opencode
---
# Obsidian
Knowledge management integration via Obsidian Local REST API for vault operations, note CRUD, search, and daily notes.
## Prerequisites
- **Obsidian Local REST API plugin** installed and enabled in Obsidian
- **API server running** on default port `27124` (or configured custom port)
- **Vault path** configured in plugin settings
- **API key** set (optional, if authentication enabled)
API endpoints available at `http://127.0.0.1:27124` by default.
## Core Workflows
### List Vault Files
Get list of all files in vault:
```bash
curl -X GET "http://127.0.0.1:27124/list"
```
Returns array of file objects with `path`, `mtime`, `ctime`, `size`.
### Get File Metadata
Retrieve metadata for a specific file:
```bash
curl -X GET "http://127.0.0.1:27124/get-file-info?path=Note%20Title.md"
```
Returns file metadata including tags, links, frontmatter.
### Create Note
Create a new note in the vault:
```bash
curl -X POST "http://127.0.0.1:27124/create-note" \
-H "Content-Type: application/json" \
-d '{"content": "# Note Title\n\nNote content..."}'
```
Use `path` parameter for specific location:
```json
{
"content": "# Note Title\n\nNote content...",
"path": "subdirectory/Note Title.md"
}
```
### Read Note
Read note content by path:
```bash
curl -X GET "http://127.0.0.1:27124/read-note?path=Note%20Title.md"
```
Returns note content as plain text or structured JSON with frontmatter parsing.
### Update Note
Modify existing note:
```bash
curl -X PUT "http://127.0.0.1:27124/update-note" \
-H "Content-Type: application/json" \
-d '{"path": "Note Title.md", "content": "# Updated Title\n\nNew content..."}'
```
### Delete Note
Remove note from vault:
```bash
curl -X DELETE "http://127.0.0.1:27124/delete-note?path=Note%20Title.md"
```
**Warning**: This operation is irreversible. Confirm with user before executing.
### Search Notes
Find notes by content, title, or tags:
```bash
# Content search
curl -X GET "http://127.0.0.1:27124/search?q=search%20term"
# Search with parameters
curl -X GET "http://127.0.0.1:27124/search?q=search%20term&path=subdirectory&context-length=100"
```
Returns array of matches with file path and context snippets.
### Daily Notes
#### Get Daily Note
Retrieve or create daily note for specific date:
```bash
# Today
curl -X GET "http://127.0.0.1:27124/daily-note"
# Specific date (YYYY-MM-DD)
curl -X GET "http://127.0.0.1:27124/daily-note?date=2026-02-03"
```
Returns daily note content or creates using Obsidian's Daily Notes template.
#### Update Daily Note
Modify today's daily note:
```bash
curl -X PUT "http://127.0.0.1:27124/daily-note" \
-H "Content-Type: application/json" \
-d '{"content": "## Journal\n\nToday I learned..."}'
```
### Get Vault Info
Retrieve vault metadata:
```bash
curl -X GET "http://127.0.0.1:27124/vault-info"
```
Returns vault path, file count, and configuration details.
## Note Structure Patterns
### Frontmatter Conventions
Use consistent frontmatter for note types:
```yaml
---
date: 2026-02-03
created: 2026-02-03T10:30:00Z
type: note
tags: #tag1 #tag2
status: active
---
```
### WikiLinks
Reference other notes using Obsidian WikiLinks:
- `[[Note Title]]` - Link to note by title
- `[[Note Title|Alias]]` - Link with custom display text
- `[[Note Title#Heading]]` - Link to specific heading
- `![[Image.png]]` - Embed images or media
### Tagging
Use tags for categorization:
- `#tag` - Single-word tag
- `#nested/tag` - Hierarchical tags
- Tags in frontmatter for metadata
- Tags in content for inline categorization
## Workflow Examples
### Create Brainstorm Note
```bash
curl -X POST "http://127.0.0.1:27124/create-note" \
-H "Content-Type: application/json" \
-d '{
"path": "03-resources/brainstorms/2026-02-03-Topic.md",
"content": "---\ndate: 2026-02-03\ncreated: 2026-02-03T10:30:00Z\ntype: brainstorm\nframework: pros-cons\nstatus: draft\ntags: #brainstorm #pros-cons\n---\n\n# Topic\n\n## Context\n\n## Options\n\n## Decision\n"
}'
```
### Append to Daily Journal
```bash
# Get current daily note
NOTE=$(curl -s "http://127.0.0.1:27124/daily-note")
# Append content
curl -X PUT "http://127.0.0.1:27124/daily-note" \
-H "Content-Type: application/json" \
-d "{\"content\": \"${NOTE}\n\n## Journal Entry\n\nLearned about Obsidian API integration.\"}"
```
### Search and Link Notes
```bash
# Search for related notes
curl -s "http://127.0.0.1:27124/search?q=Obsidian"
# Create note with WikiLinks to found notes
curl -X POST "http://127.0.0.1:27124/create-note" \
-H "Content-Type: application/json" \
-d '{
"path": "02-areas/Obsidian API Guide.md",
"content": "# Obsidian API Guide\n\nSee [[API Endpoints]] and [[Workflows]] for details."
}'
```
## Integration with Other Skills
| From Obsidian | To skill | Handoff pattern |
|--------------|----------|----------------|
| Note created | brainstorming | Create brainstorm note with frontmatter |
| Daily note updated | reflection | Append conversation analysis to journal |
| Research note | research | Save research findings with tags |
| Project note | task-management | Link tasks to project notes |
| Plan document | plan-writing | Save generated plan to vault |
| Memory note | memory | Create/read memory notes in 80-memory/ |
## Best Practices
1. **Use paths consistently** - Follow PARA structure or vault conventions
2. **Include frontmatter** - Enables search and metadata queries
3. **Use WikiLinks** - Creates knowledge graph connections
4. **Validate paths** - Check file existence before operations
5. **Handle errors** - API may return 404 for non-existent files
6. **Escape special characters** - URL-encode paths with spaces or symbols
7. **Backup vault** - REST API operations modify files directly
---
## Memory Folder Conventions
The `80-memory/` folder stores dual-layer memories synced with Mem0.
### Structure
```
80-memory/
├── preferences/ # Personal preferences (UI, workflow, communication)
├── facts/ # Objective information (role, tech stack, constraints)
├── decisions/ # Choices with rationale (tool selections, architecture)
├── entities/ # People, organizations, systems, concepts
└── other/ # Everything else
```
### Naming Convention
Memory notes use kebab-case: `prefers-dark-mode.md`, `uses-typescript.md`
### Required Frontmatter
```yaml
---
type: memory
category: # preference | fact | decision | entity | other
mem0_id: # Mem0 memory ID (e.g., "mem_abc123")
source: explicit # explicit | auto-capture
importance: # critical | high | medium | low
created: 2026-02-12
updated: 2026-02-12
tags:
- memory
sync_targets: []
---
```
### Key Fields
| Field | Purpose |
|-------|---------|
| `mem0_id` | Links to Mem0 entry for semantic search |
| `category` | Determines subfolder and classification |
| `source` | How memory was captured (explicit request vs auto) |
| `importance` | Priority for recall ranking |
---
## Memory Note Workflows
### Create Memory Note
When creating a memory note in the vault:
```bash
# Using REST API
curl -X POST "http://127.0.0.1:27124/create-note" \
-H "Content-Type: application/json" \
-d '{
"path": "80-memory/preferences/prefers-dark-mode.md",
"content": "---\ntype: memory\ncategory: preference\nmem0_id: mem_abc123\nsource: explicit\nimportance: medium\ncreated: 2026-02-12\nupdated: 2026-02-12\ntags:\n - memory\nsync_targets: []\n---\n\n# Prefers Dark Mode\n\n## Content\n\nUser prefers dark mode in all applications.\n\n## Context\n\nStated during UI preferences discussion on 2026-02-12.\n\n## Related\n\n- [[UI Settings]]\n"
}'
```
### Read Memory Note
Read by path with URL encoding:
```bash
curl -X GET "http://127.0.0.1:27124/read-note?path=80-memory%2Fpreferences%2Fprefers-dark-mode.md"
```
### Search Memories
Search within memory folder:
```bash
curl -X GET "http://127.0.0.1:27124/search?q=dark%20mode&path=80-memory"
```
### Update Memory Note
Update content and frontmatter:
```bash
curl -X PUT "http://127.0.0.1:27124/update-note" \
-H "Content-Type: application/json" \
-d '{
"path": "80-memory/preferences/prefers-dark-mode.md",
"content": "# Updated content..."
}'
```
---
## Error Handling
Common HTTP status codes:
- `200 OK` - Success
- `404 Not Found` - File or resource doesn't exist
- `400 Bad Request` - Invalid parameters or malformed JSON
- `500 Internal Server Error` - Plugin or vault error
Check API response body for error details before retrying operations.

126
skills/outline/SKILL.md Normal file
View File

@@ -0,0 +1,126 @@
---
name: outline
description: "Outline wiki integration for knowledge management and documentation workflows. Use when Opencode needs to interact with Outline for: (1) Creating and editing documents, (2) Searching and retrieving knowledge base content, (3) Managing document collections and hierarchies, (4) Handling document sharing and permissions, (5) Collaborative features like comments. Triggers: 'Outline', 'wiki', 'knowledge base', 'documentation', 'team docs', 'document in Outline', 'search Outline', 'Outline collection'."
compatibility: opencode
---
# Outline Wiki Integration
Outline is a team knowledge base and wiki platform. This skill provides guidance for Outline API operations and knowledge management workflows.
## Core Capabilities
### Document Operations
- **Create**: Create new documents with markdown content
- **Read**: Retrieve document content, metadata, and revisions
- **Update**: Edit existing documents, update titles and content
- **Delete**: Remove documents (with appropriate permissions)
### Collection Management
- **Organize**: Structure documents in collections and nested collections
- **Hierarchies**: Create parent-child relationships
- **Access Control**: Set permissions at collection level
### Search and Discovery
- **Full-text search**: Find documents by content
- **Metadata filters**: Search by collection, author, date
- **Advanced queries**: Combine multiple filters
### Sharing and Permissions
- **Public links**: Generate shareable document URLs
- **Team access**: Manage member permissions
- **Guest access**: Control external sharing
### Collaboration
- **Comments**: Add threaded discussions to documents
- **Revisions**: Track document history and changes
- **Notifications**: Stay updated on document activity
## Workflows
### Creating a New Document
1. Determine target collection
2. Create document with title and initial content
3. Set appropriate permissions
4. Share with relevant team members if needed
### Searching Knowledge Base
1. Formulate search query
2. Apply relevant filters (collection, date, author)
3. Review search results
4. Retrieve full document content when needed
### Organizing Documents
1. Review existing collection structure
2. Identify appropriate parent collection
3. Create or update documents in hierarchy
4. Update collection metadata if needed
### Document Collaboration
1. Add comments for feedback or discussion
2. Track revision history for changes
3. Notify stakeholders when needed
4. Resolve comments when addressed
## Integration Patterns
### Knowledge Capture
When capturing information from conversations or research:
- Create document in appropriate collection
- Use clear, descriptive titles
- Structure content with headers for readability
- Add tags for discoverability
### Documentation Updates
When updating existing documentation:
- Retrieve current document revision
- Make targeted, minimal changes
- Add comments explaining significant updates
- Share updates with relevant stakeholders
### Knowledge Retrieval
When searching for information:
- Start with broad search terms
- Refine with collection and metadata filters
- Review multiple relevant documents
- Cross-reference linked documents for context
## Common Use Cases
| Use Case | Recommended Approach |
|----------|---------------------|
| Project documentation | Create collection per project, organize by phase |
| Team guidelines | Use dedicated collection, group by topic |
| Meeting notes | Create documents with templates, tag by team |
| Knowledge capture | Search before creating, link to related docs |
| Onboarding resources | Create structured collection with step-by-step guides |
## Best Practices
- **Consistent naming**: Use clear, descriptive titles
- **Logical organization**: Group related documents in collections
- **Regular maintenance**: Review and update outdated content
- **Access control**: Set appropriate permissions for sensitive content
- **Searchability**: Use tags and metadata effectively
- **Collaboration**: Use comments for discussions, not content changes
## Handoff to Other Skills
| Output | Next Skill | Trigger |
|--------|------------|---------|
| Research findings | knowledge-management | "Organize this research in Outline" |
| Documentation draft | communications | "Share this document via email" |
| Task from document | task-management | "Create tasks from this outline" |
| Project plan | plan-writing | "Create project plan in Outline" |

30
skills/pdf/LICENSE.txt Normal file
View File

@@ -0,0 +1,30 @@
© 2025 Anthropic, PBC. All rights reserved.
LICENSE: Use of these materials (including all code, prompts, assets, files,
and other components of this Skill) is governed by your agreement with
Anthropic regarding use of Anthropic's services. If no separate agreement
exists, use is governed by Anthropic's Consumer Terms of Service or
Commercial Terms of Service, as applicable:
https://www.anthropic.com/legal/consumer-terms
https://www.anthropic.com/legal/commercial-terms
Your applicable agreement is referred to as the "Agreement." "Services" are
as defined in the Agreement.
ADDITIONAL RESTRICTIONS: Notwithstanding anything in the Agreement to the
contrary, users may not:
- Extract these materials from the Services or retain copies of these
materials outside the Services
- Reproduce or copy these materials, except for temporary copies created
automatically during authorized use of the Services
- Create derivative works based on these materials
- Distribute, sublicense, or transfer these materials to any third party
- Make, offer to sell, sell, or import any inventions embodied in these
materials
- Reverse engineer, decompile, or disassemble these materials
The receipt, viewing, or possession of these materials does not convey or
imply any license or right beyond those expressly granted above.
Anthropic retains all right, title, and interest in these materials,
including all copyrights, patents, and other intellectual property rights.

294
skills/pdf/SKILL.md Normal file
View File

@@ -0,0 +1,294 @@
---
name: pdf
description: Comprehensive PDF manipulation toolkit for extracting text and tables, creating new PDFs, merging/splitting documents, and handling forms. When the Coding Agent needs to fill in a PDF form or programmatically process, generate, or analyze PDF documents at scale.
license: Proprietary. LICENSE.txt has complete terms
---
# PDF Processing Guide
## Overview
This guide covers essential PDF processing operations using Python libraries and command-line tools. For advanced features, JavaScript libraries, and detailed examples, see reference.md. If you need to fill out a PDF form, read forms.md and follow its instructions.
## Quick Start
```python
from pypdf import PdfReader, PdfWriter
# Read a PDF
reader = PdfReader("document.pdf")
print(f"Pages: {len(reader.pages)}")
# Extract text
text = ""
for page in reader.pages:
text += page.extract_text()
```
## Python Libraries
### pypdf - Basic Operations
#### Merge PDFs
```python
from pypdf import PdfWriter, PdfReader
writer = PdfWriter()
for pdf_file in ["doc1.pdf", "doc2.pdf", "doc3.pdf"]:
reader = PdfReader(pdf_file)
for page in reader.pages:
writer.add_page(page)
with open("merged.pdf", "wb") as output:
writer.write(output)
```
#### Split PDF
```python
reader = PdfReader("input.pdf")
for i, page in enumerate(reader.pages):
writer = PdfWriter()
writer.add_page(page)
with open(f"page_{i+1}.pdf", "wb") as output:
writer.write(output)
```
#### Extract Metadata
```python
reader = PdfReader("document.pdf")
meta = reader.metadata
print(f"Title: {meta.title}")
print(f"Author: {meta.author}")
print(f"Subject: {meta.subject}")
print(f"Creator: {meta.creator}")
```
#### Rotate Pages
```python
reader = PdfReader("input.pdf")
writer = PdfWriter()
page = reader.pages[0]
page.rotate(90) # Rotate 90 degrees clockwise
writer.add_page(page)
with open("rotated.pdf", "wb") as output:
writer.write(output)
```
### pdfplumber - Text and Table Extraction
#### Extract Text with Layout
```python
import pdfplumber
with pdfplumber.open("document.pdf") as pdf:
for page in pdf.pages:
text = page.extract_text()
print(text)
```
#### Extract Tables
```python
with pdfplumber.open("document.pdf") as pdf:
for i, page in enumerate(pdf.pages):
tables = page.extract_tables()
for j, table in enumerate(tables):
print(f"Table {j+1} on page {i+1}:")
for row in table:
print(row)
```
#### Advanced Table Extraction
```python
import pandas as pd
with pdfplumber.open("document.pdf") as pdf:
all_tables = []
for page in pdf.pages:
tables = page.extract_tables()
for table in tables:
if table: # Check if table is not empty
df = pd.DataFrame(table[1:], columns=table[0])
all_tables.append(df)
# Combine all tables
if all_tables:
combined_df = pd.concat(all_tables, ignore_index=True)
combined_df.to_excel("extracted_tables.xlsx", index=False)
```
### reportlab - Create PDFs
#### Basic PDF Creation
```python
from reportlab.lib.pagesizes import letter
from reportlab.pdfgen import canvas
c = canvas.Canvas("hello.pdf", pagesize=letter)
width, height = letter
# Add text
c.drawString(100, height - 100, "Hello World!")
c.drawString(100, height - 120, "This is a PDF created with reportlab")
# Add a line
c.line(100, height - 140, 400, height - 140)
# Save
c.save()
```
#### Create PDF with Multiple Pages
```python
from reportlab.lib.pagesizes import letter
from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, PageBreak
from reportlab.lib.styles import getSampleStyleSheet
doc = SimpleDocTemplate("report.pdf", pagesize=letter)
styles = getSampleStyleSheet()
story = []
# Add content
title = Paragraph("Report Title", styles['Title'])
story.append(title)
story.append(Spacer(1, 12))
body = Paragraph("This is the body of the report. " * 20, styles['Normal'])
story.append(body)
story.append(PageBreak())
# Page 2
story.append(Paragraph("Page 2", styles['Heading1']))
story.append(Paragraph("Content for page 2", styles['Normal']))
# Build PDF
doc.build(story)
```
## Command-Line Tools
### pdftotext (poppler-utils)
```bash
# Extract text
pdftotext input.pdf output.txt
# Extract text preserving layout
pdftotext -layout input.pdf output.txt
# Extract specific pages
pdftotext -f 1 -l 5 input.pdf output.txt # Pages 1-5
```
### qpdf
```bash
# Merge PDFs
qpdf --empty --pages file1.pdf file2.pdf -- merged.pdf
# Split pages
qpdf input.pdf --pages . 1-5 -- pages1-5.pdf
qpdf input.pdf --pages . 6-10 -- pages6-10.pdf
# Rotate pages
qpdf input.pdf output.pdf --rotate=+90:1 # Rotate page 1 by 90 degrees
# Remove password
qpdf --password=mypassword --decrypt encrypted.pdf decrypted.pdf
```
### pdftk (if available)
```bash
# Merge
pdftk file1.pdf file2.pdf cat output merged.pdf
# Split
pdftk input.pdf burst
# Rotate
pdftk input.pdf rotate 1east output rotated.pdf
```
## Common Tasks
### Extract Text from Scanned PDFs
```python
# Requires: pip install pytesseract pdf2image
import pytesseract
from pdf2image import convert_from_path
# Convert PDF to images
images = convert_from_path('scanned.pdf')
# OCR each page
text = ""
for i, image in enumerate(images):
text += f"Page {i+1}:\n"
text += pytesseract.image_to_string(image)
text += "\n\n"
print(text)
```
### Add Watermark
```python
from pypdf import PdfReader, PdfWriter
# Create watermark (or load existing)
watermark = PdfReader("watermark.pdf").pages[0]
# Apply to all pages
reader = PdfReader("document.pdf")
writer = PdfWriter()
for page in reader.pages:
page.merge_page(watermark)
writer.add_page(page)
with open("watermarked.pdf", "wb") as output:
writer.write(output)
```
### Extract Images
```bash
# Using pdfimages (poppler-utils)
pdfimages -j input.pdf output_prefix
# This extracts all images as output_prefix-000.jpg, output_prefix-001.jpg, etc.
```
### Password Protection
```python
from pypdf import PdfReader, PdfWriter
reader = PdfReader("input.pdf")
writer = PdfWriter()
for page in reader.pages:
writer.add_page(page)
# Add password
writer.encrypt("userpassword", "ownerpassword")
with open("encrypted.pdf", "wb") as output:
writer.write(output)
```
## Quick Reference
| Task | Best Tool | Command/Code |
|------|-----------|--------------|
| Merge PDFs | pypdf | `writer.add_page(page)` |
| Split PDFs | pypdf | One page per file |
| Extract text | pdfplumber | `page.extract_text()` |
| Extract tables | pdfplumber | `page.extract_tables()` |
| Create PDFs | reportlab | Canvas or Platypus |
| Command line merge | qpdf | `qpdf --empty --pages ...` |
| OCR scanned PDFs | pytesseract | Convert to image first |
| Fill PDF forms | pdf-lib or pypdf (see forms.md) | See forms.md |
## Next Steps
- For advanced pypdfium2 usage, see reference.md
- For JavaScript libraries (pdf-lib), see reference.md
- If you need to fill out a PDF form, follow the instructions in forms.md
- For troubleshooting guides, see reference.md

205
skills/pdf/forms.md Normal file
View File

@@ -0,0 +1,205 @@
**CRITICAL: You MUST complete these steps in order. Do not skip ahead to writing code.**
If you need to fill out a PDF form, first check to see if the PDF has fillable form fields. Run this script from this file's directory:
`python scripts/check_fillable_fields <file.pdf>`, and depending on the result go to either the "Fillable fields" or "Non-fillable fields" and follow those instructions.
# Fillable fields
If the PDF has fillable form fields:
- Run this script from this file's directory: `python scripts/extract_form_field_info.py <input.pdf> <field_info.json>`. It will create a JSON file with a list of fields in this format:
```
[
{
"field_id": (unique ID for the field),
"page": (page number, 1-based),
"rect": ([left, bottom, right, top] bounding box in PDF coordinates, y=0 is the bottom of the page),
"type": ("text", "checkbox", "radio_group", or "choice"),
},
// Checkboxes have "checked_value" and "unchecked_value" properties:
{
"field_id": (unique ID for the field),
"page": (page number, 1-based),
"type": "checkbox",
"checked_value": (Set the field to this value to check the checkbox),
"unchecked_value": (Set the field to this value to uncheck the checkbox),
},
// Radio groups have a "radio_options" list with the possible choices.
{
"field_id": (unique ID for the field),
"page": (page number, 1-based),
"type": "radio_group",
"radio_options": [
{
"value": (set the field to this value to select this radio option),
"rect": (bounding box for the radio button for this option)
},
// Other radio options
]
},
// Multiple choice fields have a "choice_options" list with the possible choices:
{
"field_id": (unique ID for the field),
"page": (page number, 1-based),
"type": "choice",
"choice_options": [
{
"value": (set the field to this value to select this option),
"text": (display text of the option)
},
// Other choice options
],
}
]
```
- Convert the PDF to PNGs (one image for each page) with this script (run from this file's directory):
`python scripts/convert_pdf_to_images.py <file.pdf> <output_directory>`
Then analyze the images to determine the purpose of each form field (make sure to convert the bounding box PDF coordinates to image coordinates).
- Create a `field_values.json` file in this format with the values to be entered for each field:
```
[
{
"field_id": "last_name", // Must match the field_id from `extract_form_field_info.py`
"description": "The user's last name",
"page": 1, // Must match the "page" value in field_info.json
"value": "Simpson"
},
{
"field_id": "Checkbox12",
"description": "Checkbox to be checked if the user is 18 or over",
"page": 1,
"value": "/On" // If this is a checkbox, use its "checked_value" value to check it. If it's a radio button group, use one of the "value" values in "radio_options".
},
// more fields
]
```
- Run the `fill_fillable_fields.py` script from this file's directory to create a filled-in PDF:
`python scripts/fill_fillable_fields.py <input pdf> <field_values.json> <output pdf>`
This script will verify that the field IDs and values you provide are valid; if it prints error messages, correct the appropriate fields and try again.
# Non-fillable fields
If the PDF doesn't have fillable form fields, you'll need to visually determine where the data should be added and create text annotations. Follow the below steps *exactly*. You MUST perform all of these steps to ensure that the the form is accurately completed. Details for each step are below.
- Convert the PDF to PNG images and determine field bounding boxes.
- Create a JSON file with field information and validation images showing the bounding boxes.
- Validate the the bounding boxes.
- Use the bounding boxes to fill in the form.
## Step 1: Visual Analysis (REQUIRED)
- Convert the PDF to PNG images. Run this script from this file's directory:
`python scripts/convert_pdf_to_images.py <file.pdf> <output_directory>`
The script will create a PNG image for each page in the PDF.
- Carefully examine each PNG image and identify all form fields and areas where the user should enter data. For each form field where the user should enter text, determine bounding boxes for both the form field label, and the area where the user should enter text. The label and entry bounding boxes MUST NOT INTERSECT; the text entry box should only include the area where data should be entered. Usually this area will be immediately to the side, above, or below its label. Entry bounding boxes must be tall and wide enough to contain their text.
These are some examples of form structures that you might see:
*Label inside box*
```
┌────────────────────────┐
│ Name: │
└────────────────────────┘
```
The input area should be to the right of the "Name" label and extend to the edge of the box.
*Label before line*
```
Email: _______________________
```
The input area should be above the line and include its entire width.
*Label under line*
```
_________________________
Name
```
The input area should be above the line and include the entire width of the line. This is common for signature and date fields.
*Label above line*
```
Please enter any special requests:
________________________________________________
```
The input area should extend from the bottom of the label to the line, and should include the entire width of the line.
*Checkboxes*
```
Are you a US citizen? Yes □ No □
```
For checkboxes:
- Look for small square boxes (□) - these are the actual checkboxes to target. They may be to the left or right of their labels.
- Distinguish between label text ("Yes", "No") and the clickable checkbox squares.
- The entry bounding box should cover ONLY the small square, not the text label.
### Step 2: Create fields.json and validation images (REQUIRED)
- Create a file named `fields.json` with information for the form fields and bounding boxes in this format:
```
{
"pages": [
{
"page_number": 1,
"image_width": (first page image width in pixels),
"image_height": (first page image height in pixels),
},
{
"page_number": 2,
"image_width": (second page image width in pixels),
"image_height": (second page image height in pixels),
}
// additional pages
],
"form_fields": [
// Example for a text field.
{
"page_number": 1,
"description": "The user's last name should be entered here",
// Bounding boxes are [left, top, right, bottom]. The bounding boxes for the label and text entry should not overlap.
"field_label": "Last name",
"label_bounding_box": [30, 125, 95, 142],
"entry_bounding_box": [100, 125, 280, 142],
"entry_text": {
"text": "Johnson", // This text will be added as an annotation at the entry_bounding_box location
"font_size": 14, // optional, defaults to 14
"font_color": "000000", // optional, RRGGBB format, defaults to 000000 (black)
}
},
// Example for a checkbox. TARGET THE SQUARE for the entry bounding box, NOT THE TEXT
{
"page_number": 2,
"description": "Checkbox that should be checked if the user is over 18",
"entry_bounding_box": [140, 525, 155, 540], // Small box over checkbox square
"field_label": "Yes",
"label_bounding_box": [100, 525, 132, 540], // Box containing "Yes" text
// Use "X" to check a checkbox.
"entry_text": {
"text": "X",
}
}
// additional form field entries
]
}
```
Create validation images by running this script from this file's directory for each page:
`python scripts/create_validation_image.py <page_number> <path_to_fields.json> <input_image_path> <output_image_path>
The validation images will have red rectangles where text should be entered, and blue rectangles covering label text.
### Step 3: Validate Bounding Boxes (REQUIRED)
#### Automated intersection check
- Verify that none of bounding boxes intersect and that the entry bounding boxes are tall enough by checking the fields.json file with the `check_bounding_boxes.py` script (run from this file's directory):
`python scripts/check_bounding_boxes.py <JSON file>`
If there are errors, reanalyze the relevant fields, adjust the bounding boxes, and iterate until there are no remaining errors. Remember: label (blue) bounding boxes should contain text labels, entry (red) boxes should not.
#### Manual image inspection
**CRITICAL: Do not proceed without visually inspecting validation images**
- Red rectangles must ONLY cover input areas
- Red rectangles MUST NOT contain any text
- Blue rectangles should contain label text
- For checkboxes:
- Red rectangle MUST be centered on the checkbox square
- Blue rectangle should cover the text label for the checkbox
- If any rectangles look wrong, fix fields.json, regenerate the validation images, and verify again. Repeat this process until the bounding boxes are fully accurate.
### Step 4: Add annotations to the PDF
Run this script from this file's directory to create a filled-out PDF using the information in fields.json:
`python scripts/fill_pdf_form_with_annotations.py <input_pdf_path> <path_to_fields.json> <output_pdf_path>

612
skills/pdf/reference.md Normal file
View File

@@ -0,0 +1,612 @@
# PDF Processing Advanced Reference
This document contains advanced PDF processing features, detailed examples, and additional libraries not covered in the main skill instructions.
## pypdfium2 Library (Apache/BSD License)
### Overview
pypdfium2 is a Python binding for PDFium (Chromium's PDF library). It's excellent for fast PDF rendering, image generation, and serves as a PyMuPDF replacement.
### Render PDF to Images
```python
import pypdfium2 as pdfium
from PIL import Image
# Load PDF
pdf = pdfium.PdfDocument("document.pdf")
# Render page to image
page = pdf[0] # First page
bitmap = page.render(
scale=2.0, # Higher resolution
rotation=0 # No rotation
)
# Convert to PIL Image
img = bitmap.to_pil()
img.save("page_1.png", "PNG")
# Process multiple pages
for i, page in enumerate(pdf):
bitmap = page.render(scale=1.5)
img = bitmap.to_pil()
img.save(f"page_{i+1}.jpg", "JPEG", quality=90)
```
### Extract Text with pypdfium2
```python
import pypdfium2 as pdfium
pdf = pdfium.PdfDocument("document.pdf")
for i, page in enumerate(pdf):
text = page.get_text()
print(f"Page {i+1} text length: {len(text)} chars")
```
## JavaScript Libraries
### pdf-lib (MIT License)
pdf-lib is a powerful JavaScript library for creating and modifying PDF documents in any JavaScript environment.
#### Load and Manipulate Existing PDF
```javascript
import { PDFDocument } from 'pdf-lib';
import fs from 'fs';
async function manipulatePDF() {
// Load existing PDF
const existingPdfBytes = fs.readFileSync('input.pdf');
const pdfDoc = await PDFDocument.load(existingPdfBytes);
// Get page count
const pageCount = pdfDoc.getPageCount();
console.log(`Document has ${pageCount} pages`);
// Add new page
const newPage = pdfDoc.addPage([600, 400]);
newPage.drawText('Added by pdf-lib', {
x: 100,
y: 300,
size: 16
});
// Save modified PDF
const pdfBytes = await pdfDoc.save();
fs.writeFileSync('modified.pdf', pdfBytes);
}
```
#### Create Complex PDFs from Scratch
```javascript
import { PDFDocument, rgb, StandardFonts } from 'pdf-lib';
import fs from 'fs';
async function createPDF() {
const pdfDoc = await PDFDocument.create();
// Add fonts
const helveticaFont = await pdfDoc.embedFont(StandardFonts.Helvetica);
const helveticaBold = await pdfDoc.embedFont(StandardFonts.HelveticaBold);
// Add page
const page = pdfDoc.addPage([595, 842]); // A4 size
const { width, height } = page.getSize();
// Add text with styling
page.drawText('Invoice #12345', {
x: 50,
y: height - 50,
size: 18,
font: helveticaBold,
color: rgb(0.2, 0.2, 0.8)
});
// Add rectangle (header background)
page.drawRectangle({
x: 40,
y: height - 100,
width: width - 80,
height: 30,
color: rgb(0.9, 0.9, 0.9)
});
// Add table-like content
const items = [
['Item', 'Qty', 'Price', 'Total'],
['Widget', '2', '$50', '$100'],
['Gadget', '1', '$75', '$75']
];
let yPos = height - 150;
items.forEach(row => {
let xPos = 50;
row.forEach(cell => {
page.drawText(cell, {
x: xPos,
y: yPos,
size: 12,
font: helveticaFont
});
xPos += 120;
});
yPos -= 25;
});
const pdfBytes = await pdfDoc.save();
fs.writeFileSync('created.pdf', pdfBytes);
}
```
#### Advanced Merge and Split Operations
```javascript
import { PDFDocument } from 'pdf-lib';
import fs from 'fs';
async function mergePDFs() {
// Create new document
const mergedPdf = await PDFDocument.create();
// Load source PDFs
const pdf1Bytes = fs.readFileSync('doc1.pdf');
const pdf2Bytes = fs.readFileSync('doc2.pdf');
const pdf1 = await PDFDocument.load(pdf1Bytes);
const pdf2 = await PDFDocument.load(pdf2Bytes);
// Copy pages from first PDF
const pdf1Pages = await mergedPdf.copyPages(pdf1, pdf1.getPageIndices());
pdf1Pages.forEach(page => mergedPdf.addPage(page));
// Copy specific pages from second PDF (pages 0, 2, 4)
const pdf2Pages = await mergedPdf.copyPages(pdf2, [0, 2, 4]);
pdf2Pages.forEach(page => mergedPdf.addPage(page));
const mergedPdfBytes = await mergedPdf.save();
fs.writeFileSync('merged.pdf', mergedPdfBytes);
}
```
### pdfjs-dist (Apache License)
PDF.js is Mozilla's JavaScript library for rendering PDFs in the browser.
#### Basic PDF Loading and Rendering
```javascript
import * as pdfjsLib from 'pdfjs-dist';
// Configure worker (important for performance)
pdfjsLib.GlobalWorkerOptions.workerSrc = './pdf.worker.js';
async function renderPDF() {
// Load PDF
const loadingTask = pdfjsLib.getDocument('document.pdf');
const pdf = await loadingTask.promise;
console.log(`Loaded PDF with ${pdf.numPages} pages`);
// Get first page
const page = await pdf.getPage(1);
const viewport = page.getViewport({ scale: 1.5 });
// Render to canvas
const canvas = document.createElement('canvas');
const context = canvas.getContext('2d');
canvas.height = viewport.height;
canvas.width = viewport.width;
const renderContext = {
canvasContext: context,
viewport: viewport
};
await page.render(renderContext).promise;
document.body.appendChild(canvas);
}
```
#### Extract Text with Coordinates
```javascript
import * as pdfjsLib from 'pdfjs-dist';
async function extractText() {
const loadingTask = pdfjsLib.getDocument('document.pdf');
const pdf = await loadingTask.promise;
let fullText = '';
// Extract text from all pages
for (let i = 1; i <= pdf.numPages; i++) {
const page = await pdf.getPage(i);
const textContent = await page.getTextContent();
const pageText = textContent.items
.map(item => item.str)
.join(' ');
fullText += `\n--- Page ${i} ---\n${pageText}`;
// Get text with coordinates for advanced processing
const textWithCoords = textContent.items.map(item => ({
text: item.str,
x: item.transform[4],
y: item.transform[5],
width: item.width,
height: item.height
}));
}
console.log(fullText);
return fullText;
}
```
#### Extract Annotations and Forms
```javascript
import * as pdfjsLib from 'pdfjs-dist';
async function extractAnnotations() {
const loadingTask = pdfjsLib.getDocument('annotated.pdf');
const pdf = await loadingTask.promise;
for (let i = 1; i <= pdf.numPages; i++) {
const page = await pdf.getPage(i);
const annotations = await page.getAnnotations();
annotations.forEach(annotation => {
console.log(`Annotation type: ${annotation.subtype}`);
console.log(`Content: ${annotation.contents}`);
console.log(`Coordinates: ${JSON.stringify(annotation.rect)}`);
});
}
}
```
## Advanced Command-Line Operations
### poppler-utils Advanced Features
#### Extract Text with Bounding Box Coordinates
```bash
# Extract text with bounding box coordinates (essential for structured data)
pdftotext -bbox-layout document.pdf output.xml
# The XML output contains precise coordinates for each text element
```
#### Advanced Image Conversion
```bash
# Convert to PNG images with specific resolution
pdftoppm -png -r 300 document.pdf output_prefix
# Convert specific page range with high resolution
pdftoppm -png -r 600 -f 1 -l 3 document.pdf high_res_pages
# Convert to JPEG with quality setting
pdftoppm -jpeg -jpegopt quality=85 -r 200 document.pdf jpeg_output
```
#### Extract Embedded Images
```bash
# Extract all embedded images with metadata
pdfimages -j -p document.pdf page_images
# List image info without extracting
pdfimages -list document.pdf
# Extract images in their original format
pdfimages -all document.pdf images/img
```
### qpdf Advanced Features
#### Complex Page Manipulation
```bash
# Split PDF into groups of pages
qpdf --split-pages=3 input.pdf output_group_%02d.pdf
# Extract specific pages with complex ranges
qpdf input.pdf --pages input.pdf 1,3-5,8,10-end -- extracted.pdf
# Merge specific pages from multiple PDFs
qpdf --empty --pages doc1.pdf 1-3 doc2.pdf 5-7 doc3.pdf 2,4 -- combined.pdf
```
#### PDF Optimization and Repair
```bash
# Optimize PDF for web (linearize for streaming)
qpdf --linearize input.pdf optimized.pdf
# Remove unused objects and compress
qpdf --optimize-level=all input.pdf compressed.pdf
# Attempt to repair corrupted PDF structure
qpdf --check input.pdf
qpdf --fix-qdf damaged.pdf repaired.pdf
# Show detailed PDF structure for debugging
qpdf --show-all-pages input.pdf > structure.txt
```
#### Advanced Encryption
```bash
# Add password protection with specific permissions
qpdf --encrypt user_pass owner_pass 256 --print=none --modify=none -- input.pdf encrypted.pdf
# Check encryption status
qpdf --show-encryption encrypted.pdf
# Remove password protection (requires password)
qpdf --password=secret123 --decrypt encrypted.pdf decrypted.pdf
```
## Advanced Python Techniques
### pdfplumber Advanced Features
#### Extract Text with Precise Coordinates
```python
import pdfplumber
with pdfplumber.open("document.pdf") as pdf:
page = pdf.pages[0]
# Extract all text with coordinates
chars = page.chars
for char in chars[:10]: # First 10 characters
print(f"Char: '{char['text']}' at x:{char['x0']:.1f} y:{char['y0']:.1f}")
# Extract text by bounding box (left, top, right, bottom)
bbox_text = page.within_bbox((100, 100, 400, 200)).extract_text()
```
#### Advanced Table Extraction with Custom Settings
```python
import pdfplumber
import pandas as pd
with pdfplumber.open("complex_table.pdf") as pdf:
page = pdf.pages[0]
# Extract tables with custom settings for complex layouts
table_settings = {
"vertical_strategy": "lines",
"horizontal_strategy": "lines",
"snap_tolerance": 3,
"intersection_tolerance": 15
}
tables = page.extract_tables(table_settings)
# Visual debugging for table extraction
img = page.to_image(resolution=150)
img.save("debug_layout.png")
```
### reportlab Advanced Features
#### Create Professional Reports with Tables
```python
from reportlab.platypus import SimpleDocTemplate, Table, TableStyle, Paragraph
from reportlab.lib.styles import getSampleStyleSheet
from reportlab.lib import colors
# Sample data
data = [
['Product', 'Q1', 'Q2', 'Q3', 'Q4'],
['Widgets', '120', '135', '142', '158'],
['Gadgets', '85', '92', '98', '105']
]
# Create PDF with table
doc = SimpleDocTemplate("report.pdf")
elements = []
# Add title
styles = getSampleStyleSheet()
title = Paragraph("Quarterly Sales Report", styles['Title'])
elements.append(title)
# Add table with advanced styling
table = Table(data)
table.setStyle(TableStyle([
('BACKGROUND', (0, 0), (-1, 0), colors.grey),
('TEXTCOLOR', (0, 0), (-1, 0), colors.whitesmoke),
('ALIGN', (0, 0), (-1, -1), 'CENTER'),
('FONTNAME', (0, 0), (-1, 0), 'Helvetica-Bold'),
('FONTSIZE', (0, 0), (-1, 0), 14),
('BOTTOMPADDING', (0, 0), (-1, 0), 12),
('BACKGROUND', (0, 1), (-1, -1), colors.beige),
('GRID', (0, 0), (-1, -1), 1, colors.black)
]))
elements.append(table)
doc.build(elements)
```
## Complex Workflows
### Extract Figures/Images from PDF
#### Method 1: Using pdfimages (fastest)
```bash
# Extract all images with original quality
pdfimages -all document.pdf images/img
```
#### Method 2: Using pypdfium2 + Image Processing
```python
import pypdfium2 as pdfium
from PIL import Image
import numpy as np
def extract_figures(pdf_path, output_dir):
pdf = pdfium.PdfDocument(pdf_path)
for page_num, page in enumerate(pdf):
# Render high-resolution page
bitmap = page.render(scale=3.0)
img = bitmap.to_pil()
# Convert to numpy for processing
img_array = np.array(img)
# Simple figure detection (non-white regions)
mask = np.any(img_array != [255, 255, 255], axis=2)
# Find contours and extract bounding boxes
# (This is simplified - real implementation would need more sophisticated detection)
# Save detected figures
# ... implementation depends on specific needs
```
### Batch PDF Processing with Error Handling
```python
import os
import glob
from pypdf import PdfReader, PdfWriter
import logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
def batch_process_pdfs(input_dir, operation='merge'):
pdf_files = glob.glob(os.path.join(input_dir, "*.pdf"))
if operation == 'merge':
writer = PdfWriter()
for pdf_file in pdf_files:
try:
reader = PdfReader(pdf_file)
for page in reader.pages:
writer.add_page(page)
logger.info(f"Processed: {pdf_file}")
except Exception as e:
logger.error(f"Failed to process {pdf_file}: {e}")
continue
with open("batch_merged.pdf", "wb") as output:
writer.write(output)
elif operation == 'extract_text':
for pdf_file in pdf_files:
try:
reader = PdfReader(pdf_file)
text = ""
for page in reader.pages:
text += page.extract_text()
output_file = pdf_file.replace('.pdf', '.txt')
with open(output_file, 'w', encoding='utf-8') as f:
f.write(text)
logger.info(f"Extracted text from: {pdf_file}")
except Exception as e:
logger.error(f"Failed to extract text from {pdf_file}: {e}")
continue
```
### Advanced PDF Cropping
```python
from pypdf import PdfWriter, PdfReader
reader = PdfReader("input.pdf")
writer = PdfWriter()
# Crop page (left, bottom, right, top in points)
page = reader.pages[0]
page.mediabox.left = 50
page.mediabox.bottom = 50
page.mediabox.right = 550
page.mediabox.top = 750
writer.add_page(page)
with open("cropped.pdf", "wb") as output:
writer.write(output)
```
## Performance Optimization Tips
### 1. For Large PDFs
- Use streaming approaches instead of loading entire PDF in memory
- Use `qpdf --split-pages` for splitting large files
- Process pages individually with pypdfium2
### 2. For Text Extraction
- `pdftotext -bbox-layout` is fastest for plain text extraction
- Use pdfplumber for structured data and tables
- Avoid `pypdf.extract_text()` for very large documents
### 3. For Image Extraction
- `pdfimages` is much faster than rendering pages
- Use low resolution for previews, high resolution for final output
### 4. For Form Filling
- pdf-lib maintains form structure better than most alternatives
- Pre-validate form fields before processing
### 5. Memory Management
```python
# Process PDFs in chunks
def process_large_pdf(pdf_path, chunk_size=10):
reader = PdfReader(pdf_path)
total_pages = len(reader.pages)
for start_idx in range(0, total_pages, chunk_size):
end_idx = min(start_idx + chunk_size, total_pages)
writer = PdfWriter()
for i in range(start_idx, end_idx):
writer.add_page(reader.pages[i])
# Process chunk
with open(f"chunk_{start_idx//chunk_size}.pdf", "wb") as output:
writer.write(output)
```
## Troubleshooting Common Issues
### Encrypted PDFs
```python
# Handle password-protected PDFs
from pypdf import PdfReader
try:
reader = PdfReader("encrypted.pdf")
if reader.is_encrypted:
reader.decrypt("password")
except Exception as e:
print(f"Failed to decrypt: {e}")
```
### Corrupted PDFs
```bash
# Use qpdf to repair
qpdf --check corrupted.pdf
qpdf --replace-input corrupted.pdf
```
### Text Extraction Issues
```python
# Fallback to OCR for scanned PDFs
import pytesseract
from pdf2image import convert_from_path
def extract_text_with_ocr(pdf_path):
images = convert_from_path(pdf_path)
text = ""
for i, image in enumerate(images):
text += pytesseract.image_to_string(image)
return text
```
## License Information
- **pypdf**: BSD License
- **pdfplumber**: MIT License
- **pypdfium2**: Apache/BSD License
- **reportlab**: BSD License
- **poppler-utils**: GPL-2 License
- **qpdf**: Apache License
- **pdf-lib**: MIT License
- **pdfjs-dist**: Apache License

View File

@@ -0,0 +1,70 @@
from dataclasses import dataclass
import json
import sys
# Script to check that the `fields.json` file that the Coding Agent creates when analyzing PDFs
# does not have overlapping bounding boxes. See forms.md.
@dataclass
class RectAndField:
rect: list[float]
rect_type: str
field: dict
# Returns a list of messages that are printed to stdout for Claude to read.
def get_bounding_box_messages(fields_json_stream) -> list[str]:
messages = []
fields = json.load(fields_json_stream)
messages.append(f"Read {len(fields['form_fields'])} fields")
def rects_intersect(r1, r2):
disjoint_horizontal = r1[0] >= r2[2] or r1[2] <= r2[0]
disjoint_vertical = r1[1] >= r2[3] or r1[3] <= r2[1]
return not (disjoint_horizontal or disjoint_vertical)
rects_and_fields = []
for f in fields["form_fields"]:
rects_and_fields.append(RectAndField(f["label_bounding_box"], "label", f))
rects_and_fields.append(RectAndField(f["entry_bounding_box"], "entry", f))
has_error = False
for i, ri in enumerate(rects_and_fields):
# This is O(N^2); we can optimize if it becomes a problem.
for j in range(i + 1, len(rects_and_fields)):
rj = rects_and_fields[j]
if ri.field["page_number"] == rj.field["page_number"] and rects_intersect(ri.rect, rj.rect):
has_error = True
if ri.field is rj.field:
messages.append(f"FAILURE: intersection between label and entry bounding boxes for `{ri.field['description']}` ({ri.rect}, {rj.rect})")
else:
messages.append(f"FAILURE: intersection between {ri.rect_type} bounding box for `{ri.field['description']}` ({ri.rect}) and {rj.rect_type} bounding box for `{rj.field['description']}` ({rj.rect})")
if len(messages) >= 20:
messages.append("Aborting further checks; fix bounding boxes and try again")
return messages
if ri.rect_type == "entry":
if "entry_text" in ri.field:
font_size = ri.field["entry_text"].get("font_size", 14)
entry_height = ri.rect[3] - ri.rect[1]
if entry_height < font_size:
has_error = True
messages.append(f"FAILURE: entry bounding box height ({entry_height}) for `{ri.field['description']}` is too short for the text content (font size: {font_size}). Increase the box height or decrease the font size.")
if len(messages) >= 20:
messages.append("Aborting further checks; fix bounding boxes and try again")
return messages
if not has_error:
messages.append("SUCCESS: All bounding boxes are valid")
return messages
if __name__ == "__main__":
if len(sys.argv) != 2:
print("Usage: check_bounding_boxes.py [fields.json]")
sys.exit(1)
# Input file should be in the `fields.json` format described in forms.md.
with open(sys.argv[1]) as f:
messages = get_bounding_box_messages(f)
for msg in messages:
print(msg)

View File

@@ -0,0 +1,226 @@
import unittest
import json
import io
from check_bounding_boxes import get_bounding_box_messages
# Currently this is not run automatically in CI; it's just for documentation and manual checking.
class TestGetBoundingBoxMessages(unittest.TestCase):
def create_json_stream(self, data):
"""Helper to create a JSON stream from data"""
return io.StringIO(json.dumps(data))
def test_no_intersections(self):
"""Test case with no bounding box intersections"""
data = {
"form_fields": [
{
"description": "Name",
"page_number": 1,
"label_bounding_box": [10, 10, 50, 30],
"entry_bounding_box": [60, 10, 150, 30]
},
{
"description": "Email",
"page_number": 1,
"label_bounding_box": [10, 40, 50, 60],
"entry_bounding_box": [60, 40, 150, 60]
}
]
}
stream = self.create_json_stream(data)
messages = get_bounding_box_messages(stream)
self.assertTrue(any("SUCCESS" in msg for msg in messages))
self.assertFalse(any("FAILURE" in msg for msg in messages))
def test_label_entry_intersection_same_field(self):
"""Test intersection between label and entry of the same field"""
data = {
"form_fields": [
{
"description": "Name",
"page_number": 1,
"label_bounding_box": [10, 10, 60, 30],
"entry_bounding_box": [50, 10, 150, 30] # Overlaps with label
}
]
}
stream = self.create_json_stream(data)
messages = get_bounding_box_messages(stream)
self.assertTrue(any("FAILURE" in msg and "intersection" in msg for msg in messages))
self.assertFalse(any("SUCCESS" in msg for msg in messages))
def test_intersection_between_different_fields(self):
"""Test intersection between bounding boxes of different fields"""
data = {
"form_fields": [
{
"description": "Name",
"page_number": 1,
"label_bounding_box": [10, 10, 50, 30],
"entry_bounding_box": [60, 10, 150, 30]
},
{
"description": "Email",
"page_number": 1,
"label_bounding_box": [40, 20, 80, 40], # Overlaps with Name's boxes
"entry_bounding_box": [160, 10, 250, 30]
}
]
}
stream = self.create_json_stream(data)
messages = get_bounding_box_messages(stream)
self.assertTrue(any("FAILURE" in msg and "intersection" in msg for msg in messages))
self.assertFalse(any("SUCCESS" in msg for msg in messages))
def test_different_pages_no_intersection(self):
"""Test that boxes on different pages don't count as intersecting"""
data = {
"form_fields": [
{
"description": "Name",
"page_number": 1,
"label_bounding_box": [10, 10, 50, 30],
"entry_bounding_box": [60, 10, 150, 30]
},
{
"description": "Email",
"page_number": 2,
"label_bounding_box": [10, 10, 50, 30], # Same coordinates but different page
"entry_bounding_box": [60, 10, 150, 30]
}
]
}
stream = self.create_json_stream(data)
messages = get_bounding_box_messages(stream)
self.assertTrue(any("SUCCESS" in msg for msg in messages))
self.assertFalse(any("FAILURE" in msg for msg in messages))
def test_entry_height_too_small(self):
"""Test that entry box height is checked against font size"""
data = {
"form_fields": [
{
"description": "Name",
"page_number": 1,
"label_bounding_box": [10, 10, 50, 30],
"entry_bounding_box": [60, 10, 150, 20], # Height is 10
"entry_text": {
"font_size": 14 # Font size larger than height
}
}
]
}
stream = self.create_json_stream(data)
messages = get_bounding_box_messages(stream)
self.assertTrue(any("FAILURE" in msg and "height" in msg for msg in messages))
self.assertFalse(any("SUCCESS" in msg for msg in messages))
def test_entry_height_adequate(self):
"""Test that adequate entry box height passes"""
data = {
"form_fields": [
{
"description": "Name",
"page_number": 1,
"label_bounding_box": [10, 10, 50, 30],
"entry_bounding_box": [60, 10, 150, 30], # Height is 20
"entry_text": {
"font_size": 14 # Font size smaller than height
}
}
]
}
stream = self.create_json_stream(data)
messages = get_bounding_box_messages(stream)
self.assertTrue(any("SUCCESS" in msg for msg in messages))
self.assertFalse(any("FAILURE" in msg for msg in messages))
def test_default_font_size(self):
"""Test that default font size is used when not specified"""
data = {
"form_fields": [
{
"description": "Name",
"page_number": 1,
"label_bounding_box": [10, 10, 50, 30],
"entry_bounding_box": [60, 10, 150, 20], # Height is 10
"entry_text": {} # No font_size specified, should use default 14
}
]
}
stream = self.create_json_stream(data)
messages = get_bounding_box_messages(stream)
self.assertTrue(any("FAILURE" in msg and "height" in msg for msg in messages))
self.assertFalse(any("SUCCESS" in msg for msg in messages))
def test_no_entry_text(self):
"""Test that missing entry_text doesn't cause height check"""
data = {
"form_fields": [
{
"description": "Name",
"page_number": 1,
"label_bounding_box": [10, 10, 50, 30],
"entry_bounding_box": [60, 10, 150, 20] # Small height but no entry_text
}
]
}
stream = self.create_json_stream(data)
messages = get_bounding_box_messages(stream)
self.assertTrue(any("SUCCESS" in msg for msg in messages))
self.assertFalse(any("FAILURE" in msg for msg in messages))
def test_multiple_errors_limit(self):
"""Test that error messages are limited to prevent excessive output"""
fields = []
# Create many overlapping fields
for i in range(25):
fields.append({
"description": f"Field{i}",
"page_number": 1,
"label_bounding_box": [10, 10, 50, 30], # All overlap
"entry_bounding_box": [20, 15, 60, 35] # All overlap
})
data = {"form_fields": fields}
stream = self.create_json_stream(data)
messages = get_bounding_box_messages(stream)
# Should abort after ~20 messages
self.assertTrue(any("Aborting" in msg for msg in messages))
# Should have some FAILURE messages but not hundreds
failure_count = sum(1 for msg in messages if "FAILURE" in msg)
self.assertGreater(failure_count, 0)
self.assertLess(len(messages), 30) # Should be limited
def test_edge_touching_boxes(self):
"""Test that boxes touching at edges don't count as intersecting"""
data = {
"form_fields": [
{
"description": "Name",
"page_number": 1,
"label_bounding_box": [10, 10, 50, 30],
"entry_bounding_box": [50, 10, 150, 30] # Touches at x=50
}
]
}
stream = self.create_json_stream(data)
messages = get_bounding_box_messages(stream)
self.assertTrue(any("SUCCESS" in msg for msg in messages))
self.assertFalse(any("FAILURE" in msg for msg in messages))
if __name__ == '__main__':
unittest.main()

View File

@@ -0,0 +1,12 @@
import sys
from pypdf import PdfReader
# Script for the Coding Agent to run to determine whether a PDF has fillable form fields. See forms.md.
reader = PdfReader(sys.argv[1])
if (reader.get_fields()):
print("This PDF has fillable form fields")
else:
print("This PDF does not have fillable form fields; you will need to visually determine where to enter data")

View File

@@ -0,0 +1,35 @@
import os
import sys
from pdf2image import convert_from_path
# Converts each page of a PDF to a PNG image.
def convert(pdf_path, output_dir, max_dim=1000):
images = convert_from_path(pdf_path, dpi=200)
for i, image in enumerate(images):
# Scale image if needed to keep width/height under `max_dim`
width, height = image.size
if width > max_dim or height > max_dim:
scale_factor = min(max_dim / width, max_dim / height)
new_width = int(width * scale_factor)
new_height = int(height * scale_factor)
image = image.resize((new_width, new_height))
image_path = os.path.join(output_dir, f"page_{i+1}.png")
image.save(image_path)
print(f"Saved page {i+1} as {image_path} (size: {image.size})")
print(f"Converted {len(images)} pages to PNG images")
if __name__ == "__main__":
if len(sys.argv) != 3:
print("Usage: convert_pdf_to_images.py [input pdf] [output directory]")
sys.exit(1)
pdf_path = sys.argv[1]
output_directory = sys.argv[2]
convert(pdf_path, output_directory)

View File

@@ -0,0 +1,41 @@
import json
import sys
from PIL import Image, ImageDraw
# Creates "validation" images with rectangles for the bounding box information that
# The Coding Ageent creates when determining where to add text annotations in PDFs. See forms.md.
def create_validation_image(page_number, fields_json_path, input_path, output_path):
# Input file should be in the `fields.json` format described in forms.md.
with open(fields_json_path, 'r') as f:
data = json.load(f)
img = Image.open(input_path)
draw = ImageDraw.Draw(img)
num_boxes = 0
for field in data["form_fields"]:
if field["page_number"] == page_number:
entry_box = field['entry_bounding_box']
label_box = field['label_bounding_box']
# Draw red rectangle over entry bounding box and blue rectangle over the label.
draw.rectangle(entry_box, outline='red', width=2)
draw.rectangle(label_box, outline='blue', width=2)
num_boxes += 2
img.save(output_path)
print(f"Created validation image at {output_path} with {num_boxes} bounding boxes")
if __name__ == "__main__":
if len(sys.argv) != 5:
print("Usage: create_validation_image.py [page number] [fields.json file] [input image path] [output image path]")
sys.exit(1)
page_number = int(sys.argv[1])
fields_json_path = sys.argv[2]
input_image_path = sys.argv[3]
output_image_path = sys.argv[4]
create_validation_image(page_number, fields_json_path, input_image_path, output_image_path)

View File

@@ -0,0 +1,152 @@
import json
import sys
from pypdf import PdfReader
# Extracts data for the fillable form fields in a PDF and outputs JSON that
# The Coding Agent uses to fill the fields. See forms.md.
# This matches the format used by PdfReader `get_fields` and `update_page_form_field_values` methods.
def get_full_annotation_field_id(annotation):
components = []
while annotation:
field_name = annotation.get('/T')
if field_name:
components.append(field_name)
annotation = annotation.get('/Parent')
return ".".join(reversed(components)) if components else None
def make_field_dict(field, field_id):
field_dict = {"field_id": field_id}
ft = field.get('/FT')
if ft == "/Tx":
field_dict["type"] = "text"
elif ft == "/Btn":
field_dict["type"] = "checkbox" # radio groups handled separately
states = field.get("/_States_", [])
if len(states) == 2:
# "/Off" seems to always be the unchecked value, as suggested by
# https://opensource.adobe.com/dc-acrobat-sdk-docs/standards/pdfstandards/pdf/PDF32000_2008.pdf#page=448
# It can be either first or second in the "/_States_" list.
if "/Off" in states:
field_dict["checked_value"] = states[0] if states[0] != "/Off" else states[1]
field_dict["unchecked_value"] = "/Off"
else:
print(f"Unexpected state values for checkbox `${field_id}`. Its checked and unchecked values may not be correct; if you're trying to check it, visually verify the results.")
field_dict["checked_value"] = states[0]
field_dict["unchecked_value"] = states[1]
elif ft == "/Ch":
field_dict["type"] = "choice"
states = field.get("/_States_", [])
field_dict["choice_options"] = [{
"value": state[0],
"text": state[1],
} for state in states]
else:
field_dict["type"] = f"unknown ({ft})"
return field_dict
# Returns a list of fillable PDF fields:
# [
# {
# "field_id": "name",
# "page": 1,
# "type": ("text", "checkbox", "radio_group", or "choice")
# // Per-type additional fields described in forms.md
# },
# ]
def get_field_info(reader: PdfReader):
fields = reader.get_fields()
field_info_by_id = {}
possible_radio_names = set()
for field_id, field in fields.items():
# Skip if this is a container field with children, except that it might be
# a parent group for radio button options.
if field.get("/Kids"):
if field.get("/FT") == "/Btn":
possible_radio_names.add(field_id)
continue
field_info_by_id[field_id] = make_field_dict(field, field_id)
# Bounding rects are stored in annotations in page objects.
# Radio button options have a separate annotation for each choice;
# all choices have the same field name.
# See https://westhealth.github.io/exploring-fillable-forms-with-pdfrw.html
radio_fields_by_id = {}
for page_index, page in enumerate(reader.pages):
annotations = page.get('/Annots', [])
for ann in annotations:
field_id = get_full_annotation_field_id(ann)
if field_id in field_info_by_id:
field_info_by_id[field_id]["page"] = page_index + 1
field_info_by_id[field_id]["rect"] = ann.get('/Rect')
elif field_id in possible_radio_names:
try:
# ann['/AP']['/N'] should have two items. One of them is '/Off',
# the other is the active value.
on_values = [v for v in ann["/AP"]["/N"] if v != "/Off"]
except KeyError:
continue
if len(on_values) == 1:
rect = ann.get("/Rect")
if field_id not in radio_fields_by_id:
radio_fields_by_id[field_id] = {
"field_id": field_id,
"type": "radio_group",
"page": page_index + 1,
"radio_options": [],
}
# Note: at least on macOS 15.7, Preview.app doesn't show selected
# radio buttons correctly. (It does if you remove the leading slash
# from the value, but that causes them not to appear correctly in
# Chrome/Firefox/Acrobat/etc).
radio_fields_by_id[field_id]["radio_options"].append({
"value": on_values[0],
"rect": rect,
})
# Some PDFs have form field definitions without corresponding annotations,
# so we can't tell where they are. Ignore these fields for now.
fields_with_location = []
for field_info in field_info_by_id.values():
if "page" in field_info:
fields_with_location.append(field_info)
else:
print(f"Unable to determine location for field id: {field_info.get('field_id')}, ignoring")
# Sort by page number, then Y position (flipped in PDF coordinate system), then X.
def sort_key(f):
if "radio_options" in f:
rect = f["radio_options"][0]["rect"] or [0, 0, 0, 0]
else:
rect = f.get("rect") or [0, 0, 0, 0]
adjusted_position = [-rect[1], rect[0]]
return [f.get("page"), adjusted_position]
sorted_fields = fields_with_location + list(radio_fields_by_id.values())
sorted_fields.sort(key=sort_key)
return sorted_fields
def write_field_info(pdf_path: str, json_output_path: str):
reader = PdfReader(pdf_path)
field_info = get_field_info(reader)
with open(json_output_path, "w") as f:
json.dump(field_info, f, indent=2)
print(f"Wrote {len(field_info)} fields to {json_output_path}")
if __name__ == "__main__":
if len(sys.argv) != 3:
print("Usage: extract_form_field_info.py [input pdf] [output json]")
sys.exit(1)
write_field_info(sys.argv[1], sys.argv[2])

View File

@@ -0,0 +1,114 @@
import json
import sys
from pypdf import PdfReader, PdfWriter
from extract_form_field_info import get_field_info
# Fills fillable form fields in a PDF. See forms.md.
def fill_pdf_fields(input_pdf_path: str, fields_json_path: str, output_pdf_path: str):
with open(fields_json_path) as f:
fields = json.load(f)
# Group by page number.
fields_by_page = {}
for field in fields:
if "value" in field:
field_id = field["field_id"]
page = field["page"]
if page not in fields_by_page:
fields_by_page[page] = {}
fields_by_page[page][field_id] = field["value"]
reader = PdfReader(input_pdf_path)
has_error = False
field_info = get_field_info(reader)
fields_by_ids = {f["field_id"]: f for f in field_info}
for field in fields:
existing_field = fields_by_ids.get(field["field_id"])
if not existing_field:
has_error = True
print(f"ERROR: `{field['field_id']}` is not a valid field ID")
elif field["page"] != existing_field["page"]:
has_error = True
print(f"ERROR: Incorrect page number for `{field['field_id']}` (got {field['page']}, expected {existing_field['page']})")
else:
if "value" in field:
err = validation_error_for_field_value(existing_field, field["value"])
if err:
print(err)
has_error = True
if has_error:
sys.exit(1)
writer = PdfWriter(clone_from=reader)
for page, field_values in fields_by_page.items():
writer.update_page_form_field_values(writer.pages[page - 1], field_values, auto_regenerate=False)
# This seems to be necessary for many PDF viewers to format the form values correctly.
# It may cause the viewer to show a "save changes" dialog even if the user doesn't make any changes.
writer.set_need_appearances_writer(True)
with open(output_pdf_path, "wb") as f:
writer.write(f)
def validation_error_for_field_value(field_info, field_value):
field_type = field_info["type"]
field_id = field_info["field_id"]
if field_type == "checkbox":
checked_val = field_info["checked_value"]
unchecked_val = field_info["unchecked_value"]
if field_value != checked_val and field_value != unchecked_val:
return f'ERROR: Invalid value "{field_value}" for checkbox field "{field_id}". The checked value is "{checked_val}" and the unchecked value is "{unchecked_val}"'
elif field_type == "radio_group":
option_values = [opt["value"] for opt in field_info["radio_options"]]
if field_value not in option_values:
return f'ERROR: Invalid value "{field_value}" for radio group field "{field_id}". Valid values are: {option_values}'
elif field_type == "choice":
choice_values = [opt["value"] for opt in field_info["choice_options"]]
if field_value not in choice_values:
return f'ERROR: Invalid value "{field_value}" for choice field "{field_id}". Valid values are: {choice_values}'
return None
# pypdf (at least version 5.7.0) has a bug when setting the value for a selection list field.
# In _writer.py around line 966:
#
# if field.get(FA.FT, "/Tx") == "/Ch" and field_flags & FA.FfBits.Combo == 0:
# txt = "\n".join(annotation.get_inherited(FA.Opt, []))
#
# The problem is that for selection lists, `get_inherited` returns a list of two-element lists like
# [["value1", "Text 1"], ["value2", "Text 2"], ...]
# This causes `join` to throw a TypeError because it expects an iterable of strings.
# The horrible workaround is to patch `get_inherited` to return a list of the value strings.
# We call the original method and adjust the return value only if the argument to `get_inherited`
# is `FA.Opt` and if the return value is a list of two-element lists.
def monkeypatch_pydpf_method():
from pypdf.generic import DictionaryObject
from pypdf.constants import FieldDictionaryAttributes
original_get_inherited = DictionaryObject.get_inherited
def patched_get_inherited(self, key: str, default = None):
result = original_get_inherited(self, key, default)
if key == FieldDictionaryAttributes.Opt:
if isinstance(result, list) and all(isinstance(v, list) and len(v) == 2 for v in result):
result = [r[0] for r in result]
return result
DictionaryObject.get_inherited = patched_get_inherited
if __name__ == "__main__":
if len(sys.argv) != 4:
print("Usage: fill_fillable_fields.py [input pdf] [field_values.json] [output pdf]")
sys.exit(1)
monkeypatch_pydpf_method()
input_pdf = sys.argv[1]
fields_json = sys.argv[2]
output_pdf = sys.argv[3]
fill_pdf_fields(input_pdf, fields_json, output_pdf)

View File

@@ -0,0 +1,108 @@
import json
import sys
from pypdf import PdfReader, PdfWriter
from pypdf.annotations import FreeText
# Fills a PDF by adding text annotations defined in `fields.json`. See forms.md.
def transform_coordinates(bbox, image_width, image_height, pdf_width, pdf_height):
"""Transform bounding box from image coordinates to PDF coordinates"""
# Image coordinates: origin at top-left, y increases downward
# PDF coordinates: origin at bottom-left, y increases upward
x_scale = pdf_width / image_width
y_scale = pdf_height / image_height
left = bbox[0] * x_scale
right = bbox[2] * x_scale
# Flip Y coordinates for PDF
top = pdf_height - (bbox[1] * y_scale)
bottom = pdf_height - (bbox[3] * y_scale)
return left, bottom, right, top
def fill_pdf_form(input_pdf_path, fields_json_path, output_pdf_path):
"""Fill the PDF form with data from fields.json"""
# `fields.json` format described in forms.md.
with open(fields_json_path, "r") as f:
fields_data = json.load(f)
# Open the PDF
reader = PdfReader(input_pdf_path)
writer = PdfWriter()
# Copy all pages to writer
writer.append(reader)
# Get PDF dimensions for each page
pdf_dimensions = {}
for i, page in enumerate(reader.pages):
mediabox = page.mediabox
pdf_dimensions[i + 1] = [mediabox.width, mediabox.height]
# Process each form field
annotations = []
for field in fields_data["form_fields"]:
page_num = field["page_number"]
# Get page dimensions and transform coordinates.
page_info = next(p for p in fields_data["pages"] if p["page_number"] == page_num)
image_width = page_info["image_width"]
image_height = page_info["image_height"]
pdf_width, pdf_height = pdf_dimensions[page_num]
transformed_entry_box = transform_coordinates(
field["entry_bounding_box"],
image_width, image_height,
pdf_width, pdf_height
)
# Skip empty fields
if "entry_text" not in field or "text" not in field["entry_text"]:
continue
entry_text = field["entry_text"]
text = entry_text["text"]
if not text:
continue
font_name = entry_text.get("font", "Arial")
font_size = str(entry_text.get("font_size", 14)) + "pt"
font_color = entry_text.get("font_color", "000000")
# Font size/color seems to not work reliably across viewers:
# https://github.com/py-pdf/pypdf/issues/2084
annotation = FreeText(
text=text,
rect=transformed_entry_box,
font=font_name,
font_size=font_size,
font_color=font_color,
border_color=None,
background_color=None,
)
annotations.append(annotation)
# page_number is 0-based for pypdf
writer.add_annotation(page_number=page_num - 1, annotation=annotation)
# Save the filled PDF
with open(output_pdf_path, "wb") as output:
writer.write(output)
print(f"Successfully filled PDF form and saved to {output_pdf_path}")
print(f"Added {len(annotations)} text annotations")
if __name__ == "__main__":
if len(sys.argv) != 4:
print("Usage: fill_pdf_form_with_annotations.py [input pdf] [fields.json] [output pdf]")
sys.exit(1)
input_pdf = sys.argv[1]
fields_json = sys.argv[2]
output_pdf = sys.argv[3]
fill_pdf_form(input_pdf, fields_json, output_pdf)

View File

@@ -0,0 +1,201 @@
---
name: prompt-engineering-patterns
description: Master advanced prompt engineering techniques to maximize LLM performance, reliability, and controllability in production. Use when optimizing prompts, improving LLM outputs, or designing production prompt templates.
---
# Prompt Engineering Patterns
Master advanced prompt engineering techniques to maximize LLM performance, reliability, and controllability.
## When to Use This Skill
- Designing complex prompts for production LLM applications
- Optimizing prompt performance and consistency
- Implementing structured reasoning patterns (chain-of-thought, tree-of-thought)
- Building few-shot learning systems with dynamic example selection
- Creating reusable prompt templates with variable interpolation
- Debugging and refining prompts that produce inconsistent outputs
- Implementing system prompts for specialized AI assistants
## Core Capabilities
### 1. Few-Shot Learning
- Example selection strategies (semantic similarity, diversity sampling)
- Balancing example count with context window constraints
- Constructing effective demonstrations with input-output pairs
- Dynamic example retrieval from knowledge bases
- Handling edge cases through strategic example selection
### 2. Chain-of-Thought Prompting
- Step-by-step reasoning elicitation
- Zero-shot CoT with "Let's think step by step"
- Few-shot CoT with reasoning traces
- Self-consistency techniques (sampling multiple reasoning paths)
- Verification and validation steps
### 3. Prompt Optimization
- Iterative refinement workflows
- A/B testing prompt variations
- Measuring prompt performance metrics (accuracy, consistency, latency)
- Reducing token usage while maintaining quality
- Handling edge cases and failure modes
### 4. Template Systems
- Variable interpolation and formatting
- Conditional prompt sections
- Multi-turn conversation templates
- Role-based prompt composition
- Modular prompt components
### 5. System Prompt Design
- Setting model behavior and constraints
- Defining output formats and structure
- Establishing role and expertise
- Safety guidelines and content policies
- Context setting and background information
## Quick Start
```python
from prompt_optimizer import PromptTemplate, FewShotSelector
# Define a structured prompt template
template = PromptTemplate(
system="You are an expert SQL developer. Generate efficient, secure SQL queries.",
instruction="Convert the following natural language query to SQL:\n{query}",
few_shot_examples=True,
output_format="SQL code block with explanatory comments"
)
# Configure few-shot learning
selector = FewShotSelector(
examples_db="sql_examples.jsonl",
selection_strategy="semantic_similarity",
max_examples=3
)
# Generate optimized prompt
prompt = template.render(
query="Find all users who registered in the last 30 days",
examples=selector.select(query="user registration date filter")
)
```
## Key Patterns
### Progressive Disclosure
Start with simple prompts, add complexity only when needed:
1. **Level 1**: Direct instruction
- "Summarize this article"
2. **Level 2**: Add constraints
- "Summarize this article in 3 bullet points, focusing on key findings"
3. **Level 3**: Add reasoning
- "Read this article, identify the main findings, then summarize in 3 bullet points"
4. **Level 4**: Add examples
- Include 2-3 example summaries with input-output pairs
### Instruction Hierarchy
```
[System Context] → [Task Instruction] → [Examples] → [Input Data] → [Output Format]
```
### Error Recovery
Build prompts that gracefully handle failures:
- Include fallback instructions
- Request confidence scores
- Ask for alternative interpretations when uncertain
- Specify how to indicate missing information
## Best Practices
1. **Be Specific**: Vague prompts produce inconsistent results
2. **Show, Don't Tell**: Examples are more effective than descriptions
3. **Test Extensively**: Evaluate on diverse, representative inputs
4. **Iterate Rapidly**: Small changes can have large impacts
5. **Monitor Performance**: Track metrics in production
6. **Version Control**: Treat prompts as code with proper versioning
7. **Document Intent**: Explain why prompts are structured as they are
## Common Pitfalls
- **Over-engineering**: Starting with complex prompts before trying simple ones
- **Example pollution**: Using examples that don't match the target task
- **Context overflow**: Exceeding token limits with excessive examples
- **Ambiguous instructions**: Leaving room for multiple interpretations
- **Ignoring edge cases**: Not testing on unusual or boundary inputs
## Integration Patterns
### With RAG Systems
```python
# Combine retrieved context with prompt engineering
prompt = f"""Given the following context:
{retrieved_context}
{few_shot_examples}
Question: {user_question}
Provide a detailed answer based solely on the context above. If the context doesn't contain enough information, explicitly state what's missing."""
```
### With Validation
```python
# Add self-verification step
prompt = f"""{main_task_prompt}
After generating your response, verify it meets these criteria:
1. Answers the question directly
2. Uses only information from provided context
3. Cites specific sources
4. Acknowledges any uncertainty
If verification fails, revise your response."""
```
## Performance Optimization
### Token Efficiency
- Remove redundant words and phrases
- Use abbreviations consistently after first definition
- Consolidate similar instructions
- Move stable content to system prompts
### Latency Reduction
- Minimize prompt length without sacrificing quality
- Use streaming for long-form outputs
- Cache common prompt prefixes
- Batch similar requests when possible
## Resources
- **references/few-shot-learning.md**: Deep dive on example selection and construction
- **references/chain-of-thought.md**: Advanced reasoning elicitation techniques
- **references/prompt-optimization.md**: Systematic refinement workflows
- **references/prompt-templates.md**: Reusable template patterns
- **references/system-prompts.md**: System-level prompt design
- **assets/prompt-template-library.md**: Battle-tested prompt templates
- **assets/few-shot-examples.json**: Curated example datasets
- **scripts/optimize-prompt.py**: Automated prompt optimization tool
## Success Metrics
Track these KPIs for your prompts:
- **Accuracy**: Correctness of outputs
- **Consistency**: Reproducibility across similar inputs
- **Latency**: Response time (P50, P95, P99)
- **Token Usage**: Average tokens per request
- **Success Rate**: Percentage of valid outputs
- **User Satisfaction**: Ratings and feedback
## Next Steps
1. Review the prompt template library for common patterns
2. Experiment with few-shot learning for your specific use case
3. Implement prompt versioning and A/B testing
4. Set up automated evaluation pipelines
5. Document your prompt engineering decisions and learnings

View File

@@ -0,0 +1,106 @@
{
"sentiment_analysis": [
{
"input": "This product exceeded my expectations! The quality is outstanding.",
"output": "Positive"
},
{
"input": "Terrible experience. The item arrived damaged and customer service was unhelpful.",
"output": "Negative"
},
{
"input": "The product works as described. Nothing special, but does the job.",
"output": "Neutral"
}
],
"entity_extraction": [
{
"input": "Apple CEO Tim Cook announced the new iPhone at an event in Cupertino on September 12th.",
"output": {
"persons": ["Tim Cook"],
"organizations": ["Apple"],
"products": ["iPhone"],
"locations": ["Cupertino"],
"dates": ["September 12th"]
}
},
{
"input": "Microsoft acquired GitHub for $7.5 billion in 2018.",
"output": {
"persons": [],
"organizations": ["Microsoft", "GitHub"],
"products": [],
"locations": [],
"dates": ["2018"],
"monetary_values": ["$7.5 billion"]
}
}
],
"code_generation": [
{
"input": "Write a Python function to check if a string is a palindrome",
"output": "def is_palindrome(s: str) -> bool:\n \"\"\"Check if string is palindrome, ignoring case and spaces.\"\"\"\n # Remove spaces and convert to lowercase\n cleaned = s.replace(' ', '').lower()\n # Compare with reversed string\n return cleaned == cleaned[::-1]"
}
],
"text_classification": [
{
"input": "How do I reset my password?",
"output": "account_management"
},
{
"input": "My order hasn't arrived yet. Where is it?",
"output": "shipping_inquiry"
},
{
"input": "I'd like to cancel my subscription.",
"output": "subscription_cancellation"
},
{
"input": "The app keeps crashing when I try to log in.",
"output": "technical_support"
}
],
"data_transformation": [
{
"input": "John Smith, john@email.com, (555) 123-4567",
"output": {
"name": "John Smith",
"email": "john@email.com",
"phone": "(555) 123-4567"
}
},
{
"input": "Jane Doe | jane.doe@company.com | +1-555-987-6543",
"output": {
"name": "Jane Doe",
"email": "jane.doe@company.com",
"phone": "+1-555-987-6543"
}
}
],
"question_answering": [
{
"context": "The Eiffel Tower is a wrought-iron lattice tower in Paris, France. It was constructed from 1887 to 1889 and stands 324 meters (1,063 ft) tall.",
"question": "When was the Eiffel Tower built?",
"answer": "The Eiffel Tower was constructed from 1887 to 1889."
},
{
"context": "Python 3.11 was released on October 24, 2022. It includes performance improvements and new features like exception groups and improved error messages.",
"question": "What are the new features in Python 3.11?",
"answer": "Python 3.11 includes exception groups, improved error messages, and performance improvements."
}
],
"summarization": [
{
"input": "Climate change refers to long-term shifts in global temperatures and weather patterns. While climate change is natural, human activities have been the main driver since the 1800s, primarily due to the burning of fossil fuels like coal, oil and gas which produces heat-trapping greenhouse gases. The consequences include rising sea levels, more extreme weather events, and threats to biodiversity.",
"output": "Climate change involves long-term alterations in global temperatures and weather patterns, primarily driven by human fossil fuel consumption since the 1800s, resulting in rising sea levels, extreme weather, and biodiversity threats."
}
],
"sql_generation": [
{
"schema": "users (id, name, email, created_at)\norders (id, user_id, total, order_date)",
"request": "Find all users who have placed orders totaling more than $1000",
"output": "SELECT u.id, u.name, u.email, SUM(o.total) as total_spent\nFROM users u\nJOIN orders o ON u.id = o.user_id\nGROUP BY u.id, u.name, u.email\nHAVING SUM(o.total) > 1000;"
}
]
}

View File

@@ -0,0 +1,246 @@
# Prompt Template Library
## Classification Templates
### Sentiment Analysis
```
Classify the sentiment of the following text as Positive, Negative, or Neutral.
Text: {text}
Sentiment:
```
### Intent Detection
```
Determine the user's intent from the following message.
Possible intents: {intent_list}
Message: {message}
Intent:
```
### Topic Classification
```
Classify the following article into one of these categories: {categories}
Article:
{article}
Category:
```
## Extraction Templates
### Named Entity Recognition
```
Extract all named entities from the text and categorize them.
Text: {text}
Entities (JSON format):
{
"persons": [],
"organizations": [],
"locations": [],
"dates": []
}
```
### Structured Data Extraction
```
Extract structured information from the job posting.
Job Posting:
{posting}
Extracted Information (JSON):
{
"title": "",
"company": "",
"location": "",
"salary_range": "",
"requirements": [],
"responsibilities": []
}
```
## Generation Templates
### Email Generation
```
Write a professional {email_type} email.
To: {recipient}
Context: {context}
Key points to include:
{key_points}
Email:
Subject:
Body:
```
### Code Generation
```
Generate {language} code for the following task:
Task: {task_description}
Requirements:
{requirements}
Include:
- Error handling
- Input validation
- Inline comments
Code:
```
### Creative Writing
```
Write a {length}-word {style} story about {topic}.
Include these elements:
- {element_1}
- {element_2}
- {element_3}
Story:
```
## Transformation Templates
### Summarization
```
Summarize the following text in {num_sentences} sentences.
Text:
{text}
Summary:
```
### Translation with Context
```
Translate the following {source_lang} text to {target_lang}.
Context: {context}
Tone: {tone}
Text: {text}
Translation:
```
### Format Conversion
```
Convert the following {source_format} to {target_format}.
Input:
{input_data}
Output ({target_format}):
```
## Analysis Templates
### Code Review
```
Review the following code for:
1. Bugs and errors
2. Performance issues
3. Security vulnerabilities
4. Best practice violations
Code:
{code}
Review:
```
### SWOT Analysis
```
Conduct a SWOT analysis for: {subject}
Context: {context}
Analysis:
Strengths:
-
Weaknesses:
-
Opportunities:
-
Threats:
-
```
## Question Answering Templates
### RAG Template
```
Answer the question based on the provided context. If the context doesn't contain enough information, say so.
Context:
{context}
Question: {question}
Answer:
```
### Multi-Turn Q&A
```
Previous conversation:
{conversation_history}
New question: {question}
Answer (continue naturally from conversation):
```
## Specialized Templates
### SQL Query Generation
```
Generate a SQL query for the following request.
Database schema:
{schema}
Request: {request}
SQL Query:
```
### Regex Pattern Creation
```
Create a regex pattern to match: {requirement}
Test cases that should match:
{positive_examples}
Test cases that should NOT match:
{negative_examples}
Regex pattern:
```
### API Documentation
```
Generate API documentation for this function:
Code:
{function_code}
Documentation (follow {doc_format} format):
```
## Use these templates by filling in the {variables}

View File

@@ -0,0 +1,399 @@
# Chain-of-Thought Prompting
## Overview
Chain-of-Thought (CoT) prompting elicits step-by-step reasoning from LLMs, dramatically improving performance on complex reasoning, math, and logic tasks.
## Core Techniques
### Zero-Shot CoT
Add a simple trigger phrase to elicit reasoning:
```python
def zero_shot_cot(query):
return f"""{query}
Let's think step by step:"""
# Example
query = "If a train travels 60 mph for 2.5 hours, how far does it go?"
prompt = zero_shot_cot(query)
# Model output:
# "Let's think step by step:
# 1. Speed = 60 miles per hour
# 2. Time = 2.5 hours
# 3. Distance = Speed × Time
# 4. Distance = 60 × 2.5 = 150 miles
# Answer: 150 miles"
```
### Few-Shot CoT
Provide examples with explicit reasoning chains:
```python
few_shot_examples = """
Q: Roger has 5 tennis balls. He buys 2 more cans of tennis balls. Each can has 3 balls. How many tennis balls does he have now?
A: Let's think step by step:
1. Roger starts with 5 balls
2. He buys 2 cans, each with 3 balls
3. Balls from cans: 2 × 3 = 6 balls
4. Total: 5 + 6 = 11 balls
Answer: 11
Q: The cafeteria had 23 apples. If they used 20 to make lunch and bought 6 more, how many do they have?
A: Let's think step by step:
1. Started with 23 apples
2. Used 20 for lunch: 23 - 20 = 3 apples left
3. Bought 6 more: 3 + 6 = 9 apples
Answer: 9
Q: {user_query}
A: Let's think step by step:"""
```
### Self-Consistency
Generate multiple reasoning paths and take the majority vote:
```python
import openai
from collections import Counter
def self_consistency_cot(query, n=5, temperature=0.7):
prompt = f"{query}\n\nLet's think step by step:"
responses = []
for _ in range(n):
response = openai.ChatCompletion.create(
model="gpt-5",
messages=[{"role": "user", "content": prompt}],
temperature=temperature
)
responses.append(extract_final_answer(response))
# Take majority vote
answer_counts = Counter(responses)
final_answer = answer_counts.most_common(1)[0][0]
return {
'answer': final_answer,
'confidence': answer_counts[final_answer] / n,
'all_responses': responses
}
```
## Advanced Patterns
### Least-to-Most Prompting
Break complex problems into simpler subproblems:
```python
def least_to_most_prompt(complex_query):
# Stage 1: Decomposition
decomp_prompt = f"""Break down this complex problem into simpler subproblems:
Problem: {complex_query}
Subproblems:"""
subproblems = get_llm_response(decomp_prompt)
# Stage 2: Sequential solving
solutions = []
context = ""
for subproblem in subproblems:
solve_prompt = f"""{context}
Solve this subproblem:
{subproblem}
Solution:"""
solution = get_llm_response(solve_prompt)
solutions.append(solution)
context += f"\n\nPreviously solved: {subproblem}\nSolution: {solution}"
# Stage 3: Final integration
final_prompt = f"""Given these solutions to subproblems:
{context}
Provide the final answer to: {complex_query}
Final Answer:"""
return get_llm_response(final_prompt)
```
### Tree-of-Thought (ToT)
Explore multiple reasoning branches:
```python
class TreeOfThought:
def __init__(self, llm_client, max_depth=3, branches_per_step=3):
self.client = llm_client
self.max_depth = max_depth
self.branches_per_step = branches_per_step
def solve(self, problem):
# Generate initial thought branches
initial_thoughts = self.generate_thoughts(problem, depth=0)
# Evaluate each branch
best_path = None
best_score = -1
for thought in initial_thoughts:
path, score = self.explore_branch(problem, thought, depth=1)
if score > best_score:
best_score = score
best_path = path
return best_path
def generate_thoughts(self, problem, context="", depth=0):
prompt = f"""Problem: {problem}
{context}
Generate {self.branches_per_step} different next steps in solving this problem:
1."""
response = self.client.complete(prompt)
return self.parse_thoughts(response)
def evaluate_thought(self, problem, thought_path):
prompt = f"""Problem: {problem}
Reasoning path so far:
{thought_path}
Rate this reasoning path from 0-10 for:
- Correctness
- Likelihood of reaching solution
- Logical coherence
Score:"""
return float(self.client.complete(prompt))
```
### Verification Step
Add explicit verification to catch errors:
```python
def cot_with_verification(query):
# Step 1: Generate reasoning and answer
reasoning_prompt = f"""{query}
Let's solve this step by step:"""
reasoning_response = get_llm_response(reasoning_prompt)
# Step 2: Verify the reasoning
verification_prompt = f"""Original problem: {query}
Proposed solution:
{reasoning_response}
Verify this solution by:
1. Checking each step for logical errors
2. Verifying arithmetic calculations
3. Ensuring the final answer makes sense
Is this solution correct? If not, what's wrong?
Verification:"""
verification = get_llm_response(verification_prompt)
# Step 3: Revise if needed
if "incorrect" in verification.lower() or "error" in verification.lower():
revision_prompt = f"""The previous solution had errors:
{verification}
Please provide a corrected solution to: {query}
Corrected solution:"""
return get_llm_response(revision_prompt)
return reasoning_response
```
## Domain-Specific CoT
### Math Problems
```python
math_cot_template = """
Problem: {problem}
Solution:
Step 1: Identify what we know
- {list_known_values}
Step 2: Identify what we need to find
- {target_variable}
Step 3: Choose relevant formulas
- {formulas}
Step 4: Substitute values
- {substitution}
Step 5: Calculate
- {calculation}
Step 6: Verify and state answer
- {verification}
Answer: {final_answer}
"""
```
### Code Debugging
```python
debug_cot_template = """
Code with error:
{code}
Error message:
{error}
Debugging process:
Step 1: Understand the error message
- {interpret_error}
Step 2: Locate the problematic line
- {identify_line}
Step 3: Analyze why this line fails
- {root_cause}
Step 4: Determine the fix
- {proposed_fix}
Step 5: Verify the fix addresses the error
- {verification}
Fixed code:
{corrected_code}
"""
```
### Logical Reasoning
```python
logic_cot_template = """
Premises:
{premises}
Question: {question}
Reasoning:
Step 1: List all given facts
{facts}
Step 2: Identify logical relationships
{relationships}
Step 3: Apply deductive reasoning
{deductions}
Step 4: Draw conclusion
{conclusion}
Answer: {final_answer}
"""
```
## Performance Optimization
### Caching Reasoning Patterns
```python
class ReasoningCache:
def __init__(self):
self.cache = {}
def get_similar_reasoning(self, problem, threshold=0.85):
problem_embedding = embed(problem)
for cached_problem, reasoning in self.cache.items():
similarity = cosine_similarity(
problem_embedding,
embed(cached_problem)
)
if similarity > threshold:
return reasoning
return None
def add_reasoning(self, problem, reasoning):
self.cache[problem] = reasoning
```
### Adaptive Reasoning Depth
```python
def adaptive_cot(problem, initial_depth=3):
depth = initial_depth
while depth <= 10: # Max depth
response = generate_cot(problem, num_steps=depth)
# Check if solution seems complete
if is_solution_complete(response):
return response
depth += 2 # Increase reasoning depth
return response # Return best attempt
```
## Evaluation Metrics
```python
def evaluate_cot_quality(reasoning_chain):
metrics = {
'coherence': measure_logical_coherence(reasoning_chain),
'completeness': check_all_steps_present(reasoning_chain),
'correctness': verify_final_answer(reasoning_chain),
'efficiency': count_unnecessary_steps(reasoning_chain),
'clarity': rate_explanation_clarity(reasoning_chain)
}
return metrics
```
## Best Practices
1. **Clear Step Markers**: Use numbered steps or clear delimiters
2. **Show All Work**: Don't skip steps, even obvious ones
3. **Verify Calculations**: Add explicit verification steps
4. **State Assumptions**: Make implicit assumptions explicit
5. **Check Edge Cases**: Consider boundary conditions
6. **Use Examples**: Show the reasoning pattern with examples first
## Common Pitfalls
- **Premature Conclusions**: Jumping to answer without full reasoning
- **Circular Logic**: Using the conclusion to justify the reasoning
- **Missing Steps**: Skipping intermediate calculations
- **Overcomplicated**: Adding unnecessary steps that confuse
- **Inconsistent Format**: Changing step structure mid-reasoning
## When to Use CoT
**Use CoT for:**
- Math and arithmetic problems
- Logical reasoning tasks
- Multi-step planning
- Code generation and debugging
- Complex decision making
**Skip CoT for:**
- Simple factual queries
- Direct lookups
- Creative writing
- Tasks requiring conciseness
- Real-time, latency-sensitive applications
## Resources
- Benchmark datasets for CoT evaluation
- Pre-built CoT prompt templates
- Reasoning verification tools
- Step extraction and parsing utilities

View File

@@ -0,0 +1,369 @@
# Few-Shot Learning Guide
## Overview
Few-shot learning enables LLMs to perform tasks by providing a small number of examples (typically 1-10) within the prompt. This technique is highly effective for tasks requiring specific formats, styles, or domain knowledge.
## Example Selection Strategies
### 1. Semantic Similarity
Select examples most similar to the input query using embedding-based retrieval.
```python
from sentence_transformers import SentenceTransformer
import numpy as np
class SemanticExampleSelector:
def __init__(self, examples, model_name='all-MiniLM-L6-v2'):
self.model = SentenceTransformer(model_name)
self.examples = examples
self.example_embeddings = self.model.encode([ex['input'] for ex in examples])
def select(self, query, k=3):
query_embedding = self.model.encode([query])
similarities = np.dot(self.example_embeddings, query_embedding.T).flatten()
top_indices = np.argsort(similarities)[-k:][::-1]
return [self.examples[i] for i in top_indices]
```
**Best For**: Question answering, text classification, extraction tasks
### 2. Diversity Sampling
Maximize coverage of different patterns and edge cases.
```python
from sklearn.cluster import KMeans
class DiversityExampleSelector:
def __init__(self, examples, model_name='all-MiniLM-L6-v2'):
self.model = SentenceTransformer(model_name)
self.examples = examples
self.embeddings = self.model.encode([ex['input'] for ex in examples])
def select(self, k=5):
# Use k-means to find diverse cluster centers
kmeans = KMeans(n_clusters=k, random_state=42)
kmeans.fit(self.embeddings)
# Select example closest to each cluster center
diverse_examples = []
for center in kmeans.cluster_centers_:
distances = np.linalg.norm(self.embeddings - center, axis=1)
closest_idx = np.argmin(distances)
diverse_examples.append(self.examples[closest_idx])
return diverse_examples
```
**Best For**: Demonstrating task variability, edge case handling
### 3. Difficulty-Based Selection
Gradually increase example complexity to scaffold learning.
```python
class ProgressiveExampleSelector:
def __init__(self, examples):
# Examples should have 'difficulty' scores (0-1)
self.examples = sorted(examples, key=lambda x: x['difficulty'])
def select(self, k=3):
# Select examples with linearly increasing difficulty
step = len(self.examples) // k
return [self.examples[i * step] for i in range(k)]
```
**Best For**: Complex reasoning tasks, code generation
### 4. Error-Based Selection
Include examples that address common failure modes.
```python
class ErrorGuidedSelector:
def __init__(self, examples, error_patterns):
self.examples = examples
self.error_patterns = error_patterns # Common mistakes to avoid
def select(self, query, k=3):
# Select examples demonstrating correct handling of error patterns
selected = []
for pattern in self.error_patterns[:k]:
matching = [ex for ex in self.examples if pattern in ex['demonstrates']]
if matching:
selected.append(matching[0])
return selected
```
**Best For**: Tasks with known failure patterns, safety-critical applications
## Example Construction Best Practices
### Format Consistency
All examples should follow identical formatting:
```python
# Good: Consistent format
examples = [
{
"input": "What is the capital of France?",
"output": "Paris"
},
{
"input": "What is the capital of Germany?",
"output": "Berlin"
}
]
# Bad: Inconsistent format
examples = [
"Q: What is the capital of France? A: Paris",
{"question": "What is the capital of Germany?", "answer": "Berlin"}
]
```
### Input-Output Alignment
Ensure examples demonstrate the exact task you want the model to perform:
```python
# Good: Clear input-output relationship
example = {
"input": "Sentiment: The movie was terrible and boring.",
"output": "Negative"
}
# Bad: Ambiguous relationship
example = {
"input": "The movie was terrible and boring.",
"output": "This review expresses negative sentiment toward the film."
}
```
### Complexity Balance
Include examples spanning the expected difficulty range:
```python
examples = [
# Simple case
{"input": "2 + 2", "output": "4"},
# Moderate case
{"input": "15 * 3 + 8", "output": "53"},
# Complex case
{"input": "(12 + 8) * 3 - 15 / 5", "output": "57"}
]
```
## Context Window Management
### Token Budget Allocation
Typical distribution for a 4K context window:
```
System Prompt: 500 tokens (12%)
Few-Shot Examples: 1500 tokens (38%)
User Input: 500 tokens (12%)
Response: 1500 tokens (38%)
```
### Dynamic Example Truncation
```python
class TokenAwareSelector:
def __init__(self, examples, tokenizer, max_tokens=1500):
self.examples = examples
self.tokenizer = tokenizer
self.max_tokens = max_tokens
def select(self, query, k=5):
selected = []
total_tokens = 0
# Start with most relevant examples
candidates = self.rank_by_relevance(query)
for example in candidates[:k]:
example_tokens = len(self.tokenizer.encode(
f"Input: {example['input']}\nOutput: {example['output']}\n\n"
))
if total_tokens + example_tokens <= self.max_tokens:
selected.append(example)
total_tokens += example_tokens
else:
break
return selected
```
## Edge Case Handling
### Include Boundary Examples
```python
edge_case_examples = [
# Empty input
{"input": "", "output": "Please provide input text."},
# Very long input (truncated in example)
{"input": "..." + "word " * 1000, "output": "Input exceeds maximum length."},
# Ambiguous input
{"input": "bank", "output": "Ambiguous: Could refer to financial institution or river bank."},
# Invalid input
{"input": "!@#$%", "output": "Invalid input format. Please provide valid text."}
]
```
## Few-Shot Prompt Templates
### Classification Template
```python
def build_classification_prompt(examples, query, labels):
prompt = f"Classify the text into one of these categories: {', '.join(labels)}\n\n"
for ex in examples:
prompt += f"Text: {ex['input']}\nCategory: {ex['output']}\n\n"
prompt += f"Text: {query}\nCategory:"
return prompt
```
### Extraction Template
```python
def build_extraction_prompt(examples, query):
prompt = "Extract structured information from the text.\n\n"
for ex in examples:
prompt += f"Text: {ex['input']}\nExtracted: {json.dumps(ex['output'])}\n\n"
prompt += f"Text: {query}\nExtracted:"
return prompt
```
### Transformation Template
```python
def build_transformation_prompt(examples, query):
prompt = "Transform the input according to the pattern shown in examples.\n\n"
for ex in examples:
prompt += f"Input: {ex['input']}\nOutput: {ex['output']}\n\n"
prompt += f"Input: {query}\nOutput:"
return prompt
```
## Evaluation and Optimization
### Example Quality Metrics
```python
def evaluate_example_quality(example, validation_set):
metrics = {
'clarity': rate_clarity(example), # 0-1 score
'representativeness': calculate_similarity_to_validation(example, validation_set),
'difficulty': estimate_difficulty(example),
'uniqueness': calculate_uniqueness(example, other_examples)
}
return metrics
```
### A/B Testing Example Sets
```python
class ExampleSetTester:
def __init__(self, llm_client):
self.client = llm_client
def compare_example_sets(self, set_a, set_b, test_queries):
results_a = self.evaluate_set(set_a, test_queries)
results_b = self.evaluate_set(set_b, test_queries)
return {
'set_a_accuracy': results_a['accuracy'],
'set_b_accuracy': results_b['accuracy'],
'winner': 'A' if results_a['accuracy'] > results_b['accuracy'] else 'B',
'improvement': abs(results_a['accuracy'] - results_b['accuracy'])
}
def evaluate_set(self, examples, test_queries):
correct = 0
for query in test_queries:
prompt = build_prompt(examples, query['input'])
response = self.client.complete(prompt)
if response == query['expected_output']:
correct += 1
return {'accuracy': correct / len(test_queries)}
```
## Advanced Techniques
### Meta-Learning (Learning to Select)
Train a small model to predict which examples will be most effective:
```python
from sklearn.ensemble import RandomForestClassifier
class LearnedExampleSelector:
def __init__(self):
self.selector_model = RandomForestClassifier()
def train(self, training_data):
# training_data: list of (query, example, success) tuples
features = []
labels = []
for query, example, success in training_data:
features.append(self.extract_features(query, example))
labels.append(1 if success else 0)
self.selector_model.fit(features, labels)
def extract_features(self, query, example):
return [
semantic_similarity(query, example['input']),
len(example['input']),
len(example['output']),
keyword_overlap(query, example['input'])
]
def select(self, query, candidates, k=3):
scores = []
for example in candidates:
features = self.extract_features(query, example)
score = self.selector_model.predict_proba([features])[0][1]
scores.append((score, example))
return [ex for _, ex in sorted(scores, reverse=True)[:k]]
```
### Adaptive Example Count
Dynamically adjust the number of examples based on task difficulty:
```python
class AdaptiveExampleSelector:
def __init__(self, examples):
self.examples = examples
def select(self, query, max_examples=5):
# Start with 1 example
for k in range(1, max_examples + 1):
selected = self.get_top_k(query, k)
# Quick confidence check (could use a lightweight model)
if self.estimated_confidence(query, selected) > 0.9:
return selected
return selected # Return max_examples if never confident enough
```
## Common Mistakes
1. **Too Many Examples**: More isn't always better; can dilute focus
2. **Irrelevant Examples**: Examples should match the target task closely
3. **Inconsistent Formatting**: Confuses the model about output format
4. **Overfitting to Examples**: Model copies example patterns too literally
5. **Ignoring Token Limits**: Running out of space for actual input/output
## Resources
- Example dataset repositories
- Pre-built example selectors for common tasks
- Evaluation frameworks for few-shot performance
- Token counting utilities for different models

Some files were not shown because too many files have changed in this diff Show More