npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@typooo/kekkai

v0.0.1

Published

A unified execution facade for AI Agent CLIs

Readme

Kekkai — The casting platform for agents

Kekkai (結界) is a unified execution facade for AI Agent CLIs — structured events, session management, and pluggable backends.

Core Capabilities

  • Unified Execution API: Kekkai.run(id, request) / stream(request) — abstracts CLI protocol differences
  • Pluggable Backends: Claude, Codex, OpenCode, Antigravity, Raw — auto-register, zero core changes to add one
  • Structured Runtime Events: 12 event types with schema version, sequence, and timestamp metadata
  • NDJSON Logging: One JSON line per event, with redaction, filtering, and fan-out
  • Session Management: In-memory or file-based, with key pinning and resume

Quick Start

import { Kekkai } from 'kekkai';

// 1. Create an agent instance with configuration
Kekkai.create('my-agent', {
  defaultBackend: 'raw',
  backends: {
    raw: { command: 'echo', model: 'claude-sonnet-4' },
  },
  systemPrompt: 'You are a helpful assistant.',
  permissions: { profile: 'edit' },
  timeouts: { wall: 600000, idle: 180000, tool: 60000 },
});

// 2. Stream events (command is inherited from create-time config)
for await (const event of Kekkai.get('my-agent').stream({
  agentId: 'my-agent',
  prompt: 'hello world',
})) {
  console.log(event.type, event);
}

// Or run directly (collects all events and returns a result)
const result = await Kekkai.run('my-agent', {
  agentId: 'my-agent',
  prompt: 'hello world',
});

Built-in backends auto-register — no manual backendRegistry.register() needed.

Structured Output

Pass a JSON Schema to get validated, structured results:

const result = await Kekkai.run('my-agent', {
  agentId: 'my-agent',
  prompt: 'List 3 cat breeds with their temperaments',
  schema: {                        // ← JSON Schema for structured output
    type: 'object',
    required: ['breeds'],
    properties: {
      breeds: {
        type: 'array',
        items: {
          type: 'object',
          properties: {
            name: { type: 'string' },
            temperament: { type: 'string' },
          },
        },
      },
    },
  },
});
// result.structured → { breeds: [{ name: 'Siamese', temperament: '...' }, ...] }

For Claude and Codex, the schema is passed natively via --structured-output. For other backends, it's appended to the prompt. The run() method validates the output and populates result.structured on success.

Architecture

┌─────────────────────────────────────────────────┐
│  Kekkai                                         │
│  static: create / get / run / stream            │
│  instance: run(request) → stream(request)       │
│    → resolve backend → execute → yield events   │
├─────────────────────────────────────────────────┤
│  Backend Registry     LogSinks    SessionStore   │
│  Claude / Codex / Raw  ConfigLoader              │
├─────────────────────────────────────────────────┤
│             Agent CLI child processes            │
└─────────────────────────────────────────────────┘

Configuration

KekkaiConfig (create-time)

interface KekkaiConfig {
  defaultBackend?: string;
  systemPrompt?: string;
  permissions?: { profile?: PermissionProfile };
  timeouts?: { wall?: number; idle?: number; tool?: number };
  backends?: Record<string, BackendConfig>;
}

RunRequest (per-call)

| Field | Description | |-------|-------------| | agentId | Agent identifier | | backend | Backend name (overrides defaultBackend) | | command | Executable (overrides BackendConfig.command) | | model | Model name (overrides BackendConfig.model) | | prompt | User prompt | | schema | JSON Schema — validates output, populates result.structured | | cwd | Working directory | | sessionKey / resumeSessionId | Session resume | | signal | Cancellation signal | | overrides | Partial AgentRuntimeConfig deep merge |

Precedence: RunRequest > BackendConfig > backend defaults

Backend Support

| Backend | Protocol | Registry Name | |---------|----------|---------------| | Claude | stream-json stdout (native --structured-output) | claude | | Codex | JSON-RPC over stdio (native --structured-output) | codex | | OpenCode | --format json events (configurable via format option) | opencode | | Antigravity | stdio MCP config | antigravity | | Raw | Arbitrary stdio command | raw |

Select by name:

// Configure backend (command and model are set at create-time)
Kekkai.create('my-agent', {
  defaultBackend: 'claude',
  backends: {
    claude: { command: 'claude', model: 'claude-sonnet-4' },
  },
});

// Run — no need to repeat command or model
const result = await Kekkai.run('my-agent', {
  agentId: 'my-agent',
  prompt: 'Explain this project architecture',
  overrides: {
    mcp: { mcpServers: { filesystem: { command: 'mcp-server-fs', args: ['--root', '/tmp'] } } },
  },
});

Implementing a Backend

Extend BaseBackend and implement two methods:

import { BaseBackend, SpawnParams } from 'kekkai';

class MyBackend extends BaseBackend {
  readonly backend = 'my-backend';

  protected buildArgs(input: BackendRunInput): SpawnParams {
    return { command: 'my-cli', args: ['--flag'], stdinData: input.prompt };
  }

  protected parseLine(line: string, runId: string, agentId: string): RuntimeEvent | null {
    return { type: 'message', role: 'assistant', content: line, /* ... */ } as RuntimeEvent;
  }

  // Optional: emit events before spawning
  protected getPreludeEvents?(input: BackendRunInput, params: SpawnParams): RuntimeEvent[];
}

BaseBackend.execute() handles the full pipeline: spawn → write stdin → read stdout/stderr → yield events → detect cancellation → yield run_end.

Or implement the full AgentBackend interface:

interface AgentBackend {
  readonly backend: string;
  execute(input: BackendRunInput): AsyncIterable<RuntimeEvent>;
  cancel?(runId: string, reason?: string): Promise<void>;
}

Reference: RawBackend (~50 lines) is the minimal implementation.

Registration

Built-in backends auto-register. Custom backends:

import { backendRegistry } from 'kekkai';
backendRegistry.register('my-backend', () => new MyBackend());

Event Protocol

Events follow this sequence:

run_start (first)
  ├─ message / thinking / tool_use / tool_result / status / usage
  ├─ error (optional)
  └─ stdout / stderr (optional)
run_end (last)

Every event includes schemaVersion, runId, seq, timestamp, agentId, backend, and type.

| Type | Description | |------|-------------| | run_start | Execution started | | message | Structured message (role: assistant/user/system) | | thinking | Reasoning process | | tool_use / tool_result | Tool invocation and result | | stdout / stderr | Streaming text | | status | Status update (includes sessionId) | | usage | Token usage | | audit | Security audit event | | error | Error information | | run_end | Execution finished |

Logging

import { FileLogSink, FanoutLogSink, MemoryLogSink, CallbackLogSink } from 'kekkai';

const fanout = new FanoutLogSink([
  { sink: new FileLogSink({ dir: './logs' }), filter: (e) => e.type !== 'thinking' },
  { sink: new MemoryLogSink() },
  { sink: new CallbackLogSink({ callback: (e) => ws.send(JSON.stringify(e)) }) },
]);

CLI Usage

kekkai -c support.json "Analyze this ticket"
kekkai -c dev.json --json
kekkai -c review.json -b claude < prompt.txt

Options: -c (config path, required), -b (backend), --json (JSON output), -h (help).

Config files are JSON profiles — the filename (minus extension) is agentId:

{
  "defaultBackend": "claude",
  "systemPrompt": "You are a developer.",
  "permissions": { "profile": "edit" },
  "timeouts": { "wall": 600000, "idle": 1800000, "tool": 7200000 },
  "backends": {
    "claude": { "command": "claude", "model": "claude-sonnet-4", "args": ["--max-turns", "60"] },
    "codex": { "command": "codex", "model": "claude-sonnet-4" },
    "opencode": { "command": "opencode", "model": "claude-sonnet-4", "format": "json" }
  }
}

API Overview

| Export | Description | |--------|-------------| | Kekkai | Global lifecycle management (create/get/run/stream/remove/shutdown) | | BaseBackend | Abstract base class (buildArgs + parseLine pattern) | | RawBackend / ClaudeBackend / CodexBackend / OpenCodeBackend / AntigravityBackend | Backend implementations | | MemoryLogSink / FileLogSink / FanoutLogSink / CallbackLogSink / NoopLogSink | Log writers | | MemorySessionStore / FileSessionStore | Session persistence | | JsonConfigLoader | JSON config loader | | resolveConfig / validateConfig / defaultConfig | Config helpers | | resolvePermissionProfile / registerPolicyMapper / getPolicyMapper | Permission mapping | | validateSchema | JSON Schema validation for structured output | | ResultParser | Interface for parsing output from events | | serializeEvent / parseNDJSON | NDJSON serialization | | redactEnv / redactString / isSensitiveKey | Log redaction | | buildClaudeArgs / mapClaudeEvent / isTerminalEvent | Claude utilities |

Testing

npm test            # Run all tests
npm run test:watch  # Watch mode
npm run build       # TypeScript compilation

License

MIT