-
Notifications
You must be signed in to change notification settings - Fork 221
Description
GitHub Issue: Add Hook System for Task Lifecycle Events
Repository: MrLesk/Backlog.md
Issue Type: Feature Request
Labels: enhancement, extensibility
Title
feat: Expand status callback system into comprehensive hook system for all task lifecycle events
Summary
Proposal to expand the existing onStatusChange callback mechanism into a comprehensive hook system that supports all task lifecycle events, enabling richer integrations with AI-augmented development workflows and external tooling.
Motivation
Backlog.md already has excellent AI agent integration via MCP and a status change callback system. However, AI-augmented development workflows often need to react to more than just status changes:
Current Capability (via onStatusChange):
- React to task status transitions
- Limited to status changes only
- Single callback per event
Needed Capabilities:
- Task creation events (initialize resources, capture context)
- Task updates beyond status (assignee changes, priority shifts)
- Task archival events (cleanup, metrics collection)
- Multiple hook scripts per event type
Use Cases:
- Task Memory Systems: AI agents need to capture task context when work begins and archive it when complete
- Team Notifications: Notify Slack/email on creation, updates, or completion (not just status changes)
- External System Integration: Sync with Jira, Linear, GitHub Issues on any task change
- Analytics: Track complete task lifecycle (create → update → archive), not just status transitions
- Resource Management: Create/cleanup branches, directories, or related artifacts
Related: Issue #392 (Jira sync) would benefit from comprehensive hooks.
Proposed Design
Building on Existing Pattern
The current executeStatusChangeCallback() implementation provides an excellent foundation. The proposal is to generalize this pattern to support:
-
Additional Hook Events:
post-task-create- After task creationpost-task-update- After any metadata change (currently status-only)post-task-archive- After task archival- Future:
pre-task-*events for validation workflows
-
Hook Discovery:
- Discover scripts in
.backlog/hooks/directory - Scripts named by event:
post-task-create.sh,post-task-update.sh, etc. - Must be executable (same security model as Git hooks)
- Discover scripts in
-
Environment Variable Context:
# All hooks receive: BACKLOG_HOOK_EVENT=post-task-create BACKLOG_TASK_ID=task-42 BACKLOG_TASK_TITLE="Implement feature X" # Event-specific: BACKLOG_TASK_STATUS="To Do" # create, update BACKLOG_OLD_STATUS="To Do" # update (when status changes) BACKLOG_NEW_STATUS="In Progress" # update (when status changes) BACKLOG_TASK_ASSIGNEE="@user1,@user2" # create, update
-
Configuration (extends existing pattern):
# .backlog/config.yml hooks: enabled: true # Global enable/disable directory: .backlog/hooks # Custom hook directory timeout: 5000 # Timeout in milliseconds logLevel: info # none, error, info, debug
Implementation Approach
Following the existing executeStatusChangeCallback() pattern:
-
Create
src/core/hooks.ts:export enum HookEvent { POST_TASK_CREATE = "post-task-create", POST_TASK_UPDATE = "post-task-update", POST_TASK_ARCHIVE = "post-task-archive", } export async function emitHook( event: HookEvent, context: HookContext, config: BacklogConfig, projectRoot: string ): Promise<void>
-
Integration Points (similar to status callback):
createTask()- Emitpost-task-createafter successupdateTask()- Emitpost-task-updateafter successarchiveTask()- Emitpost-task-archiveafter success
-
Fail-Safe Execution (same as status callback):
- Hook failures never block task operations
- Errors logged but don't affect CLI commands
- Async execution with configurable timeout
Example Use Cases
Task Memory Integration
#!/bin/bash
# .backlog/hooks/post-task-update.sh
if [[ "$BACKLOG_NEW_STATUS" == "In Progress" ]]; then
# Capture task context when work begins
speckit memory capture "$BACKLOG_TASK_ID"
fi
if [[ "$BACKLOG_NEW_STATUS" == "Done" ]]; then
# Archive context when complete
speckit memory archive "$BACKLOG_TASK_ID"
fiTeam Notifications
#!/bin/bash
# .backlog/hooks/post-task-create.sh
curl -X POST "$SLACK_WEBHOOK" \
-d "text=New task created: [$BACKLOG_TASK_ID] $BACKLOG_TASK_TITLE"Jira Sync (addresses #392)
#!/bin/bash
# .backlog/hooks/post-task-update.sh
if [[ -n "$BACKLOG_NEW_STATUS" ]]; then
python scripts/sync_to_jira.py \
--task-id "$BACKLOG_TASK_ID" \
--status "$BACKLOG_NEW_STATUS"
fiDesign Decisions
Why Expand Rather Than Replace Status Callbacks?
- Backward Compatibility: Existing
onStatusChangeconfigs continue working - Event Granularity: Not all updates are status changes (assignee, priority, etc.)
- Separation of Concerns: Status callbacks for status-specific logic, general hooks for broader automation
- Migration Path: Users can migrate incrementally from status callbacks to hooks
Why Script-Based Over Plugin System?
- Simplicity: Executable scripts are easier than TypeScript plugins
- Consistency: Follows Git hooks, Husky, and other established patterns
- Security: No dynamic code loading; explicit script execution
- Cross-Language: Hooks can be bash, Python, Node.js, or any executable
Why Post-Hooks Only (Initially)?
Pre-hooks can block operations and add complexity. Starting with post-hooks provides:
- Event notification without operational risk
- Simpler implementation and testing
- Foundation for future pre-hook validation if needed
Backward Compatibility
✅ 100% backward compatible
- Hooks are opt-in (no behavior change without explicit script creation)
- Existing
onStatusChangecallbacks continue working - No breaking changes to API, CLI, or configuration
- Default behavior unchanged
Implementation Checklist
I have a complete implementation ready:
- TypeScript implementation (
src/core/hooks.ts) - Type definitions (
src/types/index.tsadditions) - Integration points in
src/core/backlog.ts - Unit tests (Bun test framework)
- User documentation (
docs/hooks.md) - Example scripts (task memory, notifications, Jira sync)
- Configuration schema
Files:
- Design document: backlog-hooks-design.md
- API documentation: hooks-api.md
- PR template: backlog-hooks-pr-template.md
Questions for Maintainer
- Interest Level: Is this a feature you'd accept a PR for?
- Naming Convention: Prefer
post-task-*,on-task-*, orafter-task-*? - Relationship to Status Callbacks: Keep both, or deprecate
onStatusChangein favor of unified hook system? - Additional Events: Any other lifecycle events you'd like to support?
- Documentation Location: Should docs go in
docs/or somewhere else?
Alternative Considered
MCP-Only Integration: Handle all events through MCP tools rather than local hooks.
Rejected Because:
- MCP is for AI agent queries/actions, not event-driven workflows
- Local hooks enable non-AI integrations (Slack, Jira, metrics)
- Hooks complement MCP rather than replace it
- Scripts provide simpler automation for common tasks
Next Steps
If this aligns with your vision for Backlog.md, I'm happy to:
- Submit a PR with the implementation
- Iterate on design feedback
- Add additional hook events based on your preferences
- Update documentation as needed
Looking forward to your thoughts!
References:
- Similar systems: Git hooks, GitHub Actions, Husky
- Related issue: [Feature]: Sync between Jira and Backlog.md #392 (Jira sync - would benefit from hooks)
- Implementation inspiration: Current
executeStatusChangeCallback()insrc/core/backlog.ts