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
2 changes: 1 addition & 1 deletion .github/ISSUE_TEMPLATE/agent_request.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ body:
value: |
Thanks for requesting a new agent! Before submitting, please check if the agent is already supported.

**Currently supported agents**: Alquimia AI, Amp, Antigravity, Auggie CLI, Claude Code, Cline, CodeBuddy, Codex CLI, Command Code, Cursor, Devin for Terminal, Factory Droid, Firebender, Forge, Gemini CLI, GitHub Copilot, Goose, Grok Build, Hermes Agent, IBM Bob, Junie, Kilo Code, Kimi Code, Kiro CLI, Lingma, Mistral Vibe, Oh My Pi, opencode, Pi Coding Agent, Qoder CLI, Qwen Code, RovoDev ACLI, SHAI, Tabnine CLI, Trae, ZCode, Zed
**Currently supported agents**: Alquimia AI, Amp, Antigravity, Auggie CLI, Claude Code, Cline, CodeBuddy, Codex CLI, Command Code, Cursor, Devin for Terminal, Factory Droid, DeepSeek Harness, Firebender, Forge, Gemini CLI, GitHub Copilot, Goose, Grok Build, Hermes Agent, IBM Bob, Junie, Kilo Code, Kimi Code, Kiro CLI, Lingma, Mistral Vibe, Oh My Pi, opencode, Pi Coding Agent, Qoder CLI, Qwen Code, RovoDev ACLI, SHAI, Tabnine CLI, Trae, ZCode, Zed

- type: input
id: agent-name
Expand Down
1 change: 1 addition & 0 deletions .github/ISSUE_TEMPLATE/bug_report.yml
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ body:
- Cursor
- Devin for Terminal
- Factory Droid
- DeepSeek Harness
- Firebender
- Forge
- Gemini CLI
Expand Down
1 change: 1 addition & 0 deletions .github/ISSUE_TEMPLATE/feature_request.yml
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ body:
- Cursor
- Devin for Terminal
- Factory Droid
- DeepSeek Harness
- Firebender
- Forge
- Gemini CLI
Expand Down
1 change: 1 addition & 0 deletions docs/reference/integrations.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ The Specify CLI supports a wide range of AI coding agents. When you run `specify
| [Codex CLI](https://github.com/openai/codex) | `codex` | Skills-based integration; installs skills into `.agents/skills` and invokes them as `$speckit-<command>` |
| [Command Code](https://commandcode.ai/docs) | `command-code` | Skills-based integration; installs skills into `.commandcode/skills/` and invokes them as `$speckit-<command>` |
| [Cursor](https://cursor.sh/) | `cursor-agent` | |
| [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) | `dsh` | Skills-based integration; installs skills into `.dsh/skills` and invokes them as `/speckit-<command>` |
| [Devin for Terminal](https://cli.devin.ai/docs) | `devin` | Skills-based integration; installs skills into `.devin/skills/` and invokes them as `/speckit-<command>` |
| [Factory Droid](https://docs.factory.ai/cli/getting-started/overview) | `droid` | Skills-based integration; installs skills into `.factory/skills/` and invokes them as `/speckit-<command>` |
| [Firebender](https://firebender.com/) | `firebender` | IDE-based agent for Android Studio / IntelliJ |
Expand Down
9 changes: 9 additions & 0 deletions integrations/catalog.json
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,15 @@
"repository": "https://github.com/github/spec-kit",
"tags": ["cli", "skills", "factory"]
},
"dsh": {
"id": "dsh",
"name": "DeepSeek Harness",
"version": "1.0.0",
"description": "DeepSeek Harness (DSH) CLI skills-based integration",
"author": "spec-kit-core",
"repository": "https://github.com/github/spec-kit",
"tags": ["cli", "skills"]
},
"amp": {
"id": "amp",
"name": "Amp",
Expand Down
2 changes: 1 addition & 1 deletion src/specify_cli/_invocation_style.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

# Agents that always render /speckit-<name>, regardless of ai_skills.
ALWAYS_SLASH_AGENTS: frozenset[str] = frozenset(
{"devin", "droid", "grok", "qodercli", "trae", "zed"}
{"devin", "droid", "dsh", "grok", "qodercli", "trae", "zed"}
)

# Agents that render /speckit-<name> only when ai_skills is enabled.
Expand Down
7 changes: 7 additions & 0 deletions src/specify_cli/commands/init.py
Original file line number Diff line number Diff line change
Expand Up @@ -1013,6 +1013,7 @@ def init(
devin_skill_mode = selected_ai == "devin"
zed_skill_mode = selected_ai == "zed" and _is_skills_integration
grok_skill_mode = selected_ai == "grok" and _is_skills_integration
dsh_skill_mode = selected_ai == "dsh" and _is_skills_integration
cline_skill_mode = selected_ai == "cline"
forge_skill_mode = selected_ai == "forge"
bob_skill_mode = selected_ai == "bob" and _is_skills_integration
Expand All @@ -1028,6 +1029,7 @@ def init(
or devin_skill_mode
or zed_skill_mode
or grok_skill_mode
or dsh_skill_mode
or bob_skill_mode
)

Expand Down Expand Up @@ -1066,6 +1068,11 @@ def init(
f"{step_num}. Start Grok Build in this project directory; spec-kit skills were installed to [cyan].grok/skills[/cyan]"
)
step_num += 1
if dsh_skill_mode:
steps_lines.append(
f"{step_num}. Start DSH ([cyan]dsh web[/cyan]) in this project directory; spec-kit skills were installed to [cyan].dsh/skills[/cyan]"
)
step_num += 1
if bob_skill_mode:
steps_lines.append(
f"{step_num}. Start Bob in this project directory; spec-kit skills were installed to [cyan].bob/skills[/cyan]"
Expand Down
2 changes: 2 additions & 0 deletions src/specify_cli/integrations/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ def _register_builtins() -> None:
from .cursor_agent import CursorAgentIntegration
from .devin import DevinIntegration
from .droid import DroidIntegration
from .dsh import DshIntegration
from .firebender import FirebenderIntegration
from .forge import ForgeIntegration
from .gemini import GeminiIntegration
Expand Down Expand Up @@ -101,6 +102,7 @@ def _register_builtins() -> None:
_register(CursorAgentIntegration())
_register(DevinIntegration())
_register(DroidIntegration())
_register(DshIntegration())
_register(FirebenderIntegration())
_register(ForgeIntegration())
_register(GeminiIntegration())
Expand Down
63 changes: 63 additions & 0 deletions src/specify_cli/integrations/dsh/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
"""DeepSeek Harness (DSH) integration — skills-based agent.

DSH discovers project skills from ``.dsh/skills`` (its native root, highest
provider rank) and from the shared ``.agents/skills`` root, one level deep,
using ``<name>/SKILL.md`` directory bundles with ``name``/``description``
frontmatter — the same agentskills.io layout Spec Kit scaffolds for other
skills-based agents. Skills are user-invocable through the ``/``-trigger
input in the DSH Web GUI (and any TUI/ACP front end): typing
``/speckit-specify <feature description>`` ships the literal token plus the
user text, and the harness injects the skill's ``<skill_content>`` into the
turn. Project guidance in ``AGENTS.md`` at the repo root is loaded
automatically by DSH, so no context-file handling is needed here.

See: https://github.com/deepseek-ai/deepseek-harness
"""

from __future__ import annotations

from ..base import SkillsIntegration


class DshIntegration(SkillsIntegration):
"""Integration for the DeepSeek Harness (DSH) agent."""

key = "dsh"
config = {
"name": "DeepSeek Harness",
"folder": ".dsh/",
"commands_subdir": "skills",
"install_url": "https://github.com/deepseek-ai/deepseek-harness",
"requires_cli": True,
}
registrar_config = {
"dir": ".dsh/skills",
"format": "markdown",
"args": "$ARGUMENTS",
"extension": "/SKILL.md",
}
# ``.dsh/`` is a static, unique agent root that no other integration
# writes into, so co-installing DSH alongside other agents is safe.
multi_install_safe = True

def build_exec_args(
self,
prompt: str,
*,
model: str | None = None,
output_json: bool = True,
) -> list[str] | None:
"""Build non-interactive CLI args for DSH.

DSH's one-shot mode is ``dsh --profile headless "<task>"``: the
runner submits the task as an ordinary user message, waits for
quiescence, and prints the last assistant message to stdout. The
headless profile recognizes whitespace-bounded ``/name`` tokens
naming user-invocable skills, so a slash-command prompt such as
``/speckit-specify build photo albums`` loads the skill exactly as
an interactive session would. The CLI has no structured-JSON output
flag, so ``output_json`` and ``model`` are ignored.
"""
args = [self._resolve_executable(), "--profile", "headless", prompt]
self._apply_extra_args_env_var(args)
return args
Loading