@polyweave/nursery (1.0.6)
Installation
@polyweave:registry=https://hub.kl1.tenere.ai/api/packages/Polyweave/npm/npm install @polyweave/nursery@1.0.6"@polyweave/nursery": "1.0.6"About this package
@polyweave/nursery
Reliability-economic protocol grower for Polyweave harnesses — scores, evolves, and selects behavior tree (BT) specifications against calibration instances from domain definitions.
Synopsis
import { createNurseryTool, growProtocol, scoreProtocolCandidate, createDomainFromSpec } from '@polyweave/nursery';
// Synchronous protocol scoring
const domain = createDomainFromSpec(myDomainSpec);
const instances = domain.generateInstances(50, 42);
const result = growProtocol({
domain: myDomainSpec,
seeds: [{ id: 'test', name: 'Test protocol', spec: '─── SYMBOLS ───\n@done : boolean = false\n\n─── ACTIONS ───\nsolve (action):\n task "Solve"\n on success: @done = true\n\n─── TREE ───\nroot = sequence { action solve }', metrics: { p0: 0.7, c: 0.2, gamma: 0.02 } }],
scoringProfile: { objectiveWeights: { validRate: 5.0, costEfficiency: 4.0 } }
});
// Frame-duplex tool
const tool = createNurseryTool({ executionGraph: myGraph });
tool.sink.write({ type: 'TOOL_CALL', content: { requirement: 'Build a microstep verifier protocol' } });
// Grow loop tool
const growTool = createNurseryGrowTool({
apiKey: process.env.OPENAI_API_KEY,
model: 'gpt-4o',
domain: myDomain,
initialSpec: baseSpec,
maxImprovements: 10,
patience: 3
});
growTool.sink.write({ type: 'TOOL_CALL', content: {} });
Install
npm install @polyweave/nursery
Why
Polyweave harnesses need protocols that maximize reliability per token — but writing BT specs by hand is brittle. The nursery automates protocol growth using multi-objective optimization: it evaluates candidates against domain calibration instances, scores them on reliability gain, validity rate, quorum convergence, temperature diversity, correction/corruption efficiency, and cost, then selects the best. This removes human trial-and-error from protocol design while providing audit trails through execution graph traces.
API
createNurseryTool(options)
Creates a frame-duplex tool for synchronous protocol growing.
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
options.executionGraph |
object |
No | New execution graph | Execution graph for tracking protocol runs |
options.executionGraphOptions |
object |
No | {} |
Options passed to createExecutionGraph |
options.scoringProfile |
object |
No | DEFAULT_SCORING_PROFILE |
Custom scoring weight profile |
options.name |
string |
No | null |
Node name |
options.* |
any |
No | — | All options forwarded to growProtocol |
TOOL_CALL args: { requirement, initialSpec, candidates, baselineAccuracy, packageInventory }
Return value: IFrameDuplex with .source, .sink, .graph (execution graph), .name, ._toolName = 'nursery'.
Handles DESCRIBE frames (returns tool description) and TOOL_CALL frames (runs growProtocol, responds with TOOL_RESULT + END). Errors are caught and returned as TOOL_RESULT with { success: false, error }.
createNurseryGrowTool(options)
Creates a bt-harness-driven nursery grow loop tool. Supports two modes:
- Static mode (no
agentAdapter/agentFactory/createAdapter): Uses sampler variants + internal scoring - BT harness mode (with agent adapters): Uses
NURSERY_GROW_SPECBT spec with real LLM calls
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
options.apiKey |
string |
Yes | — | API key for LLM calls |
options.model |
string |
No | 'deepseek-v4-pro' |
Model name for agent/evaluator |
options.domainSpec |
object |
No | — | Domain specification |
options.initialSpec |
string |
No | '' |
Starting BT spec |
options.scoringProfile |
object |
No | DEFAULT_SCORING_PROFILE |
Scoring weights |
options.packageInventory |
array |
No | DEFAULT_PACKAGE_ROLES |
Polyweave package roles |
options.executionGraph |
object |
No | New graph | Execution graph |
options.maxIterations |
number |
No | 8 |
Maximum refinement iterations |
options.patience |
number |
No | 3 |
Stagnation patience |
options.debug |
boolean |
No | false |
Debug console output |
options.agentAdapter |
object |
No | — | Agent adapter (triggers BT harness mode) |
options.evaluatorAdapter |
object |
No | — | Evaluator adapter |
options.agentFactory |
function |
No | — | Agent factory |
options.evaluatorFactory |
function |
No | — | Evaluator factory |
options.createAdapter |
function |
No | — | Adapter creation function |
options.adapterConfig |
object |
No | — | Adapter configuration |
options.quorumAdapter |
object |
No | — | Custom quorum adapter (injected into tools) |
options.redflagAdapter |
object |
No | — | Custom redflag adapter (injected into tools) |
options.name |
string |
No | null |
Node name |
Return value: IFrameDuplex with methods getBestSpec(), getBestScore(), getHistory(), .graph, .name, ._toolName = 'nursery'.
Internal tools registered: nrs_read, nrs_propose, nrs_validate, nrs_benchmark, nrs_score — each exposed as a frame-duplex tool adapter with TOOL_CALL handling.
Frame handling:
TOOL_CALL→ starts a run (static or BT harness depending on adapter presence)TICK→ forwards tick to running BT harnessCANCEL→ cancels current harness runABORT→ aborts current harness runDESCRIBE→ returns tool description
The static mode (startStaticRun) generates diversified spec proposals via createSampleVariants, validates them, benchmarks against domain calibration instances, scores them, and promotes the best. Rounds are bounded by maxIterations with stagnation-based early stopping.
The BT harness mode (startBtHarnessRun) creates a bt-harness running NURSERY_GROW_SPEC, piping its output frames for progress tracking and bt:tree_complete / bt:tree_failed / bt:error event handling.
growProtocol(options)
Synchronous protocol growing function. Scores candidates and returns the best.
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
options.domain |
object |
No | — | Domain specification |
options.requirement |
string |
No | '' |
Task requirement description |
options.initialSpec |
string |
No | — | Starting BT spec |
options.initialMetrics |
object |
No | — | Metrics for initial spec |
options.initialTokenEconomics |
object |
No | — | Token economics for initial spec |
options.candidates |
array |
No | [] |
Additional candidate protocol objects |
options.includeDefaultSeeds |
boolean |
No | false |
Include built-in seed protocols when no candidates provided |
options.scoringProfile |
object |
No | DEFAULT_SCORING_PROFILE |
Scoring weights |
options.executionGraph |
object |
No | New graph | Execution graph for recording runs, steps, candidates, verifications, selections, commits |
options.packageInventory |
array |
No | DEFAULT_PACKAGE_ROLES |
Package inventory |
options.runId |
string |
No | Auto-generated | Run identifier |
options.baselineAccuracy |
number |
No | — | Baseline accuracy for score normalization |
Return value:
{
success: true,
best: { id, name, spec, valid, errors, score, tScore, econScore,
objectiveLabels, objectiveValues, objectiveWeights,
economics: { p0, predictedP1, expectedGain, c, gamma, validRate, avgVotes,
tokenCostUsd, tokens, uncertainty, consistency, confidence,
learnedGain, diversity, judgeAgreement, exampleQuality,
temperatureDiversity, cpEfficiency, redflagQuality, oracleHeadroom,
breakEvenScale },
structure: { actionCount, conditionCount, checkCount, parallelCount, selectorCount },
rationale },
candidates: [/* all scored candidates sorted by score descending */],
packageInventory,
objective: 'maximize verified reliability per token while increasing decomposition, parallelism, and traceability'
}
scoreProtocolCandidate(candidate, context)
Scores a single BT specification against calibration instances.
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
candidate.spec |
string |
Yes | — | BT spec string |
candidate.id / candidate.name |
string |
No | Auto-generated | Candidate identifier |
candidate.metrics |
object |
No | {} |
{ p0, p1, c, gamma, validRate, avgVotes, counts } |
candidate.tokenEconomics |
object |
No | {} |
{ inputTokens, outputTokens, inputCostPer1M, outputCostPer1M, costUsd } |
candidate.uncertainty |
object |
No | {} |
{ consistency, uncertainty, confidence, samples } |
candidate.selfImproving |
object |
No | {} |
{ learnedGain, diversity, judgeAgreement, exampleQuality } |
candidate.temperature |
object |
No | {} |
{ useTemperatureVariation, firstVoteTemperature, subsequentTemperature } |
candidate.redflag |
object |
No | {} |
{ hasTokenLimit, maxTokens, hasSpikeThreshold, tokenSpikeThreshold, detectSelfContradiction, trackCollisions } |
candidate.oracle |
object |
No | {} |
{ pOracle, pSelected } |
candidate.decomposition |
object |
No | {} |
{ modes, parallelism } |
candidate.usesExecutionGraph |
boolean |
No | false |
Adds traceability bonus |
context.scoringProfile |
object |
No | DEFAULT_SCORING_PROFILE |
Scoring weight profile |
context.baselineAccuracy |
number |
No | 0.5 |
Baseline p0 fallback |
context.baselineEmbedding |
array |
No | — | Baseline embedding for diversity calculation |
Return value — see single candidate structure in growProtocol return above.
Scoring algorithm: The nursery computes a multi-objective score in two parts:
-
Economics score (weighted product):
econScore = gain × econMods × validRateMod × invGammaMod, where:gain = clamp01(p1Pred - p0 + 0.005)econMods = econBase + econCostEff × costEfficiency + econTemperature × tempDiversity + econRedflag × redflagQuality + econCpEff × cpEfficiencyinvGamma = clamp01(1 - gamma × breakEvenScale × 0.5)breakEvenScale = p0 / (1-p0)
-
Tchebycheff score: Measures worst-case weighted gap across 13 objectives (reliabilityGain, invGamma, validRate, quorumConv, temperatureDiversity, cpEfficiency, redflagQuality, consistency, learnedGain, oracleHeadroom, costEfficiency, decomposition, traceability).
Final score: score = round((econScore × (1 - tchebycheffWeight) + tchebycheffNormalized × tchebycheffWeight) × econScale)
DEFAULT_SCORING_PROFILE
Default weight configuration (frozen):
{
objectiveWeights: {
reliabilityGain: 8.0, invGamma: 4.0, validRate: 2.0,
quorumConv: 1.0, temperatureDiversity: 2.0, cpEfficiency: 2.0,
redflagQuality: 1.5, consistency: 1.0, learnedGain: 0.5,
oracleHeadroom: 1.0, costEfficiency: 3.0, decomposition: 1.0,
traceability: 0.5
},
econBase: 0.7, econCostEff: 0.15, econTemperature: 0.05,
econRedflag: 0.05, econCpEff: 0.05,
validRateWeight: 0.2, invGammaWeight: 0.5,
econScale: 1000, tchebycheffWeight: 0.3
}
defaultProtocolSeeds(options)
Returns an array of two default seed BT spec candidates:
quorum-redflag-verifier— 5-action VRFQ pipeline withp0: 0.7, c: 0.25, gamma: 0.02maximal-decomposition— 3-action decomposer withp0: 0.65, c: 0.2, gamma: 0.015
Each seed includes metrics, uncertainty, self-improving, tokenEconomics, and decomposition data.
DEFAULT_PACKAGE_ROLES
Frozen array of 22 Polyweave packages with their roles (e.g. { name: '@polyweave/bt-harness', role: 'behavior-tree control plane and evaluator-gated decomposition' }).
summarizePackageInventory(packages)
Normalizes a package inventory to { name, role } format. Accepts string arrays or object arrays.
createDomainFromSpec(spec, options)
Creates a domain object from a declarative domain specification with a composable verifier compiler.
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
spec.name |
string |
No | 'unnamed' |
Domain name |
spec.description |
string |
No | '' |
Domain description |
spec.type |
string |
No | 'batch' |
Domain type |
spec.capabilityRequirements |
array |
No | [] |
Required capabilities |
spec.taskTemplate |
string |
No | '{{task}}' |
Mustache-style prompt template |
spec.instanceGenerator |
object/function |
No | Simple seed generator | { type, name, parameters } or JS function |
spec.verifier |
object/function |
No | — | { type, rules[] } (composite) or JS function |
spec.critic |
object/function |
No | — | { onFailure: { code: message } } or JS function |
spec.slices |
object/function |
No | { all: 'true' } |
Slice predicate map { name: expr } |
options.jsEscapeHatch |
object |
No | {} |
Map of named JS functions for custom rules |
Return value: { name, description, capabilityRequirements, type, generateInstance(seed), generateInstances(count, startSeed), renderPrompt(instance), verify(output, instance), getSlice(instance), getCritique(verdict, instance), rawSpec }
Verifier rule types (compiled by createVerifierCompiler):
json_parse/is_object— output must be a JSON objectis_array— output must be a JSON arrayis_string— output must be a stringrequired_fields—{ fields: ['field', 'nested.field'] }— field presence checkinteger_range—{ field, min, max }— integer in rangepredicate—{ predicate: 'expr', code, message }— boolean expressionequals—{ field, value, fieldRef? }— equality checkarray_entry—{ rules: [...] }— each array entry checkedfunction—{ name }— delegates tojsEscapeHatch[name]code_exec—{ codeField, tests: [{ input, expected }] }— runs code through tests
Domain presets (from src/domain-presets.js): createHanoiSpec(), createJsonPatchSpec(), createBtSpecRepairSpec(), createFactGraphQuerySpec(), createHumanEvalSpec(). Accessible via DOMAIN_DEFAULTS map.
createDomainJsEscapeHatches()
Returns an object with JS functions for domain instance generation and verification:
generateHanoiInstance(seed, param)— generates Tower of Hanoi instancesverifyHanoiMove(output, instance)— verifies Hanoi move validitygenerateJsonPatchInstance(seed)— generates JSON patch instancesverifyJsonPatch(output, instance)— verifies patch correctnessgenerateBtSpecRepairInstance(seed)— generates BT spec repair instancesverifyBtSpecStructure(output, instance)— verifies repaired spec structuregenerateFactGraphQueryInstance(seed)— generates fact graph query instancesgenerateHumanEvalInstance(seed)— generates HumanEval-like instances
NURSERY_GROW_SPEC
A complete BT spec string used as the default spec for createNurseryGrowTool BT harness mode. Defines the grow loop: propose_protocols → validate_protocols → benchmark_protocols → score_protocols → promote_best (if improved) / record_stagnation (if not). Uses parametric maxIterations and patience, symbols for iteration/stagnation tracking, and selector-based branching for promote vs. stagnate.
Prompt Builders
buildBtHarnessSystemPrompt(options)— builds the system prompt for bt-harness protocol generation with domain context, pattern catalog, tool reference, scoring explanation, and 3-5 diverse spec generation instructionsbuildBtHarnessFeedbackPrompt(history, bestScore, bestSpec, domainContext, packageInventory)— builds feedback from prior rounds with per-candidate scores, c/gamma trace, improvement directionsbuildDomainContextForPrompt(domainSpec)— builds domain-aware context from a domain spec with name, task template (rendered), output schema, verifier checks, example instances, and slice definitions
Error Conditions
| Condition | Where | Handling |
|---|---|---|
| Candidate spec has no text | nrs_propose |
Returns { stored: false, error: 'Missing spec text' } |
| No valid candidate for benchmark | nrs_benchmark |
Returns { benchmarked: false, error: 'No valid candidate' } |
| No candidate to score | nrs_score |
Returns { scored: false, error: 'No candidate to score' } |
| Already running | startBtHarnessRun |
Returns ERROR frame with 'nursery already running' |
| Invalid BT harness spec | startBtHarnessRun |
Returns ERROR frame with joined errors |
| Domain spec parsing failure | initDomainContext (grow loop) |
Swallows error, sets domainObj = null, empty instances |
createDomainFromSpec missing JS function |
domain-spec rule compilation | Returns { passed: false, code: 'MISSING_FUNCTION' } |
code_exec compile/runtime error |
domain-spec verifier | Returns { passed: false, code: 'TEST_ERROR' } |
growProtocol exception |
createNurseryTool |
Caught, returned as TOOL_RESULT with { success: false, error } |
Tests
npm test
Runs node --test test/*.test.js. Covers:
scoreProtocolCandidatescoring invariants (score range, valid vs invalid, economics consistency)growProtocolbest candidate selection, execution graph recordingDEFAULT_SCORING_PROFILEimmutabilitydefaultProtocolSeedsstructuresummarizePackageInventorynormalizationcreateNurseryTooltool creation and DESCRIBE responsecreateNurseryGrowToolconstruction, quorum/redflag adapter injectioncreateDomainFromSpecwith composite verifier rulescreateDomainJsEscapeHatchesHanoi move generation and verificationbuildBtHarnessSystemPromptoutput structureNURSERY_GROW_SPECparseability
Requirements
- Node.js >= 22.0.0
- ESM only (
"type": "module") - Dependencies:
@polyweave/bt-harness,@polyweave/core,@polyweave/creativity,@polyweave/execution-graph,@polyweave/protocol-metrics,@polyweave/quorum,@polyweave/redflag,@polyweave/sampler,@polyweave/self-improving,@polyweave/state,@polyweave/uncertainty - Peer dependencies:
@polyweave/agent-loop,@polyweave/feedback-descent,@polyweave/flex,@polyweave/grpo,@polyweave/harness-base,@polyweave/meta-bt-harness,@polyweave/pool,@polyweave/prompt-manager,@polyweave/routing,@polyweave/smart-templates,@polyweave/state-search,@polyweave/tool-adapter,@polyweave/tools
Dependencies
Dependencies
| ID | Version |
|---|---|
| @polyweave/bt-harness | * |
| @polyweave/core | * |
| @polyweave/creativity | * |
| @polyweave/execution-graph | * |
| @polyweave/protocol-metrics | * |
| @polyweave/quorum | * |
| @polyweave/redflag | * |
| @polyweave/sampler | * |
| @polyweave/self-improving | * |
| @polyweave/state | * |
| @polyweave/uncertainty | * |
Development Dependencies
| ID | Version |
|---|---|
| @rigor/core | * |
Peer Dependencies
| ID | Version |
|---|---|
| @polyweave/agent-loop | * |
| @polyweave/feedback-descent | * |
| @polyweave/flex | * |
| @polyweave/grpo | * |
| @polyweave/harness-base | * |
| @polyweave/meta-bt-harness | * |
| @polyweave/pool | * |
| @polyweave/prompt-manager | * |
| @polyweave/routing | * |
| @polyweave/smart-templates | * |
| @polyweave/state-search | * |
| @polyweave/tool-adapter | * |
| @polyweave/tools | * |