Skip to content

Toady00/opencode-hindsight

Repository files navigation

opencode Hindsight

An opencode plugin for integrating with Vectorize Hindsight, an AI agent memory system. The plugin gives each opencode agent its own configurable memory behavior, including separate banks for automatic retention, automatic recall, and manual tool usage.

Status: 0.1.5 is an alpha feature release. Expect rough edges and test with non-critical memory banks before relying on it for important workflows.

Features

  • Per-agent Hindsight configuration via agent.<name>.options.hindsight.
  • Global defaults with per-agent overrides.
  • applyMode: "all" and applyMode: "opt-in" support.
  • Automatic memory recall at root session start.
  • Configure session-start context injection with a Hindsight mental model ID or a custom recall query, with per-agent overrides.
  • Automatic transcript retention on session.status idle events.
  • On-demand TUI session retention with /hindsight-retain.
  • Pre-compaction retention and recall support.
  • Manual tools:
    • hindsight_retain
    • hindsight_recall
    • hindsight_reflect
  • Multi-bank recall with bank-labeled system prompt injection.
  • Root-session-only automatic behavior, while manual tools remain available to configured child agents.
  • Graceful degradation when disabled, unconfigured, or when Hindsight/API calls fail.

Requirements

  • Bun 1.3.10 or newer compatible runtime for development.
  • opencode with @opencode-ai/plugin >=1.14.41.
  • A running Hindsight API endpoint.
  • Optional Hindsight API token, depending on your Hindsight deployment.

Installation

After the package is published to npm, install it in the environment where opencode loads plugins:

bun add @toady00/opencode-hindsight

For local development from this repository:

bun install
bun run build

Then reference the package from your opencode configuration.

If you are testing from a local checkout before publishing, build the package first and use your package manager's local-link workflow from the opencode configuration environment.

Basic opencode Configuration

Add the plugin to opencode.json:

{
  "plugin": [
    [
      "@toady00/opencode-hindsight",
      {
        "hindsightApiUrl": "http://localhost:8888",
        "hindsightApiToken": "optional-token",
        "applyMode": "all",
        "defaults": {
          "autoRetainBank": "project",
          "retainBanks": ["project"],
          "autoRecallBanks": ["project"],
          "recallBanks": ["project"],
          "retainMode": "full-session",
          "retainEveryNTurns": 3,
          "tags": ["source:opencode", "repo:my-project"],
          "autoRetainAsync": true,
          "autoRetainStrategy": "conversation",
          "manualRetain": {
            "bank": "project",
            "async": true,
            "strategy": "conversation",
            "tags": ["source:opencode", "trigger:manual"]
          },
          "retainBankStrategies": {
            "project": "manual-note"
          }
        }
      }
    ]
  ]
}

You can also configure the Hindsight endpoint via environment variables:

export HINDSIGHT_API_URL="http://localhost:8888"
export HINDSIGHT_API_TOKEN="optional-token"
export HINDSIGHT_DEBUG="true"

Environment variables are used when the equivalent plugin options are omitted.

Plugin-level defaults can include async retain behavior, retain strategies, and tags shared by all enabled agents:

{
  "defaults": {
    "autoRetainBank": "project-memory",
    "retainBanks": ["project-memory", "source-docs"],
    "tags": ["source:opencode", "repo:my-project"],
    "autoRetainAsync": true,
    "autoRetainStrategy": "conversation",
    "manualRetain": {
      "bank": "project-memory",
      "async": true,
      "strategy": "conversation",
      "tags": ["trigger:manual"]
    },
    "retainBankStrategies": {
      "project-memory": "manual-note",
      "source-docs": "source-document"
    }
  }
}

Quick Start

For a single shared project memory bank, this is the smallest useful setup:

{
  "plugin": [
    [
      "@toady00/opencode-hindsight",
      {
        "hindsightApiUrl": "http://localhost:8888",
        "defaults": {
          "autoRetainBank": "project",
          "retainBanks": ["project"],
          "autoRecallBanks": ["project"],
          "recallBanks": ["project"]
        }
      }
    ]
  ]
}

With this configuration, root sessions automatically recall from project at startup, retain transcripts to project as the session goes idle, and expose manual retain/recall/reflect tools for configured agents.

By default, automatic retention waits for three new user turns before retaining. Set retainEveryNTurns to 1 while smoke-testing if you want the first idle event after a prompt to retain immediately.

Manual TUI Retain

The /hindsight-retain TUI slash command retains the current session transcript to a configured Hindsight bank on demand. It is separate from automatic retention: auto-retain still runs on idle/compaction events, while manual retain only runs when you invoke the command from an open session.

Add the companion TUI plugin entry to enable the slash command. The root server plugin handles auto-retain, auto-recall, and manual tools; the TUI plugin handles the /hindsight-retain command.

Preferred configuration keeps all options on the server plugin and lets the TUI plugin discover them from the root plugin tuple:

{
  "plugin": [
    [
      "@toady00/opencode-hindsight",
      {
        "hindsightApiUrl": "http://localhost:8888",
        "defaults": {
          "manualRetain": {
            "bank": "project-memory"
          }
        }
      }
    ],
    "@toady00/opencode-hindsight/tui"
  ]
}

If fallback discovery is unavailable in your opencode version, or if you want the TUI command to use different defaults, provide explicit TUI options:

{
  "plugin": [
    [
      "@toady00/opencode-hindsight",
      {
        "hindsightApiUrl": "http://localhost:8888"
      }
    ],
    [
      "@toady00/opencode-hindsight/tui",
      {
        "hindsightApiUrl": "http://localhost:8888",
        "defaults": {
          "manualRetain": {
            "bank": "project-memory"
          }
        }
      }
    ]
  ]
}

manualRetain supports these fields:

Field Type Default Description
bank string omitted Target Hindsight bank for manual TUI retain. Required for /hindsight-retain to work.
async boolean true Whether manual retain uses async processing.
strategy string omitted Hindsight retain strategy for manual retain. Independent from auto-retain strategies.
tags string[] [] Tags attached to manual retain calls. Independent from auto-retain tags.

Per-agent config can override plugin defaults field-by-field. A per-agent manualRetain.tags array replaces default manual tags instead of merging with them.

YAML frontmatter example:

hindsight:
  manualRetain:
    bank: tester-memory
    async: false
    strategy: conversation
    tags:
      - source:opencode
      - trigger:manual
      - agent:tester

To use the command, open a session in the TUI and type /hindsight-retain in the command palette. Plugin and config changes, including adding the TUI plugin entry or changing manualRetain, require restarting opencode before they take effect.

Plugin Options

Option Description Default
enabled Set to false to disable the plugin entirely. true
hindsightApiUrl Hindsight API URL. Required unless HINDSIGHT_API_URL is set. none
hindsightApiToken Optional API token. Can also use HINDSIGHT_API_TOKEN. none
applyMode "all" applies defaults to every agent; "opt-in" only enables agents with explicit hindsight config. "all"
debug Enable debug logging. Can also use HINDSIGHT_DEBUG. false
defaults Agent Hindsight defaults shared by all enabled agents. built-in defaults

If enabled is false, the plugin returns no hooks. If no Hindsight API URL is configured, it logs an error and returns no hooks so opencode can continue.

Agent Hindsight Configuration

Agent settings live under each agent's options.hindsight field:

{
  "agent": {
    "build": {
      "options": {
        "hindsight": {
          "autoRetainBank": "build-session-memory",
          "retainBanks": ["build-session-memory", "implementation-notes"],
          "autoRecallBanks": ["project-context", "implementation-notes"],
          "recallBanks": ["project-context", "implementation-notes"],
          "retainMode": "last-turn",
          "retainEveryNTurns": 2,
          "tags": ["source:opencode", "agent:build"],
          "autoRetainAsync": true,
          "autoRetainStrategy": "conversation",
          "retainBankStrategies": {
            "implementation-notes": "manual-note"
          }
        }
      }
    },
    "review": {
      "options": {
        "hindsight": {
          "autoRecallBanks": ["project-context", "review-findings"],
          "recallBanks": ["project-context", "review-findings"],
          "retainBanks": []
        }
      }
    },
    "plan": {
      "options": {
        "hindsight": {
          "enabled": false
        }
      }
    }
  }
}

Agent Fields

Field Type Default Description
enabled boolean true Per-agent opt-out. false disables all Hindsight behavior for that agent.
autoRetainBank string omitted Bank used for automatic transcript retention.
retainBanks string[] [] Banks allowed for the manual hindsight_retain tool.
autoRecallBanks string[] [] Banks queried automatically at session start and compaction.
recallBanks string[] [] Banks allowed for manual hindsight_recall and hindsight_reflect.
retainMode "full-session" | "last-turn" "full-session" Transcript scope used for idle auto-retain.
retainEveryNTurns number 3 User-turn interval for idle auto-retain. Minimum is 1.
tags string[] [] Tags attached to all retain calls for this agent. User config only — not exposed as a tool argument.
autoRetainAsync boolean true Whether automatic retain uses async processing. Set false for synchronous auto-retain.
autoRetainStrategy string omitted Hindsight retain strategy for automatic retain calls. Must exist in Hindsight bank config.
manualRetain.bank string omitted Target Hindsight bank for the /hindsight-retain TUI command. Required for manual TUI retain.
manualRetain.async boolean true Whether manual TUI retain uses async processing.
manualRetain.strategy string omitted Hindsight retain strategy for manual TUI retain. Independent from autoRetainStrategy and retainBankStrategies.
manualRetain.tags string[] [] Tags attached to manual TUI retain calls. Independent from top-level tags.
retainBankStrategies Record<string, string> {} Maps manual retain bank IDs to Hindsight strategy names. Keys must match retainBanks entries exactly.
sessionStartMentalModel string | null undefined Hindsight mental model ID to fetch at root session start instead of performing generic recall. The same ID is fetched from every configured autoRecallBanks bank. Use null to explicitly clear an inherited plugin default.
sessionStartRecallPrompt string | null undefined Custom query string for root session-start recall when no mental model is configured. Use null to explicitly clear an inherited plugin default.

Bank names are passed through exactly as configured. Empty and whitespace-only bank names are ignored; duplicate entries are de-duplicated while preserving order.

Agent-level values replace plugin-level defaults using a shallow override model. For example, a per-agent tags array replaces default tags instead of merging with them.

YAML frontmatter uses the same field names:

hindsight:
  autoRetainBank: tester-memory
  retainBanks:
    - tester-memory
    - technical
  tags:
    - source:opencode
    - agent:tester
  autoRetainAsync: false
  autoRetainStrategy: conversation
  manualRetain:
    bank: tester-memory
    async: false
    strategy: conversation
    tags:
      - source:opencode
      - trigger:manual
      - agent:tester
  retainBankStrategies:
    technical: technical-note

Apply Modes

applyMode: "all"

Every agent receives the plugin defaults unless it opts out with:

{
  "options": {
    "hindsight": {
      "enabled": false
    }
  }
}

applyMode: "opt-in"

Agents with explicit options.hindsight configuration receive Hindsight behavior. If plugin-level defaults configure any banks, those defaults also apply to agents without options.hindsight; otherwise, unconfigured agents are skipped.

Automatic Recall

For root sessions, the plugin marks a session for recall when the session.created event arrives and the agent has non-empty autoRecallBanks. On the next experimental.chat.system.transform hook, each auto-recall bank is queried with this fixed query:

Relevant project context, user preferences, and recent work for this agent.

Successful recall results are appended to the system prompt in a <hindsight_memories> block with bank labels and an ISO timestamp. Existing system prompt entries are preserved.

If every bank query fails, the session remains marked for recall so the plugin can retry on the next system transform. If at least one bank succeeds but no memories are returned, the recall marker is consumed and no memory block is injected.

Session-Start Context Configuration

You can customize root session-start context injection with a Hindsight mental model ID or a custom recall query. These fields can be set as plugin-level defaults and overridden per agent.

Precedence rules:

  1. If sessionStartMentalModel is configured, the plugin fetches that mental model ID from each autoRecallBanks bank and injects the content. recall() is not called.
  2. If only sessionStartRecallPrompt is configured, the plugin calls recall() with that custom query instead of the built-in default.
  3. If neither is configured, the plugin uses the built-in default recall query shown above.

Fallback behavior:

  • If all mental model fetches fail, including 404/not-found responses, the plugin falls back to the built-in default recall query. It does not use the custom prompt for this fallback, even when sessionStartRecallPrompt is also configured.
  • If mental model fetches succeed but return empty content, the plugin warns and injects nothing. It does not fall back to recall.

Plugin-level default mental model:

{
  "plugin": [
    ["@toady00/opencode-hindsight", {
      "hindsightApiUrl": "http://localhost:8888",
      "defaults": {
        "autoRecallBanks": ["project-memory"],
        "sessionStartMentalModel": "project-architecture"
      }
    }]
  ]
}

Per-agent mental model override:

{
  "agent": {
    "build": {
      "options": {
        "hindsight": {
          "autoRecallBanks": ["project-memory", "build-memory"],
          "sessionStartMentalModel": "build-agent-context"
        }
      }
    }
  }
}

Per-agent custom recall prompt, clearing an inherited mental model:

{
  "agent": {
    "review": {
      "options": {
        "hindsight": {
          "autoRecallBanks": ["project-memory"],
          "sessionStartMentalModel": null,
          "sessionStartRecallPrompt": "Relevant code review preferences, recurring review findings, project risk areas, and recent review context."
        }
      }
    }
  }
}

YAML frontmatter mental model:

hindsight:
  autoRecallBanks:
    - project-memory
  sessionStartMentalModel: project-architecture

YAML frontmatter custom recall prompt:

hindsight:
  autoRecallBanks:
    - project-memory
  sessionStartRecallPrompt: Relevant testing conventions, flaky tests, and recent QA context for this repository.

YAML frontmatter clearing an inherited mental model:

hindsight:
  sessionStartMentalModel: null
  sessionStartRecallPrompt: Relevant code review context.

Validation and limitations:

  • sessionStartMentalModel expects a mental model ID, not the display name.
  • Empty strings and whitespace-only values are ignored with warnings.
  • Invalid per-agent values, such as non-string non-null values, fall back to valid plugin defaults.
  • null explicitly clears an inherited plugin default without a warning.
  • The same mental model ID is fetched from every configured autoRecallBanks bank.
  • Per-bank mental model mapping, where different banks use different mental model IDs, is not yet supported and is planned for a future release.

Automatic Retention

Automatic retention runs on session.status events where status.type === "idle". The plugin also accepts the deprecated session.idle event for compatibility with older event producers.

Auto-retain only runs for root sessions. Child sessions are skipped for automatic retention.

retainMode: "full-session"

The plugin fetches all session messages, formats them as a transcript, strips any previously injected Hindsight memory blocks, and retains the transcript to autoRetainBank using the session ID as the document ID. Repeated retains overwrite the same session document.

retainMode: "last-turn"

The plugin extracts the last retainEveryNTurns user turns and their assistant responses, formats that window as a transcript, and retains it as a new unique document.

Compaction

Before compaction, the plugin always attempts to retain the full transcript to autoRetainBank using the session ID as the document ID. This bypasses normal turn throttling and retainMode. It then attempts compaction recall and appends any recalled memory block to the compaction context.

Async retain, strategies, and tags

Automatic retention uses Hindsight async processing by default (autoRetainAsync: true). Set autoRetainAsync: false when the automatic retain call must wait for Hindsight to finish processing before the plugin treats the retain as successful. The plugin submits async retain operations but does not poll them or report later async failures.

autoRetainStrategy applies only to automatic retain calls. Strategy names must already exist in Hindsight bank configuration; this plugin only passes the configured strategy name through to Hindsight.

Configured tags are attached to retain calls only. Recall and reflect tag filtering is out of scope for this plugin.

Manual Tools

Configured agents receive these tools:

hindsight_retain

Stores information in a configured retain bank.

Parameters:

  • content — required; cannot be empty.
  • bank — required at execution time; must be in retainBanks.
  • context — optional first-class Hindsight retain context.
  • async — optional boolean; whether to process asynchronously. Defaults to true.

strategy and tags are not tool arguments. They are controlled by user configuration: retainBankStrategies maps manual retain bank IDs to strategy names, and tags applies configured tags to retain calls.

Example request:

{
  "content": "The project uses Bun and tsup for building the plugin.",
  "bank": "implementation-notes",
  "context": "Repository setup decision",
  "async": false
}

hindsight_recall

Searches a configured recall bank and returns matching memories.

Parameters:

  • query — required; cannot be empty.
  • bank — required at execution time; must be in recallBanks.

hindsight_reflect

Synthesizes an answer from a configured recall bank.

Parameters:

  • query — required; cannot be empty.
  • bank — required at execution time; must be in recallBanks.
  • context — optional additional context for reflection.

Manual tools can be used in child sessions if the child agent has resolved Hindsight configuration. There is no child-session restriction on manual tools.

Development

Install dependencies:

bun install

Build the ESM bundle and declarations:

bun run build

Run tests:

bun run test

Watch build output during development:

bun run dev

Issue Tracking

This project uses bd for issue tracking. After cloning the repository or creating a new worktree, run this from the worktree root:

bd bootstrap

Inspiration

This project uses the official Hindsight opencode plugin as a reference point for the integration pattern while extending the configuration model for richer per-agent and multi-bank workflows.

About

Hindsight Plugin for OpenCode

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors