Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

opencode-move-session

A /move-session slash command for opencode that reassigns the current chat session to a different project directory — and cleans up after itself so the move leaves no trace in your conversation.

/move-session ~/Projects/myrepo
/move-session to my projects
/move-session here

What it does

opencode binds each session to a project (a .git ancestor + a row in opencode.db). When you start a chat in /tmp/scratch and want it to live in ~/Projects/myrepo, there's no built-in way to move it — the session list in ~/Projects/myrepo won't show it because the project_id/directory/path columns still point at /tmp/scratch.

This command:

  1. Resolves the target (path, ~/..., relative, or natural language like "my projects") via the LLM.
  2. Atomically rewrites project_id, directory, and path for the session and every nested subagent session via a recursive CTE.
  3. Reuses an existing project row if one already covers the target's git toplevel; otherwise leaves the session on global so opencode's own migrateGlobal logic adopts it the next time a TUI opens that path.
  4. Schedules a deferred chat cleanup so the next time opencode launches, the slash-command turn (4 messages: user → subtask call → synthetic continuation → build agent paraphrase) and the background subagent session are removed permanently.

You see the "Moved to ..." reply in the current session. Restart, open the session at the new place, and the move command itself is gone.

How it's wired together

File Role
plugins/session-env.js injects OPENCODE_SESSION_ID (and OPENCODE_PROJECT_ID, OPENCODE_WORKTREE, OPENCODE_DIRECTORY, OPENCODE_CALL_ID) into every shell command opencode spawns, via the shell.env plugin hook. This is the only deterministic way to identify the calling session from inside bash.
commands/move-session.md the /move-session slash command. Runs as agent: general (subtask) so its bash and the subagent's reply don't pollute the parent session. Looks up the user's session via parent_id of $OPENCODE_SESSION_ID.
plugins/move-session-auto-undo.js one-shot at opencode startup: reads ~/.local/share/opencode/move-session-pending.jsonl and removes each queued move turn (4 messages) plus its subagent session via direct bun:sqlite DELETE (FKs cascade). Skips reverting if you typed real messages after the move.

Install

One-liner

curl -fsSL https://raw.githubusercontent.com/moha-abdi/opencode-move-session/main/install.sh | bash

Manual

mkdir -p ~/.config/opencode/plugins ~/.config/opencode/commands
cp plugins/*.js   ~/.config/opencode/plugins/
cp commands/*.md  ~/.config/opencode/commands/

Then restart opencode so the plugins load.

Usage

/move-session <target>

<target> can be:

  • An absolute path: /Users/me/code/repo
  • A ~/... path: ~/Projects/foo
  • A relative path: ../sibling
  • A bare project name that matches a known opencode project's basename
  • A natural-language phrase: to my projects, current dir, home, the foo repo

The agent resolves the phrase, performs the DB move, and replies on one line. On the next opencode launch the move turn quietly disappears from the chat.

How determinism works

The trick is that opencode passes the calling session's id into the shell.env plugin hook (tool/shell.ts:411). Hooks run synchronously per tool call, so by the time the bash script runs, $OPENCODE_SESSION_ID is exactly the session whose tool call this is — never a guess based on "most recently updated". The slash command's own backtick template expansion (prompt.ts:1692) does not go through that hook, so the command instructs the LLM to do its work via the Bash tool, which does.

For determining the user's session (rather than the subagent's), the bash queries parent_id of $OPENCODE_SESSION_ID. When run as a subtask, that's the user's session; when not, it's null and we fall back to $OPENCODE_SESSION_ID itself.

Caveats

  • The bash script writes directly to ~/.local/share/opencode/opencode.db via sqlite3. opencode's WAL mode permits concurrent writers; the move uses BEGIN IMMEDIATE to serialize against itself. If opencode changes the schema (drizzle migrations), this command will need adjusting.
  • The plugin uses bun:sqlite (opencode is a Bun runtime). It runs once at startup; if you have multiple TUIs opening at the same time, they race-claim the queue file by truncating it — duplicate processing is idempotent (DELETE on a missing row is a no-op).
  • Existing TUI sessions cache their project assignment in memory. After a move you have to restart opencode (or switch sessions) for the live TUI to pick up the change.
  • The cleanup distinguishes synthetic vs. real user messages by checking the synthetic flag on each part. Anything you type after the move has no synthetic flag, so it's preserved.

Disable

To stop auto-cleaning the chat: rm ~/.config/opencode/plugins/move-session-auto-undo.js. The slash command itself will keep working; you'd just press <leader>u manually if you want the turn gone.

To remove entirely: delete the three installed files.

License

MIT — see LICENSE.

About

A /move-session slash command for opencode that reassigns a chat session to a different project directory and cleans up after itself.

Resources

Stars

3 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages