Skip to content

[FEATURE]: Native StatusLine Hook for Plugins (Context-Free Display) #8619

Closed as not planned

Description

@keybrdist

Feature Request: Native StatusLine Hook for Plugins

Problem

Plugins that want to display persistent contextual information (timestamps, git status, session metrics) must inject text into message parts. This causes all injected content to become part of the conversation context sent to the LLM.

For a statusline that displays on every message:

  • ~30 tokens consumed per message
  • 100-message session = ~3,000 tokens wasted on display-only content
  • Reduces effective context window

Attempted Workarounds

We tried using the ignored: true flag on text parts:

Approach Result
ignored: true without IDs Validation error (missing id, sessionID, messageID)
ignored: true with proper IDs Part displays, but user's message text disappears

The ignored flag hides content from both UI and context. There's no "display-only" option.

Proposed Solution

Add a statusLine hook for plugins, similar to Claude Code's implementation:

// Plugin hook
"tui.statusLine"?: (input: StatusLineInput) => Promise<{ text: string }>;

Or a config-based approach:

{
  "statusLine": {
    "type": "command",
    "command": "~/.config/opencode/statusline.sh"
  }
}

Input Data

Provide rich session context:

{
  "session_id": "abc123",
  "model": { "id": "claude-sonnet-4-20250514", "display_name": "Sonnet" },
  "workspace": { "current_dir": "/path/to/project" },
  "cost": { "total_cost_usd": 0.0234 },
  "context_window": {
    "context_window_size": 200000,
    "current_usage": { "input_tokens": 8500, "output_tokens": 1200 }
  }
}

UI Placement

Persistent bar in the TUI (not part of conversation):

┌─────────────────────────────────────────────────┐
│  [conversation content]                         │
│  > prompt input                                 │
├─────────────────────────────────────────────────┤
│  🕐 23:28 │ ⎇ main │ Sonnet │ 45% │ $0.02      │
└─────────────────────────────────────────────────┘

Benefits

  1. Zero context cost - Display-only content doesn't consume tokens
  2. Rich session data - Plugins can show cost, context %, model info
  3. Parity with Claude Code - statusLine docs

Related Issues

Reference

Activity

  1. added
    opentuiThis relates to changes in v1.0, now that opencode uses opentui
    on Jan 15, 2026
  2. github-actions commented on Jan 15, 2026

    @github-actions
    Contributor

    This issue might be a duplicate of existing issues. Please check:

    Feel free to ignore if none of these address your specific case.

  3. slkiser commented on Jan 19, 2026

    @slkiser

    A current work around is using the Toasts.

  4. TheHamkerCat commented on Jan 31, 2026

    @TheHamkerCat

    @slkiser what did you mean by Toasts? can you point to some resource, i didn't find it in https://opencode.ai/config.json

  5. slkiser commented on Feb 4, 2026

    @slkiser

    @TheHamkerCat “Toasts” are a way to show UI-only text without adding it to the chat/context.

    In a Opencode plugin, call the TUI toast api with something like:

    await client.tui.showToast({
      body: { message: "…status…", variant: "info", duration: 9000 }
    })
    

    You can trigger it on events (idle/tool-finish/compact) or a slash command.

    It’s not persistent like a statusline, but it a good workaround.

    I use it in Opencode Quota to show token usage and quota for different providers.

  6. TheHamkerCat commented on Feb 5, 2026

    @TheHamkerCat

    @slkiser Thanks, I think i can live with calling quota API every few minutes and showing a toast, for now

  7. guyposka commented on Feb 8, 2026

    @guyposka

    +1 from practical usage. I implemented a local plugin workaround and confirmed the gap is specifically a native, single-line status surface in TUI.

    Current behavior/workarounds:

    • tui.showToast works but always renders with padded multi-line toast UI (not a true statusline).
    • Injecting message parts adds context/token overhead.
    • Setting terminal title works as a one-line hack, but it replaces window title semantics.

    Feature request (concrete API + UX):

    1. Add a plugin hook for statusline rendering (UI-only, zero context cost), eg:
      • tui.statusline.render -> returns a string (or segmented parts)
    2. Render it in a dedicated persistent one-line status bar (no toast box/padding)
    3. Trigger refresh on relevant events:
      • message.updated
      • session.status
      • session.updated
    4. Provide width-aware truncation/ellipsis in TUI
    5. Add graceful fallback when plugin hook fails (keep last value or empty line)

    Nice-to-have:

    • Optional left/right segments so users can show model/context on left and cost/git/status on right.

    This would cover the exact use case that Claude Code's statusline solves, while staying context-free and plugin-driven.

  8. dibstern-work commented on Feb 16, 2026

    @dibstern-work

    #8619 (comment)

    @Punchy25 I second this, and I'd add another nice-to-have: allow multi-line status bars

  9. slkiser commented on Feb 16, 2026

    @slkiser

    Current behavior/workarounds:

    • tui.showToast works but always renders with padded multi-line toast UI (not a true statusline).
    • Injecting message parts adds context/token overhead.
    • Setting terminal title works as a one-line hack, but it replaces window title semantics.

    This is misleading, since you can inject messages WITHOUT adding context/token overhead, see the plugin opencode-quota.

    In short you have to add two things when injecting into the session transcript :

    1. Display-only output with client.session.prompt({ noReply: true, parts: [...] }) so OpenCode shows it without triggering an LLM response.
    2. Marks injected parts as ignored: true so they’re excluded from future prompt context (no token overhead).
  10. diegomarino commented on Feb 16, 2026

    @diegomarino

    I opened a PR for this: #13885

    It implements a template-based status line system that resolves the core problem — zero-token display of session/project data in the TUI. Users define template strings in config, resolved server-side from built-in variables + shell commands + plugin-provided variables.

    "tui": {
      "status_line": {
        "templates": {
          "terminal_title": "{project_name} ({shell:branch}) [{model_id}]",
          "session_footer": "{total_tokens:k} tok | ${total_cost} | ctx {context_used_pct:bar10} {context_used_pct}%",
          "home_footer": "{cwd:basename} on {shell:branch}"
        },
        "interval": 5,
        "commands": {
          "branch": "git branch --show-current",
          "dirty": "git diff-index --quiet HEAD -- 2>/dev/null && echo '' || echo '*'"
        }
      }
    }

    Out of PR scope:

    The visual layout discussion that @Punchy25 and @davidsr2r raised — left/right alignment, multi-line bars, width-aware truncation, segmented rendering. The PR focuses on the data layer: what content is available and how to compose it into strings. The rendering is intentionally simple (single resolved string per target) so that layout decisions can be made separately without being coupled to the variable/template system.

    This means a future layout PR could consume the same resolved templates and add segment splitting, alignment, or multi-line rendering on top — without changing the config schema or resolver.

  11. FurryWolfX commented on Mar 14, 2026

    @FurryWolfX

    I would also like to display some custom status on the TUI, hoping to merge.

  12. removed
    opentuiThis relates to changes in v1.0, now that opencode uses opentui
    on May 3, 2026
  13. github-actions commented on Jul 6, 2026

    @github-actions
    Contributor

    To stay organized issues are automatically closed after 60 days of no activity. If the issue is still relevant please open a new one.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions