Skip to content

Brian-Mwangi-developer/agentchain

Repository files navigation

agents-chain

v0.0.58 — Zero-dependency security layer for AI agent systems. Ed25519 identity, JWT auth, constraint enforcement, encrypted audit, human-in-the-loop access requests, constraint-aware agent flows, and end-to-end agent session tracing.

npm License: MIT

Full documentation


Install

npm install agents-chain

Requires Node.js 18+. Ships ESM + CommonJS.

What It Does

  • Host + Agent identity — Ed25519 keypairs with JWK thumbprints as stable IDs
  • 11-step JWT verification — signature, replay protection, delegation chain, grant + constraint enforcement
  • Grant constraints — field-level rules: max, min, in, not_in, exact equality
  • Access requests — denied calls suspend and wait for human approval out-of-band (HMAC-verified, 4 scopes)
  • Constraint-aware mode — returns structured violation envelopes so AI agents can reason about permissions and explicitly request approval
  • Encrypted audit log — AES-256-GCM ring buffer with auth overhead tracking, access request lifecycle events
  • Session tracingopenTrace() / closeTrace() groups all capability and LLM calls into a single TraceRun with token counts, model names, tool calls, and per-span results
  • Zero dependencies — everything defaults to in-memory, external systems are adapter-injected

Quick Start

import { AppChain, isChainAuthError } from 'agents-chain';

const chain = await AppChain.create({
  providerName: 'billing-service',
  issuer: 'https://billing.example.com',
  capabilities: [{
    name: 'createInvoice',
    description: 'Create an invoice',
    inputSchema: {
      type: 'object',
      required: ['customerId', 'amount'],
      properties: {
        customerId: { type: 'string' },
        amount: { type: 'number' },
      },
    },
    outputSchema: { type: 'object' },
    execute: async (args, ctx) => {
      return { invoiceId: 'inv_001', amount: args.amount };
    },
  }],
});

const grants = [{
  capability: 'createInvoice',
  status: 'active' as const,
  constraints: { amount: { max: 5000 } },
  expiresAt: Date.now() + 86_400_000,
}];

const secured = chain.wrap({}, grants);

await secured.createInvoice({ customerId: 'c1', amount: 500 });  // ✅
await secured.createInvoice({ customerId: 'c1', amount: 99999 }); // ❌ constraint_violated

Constraint-Aware Mode

When constraintAware is enabled, capability calls return structured ConstraintAwareResult envelopes instead of throwing errors. This lets AI agents understand violations and decide whether to request human approval.

const chain = await AppChain.create({
  // ...capabilities, accessRequests config...
  constraintAware: true,
});

const secured = chain.wrap(service, grants);

// Allowed call — returns success envelope
const result = await secured.sendSms({ to: '+1234', message: 'Hello' });
// { success: true, result: {...}, permission: "not_required", capability: "sendSms" }

// Violation — returns structured error instead of throwing
const denied = await secured.sendSms({ to: '+9999', message: 'Hello' });
// {
//   success: false,
//   permission: "constraint_violated",
//   violations: [{ field: "to", constraint: "in", expected: ["+1234"], actual: "+9999", message: "..." }],
//   guidance: "Call request_permission to request human approval",
//   capability: "sendSms",
//   activeConstraints: { to: { in: ["+1234"] } }
// }

Two-Step Agent-Driven Permission Flow

With constraintAware: true and accessRequests configured, a built-in request_permission capability is auto-registered. The agent explicitly decides when to request human approval:

Step 1: Agent calls sendSms(+9999)
        → Returns structured violation (no suspension, no throw)

Step 2: Agent calls request_permission({ capability: "sendSms", args: {...}, reason: "..." })
        → Suspends until human approves/denies
        → Returns: { success: true, permission: "approved", result: {...} }
           OR:    { success: false, permission: "denied", reason: "..." }

The agent receives a constraint context string via chain.getConstraintContext(grants) that can be injected into its system prompt.

Access Requests

When accessRequests is configured, denied calls suspend instead of throwing. The call blocks until a human approves or denies via an HMAC-verified code:

const chain = await AppChain.create({
  // ...
  accessRequests: {
    approvalSecret: process.env.APPROVAL_SECRET,
    requestTTLMs: 5 * 60 * 1000,
    notifier: {
      async notify(request) {
        console.log(`Code: ${request.verificationCode}`);
      },
    },
  },
});

// Approve with 4 scopes: call, value, capability, global
chain.approve({ requestId, code, scope: 'value' });

Read more about access requests

Audit Trail

The audit log captures the full lifecycle of capability calls, including access request events:

Result Description
success Capability executed successfully
denied Call rejected by auth or constraints
error Capability threw during execution
access_requested Agent requested human approval (call suspended)
access_approved Human approved the access request
access_denied Human denied the access request

Export audit entries to external systems via HttpAuditExporter or implement your own AuditExporter.

Session Tracing

Track a complete agent session — every capability call, every LLM invocation, token counts, and tool calls — as a single exportable TraceRun:

import { AppChain, HttpTraceExporter } from 'agents-chain';

const chain = await AppChain.create({
  // ...
  traceExporter: new HttpTraceExporter({
    endpoint: 'https://gateway.melduo.com/traces',
    apiKey: process.env.MELDUO_API_KEY,
  }),
});

// Open a trace at session start
const traceId = chain.openTrace();

// Pass traceId into wrap() and openai()/anthropic() to group spans
const secured = chain.wrap(myService, grants, traceId);
const openai = chain.openai(new OpenAI({ apiKey: '...' }), traceId);

await secured.sendEmail({ to: 'user@example.com', subject: 'Hello' });
await openai.chat.completions.create({ model: 'gpt-4o', messages: [...] });

// Close the trace — assembles the TraceRun and exports it
const run = await chain.closeTrace(traceId, 'success');
// run.summary.totalTokens   → 1240
// run.summary.modelsUsed    → ["gpt-4o"]
// run.spans                 → [{ capability, result, durationMs, modelMetadata }, ...]

For custom LLM providers (Google, Cohere, etc.), implement and register a ModelMetadataExtractor.

Documentation

Section Description
Getting Started Installation, quick start, how it works
Core Concepts Host & Agent, Capabilities, Grants, Verification, Audit
Tracing & Observability Session traces, token counts, model extractors, exporters
Access Requests Suspend/resume, approval scopes, security model
Examples Basic service, SMS gateway, access request flow
API Reference AppChainConfig, types, error codes
Architecture Module map, data flows, internals

Sponsored by

Sponsored by Melduo

License

MIT — brianmwangidev

About

Lightweight identity, authentication, and audit layer for AI agents.

Resources

License

Stars

2 stars

Watchers

0 watching

Forks

Packages

 
 
 

Contributors