feat: role-based skill installation via role-skills.json

learn.sh now installs skills in three layers:
1. mandatory (.mandatory) - all agents
2. role/position (role-skills.json) - based on ego-mgr fields
3. agent-specific (.skill-list) - optional per-agent extras

Deduplicated across layers. ego-mgr unavailable = graceful skip.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
zhi
2026-04-18 17:05:40 +00:00
parent 840707b604
commit 4cca810c15
2 changed files with 104 additions and 24 deletions

View File

@@ -6,44 +6,85 @@ if [[ -z "${AGENT_WORKSPACE:-}" ]]; then
exit 1 exit 1
fi fi
SKILL_LIST="${AGENT_WORKSPACE}/.skill-list"
TARGET_DIR="${AGENT_WORKSPACE}/skills" TARGET_DIR="${AGENT_WORKSPACE}/skills"
CLAW_DIR="$(cd "$(dirname "$0")" && pwd)" CLAW_DIR="$(cd "$(dirname "$0")" && pwd)"
MANDATORY_FILE="${CLAW_DIR}/.mandatory" MANDATORY_FILE="${CLAW_DIR}/.mandatory"
ROLE_SKILLS_FILE="${CLAW_DIR}/role-skills.json"
SKILL_LIST="${AGENT_WORKSPACE}/.skill-list"
mkdir -p "$TARGET_DIR" mkdir -p "$TARGET_DIR"
# First: install mandatory skills from .mandatory (one per line) # Track installed skills to avoid duplicates
if [[ -f "$MANDATORY_FILE" ]]; then declare -A INSTALLED
while IFS= read -r skill_name || [[ -n "$skill_name" ]]; do
[[ -z "$skill_name" || "$skill_name" == \#* ]] && continue
skill_dir="${CLAW_DIR}/${skill_name}" install_skill() {
local skill_name="$1"
local source="$2"
[[ -z "$skill_name" || "$skill_name" == \#* ]] && return
if [[ -n "${INSTALLED[$skill_name]:-}" ]]; then
return
fi
local skill_dir="${CLAW_DIR}/${skill_name}"
if [[ -d "$skill_dir" ]]; then if [[ -d "$skill_dir" ]]; then
echo "Installing (mandatory): $skill_name" echo "Installing ($source): $skill_name"
cp -r "$skill_dir" "${TARGET_DIR}/" cp -r "$skill_dir" "${TARGET_DIR}/"
INSTALLED[$skill_name]=1
else else
echo "Skipping (not found): $skill_name" echo "Skipping (not found): $skill_name"
fi fi
}
# 1. Install mandatory skills
if [[ -f "$MANDATORY_FILE" ]]; then
while IFS= read -r skill_name || [[ -n "$skill_name" ]]; do
install_skill "$skill_name" "mandatory"
done < "$MANDATORY_FILE" done < "$MANDATORY_FILE"
fi fi
# Then: install skills from .skill-list # 2. Install role-based skills from role-skills.json
if [[ -f "$ROLE_SKILLS_FILE" ]]; then
ROLE=$(ego-mgr get role 2>/dev/null || true)
POSITION=$(ego-mgr get position 2>/dev/null || true)
if [[ -n "$ROLE" ]]; then
ROLE_SKILLS=$(python3 -c "
import json, sys
with open('$ROLE_SKILLS_FILE') as f:
data = json.load(f)
skills = data.get('roles', {}).get('$ROLE', [])
print('\n'.join(skills))
" 2>/dev/null || true)
while IFS= read -r skill_name; do
[[ -n "$skill_name" ]] && install_skill "$skill_name" "role:$ROLE"
done <<< "$ROLE_SKILLS"
fi
if [[ -n "$POSITION" ]]; then
POS_SKILLS=$(python3 -c "
import json, sys
with open('$ROLE_SKILLS_FILE') as f:
data = json.load(f)
skills = data.get('positions', {}).get('$POSITION', [])
print('\n'.join(skills))
" 2>/dev/null || true)
while IFS= read -r skill_name; do
[[ -n "$skill_name" ]] && install_skill "$skill_name" "position:$POSITION"
done <<< "$POS_SKILLS"
fi
else
echo "Warning: role-skills.json not found, skipping role-based skills"
fi
# 3. Install agent-specific skills from .skill-list (if exists)
if [[ -f "$SKILL_LIST" ]]; then if [[ -f "$SKILL_LIST" ]]; then
while IFS= read -r skill_name || [[ -n "$skill_name" ]]; do while IFS= read -r skill_name || [[ -n "$skill_name" ]]; do
[[ -z "$skill_name" || "$skill_name" == \#* ]] && continue install_skill "$skill_name" "skill-list"
skill_dir="${CLAW_DIR}/${skill_name}"
if [[ -d "$skill_dir" ]]; then
echo "Installing: $skill_name"
cp -r "$skill_dir" "${TARGET_DIR}/"
else
echo "Skipping (not found): $skill_name"
fi
done < "$SKILL_LIST" done < "$SKILL_LIST"
else
echo "Error: .skill-list not found at $SKILL_LIST"
exit 1
fi fi
echo "Done." echo "Done."

39
role-skills.json Normal file
View File

@@ -0,0 +1,39 @@
{
"_description": "Maps role and position to skill lists. learn.sh resolves skills by: mandatory → role → position (in that order, deduplicated).",
"_extensibility": "Add new roles/positions as needed. Unknown role/position values are silently skipped.",
"roles": {
"developer": [
"git-hangman-lab"
],
"manager": [
"git-hangman-lab"
],
"operator": [
"git-hangman-lab"
],
"mentor": [
"git-hangman-lab",
"claw-skills"
],
"secretary": [],
"agent-resource-director": [
"keycloak-hangman-lab",
"recruitment"
]
},
"positions": {
"tech-leader": [],
"delivery-manager": [],
"operator": [],
"mentor": [
"claw-skills"
],
"administrative-secretary": [],
"director": [
"keycloak-hangman-lab",
"recruitment"
]
}
}