Convert ClawHub skills into Manus-compatible skills.
A small, fast, fully-tested Python CLI that translates OpenClaw SKILL.md files to
Manus format in one pass — frontmatter cleanup, body rewriting, GitHub fetching,
and a change report you can actually audit.
ClawHub (the OpenClaw skill registry) and Manus use the same idea — a SKILL.md
file with YAML frontmatter and markdown body — but they don't agree on the names,
allowed fields, or filesystem paths. claw2manus is the translator.
ClawHub SKILL.md Manus SKILL.md
───────────────── ────────────────
name: Test Skill name: test-skill
description: "A test skill." description: "What it does: A test skill.
When to use it: This is a converted
skill from ClawHub, ..."
metadata: null ← dropped
# Body # Body
~/.openclaw/workspace/test → /home/ubuntu/workspace/test
sessions_list → Manus: Use `shell` tool with `ps aux` ...
See CLAUDE.md → See soul.md
See AGENTS.md → See subtasks.md
Every change is logged in a CONVERSION_REPORT.md next to the output so you
can review what happened and revert what you didn't want.
- One command, one directory.
convert-allwalks a tree of skills, emits clean Manus output, and never collides on names — even when two skills share an author. - Auditable. Every body substitution is a configurable rule in
config.yaml. Add your own without touching code. - Honest about what it can't do. No silent
CLAUDE.md→ three-paragraph prose rewrites — your references stay as filenames. No silent bracket stripping that masks bugs — descriptions with<or>are rejected so the validator can flag them. - Respects auth. Set
GITHUB_TOKENand you'll get the 5,000 req/hr GitHub limit instead of 60. Anonymous use still works.
| Capability | What you get |
|---|---|
| Batch conversion | convert-all walks a directory tree and translates every SKILL.md it finds. |
| Skill fetching | fetch-and-convert resolves a name through GitHub, with a clawhub.ai scraping fallback for skills not on GitHub. |
| Plugin rules | Body transformations live in config.yaml as a list. Add yours with SkillConverter.add_rule({...}). |
| Interactive mode | --interactive lets you override tool replacements per-run. |
| Dry-run + diff | --dry-run prints the full output; --diff shows a unified diff between input and result. |
| Validation | Built-in validate command checks naming, length, allowed fields, and required sections. |
| Conversion report | Every run emits a CONVERSION_REPORT.md next to the converted SKILL.md. |
| Path safety | Output directory names are sanitized; .. traversal is rejected. |
| Tested | 92 tests, including end-to-end fixtures in tests/fixtures/. |
# Recommended: uv
git clone https://github.com/frostmute/claw2manus.git
cd claw2manus
uv venv
source .venv/bin/activate
uv pip install -e ".[test]"Or with plain pip:
python -m venv .venv
source .venv/bin/activate
pip install -e ".[test]"System Python works too, but a venv keeps claw2manus from polluting your
site-packages.
claw2manus convert ./path/to/SKILL.md --output ./out/A CONVERSION_REPORT.md lands in ./out/<skill-name>/ next to the
converted SKILL.md.
claw2manus convert ./path/to/SKILL.md --dry-run --diff--dry-run shows the full output. --diff shows a unified diff instead of
(or in addition to) the full output. Combine them to review a change without
writing anything to disk.
claw2manus convert-all ./skills/ --output ./manus-skills/Nested layouts like skills/<author>/<skill>/SKILL.md are disambiguated
automatically — the output gets manus-skills/<author>-<skill>/ directories
that won't collide.
# Resolves through GitHub's index, with author discovery via Search API
claw2manus fetch-and-convert pwnclaw-security-scan --output ./out/
# Or with a direct URL — GitHub `blob/...` or raw URLs both work
claw2manus fetch-and-convert \
https://raw.githubusercontent.com/Xquik-dev/tweetclaw/master/skills/tweetclaw/SKILL.md \
--output ./out/For high-volume use, set a GitHub token to lift the rate limit:
export GITHUB_TOKEN=ghp_xxxxxxxxxxxx
claw2manus fetch-and-convert ...claw2manus validate ./path/to/Manus/SKILL.md
# or point it at a directory containing SKILL.md
claw2manus validate ./my-manus-skill/| Command | Purpose |
|---|---|
claw2manus convert <path> |
Convert one SKILL.md. Flags: --output, --dry-run, --diff, --interactive. |
claw2manus convert-all <dir> |
Convert every SKILL.md under <dir> recursively. Flags: --output, --interactive. |
claw2manus fetch-and-convert <name|url> |
Resolve a name or URL through GitHub / ClawHub and convert. Flags: --output, --interactive. |
claw2manus validate <path> |
Validate an existing SKILL.md against Manus rules. |
Global exit semantics:
| Code | When |
|---|---|
0 |
Conversion succeeded, validation clean (or no validation requested) |
1 |
Validation reported errors, or a fatal conversion failure occurred |
2 |
Invalid CLI arguments |
claw2manus reads claw2manus/config.yaml from the installed package by default.
You can override it by passing config_path to SkillConverter() programmatically.
The config file has three sections. See docs/CONFIGURATION.md
for the full schema and walked examples.
# 1. Exact-name tool replacements (OpenClaw → Manus instruction text).
tool_replacements:
sessions_list: "Manus: Use `shell` tool with `ps aux` ..."
# 2. Detection patterns for stdio-only tools that may need an MCP bridge.
stdio_patterns:
- pattern: '(\b(?:psql|mysql|sqlite3)\b)'
category: "Database clients"
mcp_suggestion: "Use an MCP server (e.g. mcp-server-postgres)."
# 3. Body substitution rules — regex + replacement + log template.
body_rules:
- id: claude-md-to-soul-md
pattern: '(?<![A-Za-z0-9_.-])CLAUDE\.md(?![A-Za-z0-9_.])'
replacement: soul.md
log: "Replaced CLAUDE.md with soul.md ({count} occurrence{plural})."To add rules programmatically:
from claw2manus.converter import SkillConverter
converter = SkillConverter()
converter.add_rule({
"id": "my-custom-rule",
"pattern": r"foo",
"replacement": "bar",
"log": "Replaced foo with bar ({count} occurrence{plural}).",
})Invalid regexes raise ValueError at insertion time, so plugin authors get
immediate feedback.
claw2manus/
├── README.md ← you are here
├── LICENSE
├── setup.py ← PyPI metadata + entry point
├── .pre-commit-config.yaml ← ruff + hygiene hooks
├── .github/
│ └── workflows/test.yml ← CI on Python 3.10 / 3.11 / 3.12
├── claw2manus/
│ ├── __init__.py
│ ├── cli.py ← argparse, _safe_dir_name, --diff
│ ├── converter.py ← SkillConverter, add_rule(), body rules engine
│ ├── fetcher.py ← GitHub content + Search, clawhub.ai scraping
│ ├── validators.py ← ManusSkillValidator
│ └── config.yaml ← bundled rule + tool-replacement defaults
├── docs/
│ ├── CONVERSION.md ← what the converter actually does
│ ├── CONFIGURATION.md ← config.yaml schema
│ └── DEVELOPMENT.md ← dev workflow + project layout
├── examples/
│ ├── input/ ← sample input skills
│ └── output/ ← expected converted output + reports
└── tests/
├── conftest.py
├── fixtures/
│ └── integration_repo/ ← three-skill fixture for end-to-end tests
├── test_cli.py
├── test_converter.py
├── test_fetcher.py
├── test_integration.py ← end-to-end against the fixture repo
└── test_validators.py
# Install with test extras
uv pip install -e ".[test]"
# Run the test suite
pytest
# Run a single test by name
pytest -k test_safe_dir_name
# Format & lint
ruff format .
ruff check --fix .Pre-commit hooks are configured — pre-commit install will catch lint and
whitespace issues before they hit CI. CI itself runs on Python 3.10, 3.11,
and 3.12 via .github/workflows/test.yml.
See docs/DEVELOPMENT.md for the full contributor guide.
- Documentation site — rendered with
jekyll-theme-console, dark style - Conversion Logic — what each stage of the converter does
- Configuration Guide —
config.yamlschema and examples - Development Guide — setup, project layout, testing
- Changelog — version history
The fetcher takes a hostile-input stance:
- Path segments in GitHub URLs are URL-encoded, including
.(to block..traversal). fetch-and-convertruns derived skill names through_safe_dir_namebefore treating them as filesystem paths.- Output directory names are validated against
[A-Za-z0-9._-]; anything outside that becomesconverted-skill.
If you discover a path-traversal or injection issue, please open a
security-focused issue or email frostmute@users.noreply.github.com.
PRs welcome. Use pre-commit and run pytest before pushing. Tests for new
behavior go in the relevant tests/test_*.py file; end-to-end behavior
should add a fixture under tests/fixtures/.
diffimprovements — side-by-side rendering for visual review- Plugin discovery —
SkillConverter.pluginshook for users to register rules from external packages - Schema versioning — handle v1 vs v2 Manus skill frontmatter
- More
MANIFEST.in-friendly packaging —pyproject.tomlmigration
MIT — see the file for full text.