* feat(github-copilot-sdk): add workspace skills support - Introduce ENABLE_WORKSPACE_SKILLS valve to enable/disable workspace custom tools discovery - Modify _build_session_config() to auto-load tools from .copilot-skills/ directory - Add workspace_skills_example.py template with 3 working example tools - Update README.md and README_CN.md with Workspace Skills guide and usage examples - Create v0.9.0.md and v0.9.0_CN.md release notes - Sync version to all docs files (index.md, index.zh.md, and main docs) - Bump version from 0.8.0 to 0.9.0 across all 7+ locations * docs: establish temp files handling policy (project-based, not /tmp) - Add TEMP_FILES_POLICY.md guideline for all skills and workflows - Update pr-submitter skill to use .temp/ directory instead of /tmp - Update release-prep skill documentation with temp file convention - Add .temp/ and .build/ entries to .gitignore - Create internal policy memo in /memories/repo/ This policy ensures: - All temporary files stay within project workspace (not system /tmp) - Alignment with OpenWebUI workspace isolation principles - Multi-user safety and cleanup traceability - Consistent handling across all skills and development workflows * fix(terminology): rename 'workspace skills' to 'workspace custom tools' for accuracy The term 'Skills' in Anthropic context refers to instruction-based frameworks (SKILL.md files with YAML frontmatter + markdown), not custom tool functions. Our implementation uses @define_tool decorator to define custom tools that the SDK auto-discovers from .copilot-skills/ directory. These are Tools, not Skills. Changes: - Rename ENABLE_WORKSPACE_SKILLS valve -> ENABLE_WORKSPACE_TOOLS - Update all documentation (README, README_CN, docs, release notes) - Fix section headings and descriptions throughout - Ensure consistent terminology across all files This is a terminology-only change; functionality remains identical. * feat(pipes): release v0.9.0 of GitHub Copilot SDK Pipe - Integrated OpenWebUI Skills Bridge and manage_skills tool - Reinforced status bar stability with session_finalized logic - Added persistent SDK config directory support * docs(pipes): add comprehensive guides and v0.9.0 notes for Copilot SDK - Added skill manager and best practices guides - Added publishing tool documentation - Included v0.9.0 release notes and deployment script - Updated usage guides
7.6 KiB
Skills Best Practices
A concise guide to writing, organizing, and maintaining Copilot SDK skills effectively.
Understanding How Skills Work
Skills are not command-line tools. They are context-injected instruction sets:
- The Copilot SDK daemon reads every
SKILL.mdfile from yourskill_directories - It extracts the YAML
descriptionfield from each skill - When the user sends a message, the SDK compares intent against all descriptions
- If a match is found, the SDK fires
skill.invokedand injects the full SKILL.md body into the conversation as instructions - The agent reads those instructions and executes them using
bash,create_file,view_file, etc.
Key implication: never run a skill's name as a bash command (e.g., finance-reporting). The skill IS the instructions, not an executable.
Writing a Good description Field
The description in SKILL.md frontmatter is the primary trigger mechanism. The SDK uses it like a semantic router.
Do ✅
- Start with a verb: "Manage…", "Generate…", "Analyze…"
- Include explicit "Use when:" scenarios — this is the most reliable trigger signal
- Cover all the intent variations a user might express
description: Generate a PowerPoint presentation from an outline or topic.
Use when: creating slides, building a deck, making a presentation, exporting to PPTX.
Don't ❌
- Vague descriptions: "A useful skill for various things"
- Overlapping descriptions with other skills (causes misfires)
- Omitting "Use when:" examples (reduces trigger reliability significantly)
Rule of Thumb
If two people would phrase the same request differently (e.g., "make slides" vs. "create a deck"), both phrasings should appear somewhere in the description.
Structure: What Goes Where
skill-name/
├── SKILL.md ← Required. Frontmatter + core instructions
├── .owui_id ← Auto-generated. DO NOT edit or delete
├── references/ ← Optional. Supplementary docs, loaded on demand
│ └── advanced.md
├── scripts/ ← Optional. Helper shell/Python scripts
└── assets/ ← Optional. Templates, sample files, static data
When to Use references/
Put content in references/ when it is:
- Only needed for edge cases or advanced usage
- Too long to read every time (> ~100 lines)
- Reference material (API specs, format docs, examples)
Use progressive disclosure: the agent reads SKILL.md first, then loads a specific reference file only when the task requires it.
## Advanced Export Options
See [references/export-options.md](references/export-options.md) for the full list.
When to Inline in SKILL.md
Keep content in SKILL.md when it is:
- Needed for every run of the skill
- Short enough not to slow down context injection (< ~150 lines total)
- Core to the skill's main workflow
Naming Conventions
| Item | Convention | Example |
|---|---|---|
| Skill directory name | kebab-case |
export-to-pptx |
name field in frontmatter |
kebab-case, matches dir name |
export-to-pptx |
| Script filenames | snake_case.py or snake_case.sh |
build_slide.py |
| Reference filenames | kebab-case.md |
advanced-options.md |
Avoid spaces and uppercase in skill directory names — the SDK uses the directory name as the skill identifier.
Writing Effective SKILL.md Instructions
Open With a Role Statement
Tell the agent who it is in this skill context:
# Export to PowerPoint
You are a presentation builder. Your job is to convert the user's content into a well-structured PPTX file using the scripts in this skill directory.
Use Imperative Steps
Write instructions as numbered steps, not prose:
1. Ask the user for the outline if not provided.
2. Run `python3 {scripts_dir}/build_slide.py --title "..." --output "{cwd}/output.pptx"`
3. Confirm success by checking the file exists.
4. Provide the user with the download path.
Handle Errors Explicitly
Tell the agent what to do when things go wrong:
If the script exits with a non-zero code, show the user the stderr output and ask how to proceed.
End With a Closing Instruction
After completing the task, summarize what was created and remind the user where to find the file.
Skill Scope
Each skill should do one thing well. Signs a skill is too broad:
- The description has more than 4–5 "Use when:" entries covering unrelated domains
- The SKILL.md is > 300 lines
- You've added more than 3 reference files
When a skill grows too large, split it: one parent skill for routing + separate child skills per major function.
Managing the shared/ Directory
The shared/ directory is bidirectionally synced with the OpenWebUI database:
- Skills created via the OpenWebUI UI are automatically imported into
shared/ - Skills created by the agent in
shared/are exported back to OpenWebUI at session start
Safe operations
| Operation | Method |
|---|---|
| Install from URL | python3 {scripts_dir}/install_skill.py --url <url> --dest {shared_dir} |
| Create new skill | mkdir -p {shared_dir}/<name>/ && create SKILL.md |
| Edit skill | Read → modify → write SKILL.md |
| Delete skill | rm -rf {shared_dir}/<name>/ (does NOT delete from OpenWebUI UI — do that separately) |
| List skills | python3 {scripts_dir}/list_skills.py --path {shared_dir} |
The .owui_id file
Every skill synced with OpenWebUI has a .owui_id file containing the database UUID. Never edit or delete this file — it is the link between the filesystem and OpenWebUI DB. If deleted, the skill will be treated as new on next sync and may create a duplicate.
Session Lifecycle Awareness
Skills are loaded once at session start. Changes made during a session take effect in the next session.
| When | What happens |
|---|---|
| Session starts | SDK daemon reads all SKILL.md files; _sync_openwebui_skills runs bidirectional DB↔file sync |
| During a session | New/edited/deleted skill files exist on disk but are NOT yet loaded by the daemon |
| After user starts new session | New skills become available; edited descriptions take effect |
Always tell the user after any create/edit/delete: "This change will take effect when you start a new session."
Anti-Patterns to Avoid
| Anti-pattern | Why it's bad | Fix |
|---|---|---|
Running <skill-name> as a bash command |
Skills are not executables | Read the SKILL.md instructions and act with standard tools |
Editing .owui_id |
Breaks DB sync | Never touch it |
Storing per-session state in SKILL.md |
SKILL.md is static instructions, not a state file | Use separate workspace files for session state |
| Ultra-broad skill descriptions | Causes false positives on every message | Narrow to specific intent with "Use when:" |
| Putting all logic in one 500-line SKILL.md | Slow context injection, hard to maintain | Split into SKILL.md + references/*.md |
Creating skills in /tmp |
Not persisted, not found by SDK | Always create in {shared_dir}/ |
Quick Checklist for a New Skill
- Directory name is
kebab-caseand matches thenamefield descriptionstarts with a verb and has "Use when:" examples- SKILL.md opens with a role statement for the agent
- Instructions use imperative numbered steps
- Long reference content moved to
references/ - Scripts placed in
scripts/ - Confirmed: skill does NOT overlap in description with other loaded skills
- User informed: "new skill takes effect next session"