Docs

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.sh run as a type: "command" SessionStart hook. This path requires AGENTKEEPER_API_KEY to be set in ~/.agentkeeper/config (see Troubleshooting).

Both emit the same POST /api/v1/claude-code/checkin payload. The scanner walks these skill sources:

LocationSource labelWhen scanned
~/.claude/skills/globalAlways
$cwd/.claude/skills/projectOnly 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: global or project
  • 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:

FlagWhat it detectsScore
credential_accesssecret, token, password, api_key+40
destructive_opsrm -rf, delete all, format disk+35
bash_commands```bash, Bash tool calls, shell_command+30
code_executioneval(), exec(), subprocess, os.system+30
package_installpip install, npm install, brew install+25
network_accesscurl, wget, WebFetch, https:// URLs+20
file_writeWrite tool calls, write file, create file+20

Scores are additive, capped at 100:

LevelScore range
Low0 – 25
Medium26 – 50
High51 – 75
Critical76 – 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 mcpServers in Claude Code settings (e.g., postgres, github)
  • Type: transport type: stdio, HTTP, or SSE
  • Command: the binary that runs the server (basename only, no args or environment variables are captured)
  • Source: global (from ~/.claude/settings.json) or project (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:

  1. Detects the slash-skill invocation (regex match at prompt start)
  2. Checks blocked_agent_skills, if matched, denies the invocation with: Blocked by Agent Keeper org policy: skill /name is not allowed
  3. 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:

  1. Go to Settings > Claude Code Policies in the dashboard
  2. Use the Allow / Warn / Block controls on the Agent Skills page, or edit the policy arrays directly
  3. 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