# How the Agent-Skills Lockfile System Ensures Skill Integrity and Prevents Tampering

> Discover how the Agent-Skills lockfile system secures skill integrity. Learn about atomic operations, crypto hashes, Zod validation, and versioned migrations to prevent tampering.

- Repository: [TechLeads.club 💎/agent-skills](https://github.com/tech-leads-club/agent-skills)
- Tags: internals
- Published: 2026-05-18

---

**The Agent-Skills repository uses atomic file operations, cryptographic hashes, strict Zod schema validation, and versioned migrations in [`.skill-lock.json`](https://github.com/tech-leads-club/agent-skills/blob/main/.skill-lock.json) to guarantee that skill metadata cannot be silently corrupted or altered without detection.**

The `tech-leads-club/agent-skills` repository manages complex agent configurations through a centralized lockfile system that safeguards every installation. By combining cryptographic verification with defensive file operations, the lockfile system ensures skill integrity and prevents tampering across both global and project-scoped environments.

## Core Integrity Mechanisms

The lockfile implementation in [`libs/core/src/lib/services/lockfile.service.ts`](https://github.com/tech-leads-club/agent-skills/blob/main/libs/core/src/lib/services/lockfile.service.ts) employs multiple defensive layers to maintain an immutable record of installed skills.

### Strict Zod Schema Validation

Every lockfile undergoes parsing against the `SkillLockFileSchema` which defines required fields, strict types, and allowed enum values. When `readSkillLock` executes, any invalid or malformed data immediately triggers a fallback to an empty lockfile rather than propagating corruption downstream.

This validation occurs at lines 14-31 of [`lockfile.service.ts`](https://github.com/tech-leads-club/agent-skills/blob/main/lockfile.service.ts), ensuring that only well-formed entries ever persist to disk.

### Versioned Migration for Forward Compatibility

The lockfile carries a `version` number that enables safe schema evolution. When `migrateLockFile` detects an older version (such as v1), it automatically upgrades the structure to the current schema (v2) and injects missing defaults for fields like `method` and `global`.

This mechanism, implemented at lines 49-71, guarantees that legacy files cannot hide unexpected fields or bypass modern validation requirements.

### Content-Hash Tracking for Tamper Detection

When `addSkillToLock` records a new skill (lines 62-68), it optionally stores a `contentHash` representing the SHA-256 digest of the skill's source files. Consumers can later recompute this hash and compare it against the stored value to detect any manual tampering of skill files after installation.

### Atomic Writes with Backup Protection

The `writeSkillLock` function implements a crash-resistant write pattern at lines 17-33:

1. Writes new data to a temporary `<lock>.tmp` file
2. Backs up the previous lockfile to `.skill-lock.json.backup`
3. Renames the temporary file into place atomically

If any step fails, the temporary file is cleaned up and the original lockfile remains untouched, eliminating partial-write corruption risks. This pattern extends to deletion operations through `removeAgentFromLock` and `removeSkillFromLock` (lines 106-133), ensuring that all mutations follow the same atomic path.

## Scope Isolation and Error Resilience

Beyond integrity checks, the system implements safeguards against accidental scope pollution and corruption scenarios.

### Separate Global and Project Scopes

The `getSkillLockPath` helper (lines 33-37) resolves lockfile locations based on the `global` flag, preventing cross-scope overwrites. Project-scoped skills write to [`.agents/.skill-lock.json`](https://github.com/tech-leads-club/agent-skills/blob/main/.agents/.skill-lock.json) within the repository, while global installations target `~/.agent-skills/.skill-lock.json`.

### Graceful Degradation on Corruption

If the lockfile is unreadable, missing, or corrupted, `readSkillLock` (lines 91-100) returns a fresh empty lockfile instead of throwing exceptions. This allows CLI operations to continue while maintaining a known-good state, with the backup copy (`.skill-lock.json.backup`) available for manual restoration if needed.

## Practical Implementation Examples

The following patterns demonstrate how to interact with the integrity safeguards programmatically.

```typescript
// Add a new skill with cryptographic hash for integrity verification
await addSkillToLock(
  ports,
  'accessibility',
  ['cursor', 'claude-code'],
  {
    source: 'https://github.com/tech-leads-club/skills/accessibility',
    contentHash: 'a3f5e2...', // SHA-256 of the skill bundle
    method: 'symlink',
    global: false,
    version: '1.0.0',
  },
);

```

```typescript
// Verify a skill's integrity by comparing stored hash against current files
import { createHash } from 'node:crypto';
import { readFile } from 'node:fs/promises';

async function verifySkill(ports, skillName) {
  const entry = await getSkillFromLock(ports, skillName);
  if (!entry?.contentHash) return true; // No hash stored → skip check

  const skillPath = join(ports.env.homedir(), '.../skills', skillName);
  const data = await readFile(skillPath);
  const actualHash = createHash('sha256').update(data).digest('hex');

  return actualHash === entry.contentHash;
}

```

```typescript
// Safely read lockfile with automatic fallback on corruption
const lock = await readSkillLock(ports, /* global */ false);
console.log('Installed skills:', Object.keys(lock.skills));

```

## Summary

- **Schema validation** through `SkillLockFileSchema` rejects malformed entries before they reach persistent storage.
- **Versioned migrations** ensure legacy lockfiles upgrade safely while preventing hidden field injection.
- **SHA-256 content hashes** enable cryptographic verification of skill files against tampering.
- **Atomic writes** with backup creation eliminate partial-write corruption and preserve historical state.
- **Scope isolation** via `getSkillLockPath` prevents accidental overwrites between global and project contexts.
- **Graceful degradation** allows continued operation even when lockfiles are corrupted or missing.

## Frequently Asked Questions

### What happens if someone manually edits the lockfile?

The `SkillLockFileSchema` validation in `readSkillLock` will reject malformed entries on the next read operation, triggering a fallback to an empty lockfile. This prevents corrupted edits from affecting runtime behavior while preserving the backup copy at `.skill-lock.json.backup` for inspection.

### How does the system handle concurrent installations?

The `writeSkillLock` function uses atomic file operations: it writes to a temporary file first, then renames it into place. This ensures that at most one complete version ever exists on disk, eliminating race conditions where concurrent processes might produce partially written or interleaved data.

### Where does the lockfile store its backup copy?

According to [`libs/core/src/lib/constants.ts`](https://github.com/tech-leads-club/agent-skills/blob/main/libs/core/src/lib/constants.ts), the system creates backups using the pattern `.skill-lock.json.backup` in the same directory as the original lockfile. This applies to both project-scoped paths (`.agents/.skill-lock.json.backup`) and global locations (`~/.agent-skills/.skill-lock.json.backup`).

### Can the lockfile detect if skill source files were modified after installation?

Yes, when skills are added via `addSkillToLock`, the optional `contentHash` field stores a SHA-256 digest of the skill's source files. Verification tools can recompute this hash and compare it against the stored value to detect any post-installation tampering or accidental modification.