harness-one
v0.2.0
Published
Universal primitives for AI agent harness engineering
Maintainers
Readme
harness-one
Framework-agnostic primitives for AI agent harness engineering. Zero-runtime-dep core with subpath exports (core, advanced, prompt, context, tools, guardrails, observe, session, memory, evolve-check, rag, orchestration, redact, infra, testing). eval and evolve ship from @harness-one/devkit.
Install
pnpm add harness-oneNo runtime dependencies. Node 18+.
Peer Dependencies
None required by core. Integration packages (@harness-one/anthropic, @harness-one/openai, @harness-one/ajv, ...) bring their own peers.
Quick Start
import { createAgentLoop, defineTool, createRegistry, toolSuccess } from 'harness-one';
import type { AgentAdapter } from 'harness-one/core';
const add = defineTool<{ a: number; b: number }>({
name: 'add',
description: 'Add two numbers',
parameters: {
type: 'object',
properties: { a: { type: 'number' }, b: { type: 'number' } },
required: ['a', 'b'],
},
execute: async ({ a, b }) => toolSuccess(a + b),
});
const registry = createRegistry();
registry.register(add);
declare const adapter: AgentAdapter; // Implement or use @harness-one/anthropic / @harness-one/openai
const loop = createAgentLoop({ adapter, onToolCall: registry.handler() });
for await (const ev of loop.run([
{ role: 'system', content: 'You are a calculator.' },
{ role: 'user', content: 'What is 2 + 3?' },
])) {
if (ev.type === 'message') console.log(ev.message.content);
if (ev.type === 'done') break;
}Submodule Imports
Every public API is also exported from a submodule path for better tree-shaking:
import { AgentLoop } from 'harness-one/core';
import { defineTool, createRegistry } from 'harness-one/tools';
import { createPipeline, createInjectionDetector } from 'harness-one/guardrails';
import { createTraceManager, createCostTracker } from 'harness-one/observe';Available submodules: core, advanced, prompt, context, tools, guardrails, observe, session, memory, evolve-check, rag, orchestration, redact, infra, testing.
harness-one/testingsubpath — mockAgentAdapterfactories (createMockAdapter,createFailingAdapter,createStreamingMockAdapter,createErrorStreamingMockAdapter) ship from this path so the/advancedsurface carries only production extension primitives. Seedocs/architecture/17-testing.md.
eval + evolve live in
@harness-one/devkit— the@harness-one/devkitpackage owns eval + evolve dev-tooling; the runtime architecture-rule engine stays in core underharness-one/evolve-check. The CLI ships as@harness-one/cli.The root barrel is curated to 18 value symbols (core user-journey set).
createSecurePresetis not in the root barrel — import it from@harness-one/presetto avoid aharness-one↔@harness-one/presetdependency cycle. Other factories liketoSSEStream,categorizeAdapterErroretc. live on subpaths only.
Subpath-only extensions:
harness-one/observe—MetricsPort+createNoopMetricsPort(vendor-neutral metric instruments),HarnessLifecycle+createHarnessLifecycle(init→ready→draining→shutdown state machine + aggregatedhealth())harness-one/infra—createAdmissionController(per-tenant in-process token bucket with abort/timeout fail-closed)harness-one/core—createTrustedSystemMessage,isTrustedSystemMessage,sanitizeRestoredMessagefor the system-message brand patternharness-one/guardrails—runRagContextfor per-chunk input scanning of retrieved context
HarnessErrorCodeis closed and module-prefixed. Switch onHarnessError.codeexhaustively. Always value-import (import { HarnessErrorCode }) — type-only import drops the runtimeObject.values()record (lint ruleharness-one/no-type-only-harness-error-codeenforces). See rootMIGRATION.mdand the git log for change history (CHANGELOG.mdis intentionally empty pre-release).
See the main repository README and architecture docs for the full API surface.
