Compare commits
2 Commits
fe2bc3dfd3
...
f08bf85b37
| Author | SHA1 | Date | |
|---|---|---|---|
| f08bf85b37 | |||
| 2558d6dae1 |
80
resources/skills/himalaya/SKILL.md
Normal file
80
resources/skills/himalaya/SKILL.md
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
---
|
||||||
|
name: himalaya
|
||||||
|
description: "Himalaya CLI for IMAP/SMTP mail: list, read, search, compose, reply, forward, copy, move, delete."
|
||||||
|
homepage: https://github.com/pimalaya/himalaya
|
||||||
|
metadata:
|
||||||
|
{
|
||||||
|
"openclaw":
|
||||||
|
{
|
||||||
|
"emoji": "📧",
|
||||||
|
"requires": { "bins": ["himalaya"] },
|
||||||
|
"install":
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"id": "brew",
|
||||||
|
"kind": "brew",
|
||||||
|
"formula": "himalaya",
|
||||||
|
"bins": ["himalaya"],
|
||||||
|
"label": "Install Himalaya (brew)",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
---
|
||||||
|
|
||||||
|
# Himalaya
|
||||||
|
|
||||||
|
Use `himalaya` for IMAP/SMTP email from shell.
|
||||||
|
|
||||||
|
## References
|
||||||
|
|
||||||
|
- `references/configuration.md`: account config, auth, backend setup.
|
||||||
|
- `references/message-composition.md`: MML compose syntax.
|
||||||
|
|
||||||
|
## Setup
|
||||||
|
|
||||||
|
```bash
|
||||||
|
himalaya --version
|
||||||
|
himalaya account configure
|
||||||
|
```
|
||||||
|
|
||||||
|
Config path: `~/.config/himalaya/config.toml`.
|
||||||
|
|
||||||
|
Prefer password managers/keyrings for credentials; do not paste secrets into chat/logs.
|
||||||
|
|
||||||
|
## Read/search
|
||||||
|
|
||||||
|
```bash
|
||||||
|
himalaya folder list
|
||||||
|
himalaya envelope list
|
||||||
|
himalaya message read <id>
|
||||||
|
himalaya envelope list from alice@example.com subject invoice
|
||||||
|
```
|
||||||
|
|
||||||
|
## Write
|
||||||
|
|
||||||
|
```bash
|
||||||
|
himalaya message write
|
||||||
|
himalaya template write
|
||||||
|
himalaya template send < /tmp/message.txt
|
||||||
|
himalaya message reply <id>
|
||||||
|
himalaya message forward <id>
|
||||||
|
```
|
||||||
|
|
||||||
|
Use MML for attachments and rich messages; read `references/message-composition.md` first.
|
||||||
|
|
||||||
|
## Organize
|
||||||
|
|
||||||
|
```bash
|
||||||
|
himalaya message copy <id> <folder>
|
||||||
|
himalaya message move <id> <folder>
|
||||||
|
himalaya message delete <id>
|
||||||
|
himalaya flag add <id> --flag seen
|
||||||
|
himalaya flag remove <id> --flag seen
|
||||||
|
```
|
||||||
|
|
||||||
|
## Safety
|
||||||
|
|
||||||
|
- Confirm before sending, deleting, or moving many messages.
|
||||||
|
- Use `--account` when multiple accounts exist.
|
||||||
|
- Quote exact message IDs in summaries.
|
||||||
184
resources/skills/himalaya/references/configuration.md
Normal file
184
resources/skills/himalaya/references/configuration.md
Normal file
@ -0,0 +1,184 @@
|
|||||||
|
# Himalaya Configuration Reference
|
||||||
|
|
||||||
|
Configuration file location: `~/.config/himalaya/config.toml`
|
||||||
|
|
||||||
|
## Minimal IMAP + SMTP Setup
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[accounts.default]
|
||||||
|
email = "user@example.com"
|
||||||
|
display-name = "Your Name"
|
||||||
|
default = true
|
||||||
|
|
||||||
|
# IMAP backend for reading emails
|
||||||
|
backend.type = "imap"
|
||||||
|
backend.host = "imap.example.com"
|
||||||
|
backend.port = 993
|
||||||
|
backend.encryption.type = "tls"
|
||||||
|
backend.login = "user@example.com"
|
||||||
|
backend.auth.type = "password"
|
||||||
|
backend.auth.raw = "your-password"
|
||||||
|
|
||||||
|
# SMTP backend for sending emails
|
||||||
|
message.send.backend.type = "smtp"
|
||||||
|
message.send.backend.host = "smtp.example.com"
|
||||||
|
message.send.backend.port = 587
|
||||||
|
message.send.backend.encryption.type = "start-tls"
|
||||||
|
message.send.backend.login = "user@example.com"
|
||||||
|
message.send.backend.auth.type = "password"
|
||||||
|
message.send.backend.auth.raw = "your-password"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Password Options
|
||||||
|
|
||||||
|
### Raw password (testing only, not recommended)
|
||||||
|
|
||||||
|
```toml
|
||||||
|
backend.auth.raw = "your-password"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Password from command (recommended)
|
||||||
|
|
||||||
|
```toml
|
||||||
|
backend.auth.cmd = "pass show email/imap"
|
||||||
|
# backend.auth.cmd = "security find-generic-password -a user@example.com -s imap -w"
|
||||||
|
```
|
||||||
|
|
||||||
|
### System keyring (requires keyring feature)
|
||||||
|
|
||||||
|
```toml
|
||||||
|
backend.auth.keyring = "imap-example"
|
||||||
|
```
|
||||||
|
|
||||||
|
Then run `himalaya account configure <account>` to store the password.
|
||||||
|
|
||||||
|
## Gmail Configuration
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[accounts.gmail]
|
||||||
|
email = "you@gmail.com"
|
||||||
|
display-name = "Your Name"
|
||||||
|
default = true
|
||||||
|
|
||||||
|
backend.type = "imap"
|
||||||
|
backend.host = "imap.gmail.com"
|
||||||
|
backend.port = 993
|
||||||
|
backend.encryption.type = "tls"
|
||||||
|
backend.login = "you@gmail.com"
|
||||||
|
backend.auth.type = "password"
|
||||||
|
backend.auth.cmd = "pass show google/app-password"
|
||||||
|
|
||||||
|
message.send.backend.type = "smtp"
|
||||||
|
message.send.backend.host = "smtp.gmail.com"
|
||||||
|
message.send.backend.port = 587
|
||||||
|
message.send.backend.encryption.type = "start-tls"
|
||||||
|
message.send.backend.login = "you@gmail.com"
|
||||||
|
message.send.backend.auth.type = "password"
|
||||||
|
message.send.backend.auth.cmd = "pass show google/app-password"
|
||||||
|
```
|
||||||
|
|
||||||
|
**Note:** Gmail requires an App Password if 2FA is enabled.
|
||||||
|
|
||||||
|
## iCloud Configuration
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[accounts.icloud]
|
||||||
|
email = "you@icloud.com"
|
||||||
|
display-name = "Your Name"
|
||||||
|
|
||||||
|
backend.type = "imap"
|
||||||
|
backend.host = "imap.mail.me.com"
|
||||||
|
backend.port = 993
|
||||||
|
backend.encryption.type = "tls"
|
||||||
|
backend.login = "you@icloud.com"
|
||||||
|
backend.auth.type = "password"
|
||||||
|
backend.auth.cmd = "pass show icloud/app-password"
|
||||||
|
|
||||||
|
message.send.backend.type = "smtp"
|
||||||
|
message.send.backend.host = "smtp.mail.me.com"
|
||||||
|
message.send.backend.port = 587
|
||||||
|
message.send.backend.encryption.type = "start-tls"
|
||||||
|
message.send.backend.login = "you@icloud.com"
|
||||||
|
message.send.backend.auth.type = "password"
|
||||||
|
message.send.backend.auth.cmd = "pass show icloud/app-password"
|
||||||
|
```
|
||||||
|
|
||||||
|
**Note:** Generate an app-specific password at appleid.apple.com
|
||||||
|
|
||||||
|
## Folder Aliases
|
||||||
|
|
||||||
|
Map custom folder names:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[accounts.default.folder.alias]
|
||||||
|
inbox = "INBOX"
|
||||||
|
sent = "Sent"
|
||||||
|
drafts = "Drafts"
|
||||||
|
trash = "Trash"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Multiple Accounts
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[accounts.personal]
|
||||||
|
email = "personal@example.com"
|
||||||
|
default = true
|
||||||
|
# ... backend config ...
|
||||||
|
|
||||||
|
[accounts.work]
|
||||||
|
email = "work@company.com"
|
||||||
|
# ... backend config ...
|
||||||
|
```
|
||||||
|
|
||||||
|
Switch accounts with `--account`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
himalaya --account work envelope list
|
||||||
|
```
|
||||||
|
|
||||||
|
## Notmuch Backend (local mail)
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[accounts.local]
|
||||||
|
email = "user@example.com"
|
||||||
|
|
||||||
|
backend.type = "notmuch"
|
||||||
|
backend.db-path = "~/.mail/.notmuch"
|
||||||
|
```
|
||||||
|
|
||||||
|
## OAuth2 Authentication (for providers that support it)
|
||||||
|
|
||||||
|
```toml
|
||||||
|
backend.auth.type = "oauth2"
|
||||||
|
backend.auth.client-id = "your-client-id"
|
||||||
|
backend.auth.client-secret.cmd = "pass show oauth/client-secret"
|
||||||
|
backend.auth.access-token.cmd = "pass show oauth/access-token"
|
||||||
|
backend.auth.refresh-token.cmd = "pass show oauth/refresh-token"
|
||||||
|
backend.auth.auth-url = "https://provider.com/oauth/authorize"
|
||||||
|
backend.auth.token-url = "https://provider.com/oauth/token"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Additional Options
|
||||||
|
|
||||||
|
### Signature
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[accounts.default]
|
||||||
|
signature = "Best regards,\nYour Name"
|
||||||
|
signature-delim = "-- \n"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Downloads directory
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[accounts.default]
|
||||||
|
downloads-dir = "~/Downloads/himalaya"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Editor for composing
|
||||||
|
|
||||||
|
Set via environment variable:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
export EDITOR="vim"
|
||||||
|
```
|
||||||
199
resources/skills/himalaya/references/message-composition.md
Normal file
199
resources/skills/himalaya/references/message-composition.md
Normal file
@ -0,0 +1,199 @@
|
|||||||
|
# Message Composition with MML (MIME Meta Language)
|
||||||
|
|
||||||
|
Himalaya uses MML for composing emails. MML is a simple XML-based syntax that compiles to MIME messages.
|
||||||
|
|
||||||
|
## Basic Message Structure
|
||||||
|
|
||||||
|
An email message is a list of **headers** followed by a **body**, separated by a blank line:
|
||||||
|
|
||||||
|
```
|
||||||
|
From: sender@example.com
|
||||||
|
To: recipient@example.com
|
||||||
|
Subject: Hello World
|
||||||
|
|
||||||
|
This is the message body.
|
||||||
|
```
|
||||||
|
|
||||||
|
## Headers
|
||||||
|
|
||||||
|
Common headers:
|
||||||
|
|
||||||
|
- `From`: Sender address
|
||||||
|
- `To`: Primary recipient(s)
|
||||||
|
- `Cc`: Carbon copy recipients
|
||||||
|
- `Bcc`: Blind carbon copy recipients
|
||||||
|
- `Subject`: Message subject
|
||||||
|
- `Reply-To`: Address for replies (if different from From)
|
||||||
|
- `In-Reply-To`: Message ID being replied to
|
||||||
|
|
||||||
|
### Address Formats
|
||||||
|
|
||||||
|
```
|
||||||
|
To: user@example.com
|
||||||
|
To: John Doe <john@example.com>
|
||||||
|
To: "John Doe" <john@example.com>
|
||||||
|
To: user1@example.com, user2@example.com, "Jane" <jane@example.com>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Plain Text Body
|
||||||
|
|
||||||
|
Simple plain text email:
|
||||||
|
|
||||||
|
```
|
||||||
|
From: alice@localhost
|
||||||
|
To: bob@localhost
|
||||||
|
Subject: Plain Text Example
|
||||||
|
|
||||||
|
Hello, this is a plain text email.
|
||||||
|
No special formatting needed.
|
||||||
|
|
||||||
|
Best,
|
||||||
|
Alice
|
||||||
|
```
|
||||||
|
|
||||||
|
## MML for Rich Emails
|
||||||
|
|
||||||
|
### Multipart Messages
|
||||||
|
|
||||||
|
Alternative text/html parts:
|
||||||
|
|
||||||
|
```
|
||||||
|
From: alice@localhost
|
||||||
|
To: bob@localhost
|
||||||
|
Subject: Multipart Example
|
||||||
|
|
||||||
|
<#multipart type=alternative>
|
||||||
|
This is the plain text version.
|
||||||
|
<#part type=text/html>
|
||||||
|
<html><body><h1>This is the HTML version</h1></body></html>
|
||||||
|
<#/multipart>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Attachments
|
||||||
|
|
||||||
|
Attach a file:
|
||||||
|
|
||||||
|
```
|
||||||
|
From: alice@localhost
|
||||||
|
To: bob@localhost
|
||||||
|
Subject: With Attachment
|
||||||
|
|
||||||
|
Here is the document you requested.
|
||||||
|
|
||||||
|
<#part filename=/path/to/document.pdf><#/part>
|
||||||
|
```
|
||||||
|
|
||||||
|
Attachment with custom name:
|
||||||
|
|
||||||
|
```
|
||||||
|
<#part filename=/path/to/file.pdf name=report.pdf><#/part>
|
||||||
|
```
|
||||||
|
|
||||||
|
Multiple attachments:
|
||||||
|
|
||||||
|
```
|
||||||
|
<#part filename=/path/to/doc1.pdf><#/part>
|
||||||
|
<#part filename=/path/to/doc2.pdf><#/part>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Inline Images
|
||||||
|
|
||||||
|
Embed an image inline:
|
||||||
|
|
||||||
|
```
|
||||||
|
From: alice@localhost
|
||||||
|
To: bob@localhost
|
||||||
|
Subject: Inline Image
|
||||||
|
|
||||||
|
<#multipart type=related>
|
||||||
|
<#part type=text/html>
|
||||||
|
<html><body>
|
||||||
|
<p>Check out this image:</p>
|
||||||
|
<img src="cid:image1">
|
||||||
|
</body></html>
|
||||||
|
<#part disposition=inline id=image1 filename=/path/to/image.png><#/part>
|
||||||
|
<#/multipart>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Mixed Content (Text + Attachments)
|
||||||
|
|
||||||
|
```
|
||||||
|
From: alice@localhost
|
||||||
|
To: bob@localhost
|
||||||
|
Subject: Mixed Content
|
||||||
|
|
||||||
|
<#multipart type=mixed>
|
||||||
|
<#part type=text/plain>
|
||||||
|
Please find the attached files.
|
||||||
|
|
||||||
|
Best,
|
||||||
|
Alice
|
||||||
|
<#part filename=/path/to/file1.pdf><#/part>
|
||||||
|
<#part filename=/path/to/file2.zip><#/part>
|
||||||
|
<#/multipart>
|
||||||
|
```
|
||||||
|
|
||||||
|
## MML Tag Reference
|
||||||
|
|
||||||
|
### `<#multipart>`
|
||||||
|
|
||||||
|
Groups multiple parts together.
|
||||||
|
|
||||||
|
- `type=alternative`: Different representations of same content
|
||||||
|
- `type=mixed`: Independent parts (text + attachments)
|
||||||
|
- `type=related`: Parts that reference each other (HTML + images)
|
||||||
|
|
||||||
|
### `<#part>`
|
||||||
|
|
||||||
|
Defines a message part.
|
||||||
|
|
||||||
|
- `type=<mime-type>`: Content type (e.g., `text/html`, `application/pdf`)
|
||||||
|
- `filename=<path>`: File to attach
|
||||||
|
- `name=<name>`: Display name for attachment
|
||||||
|
- `disposition=inline`: Display inline instead of as attachment
|
||||||
|
- `id=<cid>`: Content ID for referencing in HTML
|
||||||
|
|
||||||
|
## Composing from CLI
|
||||||
|
|
||||||
|
### Interactive compose
|
||||||
|
|
||||||
|
Opens your `$EDITOR`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
himalaya message write
|
||||||
|
```
|
||||||
|
|
||||||
|
### Reply (opens editor with quoted message)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
himalaya message reply 42
|
||||||
|
himalaya message reply 42 --all # reply-all
|
||||||
|
```
|
||||||
|
|
||||||
|
### Forward
|
||||||
|
|
||||||
|
```bash
|
||||||
|
himalaya message forward 42
|
||||||
|
```
|
||||||
|
|
||||||
|
### Send from stdin
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cat message.txt | himalaya template send
|
||||||
|
```
|
||||||
|
|
||||||
|
### Prefill headers from CLI
|
||||||
|
|
||||||
|
```bash
|
||||||
|
himalaya message write \
|
||||||
|
-H "To:recipient@example.com" \
|
||||||
|
-H "Subject:Quick Message" \
|
||||||
|
"Message body here"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Tips
|
||||||
|
|
||||||
|
- The editor opens with a template; fill in headers and body.
|
||||||
|
- Save and exit the editor to send; exit without saving to cancel.
|
||||||
|
- MML parts are compiled to proper MIME when sending.
|
||||||
|
- Use `himalaya message export --full` to inspect the raw MIME structure of received emails.
|
||||||
161
resources/skills/skill-creator/SKILL.md
Normal file
161
resources/skills/skill-creator/SKILL.md
Normal file
@ -0,0 +1,161 @@
|
|||||||
|
---
|
||||||
|
name: skill-creator
|
||||||
|
description: Create or update PicoBot skills. Use when the user wants a new skill, wants an existing skill revised, or needs a skill scaffold that follows PicoBot's workspace/skills mechanism.
|
||||||
|
---
|
||||||
|
|
||||||
|
# Skill Creator
|
||||||
|
|
||||||
|
Use this skill when building a new PicoBot skill or updating an existing one.
|
||||||
|
|
||||||
|
## About Skills
|
||||||
|
|
||||||
|
Skills are small, self-contained folders that give PicoBot procedural knowledge for a narrow task.
|
||||||
|
They are most useful when the same workflow, file format, or domain rule would otherwise be
|
||||||
|
re-explained over and over.
|
||||||
|
|
||||||
|
## PicoBot conventions
|
||||||
|
|
||||||
|
- Put `always: true` in the `SKILL.md` frontmatter when the skill should be injected on every turn.
|
||||||
|
- Prefer `{workspace}/skills/<skill-name>/` for skills created by the agent.
|
||||||
|
- `~/.picobot/skills/` is the built-in install location.
|
||||||
|
- `~/.agents/skills/` is the fallback shared location.
|
||||||
|
- Each skill must have a `SKILL.md` file.
|
||||||
|
- Add `agents/openai.yaml` when you want UI metadata or a default invocation prompt.
|
||||||
|
- Use `references/` for detailed docs and `assets/` for templates or bundled files.
|
||||||
|
- Keep `SKILL.md` concise; move long instructions into references.
|
||||||
|
- Use `always: true` only when the skill should be injected on every turn.
|
||||||
|
|
||||||
|
## Core Principles
|
||||||
|
|
||||||
|
### Keep It Concise
|
||||||
|
|
||||||
|
Only add information the model actually needs. Prefer short rules and concrete examples over
|
||||||
|
long explanations. If a rule can be implied from the task, leave it out.
|
||||||
|
|
||||||
|
### Set the Right Constraints
|
||||||
|
|
||||||
|
- Use high freedom when many approaches are valid.
|
||||||
|
- Use medium freedom when there is a preferred pattern but some variation is fine.
|
||||||
|
- Use low freedom when the workflow is fragile and should be followed closely.
|
||||||
|
|
||||||
|
### Protect Validation
|
||||||
|
|
||||||
|
When a skill changes, verify it against a realistic task path. Check that:
|
||||||
|
|
||||||
|
- the skill name is discoverable,
|
||||||
|
- the frontmatter is valid,
|
||||||
|
- any bundled references are actually reachable,
|
||||||
|
- and the instructions still lead to the intended output.
|
||||||
|
|
||||||
|
## Skill Anatomy
|
||||||
|
|
||||||
|
Every PicoBot skill should have:
|
||||||
|
|
||||||
|
- a required `SKILL.md`,
|
||||||
|
- optional `agents/openai.yaml` for UI metadata,
|
||||||
|
- optional `references/skill-template.md` as a starting scaffold,
|
||||||
|
- optional `references/` for longer docs,
|
||||||
|
- optional `assets/` for templates, icons, or sample files.
|
||||||
|
|
||||||
|
## Workflow
|
||||||
|
|
||||||
|
### 1) Capture Intent
|
||||||
|
|
||||||
|
Start by figuring out what the user actually wants the skill to do.
|
||||||
|
|
||||||
|
Check:
|
||||||
|
|
||||||
|
- what task the skill should enable,
|
||||||
|
- when it should trigger,
|
||||||
|
- what the expected output looks like,
|
||||||
|
- whether the task is objectively testable,
|
||||||
|
- whether the skill needs bundled references or assets.
|
||||||
|
|
||||||
|
If the request is vague, ask short, focused questions before writing files.
|
||||||
|
|
||||||
|
### 2) Draft the Skill
|
||||||
|
|
||||||
|
1. Choose a clear skill name and a narrow purpose.
|
||||||
|
2. Write `SKILL.md` with a trigger-focused `description` and a concise body.
|
||||||
|
3. Put `always: true` in the frontmatter only when the skill should be injected on every turn.
|
||||||
|
4. Add `agents/openai.yaml` for UI metadata if the skill should appear in a picker or chip list.
|
||||||
|
5. Add `references/` or `assets/` only when they reduce repetition.
|
||||||
|
|
||||||
|
### 3) Validate the Draft
|
||||||
|
|
||||||
|
Before treating the skill as done, check that:
|
||||||
|
|
||||||
|
- the frontmatter parses,
|
||||||
|
- the skill is discoverable through `get_skill`,
|
||||||
|
- the body is still concise,
|
||||||
|
- the references and assets are reachable,
|
||||||
|
- the instructions are specific enough to lead to the right output.
|
||||||
|
|
||||||
|
For objective workflows, also test the skill against a small set of representative prompts or files.
|
||||||
|
|
||||||
|
### 4) Iterate
|
||||||
|
|
||||||
|
Revise the skill based on what you learn.
|
||||||
|
|
||||||
|
- Tighten the description if the skill under-triggers.
|
||||||
|
- Narrow the instructions if the model wanders.
|
||||||
|
- Add examples if the output format keeps drifting.
|
||||||
|
- Move details into `references/` if `SKILL.md` starts to grow.
|
||||||
|
|
||||||
|
### 5) Optimize Triggering
|
||||||
|
|
||||||
|
The `description` is the main trigger surface.
|
||||||
|
|
||||||
|
- Make it specific.
|
||||||
|
- Include the contexts where the skill should be used.
|
||||||
|
- Prefer wording that helps the model notice the skill even when the user does not name it exactly.
|
||||||
|
- Keep it concise, but do not make it vague.
|
||||||
|
|
||||||
|
### 6) Re-open and Confirm
|
||||||
|
|
||||||
|
Use `get_skill action="get"` one more time to confirm the final shape if anything changed materially.
|
||||||
|
|
||||||
|
## Progressive Disclosure
|
||||||
|
|
||||||
|
Keep `SKILL.md` as the entry point and move detail into separate files when it starts to grow:
|
||||||
|
|
||||||
|
- Put setup steps, examples, and edge cases in `references/`.
|
||||||
|
- Put reusable templates or sample files in `assets/`.
|
||||||
|
- Link from `SKILL.md` to those files instead of duplicating content.
|
||||||
|
- Start new skills from `references/skill-template.md` when you want a consistent scaffold.
|
||||||
|
|
||||||
|
## What Not To Include
|
||||||
|
|
||||||
|
- Do not add general project docs that do not help create the skill.
|
||||||
|
- Do not dump every possible edge case into `SKILL.md`.
|
||||||
|
- Do not duplicate the same guidance in both `SKILL.md` and `references/`.
|
||||||
|
- Do not make the skill broad just because it can handle more cases.
|
||||||
|
|
||||||
|
## Skill scaffold
|
||||||
|
|
||||||
|
```md
|
||||||
|
---
|
||||||
|
name: example-skill
|
||||||
|
description: What this skill helps with and when to use it.
|
||||||
|
always: true
|
||||||
|
---
|
||||||
|
|
||||||
|
# Example Skill
|
||||||
|
|
||||||
|
Short, direct instructions for the agent.
|
||||||
|
```
|
||||||
|
|
||||||
|
## Good fit
|
||||||
|
|
||||||
|
- A reusable workflow with a clear trigger.
|
||||||
|
- A task that benefits from bundled references or templates.
|
||||||
|
- A skill that should be easy to discover and update inside PicoBot.
|
||||||
|
|
||||||
|
## Practical Rule of Thumb
|
||||||
|
|
||||||
|
If the skill is:
|
||||||
|
|
||||||
|
- **objective**: add test cases and validate output shape,
|
||||||
|
- **workflow-heavy**: spell out the sequence and the stop conditions,
|
||||||
|
- **content-heavy**: move examples and long references into `references/`,
|
||||||
|
- **trigger-sensitive**: spend more time on `description` than on the body.
|
||||||
4
resources/skills/skill-creator/agents/openai.yaml
Normal file
4
resources/skills/skill-creator/agents/openai.yaml
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
interface:
|
||||||
|
display_name: "Skill Creator"
|
||||||
|
short_description: "Create or update a PicoBot skill"
|
||||||
|
default_prompt: "Use $skill-name to scaffold or update a PicoBot skill."
|
||||||
44
resources/skills/skill-creator/references/skill-template.md
Normal file
44
resources/skills/skill-creator/references/skill-template.md
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
# PicoBot Skill Template
|
||||||
|
|
||||||
|
Use this as the starting point for a new skill.
|
||||||
|
|
||||||
|
---
|
||||||
|
name: example-skill
|
||||||
|
description: What this skill helps with and when to use it.
|
||||||
|
always: true
|
||||||
|
---
|
||||||
|
|
||||||
|
# Example Skill
|
||||||
|
|
||||||
|
## Purpose
|
||||||
|
|
||||||
|
Explain what this skill does in one or two sentences.
|
||||||
|
|
||||||
|
## When To Use
|
||||||
|
|
||||||
|
- Use this skill when ...
|
||||||
|
- Use this skill when ...
|
||||||
|
|
||||||
|
## Workflow
|
||||||
|
|
||||||
|
1. Do the first thing.
|
||||||
|
2. Do the second thing.
|
||||||
|
3. Verify the result.
|
||||||
|
|
||||||
|
## Rules
|
||||||
|
|
||||||
|
- Keep the instructions narrow.
|
||||||
|
- Prefer concrete examples over long explanations.
|
||||||
|
- Move long details into `references/` or `assets/`.
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
```text
|
||||||
|
User request -> expected skill behavior
|
||||||
|
```
|
||||||
|
|
||||||
|
## Optional Files
|
||||||
|
|
||||||
|
- `agents/openai.yaml` for UI metadata and default prompts.
|
||||||
|
- `references/` for long-form guidance, edge cases, and examples.
|
||||||
|
- `assets/` for reusable files, templates, or sample data.
|
||||||
@ -874,8 +874,12 @@ mod tests {
|
|||||||
®istry,
|
®istry,
|
||||||
);
|
);
|
||||||
|
|
||||||
assert!(matches!(blocks.first(), Some(ContentBlock::Text { text }) if text == "先看这段文字"));
|
assert!(
|
||||||
assert!(matches!(blocks.get(1), Some(ContentBlock::Text { text }) if text.contains("用户发来了一个文件")));
|
matches!(blocks.first(), Some(ContentBlock::Text { text }) if text == "先看这段文字")
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
matches!(blocks.get(1), Some(ContentBlock::Text { text }) if text.contains("用户发来了一个文件"))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1125,7 +1125,10 @@ impl FeishuChannel {
|
|||||||
.get("event_key")
|
.get("event_key")
|
||||||
.and_then(|v| v.as_str())
|
.and_then(|v| v.as_str())
|
||||||
.unwrap_or("unknown");
|
.unwrap_or("unknown");
|
||||||
(format!("[shared calendar event: {}]", event_key), Vec::new())
|
(
|
||||||
|
format!("[shared calendar event: {}]", event_key),
|
||||||
|
Vec::new(),
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
("[shared calendar event]".to_string(), Vec::new())
|
("[shared calendar event]".to_string(), Vec::new())
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user