Skip to content

Use the Reminder Plugin

Use this when you want the agent to receive automatic context messages after tool execution based on pattern matching — for example, reminding the agent to run cargo check after editing a .toml file, or warning about destructive commands.

  • A working awaken agent runtime (see Build an Agent)
  • Feature reminder enabled on the awaken crate
[dependencies]
awaken = { git = "https://github.com/AwakenWorks/awaken", features = ["reminder"] }
tokio = { version = "1", features = ["full"] }
serde_json = "1"
  1. Register the reminder plugin and configure agent-specific rules.
use std::sync::Arc;
use serde_json::json;
use awaken::engine::GenaiExecutor;
use awaken::ext_reminder::ReminderPlugin;
use awaken::registry_spec::ModelSpec;
use awaken::registry_spec::AgentSpec;
use awaken::{AgentRuntimeBuilder, Plugin};
let mut agent_spec = AgentSpec::new("my-agent")
.with_model_id("claude-sonnet")
.with_system_prompt("You are a helpful assistant.")
.with_hook_filter("reminder")
.with_section("reminder", json!({
"rules": [
{
"tool": "Bash(command ~ 'rm *')",
"output": { "status": "success" },
"message": {
"target": "suffix_system",
"content": "A deletion command just succeeded. Verify the result."
}
}
]
}));
agent_spec.plugin_ids.push("reminder".into());
let runtime = AgentRuntimeBuilder::new()
.with_provider("anthropic", Arc::new(GenaiExecutor::new()))
.with_model(ModelSpec::new("claude-sonnet", "anthropic", "claude-3-7-sonnet-latest"))
.with_agent_spec(agent_spec)
.with_plugin("reminder", Arc::new(ReminderPlugin::new(vec![])) as Arc<dyn Plugin>)
.build()
.expect("failed to build runtime");

The plugin registers an AfterToolExecute phase hook. After every tool call, it evaluates each rule against the tool name, arguments, and result. When a rule matches, it schedules an AddContextMessage action that injects the configured message into the prompt.

plugin_ids loads the plugin for the agent. with_hook_filter("reminder") keeps only the reminder plugin’s hooks active when multiple plugins are loaded. The reminder section is validated through ReminderConfigKey, exposed in /v1/capabilities, and saved by the admin console.

  1. Define rules with tool patterns.

    The tool field uses the same pattern DSL as the permission system:

PatternMatches
"Bash"Exact tool name Bash
"*"Any tool
"mcp__*"Glob on tool name (all MCP tools)
"Bash(command ~ 'rm *')"Tool name + primary argument glob
"Edit(file_path ~ '*.toml')"Named field glob
let json = r#"{
"rules": [
{
"name": "toml-edit-reminder",
"tool": "Edit(file_path ~ '*.toml')",
"output": "any",
"message": {
"target": "system",
"content": "You edited a TOML file. Run cargo check to verify.",
"cooldown_turns": 3
}
}
]
}"#;

The optional name field gives the rule a human-readable identifier. When omitted, one is auto-generated from the index and tool pattern (e.g. rule-0-Edit(file_path ~ '*.toml')).

  1. Configure output matching.

    The output field controls whether the rule fires based on the tool result. Set it to "any" to match all outputs, or use a structured object with status and/or content:

// Match only errors containing "permission denied"
let json = r#"{
"rules": [
{
"tool": "*",
"output": {
"status": "error",
"content": "*permission denied*"
},
"message": {
"target": "suffix_system",
"content": "Permission denied. Consider using sudo or checking file ownership."
}
}
]
}"#;

Status values: "success", "error", "pending", "any".

Content matching supports two forms:

  • Text glob (string shorthand): "*permission denied*" — matches the stringified tool output against a glob pattern.
  • JSON fields (structured): matches specific fields in JSON output.
// JSON field matching
let json = r#"{
"rules": [
{
"tool": "*",
"output": {
"status": "error",
"content": {
"fields": [
{ "path": "error.code", "op": "exact", "value": "403" }
]
}
},
"message": {
"target": "suffix_system",
"content": "HTTP 403 Forbidden. Check authentication credentials."
}
}
]
}"#;

Field match operations: "glob" (default), "exact", "regex", "not_glob", "not_exact", "not_regex". The path uses dot-separated JSON field names (e.g. "error.code"). When multiple fields are specified, all must match (AND logic).

When both status and content are present, both must match for the rule to fire.

  1. Choose a message target.

    The target field determines where the injected message appears in the prompt:

TargetPlacement
"system"Prepended to the system prompt section
"suffix_system"Appended after the system prompt
"session"Inserted as a session-scoped system message
"conversation"Inserted as a conversation-scoped system message
  1. Use cooldown to avoid repetition.

    Set cooldown_turns on the message to suppress re-injection for a number of turns after firing:

let json = r#"{
"rules": [
{
"tool": "*",
"output": "any",
"message": {
"target": "system",
"content": "Remember to be careful with file operations.",
"cooldown_turns": 5
}
}
]
}"#;

When cooldown_turns is 0 (default), the message is injected on every match.

  1. Load default rules from a file.
use awaken::ext_reminder::{ReminderPlugin, ReminderRulesConfig};
let config = ReminderRulesConfig::from_file("reminders.json")
.expect("failed to load reminder config");
let rules = config.into_rules().expect("invalid rules");
let plugin = ReminderPlugin::new(rules);

Rules passed to ReminderPlugin::new(...) are plugin defaults. Rules in the agent’s reminder config section are appended at runtime, so one plugin instance can serve many agents with different system reminders.

  1. Activate the plugin on an agent spec.
use awaken::registry_spec::AgentSpec;
let mut agent_spec = AgentSpec::new("my-agent")
.with_model_id("claude-sonnet")
.with_system_prompt("You are a helpful assistant.")
.with_hook_filter("reminder");
agent_spec.plugin_ids.push("reminder".into());

plugin_ids controls plugin loading. with_hook_filter("reminder") only filters hooks after the plugin has been loaded.

  1. Configure a rule matching a tool you can easily trigger (e.g. "*" with "any" output).
  2. Run the agent and invoke a tool.
  3. Inspect the prompt or enable tracing at debug level. You should see:
    reminder rule matched, scheduling context message
  4. Confirm the context message appears in the agent’s next inference prompt at the expected target location.
SymptomCauseFix
InvalidPattern on startupMalformed tool pattern stringCheck syntax against the pattern table above; ensure quotes are escaped in JSON
InvalidTarget on startupUnknown message targetUse one of: system, suffix_system, session, conversation
InvalidOutput on startupUnrecognized output matcher stringUse "any" or a structured { "status": ..., "content": ... } object
InvalidOp on startupUnknown field match operationUse one of: glob, exact, regex, not_glob, not_exact, not_regex
Rule never firesPlugin not loaded or hook filtered outAdd "reminder" to plugin_ids and include with_hook_filter("reminder") when using hook filters
Rule fires too oftenNo cooldown configuredSet cooldown_turns to a positive value
  • crates/awaken-ext-reminder/src/config.rs — contains test cases with various rule configurations
PathPurpose
crates/awaken-ext-reminder/src/lib.rsModule root and public re-exports
crates/awaken-ext-reminder/src/config.rsReminderRulesConfig, JSON loading, ReminderConfigKey
crates/awaken-ext-reminder/src/rule.rsReminderRule struct definition
crates/awaken-ext-reminder/src/output_matcher.rsOutputMatcher, ContentMatcher, status/content matching logic
crates/awaken-ext-reminder/src/plugin/plugin.rsReminderPlugin registration (AfterToolExecute hook)
crates/awaken-ext-reminder/src/plugin/hook.rsReminderHook — pattern + output evaluation per tool call
crates/awaken-tool-pattern/Shared glob/regex pattern matching library