-
Notifications
You must be signed in to change notification settings - Fork 15.5k
feat: Internal Hooks: Event-Driven Automation for Agent Commands #1028
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Closed
ThomsenDrake
wants to merge
10
commits into
openclaw:main
from
ThomsenDrake:feature/internal-agent-hooks
Closed
feat: Internal Hooks: Event-Driven Automation for Agent Commands #1028
ThomsenDrake
wants to merge
10
commits into
openclaw:main
from
ThomsenDrake:feature/internal-agent-hooks
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Implements an extensible event-driven hook system that allows custom automations to trigger on agent commands (e.g., /new, /stop). Hooks are configured via config.json and loaded dynamically from TypeScript modules. Features: - Core hook system with register/trigger/event types - Dynamic hook loader for external modules - Integration with command processing (/new, /reset, /stop) - Example handlers: session-memory, command-logger - Comprehensive tests (25 tests total) - Full documentation in docs/internal-hooks.md Similar to Claude Code's hook system, this enables users to extend clawdbot's behavior without modifying core code.
Adds a step to the onboarding wizard that prompts users to enable the session memory hook (/new saves context to disk). Users can: - Learn what internal hooks do - Enable the session-memory handler (default: yes) - See where session files will be saved - Disable if they prefer Includes comprehensive tests (5 tests) for the onboard-hooks module.
- Added debug console.log statements to hook loader - Created JavaScript version of session-memory handler - Added hooks/** to package.json files array - Fixed hook loading for testing The hook system now works when tested directly.
The internal hooks configuration was being stripped during config validation because it wasn't included in the Zod schema. Added: - InternalHookHandlerSchema for handler config - InternalHooksSchema for the internal section - Added 'internal' field to hooks object in ClawdbotSchema The gateway now successfully loads and registers internal hook handlers at startup. Config validation no longer strips the hooks.internal section.
Removed debug console.log statements from: - src/hooks/loader.ts - src/gateway/server-startup.ts The gateway now logs cleanly: [hooks] loaded 1 internal hook handler Ready for production use.
- Implement LLM slug generator that creates descriptive filenames - Fix session-memory hook to access OLD session before reset - Hook now finds previous session by modification time - Add cache-busting to hook loader to prevent stale modules - Add hook messages array to internal hook events - Route hook confirmation messages back to user - Create separate memory files per session with format: YYYY-MM-DD-slug.md - Remove stale JavaScript version of session-memory handler - Add debug logging throughout hook execution Fixes issue where hook received empty NEW session instead of conversation history. The hook now correctly generates descriptive slugs like 'vendor-pitch' based on conversation content using the configured LLM provider.
Redesigns internal hooks system to match skills installation experience
with automatic discovery, CLI management, and eligibility gating.
**New Infrastructure (7 modules):**
- src/hooks/types.ts - Core type definitions
- src/hooks/workspace.ts - Three-tier directory scanning
- src/hooks/frontmatter.ts - HOOK.md metadata parser
- src/hooks/config.ts - Eligibility checking (bins, env, config, os)
- src/hooks/bundled-dir.ts - Bundled hooks directory resolver
- src/hooks/hooks-status.ts - Status report builder
- src/cli/hooks-internal-cli.ts - Full CLI suite
**CLI Commands:**
- clawdbot hooks internal list [--eligible] [--json] [--verbose]
- clawdbot hooks internal info <name> [--json]
- clawdbot hooks internal check [--json]
- clawdbot hooks internal enable <name>
- clawdbot hooks internal disable <name>
**Hook Discovery:**
Three-tier hierarchy (workspace → managed → bundled):
1. <workspace>/hooks/ - Per-agent, highest precedence
2. ~/.clawdbot/hooks/ - User-installed, shared
3. <clawdbot>/hooks/bundled/ - Shipped with Clawdbot
**HOOK.md Format:**
YAML frontmatter + JSON metadata + Markdown docs:
- metadata.clawdbot.emoji - Display emoji
- metadata.clawdbot.events - Events to listen for
- metadata.clawdbot.requires - Requirements (bins, env, config, os)
- metadata.clawdbot.homepage - Documentation URL
**Bundled Hooks:**
Migrated to new structure with HOOK.md:
- hooks/bundled/session-memory/ - Saves context on /new
- hooks/bundled/command-logger/ - Logs all commands
- hooks/bundled/README.md - Comprehensive guide
**Onboarding Integration:**
- Automatic hook discovery in wizard
- Presents eligible hooks for selection
- Uses new entries config format
**Configuration:**
New format (backwards compatible):
{
"hooks": {
"internal": {
"enabled": true,
"entries": {
"session-memory": { "enabled": true },
"command-logger": { "enabled": false }
}
}
}
}
Legacy handlers[] format still supported.
**Documentation:**
- docs/internal-hooks.md - Complete rewrite (779 lines)
- docs/cli/hooks.md - CLI reference (232 lines)
**Testing:**
- All hook tests passing (43 tests)
- CLI commands tested and verified
- Gateway integration confirmed
- Build successful
Closes #XXX
- Remove empty fallback objects in spread operations - Remove unused fsp variable - Await writeConfigFile promises to avoid floating promises All lint checks now pass (0 warnings, 0 errors)
Fixes bundled hooks failing to load when installed via npm with error: "Stripping types is currently unsupported for files under node_modules" Changes: - Move bundled hooks from hooks/bundled/ to src/hooks/bundled/ for compilation - Add scripts/copy-hook-metadata.ts to copy HOOK.md files during build - Update build script to include hook metadata copy step - Update resolveBundledHooksDir() to resolve both compiled (dist/hooks/bundled) and source (src/hooks/bundled) locations - Fix import paths in hook handlers (../../internal-hooks.js) - Remove hooks/** from package.json files array (now ships compiled dist/hooks/) The bundled hooks now ship as compiled JavaScript in dist/hooks/bundled/ with their HOOK.md metadata files, allowing proper loading when installed globally.
The session-memory hook was only saving session metadata (session key, ID, source) without including the actual conversation content in the memory file. Changes: - Store sessionContent in accessible scope (not just for slug generation) - Add "## Conversation Summary" section to memory file output - Include the last 15 lines of conversation in the saved memory This ensures memory files contain the full conversation context, matching the format of manually created memory files and providing useful context for future sessions.
Contributor
|
Landed on main:
Closing PR since the changes are now on main. Thanks! |
Contributor
|
This is a really cool new feature, kudos, Drake! |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Internal Hooks: Event-Driven Automation for Agent Commands
This PR introduces internal hooks, a new first-class feature that enables event-driven automation in response to agent commands and lifecycle events. Hooks allow you to trigger custom TypeScript functions when events like
/new,/reset, or/stopoccur, without modifying Clawdbot's core code.What Are Internal Hooks?
Internal hooks provide an extensible system for automating actions in response to agent events:
/new,/reset,/stopUse cases:
Example: Simple Hook Handler
Hooks System: First-Class Feature Alongside Skills
This implementation makes hooks a first-class feature with the same patterns as skills: automatic discovery, CLI management, and eligibility gating.
Automatic Directory-Based Discovery
Hooks are automatically discovered from three tiers (matching skills pattern):
<workspace>/hooks/) - Per-agent, highest precedence~/.clawdbot/hooks/) - User-installed, shared across workspaces<clawdbot>/dist/hooks/bundled/) - Shipped with Clawdbot (compiled)No manual config editing required.
CLI Management Suite
HOOK.md Metadata Format
Each hook is a directory containing:
HOOK.md- YAML frontmatter + JSON metadata + Markdown documentationhandler.ts(source) /handler.js(compiled) - Handler implementationEligibility Gating
Hooks can declare requirements that are automatically checked:
Only eligible hooks are loaded and presented to users.
Onboarding Integration
The onboarding wizard now automatically discovers eligible hooks and presents them for selection, just like skills. No hardcoded lists.
Configuration Format
{ "hooks": { "internal": { "enabled": true, "entries": { "session-memory": { "enabled": true }, "command-logger": { "enabled": false } } } } }Legacy
handlers[]format still supported for backwards compatibility.Architecture
New Modules (8):
src/hooks/types.ts- Core type definitionssrc/hooks/workspace.ts- Three-tier directory scanningsrc/hooks/frontmatter.ts- HOOK.md metadata parsersrc/hooks/config.ts- Eligibility checkingsrc/hooks/bundled-dir.ts- Bundled hooks resolver (supports both dev and compiled paths)src/hooks/hooks-status.ts- Status report buildersrc/cli/hooks-internal-cli.ts- Full CLI suitescripts/copy-hook-metadata.ts- Build step to copy HOOK.md files alongside compiled JSCore Hook System:
src/hooks/internal-hooks.ts- Event registration and triggeringsrc/hooks/loader.ts- Updated for directory discovery + legacy supportsrc/commands/onboard-hooks.ts- Uses discovery instead of hardcoded configsrc/gateway/server-startup.ts- Loads hooks on startupEvent Triggers:
src/auto-reply/reply/commands-core.ts- Triggers command eventssrc/auto-reply/reply/commands-session.ts- Triggers session eventsBundled Hooks: Real-World Examples
1. Session Memory Hook (Solves Real User Pain)
Problem: Users have reported that some of the cheaper models (Minimax, z.ai, DeepSeek, etc.) are less eager to update memories on their own during conversations. They often need explicit prompting to save context to memory, which creates friction.
Solution: The
session-memorybundled hook automatically saves session context when you issue/new, forcing memory updates without requiring model cooperation.What it does:
/newcommand~/clawd/memory/YYYY-MM-DD-slug.mdExample output files:
2026-01-16-vendor-pitch.md2026-01-16-api-design.md2026-01-16-bug-fix.md2026-01-16-1430.md(fallback timestamp if slug generation fails)Onboarding Option:
During
clawdbot onboard, users are now prompted to enable this hook:This ensures memory is always captured, regardless of which model you're using.
2. Command Logger Hook
Logs all command events to
~/.clawdbot/logs/commands.login JSONL format for auditing and debugging.What it does:
/new,/reset,/stop, etc.)Use cases:
NPM Distribution & Compilation
Fixes Applied:
1. Bundled Hooks Compilation (c227a83)
Issue: Initial implementation shipped bundled hooks as TypeScript source files, which failed to load when installed via npm with error:
Solution:
hooks/bundled/tosrc/hooks/bundled/for TypeScript compilationscripts/copy-hook-metadata.tsbuild step to copy HOOK.md files alongside compiled JSresolveBundledHooksDir()to resolve both compiled (dist/hooks/bundled/) and source (src/hooks/bundled/) locationsdist/hooks/bundled/with metadata files2. LLM Slug Generator Import Path (c227a83)
Issue: Session-memory hook failed with module not found error due to incorrect import path (
dist/hooks/dist/hooks/llm-slug-generator.js).Solution: Fixed import path resolution to correctly locate
llm-slug-generator.jsatdist/hooks/llm-slug-generator.jsfrom compiled handler location.3. Conversation Content in Memory Files (5cab0c7)
Issue: Session-memory hook was only saving session metadata (session key, ID, source) without the actual conversation content.
Solution:
This ensures hooks work correctly in both development (TypeScript source) and production (compiled JavaScript from npm), and that memory files contain complete conversation context.
Documentation
docs/internal-hooks.md- Complete guide (779 lines)docs/cli/hooks.md- CLI reference (232 lines)hooks internalcommandsTesting
The 1 failing test is a pre-existing timezone flaky test unrelated to this PR.
Benefits
This introduces internal hooks as a first-class feature alongside skills, with two practical bundled examples that demonstrate the system's capabilities and solve real user needs.