CtrlK
BlogDocsLog inGet started
Tessl Logo

pantheon-ai/opencode-toolkit

Complete toolkit for configuring and extending OpenCode: agent creation, custom slash commands, configuration management, plugin development, and SDK usage.

98

Quality

98%

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Advisory

Suggest reviewing before use

Overview
Quality
Evals
Security
Files

toast-notifications.mdbuild-plugins/references/

Toast Notifications

Reference for showing toast notifications in OpenCode TUI

overview

Plugins can display toast notifications - temporary popup messages that appear in the TUI corner. These are ideal for brief status updates, confirmations, warnings, or alerts that don't need to persist in the chat.

guidelines

When to Use

Use toasts for:

  • Success confirmations ("Settings saved", "File exported")
  • Configuration errors or warnings
  • Model/provider fallback notices
  • Brief status updates
  • Non-critical alerts

SHOULD NOT use for:

  • Detailed information (use inline messages instead - see ui-feedback.md)
  • Persistent status that user needs to reference later
  • High-frequency updates (will spam the user)

api_reference

The API

SDK Method

await client.tui.showToast({
  body: {
    title: "Optional Title", // Optional heading
    message: "Toast message", // Required message text
    variant: "success", // "info" | "success" | "warning" | "error"
    duration: 5000, // Optional: milliseconds
  },
})

Parameters

ParameterTypeRequiredDescription
titlestringNoOptional heading for the toast
messagestringYesThe main message content
variant"info" | "success" | "warning" | "error"YesVisual style and icon
durationnumberNoAuto-dismiss time in milliseconds

Variants

VariantUse CaseVisual
infoNeutral information, fallback noticesBlue/neutral styling
successSuccessful operationsGreen styling with checkmark
warningConfiguration issues, caution noticesYellow/orange styling
errorFailures or critical problemsRed styling

examples

Complete Example

import type { Plugin } from "@opencode-ai/plugin"

export const ToastPlugin: Plugin = async ({ client }) => {
  return {
    event: async ({ event }) => {
      if (event.type === "session.idle") {
        try {
          await client.tui.showToast({
            body: {
              title: "Session Complete",
              message: "All tasks finished successfully",
              variant: "success",
              duration: 4000,
            },
          })
        } catch {
          // Ignore toast errors - TUI may not be available
        }
      }
    },
  }
}

Error Handling

MUST wrap toast calls in try/catch - the TUI MAY not be available (e.g., in headless mode):

async function showToast(
  client: any,
  message: string,
  variant: "info" | "success" | "warning" | "error" = "info",
  title?: string,
  duration?: number,
): Promise<void> {
  try {
    await client.tui.showToast({
      body: {
        title,
        message,
        variant,
        duration,
      },
    })
  } catch {
    // Ignore - TUI may not be available
  }
}

patterns

Practical Patterns

Delayed Toast (Avoid Blocking Init)

When showing toasts during plugin initialization, SHOULD use setTimeout to avoid blocking:

export const ConfigPlugin: Plugin = async ({ client }) => {
  const config = loadConfig()

  if (config.hasErrors) {
    // Delay toast to avoid blocking plugin init
    setTimeout(async () => {
      try {
        await client.tui.showToast({
          body: {
            title: "Plugin: Invalid config",
            message: `${config.path}\n${config.errorMessage}\nUsing default values`,
            variant: "warning",
            duration: 7000,
          },
        })
      } catch {}
    }, 7000) // Delay allows TUI to fully initialize
  }

  return {
    // ... hooks
  }
}

Multi-line Messages

Use \n for line breaks in toast messages:

await client.tui.showToast({
  body: {
    title: "Model Fallback",
    message: `anthropic/claude-3-opus failed\nUsing openai/gpt-4 instead`,
    variant: "info",
    duration: 5000,
  },
})

Notification on Session Events

return {
  event: async ({ event }) => {
    switch (event.type) {
      case "session.idle":
        try {
          await client.tui.showToast({
            body: {
              message: "Session completed",
              variant: "success",
            },
          })
        } catch {}
        break

      case "session.error":
        try {
          await client.tui.showToast({
            body: {
              title: "Error",
              message: "Session encountered an error",
              variant: "error",
            },
          })
        } catch {}
        break
    }
  },
}

Configuration Validation Warnings

function showConfigWarning(client: any, configPath: string, errors: string[]): void {
  const message = [configPath, ...errors.slice(0, 2), errors.length > 2 ? `(+${errors.length - 2} more errors)` : ""]
    .filter(Boolean)
    .join("\n")

  setTimeout(async () => {
    try {
      await client.tui.showToast({
        body: {
          title: "MyPlugin: Invalid config",
          message,
          variant: "warning",
          duration: 7000,
        },
      })
    } catch {}
  }, 7000)
}

Model/Provider Fallback Notice

return {
  "chat.params": async (input, output) => {
    const preferredModel = getPreferredModel()
    const actualModel = input.model

    if (preferredModel && actualModel.id !== preferredModel.id) {
      try {
        await client.tui.showToast({
          body: {
            title: "Model Fallback",
            message: `${preferredModel.provider}/${preferredModel.id} unavailable\nUsing ${actualModel.providerID}/${actualModel.id}`,
            variant: "info",
            duration: 5000,
          },
        })
      } catch {}
    }
  },
}

comparison

Toast vs Inline Messages

AspectToastInline Message
VisibilityTemporary popup cornerPersistent in chat
DurationAuto-dismissesStays until scrolled away
Detail levelBrief (1-3 lines)Can be multi-line
HistoryNot savedVisible in session
Use caseQuick alerts, warningsDetailed status with data

Use toasts for ephemeral alerts and warnings. Use inline messages (see ui-feedback.md) for detailed status that users might want to reference.

constraints

Limitations

LimitationDetails
No interactivityMUST NOT include buttons or inputs
Brief content onlySHOULD keep to 1-3 lines
No custom stylingLimited to predefined variants
TUI onlyWon't appear in web or headless mode
May fail silentlyMUST wrap in try/catch
Rate limitingSHOULD avoid rapid-fire toasts

build-plugins

SKILL.md

tile.json

tile.json