Getting Started with SchemaPin¶
This guide walks you through installing SchemaPin, generating keys, signing a tool schema, and verifying it — in Python, JavaScript, Go, and Rust.
Installation¶
Python (PyPI)¶
CLI tools included: schemapin-keygen, schemapin-sign, schemapin-verify.
JavaScript (npm)¶
Go¶
CLI tools: go install github.com/ThirdKeyAi/schemapin/go/cmd/...@v1.3.0
Rust (Cargo)¶
Step 1: Generate a Key Pair¶
SchemaPin uses ECDSA P-256 exclusively. Generate a keypair in any language:
Python¶
from schemapin.crypto import KeyManager
private_key, public_key = KeyManager.generate_keypair()
private_key_pem = KeyManager.export_private_key_pem(private_key)
public_key_pem = KeyManager.export_public_key_pem(public_key)
JavaScript¶
import { KeyManager } from 'schemapin';
const { privateKey, publicKey } = KeyManager.generateKeypair();
const privateKeyPem = KeyManager.exportPrivateKeyPem(privateKey);
const publicKeyPem = KeyManager.exportPublicKeyPem(publicKey);
Go¶
import "github.com/ThirdKeyAi/schemapin/go/pkg/crypto"
km := crypto.NewKeyManager()
privKey, pubKey, err := km.GenerateKeypair()
privPem, _ := km.ExportPrivateKeyPEM(privKey)
pubPem, _ := km.ExportPublicKeyPEM(pubKey)
Rust¶
use schemapin::crypto::generate_key_pair;
let key_pair = generate_key_pair()?;
// key_pair.private_key_pem — PEM-encoded private key
// key_pair.public_key_pem — PEM-encoded public key
CLI¶
Step 2: Sign a Tool Schema¶
Schemas are canonicalized (sorted keys, no whitespace) before signing to ensure deterministic hashing.
Python¶
from schemapin.core import SchemaPinCore
from schemapin.crypto import SignatureManager
schema = {
"name": "calculate_sum",
"description": "Calculates the sum of two numbers",
"parameters": {
"type": "object",
"properties": {
"a": {"type": "number", "description": "First number"},
"b": {"type": "number", "description": "Second number"},
},
"required": ["a", "b"],
},
}
core = SchemaPinCore()
canonical = core.canonicalize_schema(schema)
signature = SignatureManager.sign_schema(private_key, canonical)
# signature is a Base64-encoded ECDSA signature
JavaScript¶
import { SchemaPinCore, SignatureManager } from 'schemapin';
const schema = {
name: 'calculate_sum',
description: 'Calculates the sum of two numbers',
parameters: {
type: 'object',
properties: {
a: { type: 'number', description: 'First number' },
b: { type: 'number', description: 'Second number' },
},
required: ['a', 'b'],
},
};
const core = new SchemaPinCore();
const canonical = core.canonicalizeSchema(schema);
const signature = await SignatureManager.signSchema(privateKey, canonical);
Go¶
import (
"github.com/ThirdKeyAi/schemapin/go/pkg/core"
"github.com/ThirdKeyAi/schemapin/go/pkg/crypto"
)
spc := core.NewSchemaPinCore()
canonical, _ := spc.CanonicalizeSchema(schema)
sig, _ := crypto.NewSignatureManager().SignSchema(privKey, canonical)
Rust¶
use schemapin::core::SchemaPinCore;
use schemapin::crypto::{sign_data, generate_key_pair};
let core = SchemaPinCore::new();
let canonical = core.canonicalize_schema(&schema)?;
let signature = sign_data(&key_pair.private_key_pem, &canonical)?;
CLI¶
Step 3: Verify a Schema Signature¶
Python¶
from schemapin.crypto import SignatureManager
is_valid = SignatureManager.verify_signature(public_key, canonical, signature)
if is_valid:
print("Schema signature is valid")
JavaScript¶
import { SignatureManager } from 'schemapin';
const isValid = await SignatureManager.verifySignature(publicKey, canonical, signature);
if (isValid) {
console.log('Schema signature is valid');
}
Go¶
valid, err := crypto.NewSignatureManager().VerifySignature(pubKey, canonical, sig)
if valid {
fmt.Println("Schema signature is valid")
}
Rust¶
use schemapin::crypto::verify_signature;
let is_valid = verify_signature(&key_pair.public_key_pem, &canonical, &signature)?;
CLI¶
Step 4: Publish Your Public Key¶
Publish your public key at /.well-known/schemapin.json so clients can discover it:
Python¶
from schemapin.utils import create_well_known_response
from schemapin.crypto import KeyManager
response = create_well_known_response(
public_key_pem=public_key_pem,
developer_name="Acme Corp",
schema_version="1.3",
revocation_endpoint="https://example.com/.well-known/schemapin-revocations.json",
)
import json
with open(".well-known/schemapin.json", "w") as f:
json.dump(response, f, indent=2)
Discovery Document Format¶
{
"schema_version": "1.3",
"developer_name": "Acme Corp",
"public_key_pem": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0C...\n-----END PUBLIC KEY-----",
"revoked_keys": [],
"contact": "security@example.com",
"revocation_endpoint": "https://example.com/.well-known/schemapin-revocations.json"
}
Step 5: Full Verification Workflow¶
The complete workflow includes key discovery, signature verification, and TOFU key pinning:
Python (Online)¶
from schemapin.utils import SchemaVerificationWorkflow
workflow = SchemaVerificationWorkflow()
result = workflow.verify_schema(
schema=schema,
signature_b64=signature,
tool_id="example.com/calculate_sum",
domain="example.com",
auto_pin=True,
)
if result["valid"]:
print("Schema verified successfully")
print(f"Key fingerprint: {result.get('key_fingerprint')}")
Python (Offline)¶
from schemapin.verification import verify_schema_offline, KeyPinStore
pin_store = KeyPinStore()
result = verify_schema_offline(
schema=schema,
signature_b64=signature,
domain="example.com",
tool_id="calculate_sum",
discovery_data=discovery_doc,
revocation_doc=None,
pin_store=pin_store,
)
JavaScript (Offline)¶
import { verifySchemaOffline, KeyPinStore } from 'schemapin';
const pinStore = new KeyPinStore();
const result = verifySchemaOffline(
schema,
signatureB64,
'example.com',
'calculate_sum',
discoveryData,
null,
pinStore,
);
Step 6: Sign a Skill Directory (v1.3)¶
SchemaPin v1.3 adds SkillSigner for signing entire skill directories:
Python¶
from schemapin.skill import sign_skill, verify_skill_offline
# Sign a skill directory (writes .schemapin.sig)
sig = sign_skill("./my-skill/", private_key_pem, "example.com")
# Verify offline
from schemapin.verification import KeyPinStore
result = verify_skill_offline(
"./my-skill/", discovery_data, sig, None, KeyPinStore()
)
JavaScript¶
import { signSkill, verifySkillOffline } from 'schemapin/skill';
const sig = await signSkill('./my-skill/', privateKeyPem, 'example.com');
const result = verifySkillOffline('./my-skill/', discoveryData, sig, null, pinStore);
Next Steps¶
- API Reference — Complete API across all 4 languages
- Skill Signing — SkillSigner deep dive
- Trust Bundles — Offline and air-gapped verification
- Deployment — Serve
.well-knownendpoints in production - Troubleshooting — Common issues and solutions