kavachOS
Core concepts

Audit trail

Immutable logging of every authorization decision, with filtering, export, and compliance references.

How audit logging works

Every call to kavach.authorize() or kavach.authorizeByToken() writes an entry to the audit log, regardless of outcome. Allowed, denied, and rate-limited calls are all recorded. The log is append-only: entries are never updated or deleted.

authorize() returns an auditId linking the decision to its log entry:

const result = await kavach.authorize(agent.id, {
  action: 'read',
  resource: 'mcp:github:repos',
});

console.log(result.auditId); // "aud_3f8a..."

Querying logs

AuditEntry type

Prop

Type

Filtering

All filter fields are optional and combinable. Without filters, the query returns all entries up to the limit.

const logs = await kavach.audit.query({
  agentId: 'agt_...',
  userId: 'user-123',
  result: 'denied',
  since: new Date('2025-01-01'),
  until: new Date('2025-02-01'),
  actions: ['write', 'delete'],
  limit: 100,
  offset: 0,
});

Prop

Type

Exporting logs

// JSON export
const json = await kavach.audit.export({ format: 'json' });

// CSV export, suitable for spreadsheets and compliance tools
const csv = await kavach.audit.export({ format: 'csv' });

// Export a specific time range
const q4 = await kavach.audit.export({
  format: 'csv',
  since: new Date('2024-10-01'),
  until: new Date('2025-01-01'),
});

The CSV export includes a header row with field names matching the AuditEntry interface. Each row is one authorization decision.

Both since and until are optional on exports. Omitting both exports the entire log.

Compliance references

Usage patterns

Monthly access report for a user

const entries = await kavach.audit.query({
  userId: 'user-123',
  since: new Date('2025-03-01'),
  until: new Date('2025-04-01'),
});

Agents with repeated denials today

const denied = await kavach.audit.query({
  result: 'denied',
  since: new Date(new Date().setHours(0, 0, 0, 0)),
});

const countsByAgent = denied.reduce<Record<string, number>>((acc, entry) => {
  acc[entry.agentId] = (acc[entry.agentId] ?? 0) + 1;
  return acc;
}, {});

High-frequency agent detection

const highActivity = await kavach.audit.query({
  agentId: 'agt_...',
  since: new Date(Date.now() - 3_600_000), // last hour
});

console.log(`${highActivity.length} calls in the last hour`);

A sudden spike in call volume from a single agent often indicates a runaway loop. Use kavach.agent.revoke() to suspend the agent while you investigate.

Next steps

On this page