Agent Skills
Agent Skills is a fleet-wide inventory of Claude Code slash-skills (/skill-name) installed on your developers' machines. It discovers every skill at session start, scores each one for risk, and lets you govern them, allow, warn, or block, from the dashboard without touching individual workstations.
This is distinct from MCP Skill Monitoring, which covers mcp__server__tool calls. Agent Skills covers Claude Code's local slash-command skills (~/.claude/skills/).
Prerequisites
- Runtime Shield enabled: available on Free and paid plans
- Agent Keeper Claude Code plugin installed on each workstation, see Plugin Reference
The scanner activates automatically when the plugin is installed. If you installed Agent Keeper via the plugin (rather than MDM), make sure ~/.agentkeeper/config contains your API key, see Troubleshooting if skills are not appearing.
How it works
1. Discovery, SessionStart scan
Every time a developer opens Claude Code, the SessionStart hook fires and runs the scanner. Two delivery paths ship the same logic:
- Plugin install (default):
${CLAUDE_PLUGIN_ROOT}/scripts/session-start.sh, installed by the Agent Keeper Claude Code plugin. - MDM install (Kandji, Jamf):
~/.agentkeeper/cc-session-start.shrun as atype: "command"SessionStart hook. This path requiresAGENTKEEPER_API_KEYto be set in~/.agentkeeper/config(see Troubleshooting).
Both emit the same POST /api/v1/claude-code/checkin payload. The scanner walks these skill sources:
| Location | Source label | When scanned |
|---|---|---|
~/.claude/skills/ | global | Always |
$cwd/.claude/skills/ | project | Only when the working directory is not the home directory |
Two skill layouts are supported at the leaf:
skills/skill-name.md # flat file (older format)
skills/skill-name/SKILL.md # directory layout (current standard)
The scanner follows symlinks, so symlinked skill directories (installed via package managers or dotfile managers) are discovered correctly.
For each skill found, the script collects:
- Name: derived from the filename or directory name
- Source:
globalorproject - Preview: first 500 bytes of the skill file (used for risk scoring)
- Hash: SHA-256 of the full file (for drift detection)
2. Checkin payload
The skill list is included in the POST /api/v1/claude-code/checkin payload that the SessionStart hook already sends:
{
"hostname": "dev-machine",
"session_id": "abc123...",
"cwd": "/Users/alice/project",
"installed_skills": [
{
"name": "react",
"source": "global",
"preview": "# React\n...",
"hash": "a1b2c3..."
},
{
"name": "deploy",
"source": "project",
"preview": "# Deploy\n...",
"hash": "d4e5f6..."
}
]
}
The endpoint upserts each skill into the host_skill_inventory table, keyed on (host_id, skill_name, skill_source). A skill seen on 5 workstations creates 5 rows, one per host, aggregated in the dashboard view.
3. Risk scoring
Risk is scored server-side against the 500-byte content preview. Seven pattern categories are checked:
| Flag | What it detects | Score |
|---|---|---|
credential_access | secret, token, password, api_key | +40 |
destructive_ops | rm -rf, delete all, format disk | +35 |
bash_commands | ```bash, Bash tool calls, shell_command | +30 |
code_execution | eval(), exec(), subprocess, os.system | +30 |
package_install | pip install, npm install, brew install | +25 |
network_access | curl, wget, WebFetch, https:// URLs | +20 |
file_write | Write tool calls, write file, create file | +20 |
Scores are additive, capped at 100:
| Level | Score range |
|---|---|
| Low | 0 – 25 |
| Medium | 26 – 50 |
| High | 51 – 75 |
| Critical | 76 – 100 |
Scoring runs on the preview only, the first 500 bytes. Skills with their risky instructions beyond that threshold score lower than they should. If you want accurate scoring for a long skill, ensure the relevant intent appears early in the file.
4. Dashboard view
The Agent Skills page at /claude-code/skills shows two aggregated inventories across all hosts in your organization.
Skill Inventory (slash-skills):
- Skill name: the slash-command name (e.g.,
/react) - Risk level: Low / Medium / High / Critical badge
- Risk flags: which pattern categories triggered (Shell Access, Credentials, etc.)
- Hosts: how many workstations have the skill installed
- Status: Active, Warn, or Blocked per your policy
- Policy controls: Allow / Warn / Block buttons per row
Click any row to open a detail panel showing the full skill content, host list, and timestamps.
MCP Servers (below the skill table):
- Server name: the key from
mcpServersin Claude Code settings (e.g.,postgres,github) - Type: transport type:
stdio,HTTP, orSSE - Command: the binary that runs the server (basename only, no args or environment variables are captured)
- Source:
global(from~/.claude/settings.json) orproject(from.claude/settings.json/.mcp.json) - Hosts: how many workstations have the server configured
- First / Last seen: timestamps from the most recent session scans
This is proactive discovery, servers appear the first time a workstation checks in, before any tool has been called. It is distinct from the reactive MCP tool tracking in the Security dashboard, which shows tool invocations from shield events.
5. Governance, Block, Warn, Allow
Policy is stored in claude_code_policies and enforced on the UserPromptSubmit hook, the same hook that handles prompt injection detection.
When a developer types /skill-name at the start of a prompt, Agent Keeper:
- Detects the slash-skill invocation (regex match at prompt start)
- Checks
blocked_agent_skills, if matched, denies the invocation with:Blocked by Agent Keeper org policy: skill /name is not allowed - Checks
warn_only_agent_skills, if matched, allows the invocation but logs it as a shield event for review
Blocking happens before the skill content is loaded into Claude Code's context. The developer sees the deny message immediately.
To configure policy:
- Go to Settings > Claude Code Policies in the dashboard
- Use the Allow / Warn / Block controls on the Agent Skills page, or edit the policy arrays directly
- Changes sync to the enforcement endpoint within 30 seconds (in-memory cache TTL)
Supported skill layouts
The scanner handles both layout conventions used in the Claude Code ecosystem:
Flat file (older format):
~/.claude/skills/
my-skill.md
Directory layout (current standard, used by most published skill packages):
~/.claude/skills/
my-skill/
SKILL.md ← case-insensitive: SKILL.md or skill.md both work
handler.ts ← optional, not scanned
Symlinks at any level are followed (find -L). If you manage skills via a dotfiles manager that symlinks ~/.agents/skills/ into ~/.claude/skills/, they are discovered correctly.
FAQ
How often does the scan run? Once per Claude Code session start. Not on a schedule, not on file change. If a developer installs a new skill mid-session, it appears in the inventory on the next session start.
Does it scan project-level skills?
Yes. If the working directory at session start contains a .claude/skills/ folder and is not the home directory, those skills are scanned with source label project.
Does blocking prevent a skill from being installed?
No. Blocking prevents invocation (/skill-name at the start of a prompt). The skill files remain on the workstation. Installation happens outside Claude Code's control.
What content is sent to Agent Keeper?
The first 500 bytes of each skill file, plus a SHA-256 hash of the full file. The full skill content is never sent. The preview is stored in the dashboard for the content preview panel. Plugin-installed skills (from ~/.claude/plugins/) are included alongside standalone skills in ~/.claude/skills/.
Can I see which hosts have a specific skill? Yes. Click any skill row to open the detail panel, it shows the full hostname list, first/last seen timestamps, and the complete skill content.
Where do I see which MCP servers my team has installed? The MCP Servers section at the bottom of the Agent Skills page lists every server found in Claude Code settings files across your fleet, discovered proactively at session start. For tool-level activity (which tools were actually called and with what input), see the MCP Skill Monitoring page.
Why is a skill showing a lower risk score than expected? Risk scoring runs only on the first 500 bytes of the SKILL.md. If the sensitive instructions appear later in the file, they are not scored. The SHA-256 hash is stored for drift detection, if the file changes between sessions, the hash changes, though no alert is fired automatically.
Does skill scanning affect session startup time? No. The scan runs in a background shell process. Claude Code does not wait for it to complete before starting the session.
The dashboard shows 0 skills but skills are installed on the workstation.
The most common cause is a missing AGENTKEEPER_API_KEY in ~/.agentkeeper/config. Without it, cc-session-start.sh exits before scanning. See Troubleshooting for a full checklist.
Troubleshooting
Skills not appearing in the dashboard
Work through these checks in order.
1. Confirm the API key is in ~/.agentkeeper/config
The cc-session-start.sh script reads AGENTKEEPER_API_KEY from this file. If the variable is missing, the script exits silently at startup and no skills are reported, there is no error message.
grep AGENTKEEPER_API_KEY ~/.agentkeeper/config
If the line is missing, add it (replace the placeholder with your actual key from Settings > API Keys):
echo 'AGENTKEEPER_API_KEY="ak_live_..."' >> ~/.agentkeeper/config
Then restart Claude Code. This is the most common cause of 0 skills discovered.
2. Confirm ~/.claude/skills/ is populated
The scanner only walks ~/.claude/skills/. If your skills live elsewhere (e.g., a dotfiles directory), they must be symlinked into ~/.claude/skills/, the scanner follows symlinks correctly.
find -L ~/.claude/skills -mindepth 2 -maxdepth 2 -name "SKILL.md" | wc -l
If this returns 0, there are no discoverable skills on this workstation.
3. Check whether the plugin's session-start is deferring
If the workstation has HTTP-based Agent Keeper hooks configured in ~/.claude/settings.json (the connected-mode setup), the plugin's session-start.sh detects them and defers, handing off to cc-session-start.sh instead. This is expected behaviour. The fix is to ensure cc-session-start.sh has a valid API key (step 1 above).
4. Verify the scan ran
After restarting Claude Code, check whether the checkin reached the API. The workstation's Last seen timestamp on the Claude Code page should update within a few seconds of session start. If it does not update, the hook is not firing, check that ~/.agentkeeper/cc-session-start.sh exists and is executable (chmod +x ~/.agentkeeper/cc-session-start.sh).
Related
- Plugin Reference, full hook configuration and install instructions
- Runtime Shield, the detection engine that enforces skill governance
- MCP Skill Monitoring, monitoring for
mcp__server__toolcalls (separate from slash-skills)