todo-enforcer

Todo continuation enforcer for pi-coding-agent — monitors todo state and injects prompts to keep agents working until all tasks complete

Packages

Package details

extension

Install todo-enforcer from npm and Pi will load the resources declared by the package manifest.

$ pi install npm:todo-enforcer
Package
todo-enforcer
Version
1.0.0
Published
May 31, 2026
Downloads
not available
Author
buihongduc132
License
MIT
Types
extension
Size
108.5 KB
Dependencies
0 dependencies · 1 peer

Security note

Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.

README

todo-enforcer

Todo continuation enforcer for pi-coding-agent — monitors todo state and injects prompts to keep agents working until all tasks complete.

npm version License: MIT pi-package

Features

  • Automatic task continuation — injects prompts when the agent goes idle with incomplete tasks
  • Configurable rule engine — first-match-wins rule evaluation with built-in and custom conditions
  • Multiple delivery modesuserMessage (default) or customMessage via pi's messaging API
  • External command support — call external scripts/HTTP endpoints for dynamic continuation logic
  • Spawn action — run pi -p in background to generate continuation guidance
  • Stagnation detection — stops injecting when the agent is stuck on the same incomplete count
  • Exponential backoff — rate-limits retries on LLM errors (429, rate limits, etc.)
  • Message stall guard — prevents infinite loops from repeated identical messages
  • Polling timer — re-evaluates after cooldown even without agent_end events
  • Completion summary control — configurable completionSummary to suppress or enable the "all done" message (default: suppressed)

Installation

For Humans

npm install -g todo-enforcer

For AI Agents (pi / OpenCode / Claude Code / Codex)

Add to your settings.json:

{
  "packages": ["todo-enforcer"]
}

Or tell your agent:

Install and configure todo-enforcer by following:
https://raw.githubusercontent.com/buihongduc132/todo-enforcer/refs/heads/main/README.md

For pi (git-sourced)

In settings.json:

{
  "packages": ["https://github.com/buihongduc132/todo-enforcer"]
}

For pi (local path)

In settings.json:

{
  "packages": ["/path/to/todo-enforcer"]
}

Usage

todo-enforcer auto-activates via pi's agent_end lifecycle hook. No manual invocation needed.

How It Works

  1. On each agent_end event, the enforcer reads the current todo state
  2. It evaluates rules in order — the first matching rule wins
  3. If a rule matches, it generates a prompt and delivers it to the agent
  4. A polling timer re-checks after the cooldown expires

Default Rules

Rule Condition Action
incomplete-tasks-remain Any pending/in_progress tasks Inject continuation prompt
all-complete-celebration All tasks completed Inject summary (disabled by default)

Slash Commands

Command Description
/enforcer-status Show current enforcer state, rules, and injection count
/enforcer-switch <rule1,rule2,...> Switch active rules for this session
/enforcer-switch reset Reset to config defaults
/enforcer-reset Reset all enforcer state for this session

Keyboard Shortcut

Shortcut Action
Ctrl+Shift+T Toggle enforcer enabled/disabled

Configuration

Create ~/.todo-enforcer.json (global) or .todo-enforcer.json (project-level):

{
  "enabled": true,
  "maxInjections": 5,          // Max injections per session
  "cooldownMs": 5000,          // Cooldown between injections (ms)
  "completionSummary": false,  // Suppress "all done" message (default)
  "detectStagnation": true,    // Stop injecting when stuck
  "stagnationThreshold": 3,    // Consecutive idle events before stagnation
  "backoff": {
    "enabled": true,
    "factor": 2,
    "maxDelayMs": 3600000,
    "errorPatterns": ["429", "rate limit", "No deployments available"]
  },
  "messageDelivery": {
    "mode": "userMessage",     // "userMessage" or "customMessage"
    "display": true,
    "triggerTurn": true
  },
  "rules": [
    {
      "name": "incomplete-tasks-remain",
      "condition": "has_incomplete",
      "action": "prompt",
      "prompt": "You have incomplete tasks. Continue working on them.\n\n[Status: {{completed_count}}/{{total_count}} completed, {{incomplete_count}} remaining]\n\nRemaining tasks:\n{{incomplete_list}}\n\nPick up where you left off."
    },
    {
      "name": "all-complete-celebration",
      "condition": "all_complete",
      "action": "prompt",
      "prompt": "All {{total_count}} tasks are complete. Great work.\n\nCompleted tasks:\n{{completed_list}}\n\nYou may now summarize the results or ask the user for next steps."
    }
  ]
}

Built-in Conditions

Condition Description
has_incomplete Any pending/in_progress tasks remain
all_complete Every non-deleted task is completed
has_in_progress At least one task is in_progress
none Never matches (disabled rule)
always Always matches

Template Variables

Variable Description
{{incomplete_count}} Number of incomplete tasks
{{completed_count}} Number of completed tasks
{{total_count}} Total non-deleted tasks
{{incomplete_list}} Formatted list of incomplete tasks
{{completed_list}} Formatted list of completed tasks
{{latest_user_message}} Latest user message content
{{assistant_messages}} Recent assistant messages

Actions

Action Description
prompt Inject a static template string
external Call an external command or HTTP endpoint
spawn Run pi -p in background with a template
noop Do nothing (for logging/future use)

Architecture

todo-enforcer/
├── src/
│   ├── index.ts              ← Entry point — hooks, commands, shortcuts
│   ├── config.ts             ← Config loader + types + template interpolation
│   ├── conditions.ts         ← Built-in + custom condition evaluator
│   ├── external-caller.ts    ← External command/HTTP executor
│   ├── session-state.ts      ← Per-session state tracking
│   ├── todo-snapshot.ts      ← Reads todo state from session branch
│   ├── message-stall.ts      ← Repeated message + rate limit guard
│   ├── type-guards.ts        ← Runtime type guards
│   └── lib/
│       ├── plugin-logger.ts  ← File-based structured logger
│       ├── hooks-manager.ts  ← Hook registration and state
│       └── types.ts          ← Shared types
├── tests/                    ← Test suite (134 tests)
├── package.json
├── tsconfig.json
└── vitest.config.ts

Development

# Install dependencies
npm install

# Run tests
npm test

# Run tests with coverage
npm run test:ci

# Type check
npm run typecheck

License

MIT

Repository

GitHub: buihongduc132/todo-enforcer