npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@anthonyhaussman/opencode-synced

v1.0.2

Published

Sync global opencode config across machines via GitHub.

Readme

opencode-synced

Sync global opencode configuration across machines via a GitHub repo, with optional secrets support for private repos.

Features

  • Syncs global opencode config (~/.config/opencode) and related directories
  • Optional secrets sync when the repo is private
  • Optional session sync to share conversation history across machines
  • Optional prompt stash sync to share stashed prompts and history across machines
  • Startup auto-sync with restart toast
  • Per-machine overrides via opencode-synced.overrides.jsonc
  • Custom /sync-* commands and opencode_sync tool

Requirements

  • GitHub CLI (gh) installed and authenticated (gh auth login)
  • Git installed and available on PATH

Setup

Enable the plugin in your global opencode config (opencode will install it on next run):

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

opencode does not auto-update plugins. To update, modify the version number in your config file.

Configure

First machine (create new sync repo)

Run /sync-init to create a new sync repo:

  1. Detects your GitHub username
  2. Creates a private repo (my-opencode-config by default)
  3. Clones the repo and pushes your current config

Additional machines (link to existing repo)

Run /sync-link to connect to your existing sync repo:

  1. Searches your GitHub for common sync repo names (prioritizes my-opencode-config)
  2. Clones and applies the synced config
  3. Overwrites local config with synced content (preserves your local overrides file)

If auto-detection fails, specify the repo name: /sync-link my-opencode-config

After linking, restart opencode to apply the synced settings.

Custom repo name or org

You can specify a custom repo name or use an organization:

  • /sync-init - Uses {your-username}/my-opencode-config
  • /sync-init my-config - Uses {your-username}/my-config
  • /sync-init my-org/team-config - Uses my-org/team-config

Create ~/.config/opencode/opencode-synced.jsonc:

{
  "repo": {
    "owner": "your-org",
    "name": "opencode-config",
    "branch": "main",
  },
  "includeSecrets": false,
  "includeMcpSecrets": false,
  "includeSessions": false,
  "sessionBackend": {
    "type": "git",
    "turso": {
      "syncIntervalSec": 15,
      "autoSetup": true,
    },
  },
  "includePromptStash": false,
  "includeModelFavorites": true,
  "includeOpencodeSkills": true,
  "includeAgentsDir": true,
  "extraSecretPaths": [],
  "extraConfigPaths": [],
}

Synced paths (default)

  • ~/.config/opencode/opencode.json and opencode.jsonc
  • ~/.config/opencode/AGENTS.md
  • ~/.config/opencode/agent/, command/, mode/, tool/, themes/, plugin/, skills/
  • ~/.agents/
  • ~/.local/state/opencode/model.json (model favorites)
  • Any additional paths in extraConfigPaths (allowlist, files or folders). You do not need to include default paths like ~/.config/opencode/skills or ~/.agents.

Disable default directory sync by setting:

  • "includeOpencodeSkills": false to skip ~/.config/opencode/skills/
  • "includeAgentsDir": false to skip ~/.agents/

Secrets (private repos only)

Enable secrets with /sync-enable-secrets or set "includeSecrets": true:

  • ~/.local/share/opencode/auth.json
  • ~/.local/share/opencode/mcp-auth.json
  • Any extra paths in extraSecretPaths (allowlist, files or folders)

MCP API keys stored inside opencode.json(c) are not committed by default. To allow them in a private repo, set "includeMcpSecrets": true (requires includeSecrets).

Sessions (private repos only)

Session sync remains opt-in via "includeSessions": true (and requires "includeSecrets": true). Session backend defaults to Git for backward compatibility. Turso is recommended for users running multiple active machines concurrently.

{
  "repo": { ... },
  "includeSecrets": true,
  "includeSessions": true,
  "sessionBackend": {
    "type": "git", // or "turso"
    "turso": {
      "database": "my-opencode-config-sessions", // optional
      "url": "libsql://...", // optional
      "syncIntervalSec": 15, // default 15
      "autoSetup": true, // default true
    },
  },
}

Git backend (sessionBackend.type = "git", default)

Best-effort session artifact sync via Git paths:

  • ~/.local/share/opencode/opencode.db
  • ~/.local/share/opencode/opencode.db-wal and ~/.local/share/opencode/opencode.db-shm
  • ~/.local/share/opencode/storage/session/
  • ~/.local/share/opencode/storage/message/
  • ~/.local/share/opencode/storage/part/
  • ~/.local/share/opencode/storage/session_diff/

This mode can conflict with concurrent writers.

Turso backend (sessionBackend.type = "turso")

Concurrent-safe snapshot backend for sessions:

  • Session artifacts are not synced through Git paths.
  • Config + secrets continue using the normal Git sync flow.
  • Startup performs a Turso session pull before regular config sync.
  • Background loop runs pull -> push -> pull on the configured interval.
  • Manual /sync-pull and /sync-push trigger a foreground session sync cycle too.

Turso setup is machine-local and idempotent:

  • Auto-installs Turso CLI when needed (best effort).
  • Runs headless Turso login flow when needed.
  • Creates/reuses the Turso database + token.
  • Stores credentials in a local machine-only file (0600) outside the sync repo.

After pulling session changes, restart opencode to ensure the latest session state is loaded.

Prompt Stash (private repos only)

Sync your stashed prompts and prompt history across machines by setting "includePromptStash": true. This requires includeSecrets to also be enabled since prompts may contain sensitive data.

{
  "repo": { ... },
  "includeSecrets": true,
  "includePromptStash": true
}

Synced prompt data:

  • ~/.local/state/opencode/prompt-stash.jsonl - Stashed prompts
  • ~/.local/state/opencode/prompt-history.jsonl - Prompt history

Overrides

Create a local-only overrides file at:

~/.config/opencode/opencode-synced.overrides.jsonc

Overrides are merged into the runtime config and re-applied to opencode.json(c) after pull.

MCP secret scrubbing

If your opencode.json(c) contains MCP secrets (for example mcp.*.headers or mcp.*.oauth.clientSecret), opencode-synced will automatically:

  1. Move the secret values into opencode-synced.overrides.jsonc (local-only).
  2. Replace the values in the synced config with {env:...} placeholders.

This keeps secrets out of the repo while preserving local behavior. On other machines, set the matching environment variables (or add local overrides). If you want MCP secrets committed (private repos only), set "includeMcpSecrets": true alongside "includeSecrets": true.

Env var naming rules:

  • If the header name already looks like an env var (e.g. CONTEXT7_API_KEY), it is used directly.
  • Otherwise: opencode_mcp_<SERVER>_<HEADER> (non-alphanumerics become _).
  • OAuth client secrets use opencode_mcp_<SERVER>_OAUTH_CLIENT_SECRET.

Usage

| Command | Description | |---------|-------------| | /sync-init | Create a new sync repo (first machine) | | /sync-link | Link to existing sync repo (additional machines) | | /sync-status | Show repo status and last sync times | | /sync-pull | Fetch and apply remote config | | /sync-push | Commit and push local changes | | /sync-enable-secrets | Enable secrets sync (private repos only) | | /sync-secrets-pull | Pull secrets from 1Password backend | | /sync-secrets-push | Push secrets to 1Password backend | | /sync-secrets-status | Show secrets sync status (hash, last sync time) | | /sync-sessions-backend <git|turso> | Switch session backend | | /sync-sessions-setup-turso | Install/auth/provision Turso on this machine | | /sync-sessions-migrate-turso | Bootstrap + switch from Git session sync to Turso | | /sync-sessions-cleanup-git | Remove deprecated Git session artifacts after migration | | /sync-resolve | Auto-resolve uncommitted changes using AI |

Trigger a sync

Restart opencode to run the startup sync flow (pull remote, apply if changed, push local changes if needed).

Check status

Inspect the local repo directly:

cd ~/.local/share/opencode/opencode-synced/repo
git status
git log --oneline -5

Recovery

If the sync repo has uncommitted changes, you can:

  1. Auto-resolve using AI: Run /sync-resolve to let AI analyze and decide whether to commit or discard the changes
  2. Manual resolution: Navigate to the repo and resolve manually:
cd ~/.local/share/opencode/opencode-synced/repo
git status
git pull --rebase

Then re-run /sync-pull or /sync-push.

Removal

Run this one-liner to remove the plugin from your config, delete local sync files, and delete the GitHub repository:

bun -e '
  const fs = require("node:fs"), path = require("node:path"), os = require("node:os"), { spawnSync } = require("node:child_process");
  const isWin = os.platform() === "win32", home = os.homedir();
  const configDir = isWin ? path.join(process.env.APPDATA, "opencode") : path.join(home, ".config", "opencode");
  const dataDir = isWin ? path.join(process.env.LOCALAPPDATA, "opencode") : path.join(home, ".local", "share", "opencode");
  ["opencode.json", "opencode.jsonc"].forEach(f => {
    const p = path.join(configDir, f);
    if (fs.existsSync(p)) {
      const c = fs.readFileSync(p, "utf8"), u = c.replace(/"opencode-synced"\s*,?\s*/g, "").replace(/,\s*\]/g, "]");
      if (c !== u) fs.writeFileSync(p, u);
    }
  });
  const scp = path.join(configDir, "opencode-synced.jsonc");
  if (fs.existsSync(scp)) {
    try {
      const c = JSON.parse(fs.readFileSync(scp, "utf8").replace(/\/\/.*/g, ""));
      if (c.repo?.owner && c.repo?.name) {
        const res = spawnSync("gh", ["repo", "delete", `${c.repo.owner}/${c.repo.name}`, "--yes"], { stdio: "inherit" });
        if (res.status !== 0) console.log("\nNote: Repository delete failed. If it is a permission error, run: gh auth refresh -s delete_repo\n");
      }
    } catch (e) {}
  }
  [scp, path.join(configDir, "opencode-synced.overrides.jsonc"), path.join(dataDir, "sync-state.json"), path.join(dataDir, "opencode-synced")].forEach(p => {
    if (fs.existsSync(p)) fs.rmSync(p, { recursive: true, force: true });
  });
  console.log("opencode-synced removed.");
'

Manual steps

  1. Remove "opencode-synced" from the plugin array in ~/.config/opencode/opencode.json (or .jsonc).
  2. Delete the local configuration and state:
    rm ~/.config/opencode/opencode-synced.jsonc
    rm ~/.local/share/opencode/sync-state.json
    rm -rf ~/.local/share/opencode/opencode-synced
  3. (Optional) Delete the backup repository on GitHub via the web UI or gh repo delete.

Development

  • bun run build
  • bun run test
  • bun run lint

Codex Environment

This repo includes a shared Codex local environment at:

  • .codex/environments/environment.toml
  • scripts/setup-env.sh
  • scripts/e2e/github_two_instance.py

Setup behavior

The Codex environment just invokes scripts/setup-env.sh. Setup does:

  • bun install (idempotent)
  • creates runtime folders under .memory/
  • clones upstream opencode into .memory/opencode-upstream/opencode only if missing

The upstream clone is local-only and is not auto-updated by setup.

Actions

The environment exposes these actions in Codex:

  • Check -> bun run check
  • Test -> bun test
  • Build -> bun run build
  • E2E GitHub (2 instances) -> python3 scripts/e2e/github_two_instance.py

End-to-end test harness

Run manually:

python3 scripts/e2e/github_two_instance.py

Helpful options:

python3 scripts/e2e/github_two_instance.py --help
python3 scripts/e2e/github_two_instance.py --preflight-only
python3 scripts/e2e/github_two_instance.py --keep-failed-repo

The harness runs two isolated opencode instances, uses a unique ephemeral private GitHub repo, and writes artifacts to .memory/e2e/runs/<run-id>/.

Local testing (production-like)

To test the same artifact that would be published, install from a packed tarball into opencode's cache:

mise run local-pack-test

Then set ~/.config/opencode/opencode.json to use:

{
  "plugin": ["opencode-synced"]
}

Restart opencode to pick up the cached install.

Prefer a CLI version?

I stumbled upon opencodesync while publishing this plugin.