Skip to content

Commit 50404ee

Browse files
committed
feat: add Tabnine CLI agent support
Tabnine CLI is a Gemini fork that uses TOML commands with the .tabnine/agent/ directory structure and TABNINE.md context files. Changes: - Add 'tabnine' to AGENT_CONFIG in __init__.py - Update release scripts (bash + PowerShell) for TOML command generation - Update agent context scripts (bash + PowerShell) - Add to GitHub release packages - Update README.md and AGENTS.md documentation - Bump version to 0.1.14 - Add 8 new tests for cross-file consistency
1 parent 3033834 commit 50404ee

File tree

13 files changed

+135
-17
lines changed

13 files changed

+135
-17
lines changed

.github/workflows/scripts/create-github-release.sh

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ gh release create "$VERSION" \
4646
.genreleases/spec-kit-template-amp-ps-"$VERSION".zip \
4747
.genreleases/spec-kit-template-shai-sh-"$VERSION".zip \
4848
.genreleases/spec-kit-template-shai-ps-"$VERSION".zip \
49+
.genreleases/spec-kit-template-tabnine-sh-"$VERSION".zip \
50+
.genreleases/spec-kit-template-tabnine-ps-"$VERSION".zip \
4951
.genreleases/spec-kit-template-kiro-cli-sh-"$VERSION".zip \
5052
.genreleases/spec-kit-template-kiro-cli-ps-"$VERSION".zip \
5153
.genreleases/spec-kit-template-agy-sh-"$VERSION".zip \

.github/workflows/scripts/create-release-packages.ps1

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
1515
.PARAMETER Agents
1616
Comma or space separated subset of agents to build (default: all)
17-
Valid agents: claude, gemini, copilot, cursor-agent, qwen, opencode, windsurf, codex, kilocode, auggie, roo, codebuddy, amp, kiro-cli, bob, qodercli, shai, agy, generic
17+
Valid agents: claude, gemini, copilot, cursor-agent, qwen, opencode, windsurf, codex, kilocode, auggie, roo, codebuddy, amp, kiro-cli, bob, qodercli, shai, tabnine, agy, generic
1818
1919
.PARAMETER Scripts
2020
Comma or space separated subset of script types to build (default: both)
@@ -351,6 +351,12 @@ function Build-Variant {
351351
$cmdDir = Join-Path $baseDir ".shai/commands"
352352
Generate-Commands -Agent 'shai' -Extension 'md' -ArgFormat '$ARGUMENTS' -OutputDir $cmdDir -ScriptVariant $Script
353353
}
354+
'tabnine' {
355+
$cmdDir = Join-Path $baseDir ".tabnine/agent/commands"
356+
Generate-Commands -Agent 'tabnine' -Extension 'toml' -ArgFormat '{{args}}' -OutputDir $cmdDir -ScriptVariant $Script
357+
$tabnineTemplate = Join-Path 'agent_templates' 'tabnine/TABNINE.md'
358+
if (Test-Path $tabnineTemplate) { Copy-Item $tabnineTemplate (Join-Path $baseDir 'TABNINE.md') }
359+
}
354360
'agy' {
355361
$cmdDir = Join-Path $baseDir ".agent/workflows"
356362
Generate-Commands -Agent 'agy' -Extension 'md' -ArgFormat '$ARGUMENTS' -OutputDir $cmdDir -ScriptVariant $Script
@@ -375,7 +381,7 @@ function Build-Variant {
375381
}
376382

377383
# Define all agents and scripts
378-
$AllAgents = @('claude', 'gemini', 'copilot', 'cursor-agent', 'qwen', 'opencode', 'windsurf', 'codex', 'kilocode', 'auggie', 'roo', 'codebuddy', 'amp', 'kiro-cli', 'bob', 'qodercli', 'shai', 'agy', 'vibe', 'generic')
384+
$AllAgents = @('claude', 'gemini', 'copilot', 'cursor-agent', 'qwen', 'opencode', 'windsurf', 'codex', 'kilocode', 'auggie', 'roo', 'codebuddy', 'amp', 'kiro-cli', 'bob', 'qodercli', 'shai', 'tabnine', 'agy', 'vibe', 'generic')
379385
$AllScripts = @('sh', 'ps')
380386

381387
function Normalize-List {

.github/workflows/scripts/create-release-packages.sh

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ set -euo pipefail
66
# Usage: .github/workflows/scripts/create-release-packages.sh <version>
77
# Version argument should include leading 'v'.
88
# Optionally set AGENTS and/or SCRIPTS env vars to limit what gets built.
9-
# AGENTS : space or comma separated subset of: claude gemini copilot cursor-agent qwen opencode windsurf codex kilocode auggie roo codebuddy amp shai kiro-cli agy bob qodercli generic (default: all)
9+
# AGENTS : space or comma separated subset of: claude gemini copilot cursor-agent qwen opencode windsurf codex kilocode auggie roo codebuddy amp shai tabnine kiro-cli agy bob qodercli generic (default: all)
1010
# SCRIPTS : space or comma separated subset of: sh ps (default: both)
1111
# Examples:
1212
# AGENTS=claude SCRIPTS=sh $0 v0.2.0
@@ -155,7 +155,7 @@ build_variant() {
155155

156156
# NOTE: We substitute {ARGS} internally. Outward tokens differ intentionally:
157157
# * Markdown/prompt (claude, copilot, cursor-agent, opencode): $ARGUMENTS
158-
# * TOML (gemini, qwen): {{args}}
158+
# * TOML (gemini, qwen, tabnine): {{args}}
159159
# This keeps formats readable without extra abstraction.
160160

161161
case $agent in
@@ -212,6 +212,10 @@ build_variant() {
212212
shai)
213213
mkdir -p "$base_dir/.shai/commands"
214214
generate_commands shai md "\$ARGUMENTS" "$base_dir/.shai/commands" "$script" ;;
215+
tabnine)
216+
mkdir -p "$base_dir/.tabnine/agent/commands"
217+
generate_commands tabnine toml "{{args}}" "$base_dir/.tabnine/agent/commands" "$script"
218+
[[ -f agent_templates/tabnine/TABNINE.md ]] && cp agent_templates/tabnine/TABNINE.md "$base_dir/TABNINE.md" ;;
215219
kiro-cli)
216220
mkdir -p "$base_dir/.kiro/prompts"
217221
generate_commands kiro-cli md "\$ARGUMENTS" "$base_dir/.kiro/prompts" "$script" ;;
@@ -233,7 +237,7 @@ build_variant() {
233237
}
234238

235239
# Determine agent list
236-
ALL_AGENTS=(claude gemini copilot cursor-agent qwen opencode windsurf codex kilocode auggie roo codebuddy amp shai kiro-cli agy bob vibe qodercli generic)
240+
ALL_AGENTS=(claude gemini copilot cursor-agent qwen opencode windsurf codex kilocode auggie roo codebuddy amp shai tabnine kiro-cli agy bob vibe qodercli generic)
237241
ALL_SCRIPTS=(sh ps)
238242

239243
norm_list() {

AGENTS.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ Specify supports multiple AI agents by generating agent-specific command files a
4747
| **Kiro CLI** | `.kiro/prompts/` | Markdown | `kiro-cli` | Kiro CLI |
4848
| **Amp** | `.agents/commands/` | Markdown | `amp` | Amp CLI |
4949
| **SHAI** | `.shai/commands/` | Markdown | `shai` | SHAI CLI |
50+
| **Tabnine CLI** | `.tabnine/agent/commands/` | TOML | `tabnine` | Tabnine CLI |
5051
| **IBM Bob** | `.bob/commands/` | Markdown | N/A (IDE-based) | IBM Bob IDE |
5152
| **Generic** | User-specified via `--ai-commands-dir` | Markdown | N/A | Bring your own agent |
5253

@@ -322,6 +323,7 @@ Require a command-line tool to be installed:
322323
- **Qoder CLI**: `qodercli` CLI
323324
- **Amp**: `amp` CLI
324325
- **SHAI**: `shai` CLI
326+
- **Tabnine CLI**: `tabnine` CLI
325327

326328
### IDE-Based Agents
327329

@@ -360,7 +362,7 @@ Command content with {SCRIPT} and $ARGUMENTS placeholders.
360362

361363
### TOML Format
362364

363-
Used by: Gemini, Qwen
365+
Used by: Gemini, Qwen, Tabnine
364366

365367
```toml
366368
description = "Command description"

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,12 @@ Recent changes to the Specify CLI and templates are documented here.
77
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
88
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
99

10+
## [0.1.14] - 2026-03-09
11+
12+
### Added
13+
14+
- feat: add Tabnine CLI agent support
15+
1016
## [0.1.13] - 2026-03-03
1117

1218
### Changed

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,7 @@ See Spec-Driven Development in action across different scenarios with these comm
177177
| [Qwen Code](https://github.com/QwenLM/qwen-code) || |
178178
| [Roo Code](https://roocode.com/) || |
179179
| [SHAI (OVHcloud)](https://github.com/ovh/shai) || |
180+
| [Tabnine CLI](https://docs.tabnine.com/main/getting-started/tabnine-cli) || |
180181
| [Mistral Vibe](https://github.com/mistralai/mistral-vibe) || |
181182
| [Windsurf](https://windsurf.com/) || |
182183
| [Antigravity (agy)](https://antigravity.google/) || |
@@ -420,7 +421,7 @@ specify init . --force --ai claude
420421
specify init --here --force --ai claude
421422
```
422423

423-
The CLI will check if you have Claude Code, Gemini CLI, Cursor CLI, Qwen CLI, opencode, Codex CLI, Qoder CLI, or Kiro CLI installed. If you do not, or you prefer to get the templates without checking for the right tools, use `--ignore-agent-tools` with your command:
424+
The CLI will check if you have Claude Code, Gemini CLI, Cursor CLI, Qwen CLI, opencode, Codex CLI, Qoder CLI, Tabnine CLI, or Kiro CLI installed. If you do not, or you prefer to get the templates without checking for the right tools, use `--ignore-agent-tools` with your command:
424425

425426
```bash
426427
specify init <project_name> --ai claude --ignore-agent-tools

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "specify-cli"
3-
version = "0.1.13"
3+
version = "0.1.14"
44
description = "Specify CLI, part of GitHub Spec Kit. A tool to bootstrap your projects for Spec-Driven Development (SDD)."
55
requires-python = ">=3.11"
66
dependencies = [

scripts/bash/update-agent-context.sh

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,12 @@
3030
#
3131
# 5. Multi-Agent Support
3232
# - Handles agent-specific file paths and naming conventions
33-
# - Supports: Claude, Gemini, Copilot, Cursor, Qwen, opencode, Codex, Windsurf, Kilo Code, Auggie CLI, Roo Code, CodeBuddy CLI, Qoder CLI, Amp, SHAI, Kiro CLI, Mistral Vibe or Antigravity
33+
# - Supports: Claude, Gemini, Copilot, Cursor, Qwen, opencode, Codex, Windsurf, Kilo Code, Auggie CLI, Roo Code, CodeBuddy CLI, Qoder CLI, Amp, SHAI, Tabnine CLI, Kiro CLI, Mistral Vibe or Antigravity
3434
# - Can update single agents or all existing agent files
3535
# - Creates default Claude file if no agent files exist
3636
#
3737
# Usage: ./update-agent-context.sh [agent_type]
38-
# Agent types: claude|gemini|copilot|cursor-agent|qwen|opencode|codex|windsurf|kilocode|auggie|roo|codebuddy|amp|shai|kiro-cli|agy|bob|qodercli
38+
# Agent types: claude|gemini|copilot|cursor-agent|qwen|opencode|codex|windsurf|kilocode|auggie|roo|codebuddy|amp|shai|tabnine|kiro-cli|agy|bob|vibe|qodercli|generic
3939
# Leave empty to update all existing agent files
4040

4141
set -e
@@ -73,6 +73,7 @@ CODEBUDDY_FILE="$REPO_ROOT/CODEBUDDY.md"
7373
QODER_FILE="$REPO_ROOT/QODER.md"
7474
AMP_FILE="$REPO_ROOT/AGENTS.md"
7575
SHAI_FILE="$REPO_ROOT/SHAI.md"
76+
TABNINE_FILE="$REPO_ROOT/TABNINE.md"
7677
KIRO_FILE="$REPO_ROOT/AGENTS.md"
7778
AGY_FILE="$REPO_ROOT/.agent/rules/specify-rules.md"
7879
BOB_FILE="$REPO_ROOT/AGENTS.md"
@@ -649,6 +650,9 @@ update_specific_agent() {
649650
shai)
650651
update_agent_file "$SHAI_FILE" "SHAI"
651652
;;
653+
tabnine)
654+
update_agent_file "$TABNINE_FILE" "Tabnine CLI"
655+
;;
652656
kiro-cli)
653657
update_agent_file "$KIRO_FILE" "Kiro CLI"
654658
;;
@@ -666,7 +670,7 @@ update_specific_agent() {
666670
;;
667671
*)
668672
log_error "Unknown agent type '$agent_type'"
669-
log_error "Expected: claude|gemini|copilot|cursor-agent|qwen|opencode|codex|windsurf|kilocode|auggie|roo|codebuddy|amp|shai|kiro-cli|agy|bob|vibe|qodercli|generic"
673+
log_error "Expected: claude|gemini|copilot|cursor-agent|qwen|opencode|codex|windsurf|kilocode|auggie|roo|codebuddy|amp|shai|tabnine|kiro-cli|agy|bob|vibe|qodercli|generic"
670674
exit 1
671675
;;
672676
esac
@@ -736,6 +740,11 @@ update_all_existing_agents() {
736740
found_agent=true
737741
fi
738742

743+
if [[ -f "$TABNINE_FILE" ]]; then
744+
update_agent_file "$TABNINE_FILE" "Tabnine CLI"
745+
found_agent=true
746+
fi
747+
739748
if [[ -f "$QODER_FILE" ]]; then
740749
update_agent_file "$QODER_FILE" "Qoder CLI"
741750
found_agent=true
@@ -783,7 +792,7 @@ print_summary() {
783792
fi
784793

785794
echo
786-
log_info "Usage: $0 [claude|gemini|copilot|cursor-agent|qwen|opencode|codex|windsurf|kilocode|auggie|roo|codebuddy|amp|shai|kiro-cli|agy|bob|qodercli|vibe]"
795+
log_info "Usage: $0 [claude|gemini|copilot|cursor-agent|qwen|opencode|codex|windsurf|kilocode|auggie|roo|codebuddy|amp|shai|tabnine|kiro-cli|agy|bob|vibe|qodercli]"
787796
}
788797

789798
#==============================================================================

scripts/powershell/update-agent-context.ps1

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ Mirrors the behavior of scripts/bash/update-agent-context.sh:
99
2. Plan Data Extraction
1010
3. Agent File Management (create from template or update existing)
1111
4. Content Generation (technology stack, recent changes, timestamp)
12-
5. Multi-Agent Support (claude, gemini, copilot, cursor-agent, qwen, opencode, codex, windsurf, kilocode, auggie, roo, codebuddy, amp, shai, kiro-cli, agy, bob, qodercli, vibe)
12+
5. Multi-Agent Support (claude, gemini, copilot, cursor-agent, qwen, opencode, codex, windsurf, kilocode, auggie, roo, codebuddy, amp, shai, tabnine, kiro-cli, agy, bob, vibe, qodercli)
1313
1414
.PARAMETER AgentType
1515
Optional agent key to update a single agent. If omitted, updates all existing agent files (creating a default Claude file if none exist).
@@ -25,7 +25,7 @@ Relies on common helper functions in common.ps1
2525
#>
2626
param(
2727
[Parameter(Position=0)]
28-
[ValidateSet('claude','gemini','copilot','cursor-agent','qwen','opencode','codex','windsurf','kilocode','auggie','roo','codebuddy','amp','shai','kiro-cli','agy','bob','qodercli','vibe','generic')]
28+
[ValidateSet('claude','gemini','copilot','cursor-agent','qwen','opencode','codex','windsurf','kilocode','auggie','roo','codebuddy','amp','shai','tabnine','kiro-cli','agy','bob','qodercli','vibe','generic')]
2929
[string]$AgentType
3030
)
3131

@@ -58,6 +58,7 @@ $CODEBUDDY_FILE = Join-Path $REPO_ROOT 'CODEBUDDY.md'
5858
$QODER_FILE = Join-Path $REPO_ROOT 'QODER.md'
5959
$AMP_FILE = Join-Path $REPO_ROOT 'AGENTS.md'
6060
$SHAI_FILE = Join-Path $REPO_ROOT 'SHAI.md'
61+
$TABNINE_FILE = Join-Path $REPO_ROOT 'TABNINE.md'
6162
$KIRO_FILE = Join-Path $REPO_ROOT 'AGENTS.md'
6263
$AGY_FILE = Join-Path $REPO_ROOT '.agent/rules/specify-rules.md'
6364
$BOB_FILE = Join-Path $REPO_ROOT 'AGENTS.md'
@@ -400,12 +401,13 @@ function Update-SpecificAgent {
400401
'qodercli' { Update-AgentFile -TargetFile $QODER_FILE -AgentName 'Qoder CLI' }
401402
'amp' { Update-AgentFile -TargetFile $AMP_FILE -AgentName 'Amp' }
402403
'shai' { Update-AgentFile -TargetFile $SHAI_FILE -AgentName 'SHAI' }
404+
'tabnine' { Update-AgentFile -TargetFile $TABNINE_FILE -AgentName 'Tabnine CLI' }
403405
'kiro-cli' { Update-AgentFile -TargetFile $KIRO_FILE -AgentName 'Kiro CLI' }
404406
'agy' { Update-AgentFile -TargetFile $AGY_FILE -AgentName 'Antigravity' }
405407
'bob' { Update-AgentFile -TargetFile $BOB_FILE -AgentName 'IBM Bob' }
406408
'vibe' { Update-AgentFile -TargetFile $VIBE_FILE -AgentName 'Mistral Vibe' }
407409
'generic' { Write-Info 'Generic agent: no predefined context file. Use the agent-specific update script for your agent.' }
408-
default { Write-Err "Unknown agent type '$Type'"; Write-Err 'Expected: claude|gemini|copilot|cursor-agent|qwen|opencode|codex|windsurf|kilocode|auggie|roo|codebuddy|amp|shai|kiro-cli|agy|bob|qodercli|vibe|generic'; return $false }
410+
default { Write-Err "Unknown agent type '$Type'"; Write-Err 'Expected: claude|gemini|copilot|cursor-agent|qwen|opencode|codex|windsurf|kilocode|auggie|roo|codebuddy|amp|shai|tabnine|kiro-cli|agy|bob|vibe|qodercli|generic'; return $false }
409411
}
410412
}
411413

@@ -425,6 +427,7 @@ function Update-AllExistingAgents {
425427
if (Test-Path $CODEBUDDY_FILE) { if (-not (Update-AgentFile -TargetFile $CODEBUDDY_FILE -AgentName 'CodeBuddy CLI')) { $ok = $false }; $found = $true }
426428
if (Test-Path $QODER_FILE) { if (-not (Update-AgentFile -TargetFile $QODER_FILE -AgentName 'Qoder CLI')) { $ok = $false }; $found = $true }
427429
if (Test-Path $SHAI_FILE) { if (-not (Update-AgentFile -TargetFile $SHAI_FILE -AgentName 'SHAI')) { $ok = $false }; $found = $true }
430+
if (Test-Path $TABNINE_FILE) { if (-not (Update-AgentFile -TargetFile $TABNINE_FILE -AgentName 'Tabnine CLI')) { $ok = $false }; $found = $true }
428431
if (Test-Path $KIRO_FILE) { if (-not (Update-AgentFile -TargetFile $KIRO_FILE -AgentName 'Kiro CLI')) { $ok = $false }; $found = $true }
429432
if (Test-Path $AGY_FILE) { if (-not (Update-AgentFile -TargetFile $AGY_FILE -AgentName 'Antigravity')) { $ok = $false }; $found = $true }
430433
if (Test-Path $BOB_FILE) { if (-not (Update-AgentFile -TargetFile $BOB_FILE -AgentName 'IBM Bob')) { $ok = $false }; $found = $true }
@@ -443,7 +446,7 @@ function Print-Summary {
443446
if ($NEW_FRAMEWORK) { Write-Host " - Added framework: $NEW_FRAMEWORK" }
444447
if ($NEW_DB -and $NEW_DB -ne 'N/A') { Write-Host " - Added database: $NEW_DB" }
445448
Write-Host ''
446-
Write-Info 'Usage: ./update-agent-context.ps1 [-AgentType claude|gemini|copilot|cursor-agent|qwen|opencode|codex|windsurf|kilocode|auggie|roo|codebuddy|amp|shai|kiro-cli|agy|bob|qodercli|vibe|generic]'
449+
Write-Info 'Usage: ./update-agent-context.ps1 [-AgentType claude|gemini|copilot|cursor-agent|qwen|opencode|codex|windsurf|kilocode|auggie|roo|codebuddy|amp|shai|tabnine|kiro-cli|agy|bob|vibe|qodercli|generic]'
447450
}
448451

449452
function Main {

src/specify_cli/__init__.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,13 @@ def _format_rate_limit_error(status_code: int, headers: httpx.Headers, url: str)
237237
"install_url": "https://github.com/ovh/shai",
238238
"requires_cli": True,
239239
},
240+
"tabnine": {
241+
"name": "Tabnine CLI",
242+
"folder": ".tabnine/agent/",
243+
"commands_subdir": "commands",
244+
"install_url": "https://docs.tabnine.com/main/getting-started/tabnine-cli",
245+
"requires_cli": True,
246+
},
240247
"agy": {
241248
"name": "Antigravity",
242249
"folder": ".agent/",
@@ -1124,7 +1131,7 @@ def install_ai_skills(project_path: Path, selected_ai: str, tracker: StepTracker
11241131
if not templates_dir.exists() or not any(templates_dir.glob("*.md")):
11251132
# Fallback: try the repo-relative path (for running from source checkout)
11261133
# This also covers agents whose extracted commands are in a different
1127-
# format (e.g. gemini uses .toml, not .md).
1134+
# format (e.g. gemini/tabnine use .toml, not .md).
11281135
script_dir = Path(__file__).parent.parent.parent # up from src/specify_cli/
11291136
fallback_dir = script_dir / "templates" / "commands"
11301137
if fallback_dir.exists() and any(fallback_dir.glob("*.md")):

0 commit comments

Comments
 (0)