You're reading the 0.10.0 archive.

hank.json

A hank.json file is the program a Hankweave run executes. It declares an immutable workflow: a sequence of codons (sealed agent tasks) and loops (repeated branches of codons) that the runner executes in order once the file loads. The root fields around that sequence set up the shared context – editor schema support, environment requirements, global prompt layers, and hank-level overrides – while the hank array itself is where the work happens.

This page is the field-level reference for that file. It explains what each key accepts, what the loader enforces beyond what an editor can check, and where the surrounding contracts (budgets, loops, sentinels, model routing) are documented.

How to read this page#

Use this page to look up the fields accepted in hank.json. The tables show the published JSON Schema, including types, required fields, constraints, and schema defaults. The text below each table adds loader behavior that an editor cannot check, such as file existence and model availability. Code blocks come from shipped fixtures and validation captures, so the spellings and diagnostics they show are the ones the runtime actually produces.

A [changed] or [since] marker appears only where the release history identifies a version. Model names in examples come from shipped fixtures. For configuration precedence, see Hanks; for file discovery and --validate, see the CLI reference.

The schema's root description still points to the stale URL https://hankweave.dev/reference/configuration; use this page instead.

Choose the hank's root fields#

A hank is a JSON workflow object. Only hank is required, and no fields outside the seven listed below are accepted. The root fields divide into three jobs: editor support ($schema), human-facing bookkeeping (meta), and run-wide behavior (requirements, overrides, and the global system prompt fields).

Scroll to explore the table →
fieldtypedefaultrequiredconstraintsdescription
$schemastringnoJSON Schema URL for editor support
metaobjectnoMetadata for sharing/indexing (optional)
overridesobjectnoArchitect's overrides (optional)
requirementsobjectnoRequirements that must be met for this hank to run (optional)
globalSystemPromptFilestring | array<string>noGlobal system prompt file(s) applied to all codons. Must be relative path(s) inside the hank directory using '/' separators; absolute paths, '..' escapes, and symlinks are rejected.
globalSystemPromptTextstringnoGlobal system prompt text applied to all codons
hankarray<codon | loop>yesminItems 1The immutable logic sequence (required)

$schema is an optional string for editor support. If it is absent, the runtime writes it back on every startup and during --validate, then prints + Added $schema to <file> for editor support. The value is https://unpkg.com/hankweave@latest/schemas/hank.schema.json.

The schemas are also available from the npm package, so you can wire them into an editor once and get autocomplete and inline validation for every configuration file Hankweave reads. In VS Code, map each file pattern to its schema:

JSON
{
  "json.schemas": [
    {
      "fileMatch": ["**/hank.json"],
      "url": "https://unpkg.com/hankweave@latest/schemas/hank.schema.json"
    },
    {
      "fileMatch": ["**/hankweave.json"],
      "url": "https://unpkg.com/hankweave@latest/schemas/hankweave.schema.json"
    },
    {
      "fileMatch": ["**/*.sentinel.json"],
      "url": "https://unpkg.com/hankweave@latest/schemas/sentinel.schema.json"
    }
  ]
}

meta contains required name and version, plus optional description and author. Metadata is for humans: it helps remember what was built six months from now. requirements contains env: string[]; each declared name is checked fail-fast at startup and during --validate by either the direct environment-variable name or its HANKWEAVE_-prefixed form. overrides contains hank-level settings; precedence is owned by Hanks.

globalSystemPromptFile is a string or string array of file references. globalSystemPromptText is inline text. Supplying both global-system fields is a load error. The global system prompt is prepended before codon appendSystemPromptFile or appendSystemPromptText content; the parts are joined with a blank line, then receive template replacement and HTML-comment stripping.

Global prompts apply the same instruction to every codon, which keeps workflow-wide conventions in one place instead of repeating them in each task prompt. Typical content includes workspace layout, coding standards, domain constraints, and project requirements:

Scroll to explore the table →
Use CaseExample Content
Workspace layout"The codebase is a TypeScript monorepo with packages/ for libraries and apps/ for applications."
Coding standards"Use functional components. All functions need JSDoc. No console.log in production."
Domain context"This is a fintech app. PII must never be logged. All amounts are in cents."
Project constraints"The project targets Node 22+. Don't use APIs removed in newer releases."

overrides may contain model, dataHashTimeLimit, sentinel, shimIdleTimeout, and budget. The sentinel override carries enablePersistence, healthCheckGracePeriodMs, and waitForAllHealthChecks. dataHashTimeLimit is accepted as a positive hank override but is not consumed by the 0.10.0 hashing calls; normal startup omits it when calling the execution setup, and --validate uses the built-in 5000-millisecond value directly. Budget allocation belongs to budgets, and config precedence belongs to Hanks; this page does not restate either contract.

hank is an array with at least one item: the immutable logic sequence whose codon order is fixed when the hank loads. Its items are codons – sealed agent tasks – or loops – repeated branches containing codons. An unknown root key is a load error. strand is not an alternate root key: only hank is legal. A file named strand.json is usable only when passed explicitly as a config path, because implicit discovery finds hank.json only.

[changed 0.10.0] The published root schema fields were fixed so editors no longer flag requirements and globalSystemPrompt* as unknown keys.

The shipped init fixture shows how these pieces fit together in a real file: the $schema and meta block at the root, then the first codon of the hank array with its prompt file, checkpointed files, and output copy step.

JSON
{
  "$schema": "https://unpkg.com/hankweave@latest/schemas/hank.schema.json",
  "meta": {
    "name": "My Workflow",
    "version": "1.0.0",
    "description": "Generated by hankweave init"
  },
  "hank": [
    {
      "id": "analyze-haiku",
      "name": "Analyze Project (Haiku)",
      "model": "haiku",
      "continuationMode": "fresh",
      "promptFile": "./prompts/analyze-haiku.md",
      "checkpointedFiles": ["analysis-haiku.md"],
      "outputFiles": [
        {
          "copy": ["analysis-haiku.md"]
        }
      ]
    },]
}

Hanks, hankweave.json, and environment variables.

Configure one codon#

A codon describes one sealed agent task. id, name, model, and continuationMode are required. You can omit type; its schema default is "codon". The full field list follows; the subsections after it group the fields by the three things a codon definition controls: what the model is asked to do, how failures and resource limits are handled, and how files move into, through, and out of the workspace.

Scroll to explore the table →
fieldtypedefaultrequiredconstraintsdescription
typestringcodonno= codonType discriminator - optional, defaults to 'codon'
idstringyesminLength 1Unique identifier for this codon (e.g., 'codon-1', 'data-analysis')
namestringyesminLength 1Human-readable name displayed in UI and logs
promptFilestring | array<string>noPath to a file containing the prompt (mutually exclusive with promptText). Must be a relative path inside the hank directory using '/' separators; absolute paths, '..' escapes, and symlinks are rejected.
promptTextstringnoInline prompt text (mutually exclusive with promptFile)
appendSystemPromptFilestring | array<string>noPath to a file containing system prompt to append (mutually exclusive with appendSystemPromptText). Must be a relative path inside the hank directory using '/' separators; absolute paths, '..' escapes, and symlinks are…
appendSystemPromptTextstringnoInline system prompt text to append (mutually exclusive with appendSystemPromptFile)
modelstringyesminLength 1Model to use for this codon. Can be a Claude model ('sonnet', 'opus'), Gemini model ('gemini-2.0-flash-exp', 'flash'), or any other model supported by the configured shim.
continuationModeenumyesfresh | continue-previousHow this codon should handle continuation from previous codons. 'fresh': Start a new session (default for most cases). 'continue-previous': Continue from the previous codon's session, maintaining context and conversatio…
rigSetuparray<copy | command>noRig setup operations to run before codon starts. Each operation must complete successfully for codon to start.
descriptionstringnoOptional description shown to users about what this codon does
checkpointedFilesarray<string>noGlob patterns for files to checkpoint during codon execution. These files will be: watched for changes and streamed to the client, tracked in the git-based checkpoint system, and resolved using gitignore rules for consi…
envobject<string>noOptional environment variables to set for the Claude process
outputFilesarray<object>noOptional output copy steps to run after codon completion: files to copy out from a completed codon, with optional pre-copy commands.
sentinelsarray<object>noSentinels to run during this codon. Sentinels are parallel observation agents that process the event stream. Each entry is a wrapper object with sentinelConfig (portable sentinel configuration, file or inline) and setti…
archiveOnSuccessarray<string>noPaths to archive after successful completion. These files/directories are moved to rigArchive/ after the codon completes successfully. Paths are relative to the agent workspace (agentRoot/). Archived files can be restor…
onFailureenumnoabort | retry | ignoreHow to handle codon failure. 'abort' (default): Use existing failure behavior (server stays active for retriable errors, shuts down for non-retriable). 'retry': Automatically retry up to maxAttempts times if the error i…
retryConfigobjectnoConfiguration for retry behavior. Only used when onFailure is 'retry'. Delays grow exponentially from delayMs and are capped at maxDelayMs; when the provider supplies a Retry-After hint, that value is used instead of th…
exhaustWithPromptstringnoPrompt to send when extending codon until context exhaustion. When set, the codon will automatically continue with this prompt after each successful completion until context is exhausted.
maxExtensionsinteger100no> 0Maximum number of extensions before forcing completion. Default: 100. Safety valve to prevent infinite extension loops.
autoCompactbooleannoWhether the harness may auto-compact (summarize/trim) the session when the context window fills. Default: false — compaction is disabled, the provider's context-overflow error surfaces instead, plain codons fail at the…
shimIdleTimeoutintegerno> 0; max 1800Max seconds between agent events before the session aborts (idle timeout). Overrides hank-level and runtime defaults. If unset, falls back to hank override, runtime config, or the built-in default (180s for Anthropic mo…
budgetobjectno

Choose prompt and model inputs#

The published descriptions call promptFile and promptText mutually exclusive, but the loader behaves differently: at least one is required, both are accepted, and promptFile wins when both are present. By contrast, appendSystemPromptFile and appendSystemPromptText cannot be used together.

The loader resolves model against the provider registry. An unrecognized name fails at load. See model resolution for shortcuts, routing, and harnessOverride. The schema's older phrase “configured shim” means the runtime adapter selected for the provider.

continuationMode accepts "fresh" or "continue-previous". See codons for handoff requirements, model matching, and context-exhaustion behavior.

Control failure and resource limits#

onFailure is the string enum abort | retry | ignore and defaults to abort. retryConfig is accepted only with onFailure: "retry".

[since 0.6.1] A codon budget can set maxDollars, maxTimeSeconds, maxOutputTokens, maxContextTokens, and onExceeded: complete | fail. A codon-level onExceeded overrides the hank-level policy. When a measured limit is reached, the budget tracker emits an exceeded event and the runner requests SIGTERM. onExceeded: "complete" marks that interrupted codon as completed; it does not let the model finish its current reasoning. onExceeded: "fail" marks it failed. See budgets for metering and allocation.

[changed 0.8.0] autoCompact defaults to false, so the provider's context-overflow error surfaces instead of silent compaction. shimIdleTimeout must be a positive integer no greater than 1800. Its fallback is 180 seconds for Anthropic models through the Claude SDK and 120 seconds for other providers through the embedded Pi SDK. An idle-timeout abort is retriable.

exhaustWithPrompt asks a successfully completed codon to continue until context exhaustion. maxExtensions, which defaults to 100, prevents an infinite extension loop. See codons for the complete extension behavior.

Move files into, through, and out of the workspace#

rigSetup runs before the codon. In a loop, rigSetup without allowFailure: true produces a warning; allowFailure controls whether a failed setup operation fails the codon.

checkpointedFiles contains glob patterns over the agent workspace and follows gitignore rules. Configuration file references such as promptFile are different: they do not use globs or gitignore rules.

[changed 0.9.0] A failure in outputFiles copying or beforeCopy fails the run. outputFiles[].copy is a non-empty list of globs selected from agentRoot and copied to the configured output directory. beforeCopy commands run in agentRoot, including commands whose schema uses workingDirectory: project. The published descriptions retain the older execution directory and executionPath terms. There is no default output directory; see the runbook.

archiveOnSuccess contains file globs relative to agentRoot. Matching files move to rigArchive/ after success and can be restored during rollback. See execution directory for the archive layout.

sentinels attaches event observers to the codon without changing how the codon itself executes. Each entry is a wrapper object containing sentinelConfig, either a file reference or inline object, plus optional codon-scoped settings: failCodonIfNotLoaded, outputPaths.logFile, outputPaths.lastValueFile, and the lifecycle, errors, outputs, and triggers switches under reportToWebsocket. See sentinel configuration for the full contract.

The env object sets variables for the agent process. Its generated schema description retains the older phrase “Claude process.”

The anchor fixture demonstrates a three-step rigSetup: create pipeline, copy rigs/preflight.ts to pipeline/preflight.ts, and run bun pipeline/preflight.ts.

The init fixture provides the codon spelling and model examples used here; its visible excerpt is in the root-key entry above. The anchor fixture shows the sentinel wrapper shape – a single sentinelConfig file reference – without retyping the sentinel's own configuration:

JSON
      "sentinels": [
        {
          "sentinelConfig": "sentinels/quality-observer.json"
        }
      ],

Codons, model resolution, sentinel configuration, and the runbook.

Repeat codons with a loop#

A loop repeats one or more codons until its termination condition is met. type, id, name, terminateOn, and codons are required, and type must be "loop".

Scroll to explore the table →
fieldtypedefaultrequiredconstraintsdescription
typestringyes= loopType discriminator - required for loops
idstringyesminLength 1Unique identifier for this loop
namestringyesminLength 1Human-readable name displayed in UI and logs
descriptionstringnoOptional description shown to users
terminateOniterationLimit | contextExceededyesTermination condition for the loop
codonsarray<object>yesminItems 1Array of codons to execute in each iteration
budgetobjectnoBudget scope for this loop.
archiveOnSuccessarray<string>noPaths to archive when the loop terminates. Paths are relative to the agent workspace.

terminateOn is an object variant: it accepts either iterationLimit with an integer limit of at least 1, or contextExceeded. Termination semantics belong to loops. codons contains plain codons only, with at least one item; nested loops are not supported in v1.

Loop and hank overrides budgets share {maxDollars, maxTimeSeconds, allocation: shared | proportional | proportional-strict, shares: Record<id, 0-1>, onExceeded}. allocation defaults to shared; codon budgets additionally carry token caps. A loop-level archiveOnSuccess archives its paths once, when the loop terminates, relative to the agent workspace.

A contextExceeded loop containing any continuationMode: "fresh" codon is a fatal load error. Inside a loop, a continue-previous codon whose model differs from the preceding codon is a fatal load error. Duplicate codon IDs are fatal globally and within a loop; duplicate codon names produce a warning.

The checked loop fixture below shows the structure in full: one loop wrapping two codons (append-a and append-b), bounded by iterationLimit: 2. Both codons checkpoint log.txt so its state carries across iterations, and the second codon copies it out through outputFiles. The terminal capture under the fixture shows how --validate reports the result: the workflow summary counts the codons and the loop separately ("2 codons • 1 loop").

JSON
{
  "$schema": "https://unpkg.com/hankweave@0.10.0/schemas/hank.schema.json",
  "meta": {
    "name": "Minimal loop",
    "version": "1.0.0",
    "description": "Two haiku codons inside one loop bounded by iterationLimit 2."
  },
  "hank": [
    {
      "type": "loop",
      "id": "append-loop",
      "name": "Append loop",
      "terminateOn": {
        "type": "iterationLimit",
        "limit": 2
      },
      "codons": [
        {
          "id": "append-a",
          "name": "Codon A appends",
          "model": "haiku",
          "continuationMode": "fresh",
          "promptFile": "./prompts/append-a.md",
          "checkpointedFiles": [
            "log.txt"
          ]
        },
        {
          "id": "append-b",
          "name": "Codon B appends",
          "model": "haiku",
          "continuationMode": "fresh",
          "promptFile": "./prompts/append-b.md",
          "checkpointedFiles": [
            "log.txt"
          ],
          "outputFiles": [
            {
              "copy": [
                "log.txt"
              ]
            }
          ]
        }
      ]
    }
  ]
}
Output
✓ Configuration is valid!

╭──────────────────────────────────────────────────────────────────────────────╮
│  Minimal loop v1.0.0                                                         │
│  2 codons • 1 loop                                                           │
╰──────────────────────────────────────────────────────────────────────────────╯

Loops and budgets.

Keep file references inside the hank directory#

Configuration file references must be relative to the directory containing hank.json, use / as the separator, remain inside that directory, and avoid symlinks. For example, "prompts/summarize.md" is portable. "/etc/hosts", "..\prompts\summarize.md", and "../../shared/summarize.md" fail validation.

Not every path in a hank follows that rule, because fields anchor to two different roots. Authoring-time references (promptFile, global prompt files, rig sources) resolve against the hank directory, which is fixed when the file loads. Execution-time references (checkpointedFiles, outputFiles, archiveOnSuccess, rig targets) resolve against the agent workspace (agentRoot), which exists only at runtime. Use this table to choose the correct base for each field:

Scroll to explore the table →
FieldBaseExtra rules
promptFile, appendSystemPromptFile, globalSystemPromptFilehank directoryRelative / spelling; contained and symlink-free
String sentinelConfighank directoryIts internal file refs use the config file's directory [changed 0.10.0]
Sentinel-config internal refsconfig file's directoryHank directory remains the containment anchor [changed 0.10.0]
rigSetup.copy.fromhank directoryCopy-tree scan; cannot name the hank directory itself
rigSetup.copy.toagent workspace (agentRoot) at runtimePublished schema/validator use projectPath / executionPath; full target path, including its final name
checkpointedFilesagent workspaceGlob patterns use gitignore rules
outputFiles[].copyagent workspace (agentRoot) → output directoryNon-empty glob list; the published schema says “execution directory”; destination behavior belongs to the runbook
archiveOnSuccessagent workspacePaths move to rigArchive/ after success
Template variablesagentRoot<%DATA_DIR%> resolves below the read-only data mount

Absolute paths, drive-qualified paths such as C:, backslashes, NUL characters, and paths that leave the hank directory are rejected. A spelling that leaves and then re-enters the directory is also rejected. The loader rejects the first symlink below the hank directory. A symlink in the path leading to the hank itself does not count, but a symlinked directory inside the hank does.

[changed 0.10.0] These rules apply to promptFile, appendSystemPromptFile, globalSystemPromptFile, rigSetup.copy.from, and string sentinelConfig values. Within a file-based sentinel configuration, systemPromptFile, userPromptFile, and structuredOutput.schemaFile resolve from that configuration file's directory while still remaining inside the hank directory.

For rigSetup.copy.from, validation scans the whole source tree before the codon starts. It rejects symlinks, including dangling ones, and non-regular files such as FIFOs, sockets, and devices. It reports entries in a consistent sort order. copy.from also cannot name the hank directory itself, including through . or sub/... These checks are [changed 0.10.0].

At runtime, rigSetup.copy.to is joined to agentRoot. The published schema and validator use the older projectPath and executionPath terms. Supply the full target path, including the final file or directory name; that target can rename a copied file or directory.

Validation checks spelling and containment before probing whether a path exists, so it never touches a forbidden path. It collects all reference violations before reporting them. Referenced files must be regular files, so a FIFO is rejected before any read could block.

The exact path-violation messages use these forms:

Scroll to explore the table →
ProblemDiagnostic
Absolute or drive-qualified"<path>" is an absolute or drive-qualified path; hank refs must be relative paths inside the hank directory
Backslash"<path>" contains a backslash; hank refs use "/" as the only path separator
NUL character"<path>" contains an invalid character (NUL)
Leaves the hank directory"<path>" resolves outside the hank directory (<resolved>); move the file into the hank directory
Path crosses a symlink"<path>" passes through a symlink at "<component>"; symlinks are not allowed in hank refs
Copied tree contains a symlink"<path>" contains a symlink at "<entry>"; symlinks are not allowed anywhere in a copied tree
Copied tree contains another file type"<path>" contains a non-regular file at "<entry>"; only regular files and directories can be copied

The captures below show those messages as --validate emits them. Each one pinpoints a different failure: a path that climbs out of the hank directory, a reference to a file that does not exist, an absolute path, and a backslash separator. All four exit with code 1. The absolute path in the missing-file diagnostic is fixture output, not a path to copy into a hank.

Output
Validation failed:
…
   • - Codon "Write one line" (write-line) - promptFile: "../../minimal-single-provider/prompts/summarize.md" resolves outside the hank directory; move the file into the hank directory
exit=1
Output
Validation failed:
…
   • Codon 1 (write-line): promptFile "<workspace>/fixtures/scenarios/ref-violations/prompts/does-not-exist.md" does not exist
exit=1
Output
Validation failed:
…
   • - Codon "Write one line" (write-line) - promptFile: "/etc/hosts" is an absolute or drive-qualified path; hank refs must be relative paths inside the hank directory
exit=1
Output
Validation failed:
…
   • - Codon "Write one line" (write-line) - promptFile: "prompts\write-one-line.md" contains a backslash; hank refs use "/" as the only path separator
exit=1

The anchor fixture's normalize-aster codon shows the command and copy operation shapes that these rules apply to:

JSON
      "rigSetup": [
        {
          "type": "command",
          "command": {
            "run": "mkdir -p pipeline"
          }
        },
        {
          "type": "copy",
          "copy": {
            "from": "rigs/preflight.ts",
            "to": "pipeline/preflight.ts"
          }
        },
        {
          "type": "command",
          "command": {
            "run": "bun pipeline/preflight.ts"
          }
        }
      ],

Rigs, execution directory, and first-run failures.

Refer to workspace paths in prompts#

Prompt text cannot know the absolute workspace path in advance. Use one of these variables; Hankweave replaces it when the codon loads the prompt:

Scroll to explore the table →
VariableResolution
<%AGENT_ROOT%>The canonical, recommended agent workspace
<%PROJECT_DIR%>Silent alias of AGENT_ROOT
<%EXECUTION_DIR%>Silent alias of AGENT_ROOT
<%DATA_DIR%><agentRoot>/read_only_data_source, the linked or copied input data, treated as read-only by convention

Replacement applies to user prompts, exhaustWithPrompt, and system prompts. It does not apply to configuration path fields such as archiveOnSuccess. Hankweave also strips HTML comments from prompt content in this pass. See authoring prompts for prompt-writing guidance.

Authoring prompts and execution directory.

Fix unknown field names#

When the loader recognizes a likely typo, it reports Unknown field "x". Did you mean "y"?. The table below maps the misremembered or deprecated names it recognizes to the fields you should use instead:

Scroll to explore the table →
If you wroteUse
systemPromptFile, systemPromptText, or systemPromptappendSystemPromptFile, appendSystemPromptText, or one of those two fields
prompt, prompts, or promptFilespromptFile or promptText as suggested by the diagnostic
trackedFiles, tracking, tracked, watchedFiles, or fileTrackingcheckpointedFiles
rig, setup, or preSetuprigSetup
archiveRigs, rigTeardown, teardown, archive, cleanup, archiveRig, archiving, or archivesarchiveOnSuccess
environment or envVarsenv
outputs or outputoutputFiles
continuation or modecontinuationMode
costLimit, maxBudget, maxCost, or unnested maxDollarsbudget.maxDollars
maxDuration, maxDurationSeconds, unnested maxTimeSeconds, or timeLimitbudget.maxTimeSeconds
maxTokens, unnested maxOutputTokens, or tokenLimitbudget.maxOutputTokens

An unknown field outside the map lists valid fields for its position: root, codon, or loop. A root-level codon field also receives a hint to move it inside a codon in the hank array. Loop bodies are checked as nested positions.

The capture shows the diagnostic as --validate reports it: a codon using the old trackedFiles name fails with exit code 1 and a pointer to checkpointedFiles.

Output
Validation failed:
…
   • - Codon "Write one line" (write-line) - trackedFiles: Unknown field "trackedFiles". Did you mean "checkpointedFiles"?
exit=1

CLI --validate and errors and exit codes.

Decide whether a load message blocks the run#

Load errors stop the hank. Warnings do not: startup prints them under ! Configuration warnings: after the hank structure and budget table. --validate presents them under Warnings: and still exits with code 0, so a validated file can carry actionable advice without failing.

Errors include a missing prompt source, an invalid retryConfig, incompatible continuation settings, duplicate IDs, a forbidden copy.from, missing or unreadable files, invalid sentinel configurations, and failed self-tests. After a hank loads, model-based extraction can still fail like any other model task; its onFailure value controls what happens next.

Configuration warnings cover valid but suspicious choices in four areas:

Scroll to explore the table →
AreaWarning conditions
Names and loopsDuplicate codon names; loop codons with rigSetup but without allowFailure: true; loop codons relying on the onFailure: abort default
Prompt filesEmpty files or files larger than 1 MB
RigsExisting copy targets and dangerous command patterns, including root or home deletion, raw disk writes, formatting, and Windows recursive deletion
ContinuationA first codon using continue-previous; continuation from a codon with no checkpointed files; onFailure: ignore followed by continue-previous

Budget preflight adds its own warnings when a limit cannot work as configured or may produce a surprising result:

Scroll to explore the table →
AreaWarning conditions
Proportional allocationA hank- or loop-scoped child cap exceeds its allocation; shares leave money unallocated with no unshared codon to receive it; a codon starts with zero effective budget
Interruption and retriesexhaustWithPrompt is subject to a time budget; onExceeded: "fail" is combined with onFailure: "retry"
Shared poolsA later codon uses onExceeded: "fail" but an earlier codon may exhaust the pool
Model and time limitsA dollar-limited model has no pricing data; a codon time cap exceeds its loop's cap

Self-tests run on every startup, not only during --validate, once for each unique harness:provider/model identity. Here, harness is the selected runtime adapter. Self-test notices can appear with configuration warnings, but a failed self-test aborts configuration loading with category-specific guidance. See authentication and models for the two model-selection planes.

The capture below demonstrates the distinction: the hank validates successfully and exits with code 0, yet the validator still warns that codon 2 continues from a previous codon that checkpoints no files – a handoff that will run but may not carry the state the author expected.

Output
✓ Configuration is valid!
…
Warnings:
  - Codon 2 (write-second): Continues from previous codon "write-line" doesn't checkpoint any files
exit=0

CLI --validate, errors and exit codes, and authentication and models.

Why an editor-valid file can still fail at load#

A hank file can pass the editor's JSON Schema check and still fail when the loader loads it because the published schema is deliberately looser than runtime validation. The editor verifies shape; the loader verifies that the workflow can actually run.

The loader adds three layers of checks that the published schema does not cover:

  1. Its runtime schema validator checks prompt presence, system-prompt exclusivity, retryConfig, model resolution, path spelling, and whether a path remains inside the hank directory.
  2. Filesystem-aware checks reject missing files, symlinks, special files, unsafe copied trees, and invalid field combinations.
  3. Startup checks enforce requirements.env, run model self-tests, and verify catalog availability.

An editor cannot establish whether a path exists or crosses a symlink. It also cannot know the directory of a referenced sentinel configuration. For that reason, spelling and containment checks begin in the runtime schema validator, while filesystem checks happen in the loader. References inside a file-based sentinel configuration receive only the portable-spelling check until the loader knows that file's location.

At config load, Pi – Hankweave's embedded runtime SDK – runs the model_catalog preflight to check whether a registry-known model is servable by that runtime. A miss fails before earlier codons spend money and lists models available for that provider.

Run CLI --validate to apply these checks before execution. See errors and exit codes for outcomes and model resolution for catalog behavior.

This page defines hank.json fields. The surrounding configuration is documented here:

For the concepts behind the fields, see codons, loops, rigs, sentinels, and budgets.