@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.
Files changed (53) hide show
  1. package/.github/CODEOWNERS +25 -0
  2. package/.github/ISSUE_TEMPLATE/bug_report.yml +93 -0
  3. package/.github/ISSUE_TEMPLATE/config.yml +5 -0
  4. package/.github/ISSUE_TEMPLATE/feature_request.yml +54 -0
  5. package/.github/ISSUE_TEMPLATE/platform_request.yml +55 -0
  6. package/.github/PULL_REQUEST_TEMPLATE.md +53 -0
  7. package/.github/SETUP.md +65 -0
  8. package/.github/workflows/ci.yml +85 -0
  9. package/AGENTS.md +68 -0
  10. package/BACKLOG.md +55 -0
  11. package/CODE_OF_CONDUCT.md +43 -0
  12. package/CONTRIBUTING.md +136 -0
  13. package/LICENSE +201 -0
  14. package/README.md +112 -0
  15. package/SECURITY.md +42 -0
  16. package/bin/agentshift.js +4 -0
  17. package/examples/pregnancy-companion/AGENTS.md +212 -0
  18. package/examples/pregnancy-companion/BOOTSTRAP.md +55 -0
  19. package/examples/pregnancy-companion/SKILL.md +88 -0
  20. package/examples/pregnancy-companion/data/appointments.md +5 -0
  21. package/examples/pregnancy-companion/data/questions-for-doctor.md +7 -0
  22. package/examples/pregnancy-companion/data/symptoms-log.md +5 -0
  23. package/examples/pregnancy-companion/data/weight-log.md +6 -0
  24. package/examples/pregnancy-companion/knowledge/appointments.md +122 -0
  25. package/examples/pregnancy-companion/knowledge/exercise.md +114 -0
  26. package/examples/pregnancy-companion/knowledge/nutrition.md +112 -0
  27. package/examples/pregnancy-companion/knowledge/warning-signs.md +80 -0
  28. package/examples/pregnancy-companion/knowledge/week-by-week.md +198 -0
  29. package/index.js +4 -0
  30. package/package.json +18 -0
  31. package/pyproject.toml +72 -0
  32. package/specs/claude-code-format.md +397 -0
  33. package/specs/ir-schema.json +438 -0
  34. package/specs/ir-schema.md +370 -0
  35. package/specs/openclaw-skill-format.md +483 -0
  36. package/src/agentshift/__init__.py +3 -0
  37. package/src/agentshift/cli.py +44 -0
  38. package/src/agentshift/emitters/__init__.py +1 -0
  39. package/src/agentshift/ir.py +134 -0
  40. package/src/agentshift/parsers/__init__.py +1 -0
  41. package/tests/__init__.py +0 -0
  42. package/tests/fixtures/pregnancy-companion/AGENTS.md +212 -0
  43. package/tests/fixtures/pregnancy-companion/BOOTSTRAP.md +55 -0
  44. package/tests/fixtures/pregnancy-companion/SKILL.md +88 -0
  45. package/tests/fixtures/pregnancy-companion/data/appointments.md +5 -0
  46. package/tests/fixtures/pregnancy-companion/data/questions-for-doctor.md +7 -0
  47. package/tests/fixtures/pregnancy-companion/data/symptoms-log.md +5 -0
  48. package/tests/fixtures/pregnancy-companion/data/weight-log.md +6 -0
  49. package/tests/fixtures/pregnancy-companion/knowledge/appointments.md +122 -0
  50. package/tests/fixtures/pregnancy-companion/knowledge/exercise.md +114 -0
  51. package/tests/fixtures/pregnancy-companion/knowledge/nutrition.md +112 -0
  52. package/tests/fixtures/pregnancy-companion/knowledge/warning-signs.md +80 -0
  53. 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,3 @@
1
+ """AgentShift — CLI transpiler for converting AI agents between platforms."""
2
+
3
+ __version__ = "0.1.0"
@@ -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