Skip to main content

Skill Ledger User Guide

Skill Ledger is the security subsystem of agent-sec-core that maintains a version chain of file hashes, scan results, and cryptographic signatures for AI Agent Skills, helping detect tampered Skills or injected malicious content. The default quick scan runs automatically via the built-in static scanner; an optional deep scan is driven by the Agent following the skill-vetter protocol.


Part 1: Quick Tour

Core Concepts

ConceptDescription
ManifestJSON record (.skill-meta/latest.json) containing file hashes, scan results, and digital signatures; created and updated by scan, certify, or the init baseline
Version chainAppend-only ledger — each non-root version names an authenticated parent through previousVersionId and previousManifestSignature; recovery can start a new signed chain segment
StatusPer-Skill security state: pass ✅ · none 🆕 · drifted 🔄 · warn ⚠️ · deny 🚨 · tampered 🔴

1. Initialize Signing Keys

# Initialize keys and build a quick-scan baseline for Skills in covered directories
agent-sec-cli skill-ledger init

Key locations:

FilePathPermissions
Private key file~/.local/share/agent-sec/skill-ledger/key.enc0600; unencrypted by default, encrypted with --passphrase
Public key~/.local/share/agent-sec/skill-ledger/key.pub0644

To protect the private key with a passphrase:

# Interactive passphrase prompt
agent-sec-cli skill-ledger init --passphrase

# Or via environment variable (suitable for CI)
SKILL_LEDGER_PASSPHRASE="your-secret" agent-sec-cli skill-ledger init --passphrase

2. Check Skill Integrity

agent-sec-cli skill-ledger check /path/to/your-skill

Outputs JSON; the key field is status:

StatusMeaning
none 🆕Neither latest.json nor any version JSON/snapshot artifact exists, or an authenticated matching manifest has scanStatus=none
passManifest authenticity valid + files unchanged + scan passed
drifted 🔄Manifest authenticity valid, but the live Skill differs from the signed file hashes; this is an unscanned divergence, not a scanner-confirmed risk verdict
warn ⚠️Manifest authenticity valid, but the last scan has low-risk findings
deny 🚨Manifest authenticity valid, but the last scan has high-risk findings
tampered 🔴Ledger metadata failed schema, hash, signature, signed-identity, or latest/version-artifact consistency validation, including a missing latest.json while version artifacts remain, a missing signature, or signed latest replay

Skill Ledger authenticates an existing manifest and binds latest.json to the newest verified version artifact before comparing its file hashes with the live Skill. A missing latest.json is none only when no version JSON or snapshot artifact remains; otherwise the incomplete ledger is tampered. A missing or invalid signature, or replay of an older signed latest pointer, is also tampered, even when the live files have changed; only a verified current manifest can produce drifted.

3. Quick Scan + Signed Certification

For a machine-readable, read-only assessment before certification, run:

agent-sec-cli skill-ledger analyze /path/to/your-skill --format json

analyze runs both code-scanner and static-scanner against the current directory. It does not create keys, .skill-meta, manifests, snapshots, signatures, configuration entries, or security events. It is suitable as an incremental signal for submission services, but does not replace their existing content rules or approval policy.

The process contract is:

Exit codeMeaning
0Coverage is complete; inspect status for pass, warn, or deny
1A scanner or file could not be covered; status=error and coverage_complete=false
2Invalid input or protocol usage, including a missing SKILL.md

Protocol errors include a missing Skill root argument (skill-root-required) and unsupported output formats (unsupported-format); both return exit code 2 with a JSON error payload.

Callers must check the exit code, top-level status, and coverage_complete. Findings are sorted by file, line, and rule; scanner results are always ordered as code-scanner, then static-scanner. The bundled JSON Schema is agent_sec_cli/skill_ledger/analyze.schema.json. Analysis accepts at most 2,000 regular files, 50 MiB of aggregate file content, and 32 directory levels. Exceeding a limit returns incomplete coverage.

Node.js subprocess example:

import { spawn } from "node:child_process";

const child = spawn(
"agent-sec-cli",
["skill-ledger", "analyze", skillDir, "--format", "json"],
{ stdio: ["ignore", "pipe", "pipe"] },
);

let stdout = "";
child.stdout.setEncoding("utf8");
child.stdout.on("data", (chunk) => {
stdout += chunk;
});
child.on("close", (code) => {
const result = JSON.parse(stdout);
if (code !== 0 || result.status === "error" || !result.coverage_complete) {
throw new Error("Skill analysis did not complete");
}
// Keep existing submission rules; consume result.scanners as extra evidence.
});

analyze currently ships in the complete agent-sec-cli wheel and RPM. A future packaging change may extract the shared scanners into a scanner-only wheel or RPM subpackage; the scanner rules must remain single-source.

The default certification path uses the built-in quick scanner and does not depend on an LLM. For a single Skill:

agent-sec-cli skill-ledger scan /path/to/your-skill

After scanning, re-check the status:

agent-sec-cli skill-ledger check /path/to/your-skill

For a more thorough semantic review, trigger a deep scan through the Agent. The Agent reads the built-in skill-vetter-protocol.md scanning protocol and reviews the target Skill file by file across four phases (origin verification → code review → permission boundary assessment → risk grading), writing results to a findings JSON file. Then pass the findings file to certify to complete signed certification:

agent-sec-cli skill-ledger certify /path/to/your-skill \
--findings /tmp/skill-vetter-findings-your-skill.json \
--scanner skill-vetter \
--delete-findings

scan runs the built-in quick scanner and signs the result into the ledger; certify only imports external findings. certify performs, in order:

  1. Authenticates any existing manifest, then verifies file consistency (automatically creates a new version if files changed or the manifest is invalid)
  2. Normalizes findings and merges them into the manifest's scans[] array
  3. Aggregates scanStatus (pass / warn / deny)
  4. Re-signs and writes .skill-meta/latest.json

An invalid or unsigned existing manifest is never signed in place and none of its scan results or decisions are inherited. Recovery creates a new version linked only to the newest historical version whose identity, hash, signature, and snapshot all verify. If no such parent exists, the new signed version starts a new chain segment with both previous-version fields set to null.

Example output:

{
"versionId": "v000002",
"scanStatus": "pass",
"newVersion": true,
"skillName": "your-skill"
}

4. View Overall Security Posture

# Overall skill-ledger system status (keys, config, health of all Skills)
agent-sec-cli skill-ledger status

# Include per-Skill detailed status
agent-sec-cli skill-ledger status --verbose

status outputs JSON with three sections:

SectionDescription
keysSigning key state (initialized, fingerprint, encrypted, number of archived keys)
configConfiguration summary (default directories, managedSkillDirs pattern count, registered scanners)
skillsAggregate health (discovered Skill count, per-status counts, overall health label)

health label meanings: healthy (no critical/attention statuses and not all none; may mix pass/none), unscanned (all none), attention (drifted/warn present), critical (deny/tampered/error present), empty (no registered Skills).

With --verbose, an additional results array contains detailed check results for each Skill.

5. Audit the Full Version Chain

Deep-verify all historical versions — schema, hash, signature, signed identity, and explicit parent links. A parent link must point to an earlier authenticated version and carry its exact signature; a signed version with both previous-version fields set to null is a valid chain-segment root. Invalid historical versions still make the overall audit fail.

agent-sec-cli skill-ledger audit /path/to/your-skill

# Also verify snapshot file hashes
agent-sec-cli skill-ledger audit /path/to/your-skill --verify-snapshots

The most natural way to use Skill Ledger is through natural-language requests to an AI Agent. A default "scan" performs the quick scan; the skill-vetter deep scan runs only when the user explicitly requests it, or confirms continuation after a quick scan:

RequestEffect
"Scan /path/to/skill"Quick-scan certification for the specified Skill
"Scan all skills"Batch quick scan of all Skills configured in config.json
"Deep scan /path/to/skill"File-by-file deep review per the skill-vetter protocol, then certification
"Check skill status"Output the status triage table only, without scanning

Skill workflow:

  • Phase 1 (environment preparation and status view): validates CLI and keys, resolves target Skills, outputs a triage table
  • Phase 2 (quick-scan certification): invokes the built-in code-scanner and static-scanner, then signs into the manifest
  • Phase 3 (optional deep scan): skill-vetter four-phase review — origin verification → code review → permission boundary assessment → risk grading — then writes to the version chain via certify --findings

Part 2: Protecting Skills via SkillFS Activation, User Decisions, and Host Hook Policies

Architecture Overview

Skill Ledger is recommended in combination with SkillFS: SkillFS captures Skill changes and notifies the Skill Ledger daemon to scan and refresh .skill-meta/activation.json/xattr. Host hooks/capabilities can still be mounted by default with policy = "ask"; the user is prompted when the unified exposure summary carries a message, and stays silent when there is no message or the user has already made a decision.

┌──────────────────────────────────────────────────┐
│ Agent runtime │
│ │
│ ┌──────────────┐ ┌──────────────────────┐ │
│ │ SkillFS │ │ skill-ledger │ │
│ │ change │ │ SKILL.md │ │
│ │ capture │ │ (on-demand deep │ │
│ │ │ │ │ scan) │ │
│ │ ▼ │ └──────────┬───────────┘ │
│ │ daemon notify │ │ │
│ │ │ │ │ │
│ │ ▼ │ │ │
│ │ activation │ │ │
│ │ refresh │ │ │
│ └──────┤────────┘ │ │
│ ▼ ▼ │
│ ┌──────────────────────────────────────────┐ │
│ │ agent-sec-cli skill-ledger │ │
│ │ show / export / decide / scan / certify │ │
│ └──────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ .skill-meta/latest.json │
│ .skill-meta/activation.json + xattr │
└───────────────────────────────────────────────────┘
  • Recommended path — SkillFS + daemon activation: SkillFS discovers Skill file changes; the daemon refreshes the executable activation target based on the latest signed manifest, user decisions, and the activation policy. The Agent runtime reads activation metadata instead of relying on host hook pre-checks by default.
  • Compatibility path — host hook/capability policy: OpenClaw, Hermes, copilot-shell, and Qwen Code call agent-sec-cli skill-ledger show before a Skill loads; Codex and Qoder CLI run a read-only agent-sec-cli skill-ledger check at their respective local Skill trigger boundaries. The default is ask; observe / warn / block can be configured explicitly, and legacy debug remains an alias for observe.
  • Agent-driven scanning: scan runs the built-in quick scan and signs the result; the skill-ledger Skill drives the full four-phase security review when the user requests a deep scan, importing results via certify --findings. Triggered on demand, initiated by user request.

How it works:

With SkillFS enabled, the runtime entry point of Skill Ledger is handled by the daemon:

  1. SkillFS captures Skill directory creation, updates, deletion, or content changes.
  2. SkillFS notifies the Skill Ledger daemon's skill_ledger.skillfs_notify_change interface.
  3. The daemon refreshes .skill-meta/activation.json based on the signed manifest, current file state, user decisions, and the activation policy, and writes xattr on a best-effort basis.
  4. If the current version cannot be activated directly, the activation metadata points to the previous trusted pass / warn snapshot; if no trusted fallback exists, it points to a safe pending-review stub; target: null is written only for user block decisions or fail-safe scenarios.

Version requirement: SkillFS must be 0.4.0 or newer.

Since 0.4.0, the skill_ledger.skillfs_notify_change call in step 2 uses notify v2, whose business payload carries exactly four fields: canonicalSkillDir, skillId, eventKind, and paths. This is a breaking upgrade with no fallback path — the daemon rejects any request whose schemaVersion is not 2, and SkillFS performs no version negotiation. The two components must therefore be upgraded together:

  • SkillFS older than 0.4.0 sends notify v1 only, which the current daemon rejects request by request;
  • a failed notify delivery is only a warning on the SkillFS side and never stops the FUSE service.

A version mismatch therefore fails silently: newly installed Skills stay hidden and neither side reports an obvious error. When diagnosing, first confirm that skillfs --version is 0.4.0 or newer.

Two sockets, opposite directions. Most joint-deployment wiring mistakes come from conflating them:

SocketListenerDefault pathPurpose
daemon socketagent-sec-core daemon$XDG_RUNTIME_DIR/agent-sec-core/daemon.sock (override with AGENT_SEC_DAEMON_SOCKET)SkillFS points --notify-socket here to send change notifications
control socketSkillFS/run/user/<uid>/skillfs/control.sockThe daemon queries skill.resolveLiveSource back through it and writes activation metadata

Do not customize the control socket path. The Ledger resolver client only probes the default path above; no configuration key makes it follow a path given to --control-socket, and changing it makes Ledger silently fall back to host mode. SkillFS and the daemon must also run under the same effective UID.

Under the Hermes layout the activation flow carries nested identities (category/skill) rather than flat skill names, and skillId keeps both components.

For the full protocol definition, canonical path semantics, and deployment boundaries, see Skill Ledger's SkillFS integration design (Chinese only) and the SkillFS user guide.

Unified Host Hook Controls

Host adapters use SKILL_LEDGER_HOOK_ENABLED as the kill switch and SKILL_LEDGER_MODE as the behavior selector. The switch defaults to true; the policy defaults to ask and accepts observe, warn, ask, or block. observe runs the check and audit path without a user-visible message. Legacy debug maps to observe, while legacy deny maps to block. An environment policy overrides Hermes or OpenClaw capability configuration.

The host Agent reads these variables when it loads the plugin. Restart the Agent process that hosts the hook after changing them; the hook and agent-sec-core are not separate policy services.

When a hook cannot request approval, ask falls back to warn. When a hook cannot enforce a block at its current boundary, block also falls back to warn and must not claim enforcement. Set SKILL_LEDGER_HOOK_ENABLED=false to skip input processing, key initialization, and CLI calls.

Compatibility Path: Hook / Capability Policy

When the Agent loads a Skill, the OpenClaw, Hermes, copilot-shell, and Qwen Code hooks resolve the Skill directory, run agent-sec-cli skill-ledger show <skill_dir>, and let the unified policy control the host-specific behavior. These hooks consume only the message in the summary:

PolicyBehavior
observemessage != null only writes audit/debug diagnostics and passes.
warnmessage == null passes silently; message != null shows a warning and passes.
askDefault. message == null passes silently; message != null requests user confirmation or uses the host approval UI.
blockmessage != null blocks directly, using the message as the reason or alert text.

The trigger rules for message are decided uniformly by Skill Ledger: no prompt when the user already has an allow / always_allow / rollback / block decision; no prompt when latest is pass or warn and directly exposable; a prompt when there is no user decision and latest is deny / none / drifted / tampered, explaining whether the current active version is a fallback or a safe pending-review stub. latestStatus=unmanaged means the daemon cannot manage this root and cannot write .skill-meta or record user decisions, so it is returned as diagnostics only with message=null, and every hook policy including block passes silently.

Codex and Qoder CLI are low-level integrity gates that run skill-ledger check <skill_dir> after canonical-path and root-boundary validation. Codex resolves $skill-name references at UserPromptSubmit; because that boundary cannot request approval, ask falls back to warn. Qoder CLI registers a dedicated PreToolUse hook for the Skill tool, builds user → project directory tables from the absolute cwd in the event, and parses the SKILL.md frontmatter name (falling back to the directory name when frontmatter is absent). When Qoder frontmatter exists but name is missing, ambiguous, or uses a YAML scalar the hook cannot safely parse, the call is not downgraded to a non-local Skill — it is handled per the current policy. pass passes silently; none / drifted / warn / deny / tampered and error are audited silently, warned and passed, sent for confirmation where supported, or blocked per the observe / warn / ask / block policy. Qoder CLI unavailability, execution failure, timeout, or unparseable output is also handled by this four-level policy rather than a fixed fail-open; legacy debug is only an alias for observe.

All six adapters enable Skill Ledger by default with policy ask; copilot-shell, Codex, Qoder CLI, and Qwen Code register their corresponding hook boundaries in their default manifests. OpenClaw and Hermes can also take capability configuration, while SKILL_LEDGER_MODE remains the deployment-level override. Apart from the explicitly documented Qoder CLI low-level gate above, the other compatibility hooks remain fail-open when the CLI infrastructure misbehaves, avoiding blocked Skill loads.

The copilot-shell hook currently covers three directory classes — project / user / system: <cwd>/.copilot-shell/skills/, ~/.copilot-shell/skills/, and the RPM and raw-install system roots /usr/share/anolisa/skills/ and /usr/local/share/anolisa/skills/. Skills from custom, extension, remote, or other paths make the hook fail open and skip the skill-ledger check; the OpenClaw plugin extracts the Skill directory from the SKILL.md path it reads.

For batch certification or post-install certification, complete directory resolution and certification before letting the Agent read uncertified Skill content: avoid proactively reading an uncertified Skill's SKILL.md or auxiliary files before batch certification; after a successful install, locate the final local directory, confirm it contains SKILL.md, then run quick-scan certification.

Enabling in OpenClaw:

{
"capabilities": {
"skill-ledger": {
"enabled": true,
"policy": "ask"
}
}
}

Enabling in Hermes:

[capabilities.skill-ledger]
enabled = true
timeout = 5
policy = "ask"
enable_block = false

Configuring copilot-shell: the default Cosh manifest already registers the skill-ledger hook. The default policy is ask; for observe-only, warning-only, or hard denial, set SKILL_LEDGER_MODE=observe / warn / block. The debug value remains an alias for observe. This environment variable should be set by a trusted host or deployment environment — not by Skills, project scripts, or untrusted shell startup logic; to prevent policy downgrades via a tampered local shell profile, it should eventually move to a trusted host configuration source.

Configuring Qoder CLI: after installing qoder-plugin, the plugin automatically registers a PreToolUse hook with matcher Skill. The default policy is ask; a trusted launch environment may set SKILL_LEDGER_MODE=observe / warn / block and adjust the CLI timeout via SKILL_LEDGER_TIMEOUT (default 5 seconds). The debug value remains an alias for observe. The hook covers local Skills under ~/.qoder/skills/ and <cwd>/.qoder/skills/, with user-level Skills of the same name taking precedence; only when both directory tables resolve trustworthily with no match is the call treated as a built-in, plugin, or remote Skill — passed and logged at debug. The hook never runs init or scan automatically. A Skill with neither latest.json nor any version JSON/snapshot artifact enters the policy as none. A missing latest.json while history remains, or an existing latest manifest with a missing or invalid signature, enters as tampered. After review, run agent-sec-cli skill-ledger scan <skill_dir> explicitly.

The global Skill Ledger activationPolicy belongs to SkillFS/daemon activation; the hook policy here only controls the user-visible behavior and log level of host hooks/capabilities.

Reviewing and Deciding on Non-Pass Skills

When a hook or show indicates the current skill needs user review, start with the unified exposure summary:

agent-sec-cli skill-ledger show /path/to/skill

Key fields:

FieldMeaning
latestStatusStatus of the latest skill root or the latest signed version
activeVersionIdVersion currently exposed to SkillFS; null means no real active version
targetTarget SkillFS currently reads; pending state points to .skill-meta/versions/__pending_decision__.snapshot
userDecisionCurrently matched user decision; null means no decision yet
messageInformation to surface to the user; hooks stay silent when null

To fully review a version that is not exposed, export the latest snapshot, manifest, and findings:

agent-sec-cli skill-ledger export /path/to/skill --version latest --output /tmp/skill-review

After review, choose via the unified decide command:

# Allow the current specific version; not inherited by future versions
agent-sec-cli skill-ledger decide /path/to/skill --action allow --reason "reviewed manually"

# Allow current and future versions until the user changes or clears the decision
agent-sec-cli skill-ledger decide /path/to/skill --action always_allow --reason "trusted source"

# Fully hide the current skill; the block is not inherited by future new versions
agent-sec-cli skill-ledger decide /path/to/skill --action block --reason "unsafe behavior"

# Roll back to a specific version; without --version, defaults to the current real active version
agent-sec-cli skill-ledger decide /path/to/skill --action rollback --version v000001 --reason "use previous trusted version"

# Clear the user decision on the latest manifest, restoring global activation behavior
agent-sec-cli skill-ledger decide /path/to/skill --clear

Note: a hook's ask confirmation only lets the current host operation continue — it is not equivalent to a Skill Ledger allow. Only decide changes the subsequent activation target.

Agent-Driven Deep Scan

Configuring Skill Directories (for batch scans)

Six built-in directories are included by default: ~/.openclaw/skills/*, ~/.copilot-shell/skills/*, ~/.hermes/skills/**, ~/.qoder/skills/*, /usr/share/anolisa/skills/*, /usr/local/share/anolisa/skills/*. Project-level Qoder directories are not relative defaults; after an explicit scan or certify on a project Skill, its absolute directory is written to managedSkillDirs via the auto-memoization mechanism. To add other directories, create or edit ~/.config/agent-sec/skill-ledger/config.json:

{
"enableDefaultSkillDirs": true,
"managedSkillDirs": [
"/opt/custom-skills/*",
"/opt/custom-skills/my-skill"
]
}

Default directories are enabled by default; managedSkillDirs holds directories dynamically managed by skill-ledger or added by the user, appended after the defaults (deduplicated automatically). Set enableDefaultSkillDirs to false for isolated runs.

  • "path/*" — glob pattern: each subdirectory containing SKILL.md counts as one Skill
  • "path/to/skill" — a single Skill directory (must also contain SKILL.md)

Non-existent directories are silently ignored. Additionally, running scan or certify on a Skill auto-appends unregistered directories to the config for later --all batch operations. check is a read-only status query and never writes config.

Scheduled Default Quick Scans

To periodically refresh default quick-scan results, put scan --all into cron. scan --all automatically skips Skills whose files are unchanged and already have complete scan results, re-scanning only new, changed, scan-result-missing, or manifest-anomalous Skills.

Without a key passphrase:

mkdir -p "$HOME/.local/state/agent-sec"
AGENT_SEC_CLI="$(command -v agent-sec-cli)"
CRON_LINE="0 3 * * * $AGENT_SEC_CLI skill-ledger scan --all >> $HOME/.local/state/agent-sec/skill-ledger-scan.log 2>&1"
(crontab -l 2>/dev/null | grep -Fv "skill-ledger scan --all"; echo "$CRON_LINE") | crontab -

With a passphrase-protected private key, the scheduled job needs SKILL_LEDGER_PASSPHRASE. The command below writes the passphrase in plaintext to the current user's crontab and the system cron spool — use it only in trusted single-user environments; safer alternatives are the default passphrase-less key, or wrapping scan --all with a local secret manager / permission-restricted file.

read -rsp "SKILL_LEDGER_PASSPHRASE: " SKILL_LEDGER_PASSPHRASE; echo
mkdir -p "$HOME/.local/state/agent-sec"
AGENT_SEC_CLI="$(command -v agent-sec-cli)"
CRON_LINE="0 3 * * * SKILL_LEDGER_PASSPHRASE='$SKILL_LEDGER_PASSPHRASE' $AGENT_SEC_CLI skill-ledger scan --all >> $HOME/.local/state/agent-sec/skill-ledger-scan.log 2>&1"
(crontab -l 2>/dev/null | grep -Fv "skill-ledger scan --all"; echo "$CRON_LINE") | crontab -
unset SKILL_LEDGER_PASSPHRASE

Inspect installed scheduled jobs:

crontab -l

Triggering Scans

Just instruct the Agent in natural language. The default scan runs Phase 1 → Phase 2; Phase 1 → Phase 3 runs when the user explicitly requests a deep scan.

Deep-scan rule table (skill-vetter):

LevelRule IDDetection Target
denydangerous-execDangerous process execution (child_process, subprocess)
denydynamic-code-evalDynamic code execution (eval(), new Function())
denyenv-harvestingBulk environment variable harvesting + network exfiltration
denycrypto-miningMining signatures (stratum, xmrig, etc.)
denycredential-accessCredential and sensitive file access (~/.ssh/, .env)
denysystem-modificationSystem file tampering (/etc/, crontab)
denyprompt-overridePrompt-override instructions
denyhidden-instructionHidden instructions (zero-width characters, HTML comments)
warnobfuscated-codeCode obfuscation (very long lines, base64 + decode)
warnsuspicious-networkSuspicious network connections (direct IPs, non-standard ports)
warnexfiltration-patternData exfiltration patterns (file read + network send combos)
warnagent-data-accessAgent identity data access (MEMORY.md, etc.)
warnunauthorized-installUndeclared package installation
warnunrestricted-tool-useUnconstrained tool-use instructions
warnexternal-fetch-execExternal fetch-and-execute (curl | bash)
warnprivilege-escalationPrivilege escalation (sudo, chmod 777)

Real-World Scenarios

Scenario A: Detecting tampering when loading a third-party Skill

# SkillFS/daemon or host hook detects an anomalous status
[skill-ledger] 🚨 Skill 'third-party-tool' metadata signature verification failed

The alert indicates someone may have modified the manifest, flipping scanStatus from deny to pass to bypass security checks.

Scenario B: Detecting drift after a Skill update

agent-sec-cli skill-ledger check /path/to/my-skill
# → {"status": "drifted", "added": [...], "modified": [...]}

The status becomes drifted after updating the Skill. This only reports that the live root differs from the signed version; it is not a scanner-confirmed risk result. Trigger a re-scan to certify the new content and obtain its current scan status:

Scan /path/to/my-skill

Scenario C: Auditing historical integrity

agent-sec-cli skill-ledger audit /path/to/my-skill --verify-snapshots

Per-version verification: schema → hash integrity → signature validity → signed identity → explicit parent links → snapshot consistency.


Command Cheat Sheet

CommandPurpose
agent-sec-cli skill-ledger initInitialize keys and build a quick-scan baseline for covered Skills
agent-sec-cli skill-ledger init --no-baselineInitialize keys only, without scanning Skills
agent-sec-cli skill-ledger check <dir>Check integrity status (JSON output)
agent-sec-cli skill-ledger show <dir>Show latest, active, user decision, activation target, findings, and alerts
agent-sec-cli skill-ledger export <dir> --version latest --output <path>Export a snapshot, manifest, and findings for full review
agent-sec-cli skill-ledger decide <dir> --action allow|always_allow|block|rollbackRecord a user decision and refresh activation
agent-sec-cli skill-ledger decide <dir> --clearClear the user decision on the latest manifest
agent-sec-cli skill-ledger scan <dir>Run a quick scan and sign it into the manifest
agent-sec-cli skill-ledger scan --allGap-filling quick scan across all discovered Skills
agent-sec-cli skill-ledger certify <dir> --findings <file>Sign deep-scan findings into the manifest
agent-sec-cli skill-ledger statusOverall security posture (keys, config, Skill health)
agent-sec-cli skill-ledger status --verboseOverall posture including per-Skill detailed results
agent-sec-cli skill-ledger audit <dir>Deep-verify the version chain
agent-sec-cli skill-ledger list-scannersList registered scanners

Key Paths

PathPurpose
~/.local/share/agent-sec/skill-ledger/key.encPrivate key file (unencrypted by default, encrypted with --passphrase)
~/.local/share/agent-sec/skill-ledger/key.pubPublic key
~/.local/share/agent-sec/skill-ledger/keyring/Archived historical public keys (after key rotation)
~/.config/agent-sec/skill-ledger/config.jsonConfiguration file (managedSkillDirs, scanners)
<skill_dir>/.skill-meta/latest.jsonCurrent manifest (written by scan, certify, or the init baseline)
<skill_dir>/.skill-meta/versions/Version chain history