A sentinel observes a running codon from the outside. While a codon (a sealed unit of agent work) executes, the sentinel watches the event stream, batches matching events into language-model calls, and writes a report. This page is the lookup reference for the JSON configuration that controls all of that: which events to match, when to call the model, what the prompt sees, and where the output goes.
The configuration lives in a hank directory, the folder containing the hank's JSON configuration, hank.json, including its meta, overrides, and hank array. Sentinel configurations are attached to individual codons from that file, either as file references or inline objects; the attachment mechanics are at the end of this page, after the field reference.
The sections follow the order you will usually need them: the top-level fields first, then triggers and execution strategies, then prompts, output, error handling, and finally the codon wrapper and the list of events that can actually reach a sentinel. Each table is generated from the published schema; the prose around it records the runtime behavior that a schema cannot express, including several checks that happen at load time or first call rather than at validation.
Schema fields and runtime checks#
Use the tables to look up types, required fields, and bounds from the published sentinel.schema.json (docs.lock hash 63b4609a…). The text below them covers runtime checks that JSON Schema cannot express. Version markers identify when a field changed.
Two publication details are worth knowing before you rely on the schema in an editor. The published schema description still links to https://hankweave.dev/reference/sentinel-config; use Sentinel configuration instead. And the runtime sentinel parser is strict and does not declare a $schema property. The published $schema row is editor metadata, so associate the schema in the editor rather than placing $schema inside a sentinel configuration.
Define top-level fields#
A sentinel configuration is a strict object with 18 published properties. id, name, trigger, execution, and model are required; other keys are rejected.
| field | type | default | required | constraints | description |
|---|---|---|---|---|---|
id | string | yes | minLength 1; pattern ^[a-z0-9-]+$ | ||
name | string | yes | minLength 1 | ||
description | string | no | |||
trigger | event | sequence | yes | |||
execution | immediate | debounce | count | timeWindow | yes | |||
systemPromptFile | string | array<string> | no | System prompt file(s), relative to this config file's directory (or the hank directory for inline configs), using '/' separators. Must stay inside the hank directory; absolute paths and symlinks are rejected. | ||
systemPromptText | string | no | |||
userPromptFile | string | array<string> | no | User prompt file(s), relative to this config file's directory (or the hank directory for inline configs), using '/' separators. Must stay inside the hank directory; absolute paths and symlinks are rejected. | ||
userPromptText | string | no | |||
conversational | object | no | |||
errorHandling | object | no | |||
llmParams | object | no | |||
model | string | yes | The full model ID to use (e.g., "anthropic/claude-3-5-sonnet-20241022", "openai/gpt-4-turbo"). | ||
structuredOutput | object | no | |||
joinString | string | no | String to join entries in text-based log file. Only valid for text output. Supports escape sequences: \n (newline), \t (tab), \r (carriage return), \ (backslash). Defaults to '\n---\n' for visual separation. | ||
reportToWebsocket | object | no | |||
output | object | no | |||
$schema | string | no | JSON Schema URL for editor support |
Most of these fields behave as the table suggests; id and model carry extra runtime rules. id uses lowercase letters, numbers, and hyphens, and duplicate IDs in one codon are rejected at load.
The model field decides whether the sentinel can run at all, and the check depends on the form of the ID. The schema describes model as a full model ID. For a slash-containing model, a missing registry entry, an unconfigured provider, or a failed or pending provider health check causes the sentinel to be skipped with an info-level Skipping sentinel <id>: … message; the codon proceeds. A slash-less short name such as haiku skips that load-time gate: the sentinel loads and fires, then always fails its first LLM call with llm-call-failed: No LLM provider available, because only slash-containing full model IDs receive a provider call.
A captured quality-observer run used anthropic/claude-haiku-4-5 and produced a report. That report is an event-observer result: it can summarize the completion event it received, but it cannot verify artifact existence, row coverage, or artifact correctness without corresponding event data. Model shortcuts and model-selection planes are documented in model resolution and authentication and models. AWS Bedrock covers sentinel credentials. The general path/ref contract belongs to hank.json; this page only states sentinel-specific reference bases.
Match events with triggers#
The required trigger field decides which events the sentinel cares about. It is a discriminated union with an event form (match individual events, optionally filtered by conditions) and a sequence form (match an ordered pattern across the event history).
| field | type | default | required | constraints | description |
|---|---|---|---|---|---|
event | object | type = event | |||
↳ on | array<string> | yes | minItems 1 | ||
↳ conditions | array<object | object | contains | matches | object> | no | |||
sequence | object | type = sequence | |||
↳ interestFilter | object | yes | |||
↳ ↳ on | array<string> | yes | minItems 1 | ||
↳ pattern | array<object> | yes | minItems 1 | ||
↳ options | object | no | |||
↳ ↳ consecutive | boolean | no |
Both forms are validated against the live runtime, not just the schema. Every named event type in on is checked against the live serverEventTypes list at load. Condition paths use dot notation into event.data, such as exitStatus.type, and are checked against the named event type's data shape; that path check is skipped when on contains *. Conditions in one array are AND-ed, and a missing path evaluates to undefined and does not match. The eight operators are equals, notEquals, in, notIn, contains, matches, greaterThan, and lessThan; equals and notEquals take a string, number, boolean, or null; in and notIn take a non-empty array of strings or numbers; contains and matches take strings; and greaterThan and lessThan take numbers.
The sequence form adds state. A sequence keeps an in-memory history of interest-filtered events capped at 1000 per sentinel and tracks the last trigger position to avoid duplicate matches. options.consecutive defaults to true: consecutive matching must reach the exact history tail, while false matches pattern steps greedily with gaps allowed. Wildcards are accepted in the interest filter and pattern-step types. This history cap is separate from the template and queue caps below.
Batch events with execution strategies#
Matching an event does not call the model directly. The required execution field controls when matched events become LLM calls, so a sentinel can react to every match or accumulate matches into batches.
| field | type | default | required | constraints | description |
|---|---|---|---|---|---|
immediate | object | strategy = immediate | |||
debounce | object | strategy = debounce | |||
↳ milliseconds | integer | yes | > 0; max 300000 | ||
count | object | strategy = count | |||
↳ threshold | integer | yes | > 0; max 1000 | ||
timeWindow | object | strategy = timeWindow | |||
↳ milliseconds | integer | yes | > 0; max 3600000 |
immediate queues one batch per match. debounce accumulates matches until a quiet-period timer fires. count queues at its threshold. timeWindow queues on a periodic schedule.
Batching interacts with a bounded queue. Each sentinel processes its trigger queue serially, so new matches wait while an item is processed. The queue is capped at 100 triggers and 10000 total events. When either cap is reached, the oldest trigger is dropped with an info-level log; once the queue passes 70% of the trigger cap, it logs [Sentinel:<id>] Queue backpressure: <n>/100 triggers queued at info level. At codon completion, pending accumulated events are flushed and the queue drains before the codon is considered done. Sentinel concepts covers the observer lifecycle and drain semantics.
Prompts and template context#
Once a batch fires, the prompts decide what the model actually sees. A sentinel must define at least one of userPromptFile and userPromptText. Supplying both is accepted: file content is assembled first and text is appended, so these fields are not an XOR pair. Prompt-file fields accept a string or an array of strings; array entries concatenate in order. File-based references resolve from the directory containing that sentinel configuration, while inline configurations resolve from the hank directory. In 0.10.0, systemPromptFile, userPromptFile, and structuredOutput.schemaFile use each file configuration's own directory instead of the first configuration's directory. Escape and symlink (filesystem-link) checks run when the codon starts and again on cache hits.
Prompts are Eta templates with caching enabled and autoEscape: false, so rendered text is raw. The available context is:
| Context property | Meaning |
|---|---|
it.events | Triggering events, capped at the first 1000 events |
it.codon.id | Current codon ID |
it.codon.name | The sentinel configuration's name |
it.codon.description | The sentinel configuration's optional description |
it.codon.startTime | Time the sentinel run started |
it.world.currentTime | Trigger queue time |
Three properties of this context trip people up. it.world.currentTime is trigger.queuedAt, not template-execution time. Templates execute synchronously and cannot be interrupted, so keep them lightweight and avoid complex computation or infinite loops. And it.timestamp and it.context are not part of the context.
Most importantly, event data reaches the model only when the template interpolates it; a prompt without <%= it.events %> receives no event data. The sweep capture demonstrates both cases: an untemplated prompt produced a no-events response, while the Eta-templated prompt reported the received codon.completed event. The captured report is shown first; the event stream follows.
Templated sweep report.
---
# Sweep Report
1. Received 1 event of type `codon.completed`.
2. Codon `step-two` completed successfully with a cost of $<cost> and duration of <ms>ms.
3. Sweep: clean
The captured event stream is available here. Note the sentinel.output entry from the untemplated run: the model explicitly reports that no event data was provided, which is what a missing <%= it.events %> interpolation looks like from the outside.
Captured sentinel event stream.
{"id":"<id>","timestamp":"<ts>","type":"codon.completed","data":{"codonId":"step-one","success":true,"cost":"<n>","duration":"<n>","exitStatus":{"type":"success"}}}
{"id":"<id>","timestamp":"<ts>","type":"codon.completed","data":{"codonId":"step-two","success":true,"cost":"<n>","duration":"<n>","exitStatus":{"type":"success"}}}
{"id":"<id>","timestamp":"<ts>","type":"sentinel.triggered","data":{"sentinelId":"sweep-observer","codonId":"step-two","triggerNumber":1,"strategy":"immediate","eventCount":1,"queueSize":0}}
{"id":"<id>","timestamp":"<ts>","type":"sentinel.output","data":{"sentinelId":"sweep-observer","codonId":"step-two","triggerNumber":1,"outputType":"text","content":"I don't see any events in your message. You've described a scenario involving codon completion events and asked me to write a sweep report, but no actual event data has been provided for me to analyze.\n\nTo write the three-line report you've requested, I would need to see the events themselves. Could you please share:\n\n- The event log or event stream from the two-codon run\n- Details about each `codon.completed` event (success/failure status, costs if applicable)\n\nOnce you provide the events, I can generate:\n1. Count of codon.completed events and their success status\n2. Total cost calculation\n3. Sweep status assessment\n\nPlease paste the events and I'll write your report.","cost":"<n>","tokens":{"input":102,"output":158},"eventCount":1}}
The captured quality-observer report likewise cites completion-event data and explicitly says that artifact existence, row coverage, and correctness cannot be verified from that event data. Use a rig (an executable setup or checker) or an artifact-reading codon for filesystem assertions; a sentinel is an event observer, not a filesystem-tool session.
Hank JSON owns the general reference-path contract. Environment variables lists sentinel-scoped provider keys.
Bound conversational history#
By default each trigger is an independent LLM call. Conversational mode instead retains history across triggers, and because that history grows, it requires a trimming strategy.
| field | type | default | required | constraints | description |
|---|---|---|---|---|---|
conversational | object | no |
trimmingStrategy is required: maxTurns is an integer greater than 0 and at most 100, while maxTokens is an integer greater than 0 and at most 100000. continueOnError defaults to false. A conversational sentinel also requires systemPromptFile or systemPromptText. maxTurns prunes the oldest complete user-and-assistant turns. maxTokens prunes the oldest messages using exact token counts when available and a text.length / 4 estimate for older messages; that mode may break turn pairing.
History persists through atomic writes at .hankweave/sentinels/history/{sentinel-id}-codon-{codon-id}.json, so state resumes after a server restart. The consecutive-failure threshold does not apply to conversational sentinels; category-specific fatal policy still applies, so corruption unloads unless continueOnError is true.
Constrain structured output#
Structured output selects object, array, or enum output and constrains which schema material may accompany it.
| field | type | default | required | constraints | description |
|---|---|---|---|---|---|
structuredOutput | object | no |
The modes have complementary requirements. Enum mode requires a non-empty enumValues array and forbids schema fields. Object and array modes require exactly one of schemaStr and schemaFile and forbid enumValues. Schema code is evaluated with the Zod z object already in scope; neither inline code nor a schema file needs an import, and the result must be a Zod schema or loading fails.
Structured output also adds a model-capability requirement, checked late rather than at load. A structured-output sentinel with a full slash model whose registry entry lacks tool-call capability loads and fires, then fails its first structured-output call with a fatal configuration error when real providers exist. The capability check is invoked when a trigger fires, not as a load-only rejection. Slash-less short names follow the separate load-and-first-call behavior described under top-level fields. With structuredOutput, output.format is rejected and joinString is invalid.
Set LLM parameters#
llmParams bounds response-generation settings and merges defaults when fields are absent.
| field | type | default | required | constraints | description |
|---|---|---|---|---|---|
llmParams | object | no |
The runtime defaults are temperature: 0, maxOutputTokens: 8192, and maxRetries: 2. Temperature 0 is the deterministic default for consistent sentinel output. Authentication and models covers provider access and model-selection planes.
Error handling and unloading#
Error handling counts consecutive failures and applies category-specific unloading rules.
| field | type | default | required | constraints | description |
|---|---|---|---|---|---|
errorHandling | object | no |
maxConsecutiveFailures defaults to 3. A non-conversational sentinel unloads when consecutive failures reach that threshold; one success resets the counter. Fatal policy is category-based: template and configuration errors always unload; resource errors never unload; an explicit unload request takes precedence. A corruption error unloads a conversational sentinel unless continueOnError is true; for a non-conversational sentinel it is retained and handled by the consecutive-failure threshold.
One schema field is misleading here. unloadOnFatalError is present in the schema with a stated default of true, but the runtime never reads it. It is metadata, not an effective switch. See errors and exit codes for the failure taxonomy and exit behavior.
Write output files#
A sentinel writes text or JSONL output. Structured output is always NDJSON, one JSON object per line, regardless of output.format.
| field | type | default | required | constraints | description |
|---|---|---|---|---|---|
output | object | no | |||
joinString | string | no | String to join entries in text-based log file. Only valid for text output. Supports escape sequences: \n (newline), \t (tab), \r (carriage return), \ (backslash). Defaults to '\n---\n' for visual separation. |
The two formats differ in how entries are stored. Text output appends joinString + text to an append-only log. Auto-named text logs use a .md extension; a configured output.file keeps its configured name. JSONL wraps each text output as one JSON line containing text, timestamp, and sentinelId, with a .jsonl extension. joinString defaults to \n---\n and supports \n, \t, \r, and \\ escapes.
Where the file lands depends on a priority chain. The log-file priority chain is codon-level settings.outputPaths.logFile, then sentinel-level output.file, then the automatic path .hankweave/sentinels/outputs/{id}/{id}-{codonId}-{timestamp}.{md|jsonl|ndjson}. lastValueFile follows the same chain. A bare filename with no / resolves under the managed execution path .hankweave/sentinels/outputs/{id}/; a path containing /, including ./x.md, resolves relative to agentRoot. A resolved path that escapes both the execution directory and agentRoot is rejected as a fatal configuration error.
lastValueFile is atomically replaced for every output; the log is append-only. Initialization failures while creating the directory or file, or checking writability, are fatal configuration errors. Write failures after initialization are logged and do not fail the sentinel. The sentinel-sweep capture uses the bare name sweep-report.log, so its managed location is <exec>/.hankweave/sentinels/outputs/<sentinel-id>/sweep-report.log, not agentRoot.
Control WebSocket reporting#
reportToWebsocket.errors and .outputs gate sentinel.error and sentinel.output emission. lifecycle and triggers are declared client-visibility keys for events that are always emitted into the event stream.
| field | type | default | required | constraints | description |
|---|---|---|---|---|---|
reportToWebsocket | object | no |
errors and outputs emit unless their values are false, suppressing sentinel.error and sentinel.output respectively. sentinel.loaded, sentinel.unloaded, and sentinel.triggered are emitted into the event stream without corresponding server-side lifecycle or triggers suppression gates; those schema fields are client-visibility controls, and this page does not claim a server-side suppression read site.
Events owns event shapes; WebSocket protocol covers client delivery.
Attach sentinels to codons#
With the configuration defined, the last step is attaching it. A codon attaches sentinels through a per-codon wrapper containing sentinelConfig and optional settings.
| field | type | default | required | constraints | description |
|---|---|---|---|---|---|
sentinels | array<object> | no | Sentinels 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… |
sentinelConfig is either a hank-directory-anchored file path or an inline configuration object. Inline references receive escape checks at the wrapper level; file-based references receive them at the file's own directory. The wrapper's settings carries failCodonIfNotLoaded (default false), outputPaths.logFile, outputPaths.lastValueFile, and reportToWebsocket.
Sentinels are wired per codon as "sentinels": [{"sentinelConfig": "<path>"}]; a root-level sentinels array fails validation with Unrecognized field(s) at hank root: sentinels. With failCodonIfNotLoaded: true, a sentinel load failure is fatal for the codon. With the default false, the failure is logged and the sentinel is skipped. On load, the runtime emits sentinel.loaded with sentinelId, codonId, model, triggerType, executionStrategy, conversational, source, and optional sourcePath.
Which events reach sentinels#
Trigger validation accepts any well-formed event name, but routing is narrower than validation. Only server-state and agentic-backbone event categories are routed to sentinels. Connection-state events are client-specific, and sentinel events are not routed, preventing self-observation loops. The table below is the authoritative list of what a trigger can actually match.
| id | category | journaled | sentinelRouted | payloadFields | receipts |
|---|---|---|---|---|---|
| archive.completed | server-state | true | true | codonId, archivedPaths | schemas/event-schemas.ts:668, schemas/event-schemas.ts:977, schemas/event-schemas.ts:1257, hankweave-runtime.ts:5465 |
| archive.partial | server-state | true | true | codonId, archivedPaths, failedPaths | schemas/event-schemas.ts:673, schemas/event-schemas.ts:978, schemas/event-schemas.ts:1258, hankweave-runtime.ts:5450 |
| assistant.action | agentic-backbone | true | true | codonId, action, content, toolName?, toolInput? | schemas/event-schemas.ts:572, schemas/event-schemas.ts:986, schemas/event-schemas.ts:1237, hankweave-runtime.ts:2777, hankweave-runtime.ts:2789, hankweave-runtime.ts:2824 |
| budget.summary | server-state | true | true | ceiling, allocation, rows, totals | schemas/event-schemas.ts:724, schemas/event-schemas.ts:979, schemas/event-schemas.ts:1267, hankweave-runtime.ts:6478 |
| checkpoint.list | server-state | true | true | runId, checkpoints, currentBranch | schemas/event-schemas.ts:637, schemas/event-schemas.ts:968, schemas/event-schemas.ts:1250, hankweave-runtime.ts:4255 |
| codon.completed | server-state | true | true | codonId, success, cost, duration, exitStatus, failureReason?, failureIgnored?, budgetExceeded? | schemas/event-schemas.ts:560, schemas/event-schemas.ts:961, schemas/event-schemas.ts:1235, hankweave-runtime.ts:1886, hankweave-runtime.ts:2064, hankweave-runtime.ts:2253, hankweave-runtime.ts:3365 |
| codon.extended | server-state | true | true | codonId, codonName, extensionNumber, exhaustWithPrompt, cumulativeTokens, cumulativeCost | schemas/event-schemas.ts:565, schemas/event-schemas.ts:962, schemas/event-schemas.ts:1236, hankweave-runtime.ts:2946 |
| codon.started | server-state | true | true | codonId, codonName, codonDescription?, sessionId, previousSessionId?, startTime, promptMetadata? | schemas/event-schemas.ts:555, schemas/event-schemas.ts:960, schemas/event-schemas.ts:1234, hankweave-runtime.ts:316 |
| error | server-state | true | true | message, codon?, fatal, severity?, context?, code? | schemas/event-schemas.ts:617, schemas/event-schemas.ts:967, schemas/event-schemas.ts:1246, hankweave-runtime.ts:975, hankweave-runtime.ts:995, hankweave-runtime.ts:1019, hankweave-runtime.ts:1062, hankweave-runtime.ts:1090, hankweave-runtime.ts:1116, hankweave-runtime.ts:1814, hankweave-runtime.ts:1867, hankweave-runtime.ts:2045, hankweave-runtime.ts:2236, hankweave-runtime.ts:2609, hankweave-runtime.ts:3981, hankweave-runtime.ts:4177, hankweave-runtime.ts:4273, hankweave-runtime.ts:4349, hankweave-runtime.ts:4512, hankweave-runtime.ts:4536, hankweave-runtime.ts:4599, hankweave-runtime.ts:4769, hankweave-runtime.ts:4804, hankweave-runtime.ts:4896, hankweave-runtime.ts:4918, hankweave-runtime.ts:5016 |
| file.updated | agentic-backbone | true | true | path, filename, content, action | schemas/event-schemas.ts:587, schemas/event-schemas.ts:988, schemas/event-schemas.ts:1240, hankweave-runtime.ts:2357, hankweave-runtime.ts:3927 |
| filetree.updated | agentic-backbone | true | true | tree | schemas/event-schemas.ts:592, schemas/event-schemas.ts:989, schemas/event-schemas.ts:1241, hankweave-runtime.ts:3954 |
| info | server-state | true | true | message | schemas/event-schemas.ts:627, schemas/event-schemas.ts:966, schemas/event-schemas.ts:1248, hankweave-runtime.ts:1705, hankweave-runtime.ts:1728, hankweave-runtime.ts:1902, hankweave-runtime.ts:1933, hankweave-runtime.ts:1971, hankweave-runtime.ts:2080, hankweave-runtime.ts:2196, hankweave-runtime.ts:2269, hankweave-runtime.ts:2730, hankweave-runtime.ts:3082, hankweave-runtime.ts:3100, hankweave-runtime.ts:3181, hankweave-runtime.ts:3205, hankweave-runtime.ts:3474, hankweave-runtime.ts:3723, hankweave-runtime.ts:3755, hankweave-runtime.ts:4058, hankweave-runtime.ts:4328, hankweave-runtime.ts:6427 |
| loop.iteration.completed | server-state | true | true | loopId, iteration, durationMs, costUsd, tokensUsed, isFinal, terminationReason? | schemas/event-schemas.ts:612, schemas/event-schemas.ts:976, schemas/event-schemas.ts:1245, hankweave-runtime.ts:6035 |
| rig.output | agentic-backbone | true | true | codonId, stream, line, commandIndex | schemas/event-schemas.ts:607, schemas/event-schemas.ts:992, schemas/event-schemas.ts:1244, hankweave-runtime.ts:6109 |
| rig.setup.completed | agentic-backbone | true | true | codonId, rigType, commandCount, durationMs, createdCheckpoint | schemas/event-schemas.ts:597, schemas/event-schemas.ts:990, schemas/event-schemas.ts:1242, hankweave-runtime.ts:2160 |
| rig.setup.failed | agentic-backbone | true | true | codonId, failureType, exitCode?, commandIndex?, ignored | schemas/event-schemas.ts:602, schemas/event-schemas.ts:991, schemas/event-schemas.ts:1243, hankweave-runtime.ts:1791 |
| rollback.archiveRestore | server-state | true | true | codonId, restoredPaths, failedPaths?, status | schemas/event-schemas.ts:678, schemas/event-schemas.ts:974, schemas/event-schemas.ts:1256, hankweave-runtime.ts:5557 |
| rollback.codonCheckpoint | server-state | true | true | codonId, codonName, checkpoint, checkpointType, message | schemas/event-schemas.ts:647, schemas/event-schemas.ts:971, schemas/event-schemas.ts:1252, hankweave-runtime.ts:4684, hankweave-runtime.ts:5136, hankweave-runtime.ts:5191 |
| rollback.completed | server-state | true | true | fromRun, toRun, checkpoint, codonId, codonName, checkpointType, autoRestart | schemas/event-schemas.ts:662, schemas/event-schemas.ts:972, schemas/event-schemas.ts:1255, hankweave-runtime.ts:4722, hankweave-runtime.ts:5254 |
| rollback.progress | server-state | true | true | currentStep, totalSteps, message | schemas/event-schemas.ts:657, schemas/event-schemas.ts:970, schemas/event-schemas.ts:1254, hankweave-runtime.ts:5117, hankweave-runtime.ts:5156 |
| rollback.rigCleanup | server-state | true | true | codonId, codonName, directories, status, successfulCleanups?, failedCleanups?, error? | schemas/event-schemas.ts:652, schemas/event-schemas.ts:973, schemas/event-schemas.ts:1253, hankweave-runtime.ts:5624, hankweave-runtime.ts:5662, hankweave-runtime.ts:5678 |
| rollback.started | server-state | true | true | fromRun, fromCodon, toCodon, toCheckpoint, checkpointType, codonsToProcess | schemas/event-schemas.ts:642, schemas/event-schemas.ts:969, schemas/event-schemas.ts:1251, hankweave-runtime.ts:4645, hankweave-runtime.ts:5095 |
| sentinel.error | sentinel | true | false | sentinelId, codonId, errorType, message, retriable, consecutiveFailureCount | schemas/event-schemas.ts:709, schemas/event-schemas.ts:1001, schemas/event-schemas.ts:1264, sentinels/sentinel.ts:576, sentinels/sentinel.ts:663, sentinels/sentinel.ts:798, sentinels/sentinel.ts:905 |
| sentinel.loaded | sentinel | true | false | sentinelId, codonId, model, triggerType, executionStrategy, conversational, source, sourcePath? | schemas/event-schemas.ts:699, schemas/event-schemas.ts:999, schemas/event-schemas.ts:1262, hankweave-runtime.ts:5819 |
| sentinel.output | sentinel | true | false | sentinelId, codonId, triggerNumber, outputType, content, cost, tokens, eventCount | schemas/event-schemas.ts:714, schemas/event-schemas.ts:1002, schemas/event-schemas.ts:1265, sentinels/sentinel.ts:538, sentinels/sentinel.ts:635, sentinels/sentinel.ts:762, sentinels/sentinel.ts:877 |
| sentinel.triggered | sentinel | true | false | sentinelId, codonId, triggerNumber, strategy, eventCount, queueSize | schemas/event-schemas.ts:719, schemas/event-schemas.ts:1003, schemas/event-schemas.ts:1266, sentinels/sentinel.ts:392 |
| sentinel.unloaded | sentinel | true | false | sentinelId, codonId, reason, errorType?, finalCost, llmCallCount | schemas/event-schemas.ts:704, schemas/event-schemas.ts:1000, schemas/event-schemas.ts:1263, sentinels/sentinel-manager.ts:851 |
| server.idle | server-state | true | true | reason, message | schemas/event-schemas.ts:632, schemas/event-schemas.ts:964, schemas/event-schemas.ts:1249, hankweave-runtime.ts:941, hankweave-runtime.ts:3621, hankweave-runtime.ts:3791, hankweave-runtime.ts:3812, hankweave-runtime.ts:4072, hankweave-runtime.ts:4743, hankweave-runtime.ts:5279, hankweave-runtime.ts:5291 |
| state.snapshot | server-state | true | true | currentCodon?, completedCodons, fileTree, totalCost, totalTime, recentFileAccess?, isRollingBack | schemas/event-schemas.ts:550, schemas/event-schemas.ts:963, schemas/event-schemas.ts:1233, hankweave-runtime.ts:1422 |
| state.transition | server-state | true | true | transitionType, runId?, codonId?, transition, resultingState | schemas/event-schemas.ts:693, schemas/event-schemas.ts:975, schemas/event-schemas.ts:1261, hankweave-runtime.ts:394 |
| token.usage | server-state | true | true | codonId, inputTokens, outputTokens, cacheCreationTokens, cacheReadTokens, totalCost, modelId?, modelUsage? | schemas/event-schemas.ts:577, schemas/event-schemas.ts:965, schemas/event-schemas.ts:1238, hankweave-runtime.ts:2646, hankweave-runtime.ts:2660 |
| tool.result | agentic-backbone | true | true | codonId, toolUseId, toolName, result, truncated, originalLength, executionTimeMs, isError | schemas/event-schemas.ts:582, schemas/event-schemas.ts:987, schemas/event-schemas.ts:1239, hankweave-runtime.ts:2906 |
The generated selection contains 27 routed event types, including codon.extended, rig.setup.completed, rig.setup.failed, rig.output, loop.iteration.completed, archive.completed, archive.partial, rollback.archiveRestore, and budget.summary. Sentinel event names can pass trigger schema validation but never reach a sentinel; a trigger on sentinel.output loads successfully and never fires. Events owns the complete catalog, while Sentinel concepts owns the observer semantics.