Paraharness
Declarative multi-agent orchestration and durable execution for TypeScript. → Documentation & API Reference
Paraharness is a TypeScript framework for building autonomous LLM agent systems that run over isolated workspaces. Instead of writing ad-hoc prompt loops and unguarded shell tools, you declare agents, capability policies, verification loops, and multi-step flows with the P.* DSL, compile them into a pure passive AST, and execute them on a crash-recoverable runtime (@paraharness/core/runtime).
Installation
With npm:
npm install @paraharness/core zodWith yarn:
yarn add @paraharness/core zodWith pnpm:
pnpm add @paraharness/core zodQuick Start
import { P, z } from '@paraharness/core';
import { createRuntime, runFlow, runStep } from '@paraharness/core/runtime';
import { claude, claudeExecutors } from '@paraharness/claude';
import { fs, fsExecutors } from '@paraharness/fs';
import { git, gitExecutors } from '@paraharness/git';
import { local, nodeExecutors } from '@paraharness/node';
import { sqlite, sqliteExecutors } from '@paraharness/sqlite';
const TaskInput = z.object({
taskId: z.string(),
prompt: z.string(),
});
const runner = local.runner({ slots: 4, maxDaemons: 2 });
const sonnet = claude.model('claude-sonnet-4-6');
const verifySuite = local
.streamCheck('verify-suite')
.runner(runner)
.argv(['pnpm', 'test', '--run'])
.circuitBreakWhenStdout(/FAIL/);
const worker = P.agent('worker')
.model(sonnet)
.tools(fs.codingTools(), verifySuite.asTool())
.instructions('Implement the requested change and keep all checks passing.')
.beforeStop(verifySuite)
.input(TaskInput)
.output(z.object({ summary: z.string() }));
const stepOut = await runStep(
worker,
{ taskId: 'task-1', prompt: 'Add input validation' },
{
registry: [claudeExecutors, fsExecutors, nodeExecutors],
env: process.env,
},
);
const deliveryFlow = P.flow('delivery-flow')
.input(TaskInput)
.scope(git.cowWorktree())
.step('implement', worker)
.exit('done');
const flowResult = await runFlow(
deliveryFlow,
{ taskId: 'task-1', prompt: 'Add input validation' },
{
registry: [claudeExecutors, fsExecutors, gitExecutors, nodeExecutors, sqliteExecutors],
ledger: sqlite.ledger('.harness/state.sqlite'),
env: process.env,
},
);
const harness = P.harness('engineering-harness')
.ledger(sqlite.ledger('.harness/state.sqlite'))
.pools(runner)
.lanes(
P.lane('main-lane')
.input(TaskInput)
.key((item) => item.taskId)
.runs(deliveryFlow)
.concurrency(2)
.priority('normal'),
);
const runtime = createRuntime(harness, {
registry: [claudeExecutors, fsExecutors, gitExecutors, nodeExecutors, sqliteExecutors],
env: process.env,
});
await runtime.start();Usage
Policy Guardrails & Post-Flight Rollbacks
Attach P.policy masks to restrict what files an agent can mutate, intercept edits to existing tests via typed P.interrupt escalations, and enforce turn and budget ceilings with automatic workspace rollback if a subprocess mutates protected paths:
import { P, z } from '@paraharness/core';
import { fs } from '@paraharness/fs';
import { git } from '@paraharness/git';
const leaseRequest = P.interrupt(
'lease-request',
z.object({
requestedPaths: z.array(z.string()),
justification: z.string(),
}),
);
const workerPolicy = P.policy('worker-policy')
.guard(fs.protect(['packages/*/src/index.ts', 'PRODUCT_SPEC.md', '.harness/**']))
.onViolation('deny-with-error')
.guard(
fs.writeGuard({
denyGlobs: ['**/*.test.ts', '**/*.test.tsx'],
onlyExistingAtBaseRef: true,
}),
)
.onViolation('raise-interrupt', leaseRequest, (violation) => ({
requestedPaths: fs.violatedPaths(violation),
justification: violation.violationSummary,
}))
.tripwire(fs.maxFilesMutated(6))
.maxTurns(12)
.maxCostUsd(2.0)
.onAbort(git.snapshotAndReset());Act-Evaluate Verification Loops
Pair a write-capable implementation agent with a read-only adversarial evaluator inside P.loop. Rejected iterations append structured deficits directly onto the actor's preserved session until all checks and review criteria pass:
import { P, z } from '@paraharness/core';
import { fs } from '@paraharness/fs';
import { git } from '@paraharness/git';
const readOnlyPolicy = P.policy('read-only')
.guard(fs.readOnly())
.onViolation('deny-with-error');
const evaluator = P.agent('evaluator')
.model(sonnet)
.policy(readOnlyPolicy)
.tools(fs.readOnlyTools(runner))
.instructions('Audit the candidate diff and reject if any edge cases or tests are missing.')
.input(
z.object({
task: TaskInput,
candidate: z.object({ summary: z.string() }),
scopeReceipt: git.ScopeReceiptSchema,
}),
)
.output(
z.object({
accepted: z.boolean(),
deficits: z.array(z.string()),
}),
);
const verifiedWorkerLoop = P.loop('verified-worker-loop')
.maxIterations(3)
.preserveActorSession(true)
.act('execute', worker.withPolicy(workerPolicy))
.evaluate('audit', evaluator, {
mapInput: (task, candidate, scopeReceipt) => ({ task, candidate, scopeReceipt }),
acceptWhen: (ev) => ev.accepted && ev.deficits.length === 0,
feedbackMapper: (ev) => `Resolve these deficits:\n- ${ev.deficits.join('\n- ')}`,
});Parallel Subagent Forks & Speculative Tournaments
Equip coordinator agents with .fork() for isolated child worktree delegation and .speculate() to race competing implementation strategies across parallel Copy-on-Write worktrees judged by an arbiter:
import { P, z } from '@paraharness/core';
import { git } from '@paraharness/git';
const candidateArbiter = P.agent('candidate-arbiter')
.model(sonnet)
.tools(fs.readOnlyTools(runner), git.candidateComparisonTools(runner))
.instructions('Select the strongest candidate branch or reject all.')
.input(
P.SpeculationInputSchema(
TaskInput,
z.object({ summary: z.string() }),
git.ScopeReceiptSchema,
),
)
.output(
z.discriminatedUnion('decision', [
z.object({
decision: z.literal('select-winner'),
winnerBranchIndex: z.union([z.literal(0), z.literal(1)]),
rationale: z.string(),
}),
z.object({
decision: z.literal('reject-all'),
rationale: z.string(),
}),
]),
);
const coordinator = P.agent('coordinator')
.model(sonnet)
.tools(fs.codingTools(runner), git.refReaderTools(runner))
.instructions('Decompose tasks across partitions or run speculative tournaments for high-risk changes.')
.input(TaskInput)
.output(z.object({ summary: z.string() }))
.capabilities(($cap) =>
$cap
.fork('delegate-subtask', verifiedWorkerLoop, ($f) =>
$f
.historyMode('shared-prefix-only')
.requestSchema(z.object({ subtaskPrompt: z.string() }))
.mapInput((parent, req) => ({
taskId: parent.taskId,
prompt: req.subtaskPrompt,
})),
)
.speculate('explore-candidates', ($s) =>
$s
.requestSchema(
z.object({
strategyA: z.string(),
strategyB: z.string(),
}),
)
.worker(verifiedWorkerLoop)
.branches(2, (parent, req) => [
{ taskId: parent.taskId, prompt: req.strategyA },
{ taskId: parent.taskId, prompt: req.strategyB },
])
.arbiter(candidateArbiter),
),
);Warm-Fork Prefix Caching, Topology & Empirical Lessons
Pin byte-identical system prompts across agent roles with P.prefixGroup, declare partition dependency graphs with P.topology, and distill empirical lessons from loop and gate recoveries with P.lessons:
import { P } from '@paraharness/core';
import { fs } from '@paraharness/fs';
import { md } from '@paraharness/markdown';
import { sqlite } from '@paraharness/sqlite';
const repoTopology = P.topology('repo-topology')
.store(sqlite.topologyStore('.harness/state.sqlite'))
.partitions({
db: {},
api: { dependsOn: ['db'] },
web: { dependsOn: ['api'] },
});
const repoRules = P.rules('repo-rules')
.global(md.globalRules('.harness/rules/global/*.md'))
.scoped(md.scopedRules('.harness/rules/scoped/*.md'));
const sharedPrefix = P.prefixGroup('engineering-prefix')
.toolsMode('role-scoped')
.sharedGrounding(fs.text('PRODUCT_SPEC.md'), fs.text('TECH_DESIGN.md'))
.sharedInstructions(fs.text('.harness/prompts/base-posture.md'))
.sharedRules(repoRules);
const repoLessons = P.lessons('repo-lessons')
.store(sqlite.lessonStore('.harness/state.sqlite'))
.queryFrom(TaskInput, (item) => item.prompt)
.distillWith(sonnet, ($d) => $d.onLoopRecovery().onGateRecovery({ minFailedChecks: 1 }));Packages
| Package | Description |
|---|---|
@paraharness/core | Core declarative P.* DSL builders, AST contracts, port interfaces, and durable execution runtime (@paraharness/core/runtime) |
@paraharness/node | Local OS subprocess runner pools, one-shot commands, circuit-breaking stream checks, PTY daemons, and MCP control planes (local.*, mcp.*) |
@paraharness/git | Copy-on-Write Git worktree isolation scope, git-index checkpoints, 3-way merge-tree reconciliation, and candidate comparison tools (git.*) |
@paraharness/fs | Workspace-jailed file tools, glob matchers, pre/post-flight write guards, quota tripwires, and atomic JSONL lesson store (fs.*) |
@paraharness/markdown | Frontmatter and section-aware Markdown loaders for global rules, scoped rules, and on-demand skills (md.*) |
@paraharness/sqlite | WAL-mode SQLite drivers for LedgerStore, Copy-on-Write TopologyStore, LessonStore, and global rules (sqlite.*) |
@paraharness/postgres | Distributed PostgreSQL drivers for LedgerStore, Copy-on-Write TopologyStore, LessonStore, and global rules (postgres.*) |
@paraharness/lockfile | Cross-process advisory lockfile utility with p-queue in-process serialization, heartbeat, and stale lock reclamation (withFileLock) |
@paraharness/claude | Anthropic Claude /v1/messages ModelDriver and AST builders (claude.cliAccount, claude.model) |
@paraharness/openai | OpenAI Responses API & Codex CLI ModelDriver and AST builders (openai.account, openai.cliAccount, openai.model) |
@paraharness/gemini | Google Gemini generateContent ModelDriver and AST builders (gemini.account, gemini.cliAccount, gemini.model) |
@paraharness/github | GitHub Issues tracker adapter, HMAC-SHA256 webhook event stream source, and idempotent pull-request step executor (github.*) |
@paraharness/slack | Slack Socket Mode interactive human approval / control-plane adapter and incoming webhook notifier (slack.*) |
Documentation
License
MIT © Tornike Tsomaia