Reference
Sentinel Configuration

Sentinel Configuration Reference

This document is a complete reference for all sentinel configuration options. It's a lookup guide for developers who already understand the core concepts and need to configure specific behaviors.

To learn why sentinels work the way they do, start with the Sentinels conceptual guide first.

Who is this for? This page is for developers who understand sentinels and need a reference for specific configuration options.

Sentinel Pipeline Overview

Every sentinel follows the same flow: events from the event stream are filtered by a trigger, batched by an execution strategy, and then processed by an LLM to produce output.

Sentinel Architecture

Configuration File Structure

Sentinel configuration is defined in JSON files with the following top-level structure:

Text
{
  "id": "example-sentinel",
  "name": "Example Sentinel",
  "description": "Optional description of what this sentinel does",
  "model": "anthropic/claude-haiku-4-5",
  "trigger": { /* ... */ },
  "execution": { /* ... */ },
  "systemPromptFile": "./prompts/system.md",
  "systemPromptText": "Alternative inline system prompt",
  "userPromptFile": "./prompts/user.md",
  "userPromptText": "Alternative inline user prompt",
  "conversational": { /* ... */ },
  "structuredOutput": { /* ... */ },
  "llmParams": { /* ... */ },
  "errorHandling": { /* ... */ },
  "output": { /* ... */ },
  "joinString": "\n---\n",
  "reportToWebsocket": { /* ... */ }
}

Required Fields

FieldTypeDescription
idstringUnique identifier. Lowercase letters, numbers, hyphens only. Pattern: /^[a-z0-9-]+$/
namestringHuman-readable name for display.
modelstringFull model ID (e.g., "anthropic/claude-haiku-4-5") or a short name (e.g., "haiku"). See Model Specification for options.
triggerobjectDefines when the sentinel fires. See Triggers.
executionobjectDefines how triggered events become LLM calls. See Execution Strategies.

You must also provide at least one of userPromptFile or userPromptText.

Optional Fields

FieldTypeDefaultDescription
descriptionstringOptional description for documentation.
systemPromptFilestring | string[]Path(s) to system prompt file(s).
systemPromptTextstringInline system prompt text.
userPromptFilestring | string[]Path(s) to user prompt file(s).
userPromptTextstringInline user prompt text.
conversationalobjectEnable conversation history. See Conversational Mode.
structuredOutputobjectGenerate validated JSON. See Structured Output.
llmParamsobjectLLM generation parameters. See LLM Parameters.
errorHandlingobjectError handling behavior. See Error Handling.
outputobjectDirect output configuration. See Output Configuration.
joinStringstring"\n---\n"Separator for log file entries. Only used for text output format.
reportToWebsocketobjectControl WebSocket event emission. See Event Reporting.

Triggers

Triggers define when a sentinel executes, either by matching single events or by detecting sequences of events.

Event Trigger

Fires when a specific event type occurs and meets all conditions.

Text
{
  "trigger": {
    "type": "event",
    "on": ["assistant.action", "tool.result"],
    "conditions": [
      {
        "operator": "equals",
        "path": "isError",
        "value": true
      }
    ]
  }
}
FieldTypeRequiredDescription
type"event"YesDiscriminator field.
onstring[]YesEvent types to match. Use "*" for a wildcard to match any event.
conditionsCondition[]NoAdditional conditions that must all be met (AND logic).

Available Event Types

Event TypeDescription
assistant.actionAgent thinking, tool use, or messages.
tool.resultResults from tool executions.
file.updatedA file was created, modified, or deleted.
filetree.updatedFile tree structure has changed.
codon.startedCodon execution begins.
codon.completedCodon execution ends.
token.usageToken consumption statistics are updated.
errorA generic error event occurred.
infoAn informational message was emitted.
server.idleThe server is waiting for commands.
state.snapshotThe current execution state.
state.transitionAn internal state machine transition occurred.
checkpoint.listList of available checkpoints.
rollback.startedA rollback operation has started.
rollback.progressRollback progress update.
rollback.codonCheckpointA checkpoint was applied during rollback.
rollback.rigCleanupRig directory was cleaned up during rollback.
rollback.completedThe rollback has finished.
sentinel.loadedA sentinel has started.
sentinel.triggeredA sentinel's trigger has fired.
sentinel.outputA sentinel has produced an LLM response.
sentinel.errorA sentinel encountered an error.
sentinel.unloadedA sentinel has stopped.
*Wildcard—matches any event type.

Sequence Trigger

Fires when a specific pattern of events occurs in the event stream. This is useful for detecting repeated failures, specific workflows, or complex state changes.

Sequence Trigger

This example detects three consecutive tool errors:

Text
{
  "trigger": {
    "type": "sequence",
    "interestFilter": {
      "on": ["tool.result"]
    },
    "pattern": [
      {
        "type": "tool.result",
        "conditions": [{"operator": "equals", "path": "isError", "value": true}]
      },
      {
        "type": "tool.result",
        "conditions": [{"operator": "equals", "path": "isError", "value": true}]
      },
      {
        "type": "tool.result",
        "conditions": [{"operator": "equals", "path": "isError", "value": true}]
      }
    ],
    "options": {
      "consecutive": true
    }
  }
}
FieldTypeRequiredDescription
type"sequence"YesDiscriminator field.
interestFilter.onstring[]YesEvent types to track in the history buffer.
patternPatternStep[]YesThe sequence of events to detect (minimum 1 step).
options.consecutivebooleanNoIf true (default), the events must occur consecutively. If false, other events can occur between pattern steps.

Pattern Step

A pattern step defines one event in the sequence to be matched.

Text
{
  "type": "tool.result",
  "conditions": [
    {"operator": "equals", "path": "isError", "value": true}
  ]
}
FieldTypeRequiredDescription
typestringYesThe event type to match. Use "*" for a wildcard.
conditionsCondition[]NoConditions that must be met for this step.

History Limit: Sequence triggers maintain a history of up to 1000 events in memory.

Conditions

Conditions provide fine-grained control for both event and sequence triggers. All conditions within a conditions array use AND logic—every condition must pass for the trigger to fire.

Text
{
  "conditions": [
    {"operator": "equals", "path": "isError", "value": true},
    {"operator": "greaterThan", "path": "duration", "value": 1000}
  ]
}

Condition Operators

OperatorValue TypeDescription
equalsstring | number | boolean | nullValue is an exact match.
notEqualsstring | number | boolean | nullValue is not equal.
in(string | number)[]Value is present in the array.
notIn(string | number)[]Value is not present in the array.
containsstringString contains the specified substring.
matchesstringString matches the specified regular expression.
greaterThannumberValue is numerically greater than.
lessThannumberValue is numerically less than.

Path Syntax

Paths use dot notation to access nested fields within the data object of an event. For example, exitStatus.type accesses event.data.exitStatus.type.

Text
{"operator": "equals", "path": "exitStatus.type", "value": "success"}

Validation: Condition paths are validated against the event's schema when the configuration is loaded. An invalid path for the specified event type will cause a validation error.


Execution Strategies

The execution strategy determines how triggered events are batched into LLM calls. Sentinels can fire immediately on each trigger or batch events by time, quiet periods, or count.

Execution Strategies

Immediate

Fires an LLM call for every trigger match.

Text
{
  "execution": {
    "strategy": "immediate"
  }
}

Debounce

Waits for a period of inactivity (a "quiet period") before firing an LLM call with all events accumulated during that time. Each new event resets the timer.

Text
{
  "execution": {
    "strategy": "debounce",
    "milliseconds": 3000
  }
}
FieldTypeConstraintsDescription
millisecondsnumber1–300000The quiet period in milliseconds (max 5 minutes).

Count

Fires an LLM call after a specific number of trigger matches have occurred.

Text
{
  "execution": {
    "strategy": "count",
    "threshold": 10
  }
}
FieldTypeConstraintsDescription
thresholdnumber1–1000The number of events to accumulate before firing.

Time Window

Fires an LLM call on a fixed time interval, batching all events that occurred during that window.

Text
{
  "execution": {
    "strategy": "timeWindow",
    "milliseconds": 30000
  }
}
FieldTypeConstraintsDescription
millisecondsnumber1–3600000The window duration in milliseconds (max 1 hour).

The timer for the next window starts only after the current one finishes processing. If an LLM call takes longer than the window duration, subsequent windows will be delayed. The schedule does not "catch up" to a fixed real-world clock.


Prompts

Every sentinel requires a user prompt, defined via either userPromptFile or userPromptText. System prompts are optional for single-shot sentinels but required for conversational mode.

Prompt Fields

FieldTypeDescription
systemPromptFilestring | string[]Path(s) to system prompt file(s).
systemPromptTextstringInline system prompt text.
userPromptFilestring | string[]Path(s) to user prompt file(s).
userPromptTextstringInline user prompt text.

When you provide an array of file paths, the files are concatenated in order.

Template Syntax

Prompts use Eta (opens in a new tab) templates, giving you access to the triggering events and codon context via the it object. See Template Context for all available properties.

Text
Summarize these <%= it.events.length %> events:

<%= JSON.stringify(it.events, null, 2) %>

Template Context

PropertyTypeDescription
it.eventsServerEvent[]Array of events that triggered this execution.
it.codon.idstringThe ID of the current codon.
it.codon.namestringThe name of the current codon.
it.codon.descriptionstring?The optional description of the current codon.
it.codon.startTimeDateThe start time of the codon execution.
it.world.currentTimeDateThe timestamp when the trigger was queued.

Queue Time vs. Execution Time: it.world.currentTime reflects when the trigger was queued, not when the template runs. This provides a consistent timestamp even if LLM execution is delayed.

Template Examples

Iterate over events:

Text
<% for (const event of it.events) { %>
- <%= event.type %>: <%= event.data?.codonId || 'N/A' %>
<% } %>

Conditional content:

Text
<% if (it.events.length > 10) { %>
High activity detected: <%= it.events.length %> events
<% } else { %>
Normal activity: <%= it.events.length %> events
<% } %>

Access the last event:

Text
Last event: <%= JSON.stringify(it.events[it.events.length - 1]) %>

Conversational Mode

For sentinels that need to maintain memory across invocations, conversational mode keeps a rolling history of previous user prompts and assistant responses. This allows the sentinel to build context over time.

Text
{
  "conversational": {
    "trimmingStrategy": {
      "type": "maxTurns",
      "maxTurns": 5
    },
    "continueOnError": true
  }
}
⚠️

System Prompt Required: Conversational sentinels must have systemPromptFile or systemPromptText defined. This is enforced by validation.

Conversational Fields

FieldTypeRequiredDescription
trimmingStrategyobjectYesThe strategy for pruning the conversation history to prevent it from growing indefinitely.
continueOnErrorbooleanNoIf true, the sentinel will continue with a potentially corrupted history after an LLM failure. Defaults to false.

Trimming Strategies

You must choose a strategy to prune the conversation history.

maxTurns

Keeps the last N complete turns (a turn consists of one user message and one assistant response).

Text
{
  "trimmingStrategy": {
    "type": "maxTurns",
    "maxTurns": 5
  }
}
FieldTypeConstraintsDescription
maxTurnsnumber1–100The number of turns to keep.

maxTokens

Keeps the most recent messages that fit within a specified token limit.

Text
{
  "trimmingStrategy": {
    "type": "maxTokens",
    "maxTokens": 4000
  }
}
FieldTypeConstraintsDescription
maxTokensnumber1–100000The token budget for the history.

Token counting uses exact counts from LLM responses when available, falling back to a text.length / 4 approximation for older messages.

History Persistence

Conversation history is persisted to .hankweave/sentinels/history/{sentinel-id}-codon-{codon-id}.json, allowing sentinels to resume their state after a server restart.


Structured Output

For machine-readable output, structured output mode generates validated JSON according to a Zod schema. The LLM's response is parsed and validated before being written to the output file.

Text
{
  "structuredOutput": {
    "output": "object",
    "schemaStr": "z.object({ score: z.number(), notes: z.string() })",
    "schemaName": "Evaluation",
    "schemaDescription": "Code evaluation result"
  }
}

Structured Output Fields

FieldTypeRequiredDescription
output"object" | "array" | "enum"YesThe desired output mode.
schemaStrstringConditionalAn inline Zod schema definition as a string.
schemaFilestringConditionalThe path to a file containing a Zod schema.
enumValuesstring[]ConditionalAn array of allowed string values for enum mode.
schemaNamestringNoA name for the schema, passed to the LLM.
schemaDescriptionstringNoA description for the schema, passed to the LLM.

Schema Rules

Hankweave enforces these rules at load time:

  • For object or array mode, you must provide exactly one of schemaStr or schemaFile.
  • For enum mode, you must provide enumValues and must not provide schemaStr or schemaFile.

Output Modes

Object Mode

Generates a single JSON object that conforms to the schema.

Text
{
  "structuredOutput": {
    "output": "object",
    "schemaStr": "z.object({ category: z.string(), confidence: z.number() })"
  }
}

Array Mode

Generates a JSON array of objects that conform to the schema.

Text
{
  "structuredOutput": {
    "output": "array",
    "schemaStr": "z.array(z.object({ item: z.string(), count: z.number() }))"
  }
}

Enum Mode

Generates a single string value from a predefined list.

Text
{
  "structuredOutput": {
    "output": "enum",
    "enumValues": ["urgent", "normal", "low-priority", "ignore"]
  }
}

Schema Files

For complex schemas, define them in a separate file and export the Zod schema as the default expression. The z object is automatically available in the file's scope; no import is needed.

Text
z.object({
  score: z.number().min(0).max(100),
  notes: z.string(),
  issues: z.array(z.string()).optional()
})
⚠️

Model Requirement: Structured output requires a model that supports tool calls. Using an incompatible model will cause a validation error at load time.

⚠️

No joinString: The joinString property is invalid when structuredOutput is configured. Structured output is always written in NDJSON format (one JSON object per line).


LLM Parameters

Fine-tune the LLM's generation process.

Text
{
  "llmParams": {
    "temperature": 0.3,
    "maxOutputTokens": 4096,
    "maxRetries": 2
  }
}

LLM Parameter Fields

FieldTypeDefaultConstraintsDescription
temperaturenumber00–2Controls randomness. 0 is deterministic, higher values are more creative.
maxOutputTokensnumber81921–100000The maximum number of tokens to generate in the response.
maxRetriesnumber20–5Number of retry attempts for transient API failures.

Error Handling

Configure how the sentinel behaves when it encounters errors like network issues or API failures.

Text
{
  "errorHandling": {
    "maxConsecutiveFailures": 5,
    "unloadOnFatalError": false
  }
}

Error Handling Fields

FieldTypeDefaultDescription
maxConsecutiveFailuresnumber3The number of consecutive failures before the sentinel unloads itself (min: 1).
unloadOnFatalErrorbooleantrueIf true, the sentinel unloads on non-recoverable errors (e.g., bad template syntax).

Error Categories

Hankweave distinguishes between different error types:

  1. Template Errors: Syntax errors in prompts that are guaranteed to fail on every execution.
  2. Configuration Errors: Invalid settings caught at load time. The sentinel will not start.
  3. Corruption Errors: Invalid data in the conversation history. Behavior depends on continueOnError.
  4. Resource Errors: Network timeouts or API failures. These are typically transient and retried.

A single successful LLM call resets the consecutive failure counter.


Output Configuration

By default, sentinel output is written to an auto-generated file. You can customize the format and location.

Text
{
  "output": {
    "format": "text",
    "file": "narrator-output.md"
  }
}

Output Fields

FieldTypeDefaultDescription
format"text" | "jsonl"textThe output file format.
filestring(auto)The output file path.

Path Conventions

File paths are resolved based on their structure:

  • A single filename (e.g., "output.md"): Written to .hankweave/sentinels/outputs/{sentinel-id}/{filename}.
  • A relative path (e.g., "logs/output.md"): Written relative to the current execution directory.

Auto-generated Paths

If output.file is not specified, Hankweave generates a path automatically:

  • Text: .hankweave/sentinels/outputs/{id}/{id}-{codon}-{timestamp}.md
  • Structured: .hankweave/sentinels/outputs/{id}/{id}-{codon}-{timestamp}.ndjson

Join String

For text output, joinString defines the separator between consecutive entries in the log file.

Text
{
  "joinString": "\n\n---\n\n"
}

Supported escape sequences include \n (newline), \t (tab), \r (carriage return), and \\ (backslash). The default is "\n---\n".


Event Reporting

By default, sentinels emit lifecycle, error, and output events to connected WebSocket clients. You can configure this to reduce noise.

Text
{
  "reportToWebsocket": {
    "lifecycle": true,
    "errors": true,
    "outputs": true,
    "triggers": false
  }
}

Event Reporting Fields

FieldTypeDefaultEvents Reported
lifecyclebooleantruesentinel.loaded, sentinel.unloaded
errorsbooleantruesentinel.error
outputsbooleantruesentinel.output
triggersbooleanfalsesentinel.triggered (can be very verbose)

Attaching to Codons

To use a sentinel, attach it to a codon in your hank.json file. You can reference an external configuration file or define the entire configuration inline.

Text
{
  "hank": [
    {
      "id": "generate-code",
      "sentinels": [
        {
          "sentinelConfig": "./sentinels/narrator.sentinel.json"
        },
        {
          "sentinelConfig": {
            "id": "inline-sentinel",
            "name": "Inline Example",
            "model": "anthropic/claude-haiku-4-5",
            "trigger": { "type": "event", "on": ["*"] },
            "execution": { "strategy": "debounce", "milliseconds": 5000 },
            "userPromptText": "Summarize: <%= JSON.stringify(it.events) %>"
          },
          "settings": {
            "failCodonIfNotLoaded": true,
            "outputPaths": {
              "logFile": "custom-log.md",
              "lastValueFile": "current-state.md"
            },
            "reportToWebsocket": {
              "triggers": true
            }
          }
        }
      ]
    }
  ]
}

Sentinel Entry Structure

FieldTypeDescription
sentinelConfigstring | SentinelConfigPath to a .sentinel.json file or an inline configuration object.
settingsobjectCodon-specific overrides for the sentinel's behavior.

Codon-Level Settings

These settings allow you to reuse a single sentinel configuration with different behaviors for different codons.

Text
{
  "settings": {
    "failCodonIfNotLoaded": true,
    "outputPaths": {
      "logFile": "custom-output.md",
      "lastValueFile": "current.md"
    },
    "reportToWebsocket": {
      /* ... */
    }
  }
}
FieldTypeDefaultDescription
failCodonIfNotLoadedbooleanfalseIf true, the codon will fail if this sentinel cannot be loaded.
outputPaths.logFilestring(from config)Overrides the output.file path.
outputPaths.lastValueFilestringAn additional output file that is atomically replaced with the latest value on each output.
reportToWebsocketobject(from config)Overrides the reportToWebsocket configuration.

lastValueFile vs. logFile: The logFile is append-only, creating a history of all outputs. The lastValueFile is overwritten each time, making it useful for dashboards or integrations that only need the current state.


Complete Examples

These battle-tested configurations cover common sentinel patterns.

Narrator Sentinel

The most common pattern: watch agent activity and produce human-readable summaries. Debouncing prevents spam during bursts of activity.

Text
{
  "id": "narrator",
  "name": "Activity Narrator",
  "description": "Provides human-readable summaries of agent activities.",
  "model": "anthropic/claude-haiku-4-5",
  "trigger": {
    "type": "event",
    "on": ["assistant.action", "tool.result"]
  },
  "execution": {
    "strategy": "debounce",
    "milliseconds": 3000
  },
  "userPromptText": "Summarize what the agent just did:\n\n<%= JSON.stringify(it.events, null, 2) %>\n\nProvide a brief, clear summary.",
  "llmParams": {
    "temperature": 0.3,
    "maxOutputTokens": 2048
  },
  "output": {
    "format": "text",
    "file": "narrator.md"
  }
}

Conversational Narrator

When a sentinel needs to remember its previous outputs, conversational mode maintains history. This narrator builds on its previous summaries rather than repeating context.

Text
{
  "id": "conversational-narrator",
  "name": "Conversational Narrator",
  "description": "Maintains context across events for coherent narration.",
  "model": "anthropic/claude-haiku-4-5",
  "trigger": {
    "type": "event",
    "on": ["assistant.action", "tool.result"]
  },
  "execution": {
    "strategy": "debounce",
    "milliseconds": 500
  },
  "systemPromptText": "You are a narrator maintaining context. Build on previous summaries without repeating yourself.",
  "userPromptText": "Summarize these events: <%= JSON.stringify(it.events, null, 2) %>",
  "conversational": {
    "trimmingStrategy": {
      "type": "maxTurns",
      "maxTurns": 5
    },
    "continueOnError": true
  },
  "output": {
    "format": "text",
    "file": "conversational-narrator.log"
  }
}

Error Pattern Detector

Sequence triggers are ideal for detecting patterns. This sentinel fires after three consecutive tool errors, which often indicates a systematic problem.

Text
{
  "id": "error-detector",
  "name": "Error Pattern Detector",
  "description": "Detects when the agent encounters repeated errors.",
  "model": "anthropic/claude-haiku-4-5",
  "trigger": {
    "type": "sequence",
    "interestFilter": {
      "on": ["tool.result"]
    },
    "pattern": [
      {
        "type": "tool.result",
        "conditions": [{"operator": "equals", "path": "isError", "value": true}]
      },
      {
        "type": "tool.result",
        "conditions": [{"operator": "equals", "path": "isError", "value": true}]
      },
      {
        "type": "tool.result",
        "conditions": [{"operator": "equals", "path": "isError", "value": true}]
      }
    ],
    "options": {
      "consecutive": true
    }
  },
  "execution": {
    "strategy": "immediate"
  },
  "userPromptText": "The agent encountered 3 consecutive errors. Analyze:\n\n<%= JSON.stringify(it.events, null, 2) %>\n\nProvide:\n1. Common cause analysis\n2. Suggested fixes\n3. Whether to continue or intervene",
  "output": {
    "format": "jsonl",
    "file": "error-patterns.jsonl"
  }
}

Cost Tracker with Conditions

Conditions filter triggers based on event data. This sentinel fires only when spending exceeds a threshold, helping to catch runaway costs.

Text
{
  "id": "cost-tracker",
  "name": "Cost and Token Tracker",
  "description": "Monitors token usage and costs, alerting on high usage.",
  "model": "anthropic/claude-haiku-4-5",
  "trigger": {
    "type": "event",
    "on": ["token.usage"],
    "conditions": [
      {
        "operator": "greaterThan",
        "path": "totalCost",
        "value": 0.5
      }
    ]
  },
  "execution": {
    "strategy": "immediate"
  },
  "userPromptText": "High cost detected in codon <%= it.codon.id %>:\n\nTotal cost: $<%= it.events[0].data.totalCost %>\n\nAnalyze if this cost is justified.",
  "output": {
    "format": "jsonl",
    "file": "cost-alerts.jsonl"
  }
}

Code Review with Structured Output

Structured output enables programmatic use of a sentinel's results. This QA sentinel reviews TypeScript files and returns validated JSON that downstream tools can consume.

Text
{
  "id": "qa-review",
  "name": "QA Code Review",
  "description": "Reviews TypeScript files and provides structured feedback.",
  "model": "anthropic/claude-haiku-4-5",
  "trigger": {
    "type": "event",
    "on": ["file.updated"],
    "conditions": [
      {
        "operator": "matches",
        "path": "path",
        "value": "\\.ts$"
      }
    ]
  },
  "execution": {
    "strategy": "debounce",
    "milliseconds": 10000
  },
  "systemPromptText": "You are a senior TypeScript developer. Review code for correctness, style, and bugs.",
  "userPromptText": "Review these file changes:\n\n<% for (const e of it.events) { %>- <%= e.data.path %>\n<% } %>",
  "structuredOutput": {
    "output": "object",
    "schemaStr": "z.object({ issues: z.array(z.object({ severity: z.enum(['error', 'warning', 'info']), file: z.string(), line: z.number().optional(), message: z.string() })), summary: z.string(), overallScore: z.number().min(0).max(100) })",
    "schemaName": "CodeReview",
    "schemaDescription": "Structured code review feedback"
  }
}

Periodic Summary with Time Window

The timeWindow strategy fires on a fixed schedule regardless of event volume, making it ideal for periodic status updates.

Text
{
  "id": "periodic-summary",
  "name": "30-Second Summary",
  "description": "Creates summaries every 30 seconds.",
  "model": "anthropic/claude-haiku-4-5",
  "trigger": {
    "type": "event",
    "on": ["assistant.action", "tool.result", "codon.started", "codon.completed"]
  },
  "execution": {
    "strategy": "timeWindow",
    "milliseconds": 30000
  },
  "userPromptText": "Summarize the last 30 seconds of activity:\n\n<%= JSON.stringify(it.events, null, 2) %>",
  "output": {
    "format": "text",
    "file": "periodic-summaries.log"
  }
}

Tool Usage Analyzer with Count Strategy

The count strategy waits to accumulate N events before firing. This sentinel analyzes tool usage patterns after every 10 tool calls.

Text
{
  "id": "tool-analyzer",
  "name": "Tool Usage Pattern Analyzer",
  "description": "Analyzes patterns in tool usage to identify inefficiencies.",
  "model": "anthropic/claude-haiku-4-5",
  "trigger": {
    "type": "event",
    "on": ["tool.result"]
  },
  "execution": {
    "strategy": "count",
    "threshold": 10
  },
  "userPromptText": "Analyze tool usage patterns from <%= it.events.length %> calls:\n\n<%= JSON.stringify(it.events, null, 2) %>\n\nIdentify:\n1. Most frequently used tools\n2. Success/failure rates\n3. Inefficient patterns\n4. Optimization suggestions",
  "output": {
    "format": "jsonl",
    "file": "tool-patterns.jsonl"
  }
}

Validation Rules

Hankweave validates sentinel configurations when they are loaded. The sentinel will fail to load if any of these rules are violated:

  1. Required user prompt: At least one of userPromptFile or userPromptText must be provided.
  2. Conversational requires system prompt: If conversational is configured, systemPromptFile or systemPromptText is required.
  3. joinString compatibility: joinString is only valid for text output and cannot be used when structuredOutput is configured.
  4. Structured output schema rules:
    • object or array mode requires exactly one of schemaStr or schemaFile.
    • enum mode requires enumValues and forbids schema definitions.
  5. ID format: The id must match the pattern /^[a-z0-9-]+$/.
  6. Condition path validation: Paths in conditions are validated against the schemas of the specified event types.

Related Pages