Skip to content
    ↑↓ select↵ openesc close
    English中文
    doomsday616

    Github Sync

    v3.0.1Git & VCS
    opencode-github-sync

    Sync your OpenCode config, skills, and selected sessions across machines via a private GitHub repo — as a plugin or a CLI.

    GitHub stars

    26

    +1 in 30 days

    Monthly installs

    317

    16 in 7 days

    Composite scoreSCORE

    48.0

    Multi-signal model

    Last commit

    22 days ago

    2026-07-29

    Install and configure

    opencode.json

    Writes to this project's opencode.json — applies to this repository only.

    opencode.json

    {
      "$schema": "https://opencode.ai/config.json",
      "plugin": ["opencode-github-sync@3.0.1"]
    }

    opencode loads npm dependencies through its embedded runtime on startup and caches them locally — no manual global install needed.

    opencode-github-sync

    npm CI license platform

    简体中文  ·  Quick start  ·  Overrides  ·  Sessions  ·  Commands


    You use OpenCode on more than one machine. Your config, agents, commands, skills and MCP servers live on whichever one you touched last.

    opencode-github-sync keeps them all in step through a private GitHub repository — as an OpenCode plugin, as a CLI, or both.

    npm install -g opencode-github-sync
    opencode-sync init          # creates the private repo and configures this machine
    opencode-sync push
    

    opencode-sync push


    Why another sync tool

    Most config-sync tools stop being safe the moment real use hits them. These are the three places that happens, and what this one does instead.

    Typical approach Here
    Machine differences Every machine forced identical Per-machine overrides that sync can never overwrite
    Sessions Commit opencode.db — gigabytes, unmergeable Selective per-session shards, a few MB, conflict-free
    When it breaks Plugin-only: bad config means no way back The CLI runs outside OpenCode and can always recover you

    Plus the boring things that turn out to matter:

    • Symlinks are refused, not followed. No copying files out of the machine by accident, no junction turning a delete into the wrong delete.
    • Every replacement is atomic. A crash mid-sync cannot leave a half-written config that stops OpenCode from starting.
    • A push is verified against the remote. git push can exit 0 without the remote moving; that is checked, not assumed.
    • Nothing runs twice at once. A cross-process lock covers the plugin, the CLI and every OpenCode window.
    • Credentials are opt-in and refused outright on a public repository.
    • Your hostname never leaves the machine. Commits are signed with a stable pseudonym, so a corporate asset tag never lands in a repo that might not stay private.

    Install

    As an OpenCode plugin

    // ~/.config/opencode/opencode.json
    {
      "$schema": "https://opencode.ai/config.json",
      "plugin": ["opencode-github-sync"]
    }
    

    OpenCode installs it on the next start. The plugin adds a pull on startup, an optional push when a session goes idle, and an opencode_sync tool so you can just ask for a sync in plain language.

    As a CLI

    npm install -g opencode-github-sync
    

    Keep the CLI even if you use the plugin. A plugin cannot fix the configuration that stops OpenCode from loading the plugin.

    Requirements — git, and gh for automatic setup. Node 18+ for config sync; Node 22.5+ or Bun for session sync.


    Quick start

    First machine

    opencode-sync init                 # → <you>/my-opencode-config
    opencode-sync init team-config     # custom name
    opencode-sync init my-org/shared   # inside an organisation
    opencode-sync push
    

    init creates a private repository, writes ~/.config/opencode/opencode-sync.jsonc, and leaves an empty overrides file ready for you.

    Every other machine

    opencode-sync link doomsday616/my-opencode-config
    opencode-sync pull
    

    Then restart OpenCode.

    Day to day

    opencode-sync push        # share what changed here
    opencode-sync pull        # take what changed elsewhere
    opencode-sync status      # what is in sync, what is not
    

    What gets synced

    Architecture

    Source In the repo Contents
    ~/.config/opencode/ repo root config, agents, commands, skills, themes, MCP
    ~/.local/share/opencode/ _data/ project metadata, optional credentials
    ~/.local/state/opencode/ _state/ frecency, model cache, prompt history
    ~/.agents/skills/ _agents/ skills installed by the skills CLI
    selected sessions _sessions/ one gzipped shard per session

    Never synced: opencode.db and its journals, tool output, snapshots, logs, and your local settings and overrides files.

    Add anything else with extraPaths:

    {
      "extraPaths": [".tavily", ".config/gh/config.yml"]
    }
    

    Per-machine overrides

    A synced repository makes every machine identical. That is exactly wrong for the settings that are genuinely machine-specific: a corporate proxy, a local toolchain path, an MCP server that only exists on one box.

    Put those in ~/.config/opencode/opencode-sync.overrides.jsonc:

    {
      "model": "github-copilot/claude-sonnet-4",
      "mcp": {
        "playwright": { "enabled": true }
      }
    }
    
       repo opencode.jsonc        shared baseline, committed
     + overrides.jsonc            this machine only, never committed
     ─────────────────────────    deep merge
     = effective opencode.jsonc   what OpenCode actually reads
    

    Merge rules: objects merge key by key, arrays and scalars replace, null deletes a key.

    The half that other tools get wrong is push. Because the effective file is what sits on disk, a naive push uploads your overrides to everyone. Here, any key the overrides file claims is restored to the value the repository already had before committing — so an overridden key is invisible to sync in both directions, and your machine keeps its own settings the whole time.

    With no overrides file the config is copied byte for byte and your comments and formatting are untouched. The structural rewrite only happens once you actually opt in.


    Session sync

    Off by default. Turn it on only for a private repository — conversations are private data.

    opencode-sync sessions enable
    opencode-sync sessions list
    opencode-sync sessions include ses_065cad1caffeN3lf1RgLZno30   # pin one forever
    opencode-sync sessions exclude ses_0ba19b4e7ffeMbSmWYi3Nj6xfZ  # never sync this one
    

    Why not just commit the database

    A real OpenCode database reaches several gigabytes, almost all of it tool output inside part.data. Git cannot delta-compress it, GitHub's LFS free tier is one gigabyte, and copying a live database alongside its write-ahead log can capture a torn state that only shows up much later.

    So sessions are exported one at a time. Each becomes an independent gzipped JSON shard holding its own rows plus the project and workspace rows it needs:

    • No large files. Shards are small and compress well.
    • Conflicts isolate themselves. Two machines working on different sessions touch different files, so git merges them with no special handling. The only real conflict is one session edited in two places, and there the newer time_updated wins — an in-progress conversation is never clobbered by a stale copy.
    • You choose what travels. A time window, an explicit include list, a project filter and a per-session size cap. Ancient sessions stay where they are.

    Import is an upsert inside a transaction, so a failure leaves your database exactly as it was.

    {
      "sessions": {
        "enabled": true,
        "days": 7,             // only sessions touched this recently
        "maxSessions": 50,     // hard cap per push, newest first
        "maxSessionBytes": 5242880,  // skip any single runaway session
        "include": [],         // always sync these, whatever the window says
        "exclude": [],         // never sync these
        "directories": []      // only sessions under these project directories
      }
    }
    

    The internal event log is deliberately excluded. It is the largest table by row count and nothing about resuming a conversation depends on it.


    Command reference

    Command What it does
    opencode-sync init [name] Create a private sync repository
    opencode-sync link <owner/repo> Point this machine at an existing one
    opencode-sync push Share this machine's configuration
    opencode-sync pull Apply the shared configuration
    opencode-sync status Show what is in sync and what is not
    opencode-sync sessions list Recent sessions and their ids
    opencode-sync sessions enable Turn selective session sync on
    opencode-sync sessions include Pin a session, ignoring the time window
    opencode-sync overrides Create/locate the per-machine patch
    opencode-sync config Print the current settings
    Flag Effect
    --force Overwrite the other side on conflict (confirmed)
    --dry-run Report what would change, write nothing
    Environment variable Effect
    OPENCODE_SYNC_HOST_ALIAS Name this machine in commit messages
    OPENCODE_SYNC_VERBOSE=1 Full file list and stack traces
    NO_COLOR Disable colour
    SYNC_REMOTE_URL Override the repository URL

    Settings

    ~/.config/opencode/opencode-sync.jsonc — never committed.

    {
      "repo": { "owner": "you", "name": "my-opencode-config", "branch": "main" },
    
      "machineAlias": "laptop",     // optional; otherwise a stable pseudonym
    
      "includeCredentials": false,  // auth.json / account.json — private repos only
      "includeSkills": true,
      "includeState": true,
      "extraPaths": [],
    
      "sessions": { "enabled": false },
    
      "autoPullOnStartup": true,    // plugin only
      "autoPushOnIdle": false       // plugin only
    }
    

    When something goes wrong

    A pull conflicted with local edits. The worktree is rolled back to a clean state and your changes stay in the stash. The exact recovery commands are printed. Nothing is lost.

    cd ~/.config/opencode
    git stash list
    git stash show -p stash@{0}
    

    "This machine has N commits that were never pushed." Deliberate — pulling would destroy them. Run opencode-sync push, or pull --force to discard.

    Authentication failed. gh auth login -h github.com. The token needs the repo scope for private repositories.

    Session sync says no SQLite driver. Node 22.5+ or Bun. Config sync is unaffected.

    Everything is broken and OpenCode will not start. This is why the CLI exists:

    opencode-sync pull --force
    

    Development

    npm install
    npm run check     # lint + typecheck + tests
    npm run build
    

    The test suite runs against a real bare git repository on disk and simulates two separate machines, so push, pull, force, rebase, stashing and the override round-trip are all exercised end to end.


    Star history

    Star history chart

    License

    MIT

    If this saved you some time, a ⭐ is appreciated.