echo-agent 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- echo_agent/__init__.py +5 -0
- echo_agent/__main__.py +538 -0
- echo_agent/_bundled/skills/development/plan/SKILL.md +54 -0
- echo_agent/_bundled/skills/development/skill-creator/SKILL.md +270 -0
- echo_agent/_bundled/skills/development/skill-creator/scripts/init_skill.py +226 -0
- echo_agent/_bundled/skills/development/skill-creator/scripts/package_skill.py +146 -0
- echo_agent/_bundled/skills/development/skill-creator/scripts/quick_validate.py +222 -0
- echo_agent/_bundled/skills/productivity/summarize/SKILL.md +67 -0
- echo_agent/_bundled/skills/productivity/weather/SKILL.md +49 -0
- echo_agent/_bundled/skills/research/arxiv/SKILL.md +232 -0
- echo_agent/_bundled/skills/research/arxiv/scripts/search_arxiv.py +115 -0
- echo_agent/a2a/__init__.py +5 -0
- echo_agent/a2a/client.py +66 -0
- echo_agent/a2a/models.py +98 -0
- echo_agent/a2a/protocol.py +85 -0
- echo_agent/a2a/server.py +71 -0
- echo_agent/agent/__init__.py +0 -0
- echo_agent/agent/approval_gate.py +326 -0
- echo_agent/agent/compression/__init__.py +14 -0
- echo_agent/agent/compression/assembler.py +45 -0
- echo_agent/agent/compression/boundary.py +141 -0
- echo_agent/agent/compression/compressor.py +181 -0
- echo_agent/agent/compression/engine.py +88 -0
- echo_agent/agent/compression/pruner.py +150 -0
- echo_agent/agent/compression/summarizer.py +181 -0
- echo_agent/agent/compression/types.py +41 -0
- echo_agent/agent/compression/validator.py +96 -0
- echo_agent/agent/consolidation.py +96 -0
- echo_agent/agent/context.py +403 -0
- echo_agent/agent/executors/__init__.py +0 -0
- echo_agent/agent/executors/base.py +211 -0
- echo_agent/agent/executors/factory.py +34 -0
- echo_agent/agent/executors/remote.py +193 -0
- echo_agent/agent/loop.py +891 -0
- echo_agent/agent/multi_agent/__init__.py +15 -0
- echo_agent/agent/multi_agent/audit.py +19 -0
- echo_agent/agent/multi_agent/error_messages.py +35 -0
- echo_agent/agent/multi_agent/error_types.py +36 -0
- echo_agent/agent/multi_agent/models.py +37 -0
- echo_agent/agent/multi_agent/registry.py +41 -0
- echo_agent/agent/multi_agent/runtime.py +201 -0
- echo_agent/agent/pipeline/__init__.py +14 -0
- echo_agent/agent/pipeline/context_stage.py +219 -0
- echo_agent/agent/pipeline/inference_stage.py +433 -0
- echo_agent/agent/pipeline/response_stage.py +146 -0
- echo_agent/agent/pipeline/types.py +40 -0
- echo_agent/agent/planning/__init__.py +4 -0
- echo_agent/agent/planning/models.py +83 -0
- echo_agent/agent/planning/planner.py +57 -0
- echo_agent/agent/planning/reflection.py +54 -0
- echo_agent/agent/planning/strategies.py +183 -0
- echo_agent/agent/tools/__init__.py +167 -0
- echo_agent/agent/tools/base.py +149 -0
- echo_agent/agent/tools/circuit_breaker.py +82 -0
- echo_agent/agent/tools/clarify.py +42 -0
- echo_agent/agent/tools/code_exec.py +147 -0
- echo_agent/agent/tools/cronjob.py +93 -0
- echo_agent/agent/tools/delegate.py +393 -0
- echo_agent/agent/tools/filesystem.py +180 -0
- echo_agent/agent/tools/image_gen.py +65 -0
- echo_agent/agent/tools/knowledge.py +81 -0
- echo_agent/agent/tools/memory.py +198 -0
- echo_agent/agent/tools/message.py +39 -0
- echo_agent/agent/tools/notify.py +35 -0
- echo_agent/agent/tools/patch.py +178 -0
- echo_agent/agent/tools/process.py +139 -0
- echo_agent/agent/tools/registry.py +185 -0
- echo_agent/agent/tools/search.py +99 -0
- echo_agent/agent/tools/session_search.py +76 -0
- echo_agent/agent/tools/shell.py +164 -0
- echo_agent/agent/tools/skill_install.py +255 -0
- echo_agent/agent/tools/skills.py +177 -0
- echo_agent/agent/tools/task.py +104 -0
- echo_agent/agent/tools/todo.py +148 -0
- echo_agent/agent/tools/tts.py +77 -0
- echo_agent/agent/tools/vision.py +71 -0
- echo_agent/agent/tools/web.py +208 -0
- echo_agent/agent/tools/workflow.py +89 -0
- echo_agent/bus/__init__.py +11 -0
- echo_agent/bus/events.py +193 -0
- echo_agent/bus/queue.py +158 -0
- echo_agent/bus/rate_limiter.py +51 -0
- echo_agent/channels/__init__.py +0 -0
- echo_agent/channels/base.py +185 -0
- echo_agent/channels/cli.py +149 -0
- echo_agent/channels/cron.py +44 -0
- echo_agent/channels/dingtalk.py +195 -0
- echo_agent/channels/discord.py +359 -0
- echo_agent/channels/email.py +168 -0
- echo_agent/channels/feishu.py +240 -0
- echo_agent/channels/manager.py +417 -0
- echo_agent/channels/matrix.py +281 -0
- echo_agent/channels/qqbot.py +638 -0
- echo_agent/channels/qqbot_media.py +482 -0
- echo_agent/channels/slack.py +297 -0
- echo_agent/channels/telegram.py +275 -0
- echo_agent/channels/webhook.py +106 -0
- echo_agent/channels/wecom.py +152 -0
- echo_agent/channels/weixin.py +603 -0
- echo_agent/channels/whatsapp.py +138 -0
- echo_agent/cli/__init__.py +0 -0
- echo_agent/cli/colors.py +42 -0
- echo_agent/cli/evolution_cmd.py +299 -0
- echo_agent/cli/i18n/__init__.py +123 -0
- echo_agent/cli/i18n/en.py +275 -0
- echo_agent/cli/i18n/zh.py +275 -0
- echo_agent/cli/plugins_cmd.py +205 -0
- echo_agent/cli/prompt.py +102 -0
- echo_agent/cli/service.py +156 -0
- echo_agent/cli/setup.py +1111 -0
- echo_agent/cli/status.py +93 -0
- echo_agent/config/__init__.py +8 -0
- echo_agent/config/default.yaml +199 -0
- echo_agent/config/loader.py +125 -0
- echo_agent/config/schema.py +652 -0
- echo_agent/evaluation/__init__.py +4 -0
- echo_agent/evaluation/dataset.py +66 -0
- echo_agent/evaluation/metrics.py +70 -0
- echo_agent/evaluation/reporter.py +42 -0
- echo_agent/evaluation/runner.py +143 -0
- echo_agent/evolution/__init__.py +38 -0
- echo_agent/evolution/engine.py +335 -0
- echo_agent/evolution/evolver.py +397 -0
- echo_agent/evolution/gate.py +413 -0
- echo_agent/evolution/recorder.py +288 -0
- echo_agent/evolution/scheduler.py +133 -0
- echo_agent/evolution/store.py +331 -0
- echo_agent/evolution/tools.py +110 -0
- echo_agent/evolution/types.py +270 -0
- echo_agent/gateway/__init__.py +7 -0
- echo_agent/gateway/auth.py +178 -0
- echo_agent/gateway/editor.py +121 -0
- echo_agent/gateway/health.py +51 -0
- echo_agent/gateway/hooks.py +86 -0
- echo_agent/gateway/media.py +137 -0
- echo_agent/gateway/rate_limiter.py +72 -0
- echo_agent/gateway/router.py +86 -0
- echo_agent/gateway/server.py +570 -0
- echo_agent/gateway/session_context.py +57 -0
- echo_agent/gateway/session_policy.py +47 -0
- echo_agent/gateway/static/index.html +432 -0
- echo_agent/knowledge/__init__.py +5 -0
- echo_agent/knowledge/index.py +308 -0
- echo_agent/mcp/__init__.py +3 -0
- echo_agent/mcp/client.py +158 -0
- echo_agent/mcp/manager.py +161 -0
- echo_agent/mcp/oauth.py +208 -0
- echo_agent/mcp/security.py +79 -0
- echo_agent/mcp/tool_adapter.py +73 -0
- echo_agent/mcp/transport.py +353 -0
- echo_agent/memory/__init__.py +0 -0
- echo_agent/memory/consolidator.py +273 -0
- echo_agent/memory/contradiction.py +287 -0
- echo_agent/memory/forgetting.py +114 -0
- echo_agent/memory/retrieval.py +184 -0
- echo_agent/memory/reviewer.py +192 -0
- echo_agent/memory/store.py +706 -0
- echo_agent/memory/tiers.py +243 -0
- echo_agent/memory/types.py +168 -0
- echo_agent/memory/vectors.py +148 -0
- echo_agent/models/__init__.py +0 -0
- echo_agent/models/credential_pool.py +86 -0
- echo_agent/models/inference.py +98 -0
- echo_agent/models/provider.py +208 -0
- echo_agent/models/providers/__init__.py +209 -0
- echo_agent/models/providers/anthropic_provider.py +164 -0
- echo_agent/models/providers/bedrock_provider.py +261 -0
- echo_agent/models/providers/format_utils.py +198 -0
- echo_agent/models/providers/gemini_provider.py +159 -0
- echo_agent/models/providers/openai_provider.py +253 -0
- echo_agent/models/providers/openrouter_provider.py +38 -0
- echo_agent/models/rate_limiter.py +75 -0
- echo_agent/models/router.py +325 -0
- echo_agent/models/tokenizer.py +111 -0
- echo_agent/observability/__init__.py +0 -0
- echo_agent/observability/monitor.py +209 -0
- echo_agent/observability/spans.py +75 -0
- echo_agent/observability/telemetry.py +86 -0
- echo_agent/permissions/__init__.py +0 -0
- echo_agent/permissions/allowlist.py +97 -0
- echo_agent/permissions/manager.py +460 -0
- echo_agent/plugins/__init__.py +30 -0
- echo_agent/plugins/context.py +145 -0
- echo_agent/plugins/errors.py +23 -0
- echo_agent/plugins/hooks.py +126 -0
- echo_agent/plugins/loader.py +251 -0
- echo_agent/plugins/manager.py +216 -0
- echo_agent/plugins/manifest.py +70 -0
- echo_agent/runtime_paths.py +25 -0
- echo_agent/scheduler/__init__.py +0 -0
- echo_agent/scheduler/delivery.py +63 -0
- echo_agent/scheduler/service.py +398 -0
- echo_agent/security/__init__.py +11 -0
- echo_agent/security/capabilities.py +54 -0
- echo_agent/security/guards.py +265 -0
- echo_agent/security/path_policy.py +212 -0
- echo_agent/security/risk_classifier.py +75 -0
- echo_agent/security/smart_approval.py +60 -0
- echo_agent/security/tool_policy.py +159 -0
- echo_agent/session/__init__.py +0 -0
- echo_agent/session/manager.py +404 -0
- echo_agent/skills/__init__.py +0 -0
- echo_agent/skills/manager.py +279 -0
- echo_agent/skills/reviewer.py +163 -0
- echo_agent/skills/store.py +358 -0
- echo_agent/storage/__init__.py +0 -0
- echo_agent/storage/backend.py +111 -0
- echo_agent/storage/sqlite.py +523 -0
- echo_agent/tasks/__init__.py +20 -0
- echo_agent/tasks/manager.py +108 -0
- echo_agent/tasks/models.py +180 -0
- echo_agent/tasks/workflow.py +182 -0
- echo_agent/utils/__init__.py +0 -0
- echo_agent/utils/async_io.py +80 -0
- echo_agent/utils/text.py +91 -0
- echo_agent-0.1.0.dist-info/METADATA +286 -0
- echo_agent-0.1.0.dist-info/RECORD +219 -0
- echo_agent-0.1.0.dist-info/WHEEL +4 -0
- echo_agent-0.1.0.dist-info/entry_points.txt +2 -0
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: skill-creator
|
|
3
|
+
description: Create or update AgentSkills. Use when designing, structuring, or packaging skills with scripts, references, and assets.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Skill Creator
|
|
7
|
+
|
|
8
|
+
This skill provides guidance for creating effective skills.
|
|
9
|
+
|
|
10
|
+
## About Skills
|
|
11
|
+
|
|
12
|
+
Skills are modular, self-contained packages that extend the agent's capabilities by providing
|
|
13
|
+
specialized knowledge, workflows, and tools. Think of them as "onboarding guides" for specific
|
|
14
|
+
domains or tasks—they transform the agent from a general-purpose agent into a specialized agent
|
|
15
|
+
equipped with procedural knowledge that no model can fully possess.
|
|
16
|
+
|
|
17
|
+
### What Skills Provide
|
|
18
|
+
|
|
19
|
+
1. Specialized workflows - Multi-step procedures for specific domains
|
|
20
|
+
2. Tool integrations - Instructions for working with specific file formats or APIs
|
|
21
|
+
3. Domain expertise - Company-specific knowledge, schemas, business logic
|
|
22
|
+
4. Bundled resources - Scripts, references, and assets for complex and repetitive tasks
|
|
23
|
+
|
|
24
|
+
## Core Principles
|
|
25
|
+
|
|
26
|
+
### Concise is Key
|
|
27
|
+
|
|
28
|
+
The context window is a public good. Skills share the context window with everything else the agent needs: system prompt, conversation history, other Skills' metadata, and the actual user request.
|
|
29
|
+
|
|
30
|
+
**Default assumption: the agent is already very smart.** Only add context the agent doesn't already have. Challenge each piece of information: "Does the agent really need this explanation?" and "Does this paragraph justify its token cost?"
|
|
31
|
+
|
|
32
|
+
Prefer concise examples over verbose explanations.
|
|
33
|
+
|
|
34
|
+
### Set Appropriate Degrees of Freedom
|
|
35
|
+
|
|
36
|
+
Match the level of specificity to the task's fragility and variability:
|
|
37
|
+
|
|
38
|
+
**High freedom (text-based instructions)**: Use when multiple approaches are valid, decisions depend on context, or heuristics guide the approach.
|
|
39
|
+
|
|
40
|
+
**Medium freedom (pseudocode or scripts with parameters)**: Use when a preferred pattern exists, some variation is acceptable, or configuration affects behavior.
|
|
41
|
+
|
|
42
|
+
**Low freedom (specific scripts, few parameters)**: Use when operations are fragile and error-prone, consistency is critical, or a specific sequence must be followed.
|
|
43
|
+
|
|
44
|
+
### Anatomy of a Skill
|
|
45
|
+
|
|
46
|
+
Every skill consists of a required SKILL.md file and optional bundled resources:
|
|
47
|
+
|
|
48
|
+
```
|
|
49
|
+
skill-name/
|
|
50
|
+
├── SKILL.md (required)
|
|
51
|
+
│ ├── YAML frontmatter metadata (required)
|
|
52
|
+
│ │ ├── name: (required)
|
|
53
|
+
│ │ └── description: (required)
|
|
54
|
+
│ └── Markdown instructions (required)
|
|
55
|
+
└── Bundled Resources (optional)
|
|
56
|
+
├── scripts/ - Executable code (Python/Bash/etc.)
|
|
57
|
+
├── references/ - Documentation intended to be loaded into context as needed
|
|
58
|
+
└── assets/ - Files used in output (templates, icons, fonts, etc.)
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
#### SKILL.md (required)
|
|
62
|
+
|
|
63
|
+
Every SKILL.md consists of:
|
|
64
|
+
|
|
65
|
+
- **Frontmatter** (YAML): Contains `name` and `description` fields. These are the only fields that the agent reads to determine when the skill gets used, thus it is very important to be clear and comprehensive in describing what the skill is, and when it should be used.
|
|
66
|
+
- **Body** (Markdown): Instructions and guidance for using the skill. Only loaded AFTER the skill triggers (if at all).
|
|
67
|
+
|
|
68
|
+
#### Bundled Resources (optional)
|
|
69
|
+
|
|
70
|
+
##### Scripts (`scripts/`)
|
|
71
|
+
|
|
72
|
+
Executable code (Python/Bash/etc.) for tasks that require deterministic reliability or are repeatedly rewritten.
|
|
73
|
+
|
|
74
|
+
- **When to include**: When the same code is being rewritten repeatedly or deterministic reliability is needed
|
|
75
|
+
- **Example**: `scripts/rotate_pdf.py` for PDF rotation tasks
|
|
76
|
+
- **Benefits**: Token efficient, deterministic, may be executed without loading into context
|
|
77
|
+
|
|
78
|
+
##### References (`references/`)
|
|
79
|
+
|
|
80
|
+
Documentation and reference material intended to be loaded as needed into context.
|
|
81
|
+
|
|
82
|
+
- **When to include**: For documentation that the agent should reference while working
|
|
83
|
+
- **Examples**: `references/api_docs.md`, `references/policies.md`
|
|
84
|
+
- **Best practice**: If files are large (>10k words), include grep search patterns in SKILL.md
|
|
85
|
+
|
|
86
|
+
##### Assets (`assets/`)
|
|
87
|
+
|
|
88
|
+
Files not intended to be loaded into context, but rather used within the output the agent produces.
|
|
89
|
+
|
|
90
|
+
- **When to include**: When the skill needs files that will be used in the final output
|
|
91
|
+
- **Examples**: `assets/logo.png`, `assets/slides.pptx`, `assets/frontend-template/`
|
|
92
|
+
|
|
93
|
+
#### What to Not Include in a Skill
|
|
94
|
+
|
|
95
|
+
A skill should only contain essential files that directly support its functionality. Do NOT create extraneous documentation or auxiliary files, including:
|
|
96
|
+
|
|
97
|
+
- README.md
|
|
98
|
+
- INSTALLATION_GUIDE.md
|
|
99
|
+
- QUICK_REFERENCE.md
|
|
100
|
+
- CHANGELOG.md
|
|
101
|
+
|
|
102
|
+
The skill should only contain the information needed for an AI agent to do the job at hand.
|
|
103
|
+
|
|
104
|
+
### Progressive Disclosure Design Principle
|
|
105
|
+
|
|
106
|
+
Skills use a three-level loading system to manage context efficiently:
|
|
107
|
+
|
|
108
|
+
1. **Metadata (name + description)** - Always in context (~100 words)
|
|
109
|
+
2. **SKILL.md body** - When skill triggers (<5k words)
|
|
110
|
+
3. **Bundled resources** - As needed by the agent (Unlimited because scripts can be executed without reading into context window)
|
|
111
|
+
|
|
112
|
+
#### Progressive Disclosure Patterns
|
|
113
|
+
|
|
114
|
+
Keep SKILL.md body to the essentials and under 500 lines to minimize context bloat. Split content into separate files when approaching this limit.
|
|
115
|
+
|
|
116
|
+
**Pattern 1: High-level guide with references**
|
|
117
|
+
|
|
118
|
+
```markdown
|
|
119
|
+
# PDF Processing
|
|
120
|
+
|
|
121
|
+
## Quick start
|
|
122
|
+
Extract text with pdfplumber:
|
|
123
|
+
[code example]
|
|
124
|
+
|
|
125
|
+
## Advanced features
|
|
126
|
+
- **Form filling**: See [FORMS.md](FORMS.md) for complete guide
|
|
127
|
+
- **API reference**: See [REFERENCE.md](REFERENCE.md) for all methods
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
**Pattern 2: Domain-specific organization**
|
|
131
|
+
|
|
132
|
+
```
|
|
133
|
+
bigquery-skill/
|
|
134
|
+
├── SKILL.md (overview and navigation)
|
|
135
|
+
└── reference/
|
|
136
|
+
├── finance.md (revenue, billing metrics)
|
|
137
|
+
├── sales.md (opportunities, pipeline)
|
|
138
|
+
└── product.md (API usage, features)
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
**Pattern 3: Conditional details**
|
|
142
|
+
|
|
143
|
+
```markdown
|
|
144
|
+
# DOCX Processing
|
|
145
|
+
|
|
146
|
+
## Creating documents
|
|
147
|
+
Use docx-js for new documents. See [DOCX-JS.md](DOCX-JS.md).
|
|
148
|
+
|
|
149
|
+
## Editing documents
|
|
150
|
+
For simple edits, modify the XML directly.
|
|
151
|
+
**For tracked changes**: See [REDLINING.md](REDLINING.md)
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
**Important guidelines:**
|
|
155
|
+
- **Avoid deeply nested references** - Keep references one level deep from SKILL.md.
|
|
156
|
+
- **Structure longer reference files** - For files longer than 100 lines, include a table of contents at the top.
|
|
157
|
+
|
|
158
|
+
## Skill Creation Process
|
|
159
|
+
|
|
160
|
+
Skill creation involves these steps:
|
|
161
|
+
|
|
162
|
+
1. Understand the skill with concrete examples
|
|
163
|
+
2. Plan reusable skill contents (scripts, references, assets)
|
|
164
|
+
3. Initialize the skill (run init_skill.py)
|
|
165
|
+
4. Edit the skill (implement resources and write SKILL.md)
|
|
166
|
+
5. Package the skill (run package_skill.py)
|
|
167
|
+
6. Iterate based on real usage
|
|
168
|
+
|
|
169
|
+
Follow these steps in order, skipping only if there is a clear reason why they are not applicable.
|
|
170
|
+
|
|
171
|
+
### Skill Naming
|
|
172
|
+
|
|
173
|
+
- Use lowercase letters, digits, and hyphens only; normalize user-provided titles to hyphen-case (e.g., "Plan Mode" -> `plan-mode`).
|
|
174
|
+
- When generating names, generate a name under 64 characters (letters, digits, hyphens).
|
|
175
|
+
- Prefer short, verb-led phrases that describe the action.
|
|
176
|
+
- Name the skill folder exactly after the skill name.
|
|
177
|
+
|
|
178
|
+
### Step 1: Understanding the Skill with Concrete Examples
|
|
179
|
+
|
|
180
|
+
Skip this step only when the skill's usage patterns are already clearly understood.
|
|
181
|
+
|
|
182
|
+
To create an effective skill, clearly understand concrete examples of how the skill will be used. For example, when building an image-editor skill, relevant questions include:
|
|
183
|
+
|
|
184
|
+
- "What functionality should the image-editor skill support?"
|
|
185
|
+
- "Can you give some examples of how this skill would be used?"
|
|
186
|
+
- "What would a user say that should trigger this skill?"
|
|
187
|
+
|
|
188
|
+
To avoid overwhelming users, avoid asking too many questions at once. Prefer 1-2 targeted questions.
|
|
189
|
+
|
|
190
|
+
### Step 2: Planning Reusable Skill Contents
|
|
191
|
+
|
|
192
|
+
Before writing the skill, plan what resources it needs:
|
|
193
|
+
|
|
194
|
+
- **Scripts**: For deterministic operations that need consistency
|
|
195
|
+
- **References**: For detailed documentation the agent should reference
|
|
196
|
+
- **Assets**: For files used in output (templates, images, etc.)
|
|
197
|
+
|
|
198
|
+
### Step 3: Initializing a Skill
|
|
199
|
+
|
|
200
|
+
Use the bundled initialization script:
|
|
201
|
+
|
|
202
|
+
```bash
|
|
203
|
+
scripts/init_skill.py <skill-name> --path <output-path>
|
|
204
|
+
scripts/init_skill.py <skill-name> --path <output-path> --resources scripts,references
|
|
205
|
+
scripts/init_skill.py <skill-name> --path <output-path> --resources scripts --examples
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
This creates a skill directory with a SKILL.md template and optional resource directories.
|
|
209
|
+
|
|
210
|
+
### Step 4: Editing the Skill
|
|
211
|
+
|
|
212
|
+
#### Frontmatter
|
|
213
|
+
|
|
214
|
+
Required fields:
|
|
215
|
+
|
|
216
|
+
```yaml
|
|
217
|
+
---
|
|
218
|
+
name: my-skill-name
|
|
219
|
+
description: >-
|
|
220
|
+
Clear description of what this skill does and when to use it.
|
|
221
|
+
Include trigger scenarios, file types, or tasks that should activate this skill.
|
|
222
|
+
Example: "Process and manipulate PDF files including merging, splitting, extracting text,
|
|
223
|
+
filling forms, or any other document tasks"
|
|
224
|
+
---
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
Keep frontmatter minimal. `metadata` and `always` are also supported when needed, but avoid adding extra fields unless they are actually required.
|
|
228
|
+
|
|
229
|
+
#### Body
|
|
230
|
+
|
|
231
|
+
Write instructions for using the skill and its bundled resources.
|
|
232
|
+
|
|
233
|
+
### Step 5: Packaging a Skill
|
|
234
|
+
|
|
235
|
+
Once development of the skill is complete, it must be packaged into a distributable .skill file. The packaging process automatically validates the skill first:
|
|
236
|
+
|
|
237
|
+
```bash
|
|
238
|
+
scripts/package_skill.py <path/to/skill-folder>
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
Optional output directory specification:
|
|
242
|
+
|
|
243
|
+
```bash
|
|
244
|
+
scripts/package_skill.py <path/to/skill-folder> ./dist
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
The packaging script will:
|
|
248
|
+
|
|
249
|
+
1. **Validate** the skill automatically, checking:
|
|
250
|
+
- YAML frontmatter format and required fields
|
|
251
|
+
- Skill naming conventions and directory structure
|
|
252
|
+
- Description completeness and quality
|
|
253
|
+
- File organization and resource references
|
|
254
|
+
|
|
255
|
+
2. **Package** the skill if validation passes, creating a .skill file named after the skill (e.g., `my-skill.skill`) that includes all files and maintains the proper directory structure for distribution. The .skill file is a zip file with a .skill extension.
|
|
256
|
+
|
|
257
|
+
Security restriction: symlinks are rejected and packaging fails when any symlink is present.
|
|
258
|
+
|
|
259
|
+
If validation fails, the script will report the errors and exit without creating a package. Fix any validation errors and run the packaging command again.
|
|
260
|
+
|
|
261
|
+
### Step 6: Iterate
|
|
262
|
+
|
|
263
|
+
After testing the skill, users may request improvements. Often this happens right after using the skill, with fresh context of how the skill performed.
|
|
264
|
+
|
|
265
|
+
**Iteration workflow:**
|
|
266
|
+
|
|
267
|
+
1. Use the skill on real tasks
|
|
268
|
+
2. Notice struggles or inefficiencies
|
|
269
|
+
3. Identify how SKILL.md or bundled resources should be updated
|
|
270
|
+
4. Implement changes and test again
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Skill Initializer - Creates a new skill from template
|
|
4
|
+
|
|
5
|
+
Usage:
|
|
6
|
+
init_skill.py <skill-name> --path <path> [--resources scripts,references,assets] [--examples]
|
|
7
|
+
|
|
8
|
+
Examples:
|
|
9
|
+
init_skill.py my-new-skill --path skills/public
|
|
10
|
+
init_skill.py my-new-skill --path skills/public --resources scripts,references
|
|
11
|
+
init_skill.py my-api-helper --path skills/private --resources scripts --examples
|
|
12
|
+
init_skill.py custom-skill --path /custom/location
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
import argparse
|
|
16
|
+
import re
|
|
17
|
+
import sys
|
|
18
|
+
from pathlib import Path
|
|
19
|
+
|
|
20
|
+
MAX_SKILL_NAME_LENGTH = 64
|
|
21
|
+
ALLOWED_RESOURCES = {"scripts", "references", "assets"}
|
|
22
|
+
|
|
23
|
+
SKILL_TEMPLATE = """---
|
|
24
|
+
name: {skill_name}
|
|
25
|
+
description: "Complete this description with what the skill does and when to use it. Include the trigger scenarios, file types, or tasks that should activate this skill."
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
# {skill_title}
|
|
29
|
+
|
|
30
|
+
## Overview
|
|
31
|
+
|
|
32
|
+
[Write 1-2 sentences explaining what this skill enables.]
|
|
33
|
+
|
|
34
|
+
## Structuring This Skill
|
|
35
|
+
|
|
36
|
+
[Choose the structure that best fits this skill's purpose. Common patterns:
|
|
37
|
+
|
|
38
|
+
**1. Workflow-Based** (best for sequential processes)
|
|
39
|
+
- Structure: ## Overview -> ## Workflow Decision Tree -> ## Step 1 -> ## Step 2...
|
|
40
|
+
|
|
41
|
+
**2. Task-Based** (best for tool collections)
|
|
42
|
+
- Structure: ## Overview -> ## Quick Start -> ## Task Category 1 -> ## Task Category 2...
|
|
43
|
+
|
|
44
|
+
**3. Reference/Guidelines** (best for standards or specifications)
|
|
45
|
+
- Structure: ## Overview -> ## Guidelines -> ## Specifications -> ## Usage...
|
|
46
|
+
|
|
47
|
+
**4. Capabilities-Based** (best for integrated systems)
|
|
48
|
+
- Structure: ## Overview -> ## Core Capabilities -> ### 1. Feature -> ### 2. Feature...
|
|
49
|
+
|
|
50
|
+
Delete this entire "Structuring This Skill" section when done - it's just guidance.]
|
|
51
|
+
|
|
52
|
+
## [Replace with the first main section based on the chosen structure]
|
|
53
|
+
|
|
54
|
+
[Add content here.]
|
|
55
|
+
|
|
56
|
+
## Resources (optional)
|
|
57
|
+
|
|
58
|
+
Create only the resource directories this skill actually needs. Delete this section if no resources are required.
|
|
59
|
+
|
|
60
|
+
### scripts/
|
|
61
|
+
Executable code (Python/Bash/etc.) that can be run directly to perform specific operations.
|
|
62
|
+
|
|
63
|
+
### references/
|
|
64
|
+
Documentation and reference material intended to be loaded into context to inform the agent's process and thinking.
|
|
65
|
+
|
|
66
|
+
### assets/
|
|
67
|
+
Files not intended to be loaded into context, but rather used within the output the agent produces.
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
**Not every skill requires all three types of resources.**
|
|
72
|
+
"""
|
|
73
|
+
|
|
74
|
+
EXAMPLE_SCRIPT = '''#!/usr/bin/env python3
|
|
75
|
+
"""
|
|
76
|
+
Example helper script for {skill_name}
|
|
77
|
+
|
|
78
|
+
Replace with actual implementation or delete if not needed.
|
|
79
|
+
"""
|
|
80
|
+
|
|
81
|
+
def main():
|
|
82
|
+
print("This is an example script for {skill_name}")
|
|
83
|
+
|
|
84
|
+
if __name__ == "__main__":
|
|
85
|
+
main()
|
|
86
|
+
'''
|
|
87
|
+
|
|
88
|
+
EXAMPLE_REFERENCE = """# Reference Documentation for {skill_title}
|
|
89
|
+
|
|
90
|
+
This is a placeholder for detailed reference documentation.
|
|
91
|
+
Replace with actual reference content or delete if not needed.
|
|
92
|
+
|
|
93
|
+
## When to Load This Reference
|
|
94
|
+
|
|
95
|
+
The agent should load this reference when:
|
|
96
|
+
- [Describe specific scenarios]
|
|
97
|
+
"""
|
|
98
|
+
|
|
99
|
+
EXAMPLE_ASSET_README = """# Assets for {skill_title}
|
|
100
|
+
|
|
101
|
+
Place files here that should be used in the agent's output (templates, images, fonts, etc.).
|
|
102
|
+
These files are NOT loaded into context — they are used directly in output.
|
|
103
|
+
"""
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def normalize_skill_name(raw_name: str) -> str:
|
|
107
|
+
name = raw_name.strip().lower()
|
|
108
|
+
name = re.sub(r"[^a-z0-9]+", "-", name)
|
|
109
|
+
name = name.strip("-")
|
|
110
|
+
return name
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def parse_resources(resources_str: str) -> list[str]:
|
|
114
|
+
if not resources_str.strip():
|
|
115
|
+
return []
|
|
116
|
+
resources = [r.strip().lower() for r in resources_str.split(",") if r.strip()]
|
|
117
|
+
invalid = [r for r in resources if r not in ALLOWED_RESOURCES]
|
|
118
|
+
if invalid:
|
|
119
|
+
print(f"[ERROR] Invalid resource types: {', '.join(invalid)}")
|
|
120
|
+
print(f" Allowed: {', '.join(sorted(ALLOWED_RESOURCES))}")
|
|
121
|
+
sys.exit(1)
|
|
122
|
+
return resources
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def init_skill(skill_name: str, base_path: str, resources: list[str], examples: bool = False) -> bool:
|
|
126
|
+
skill_title = skill_name.replace("-", " ").title()
|
|
127
|
+
skill_path = Path(base_path) / skill_name
|
|
128
|
+
|
|
129
|
+
if skill_path.exists():
|
|
130
|
+
print(f"[ERROR] Directory already exists: {skill_path}")
|
|
131
|
+
return False
|
|
132
|
+
|
|
133
|
+
skill_path.mkdir(parents=True, exist_ok=True)
|
|
134
|
+
|
|
135
|
+
skill_md = SKILL_TEMPLATE.format(skill_name=skill_name, skill_title=skill_title)
|
|
136
|
+
(skill_path / "SKILL.md").write_text(skill_md, encoding="utf-8")
|
|
137
|
+
print(f" Created: {skill_path / 'SKILL.md'}")
|
|
138
|
+
|
|
139
|
+
for resource in resources:
|
|
140
|
+
resource_dir = skill_path / resource
|
|
141
|
+
resource_dir.mkdir(exist_ok=True)
|
|
142
|
+
print(f" Created: {resource_dir}/")
|
|
143
|
+
|
|
144
|
+
if examples:
|
|
145
|
+
if resource == "scripts":
|
|
146
|
+
example_file = resource_dir / f"example_{skill_name.replace('-', '_')}.py"
|
|
147
|
+
example_file.write_text(
|
|
148
|
+
EXAMPLE_SCRIPT.format(skill_name=skill_name), encoding="utf-8"
|
|
149
|
+
)
|
|
150
|
+
print(f" Created: {example_file}")
|
|
151
|
+
elif resource == "references":
|
|
152
|
+
example_file = resource_dir / "README.md"
|
|
153
|
+
example_file.write_text(
|
|
154
|
+
EXAMPLE_REFERENCE.format(skill_title=skill_title), encoding="utf-8"
|
|
155
|
+
)
|
|
156
|
+
print(f" Created: {example_file}")
|
|
157
|
+
elif resource == "assets":
|
|
158
|
+
example_file = resource_dir / "README.md"
|
|
159
|
+
example_file.write_text(
|
|
160
|
+
EXAMPLE_ASSET_README.format(skill_title=skill_title), encoding="utf-8"
|
|
161
|
+
)
|
|
162
|
+
print(f" Created: {example_file}")
|
|
163
|
+
|
|
164
|
+
print(f"\n[OK] Skill '{skill_name}' initialized at: {skill_path}")
|
|
165
|
+
return True
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
def main():
|
|
169
|
+
parser = argparse.ArgumentParser(
|
|
170
|
+
description="Initialize a new skill directory with a SKILL.md template.",
|
|
171
|
+
)
|
|
172
|
+
parser.add_argument("skill_name", help="Skill name (normalized to hyphen-case)")
|
|
173
|
+
parser.add_argument("--path", required=True, help="Output directory for the skill")
|
|
174
|
+
parser.add_argument(
|
|
175
|
+
"--resources",
|
|
176
|
+
default="",
|
|
177
|
+
help="Comma-separated list: scripts,references,assets",
|
|
178
|
+
)
|
|
179
|
+
parser.add_argument(
|
|
180
|
+
"--examples",
|
|
181
|
+
action="store_true",
|
|
182
|
+
help="Create example files inside the selected resource directories",
|
|
183
|
+
)
|
|
184
|
+
args = parser.parse_args()
|
|
185
|
+
|
|
186
|
+
raw_skill_name = args.skill_name
|
|
187
|
+
skill_name = normalize_skill_name(raw_skill_name)
|
|
188
|
+
if not skill_name:
|
|
189
|
+
print("[ERROR] Skill name must include at least one letter or digit.")
|
|
190
|
+
sys.exit(1)
|
|
191
|
+
if len(skill_name) > MAX_SKILL_NAME_LENGTH:
|
|
192
|
+
print(
|
|
193
|
+
f"[ERROR] Skill name '{skill_name}' is too long ({len(skill_name)} characters). "
|
|
194
|
+
f"Maximum is {MAX_SKILL_NAME_LENGTH} characters."
|
|
195
|
+
)
|
|
196
|
+
sys.exit(1)
|
|
197
|
+
if skill_name != raw_skill_name:
|
|
198
|
+
print(f"Note: Normalized skill name from '{raw_skill_name}' to '{skill_name}'.")
|
|
199
|
+
|
|
200
|
+
resources = parse_resources(args.resources)
|
|
201
|
+
if args.examples and not resources:
|
|
202
|
+
print("[ERROR] --examples requires --resources to be set.")
|
|
203
|
+
sys.exit(1)
|
|
204
|
+
|
|
205
|
+
path = args.path
|
|
206
|
+
|
|
207
|
+
print(f"Initializing skill: {skill_name}")
|
|
208
|
+
print(f" Location: {path}")
|
|
209
|
+
if resources:
|
|
210
|
+
print(f" Resources: {', '.join(resources)}")
|
|
211
|
+
if args.examples:
|
|
212
|
+
print(" Examples: enabled")
|
|
213
|
+
else:
|
|
214
|
+
print(" Resources: none (create as needed)")
|
|
215
|
+
print()
|
|
216
|
+
|
|
217
|
+
result = init_skill(skill_name, path, resources, args.examples)
|
|
218
|
+
|
|
219
|
+
if result:
|
|
220
|
+
sys.exit(0)
|
|
221
|
+
else:
|
|
222
|
+
sys.exit(1)
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
if __name__ == "__main__":
|
|
226
|
+
main()
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Skill Packager - Creates a distributable .skill file of a skill folder
|
|
4
|
+
|
|
5
|
+
Usage:
|
|
6
|
+
python package_skill.py <path/to/skill-folder> [output-directory]
|
|
7
|
+
|
|
8
|
+
Example:
|
|
9
|
+
python package_skill.py skills/public/my-skill
|
|
10
|
+
python package_skill.py skills/public/my-skill ./dist
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
import sys
|
|
14
|
+
import zipfile
|
|
15
|
+
from pathlib import Path
|
|
16
|
+
|
|
17
|
+
from quick_validate import validate_skill
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def _is_within(path: Path, root: Path) -> bool:
|
|
21
|
+
try:
|
|
22
|
+
path.relative_to(root)
|
|
23
|
+
return True
|
|
24
|
+
except ValueError:
|
|
25
|
+
return False
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def _cleanup_partial_archive(skill_filename: Path) -> None:
|
|
29
|
+
try:
|
|
30
|
+
if skill_filename.exists():
|
|
31
|
+
skill_filename.unlink()
|
|
32
|
+
except OSError:
|
|
33
|
+
return None
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def package_skill(skill_path, output_dir=None):
|
|
37
|
+
"""
|
|
38
|
+
Package a skill folder into a .skill file.
|
|
39
|
+
|
|
40
|
+
Args:
|
|
41
|
+
skill_path: Path to the skill folder
|
|
42
|
+
output_dir: Optional output directory for the .skill file
|
|
43
|
+
|
|
44
|
+
Returns:
|
|
45
|
+
Path to the created .skill file, or None if error
|
|
46
|
+
"""
|
|
47
|
+
skill_path = Path(skill_path).resolve()
|
|
48
|
+
|
|
49
|
+
if not skill_path.exists():
|
|
50
|
+
print(f"[ERROR] Skill folder not found: {skill_path}")
|
|
51
|
+
return None
|
|
52
|
+
|
|
53
|
+
if not skill_path.is_dir():
|
|
54
|
+
print(f"[ERROR] Path is not a directory: {skill_path}")
|
|
55
|
+
return None
|
|
56
|
+
|
|
57
|
+
skill_md = skill_path / "SKILL.md"
|
|
58
|
+
if not skill_md.exists():
|
|
59
|
+
print(f"[ERROR] SKILL.md not found in {skill_path}")
|
|
60
|
+
return None
|
|
61
|
+
|
|
62
|
+
print("Validating skill...")
|
|
63
|
+
valid, message = validate_skill(skill_path)
|
|
64
|
+
if not valid:
|
|
65
|
+
print(f"[ERROR] Validation failed: {message}")
|
|
66
|
+
print(" Please fix the validation errors before packaging.")
|
|
67
|
+
return None
|
|
68
|
+
print(f"[OK] {message}\n")
|
|
69
|
+
|
|
70
|
+
skill_name = skill_path.name
|
|
71
|
+
if output_dir:
|
|
72
|
+
output_path = Path(output_dir).resolve()
|
|
73
|
+
output_path.mkdir(parents=True, exist_ok=True)
|
|
74
|
+
else:
|
|
75
|
+
output_path = Path.cwd()
|
|
76
|
+
|
|
77
|
+
skill_filename = output_path / f"{skill_name}.skill"
|
|
78
|
+
|
|
79
|
+
EXCLUDED_DIRS = {".git", ".svn", ".hg", "__pycache__", "node_modules"}
|
|
80
|
+
|
|
81
|
+
files_to_package = []
|
|
82
|
+
resolved_archive = skill_filename.resolve()
|
|
83
|
+
|
|
84
|
+
for file_path in skill_path.rglob("*"):
|
|
85
|
+
if file_path.is_symlink():
|
|
86
|
+
print(f"[ERROR] Symlink not allowed in packaged skill: {file_path}")
|
|
87
|
+
_cleanup_partial_archive(skill_filename)
|
|
88
|
+
return None
|
|
89
|
+
|
|
90
|
+
rel_parts = file_path.relative_to(skill_path).parts
|
|
91
|
+
if any(part in EXCLUDED_DIRS for part in rel_parts):
|
|
92
|
+
continue
|
|
93
|
+
|
|
94
|
+
if file_path.is_file():
|
|
95
|
+
resolved_file = file_path.resolve()
|
|
96
|
+
if not _is_within(resolved_file, skill_path):
|
|
97
|
+
print(f"[ERROR] File escapes skill root: {file_path}")
|
|
98
|
+
_cleanup_partial_archive(skill_filename)
|
|
99
|
+
return None
|
|
100
|
+
if resolved_file == resolved_archive:
|
|
101
|
+
print(f"[WARN] Skipping output archive: {file_path}")
|
|
102
|
+
continue
|
|
103
|
+
files_to_package.append(file_path)
|
|
104
|
+
|
|
105
|
+
try:
|
|
106
|
+
with zipfile.ZipFile(skill_filename, "w", zipfile.ZIP_DEFLATED) as zipf:
|
|
107
|
+
for file_path in files_to_package:
|
|
108
|
+
arcname = Path(skill_name) / file_path.relative_to(skill_path)
|
|
109
|
+
zipf.write(file_path, arcname)
|
|
110
|
+
print(f" Added: {arcname}")
|
|
111
|
+
|
|
112
|
+
print(f"\n[OK] Successfully packaged skill to: {skill_filename}")
|
|
113
|
+
return skill_filename
|
|
114
|
+
|
|
115
|
+
except Exception as e:
|
|
116
|
+
_cleanup_partial_archive(skill_filename)
|
|
117
|
+
print(f"[ERROR] Error creating .skill file: {e}")
|
|
118
|
+
return None
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def main():
|
|
122
|
+
if len(sys.argv) < 2:
|
|
123
|
+
print("Usage: python package_skill.py <path/to/skill-folder> [output-directory]")
|
|
124
|
+
print("\nExample:")
|
|
125
|
+
print(" python package_skill.py skills/public/my-skill")
|
|
126
|
+
print(" python package_skill.py skills/public/my-skill ./dist")
|
|
127
|
+
sys.exit(1)
|
|
128
|
+
|
|
129
|
+
skill_path = sys.argv[1]
|
|
130
|
+
output_dir = sys.argv[2] if len(sys.argv) > 2 else None
|
|
131
|
+
|
|
132
|
+
print(f"Packaging skill: {skill_path}")
|
|
133
|
+
if output_dir:
|
|
134
|
+
print(f" Output directory: {output_dir}")
|
|
135
|
+
print()
|
|
136
|
+
|
|
137
|
+
result = package_skill(skill_path, output_dir)
|
|
138
|
+
|
|
139
|
+
if result:
|
|
140
|
+
sys.exit(0)
|
|
141
|
+
else:
|
|
142
|
+
sys.exit(1)
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
if __name__ == "__main__":
|
|
146
|
+
main()
|