Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ Installation, sign-in, and usage instructions are in the documentation:

Supported platforms: macOS (x64, arm64), Linux (x64, arm64), and Windows (x64, arm64).

## Migrate from Tabnine CLI

If you're switching from Tabnine CLI (or Gemini CLI), the [Migration helper](migration_helper/README.md) copies your MCP servers, skills, subagents, slash commands, and TABNINE.md context files into opencode. It runs as interactive wizards inside opencode itself and never overwrites files without asking.

## Report a bug or request a feature

Please use the issue templates:
Expand Down
21 changes: 21 additions & 0 deletions migration_helper/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2026 Tabnine Ltd.

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
129 changes: 129 additions & 0 deletions migration_helper/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
# Migration helper: Tabnine CLI to opencode

Copies your Tabnine CLI (or Gemini CLI) configuration into an opencode configuration directory. Runs as interactive wizards inside opencode itself: they scan your disk, show what they found, ask what to migrate, translate fields that differ between the two systems, and never overwrite an existing file without asking.

Nothing is deleted from your Tabnine CLI installation. This is a copy-and-translate flow. You can keep using Tabnine CLI after.

Two skills are included:

- **`migrate-from-tabnine-cli`** (`/migrate`) — MCP servers, skills, subagents, slash commands, and extension contents. Run once per target scope (global or project).
- **`migrate-tabnine-context`** (`/migrate-context`) — context/memory files (`TABNINE.md`, `GEMINI.md`, or custom `context.fileName` files) into opencode's `AGENTS.md`. Re-runnable in every repository you work in.

## What gets migrated

MCP servers, skills, subagents, slash commands, the contents of Tabnine CLI extensions, and context files (`TABNINE.md` → `AGENTS.md`, via the second skill). Fields that have no opencode equivalent are dropped with a note. See `skills/migrate-from-tabnine-cli/references/mapping.md` for the complete field-by-field translation table.

## What does NOT get migrated

OAuth tokens (`~/.tabnine/agent/mcp-oauth-tokens.json`), Tabnine credentials, and Tabnine-specific admin policy fields — you will re-authenticate each remote MCP server on first use. Also out of scope: hooks, themes, keybindings, and general settings (model selection, approval mode); configure those directly in opencode.

## Prerequisites

An installed and working opencode. The wizard is a skill that loads inside opencode; the installer below only copies files into place.

The installer script requires `bash`, `cp`, `diff`, and `mv`, which are standard on macOS and Linux. Windows users should follow the manual copy instructions below.

## Install with the script

Clone the repo and run the installer:

```bash
git clone https://github.com/codota/tabnine-opencode-public
cd tabnine-opencode-public/migration_helper
./install.sh
```

By default this installs globally into `~/.config/opencode/`. To install into the current project instead:

```bash
./install.sh --project
```

To overwrite existing files without diff prompts:

```bash
./install.sh --overwrite
```

When a target file already exists and differs from the incoming copy, the installer prints a unified diff and asks whether to skip, overwrite, or rename the existing file with a timestamped `.bak-YYYYMMDD-HHMMSS` suffix before installing the new one.

## Install manually

Manual copy is a fully supported alternative. It is the recommended path on Windows and works on macOS and Linux equally well.

For a global install on macOS or Linux:

```bash
mkdir -p ~/.config/opencode/skills ~/.config/opencode/commands
cp -r migration_helper/skills/migrate-from-tabnine-cli migration_helper/skills/migrate-tabnine-context ~/.config/opencode/skills/
cp migration_helper/commands/migrate.md migration_helper/commands/migrate-context.md ~/.config/opencode/commands/
```

For a project install on macOS or Linux:

```bash
mkdir -p .opencode/skills .opencode/commands
cp -r migration_helper/skills/migrate-from-tabnine-cli migration_helper/skills/migrate-tabnine-context .opencode/skills/
cp migration_helper/commands/migrate.md migration_helper/commands/migrate-context.md .opencode/commands/
```

For a global install on Windows (PowerShell):

```powershell
New-Item -ItemType Directory -Force "$env:USERPROFILE\.config\opencode\skills", "$env:USERPROFILE\.config\opencode\commands" | Out-Null
Copy-Item -Recurse migration_helper\skills\migrate-from-tabnine-cli, migration_helper\skills\migrate-tabnine-context "$env:USERPROFILE\.config\opencode\skills\"
Copy-Item migration_helper\commands\migrate.md, migration_helper\commands\migrate-context.md "$env:USERPROFILE\.config\opencode\commands\"
```

If any of the target files already exist, back them up first. The installer script does this automatically; the manual commands above do not.

## Usage after install

Quit and restart opencode so it picks up the new skill and slash command. opencode does not hot-reload its configuration.

Once restarted, run the config wizard in either of two ways:

Run the slash command directly:

```
/migrate
```

Or ask opencode in natural language:

```
migrate my tabnine cli config to opencode
```

Either entry point activates the same skill. The wizard scans for Tabnine CLI configuration, prints a compact inventory, and then asks you category by category (MCP servers, skills, subagents, commands, extensions) which items to migrate and where to write them.

To migrate your `TABNINE.md` context files into `AGENTS.md`, run `/migrate-context` (or ask "migrate my tabnine context files"). That skill is scoped per repository — re-run it in each project whose context files you want to bring over.

## Uninstall

Remove the paths the installer created:

```bash
rm -rf ~/.config/opencode/skills/migrate-from-tabnine-cli ~/.config/opencode/skills/migrate-tabnine-context
rm ~/.config/opencode/commands/migrate.md ~/.config/opencode/commands/migrate-context.md
```

For a project install, replace `~/.config/opencode` with `.opencode`. Restart opencode after.

## Troubleshooting

The most common issue is forgetting to restart. Opencode loads skills and commands at startup. If `/migrate` is not recognized or the wizard behaviour is stale, quit opencode fully and start it again.

If opencode fails to start after the migration with a `ConfigInvalidError`, one of the migrated fields has been rejected. Recover with either of these:

```bash
OPENCODE_DISABLE_PROJECT_CONFIG=1 opencode
```

Or edit the offending file directly, using the field-by-field rules in `skills/migrate-from-tabnine-cli/references/mapping.md` as a reference.

A `duplicate skill name` warning at load time means two skills with the same `name` field exist under paths opencode scans (`~/.config/opencode/skills/`, `~/.claude/skills/`, and the equivalent workspace paths). Rename one or delete the older copy.

## License

Licensed under the MIT License. See `LICENSE`.
5 changes: 5 additions & 0 deletions migration_helper/commands/migrate-context.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
description: Migrate Tabnine CLI context files (TABNINE.md) into opencode's AGENTS.md.
---

Load the migrate-tabnine-context skill and run it. Discover the user's Tabnine CLI context/memory files (TABNINE.md, GEMINI.md, or custom context.fileName files) in this repository and globally, show what was found, and ask before writing anything. Never overwrite an existing AGENTS.md without asking and never modify the source files.
5 changes: 5 additions & 0 deletions migration_helper/commands/migrate.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
description: Migrate Tabnine CLI (or Gemini CLI) configuration into opencode.
---

Load the migrate-from-tabnine-cli skill and run the interactive migration wizard. Scan the user's disk for Tabnine CLI configuration (MCP servers, skills, agents, slash commands, extensions), show a compact inventory, and ask per-category what to migrate. Never overwrite existing opencode files without asking. Remind the user to restart opencode when done.
207 changes: 207 additions & 0 deletions migration_helper/install.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,207 @@
#!/usr/bin/env bash
# Install the Tabnine CLI migration skills (migrate-from-tabnine-cli,
# migrate-tabnine-context) and their slash commands (/migrate,
# /migrate-context) into an opencode configuration directory.
#
# Usage:
# ./install.sh # install globally into ~/.config/opencode/
# ./install.sh --project # install into ./.opencode/ in the current directory
# ./install.sh --overwrite # skip diff prompts, overwrite existing files
# ./install.sh --help # show usage
#
# For each file this installer wants to place, one of three things happens:
# - target is missing -> file is copied
# - target is byte-identical -> file is skipped
# - target differs -> a diff is shown and the user is prompted
# to (s)kip, (o)verwrite, or (r)ename the
# existing target before copying

set -euo pipefail

# -----------------------------------------------------------------------------
# Argument parsing
# -----------------------------------------------------------------------------

TARGET_SCOPE="global"
OVERWRITE=0

usage() {
cat <<'EOF'
Install the Tabnine CLI -> opencode migration helper.

Usage:
install.sh [--project] [--overwrite] [--help]

Options:
--project Install into ./.opencode/ (project scope) instead of
~/.config/opencode/ (global scope, the default).
--overwrite Overwrite existing target files without prompting.
--help, -h Show this message and exit.

The installer copies:

skills/migrate-from-tabnine-cli/ -> <target>/skills/migrate-from-tabnine-cli/
skills/migrate-tabnine-context/ -> <target>/skills/migrate-tabnine-context/
commands/migrate.md -> <target>/commands/migrate.md
commands/migrate-context.md -> <target>/commands/migrate-context.md

Where <target> is either ~/.config/opencode or ./.opencode.

You can also install manually. See the README for the copy commands.
EOF
}

while [[ $# -gt 0 ]]; do
case "$1" in
--project) TARGET_SCOPE="project"; shift ;;
--overwrite) OVERWRITE=1; shift ;;
--help|-h) usage; exit 0 ;;
*) echo "Unknown argument: $1" >&2; usage >&2; exit 2 ;;
esac
done

# -----------------------------------------------------------------------------
# Locate source (the directory this script lives in)
# -----------------------------------------------------------------------------

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"

SKILLS="migrate-from-tabnine-cli migrate-tabnine-context"
COMMANDS="migrate.md migrate-context.md"

MISSING=0
for skill in $SKILLS; do
[[ -d "$SCRIPT_DIR/skills/$skill" ]] || MISSING=1
done
for cmd in $COMMANDS; do
[[ -f "$SCRIPT_DIR/commands/$cmd" ]] || MISSING=1
done

if [[ "$MISSING" -eq 1 ]]; then
echo "Error: could not find source files next to this script." >&2
echo "Expected under $SCRIPT_DIR: skills/{$(echo $SKILLS | tr ' ' ',')}/ and commands/{$(echo $COMMANDS | tr ' ' ',')}" >&2
echo "" >&2
echo "If you ran this via 'curl | bash', download the repo first:" >&2
echo " git clone https://github.com/codota/tabnine-opencode-public" >&2
echo " cd tabnine-opencode-public/migration_helper" >&2
echo " ./install.sh" >&2
exit 1
fi

# -----------------------------------------------------------------------------
# Resolve target
# -----------------------------------------------------------------------------

if [[ "$TARGET_SCOPE" == "global" ]]; then
TARGET_DIR="$HOME/.config/opencode"
else
TARGET_DIR="$PWD/.opencode"
fi

echo "Installing into: $TARGET_DIR ($TARGET_SCOPE scope)"
echo ""

mkdir -p "$TARGET_DIR/skills" "$TARGET_DIR/commands"

# -----------------------------------------------------------------------------
# Per-file install helper
# -----------------------------------------------------------------------------
# Args: <source path> <target path>
install_file() {
local src="$1"
local dst="$2"

mkdir -p "$(dirname "$dst")"

if [[ ! -e "$dst" ]]; then
cp "$src" "$dst"
echo " installed $dst"
return
fi

if cmp -s "$src" "$dst"; then
echo " up to date $dst"
return
fi

if [[ "$OVERWRITE" -eq 1 ]]; then
cp "$src" "$dst"
echo " overwrote $dst"
return
fi

echo ""
echo " Target exists and differs: $dst"
echo " Diff (existing -> incoming):"
echo " ---"
diff -u "$dst" "$src" || true
echo " ---"

# -r /dev/tty is true even without a controlling terminal; test the open itself.
if ! ( : < /dev/tty ) 2>/dev/null; then
echo " skipped $dst (no terminal to prompt on; re-run interactively or use --overwrite)"
return
fi

while true; do
read -rp " [s]kip, [o]verwrite, or [r]ename existing and install? " choice </dev/tty
case "$choice" in
s|S)
echo " skipped $dst"
break
;;
o|O)
cp "$src" "$dst"
echo " overwrote $dst"
break
;;
r|R)
local ts backup
ts="$(date +%Y%m%d-%H%M%S)"
backup="$dst.bak-$ts"
mv "$dst" "$backup"
cp "$src" "$dst"
echo " renamed $backup"
echo " installed $dst"
break
;;
*)
echo " Please answer s, o, or r."
;;
esac
done
}

# -----------------------------------------------------------------------------
# Copy skill directory (recursive)
# -----------------------------------------------------------------------------

# Walk each source skill directory and install each file individually so
# collisions are handled per file, not silently overwritten as a tree.
for skill in $SKILLS; do
echo "Skill: $skill"
while IFS= read -r -d '' src_file; do
rel_path="${src_file#$SCRIPT_DIR/skills/}"
dst_file="$TARGET_DIR/skills/$rel_path"
install_file "$src_file" "$dst_file"
done < <(find "$SCRIPT_DIR/skills/$skill" -type f -print0)
echo ""
done

for cmd in $COMMANDS; do
echo "Command: $cmd"
install_file "$SCRIPT_DIR/commands/$cmd" "$TARGET_DIR/commands/$cmd"
done

# -----------------------------------------------------------------------------
# Done
# -----------------------------------------------------------------------------

echo ""
echo "Done."
echo ""
echo "Quit and restart opencode for these changes to take effect."
echo "Then invoke the wizards with:"
echo " /migrate (MCP servers, skills, agents, commands, extensions)"
echo " /migrate-context (TABNINE.md context files -> AGENTS.md)"
echo "or by asking opencode to migrate your Tabnine CLI configuration."
Loading