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:
89
learn.sh
89
learn.sh
@@ -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
|
||||||
|
declare -A INSTALLED
|
||||||
|
|
||||||
|
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
|
||||||
|
echo "Installing ($source): $skill_name"
|
||||||
|
cp -r "$skill_dir" "${TARGET_DIR}/"
|
||||||
|
INSTALLED[$skill_name]=1
|
||||||
|
else
|
||||||
|
echo "Skipping (not found): $skill_name"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# 1. Install mandatory skills
|
||||||
if [[ -f "$MANDATORY_FILE" ]]; then
|
if [[ -f "$MANDATORY_FILE" ]]; 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" "mandatory"
|
||||||
|
|
||||||
skill_dir="${CLAW_DIR}/${skill_name}"
|
|
||||||
if [[ -d "$skill_dir" ]]; then
|
|
||||||
echo "Installing (mandatory): $skill_name"
|
|
||||||
cp -r "$skill_dir" "${TARGET_DIR}/"
|
|
||||||
else
|
|
||||||
echo "Skipping (not found): $skill_name"
|
|
||||||
fi
|
|
||||||
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
39
role-skills.json
Normal 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"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user