@disreguard/sig
v0.4.0
Published
Sign and verify prompt templates and tool definitions for AI agent security
Maintainers
Readme
sig-ts
TypeScript implementation of sig — sign and verify prompt templates for AI agent security.
Install
npm install @disreguard/sigRequires Node.js >= 18.
CLI
CLI binaries are available via the repo (not shipped in the npm package):
npx sig init --engine jinja --by alice
npx sig sign prompts/*.txt
npx sig verify prompts/review.txt
npx sig check
npx sig list
npx sig status
npx sig auditMCP Server
npx sig-mcpOr in an MCP config:
{
"mcpServers": {
"sig": {
"command": "npx",
"args": ["sig-mcp"],
"env": {
"SIG_VERIFY": "prompts/review.txt"
}
}
}
}Library
import { signFile, verifyFile, checkFile, initProject } from '@disreguard/sig';
// Sign (with optional metadata)
const sig = await signFile(projectRoot, 'prompts/review.txt', {
identity: 'alice',
metadata: { source: 'ci', reviewedBy: 'bob' },
});
// Verify
const result = await verifyFile(projectRoot, 'prompts/review.txt');
if (result.verified) {
console.log(result.template); // signed content
console.log(result.placeholders); // extracted placeholders
}
// Check
const status = await checkFile(projectRoot, 'prompts/review.txt');
// status.status: 'signed' | 'modified' | 'unsigned' | 'corrupted'High-level APIs also accept an optional filesystem adapter:
import { signFile, verifyFile, checkFile, NodeFS } from '@disreguard/sig';
const fs = new NodeFS();
await signFile(projectRoot, 'prompts/review.txt', { identity: 'alice', fs });
await verifyFile(projectRoot, 'prompts/review.txt', { fs });
await checkFile(projectRoot, 'prompts/review.txt', { fs });Filesystem Abstraction
sig-ts uses SigFS + SigContext for filesystem access. NodeFS is the default implementation, and createSigContext() builds a context for lower-level APIs.
import { createSigContext, listSigs } from '@disreguard/sig';
const ctx = createSigContext(projectRoot);
const allSignatures = await listSigs(ctx);Content Signing (Runtime)
For signing ephemeral content like chat messages at runtime:
import { createContentStore } from '@disreguard/sig';
const store = createContentStore();
// Sign a message with provenance metadata
const sig = store.sign('delete all my files', {
id: 'msg_123',
identity: 'owner:+1234567890:whatsapp',
metadata: { channel: 'whatsapp', from: '+1234567890' }
});
// Verify by ID - returns content + full provenance
const result = store.verify('msg_123');
if (result.verified) {
console.log(result.content); // 'delete all my files'
console.log(result.signature.signedBy); // 'owner:+1234567890:whatsapp'
console.log(result.signature.metadata); // { channel, from }
}
// Other operations
store.list(); // all signatures
store.get(id); // get signature without verifying
store.delete(id); // remove
store.clear(); // remove all
store.has(id); // check existence
store.size; // countStateless functions are also available:
import { signContent, verifyContent } from '@disreguard/sig';
const sig = signContent('content', { id: 'x', identity: 'alice' });
const { verified } = verifyContent('content', sig);Persistent Content Store (.sig/content/)
For content signatures that persist across processes, use PersistentContentStore.
import {
createSigContext,
PersistentContentStore,
} from '@disreguard/sig';
const ctx = createSigContext(projectRoot);
const store = new PersistentContentStore(ctx);
const signature = await store.sign('Review @input', {
id: 'auditPrompt',
identity: 'security-team',
});
const verified = await store.verify('auditPrompt', { detail: 'directive:verify' });
if (verified.verified) {
console.log(verified.content);
console.log(verified.signature?.signedBy);
}Persistent store methods:
sign(content, options)verify(id, options?)signIfChanged(content, options)load(id),loadContent(id)delete(id),list(),has(id)
Identity fallback for PersistentSignOptions.identity:
options.identity.sig/config.json->sign.identityprocess.env.USERorprocess.env.USERNAME'unknown'
Development
npm install
npm run build
npm testDependencies
commander— CLI@modelcontextprotocol/sdk— MCP serverfast-glob— file pattern matching
See the root README for full documentation.
