Today: a Claude Code toolkit. Future: harness-agnostic.
This library currently targets Claude Code hooks. The long-term goal is to generalize the harness layer so the same validators, builders, and session tooling work across multiple agent platforms. Claude-specific API names (event names, CLI binaries) will remain stable.
TypeScript library for Claude Code hooks with strict types, Zod-validated inputs, and a fluent output builder for all 30 hook events.
Why use this instead of raw shell scripts?
Writing hook output JSON by hand is error-prone: field names, nesting, and event-specific shapes vary across 30 event types. This library validates inputs at the boundary and produces the right output shapes via HookOutputBuilder, so you write logic, not plumbing.
It also ships session-processing CLIs: export sessions to clean markdown/JSONL, and tail a live session JSONL as structured blocks for downstream ingestion. Retained tool-result bodies are secret-redacted by default (API keys, tokens, passwords, URL credentials).
Runtime support targets Node.js 22 and newer. Development, type-checking, and CI use a Node 24 baseline without raising the consumer runtime floor.
pnpm add @libar-dev/agent-harness-kit
pnpm add -D tsx # to run .ts hooks directly without a build stepCreate .claude/hooks/bash-guard.ts:
#!/usr/bin/env tsx
import { executeHook, outputJson, isDangerousCommand } from '@libar-dev/agent-harness-kit/utils';
import { HookOutputBuilder, type PreToolUseInput } from '@libar-dev/agent-harness-kit/types';
import { validateBashToolInput } from '@libar-dev/agent-harness-kit/validation';
async function hook(input: PreToolUseInput): Promise<void> {
if (input.tool_name !== 'Bash') return;
const bash = validateBashToolInput(input); // unknown → BashToolInput (typed)
if (isDangerousCommand(bash.command)) {
outputJson(HookOutputBuilder.permission('deny', `Blocked: ${bash.command}`));
}
}
if (import.meta.url === `file://${process.argv[1]}`) {
executeHook<PreToolUseInput>(hook);
}Register it in .claude/settings.json:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [{ "type": "command", "command": "tsx .claude/hooks/bash-guard.ts" }]
}
]
}
}Test it without starting Claude Code:
echo '{"hook_event_name":"PreToolUse","session_id":"s1","transcript_path":"/tmp/t.json","cwd":"/","tool_name":"Bash","tool_input":{"command":"rm -rf /"},"tool_use_id":"tu_1"}' \
| tsx .claude/hooks/bash-guard.ts| Module | Contents |
|---|---|
@libar-dev/agent-harness-kit/types |
TypeScript types for all 30 events + HookOutputBuilder |
@libar-dev/agent-harness-kit/utils |
executeHook, outputJson, isProtectedFile, isDangerousCommand, logging |
@libar-dev/agent-harness-kit/validation |
Zod schemas, per-event validators, 15 tool-input validators, validateHooksConfig |
@libar-dev/agent-harness-kit/pre-tool-use |
Reference handlers: bash validator, file protector, ESLint-disable blocker |
@libar-dev/agent-harness-kit/post-tool-use |
Reference handlers: Prettier formatter, TypeScript checker |
@libar-dev/agent-harness-kit/lifecycle |
Reference handlers: setup, session start/end, notifications, message display, stop, subagents, elicitation |
@libar-dev/agent-harness-kit/processing |
Session parsing, full-history reads, structured exports, and multi-source raw transcript tailing |
- Getting Started — install, sub-path imports, 5-minute walkthrough
- Writing Your First Hook —
executeHookskeleton, validators,permission(), testing - Configuring settings.json — 5 handler types, matcher syntax,
if/timeout/async - Cookbook — 10 copy-pasteable recipes
- Hook Events Reference — all 30 events with input/output shapes
- HookOutputBuilder Reference — every method with examples
- Validators Reference — tool-input validators, type guards, config validators
- Environment Variables — all
CLAUDE_HOOK_*vars - Session tailing — CLI and public library APIs for live transcript ingestion
- Full docs index
Use Node 24 for local development to match the repo's @types/node baseline and CI matrix. Published runtime support remains Node 22+.
pnpm install
pnpm run check # type-check + lint
pnpm run test:run # run all tests (no build needed)
pnpm run fix # auto-fix lint/formatting
pnpm run build # compile src/ → dist/ (publish only)Absolute rule: no any types. Use unknown + a validator instead. See CONTRIBUTING.md.
Version 0.1.0 is the initial npm release candidate. The public API is stable but may change before the first published release. Pin to a commit hash if you depend on this from another project.
See CONTRIBUTING.md for the PR checklist, commit style, and architecture notes.
MIT © Libar AI