@haldir/sdk
v0.1.1
Published
Haldir SDK — skill verification for agent platforms and runtimes
Maintainers
Readme
@haldir/sdk
High-level SDK for integrating Haldir verification into agent platforms.
What This Package Does
Provides a simple, batteries-included API for verifying agent skills. Wraps @haldir/core with sensible defaults, automatic key management, and multi-signature support.
Installation
npm install @haldir/sdkQuick Start
import { Haldir } from '@haldir/sdk';
// Initialize with trusted keys
const haldir = new Haldir({
trustedKeys: {
'publisher-2026': 'ed25519:AAAA...',
'haldir-prod-2026': 'ed25519:BBBB...'
}
});
// Verify a skill before installation
const result = await haldir.verify('./skills/my-skill/', {
context: 'install',
revocationList,
cachedSequenceNumber: 41
});
if (result.valid) {
console.log(`✓ Verified by ${result.keyId}`);
console.log(` Trust: ${result.trustLevel}`);
console.log(` Vetting: ${result.vettingReport?.overall_status || 'none'}`);
// Safe to load skill
} else {
console.log(`✗ Verification failed: ${result.errors[0].message}`);
// DO NOT load skill
}API
Constructor
const haldir = new Haldir(options);Options:
interface HaldirOptions {
// Ed25519 trusted keys (keyId → public key PEM)
trustedKeys?: Record<string, string>;
// Sigstore trusted identities (issuer=subject format)
trustedIdentities?: string[];
// Revocation list signing keys (keyId → public key PEM)
revocationKeys?: Record<string, string>;
// Enable auto-update of revocation list
autoUpdateRevocations?: boolean;
// Revocation list URL
revocationListUrl?: string;
}Methods
verify(skillPath, options?)
Verifies a skill directory.
Options:
interface VerifyOptions {
// Verification context
context?: 'install' | 'runtime'; // default: 'install'
// Revocation list (optional)
revocationList?: RevocationList;
// Cached sequence number (skip if list unchanged)
cachedSequenceNumber?: number;
// Override trusted keys for this verification
trustedKeys?: Record<string, string>;
}Returns: Promise<VerificationResult>
interface VerificationResult {
valid: boolean;
trustLevel: 'full' | 'degraded' | 'none';
keyId?: string;
warnings: Warning[];
errors: Error[];
attestation?: Attestation;
permissions?: Permissions;
vettingReport?: VettingReport;
}autoVerify(skillPath, options?)
Auto-detects Ed25519 or Sigstore and verifies accordingly.
const result = await haldir.autoVerify('./my-skill/', {
context: 'install'
});verifySigstore(skillPath, options?)
Verifies a Sigstore-signed skill.
const result = await haldir.verifySigstore('./my-skill/', {
trustedIdentities: ['https://github.com/login/[email protected]'],
context: 'install'
});Usage Patterns
Pre-Install Verification (Fail-Closed)
async function installSkill(skillPath: string) {
const result = await haldir.verify(skillPath, {
context: 'install',
revocationList: await fetchRevocationList()
});
if (!result.valid) {
throw new Error(`Skill verification failed: ${result.errors[0].message}`);
}
if (result.trustLevel !== 'full') {
throw new Error(`Insufficient trust level: ${result.trustLevel}`);
}
// Safe to load
await loadSkill(skillPath, result.permissions);
}Runtime Verification (Fail-Open with Grace)
async function checkInstalledSkill(skillPath: string) {
const result = await haldir.verify(skillPath, {
context: 'runtime',
revocationList: cachedRevocationList
});
if (!result.valid) {
console.error(`Skill ${skillPath} is no longer valid`);
await unloadSkill(skillPath);
return;
}
if (result.trustLevel === 'degraded') {
console.warn(`Skill ${skillPath} has degraded trust (stale revocation list)`);
// Still OK to run, but schedule re-check
}
if (result.warnings.length > 0) {
console.warn(`Warnings for ${skillPath}:`, result.warnings);
}
}Multi-Signature (Dual-Sign)
const haldir = new Haldir({
trustedKeys: {
// Trust EITHER publisher OR authority
'publisher-alice': 'ed25519:AAAA...',
'haldir-authority': 'ed25519:BBBB...'
}
});
// Verifies successfully if ANY trusted key signed
const result = await haldir.verify('./skill/');
// Both signatures present? Check attestation
if (result.attestation?.signatures?.length === 2) {
console.log('Dual-signed by publisher + authority');
}Sigstore Keyless Verification
const haldir = new Haldir({
trustedIdentities: [
// Trust specific GitHub repo
'https://token.actions.githubusercontent.com=https://github.com/org/repo/.github/workflows/sign.yml@refs/heads/main',
// Trust Google account
'https://[email protected]'
]
});
const result = await haldir.verifySigstore('./skill/', {
context: 'install'
});Vetting Report Transparency
const result = await haldir.verify('./skill/', { context: 'install' });
if (result.vettingReport) {
console.log(`Vetting status: ${result.vettingReport.overall_status}`);
console.log(`Pipeline version: ${result.vettingReport.pipeline_version}`);
console.log(`Vetted at: ${result.vettingReport.vetting_timestamp}`);
for (const layer of result.vettingReport.layers) {
console.log(`Layer ${layer.layer} (${layer.name}): ${layer.status}`);
if (layer.findings.length > 0) {
console.log(` ${layer.findings.length} findings`);
}
}
if (result.vettingReport.publisher_note) {
console.log(`Publisher note: ${result.vettingReport.publisher_note}`);
}
}Integration Examples
Express Middleware
import { Haldir } from '@haldir/sdk';
const haldir = new Haldir({ trustedKeys: TRUSTED_KEYS });
function verifySkillMiddleware(req, res, next) {
const skillPath = req.body.skillPath;
haldir.verify(skillPath, { context: 'install' })
.then(result => {
if (result.valid) {
req.verification = result;
next();
} else {
res.status(403).json({ error: result.errors[0].message });
}
})
.catch(err => {
res.status(500).json({ error: err.message });
});
}Agent Skill Loader
class SkillManager {
private haldir: Haldir;
constructor() {
this.haldir = new Haldir({
trustedKeys: PRODUCTION_KEYS,
revocationListUrl: 'https://haldir.ai/.well-known/haldir-revocation.json'
});
}
async loadSkill(skillPath: string) {
const result = await this.haldir.verify(skillPath, {
context: 'install',
revocationList: await this.fetchRevocationList()
});
if (!result.valid) {
throw new Error(`Verification failed: ${result.errors[0].code}`);
}
// Enforce permissions from attestation
await this.enforcePermissions(skillPath, result.permissions);
// Load skill
return await this.importSkill(skillPath);
}
}Error Handling
try {
const result = await haldir.verify('./skill/');
if (!result.valid) {
// Verification failed - check errors
for (const error of result.errors) {
switch (error.code) {
case 'E_NO_VAULT':
console.error('Skill not signed');
break;
case 'E_SIGNATURE_INVALID':
console.error('Invalid signature');
break;
case 'E_INTEGRITY_MISMATCH':
console.error(`File tampered: ${error.file}`);
break;
case 'E_REVOKED':
console.error('Skill revoked');
break;
default:
console.error(error.message);
}
}
}
// Check warnings (non-fatal)
for (const warning of result.warnings) {
console.warn(`${warning.code}: ${warning.message}`);
}
} catch (err) {
// Unexpected errors (filesystem, parsing, etc.)
console.error('Verification error:', err);
}TypeScript Support
Full TypeScript types included:
import type {
Haldir,
HaldirOptions,
VerifyOptions,
VerificationResult,
TrustLevel,
ErrorCode,
WarningCode
} from '@haldir/sdk';Performance
- Typical verification: 50-100ms
- Large skills (10K files): <5s
- Revocation check: <10ms (in-memory)
- Sigstore verification: 200-500ms (includes Rekor lookup)
See Also
- @haldir/core - Low-level crypto primitives
- @haldir/cli - Command-line interface
- SPEC.md - Full specification
- Root README - Quick start guide
License
Apache 2.0
