Skip to content

Commit 997bfec

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 d0ff0f4 commit 997bfec

File tree

12 files changed

+118
-17
lines changed

12 files changed

+118
-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
@@ -371,7 +377,7 @@ function Build-Variant {
371377
}
372378

373379
# Define all agents and scripts
374-
$AllAgents = @('claude', 'gemini', 'copilot', 'cursor-agent', 'qwen', 'opencode', 'windsurf', 'codex', 'kilocode', 'auggie', 'roo', 'codebuddy', 'amp', 'kiro-cli', 'bob', 'qodercli', 'shai', 'agy', 'generic')
380+
$AllAgents = @('claude', 'gemini', 'copilot', 'cursor-agent', 'qwen', 'opencode', 'windsurf', 'codex', 'kilocode', 'auggie', 'roo', 'codebuddy', 'amp', 'kiro-cli', 'bob', 'qodercli', 'shai', 'tabnine', 'agy', 'generic')
375381
$AllScripts = @('sh', 'ps')
376382

377383
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" ;;
@@ -230,7 +234,7 @@ build_variant() {
230234
}
231235

232236
# Determine agent list
233-
ALL_AGENTS=(claude gemini copilot cursor-agent qwen opencode windsurf codex kilocode auggie roo codebuddy amp shai kiro-cli agy bob qodercli generic)
237+
ALL_AGENTS=(claude gemini copilot cursor-agent qwen opencode windsurf codex kilocode auggie roo codebuddy amp shai tabnine kiro-cli agy bob qodercli generic)
234238
ALL_SCRIPTS=(sh ps)
235239

236240
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 (Gemini fork) |
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 (Gemini fork using TOML commands, `.tabnine/agent/` directory)
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
@@ -171,6 +171,7 @@ See Spec-Driven Development in action across different scenarios with these comm
171171
| [Qwen Code](https://github.com/QwenLM/qwen-code) || |
172172
| [Roo Code](https://roocode.com/) || |
173173
| [SHAI (OVHcloud)](https://github.com/ovh/shai) || |
174+
| [Tabnine CLI](https://docs.tabnine.com/main/getting-started/tabnine-cli) || |
174175
| [Windsurf](https://windsurf.com/) || |
175176
| [Antigravity (agy)](https://antigravity.google/) || |
176177
| Generic || Bring your own agent — use `--ai generic --ai-commands-dir <path>` for unsupported agents |
@@ -410,7 +411,7 @@ specify init . --force --ai claude
410411
specify init --here --force --ai claude
411412
```
412413

413-
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:
414+
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:
414415

415416
```bash
416417
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, 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, 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|qodercli
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"
@@ -648,6 +649,9 @@ update_specific_agent() {
648649
shai)
649650
update_agent_file "$SHAI_FILE" "SHAI"
650651
;;
652+
tabnine)
653+
update_agent_file "$TABNINE_FILE" "Tabnine CLI"
654+
;;
651655
kiro-cli)
652656
update_agent_file "$KIRO_FILE" "Kiro CLI"
653657
;;
@@ -662,7 +666,7 @@ update_specific_agent() {
662666
;;
663667
*)
664668
log_error "Unknown agent type '$agent_type'"
665-
log_error "Expected: claude|gemini|copilot|cursor-agent|qwen|opencode|codex|windsurf|kilocode|auggie|roo|codebuddy|amp|shai|kiro-cli|agy|bob|qodercli|generic"
669+
log_error "Expected: claude|gemini|copilot|cursor-agent|qwen|opencode|codex|windsurf|kilocode|auggie|roo|codebuddy|amp|shai|tabnine|kiro-cli|agy|bob|qodercli|generic"
666670
exit 1
667671
;;
668672
esac
@@ -732,6 +736,11 @@ update_all_existing_agents() {
732736
found_agent=true
733737
fi
734738

739+
if [[ -f "$TABNINE_FILE" ]]; then
740+
update_agent_file "$TABNINE_FILE" "Tabnine CLI"
741+
found_agent=true
742+
fi
743+
735744
if [[ -f "$QODER_FILE" ]]; then
736745
update_agent_file "$QODER_FILE" "Qoder CLI"
737746
found_agent=true
@@ -775,7 +784,7 @@ print_summary() {
775784

776785
echo
777786

778-
log_info "Usage: $0 [claude|gemini|copilot|cursor-agent|qwen|opencode|codex|windsurf|kilocode|auggie|roo|codebuddy|amp|shai|kiro-cli|agy|bob|qodercli]"
787+
log_info "Usage: $0 [claude|gemini|copilot|cursor-agent|qwen|opencode|codex|windsurf|kilocode|auggie|roo|codebuddy|amp|shai|tabnine|kiro-cli|agy|bob|qodercli]"
779788
}
780789

781790
#==============================================================================

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)
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, 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','generic')]
28+
[ValidateSet('claude','gemini','copilot','cursor-agent','qwen','opencode','codex','windsurf','kilocode','auggie','roo','codebuddy','amp','shai','tabnine','kiro-cli','agy','bob','qodercli','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'
@@ -399,11 +400,12 @@ function Update-SpecificAgent {
399400
'qodercli' { Update-AgentFile -TargetFile $QODER_FILE -AgentName 'Qoder CLI' }
400401
'amp' { Update-AgentFile -TargetFile $AMP_FILE -AgentName 'Amp' }
401402
'shai' { Update-AgentFile -TargetFile $SHAI_FILE -AgentName 'SHAI' }
403+
'tabnine' { Update-AgentFile -TargetFile $TABNINE_FILE -AgentName 'Tabnine CLI' }
402404
'kiro-cli' { Update-AgentFile -TargetFile $KIRO_FILE -AgentName 'Kiro CLI' }
403405
'agy' { Update-AgentFile -TargetFile $AGY_FILE -AgentName 'Antigravity' }
404406
'bob' { Update-AgentFile -TargetFile $BOB_FILE -AgentName 'IBM Bob' }
405407
'generic' { Write-Info 'Generic agent: no predefined context file. Use the agent-specific update script for your agent.' }
406-
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|generic'; return $false }
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|tabnine|kiro-cli|agy|bob|qodercli|generic'; return $false }
407409
}
408410
}
409411

@@ -423,6 +425,7 @@ function Update-AllExistingAgents {
423425
if (Test-Path $CODEBUDDY_FILE) { if (-not (Update-AgentFile -TargetFile $CODEBUDDY_FILE -AgentName 'CodeBuddy CLI')) { $ok = $false }; $found = $true }
424426
if (Test-Path $QODER_FILE) { if (-not (Update-AgentFile -TargetFile $QODER_FILE -AgentName 'Qoder CLI')) { $ok = $false }; $found = $true }
425427
if (Test-Path $SHAI_FILE) { if (-not (Update-AgentFile -TargetFile $SHAI_FILE -AgentName 'SHAI')) { $ok = $false }; $found = $true }
428+
if (Test-Path $TABNINE_FILE) { if (-not (Update-AgentFile -TargetFile $TABNINE_FILE -AgentName 'Tabnine CLI')) { $ok = $false }; $found = $true }
426429
if (Test-Path $KIRO_FILE) { if (-not (Update-AgentFile -TargetFile $KIRO_FILE -AgentName 'Kiro CLI')) { $ok = $false }; $found = $true }
427430
if (Test-Path $AGY_FILE) { if (-not (Update-AgentFile -TargetFile $AGY_FILE -AgentName 'Antigravity')) { $ok = $false }; $found = $true }
428431
if (Test-Path $BOB_FILE) { if (-not (Update-AgentFile -TargetFile $BOB_FILE -AgentName 'IBM Bob')) { $ok = $false }; $found = $true }
@@ -440,7 +443,7 @@ function Print-Summary {
440443
if ($NEW_FRAMEWORK) { Write-Host " - Added framework: $NEW_FRAMEWORK" }
441444
if ($NEW_DB -and $NEW_DB -ne 'N/A') { Write-Host " - Added database: $NEW_DB" }
442445
Write-Host ''
443-
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|generic]'
446+
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|qodercli|generic]'
444447
}
445448

446449
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/",
@@ -1117,7 +1124,7 @@ def install_ai_skills(project_path: Path, selected_ai: str, tracker: StepTracker
11171124
if not templates_dir.exists() or not any(templates_dir.glob("*.md")):
11181125
# Fallback: try the repo-relative path (for running from source checkout)
11191126
# This also covers agents whose extracted commands are in a different
1120-
# format (e.g. gemini uses .toml, not .md).
1127+
# format (e.g. gemini/tabnine use .toml, not .md).
11211128
script_dir = Path(__file__).parent.parent.parent # up from src/specify_cli/
11221129
fallback_dir = script_dir / "templates" / "commands"
11231130
if fallback_dir.exists() and any(fallback_dir.glob("*.md")):

0 commit comments

Comments
 (0)