@ogkranthi/agentshift 0.1.0
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.
- package/.github/CODEOWNERS +25 -0
- package/.github/ISSUE_TEMPLATE/bug_report.yml +93 -0
- package/.github/ISSUE_TEMPLATE/config.yml +5 -0
- package/.github/ISSUE_TEMPLATE/feature_request.yml +54 -0
- package/.github/ISSUE_TEMPLATE/platform_request.yml +55 -0
- package/.github/PULL_REQUEST_TEMPLATE.md +53 -0
- package/.github/SETUP.md +65 -0
- package/.github/workflows/ci.yml +85 -0
- package/AGENTS.md +68 -0
- package/BACKLOG.md +55 -0
- package/CODE_OF_CONDUCT.md +43 -0
- package/CONTRIBUTING.md +136 -0
- package/LICENSE +201 -0
- package/README.md +112 -0
- package/SECURITY.md +42 -0
- package/bin/agentshift.js +4 -0
- package/examples/pregnancy-companion/AGENTS.md +212 -0
- package/examples/pregnancy-companion/BOOTSTRAP.md +55 -0
- package/examples/pregnancy-companion/SKILL.md +88 -0
- package/examples/pregnancy-companion/data/appointments.md +5 -0
- package/examples/pregnancy-companion/data/questions-for-doctor.md +7 -0
- package/examples/pregnancy-companion/data/symptoms-log.md +5 -0
- package/examples/pregnancy-companion/data/weight-log.md +6 -0
- package/examples/pregnancy-companion/knowledge/appointments.md +122 -0
- package/examples/pregnancy-companion/knowledge/exercise.md +114 -0
- package/examples/pregnancy-companion/knowledge/nutrition.md +112 -0
- package/examples/pregnancy-companion/knowledge/warning-signs.md +80 -0
- package/examples/pregnancy-companion/knowledge/week-by-week.md +198 -0
- package/index.js +4 -0
- package/package.json +18 -0
- package/pyproject.toml +72 -0
- package/specs/claude-code-format.md +397 -0
- package/specs/ir-schema.json +438 -0
- package/specs/ir-schema.md +370 -0
- package/specs/openclaw-skill-format.md +483 -0
- package/src/agentshift/__init__.py +3 -0
- package/src/agentshift/cli.py +44 -0
- package/src/agentshift/emitters/__init__.py +1 -0
- package/src/agentshift/ir.py +134 -0
- package/src/agentshift/parsers/__init__.py +1 -0
- package/tests/__init__.py +0 -0
- package/tests/fixtures/pregnancy-companion/AGENTS.md +212 -0
- package/tests/fixtures/pregnancy-companion/BOOTSTRAP.md +55 -0
- package/tests/fixtures/pregnancy-companion/SKILL.md +88 -0
- package/tests/fixtures/pregnancy-companion/data/appointments.md +5 -0
- package/tests/fixtures/pregnancy-companion/data/questions-for-doctor.md +7 -0
- package/tests/fixtures/pregnancy-companion/data/symptoms-log.md +5 -0
- package/tests/fixtures/pregnancy-companion/data/weight-log.md +6 -0
- package/tests/fixtures/pregnancy-companion/knowledge/appointments.md +122 -0
- package/tests/fixtures/pregnancy-companion/knowledge/exercise.md +114 -0
- package/tests/fixtures/pregnancy-companion/knowledge/nutrition.md +112 -0
- package/tests/fixtures/pregnancy-companion/knowledge/warning-signs.md +80 -0
- package/tests/fixtures/pregnancy-companion/knowledge/week-by-week.md +198 -0
|
@@ -0,0 +1,483 @@
|
|
|
1
|
+
# OpenClaw SKILL.md Format Spec
|
|
2
|
+
|
|
3
|
+
**Status:** Canonical
|
|
4
|
+
**Source:** Observed from `~/.nvm/versions/node/v22.22.1/lib/node_modules/openclaw/skills/` and `~/.openclaw/skills/`
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Overview
|
|
9
|
+
|
|
10
|
+
An OpenClaw skill is a directory containing a required `SKILL.md` file and optional supporting files. The `SKILL.md` follows a **YAML frontmatter + Markdown body** pattern.
|
|
11
|
+
|
|
12
|
+
```
|
|
13
|
+
skill-name/
|
|
14
|
+
├── SKILL.md # Required — identity + instructions
|
|
15
|
+
├── AGENTS.md # Optional — workspace/session rules for the agent
|
|
16
|
+
├── SOUL.md # Optional — agent personality and values
|
|
17
|
+
├── USER.md # Optional — user profile and preferences
|
|
18
|
+
├── IDENTITY.md # Optional — agent name, creature, emoji
|
|
19
|
+
├── TOOLS.md # Optional — local tool/device notes
|
|
20
|
+
├── HEARTBEAT.md # Optional — periodic check tasks
|
|
21
|
+
├── BOOTSTRAP.md # Optional — first-run initialization script
|
|
22
|
+
├── knowledge/ # Optional — reference documents (loaded on demand)
|
|
23
|
+
│ ├── week-by-week.md
|
|
24
|
+
│ └── nutrition.md
|
|
25
|
+
├── data/ # Optional — runtime data written by the agent
|
|
26
|
+
│ ├── symptoms-log.md
|
|
27
|
+
│ └── appointments.md
|
|
28
|
+
├── scripts/ # Optional — executable scripts
|
|
29
|
+
├── references/ # Optional — detailed reference docs
|
|
30
|
+
├── assets/ # Optional — output files (templates, images)
|
|
31
|
+
└── .openclaw/
|
|
32
|
+
└── workspace-state.json # Runtime state (auto-managed)
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## SKILL.md Structure
|
|
38
|
+
|
|
39
|
+
```
|
|
40
|
+
---
|
|
41
|
+
<YAML frontmatter>
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
# Skill Title
|
|
45
|
+
|
|
46
|
+
<Markdown body — agent instructions>
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
The YAML frontmatter and Markdown body are separated by `---` delimiters.
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
## YAML Frontmatter Fields
|
|
54
|
+
|
|
55
|
+
### Required Fields
|
|
56
|
+
|
|
57
|
+
| Field | Type | Description |
|
|
58
|
+
|-------|------|-------------|
|
|
59
|
+
| `name` | string | Skill slug. Lowercase, hyphens. e.g. `weather`, `pregnancy-companion`. Must match the directory name. |
|
|
60
|
+
| `description` | string | One-sentence description + trigger guidance. This is the **primary triggering signal** — OpenClaw reads only `name` and `description` to decide when to load the skill. |
|
|
61
|
+
|
|
62
|
+
### Optional Fields
|
|
63
|
+
|
|
64
|
+
| Field | Type | Description |
|
|
65
|
+
|-------|------|-------------|
|
|
66
|
+
| `homepage` | URI | URL for the tool's documentation or project page. |
|
|
67
|
+
| `os` | string[] | Operating systems. Values: `darwin`, `linux`, `windows`. Omit for cross-platform. |
|
|
68
|
+
| `metadata` | object | Nested platform-specific metadata (see below). |
|
|
69
|
+
|
|
70
|
+
### `metadata.openclaw` Object
|
|
71
|
+
|
|
72
|
+
The `metadata` field always wraps an `openclaw` key:
|
|
73
|
+
|
|
74
|
+
```yaml
|
|
75
|
+
metadata:
|
|
76
|
+
openclaw:
|
|
77
|
+
emoji: "☔"
|
|
78
|
+
requires:
|
|
79
|
+
bins: ["curl"]
|
|
80
|
+
anyBins: ["claude", "codex"]
|
|
81
|
+
config: ["channels.slack"]
|
|
82
|
+
install:
|
|
83
|
+
- id: brew
|
|
84
|
+
kind: brew
|
|
85
|
+
formula: gh
|
|
86
|
+
bins: [gh]
|
|
87
|
+
label: "Install GitHub CLI (brew)"
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
#### `metadata.openclaw` Fields
|
|
91
|
+
|
|
92
|
+
| Field | Type | Description |
|
|
93
|
+
|-------|------|-------------|
|
|
94
|
+
| `emoji` | string | Display emoji for the skill in OpenClaw UI. |
|
|
95
|
+
| `requires.bins` | string[] | All of these binaries must be present for the skill to work. |
|
|
96
|
+
| `requires.anyBins` | string[] | At least one of these binaries must be present. |
|
|
97
|
+
| `requires.config` | string[] | OpenClaw config keys that must be set. e.g. `channels.slack`. |
|
|
98
|
+
| `install` | InstallStep[] | One or more installation methods for the skill's dependencies (see below). |
|
|
99
|
+
|
|
100
|
+
#### InstallStep Object
|
|
101
|
+
|
|
102
|
+
```yaml
|
|
103
|
+
install:
|
|
104
|
+
- id: brew
|
|
105
|
+
kind: brew
|
|
106
|
+
formula: gh
|
|
107
|
+
bins: [gh]
|
|
108
|
+
label: "Install GitHub CLI (brew)"
|
|
109
|
+
- id: apt
|
|
110
|
+
kind: apt
|
|
111
|
+
package: gh
|
|
112
|
+
bins: [gh]
|
|
113
|
+
label: "Install GitHub CLI (apt)"
|
|
114
|
+
- id: go
|
|
115
|
+
kind: go
|
|
116
|
+
module: github.com/Hyaxia/blogwatcher/cmd/blogwatcher@latest
|
|
117
|
+
bins: [blogwatcher]
|
|
118
|
+
label: "Install blogwatcher (go)"
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
| Field | Description |
|
|
122
|
+
|-------|-------------|
|
|
123
|
+
| `id` | Unique identifier for this install method. e.g. `brew`, `apt`, `go`. |
|
|
124
|
+
| `kind` | Package manager: `brew`, `apt`, `go`, `npm`, `pip`, `cargo`, `script`. |
|
|
125
|
+
| `formula` | Homebrew formula name (when `kind: brew`). |
|
|
126
|
+
| `package` | apt/npm/pip package name (when `kind: apt`/`npm`/`pip`). |
|
|
127
|
+
| `module` | Go module path (when `kind: go`). |
|
|
128
|
+
| `bins` | Binary names installed by this step (for verification). |
|
|
129
|
+
| `label` | Human-readable label shown during install. |
|
|
130
|
+
|
|
131
|
+
---
|
|
132
|
+
|
|
133
|
+
## Frontmatter Examples
|
|
134
|
+
|
|
135
|
+
### Minimal (no dependencies)
|
|
136
|
+
|
|
137
|
+
```yaml
|
|
138
|
+
---
|
|
139
|
+
name: pregnancy-companion
|
|
140
|
+
description: 24/7 pregnancy companion — answers questions, tracks symptoms, gives weekly updates, and supports a healthy pregnancy journey
|
|
141
|
+
os:
|
|
142
|
+
- darwin
|
|
143
|
+
- linux
|
|
144
|
+
---
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### With emoji and binary requirement
|
|
148
|
+
|
|
149
|
+
```yaml
|
|
150
|
+
---
|
|
151
|
+
name: weather
|
|
152
|
+
description: "Get current weather and forecasts via wttr.in or Open-Meteo. Use when: user asks about weather, temperature, or forecasts for any location. NOT for: historical weather data, severe weather alerts."
|
|
153
|
+
homepage: https://wttr.in/:help
|
|
154
|
+
metadata: { "openclaw": { "emoji": "☔", "requires": { "bins": ["curl"] } } }
|
|
155
|
+
---
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
> Note: The `metadata` field can be expressed as inline JSON (single-line) or as multi-line YAML.
|
|
159
|
+
|
|
160
|
+
### With config requirement (Slack)
|
|
161
|
+
|
|
162
|
+
```yaml
|
|
163
|
+
---
|
|
164
|
+
name: slack
|
|
165
|
+
description: Use when you need to control Slack from OpenClaw via the slack tool.
|
|
166
|
+
metadata: { "openclaw": { "emoji": "💬", "requires": { "config": ["channels.slack"] } } }
|
|
167
|
+
---
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
### With binary alternatives and install steps
|
|
171
|
+
|
|
172
|
+
```yaml
|
|
173
|
+
---
|
|
174
|
+
name: coding-agent
|
|
175
|
+
description: 'Delegate coding tasks to Codex, Claude Code, or Pi agents. Use when: (1) building/creating features, (2) reviewing PRs, (3) refactoring. NOT for: simple one-liner fixes, reading code.'
|
|
176
|
+
metadata:
|
|
177
|
+
{
|
|
178
|
+
"openclaw": { "emoji": "🧩", "requires": { "anyBins": ["claude", "codex", "opencode", "pi"] } },
|
|
179
|
+
}
|
|
180
|
+
---
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
### With install steps (multi-line YAML)
|
|
184
|
+
|
|
185
|
+
```yaml
|
|
186
|
+
---
|
|
187
|
+
name: github
|
|
188
|
+
description: "GitHub operations via `gh` CLI: issues, PRs, CI runs, code review. Use when: checking PR status, creating issues, listing PRs. NOT for: local git operations."
|
|
189
|
+
metadata:
|
|
190
|
+
{
|
|
191
|
+
"openclaw":
|
|
192
|
+
{
|
|
193
|
+
"emoji": "🐙",
|
|
194
|
+
"requires": { "bins": ["gh"] },
|
|
195
|
+
"install":
|
|
196
|
+
[
|
|
197
|
+
{
|
|
198
|
+
"id": "brew",
|
|
199
|
+
"kind": "brew",
|
|
200
|
+
"formula": "gh",
|
|
201
|
+
"bins": ["gh"],
|
|
202
|
+
"label": "Install GitHub CLI (brew)",
|
|
203
|
+
},
|
|
204
|
+
{
|
|
205
|
+
"id": "apt",
|
|
206
|
+
"kind": "apt",
|
|
207
|
+
"package": "gh",
|
|
208
|
+
"bins": ["gh"],
|
|
209
|
+
"label": "Install GitHub CLI (apt)",
|
|
210
|
+
},
|
|
211
|
+
],
|
|
212
|
+
},
|
|
213
|
+
}
|
|
214
|
+
---
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
---
|
|
218
|
+
|
|
219
|
+
## Markdown Body Structure
|
|
220
|
+
|
|
221
|
+
The body is free-form Markdown. OpenClaw loads the full body as system prompt context after the skill triggers.
|
|
222
|
+
|
|
223
|
+
### Description Format Best Practices (observed)
|
|
224
|
+
|
|
225
|
+
Effective `description` fields follow this pattern:
|
|
226
|
+
|
|
227
|
+
```
|
|
228
|
+
<What it does>. Use when: <trigger conditions (1), (2), ...>. NOT for: <anti-triggers>.
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
This dual-signal format lets OpenClaw's routing layer both select the skill (trigger) and prevent false positives (anti-trigger).
|
|
232
|
+
|
|
233
|
+
### Typical Body Sections
|
|
234
|
+
|
|
235
|
+
```markdown
|
|
236
|
+
# Skill Name
|
|
237
|
+
|
|
238
|
+
## When to Use / When NOT to Use
|
|
239
|
+
Explicit positive/negative examples.
|
|
240
|
+
|
|
241
|
+
## Setup
|
|
242
|
+
One-time configuration steps.
|
|
243
|
+
|
|
244
|
+
## Commands / Actions
|
|
245
|
+
Core workflows with code examples.
|
|
246
|
+
|
|
247
|
+
## Examples / Templates
|
|
248
|
+
Copy-paste patterns for common tasks.
|
|
249
|
+
|
|
250
|
+
## Notes / Caveats
|
|
251
|
+
Rate limits, gotchas, edge cases.
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
There is no enforced schema for the body — the structure is guidance to the agent.
|
|
255
|
+
|
|
256
|
+
---
|
|
257
|
+
|
|
258
|
+
## Supporting Files
|
|
259
|
+
|
|
260
|
+
These files are convention-based, not required by the OpenClaw engine.
|
|
261
|
+
|
|
262
|
+
### `AGENTS.md`
|
|
263
|
+
|
|
264
|
+
Workspace and session rules. Loaded at agent startup. Covers:
|
|
265
|
+
- Memory system (daily notes in `memory/YYYY-MM-DD.md`, long-term `MEMORY.md`)
|
|
266
|
+
- Heartbeat behavior (when to speak in group chats, when to stay silent)
|
|
267
|
+
- Red lines (never exfiltrate data, ask before destructive commands)
|
|
268
|
+
- Tool usage conventions
|
|
269
|
+
|
|
270
|
+
### `SOUL.md`
|
|
271
|
+
|
|
272
|
+
Agent values, personality, and purpose. Defines who the agent is rather than what it does. Loaded alongside `AGENTS.md` at startup.
|
|
273
|
+
|
|
274
|
+
### `USER.md`
|
|
275
|
+
|
|
276
|
+
User profile. Name, timezone, preferences, communication style. Loaded at startup. Kept separate from `SOUL.md` so agent identity and user context are distinct.
|
|
277
|
+
|
|
278
|
+
### `IDENTITY.md`
|
|
279
|
+
|
|
280
|
+
Agent name, creature type, emoji, and vibe. Created during `BOOTSTRAP.md` first-run flow.
|
|
281
|
+
|
|
282
|
+
### `TOOLS.md`
|
|
283
|
+
|
|
284
|
+
Local device/environment notes that are specific to the user's setup:
|
|
285
|
+
- Camera names and locations
|
|
286
|
+
- SSH host aliases
|
|
287
|
+
- TTS voice preferences
|
|
288
|
+
- Device nicknames
|
|
289
|
+
|
|
290
|
+
Kept separate from `SKILL.md` because skills are shareable but this file is personal.
|
|
291
|
+
|
|
292
|
+
### `HEARTBEAT.md`
|
|
293
|
+
|
|
294
|
+
Periodic task checklist. When empty (or containing only comments), the agent replies `HEARTBEAT_OK` to heartbeat polls. When populated, the agent executes the listed tasks.
|
|
295
|
+
|
|
296
|
+
```markdown
|
|
297
|
+
# HEARTBEAT.md
|
|
298
|
+
|
|
299
|
+
## Tasks
|
|
300
|
+
- Check email for urgent messages
|
|
301
|
+
- Review today's calendar
|
|
302
|
+
- Log morning weight if available
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
### `BOOTSTRAP.md`
|
|
306
|
+
|
|
307
|
+
First-run initialization script. The agent reads this once, sets up `SOUL.md`, `IDENTITY.md`, and `USER.md`, then deletes `BOOTSTRAP.md`. It is not present in mature skill directories.
|
|
308
|
+
|
|
309
|
+
---
|
|
310
|
+
|
|
311
|
+
## Cron Triggers
|
|
312
|
+
|
|
313
|
+
OpenClaw cron jobs are **not** expressed inside `SKILL.md`. They live in `~/.openclaw/cron/jobs.json` and are managed via `openclaw cron` commands.
|
|
314
|
+
|
|
315
|
+
A cron job that invokes a skill looks like:
|
|
316
|
+
|
|
317
|
+
```json
|
|
318
|
+
{
|
|
319
|
+
"id": "pregnancy-daily-tip",
|
|
320
|
+
"agentId": "pregnancy-companion",
|
|
321
|
+
"schedule": {
|
|
322
|
+
"expr": "0 9 * * *"
|
|
323
|
+
},
|
|
324
|
+
"enabled": true,
|
|
325
|
+
"name": "Daily Pregnancy Tip",
|
|
326
|
+
"description": "Morning tip for the pregnancy companion",
|
|
327
|
+
"wakeMode": "now",
|
|
328
|
+
"payload": {
|
|
329
|
+
"kind": "agentTurn",
|
|
330
|
+
"message": "Give today's pregnancy tip based on the current week. Keep it brief and warm."
|
|
331
|
+
},
|
|
332
|
+
"sessionTarget": "isolated",
|
|
333
|
+
"delivery": {
|
|
334
|
+
"mode": "announce",
|
|
335
|
+
"channel": "telegram",
|
|
336
|
+
"accountId": "mybot",
|
|
337
|
+
"to": "123456789"
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
Key cron job fields:
|
|
343
|
+
|
|
344
|
+
| Field | Description |
|
|
345
|
+
|-------|-------------|
|
|
346
|
+
| `id` | Unique job identifier |
|
|
347
|
+
| `agentId` | The skill `name` this job targets |
|
|
348
|
+
| `schedule.expr` | 5-field cron expression (`min hour dom month dow`) |
|
|
349
|
+
| `schedule.every` | Interval shorthand alternative. e.g. `"30m"`, `"2h"` |
|
|
350
|
+
| `wakeMode` | `"now"` = run immediately when triggered |
|
|
351
|
+
| `payload.kind` | `"agentTurn"` = inject a message into a new agent session |
|
|
352
|
+
| `payload.message` | The message/prompt injected into the agent session |
|
|
353
|
+
| `sessionTarget` | `"isolated"` = fresh session, `"main"` = main session |
|
|
354
|
+
| `delivery.mode` | `"announce"` = send output to channel, `"silent"` = no output |
|
|
355
|
+
| `delivery.channel` | `"telegram"`, `"slack"`, `"discord"`, `"email"`, `"stdout"` |
|
|
356
|
+
| `delivery.to` | Destination identifier (chat_id, channel_id, email) |
|
|
357
|
+
|
|
358
|
+
### Skill-Side Cron Documentation Convention
|
|
359
|
+
|
|
360
|
+
Although cron jobs live outside `SKILL.md`, it's good practice to document expected cron behavior in the skill body:
|
|
361
|
+
|
|
362
|
+
```markdown
|
|
363
|
+
## Proactive Support
|
|
364
|
+
|
|
365
|
+
When triggered by cron jobs, provide:
|
|
366
|
+
- Daily tips relevant to the current pregnancy week
|
|
367
|
+
- Weekly pregnancy updates with baby development info
|
|
368
|
+
- Appointment reminders with suggested questions
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
---
|
|
372
|
+
|
|
373
|
+
## Knowledge Sources
|
|
374
|
+
|
|
375
|
+
Knowledge files are referenced by path in `SKILL.md` rather than declared in a schema. The agent reads them with the `bash` tool (or `Read` tool) when needed.
|
|
376
|
+
|
|
377
|
+
```markdown
|
|
378
|
+
## Knowledge Base
|
|
379
|
+
|
|
380
|
+
Refer to the files in `~/.openclaw/skills/pregnancy-companion/knowledge/`:
|
|
381
|
+
- `week-by-week.md` — Baby development and symptoms by week
|
|
382
|
+
- `nutrition.md` — Pregnancy nutrition guide by trimester
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
Standard directory layout:
|
|
386
|
+
|
|
387
|
+
```
|
|
388
|
+
skill-name/
|
|
389
|
+
└── knowledge/
|
|
390
|
+
├── week-by-week.md
|
|
391
|
+
├── nutrition.md
|
|
392
|
+
└── warning-signs.md
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
---
|
|
396
|
+
|
|
397
|
+
## Data Files
|
|
398
|
+
|
|
399
|
+
Runtime data written by the agent lives in a `data/` subdirectory:
|
|
400
|
+
|
|
401
|
+
```
|
|
402
|
+
skill-name/
|
|
403
|
+
└── data/
|
|
404
|
+
├── symptoms-log.md
|
|
405
|
+
├── weight-log.md
|
|
406
|
+
├── appointments.md
|
|
407
|
+
└── questions-for-doctor.md
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
These are referenced by absolute or `~`-relative paths in the system prompt:
|
|
411
|
+
|
|
412
|
+
```markdown
|
|
413
|
+
**Symptoms**: Append to `~/.openclaw/skills/pregnancy-companion/data/symptoms-log.md`
|
|
414
|
+
```
|
|
415
|
+
|
|
416
|
+
---
|
|
417
|
+
|
|
418
|
+
## Progressive Loading
|
|
419
|
+
|
|
420
|
+
OpenClaw loads skill content in three stages:
|
|
421
|
+
|
|
422
|
+
1. **`name` + `description` only** — always in context (~100 words). Used for routing/triggering.
|
|
423
|
+
2. **Full `SKILL.md` body** — loaded when the skill is selected.
|
|
424
|
+
3. **`knowledge/` and `references/` files** — loaded by the agent on demand using file-read tools.
|
|
425
|
+
|
|
426
|
+
Keep `SKILL.md` bodies under 500 lines to minimize context cost.
|
|
427
|
+
|
|
428
|
+
---
|
|
429
|
+
|
|
430
|
+
## Complete Minimal Example
|
|
431
|
+
|
|
432
|
+
```
|
|
433
|
+
skill-name/
|
|
434
|
+
└── SKILL.md
|
|
435
|
+
```
|
|
436
|
+
|
|
437
|
+
```yaml
|
|
438
|
+
---
|
|
439
|
+
name: wttr-weather
|
|
440
|
+
description: "Get current weather for any city using wttr.in. Use when: user asks about weather, temperature, or forecasts. NOT for: historical data or severe weather alerts."
|
|
441
|
+
homepage: https://wttr.in/:help
|
|
442
|
+
metadata: { "openclaw": { "emoji": "🌤️", "requires": { "bins": ["curl"] } } }
|
|
443
|
+
---
|
|
444
|
+
|
|
445
|
+
# Weather
|
|
446
|
+
|
|
447
|
+
Get current conditions and forecasts from wttr.in. No API key required.
|
|
448
|
+
|
|
449
|
+
## Current weather
|
|
450
|
+
|
|
451
|
+
```bash
|
|
452
|
+
curl "wttr.in/London?format=3"
|
|
453
|
+
```
|
|
454
|
+
|
|
455
|
+
## 3-day forecast
|
|
456
|
+
|
|
457
|
+
```bash
|
|
458
|
+
curl "wttr.in/London"
|
|
459
|
+
```
|
|
460
|
+
|
|
461
|
+
## Format codes
|
|
462
|
+
|
|
463
|
+
- `%t` temperature `%w` wind `%h` humidity `%p` precipitation
|
|
464
|
+
|
|
465
|
+
## Notes
|
|
466
|
+
|
|
467
|
+
- Supports city names, ZIP codes, and airport codes
|
|
468
|
+
- Rate limited — don't spam requests
|
|
469
|
+
```
|
|
470
|
+
|
|
471
|
+
---
|
|
472
|
+
|
|
473
|
+
## Full Example — pregnancy-companion
|
|
474
|
+
|
|
475
|
+
See `~/.openclaw/skills/pregnancy-companion/SKILL.md` for the complete reference implementation.
|
|
476
|
+
|
|
477
|
+
Key observations from that file:
|
|
478
|
+
- No `metadata` block (no external binary dependencies)
|
|
479
|
+
- `os: [darwin, linux]` restricts platform
|
|
480
|
+
- Body uses `##` sections for clear agent instructions
|
|
481
|
+
- Safety rules are explicit, numbered, and marked `CRITICAL`
|
|
482
|
+
- Data file paths use `~/.openclaw/skills/<name>/data/` convention
|
|
483
|
+
- Knowledge files use `~/.openclaw/skills/<name>/knowledge/` convention
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"""AgentShift CLI — convert AI agents between platforms."""
|
|
2
|
+
|
|
3
|
+
import typer
|
|
4
|
+
|
|
5
|
+
app = typer.Typer(
|
|
6
|
+
name="agentshift",
|
|
7
|
+
help="Convert AI agents between platforms. OpenClaw → Copilot, Bedrock, Vertex AI, Claude Code.",
|
|
8
|
+
no_args_is_help=True,
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@app.command()
|
|
13
|
+
def convert(
|
|
14
|
+
source: str = typer.Argument(help="Path to source agent (e.g., ./my-skill/)"),
|
|
15
|
+
to: str = typer.Option(help="Target platform: claude-code, copilot, bedrock, vertex, all"),
|
|
16
|
+
output: str = typer.Option(None, "--output", "-o", help="Output directory (default: ./agentshift-output/)"),
|
|
17
|
+
) -> None:
|
|
18
|
+
"""Convert an agent from one platform to another."""
|
|
19
|
+
typer.echo(f"Converting {source} → {to}")
|
|
20
|
+
typer.echo("Not yet implemented — agents are building this!")
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@app.command()
|
|
24
|
+
def diff(
|
|
25
|
+
source: str = typer.Argument(help="Path to source agent"),
|
|
26
|
+
targets: str = typer.Option("all", help="Comma-separated targets: claude-code,copilot,bedrock,vertex"),
|
|
27
|
+
) -> None:
|
|
28
|
+
"""Show portability matrix — what converts cleanly vs. needs manual work."""
|
|
29
|
+
typer.echo(f"Diffing {source} against {targets}")
|
|
30
|
+
typer.echo("Not yet implemented — agents are building this!")
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
@app.command()
|
|
34
|
+
def validate(
|
|
35
|
+
source: str = typer.Argument(help="Path to generated agent config"),
|
|
36
|
+
target: str = typer.Option(help="Target platform to validate against"),
|
|
37
|
+
) -> None:
|
|
38
|
+
"""Validate a generated config against the target platform's schema."""
|
|
39
|
+
typer.echo(f"Validating {source} for {target}")
|
|
40
|
+
typer.echo("Not yet implemented — agents are building this!")
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
if __name__ == "__main__":
|
|
44
|
+
app()
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""AgentShift emitters — write IR to target platform formats."""
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
"""AgentShift Intermediate Representation (IR) — Pydantic v2 models."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Any, Literal
|
|
6
|
+
|
|
7
|
+
from pydantic import BaseModel, Field
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class ToolAuth(BaseModel):
|
|
11
|
+
model_config = {"extra": "forbid"}
|
|
12
|
+
|
|
13
|
+
type: Literal["none", "api_key", "oauth2", "bearer", "basic", "config_key"] = "none"
|
|
14
|
+
env_var: str | None = None
|
|
15
|
+
config_key: str | None = None
|
|
16
|
+
scopes: list[str] = Field(default_factory=list)
|
|
17
|
+
notes: str | None = None
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class Tool(BaseModel):
|
|
21
|
+
model_config = {"extra": "forbid"}
|
|
22
|
+
|
|
23
|
+
name: str
|
|
24
|
+
description: str
|
|
25
|
+
kind: Literal["mcp", "openapi", "shell", "builtin", "function", "unknown"] = "unknown"
|
|
26
|
+
parameters: dict[str, Any] | None = None
|
|
27
|
+
auth: ToolAuth | None = None
|
|
28
|
+
endpoint: str | None = None
|
|
29
|
+
platform_availability: list[
|
|
30
|
+
Literal["openclaw", "claude-code", "copilot", "bedrock", "vertex-ai"]
|
|
31
|
+
] = Field(default_factory=list)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class KnowledgeSource(BaseModel):
|
|
35
|
+
model_config = {"extra": "forbid"}
|
|
36
|
+
|
|
37
|
+
name: str
|
|
38
|
+
kind: Literal["file", "directory", "url", "vector_store", "database", "s3"]
|
|
39
|
+
path: str | None = None
|
|
40
|
+
description: str | None = None
|
|
41
|
+
format: Literal["markdown", "json", "yaml", "text", "pdf", "html", "unknown"] = "unknown"
|
|
42
|
+
load_mode: Literal["always", "on_demand", "indexed"] = "on_demand"
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class TriggerDelivery(BaseModel):
|
|
46
|
+
model_config = {"extra": "forbid"}
|
|
47
|
+
|
|
48
|
+
mode: Literal["announce", "silent", "reply"] = "announce"
|
|
49
|
+
channel: Literal["telegram", "slack", "discord", "email", "webhook", "stdout"] | None = None
|
|
50
|
+
to: str | None = None
|
|
51
|
+
account_id: str | None = None
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
class Trigger(BaseModel):
|
|
55
|
+
model_config = {"extra": "forbid"}
|
|
56
|
+
|
|
57
|
+
kind: Literal["cron", "webhook", "message", "event", "manual"]
|
|
58
|
+
id: str | None = None
|
|
59
|
+
cron_expr: str | None = None
|
|
60
|
+
every: str | None = None
|
|
61
|
+
message: str | None = None
|
|
62
|
+
webhook_path: str | None = None
|
|
63
|
+
event_name: str | None = None
|
|
64
|
+
delivery: TriggerDelivery | None = None
|
|
65
|
+
session_target: Literal["isolated", "main", "thread"] = "isolated"
|
|
66
|
+
enabled: bool = True
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
class Constraints(BaseModel):
|
|
70
|
+
model_config = {"extra": "forbid"}
|
|
71
|
+
|
|
72
|
+
max_instruction_chars: int | None = None
|
|
73
|
+
supported_os: list[Literal["darwin", "linux", "windows"]] = Field(default_factory=list)
|
|
74
|
+
required_bins: list[str] = Field(default_factory=list)
|
|
75
|
+
any_required_bins: list[str] = Field(default_factory=list)
|
|
76
|
+
required_config_keys: list[str] = Field(default_factory=list)
|
|
77
|
+
guardrails: list[str] = Field(default_factory=list)
|
|
78
|
+
topic_restrictions: list[str] = Field(default_factory=list)
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
class InstallStep(BaseModel):
|
|
82
|
+
model_config = {"extra": "forbid"}
|
|
83
|
+
|
|
84
|
+
id: str
|
|
85
|
+
kind: Literal["brew", "apt", "go", "npm", "pip", "cargo", "script", "manual"]
|
|
86
|
+
formula: str | None = None
|
|
87
|
+
package: str | None = None
|
|
88
|
+
module: str | None = None
|
|
89
|
+
script_url: str | None = None
|
|
90
|
+
bins: list[str] = Field(default_factory=list)
|
|
91
|
+
label: str | None = None
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
class Persona(BaseModel):
|
|
95
|
+
model_config = {"extra": "forbid"}
|
|
96
|
+
|
|
97
|
+
system_prompt: str | None = None
|
|
98
|
+
personality_notes: str | None = None
|
|
99
|
+
language: str = "en"
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
class Metadata(BaseModel):
|
|
103
|
+
model_config = {"extra": "forbid"}
|
|
104
|
+
|
|
105
|
+
source_platform: (
|
|
106
|
+
Literal["openclaw", "claude-code", "copilot", "bedrock", "vertex-ai", "unknown"] | None
|
|
107
|
+
) = None
|
|
108
|
+
target_platforms: list[
|
|
109
|
+
Literal["openclaw", "claude-code", "copilot", "bedrock", "vertex-ai"]
|
|
110
|
+
] = Field(default_factory=list)
|
|
111
|
+
created_at: str | None = None
|
|
112
|
+
updated_at: str | None = None
|
|
113
|
+
source_file: str | None = None
|
|
114
|
+
emoji: str | None = None
|
|
115
|
+
tags: list[str] = Field(default_factory=list)
|
|
116
|
+
platform_extensions: dict[str, dict[str, Any]] = Field(default_factory=dict)
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
class AgentIR(BaseModel):
|
|
120
|
+
model_config = {"extra": "forbid"}
|
|
121
|
+
|
|
122
|
+
ir_version: Literal["1.0"] = "1.0"
|
|
123
|
+
name: str
|
|
124
|
+
description: str
|
|
125
|
+
version: str = "1.0.0"
|
|
126
|
+
author: str | None = None
|
|
127
|
+
homepage: str | None = None
|
|
128
|
+
persona: Persona = Field(default_factory=Persona)
|
|
129
|
+
tools: list[Tool] = Field(default_factory=list)
|
|
130
|
+
knowledge: list[KnowledgeSource] = Field(default_factory=list)
|
|
131
|
+
triggers: list[Trigger] = Field(default_factory=list)
|
|
132
|
+
constraints: Constraints = Field(default_factory=Constraints)
|
|
133
|
+
install: list[InstallStep] = Field(default_factory=list)
|
|
134
|
+
metadata: Metadata = Field(default_factory=Metadata)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""AgentShift parsers — read source agent formats into IR."""
|
|
File without changes
|