Managing Skills
Once a device has gone through onboarding, there are three things you'll typically do with skills: change the role, let the device update itself, and (occasionally) reset everything when state gets stuck.
Role change
A user can switch roles at any time by saying any of:
change my roleswitch roleI'm now in <new role>
The onboarding skill intercepts the message and runs:
1. Ask user which role to switch to.
2. Match the reply against manifest.roles[*].keywords
(same matching logic as initial onboarding).
3. Read onboarding.json → installed_role = OLD role.
4. Look up manifest.roles[OLD].skills → delete those folders
from workspace/skills/. Generic folders are left alone.
5. Download {BASE_URL}/skills_zip/{manifest.roles[NEW].skills_zip}
→ extract to workspace/skills/.
6. Update onboarding.json:
installed_role = NEW
skills = generic… + manifest.roles[NEW].skills
updated_at = now
7. Reply on the user's channel:
✅ Role switched to {NEW.label}!
Removed: {old role skills}
Installed: {new role skills}
📦 Generic skills unchanged.
Generic skills are never removed by a role change — they stay until the device is wiped. If a skill folder exists in both the generic and the new role zip, the role-specific copy overwrites the generic one (role wins).
Auto-update
The onboarding skill registers a cronjob on first run. The cronjob ID is persisted as update_cronjob_id inside onboarding.json so it isn't created twice.
| Setting | Value |
|---|---|
| Schedule | every 6 hours |
| Action | fetch version.txt from GitHub, compare to installed_version |
| Trigger | new version → re-download generic + currently-installed role zip |
| Strategy | full overwrite (never merge) |
| Notify | one channel message on success: 🔄 Skills updated to version X.Y.Z |
cron tick (every 6h)
│
▼
GET raw.githubusercontent.com/…/main/version.txt
│
▼
compare to onboarding.json.installed_version
│
┌──────┴──────┐
│ same │ newer
│ │
▼ ▼
do nothing download generic.zip + {installed_role}.zip
→ extract over workspace/skills/
→ set onboarding.json.installed_version = new
→ notify channel
Because zips are overwritten wholesale, a version bump is the right way to add, change, or remove any skill in a bundle. There is no per-skill update — bundles are the unit.
Forcing an update
If you don't want to wait 6 hours, just ask the device — the onboarding skill responds to messages like update skills now by running the same compare-and-fetch logic immediately. Otherwise, SSH in (see Developer Edition → SSH Access) and remove manifest_cache.json and onboarding.json.installed_version; the next cronjob tick treats the device as out-of-date and re-fetches.
Manual reset
If onboarding.json ends up in a state you can't recover from a chat command, SSH in and start fresh:
# Delete state — onboarding will re-trigger on the next user message.
rm /root/workspace/skills/autonomous-intern-onboarding/onboarding.json
# Optional — also drop the cached manifest so the next fetch is fresh.
rm /root/workspace/skills/autonomous-intern-onboarding/manifest_cache.json
# Optional — clear previously installed skill folders if they're broken.
# Keep the onboarding skill itself.
find /root/workspace/skills -mindepth 1 -maxdepth 1 \
-type d ! -name 'autonomous-intern-onboarding' -exec rm -rf {} +
The next user message hits the onboarding flow again. The user will be re-greeted and re-asked for their role.
workspace/skills/ paths on the device depend on how the runtime is configured. The paths above (/root/workspace/skills/) match the default OpenClaw layout — adjust if your install uses a different workspace root.
Troubleshooting
| Symptom | What to check |
|---|---|
| Onboarding greeting fires on every message | onboarding.json doesn't exist, isn't readable, or has empty installed_role. SSH in and cat the file. If corrupted, delete it (the skill self-heals by recreating it on next run). |
| User said their role but nothing was installed | Watch the device's chat log — keyword match likely went ambiguous or 0-match and the skill re-asked. Check that the user's reply contains any of the role's keywords (see Role Catalog). |
| Skill that should be there isn't responding | ls /root/workspace/skills/ — confirm the folder exists. If yes, check its SKILL.md is readable. If not, the role zip extracted partially — force an update (see above). |
| Updates haven't shipped in days | `cat onboarding.json |
installed_version doesn't match version.txt on GitHub | Either the cronjob hasn't fired yet (wait 6h or force an update) or the download is failing — check the device's network and re-trigger the skill via chat. |
| Wrong role got matched | Tell the device change my role (see Role change). |
Two roles' keywords overlap and matching is unpredictable | Edit manifest.json in the repo to tighten one side's keywords, bump version.txt, and let the cronjob propagate. The greeting also asks for clarification when more than one role matches. |
| No internet on the device during onboarding | The skill caches manifest.json as manifest_cache.json and retries fetches. Pairing-time internet is required at least once; thereafter, the cached manifest carries the device through brief outages. |
Where the source lives
- Skill registry & flow source:
autonomous-ai/intern-skills - Onboarding skill:
autonomous-intern-onboarding/SKILL.md - Catalog:
manifest.json— also documented in Role Catalog - Version:
version.txt