Skip to content

Add migration helper for Tabnine CLI to opencode - #1

Open
Pavel-tabnine wants to merge 1 commit into
mainfrom
feat/migration-helper
Open

Add migration helper for Tabnine CLI to opencode#1
Pavel-tabnine wants to merge 1 commit into
mainfrom
feat/migration-helper

Conversation

@Pavel-tabnine

@Pavel-tabnine Pavel-tabnine commented Jul 30, 2026

Copy link
Copy Markdown
Collaborator

Summary

Adds a migration_helper/ subtree that helps users move their Tabnine CLI (or Gemini CLI) configuration into opencode.

The heart of it is an opencode skill (migrate-from-tabnine-cli) that runs as an interactive wizard inside opencode itself. This PR bundles that skill plus a /migrate slash command and a small bash installer for placing them into the user's opencode config directory.

What's inside migration_helper/

migration_helper/
├── LICENSE                       # MIT, subtree-scoped
├── README.md                     # install (script or manual) + usage
├── install.sh                    # bash installer (executable)
├── commands/
│   └── migrate.md                # /migrate slash command
└── skills/
    └── migrate-from-tabnine-cli/
        ├── SKILL.md              # main wizard skill
        └── references/
            ├── source-map.md     # where Tabnine CLI stores each thing
            └── mapping.md        # field-by-field translation rules

What it migrates

MCP servers, skills, subagents, slash commands, and the contents of Tabnine CLI extensions. Fields with no opencode equivalent are dropped with a note. Nothing is deleted from the Tabnine CLI installation — this is a copy-and-translate flow.

Installer behaviour

./install.sh                 # global: ~/.config/opencode/
./install.sh --project       # project: ./.opencode/
./install.sh --overwrite     # skip diff prompts

For every file it wants to place:

  • Missing target → copy.
  • Identical target → skip (idempotent).
  • Different target → show a unified diff, prompt [s]kip / [o]verwrite / [r]ename (rename appends .bak-YYYYMMDD-HHMMSS).

Manual cp -r is documented as a fully supported alternative for users who don't want to run the script (mandatory path for Windows).

Verification

  • bash -n install.sh passes.
  • Tested fresh install into a temp $HOME — writes 4 files correctly.
  • Tested --project install into a temp directory — writes 4 files under ./.opencode/.
  • Second run over an unchanged install reports up to date on every file (idempotent).
  • grep -rn "pavel\|2026-07-08" migration_helper/ returns clean (no personal paths or hardcoded dates leaked).

Root README

One new section, ## Migrate from Tabnine CLI, links to migration_helper/README.md. Otherwise the root README is unchanged.

Licensing

migration_helper/LICENSE scopes this subtree to MIT with Copyright (c) 2026 Tabnine Ltd.. This is a documentation + shell subtree; MIT is the shortest, most permissive, best-known license for that shape. The root repo's proprietary posture (© Tabnine. All rights reserved.) is unchanged — only this subtree is MIT.

Adds migration_helper/ subtree with:

- skills/migrate-from-tabnine-cli/ — interactive wizard skill that
  discovers Tabnine CLI (or Gemini CLI) configuration on disk, asks
  the user per category what to migrate, and translates fields into
  opencode's schema. Includes reference docs for source paths and
  field-by-field translation rules.
- commands/migrate.md — /migrate slash command as an entry point to
  the wizard.
- install.sh — bash installer that copies the skill and command into
  either ~/.config/opencode/ (default) or ./.opencode/ (--project).
  Shows a diff and prompts skip/overwrite/rename on collisions.
  Supports --overwrite to bypass prompts.
- README.md — install (script or manual copy) and usage docs.
- LICENSE — MIT, subtree-scoped.

Root README gets one new section linking to migration_helper/README.md.
@Pavel-tabnine

Copy link
Copy Markdown
Collaborator Author

Independent review: migrate-from-tabnine-cli

Verdict: A well-scoped, disciplined migration wizard whose references are grounded in the actual Tabnine CLI source with concrete file:line citations rather than guesses. A handful of real gaps around name-regex mismatch, an internal contradiction on discovery depth, and a few instructions that punt too much to model judgement keep it from shipping unchanged.

Strengths

  • Discovery-first flow with explicit "never invent" and "never touch sources" rules (SKILL.md:12-15) is exactly the shape a destructive-ish wizard needs.
  • Reference material is verified against the real Tabnine codebase with concrete file:line citations (source-map.md:16, 42, 66, 101, 189), which is load-bearing for a translation table.
  • Correctly catches the .claude/skills auto-scan collision hazard and defaults to skipping (SKILL.md:158) — an easy bug to ship otherwise.
  • Progressive disclosure is textbook: 171-line SKILL.md points to two focused references, one level deep (SKILL.md:75, 169).
  • Post-migration reminders (OAuth non-transfer, restart requirement, built-in-server collision) are surfaced up front and again in the summary phase (SKILL.md:16-17, 149-156, source-map.md:206-209).

Blockers

  1. references/mapping.md:89 — "Direct copy. Both systems use SKILL.md with the same required frontmatter fields." — Tabnine's name regex allows underscores (/^[a-z0-9-_]+$/, source-map.md:137) but opencode's does not (^[a-z0-9]+(-[a-z0-9]+)*$, per the opencode/docs/skills page). Any skill or agent whose name contains an underscore will fail opencode validation, and because the directory name must match name (opencode docs), a rename cascades. Fix: add a pre-write validation step in Phase 3 that normalises _ to - in name and folder name (with user confirmation) and hard-rejects anything still non-matching.
  2. SKILL.md:93 "Do not edit the SKILL.md" combined with SKILL.md:95 "If the skill body references Gemini-specific tools, note the affected skills to the user" contradicts SKILL.md:40, which restricts discovery to frontmatter only. There is no defined phase in which the body is read, so the flag-for-review step cannot actually fire. Fix: add a Phase 3 sub-step that greps each selected skill body for a documented token list (gemini, gemini -p, tui-tester, ...) and records hits for the Phase 4 summary.

Improvements

  1. SKILL.md:67 — "For each selected agent, ask a follow-up: subagent (default) or primary mode. Explain the difference in one sentence." — The skill defers the actual explanation to the model, which is exactly the "voodoo constant" anti-pattern in prose form. Different models will explain it differently, and a wrong choice puts the agent in the primary rotation. Fix: inline the one-sentence explanation ("primary agents are user-facing entry points that own a session; subagents are invoked by a primary via the task tool and inherit its context") so the wizard produces the same guidance every run.
  2. SKILL.md:64 — "It can be overridden per-category if the user wants." — The override procedure is never defined. Phase 2 lists categories but not a re-prompt hook. Fix: either drop the override promise or add "before each multi-select, if the user says 'switch to project/global for this one', re-scope only this category" to Phase 2.
  3. SKILL.md:141 — "Nested subfolders in the source (commands/foo/bar.toml) become filename-mangled names or nested folders — mirror the source structure." — contradicts mapping.md:206 which says "either preserve the folder structure or flatten with a hyphen — ask the user." Two references, two policies. Fix: pick one (mirroring is safer; opencode supports command/foo/bar.md) and remove the other option, or move both to a single "ask the user" line in SKILL.md.
  4. SKILL.md:89 — "Merge into opencode.json's mcp object rather than replacing it. Preserve $schema, plugin, and any other keys already present." — No backup step. A merge that hits a JSON parse mid-write leaves the user with a broken config and no opencode.json to restart into. Fix: write opencode.json.bak-<timestamp> next to it before the merge, and mention the backup path in Phase 4.
  5. SKILL.md:16 and SKILL.md:171 — "load the customize-opencode skill or fetch https://opencode.ai/config.json" — The wizard hard-depends on a sibling skill that may not be installed in the user's opencode. Fix: state the fallback as primary ("fetch https://opencode.ai/config.json"), and mention customize-opencode only as an optimisation if present.
  6. mapping.md:106 — "Unknown fields are silently routed into options where they have no effect — so drop them explicitly." — This asserts opencode behaviour that isn't documented on the skills docs page (which only says unknown frontmatter is ignored for skills, not agents). Either cite the source in the opencode repo or soften the claim to "drop them explicitly, since opencode's agent schema may reject or silently swallow them".
  7. source-map.md:181 — "Array frontmatter is also accepted (multiple remote agents in one file). opencode has no direct equivalent for A2A agents — skip these with a warning." — Fine as policy, but a single .md with array frontmatter breaks the "read only top-of-file up to second ---" heuristic at SKILL.md:40. Fix: call this out in Phase 1 discovery: if the first frontmatter block is an array, treat the whole file as remote-agent bundle and skip it up front.
  8. SKILL.md:71 — "Never present a 'migrate all' shortcut without also showing the individual list." — Good rule, but not enforced in the sample inventory at lines 44-56, which invites the model to offer a shortcut anyway. Fix: add an explicit "the very next message must be the MCP-selection prompt, not a yes/no confirmation" instruction.

Nits

  1. SKILL.md:3 — description is ~500 chars; well under the 1024 limit but the sentence "Walks the user through discovery, per-item selection, target-scope choice (global vs project), and field translation so opencode's strict schema accepts the results." adds little for discovery/routing. Tightening it buys a few tokens on every session.
  2. SKILL.md:1-4 — Anthropic best practices suggest gerund-form skill names (migrating-tabnine-cli-config). migrate-from-tabnine-cli is verb-form; not wrong, just off-convention.
  3. SKILL.md:17 and SKILL.md:156 — restart reminder appears twice. Justified for emphasis on a hard failure mode, but Techdox-style deduplication would consolidate to one prominent line.
  4. mapping.md:33 — "Not per-server in opencode. There's an experimental.mcp_timeout for all servers." — the experimental prefix suggests instability; worth noting it may vanish and shouldn't be relied on.
  5. source-map.md:76-81 — the built-in tabnine-context and tabnine-coaching servers are called out as "do not migrate", but the discovery inventory sample at SKILL.md:44-56 doesn't show how they'd appear in the printed list. Suggest: either filter them out silently, or show them greyed-out as "(built-in, skipped)" so the user isn't confused when they don't appear in the multi-select.
  6. mapping.md:120 — "model: <plain name> ... must be dropped." — Dropping is correct given the "don't guess" rule, but a one-line hint pointing the user at opencode's provider list in the Phase 4 summary would make the drop actionable.

opencode runtime fit

The skill is well-adapted to opencode's runtime: it correctly targets .opencode/skills/, agent/, command/, and the global ~/.config/opencode/ paths (SKILL.md:64, 116, 141), respects opencode's on-demand skill loading model by keeping SKILL.md compact and pushing detail into references/, and uses the question tool for interactive selection as expected in a wizard flow. It also correctly assumes no hot-reload and enforces a restart. The one place the runtime fit is loose is the assumption that a sibling customize-opencode skill is available for schema lookups — that's a reasonable ecosystem bet inside this repo but not a guaranteed opencode invariant.

Recommendation

Ship after fixes #1 (name-regex normalisation) and #2 (define where skill-body scanning happens); the improvements can follow in a v1.1. The bones are solid and the references are unusually well-sourced.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant