npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@frugally3683/agent-loop-plugin

v5.1.2

Published

Minimal Task Continuation Plugin - Automatically continues sessions when incomplete tasks remain

Readme

Task Continuation & Goal Management Plugin

Minimal task continuation and goal management plugin for OpenCode - automatically continues sessions when incomplete tasks remain and provides structured goal tracking for AI agents using the modern tool pattern.

Overview

This plugin provides two complementary systems:

  1. Task Continuation: Automatically continues sessions when incomplete todos remain
  2. Goal Management: Structured goal tracking with persistence across sessions using the modern OpenCode tool pattern
  3. Goal Context Injection: Automatically injects the current goal into session context so agents never forget their objectives

Perfect for:

  • Multi-step task execution with automatic continuation
  • Long-running agent workflows with clear objectives
  • Goal-oriented AI agents that need to maintain context
  • Preventing premature session termination
  • Ensuring all tasks in a todo list are completed

New Plugin Architecture

This plugin follows the modern OpenCode plugin architecture with a clean separation of concerns:

src/
├── plugin.ts              # Main plugin entry point
├── types.ts               # TypeScript type definitions
├── logger.ts              # Logging utilities
├── goal/                  # Core goal management implementation
│   ├── management.ts      # Goal CRUD operations
│   ├── continuation.ts    # Task continuation logic
│   └── storage.ts         # File-based storage
└── tools/goal/            # OpenCode tool definitions (NEW!)
    ├── index.ts           # Tool factory function
    ├── goal_set.ts        # goal_set tool
    ├── goal_status.ts     # goal_status tool
    ├── goal_done.ts       # goal_done tool
    └── goal_cancel.ts     # goal_cancel tool

Key Architecture Changes

  • Tool Pattern: Uses @opencode-ai/plugin tool() decorator for LLM-accessible tools
  • Separation of Concerns: Core logic (goal/) separated from tool definitions (tools/goal/)
  • Type Safety: Full TypeScript support with comprehensive interfaces
  • Event-Driven: Uses OpenCode event system for session management

Installation

npm install @frugally3683/agent-loop-plugin

Quick Start

Basic Plugin Usage

import agentLoopPlugin from "@frugally3683/agent-loop-plugin"

export default agentLoopPlugin

Advanced Usage with Custom Configuration

import { agentLoopPlugin } from "@frugally3683/agent-loop-plugin"

export default {
  plugins: [agentLoopPlugin],
  // Custom configuration if needed
}

Tool Reference

The plugin exposes four powerful tools that AI agents can use during conversations to manage goals effectively.

goal_set

Purpose: Set a new goal for the current session to keep the agent focused on primary objectives.

Usage:

goal_set({
  title: "Implement user authentication",
  done_condition: "Users can sign up, log in, and log out securely",
  description: "Create a complete auth system with JWT tokens",
})

Parameters:

  • title (string, required): Short, clear title for the goal
  • done_condition (string, required): Description of what constitutes goal completion
  • description (string, optional): Detailed explanation of the goal

Example Response:

✅ Goal set successfully!

**Title:** Implement user authentication
**Done Condition:** Users can sign up, log in, and log out securely
**Description:** Create a complete auth system with JWT tokens

The agent will work toward this goal. Use goal_done when the condition is met.

goal_status

Purpose: Check the current goal status to understand what the agent should be working on.

Usage:

goal_status()

Parameters: None required

Example Response:

🎯 **Current Goal:** Implement user authentication
**Description:** Create a complete auth system with JWT tokens
**Status:** 🟡 In Progress
**Done Condition:** Users can sign up, log in, and log out securely
**Created:** 1/15/2024, 10:30 AM

goal_done

Purpose: Mark the current goal as successfully completed when the done condition is met.

Usage:

goal_done()

Parameters: None required

Example Response:

🎉 Goal completed!

**Title:** Implement user authentication
**Completed At:** 1/15/2024, 2:45 PM

The goal has been marked as complete.

goal_cancel

Purpose: Cancel or abandon the current goal without completing it when goals are no longer relevant.

Usage:

goal_cancel({
  reason: "Requirements changed, need to reassess approach",
})

Parameters:

  • reason (string, optional): Explanation for why the goal is being cancelled

Example Response:

🚫 Goal cancelled.

**Title:** Implement user authentication
**Reason:** Requirements changed, need to reassess approach
The goal has been removed.

goal_validate

Purpose: Validate a completed goal after agent review. This is the final step in the goal lifecycle where the agent confirms the done condition has been met.

Usage:

goal_validate()

Preconditions:

  • Goal must be in "completed" status (use goal_done first)
  • Agent should review the goal and verify the done condition is satisfied

Parameters: None required

Example Response:

✅ Goal validated!

**Title:** Implement user authentication
**Status:** Validated
**Completed:** 1/15/2024, 2:45 PM
**Validated:** 1/15/2024, 3:00 PM
**Done Condition:** Users can sign up, log in, and log out with secure password handling

The goal has been successfully validated and is now complete.

Goal Lifecycle:

  1. Active: Goal is being worked on
  2. Completed: Agent has marked goal as done (goal_done)
  3. Validated: Agent has reviewed and confirmed the done condition is met (goal_validate)

Goal Management API

Goal Concepts

A goal represents a distinct objective that an AI agent should work toward. Unlike todos, which are individual tasks, goals are broader achievements that typically require multiple steps to accomplish. Goals provide:

  • Persistent Context: Goals persist across sessions, helping agents remember their objectives
  • Clear Completion Criteria: Each goal has a defined "done condition" that specifies when it's achieved
  • Structured Workflows: Goals help organize complex multi-step workflows into coherent units
  • Progress Tracking: Goals track their status (active/completed/validated) and completion/validation timestamps

Goal Structure

Goals are stored as JSON files with the following structure:

interface Goal {
  /** Title of the goal */
  title: string
  /** Optional detailed description of the goal */
  description?: string
  /** String description of what constitutes goal completion */
  done_condition: string
  /** Current status of the goal */
  status: "active" | "completed" | "validated"
  /** ISO timestamp when the goal was created */
  created_at: string
  /** ISO timestamp when the goal was completed, null if not completed */
  completed_at: string | null
  /** ISO timestamp when the goal was validated, null if not validated */
  validated_at: string | null
}

Goal Storage

Goals are stored in the following location:

  • Base Path: ~/.local/share/opencode/plugin/agent-loop
  • Session Path: {basePath}/{sessionID}/goal.json
  • Custom Path: Configurable via goalsBasePath option

Each session can have one active goal at a time. Setting a new goal overwrites the existing one, ensuring agents always have a clear, current objective.

Advanced Usage

Direct Goal Management API

For more control, you can use the goal management API directly:

import { createGoalManagement } from "@frugally3683/agent-loop-plugin"

export default function myPlugin() {
  // Create goal management with custom options
  const goalManagement = createGoalManagement({
    goalsBasePath: "/custom/path/to/goals",
  })

  return { goalManagement }
}

Goal Management Functions

createGoal

Creates a new active goal for the session. Overwrites any existing goal.

interface GoalManagement {
  createGoal: (
    sessionID: string,
    title: string,
    doneCondition: string,
    description?: string
  ) => Promise<Goal>
}

Example:

const goal = await goalManagement.createGoal(
  sessionID,
  "Implement user authentication",
  "Users can sign up, log in, and log out with secure password handling",
  "Create a complete authentication system with JWT tokens"
)

getGoal

Retrieves the current goal for a session, or null if no goal exists.

interface GoalManagement {
  getGoal: (sessionID: string) => Promise<Goal | null>
}

Example:

const currentGoal = await goalManagement.getGoal(sessionID)
if (currentGoal) {
  console.log(`Working on: ${currentGoal.title}`)
  console.log(`Done when: ${currentGoal.done_condition}`)
}

completeGoal

Marks the current goal as completed and records the completion timestamp.

interface GoalManagement {
  completeGoal: (sessionID: string) => Promise<Goal | null>
}

Example:

const completedGoal = await goalManagement.completeGoal(sessionID)
if (completedGoal) {
  console.log(`Goal completed: ${completedGoal.title}`)
  console.log(`Completed at: ${completedGoal.completed_at}`)
}

Task Continuation with Goal Awareness

The task continuation system integrates with goal management for intelligent session continuation:

import { createTaskContinuation } from "@frugally3683/agent-loop-plugin"

export default function myPlugin(ctx: PluginContext) {
  const goalManagement = createGoalManagement({})

  const taskContinuation = createTaskContinuation(ctx, {
    countdownSeconds: 3,
    goalManagement, // Enable goal-aware continuation
  })

  return { taskContinuation, goalManagement }
}

Tool Development Patterns

Using the tool() Decorator

This plugin demonstrates the modern OpenCode tool pattern using the tool() decorator from @opencode-ai/plugin:

import { tool } from "@opencode-ai/plugin"

export const myTool = tool({
  description: `My Custom Tool
  
  A detailed description of what this tool does and when to use it.
  
  **Parameters:**
  - \`param1\`: Description of first parameter
  - \`param2\`: Description of second parameter`,

  args: {
    param1: tool.schema.string().describe("First parameter description"),
    param2: tool.schema.number().describe("Second parameter description"),
    optionalParam: tool.schema.boolean().optional().describe("Optional parameter"),
  },

  async execute(args, context) {
    // Tool implementation
    return `Tool executed with: ${args.param1}, ${args.param2}`
  },
})

Schema Definition Best Practices

  1. Use Descriptive Names: Name parameters clearly to help LLM agents understand their purpose
  2. Add Descriptions: Use .describe() to provide context for each parameter
  3. Validate Input Types: Use appropriate schema types (string, number, boolean, etc.)
  4. Mark Optional Parameters: Use .optional() for non-required parameters
  5. Provide Defaults: Use .default() when appropriate for optional parameters

Tool Context

Tools receive a context object with session information:

interface ToolContext {
  sessionID: string // Current session identifier
  messageID: string // Current message identifier
  agent: string // Current agent name
  abort: AbortSignal // Signal for cancellation
}

Integration Patterns

Pattern 1: Goal-Directed Task Execution

AI agents can use goals to maintain focus on overarching objectives:

// Agent sets a high-level goal at the start of a complex task
await goal_set({
  title: "Build REST API for task management",
  done_condition: "GET, POST, PUT, DELETE endpoints work for tasks with proper error handling",
  description: "Create a complete REST API with Express.js including validation and authentication",
})

// Agent can check the goal to stay on track
const goalInfo = await goal_status()
console.log(`Remember the goal: ${goalInfo}`)

// When API is complete, mark goal as done
await goal_done()

Pattern 2: Hierarchical Goal Setting

Agents can break down complex objectives into sub-goals:

// Set main project goal
await goal_set({
  title: "Complete e-commerce platform",
  done_condition:
    "Users can browse products, add to cart, checkout, and receive order confirmation",
})

// When starting a specific feature, update the goal
await goal_set({
  title: "Implement shopping cart",
  done_condition: "Users can add/remove items, view cart contents, and proceed to checkout",
})

// Later, move to next goal
await goal_set({
  title: "Implement checkout flow",
  done_condition: "Users can enter shipping info, payment details, and receive order confirmation",
})

Pattern 3: Goal-Integrated Todo System

Combine goals with todos for comprehensive task management:

// Set a goal
await goal_set({
  title: "Deploy application to production",
  done_condition: "Application is running in production with SSL and accessible via domain",
})

// Create todos that support the goal
await todowrite([
  { id: "1", content: "Set up CI/CD pipeline", status: "pending", priority: "high" },
  { id: "2", content: "Configure production database", status: "pending", priority: "high" },
  { id: "3", content: "Set up SSL certificates", status: "pending", priority: "medium" },
  { id: "4", content: "Update DNS records", status: "pending", priority: "medium" },
  { id: "5", content: "Test production deployment", status: "pending", priority: "high" },
])

// When all todos are complete, mark goal as done
await goal_done()

Pattern 4: Session Persistence

Goals persist across sessions, making them ideal for long-running workflows:

// Session 1: Agent sets a complex goal
await goal_set({
  title: "Migrate legacy database to new schema",
  done_condition: "All data migrated, applications updated, old database decommissioned",
})

// Session ends, but goal persists...

// Session 2: Agent checks goal and continues work
const goalInfo = await goal_status()
if (goalInfo.includes("Migrate legacy database")) {
  console.log("Resuming work on database migration...")
  // Continue with migration tasks...
}

Pattern 5: Conditional Goal Completion

Agents can use the done_condition to evaluate progress:

const goalInfo = await goal_status()
if (goalInfo.includes("🟡 In Progress")) {
  // Check if done condition is met
  const progress = assessProgress()

  if (progress.meetsCriteria()) {
    await goal_done()
    console.log("Goal completion criteria met!")
  } else {
    console.log("Still working toward goal completion...")
  }
}

Goal Context Injection

The plugin automatically injects the current goal into session context to ensure agents never forget their objectives. This provides persistent goal awareness across interactions.

Features:

  • Automatic Goal Injection: Injects the current goal into new sessions
  • Goal Guidance: Provides helpful goal tool usage instructions
  • Smart Deduplication: Only injects context once per session
  • Graceful Degradation: Silently skips if no goal exists
  • Session Recovery: Re-injects goal context on session compaction
  • Mode Preservation: Maintains the current model and agent settings

How It Works:

  1. On New Sessions: When a chat message is received, the plugin:

    • Checks if goal context was already injected
    • Gets the current goal for the session
    • Injects goal context with helpful tool guidance
    • Preserves model/agent settings to prevent mode switching
  2. On Session Compaction: When sessions are compacted, goal context is re-injected to maintain persistence

  3. Goal Context Format: The injected context includes:

    • Goal title
    • Goal description (if present)
    • Done condition (what constitutes completion)
    • Current status
    • Guidance on using goal tools

Goal Context Example:

<goal-context>
Implement user authentication system
Description: Create a complete authentication system with JWT tokens
Done Condition: Users can sign up, log in, and log out securely
Status: active
</goal-context>

## Goal Context

The agent has an active goal for this session. Use the goal tools to manage it:
- `goal_status` - Check the current goal details
- `goal_done` - Mark the goal as completed when the done condition is met
- `goal_cancel` - Cancel the goal if it's no longer relevant

**Remember:** Work toward completing the goal's done condition.

Benefits:

  • Never Forget Goals: Agents always have the current goal in context
  • Persistent Awareness: Goal context survives session compaction and plugin reload
  • Clear Focus: Agents can see exactly what they should be working toward
  • Tool Integration: Provides immediate access to goal management tools

Configuration:

The goal context injection is automatic and requires no configuration. It gracefully handles:

  • Missing goals (no injection occurs)
  • Plugin reload/reconnection scenarios
  • Session compaction events

Plugin Options

| Option | Type | Default | Description | | ------------------ | ------- | ------- | ---------------------------------------- | | taskLoop | boolean | true | Enable task loop functionality | | countdownSeconds | number | 2 | Seconds to wait before auto-continuation | | errorCooldownMs | number | 3000 | Cooldown period after errors | | toastDurationMs | number | 900 | Toast notification duration | | debug | boolean | true | Enable debug logging | | logFilePath | string | - | Path to log file for debugging |

Goal Management Options

| Option | Type | Default | Description | | --------------- | ------ | ----------------------------------------- | --------------------------------- | | goalsBasePath | string | ~/.local/share/opencode/plugin/agent-loop | Custom base path for goal storage |

Task Continuation Options

| Option | Type | Default | Description | | ------------------ | -------------- | ------- | --------------------------------------------- | | countdownSeconds | number | 2 | Seconds to wait before continuation | | errorCooldownMs | number | 3000 | Cooldown period after errors | | toastDurationMs | number | 900 | Toast notification duration | | agent | string | - | Agent name for continuation prompts | | model | string | - | Model name for continuation prompts | | logFilePath | string | - | Path to log file for debugging | | goalManagement | GoalManagement | - | Goal management instance for goal integration |

OpenCode SDK Integration

This plugin uses the OpenCode SDK patterns for session interaction:

interface PluginContext {
  /** Working directory for the session */
  directory: string

  /** Client API for interacting with OpenCode */
  client: {
    /** Session management APIs */
    readonly session: {
      /** Get current session ID */
      readonly id: string

      /** Get session details including agent and model */
      get(opts: { path: { id: string } }): Promise<SessionInfo>

      /** List messages in a session, returns most recent first */
      messages(opts: {
        path: { id: string }
      }): Promise<Array<{ info: MessageInfo; parts: unknown[] }>>

      /** Send a prompt to a session */
      prompt(opts: {
        path: { id: string }
        body: {
          agent?: string
          model?: string | ModelSpec
          noReply?: boolean
          parts: Array<PromptPart>
        }
        query?: { directory: string }
      }): Promise<void>

      /** Get todos for a session */
      todo(opts: { path: { id: string } }): Promise<Todo[] | { data: Todo[] }>
    }

    /** Text UI APIs */
    tui: {
      /** Show a toast notification in the UI */
      showToast(opts: {
        body: {
          title: string
          message: string
          variant: "info" | "success" | "warning" | "error"
          duration: number
        }
      }): Promise<void>
    }
  }
}

Development

# Install dependencies
npm install

# Run tests
npm test

# Type check
npm run typecheck

# Build
npm run build

# Lint
npm run lint

# Format
npm run format

Goal Storage Format

Goals are stored as JSON files in the following structure:

File Location: {goalsBasePath}/{sessionID}/goal.json

Example Goal File:

{
  "title": "Implement user authentication system",
  "description": "Create a complete authentication system with JWT tokens, refresh tokens, and secure password hashing",
  "done_condition": "Users can sign up, log in, and log out with secure password handling and session management",
  "status": "active",
  "created_at": "2024-01-15T10:30:00.000Z",
  "completed_at": null
}

Example Completed Goal:

{
  "title": "Set up development environment",
  "description": "Configure all necessary tools and dependencies for development",
  "done_condition": "All developers can run 'npm install' and 'npm run dev' successfully",
  "status": "completed",
  "created_at": "2024-01-10T09:00:00.000Z",
  "completed_at": "2024-01-10T11:45:00.000Z"
}

Best Practices

  1. Clear Goal Titles: Use concise, descriptive titles that fit in a single line
  2. Specific Done Conditions: Define exactly what "done" means for each goal
  3. Reasonable Scope: Goals should be achievable within a few hours to days
  4. Update Goals: When objectives change, update the goal rather than creating new ones
  5. Use with Todos: Combine goals with todos for comprehensive task management
  6. Complete Goals: Always call goal_done when a goal is achieved
  7. Cancel When Needed: Use goal_cancel when goals are no longer relevant
  8. Leverage Tools: Use the goal tools during conversations for better agent coordination

API Reference

agentLoopPlugin

const agentLoopPlugin: Plugin = async (ctx: PluginContext): Promise<PluginResult>

Parameters:

  • ctx: Plugin context with session and tui access

Returns: PluginResult with tools and event handlers

Tools Provided:

  • goal_set: Set a new goal for the session
  • goal_status: Check current goal status
  • goal_done: Mark current goal as completed
  • goal_cancel: Cancel current goal

createGoalManagement

function createGoalManagement(options?: GoalManagementOptions): GoalManagement

Parameters:

  • options: Optional configuration for goal management

Returns: GoalManagement interface with readGoal, writeGoal, createGoal, completeGoal, getGoal, hasActiveGoal, handler, and cleanup methods

createTaskContinuation

function createTaskContinuation(
  ctx: PluginContext,
  options?: TaskContinuationOptions
): TaskContinuation

Parameters:

  • ctx: Plugin context with session and tui access
  • options: Optional configuration for task continuation

Returns: TaskContinuation interface with handler, markRecovering, markRecoveryComplete, cancel, and cleanup methods

Migration Guide

From Previous Versions

If you're migrating from an older version of this plugin:

  1. Import Changes: Update imports to use the new structure

    // Old way
    import { createGoalManagement } from "@frugally3683/agent-loop-plugin"
    
    // New way (still supported)
    import { createGoalManagement } from "@frugally3683/agent-loop-plugin"
  2. Tool Usage: Tools are now automatically exposed to agents

    // Old way - manual command handling
    .prompt({
    await ctx.client.session     path: { id: sessionID },
      body: {
        parts: [{
          type: "text",
          text: JSON.stringify({
            command: "goal_set",
            args: { title: "...", done_condition: "..." }
          })
        }]
      }
    })
    
    // New way - direct tool calls
    await goal_set({
      title: "...",
      done_condition: "...",
      description: "..."
    })
  3. Plugin Integration: The plugin now automatically handles tool exposure

    // Just import and use the plugin
    import agentLoopPlugin from "@frugally3683/agent-loop-plugin"
    
    export default agentLoopPlugin

New Tool Pattern Benefits

  • Natural Language Interface: Agents can call tools using natural language
  • Automatic Schema Validation: Input validation built into the tool pattern
  • Better Error Handling: Consistent error responses across all tools
  • Context Awareness: Tools have access to session context automatically
  • Type Safety: Full TypeScript support for tool definitions

License

MIT