@lyhna/bind
v0.3.8
Published
The execution boundary for autonomous AI systems. bind() must reach Lyhna or throw — no silent fallbacks, no local signing, no fabricated receipts.
Maintainers
Readme
@lyhna/bind
The execution boundary for autonomous AI systems.
bind() is a pre-execution gate that produces cryptographically signed, offline-verifiable receipts on every outcome (APPROVED, REFUSED, ESCALATED). Fail-closed by construction.
Constitutional invariant: only an APPROVED receipt licenses execution.
Installation
npm install @lyhna/bind@lyhna/bind is a project dependency. Install it inside your Node project with npm install @lyhna/bind. Do not install it globally.
Quick start
ESM-only.
@lyhna/bindis an ES module. Add"type": "module"to yourpackage.json, or use dynamicimport(). CommonJSrequire()is not supported.
import { bind } from '@lyhna/bind';
const receipt = await bind({
action_type: 'test_ping',
action_payload: {},
intent: 'verify_install',
intent_version: '1.0',
});
if (receipt?.receipt_id && receipt?.signature) {
console.log('Lyhna install verified.');
console.log('Outcome:', receipt.outcome);
console.log('Receipt:', receipt.receipt_id);
}
if (receipt.outcome === 'ESCALATED') {
console.log('Fresh tenant: ESCALATED is expected until authority rules are configured.');
}A fresh tenant may return ESCALATED for
test_pinguntil authority rules are configured. That still proves install success: the SDK reached Lyhna,bind()executed, and a signed receipt was returned.
Configuration
bind() requires one environment variable:
| Variable | Purpose |
|-------------------|--------------------------------------------|
| LYHNA_API_KEY | Tenant API key issued by the Lyhna dashboard |
If LYHNA_API_KEY is missing, bind() throws. There is no local fallback.
The SDK reads LYHNA_API_KEY from your environment automatically. No init() call is required.
Endpoint Override
By default, bind() sends requests to https://api.lyhna.com.
For staging, local testing, or self-hosted deployments, set LYHNA_ENDPOINT:
export LYHNA_ENDPOINT="https://staging.example.com"Resolution order (highest precedence first):
LYHNA_ENDPOINTenvironment variable.- Default:
https://api.lyhna.com.
The request contract
bind() accepts exactly four fields. All required. No aliases.
interface BindRequest {
action_type: string; // what you intend to do
action_payload: object; // parameters of the action
intent: string; // declared business purpose
intent_version: string; // version of the intent
}You do not send authority_tier. Authority tier is determined exclusively by Lyhna's canonical registry and your tenant authority rules — configured through the dashboard, never by the caller.
Outcomes
bind() returns one of three outcomes, all represented as a signed receipt:
- APPROVED — the action is bound; you may proceed.
- REFUSED — policy denied the action; you must not proceed.
- ESCALATED — authority required; the action waits for a human or higher-tier decision.
Handling ESCALATED
bind() returns immediately on ESCALATED. It does not block. The receipt contains escalate_to metadata identifying who needs to approve.
If your code wants to wait synchronously for the escalation to resolve, use awaitResolution():
import { bind, awaitResolution } from '@lyhna/bind';
const receipt = await bind({
action_type: 'deploy_production',
action_payload: { version: 'v3' },
intent: 'production_deploy',
intent_version: '1.0',
});
if (receipt.outcome === 'ESCALATED') {
const resolved = await awaitResolution(receipt, {
pollIntervalMs: 5000,
timeoutMs: 300_000,
});
if (resolved.outcome === 'APPROVED') {
console.log('Resolved:', resolved.outcome, resolved.receipt_id);
}
}awaitResolution() polls the enforcement core and resolves when:
- The receipt transitions to APPROVED or REFUSED
- The receipt expires (
expires_atreached — throws) - The polling timeout is reached (throws)
Offline receipt verification
Every receipt carries its own signature and public key. You can verify a receipt anywhere, without contacting Lyhna:
import { verifyReceipt } from '@lyhna/bind';
const valid = await verifyReceipt(receipt);
if (!valid) {
throw new Error('Receipt failed integrity check');
}When LYHNA_API_KEY and LYHNA_ENDPOINT are set, verifyReceipt() also consults the server for replay, revocation, and tenant-scope checks.
CLI
lyhna verify path/to/receipt.jsonConstitutional invariants
- Fail-closed — no APPROVED receipt, no execution
- Deterministic — same input, same outcome
- Append-only — receipts are never mutated
- Verifiable offline — Ed25519, no call home required
- Declared deltas — the submitting authority declares material changes
- Tenant-sovereign — data never crosses tenant boundaries
Failure modes
bind() throws — it does not return fake receipts — when:
LYHNA_API_KEYorLYHNA_ENDPOINTis missing- Request fields are malformed
- The enforcement core is unreachable
- The server returns a non-200 status
- The response is not valid JSON
- The response does not contain a receipt
A thrown error means the action was not bound. Your code must not proceed as if it had been.
License
MIT
