Core utilities for implementing the Agent Handoff Protocol (AHP) in backend services. This package includes identifier generation, PoW verification, token hashing, handle rotation helpers, and sandbox state utilities.
npm install @ahp/coreimport {
resolveConfig,
generateSandboxId,
verifyPoWSync,
verifyClaimWithPoW,
type AHPConfig,
} from '@ahp/core';
const config: AHPConfig = {
tokenPrefix: 'myapp_sbx_',
exchangePrefix: 'myapp_exch_',
claimCodePrefix: 'MYAPP',
urls: {
preview: 'https://preview.myapp.com/{handle}',
published: 'https://{handle}.myapp.com',
claim: 'https://myapp.com/claim/{sandboxId}',
exchange: 'https://myapp.com/exchange/{code}',
},
};
const resolved = resolveConfig(config);
const sandboxId = generateSandboxId('sbx_');
const powValid = verifyPoWSync('challenge', 'nonce', resolved.pow.baseDifficulty);
// Claim verification MUST include proof-of-work
const claimResult = await verifyClaimWithPoW(
'MYAPP-ABCD-EFGH-JKLM-NPQR',
async (hash) => lookupClaimCode(hash),
{
challenge: 'claim_challenge',
nonce: 'claim_nonce',
difficulty: resolved.pow.baseDifficulty,
}
);@ahp/core/crypto: identifiers, tokens, PoW helpers, timing utilities@ahp/core/state: sandbox state transitions and helpers@ahp/core/claim: claim code generation and verification@ahp/core/handles: handle rotation helpers@ahp/core/auth: auth middleware helpers and scope checks
For protocol compliance, prefer validateBearerTokenProtocolSafe to avoid
token existence or expiration oracles.
The state helpers are protocol-focused. If you use TTL extensions, make sure the
SandboxContext includes the original creation time so max TTL caps are correct.
import { createSandboxContext, calculateExtendedExpiry } from '@ahp/core';
const context = createSandboxContext(
new Date(Date.now() + 48 * 60 * 60 * 1000),
2,
new Date()
);
const extended = calculateExtendedExpiry(
context,
24 * 60 * 60 * 1000,
7 * 24 * 60 * 60 * 1000
);Implementations should return the well-known discovery document from
GET /.well-known/agent-access.
You can build the response with buildDiscoveryDocument:
import { buildDiscoveryDocument } from '@ahp/core';
const document = buildDiscoveryDocument({
provider: {
name: 'Provider Name',
docs: 'https://...'
},
sandbox: {
admission: ['proof_of_work'],
challengeEndpoint: 'https://.../v1/sandboxes/challenge',
createEndpoint: 'https://.../v1/sandboxes',
ttlHours: 48
},
security: {
handleRotationOnClaim: true,
handleRotationOnPublish: true,
adaptivePow: true
},
contentTypes: ['faq'],
claim: {
method: 'code_plus_pow'
}
});{
"ahp_version": "1.0",
"provider": {
"name": "Provider Name",
"docs": "https://..."
},
"sandbox": {
"enabled": true,
"admission": ["proof_of_work"],
"challenge_endpoint": "https://...",
"create_endpoint": "https://...",
"ttl_hours": 48
},
"security": {
"handle_rotation_on_claim": true,
"handle_rotation_on_publish": true,
"adaptive_pow": true
},
"content_types": ["faq"],
"claim": {
"method": "code_plus_pow"
}
}AHP supports both a preview surface and a public published surface. Preview is intended for private, read-only review before claim. Publish exposes content to a public handle for broader sharing. If content needs to be removed from public view while retaining preview access, the sandbox can be un-published (published -> active) and later re-published if needed.
To prevent existence oracles, claim verification uses generic not_found
errors for invalid, expired, or malformed codes. Use
getClaimFailureReason for internal logging and diagnostics.
npm run build
npm run test
npm run typecheckMIT