Skip to content

[FEATURE]: slash command for reload #6719

Closed

Description

@wojons

Feature hasn't been suggested before.

  • I have verified this feature I'm about to request hasn't been suggested before.

Describe the enhancement you want to request

A /reload that reloads config files like opencode.jsonc of global and project level and also .opencode/ this way without having to close and open the tui just able to reload easily could be even better done when a /compact is runnning

Activity

  1. added
    discussionUsed for feature requests, proposals, ideas, etc. Open discussion
    on Jan 3, 2026
  2. github-actions commented on Jan 3, 2026

    @github-actions
    Contributor

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

    Feel free to ignore if this doesn't address your specific case about reloading all config files (opencode.jsonc, .opencode/, etc) in one command.

  3. JosXa commented on Jan 17, 2026

    @JosXa
    Contributor

    Are there technical hurdles to this?

  4. JosXa commented on Jan 18, 2026

    @JosXa
    Contributor

    This is what plan mode came back with:


    Analysis Summary

    The Issue

    GitHub Issue #6719 requests a /reload slash command that reloads the entire config (both global and project-level opencode.jsonc files and the .opencode/ directory) without having to restart the TUI.

    Current Architecture

    The codebase already has the core reload mechanism in place:

    1. Worker-side reload (packages/opencode/src/cli/cmd/tui/worker.ts line 133-136):

      async reload() {
        Config.global.reset()
        await Instance.disposeAll()
      }
    2. SIGUSR2 signal handler (packages/opencode/src/cli/cmd/tui/thread.ts line 108-110):

      process.on("SIGUSR2", async () => {
        await client.call("reload", undefined)
      })
    3. Config lazy loading (Config.global uses lazy() which can be .reset() to force re-evaluation)

    4. Instance state disposal (Instance.disposeAll() clears all cached instance state, forcing Config, Commands, Agents, MCP, etc. to reload)

    5. Slash commands are registered via command.register() in the TUI with a slash: { name, aliases } property

    What's Missing

    Currently, there's no way for users to trigger a reload from within the TUI - the only way is to send a SIGUSR2 signal from outside. The feature request asks for a /reload slash command exposed to users.


    Implementation Plan

    Approach A: TUI-Only Implementation (Simpler)

    Since the worker already has an RPC reload() method, and the TUI already uses RPC for other operations, we can add a /reload slash command that calls the worker's reload method directly.

    Files to Modify:

    1. packages/opencode/src/cli/cmd/tui/app.tsx

      • Add a new command registration for /reload
      • The command would:
        1. Call worker's reload via RPC (through SDK or direct worker call)
        2. Wait for reload to complete
        3. Trigger a sync refresh to reload all data from the server
        4. Show a toast notification confirming reload
    2. Potentially expose RPC reload to TUI context

      • The thread.ts sets up the RPC client, but it's not directly accessible in the TUI components
      • May need to pass a reload function through context or add an SDK endpoint

    Key Decision Point:

    The current architecture uses SDK (HTTP) for most TUI<->Server communication, but reload is only exposed via direct RPC. We have two sub-options:

    A1. Add reload to SDK/Server API (Recommended)

    • Add a POST /config/reload endpoint to ConfigRoutes
    • Update SDK generation
    • Call via SDK in TUI

    A2. Pass RPC reload through context

    • Modify the TUI provider chain to pass a reload callback
    • More invasive changes to the component tree

    Recommended Approach: A1 (Add Server Endpoint)

    This follows the existing patterns and is cleaner.

    Implementation Steps:

    1. Add Server Endpoint (packages/opencode/src/server/routes/config.ts)

      .post(
        "/reload",
        describeRoute({
          summary: "Reload configuration",
          description: "Reload all configuration files...",
          operationId: "config.reload",
          responses: { 200: ... },
        }),
        async (c) => {
          Config.global.reset()
          await Instance.dispose()  // Just current instance, not all
          return c.json({ success: true })
        },
      )
    2. Regenerate SDK (run ./packages/sdk/js/script/build.ts)

    3. Add TUI Slash Command (packages/opencode/src/cli/cmd/tui/app.tsx)

      • Register a new command with slash: { name: "reload" }
      • Call sdk.client.config.reload()
      • Trigger sync.refresh() to re-fetch all data
      • Show toast on success
    4. Add Web App Slash Command (packages/app/src/pages/session.tsx)

      • Same pattern as TUI
    5. Handle MCP Reconnection (if needed)

      • MCP servers may need special handling during reload
      • Check if Instance.dispose() properly handles MCP cleanup

    Considerations:

    • Event stream: After reload, the event stream may need to be restarted (already handled in worker.ts via startEventStream)
    • Active sessions: Should warn if a session is running, or gracefully handle in-progress operations
    • Provider reconnection: Provider state may need refresh after config reload

    Questions

    1. Scope: Should /reload also restart MCP servers that may have changed config? Or just reload config values?

    2. Session behavior: If there's an active chat session, should reload:

      • Cancel/abort it first?
      • Queue reload for after completion?
      • Reload anyway (might cause issues if agent/model config changed)?
    3. Web app: Should this also be implemented in the web app (packages/app), or just TUI for now?

    4. Confirmation: Should there be a confirmation dialog, or just execute immediately with a toast notification?

  5. JosXa commented on Jan 18, 2026

    @JosXa
    Contributor

    @opencode-agent

    1. Are there any potential unintended side-effects or configuration files that get loaded on startup but we're missing in this approach? Please thoroughly check the codebase for all file read operations again.
    2. Are there any code paths that rely on configuration being available at startup, or modules that run only once after configuration loading has concluded? We must ensure that all configurations are properly reloaded.
  6. JosXa commented on Jan 18, 2026

    @JosXa
    Contributor

    Great questions! I dug deeper into the codebase to answer them:

    1. What components use Instance.state() and will reload on dispose?

    Here's the complete list of modules that use Instance.state() and will be re-initialized after Instance.dispose():

    Module State Purpose
    Config.state Project-level config (merges global + project opencode.json)
    Agent.state Agent definitions (built-in + user-defined from config)
    MCP.state MCP client connections and status
    Command.state Slash commands (built-in + .opencode/ commands)
    Skill.state Skill definitions
    Provider.state Provider configuration and auth
    Provider.auth.state Provider authentication tokens
    Bus.state Event bus subscriptions
    Permission.state Permission rules
    PermissionNext.state New permission system state
    LSP.state Language server connections
    Format.state Code formatters
    File.state File indexing/caching
    FileWatcher.state File system watchers
    FileTime.state File modification times
    Pty.state PTY sessions
    Vcs.state Git/VCS info
    Tool.registry.state Tool registry
    Question.state Question tool state
    Plugin.state Plugin registry
    Env.state Environment variables
    Session.status.state Session status tracking
    Session.prompt.state Prompt state

    The MCP module has a proper dispose function that closes all client connections:

    async (state) => {
      await Promise.all(
        Object.values(state.clients).map((client) =>
          client.close().catch(...)
        ),
      )
    }

    2. Global lazy values (reset via Config.global.reset())

    These use lazy() directly (not Instance.state) and are reset by Config.global.reset():

    Module Purpose
    Config.global Global config file (~/.config/opencode/opencode.json)
    Shell.preferred Preferred shell detection
    Shell.acceptable Acceptable shells list
    Server.App Hono app instance (routes)
    Various route modules Lazy route definitions

    3. Bootstrap functions (one-time init)

    The InstanceBootstrap() function in packages/opencode/src/project/bootstrap.ts runs once per instance creation:

    export async function InstanceBootstrap() {
      await Plugin.init()
      Share.init()
      ShareNext.init()
      Format.init()
      await LSP.init()
      FileWatcher.init()
      File.init()
      Vcs.init()
      // Also sets up Bus subscription for Command.Event.Executed
    }

    These init() functions typically just call the state accessor to trigger lazy initialization, so they'll work correctly on reload since the state is disposed first.

    4. Potential gotchas for reload

    Things that should work:

    • Config changes (global + project level)
    • MCP server changes (has proper dispose/reconnect)
    • Agent definitions
    • Command/skill changes in .opencode/
    • Provider configuration

    Things to verify:

    • Event stream: The worker's event stream (startEventStream) uses a fixed directory parameter set at startup. After Instance.dispose(), the same event stream continues - may need to restart it with the new instance context.
    • LSP connections: LSP servers get closed on dispose but may need manual restart notification
    • Active sessions: If a session is running when reload happens, it could cause issues since the agent/model config may change mid-conversation

    Recommendation

    The existing rpc.reload() implementation looks solid:

    async reload() {
      Config.global.reset()
      await Instance.disposeAll()
    }

    This should handle most cases. The main addition needed is:

    1. A way to trigger this from the TUI (the /reload slash command)
    2. Possibly restart the event stream after reload
    3. Show feedback to the user (toast notification)
    4. Optional: warn if a session is actively running

    Would you like me to start implementing this?

  7. JosXa commented on Jan 21, 2026

    @JosXa
    Contributor

    Research Summary: Plugin Reload Strategy

    Great question! I've done a deep dive into the plugin system architecture to understand how /reload should handle custom plugins. Here's what I found:

    Current Plugin Architecture

    Plugins in OpenCode are loaded through a stateful initialization pattern using Instance.state():

    1. Plugin Loading (packages/opencode/src/plugin/index.ts:15-96):

      • Plugins are async functions that return a Hooks object
      • Each plugin is initialized once during instance creation and stored in memory
      • The initialization creates event subscriptions, tool registrations, and hook implementations
    2. No Lifecycle Hooks:

      • Plugins do not have dispose/cleanup/shutdown hooks - I checked the plugin interface thoroughly
      • The Hooks interface only defines event handlers and lifecycle hooks for OpenCode events, not plugin lifecycle
      • Plugins can maintain internal state, subscribe to events, and register tools, but there's no standard way to tear them down
    3. Existing Reload Mechanism (packages/opencode/src/cli/cmd/tui/worker.ts:133-136):

      async reload() {
        Config.global.reset()
        await Instance.disposeAll()
      }

      This completely disposes all instances, which triggers the State.dispose() mechanism that clears all cached state, including plugins.

    Answer: Complete Shutdown & Reload (Preferred)

    Plugins will be completely shut down and force-reloaded - no extra effort needed from maintainers!

    Here's why this is the preferred approach:

    ✅ Already Implemented: The existing reload() mechanism in worker.ts calls Instance.disposeAll(), which:

    • Clears all state caches via State.dispose()
    • Deletes the instance cache in Instance.ts
    • Triggers cleanup of all plugin state

    ✅ Clean Slate: When the next request comes in after reload:

    • Instance.provide() creates a fresh instance
    • Plugins are re-imported and re-initialized from scratch
    • All hooks and event subscriptions are recreated
    • Config files (global & project) are re-read

    ✅ No Plugin Developer Burden:

    • Plugin authors don't need to implement special reload hooks
    • The plugin interface stays simple - just return hooks from an async function
    • State management is handled by OpenCode's instance lifecycle

    How It Works

    1. User runs /reload
    2. Config.global.reset() clears cached config
    3. Instance.disposeAll() tears down all instances and their plugin state
    4. Next operation triggers Instance.provide() which:
      • Reads fresh config files
      • Re-installs/re-imports plugins
      • Re-initializes all plugin hooks
      • Rebuilds event subscriptions

    Potential Gotcha: Plugin Dependencies

    One thing to watch: if plugins have external resources (database connections, file watchers, network connections), they might leak since there's no explicit disposal hook. However:

    • Most plugins use the SDK client or Bun shell APIs which are scoped to the instance
    • Event subscriptions are cleared when instances dispose
    • Well-behaved plugins should use instance-scoped resources

    Recommendation

    The current approach is solid. Plugins get completely shut down and reloaded - no custom hooks needed. This keeps the plugin API simple and guarantees a clean reload without requiring plugin maintainers to implement special lifecycle methods.

    If we find specific plugins that need cleanup (rare), we could add an optional dispose hook to the plugin interface later, but it's not necessary for the /reload command to work correctly.

  8. JosXa commented on Jan 21, 2026

    @JosXa
    Contributor

    yo opencode, sounds good. I think we have all the infos we need. Adding a /reload plugin seems really straightforward from what we gathered, no particularly concerning edge cases. In particular, you told me that also users' custom plugins can get completely restarted automatically. Please implement it as a pull request against the dev branch. Please check the existing unit tests and see if the existing reload mechanism is already covered. If it is not, I think we best just build an integration/system test for the new /reload command using one of the existing pseudo-terminal tests as boilerplate.

  9. JosXa commented on Jan 21, 2026

    @JosXa
    Contributor

    yo opencode, sounds good. I think we have all the infos we need. Adding a /reload plugin seems really straightforward from what we gathered, no particularly concerning edge cases. Please implement it as a pull request against the dev branch. Please check the existing unit tests and see if the existing reload mechanism is already covered. If it is not, I think we best just build an integration/system test for the new /reload command using one of the existing pseudo-terminal tests as boilerplate.

    Summary

    I've implemented the /reload slash command that allows reloading configuration files without restarting the TUI.

    Changes

    • packages/opencode/src/server/routes/config.ts - Added POST /config/reload endpoint that calls Config.global.reset() and Instance.disposeAll() to reload all configurations
    • packages/opencode/src/command/index.ts - Added RELOAD: "reload" to builtin commands
    • packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx - Added special handling for /reload to call the config reload endpoint with toast notifications
    • packages/sdk/js/src/v2/gen/sdk.gen.ts - Added reload() method to the SDK Config class
    • packages/opencode/test/server/config-reload.test.ts - Added integration tests for the reload endpoint

    Testing

    Checked existing tests - no prior tests for the reload mechanism existed. Added integration tests for the new /config/reload endpoint that verify the endpoint exists and returns { success: true }.

    Pull Request

    Created PR #9871: feat: add /reload slash command

  10. 2 remaining items

  11. JosXa commented on Feb 8, 2026

    @JosXa
    Contributor

    any updates on this?

    Awaiting review #9871

  12. Femumme commented on Apr 6, 2026

    @Femumme

    This would solve a real workflow gap for me.

    I added a local profile switcher that rewrites agent model assignments in ~/.config/opencode/opencode.json (for example switching thinker/implementer/light agent groups between different models). The config file updates correctly, but the running OpenCode server keeps using the old cached models until restart.

    I also tried the undocumented signal-based workaround and, in my setup, sending SIGUSR2 to the running app/server just killed it instead of giving me a usable reload flow.

    A supported /reload that re-reads global/project config and invalidates cached agent/config state would make model/profile switching usable without restarting the app.

  13. JosXa commented on Apr 6, 2026

    @JosXa
    Contributor

    This would solve a real workflow gap for me.

    I added a local profile switcher that rewrites agent model assignments in ~/.config/opencode/opencode.json (for example switching thinker/implementer/light agent groups between different models). The config file updates correctly, but the running OpenCode server keeps using the old cached models until restart.

    I also tried the undocumented signal-based workaround and, in my setup, sending SIGUSR2 to the running app/server just killed it instead of giving me a usable reload flow.

    A supported /reload that re-reads global/project config and invalidates cached agent/config state would make model/profile switching usable without restarting the app.

    Yeah, exactly - there are countless use cases where you wanna continue in the same instance while playing with the config

  14. removed
    discussionUsed for feature requests, proposals, ideas, etc. Open discussion
    on May 3, 2026
  15. AceCodePt commented on May 5, 2026

    @AceCodePt

    Big plus! Please merge it!

  16. maxylev commented on May 7, 2026

    @maxylev

    The subagent from /agents/tester.md has reached its token limit, so I'm changing the model name to continue working in the current session. How do I apply the changes? - /reload

  17. repomaa commented on Jun 15, 2026

    @repomaa

    +1! Would be great for having opencode develop tools. I'd actually love to have this available as a tool for an agent to use.

    1. Write tool
    2. Reload
    3. Test
    4. Refactor
    5. Repeat
  18. rekram1-node commented on Oct 1, 2026

    @rekram1-node
    Collaborator

    https://opencode.ai/v2/docs

    Opencode v2 has hot reloading and u can manually reload it w/ reload

    Image
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