Tripo3D-Plugin-dsh
Tripo 3D plugin for DeepSeek Harness (dsh): text/image → textured, rig-ready 3D assets via tripo-cli
- Stars
- 5
- Language
- JavaScript
- Created
- Sep 7, 2026
- Updated
- Oct 21, 2026
Introduction
Tripo 3D for DeepSeek Harness
A skills-only plugin for DeepSeek Harness (dsh). It gives the dsh agent Tripo's 3D generation
as two skills; the agent drives tripo-cli through its
shell tool, and the generated models land directly in the user's project.
npm tripo-dsh · zero dependencies · pure ESM ·
no build step · both Tripo regions (China mainland and international)
user DeepSeek Harness (dsh) this plugin Tripo
──── ────────────────────── ─────────── ─────
"make a low-poly treasure chest"
│
▼
┌──────────┐ catalog lists tripo-3d ┌────────────────────────┐
│ agent │ ◀── name + description ─────────────── │ index.js │
│ (model) │ │ ctx.skills │
│ │ ── skill tool loads the body ────────▶ │ .registerProvider() │
│ │ ◀── SKILL.md body ──────────────────── │ skills/*/SKILL.md │
│ │ └────────────────────────┘
│ │
│ │ ── shell: tripo make "..." --json --yes ──────────────────────▶ ┌─────────┐
│ │ (blocking: submit, poll, download) │ Tripo │
│ │ ◀── last stdout line = result JSON, plus exit code ─────────── │ API │
└──────────┘ │ cn / ov │
│ └─────────┘
▼
./tripo-out/<name>-<id8>/model.glb preview.png task.json (already on the user's disk)
Runtime behavior (setup, device login, plan and confirmation, exit codes, result JSON, credit
rules) is documented once, in plugin/skills/tripo-3d/SKILL.md.
This README covers the repository, installation, development, release and design.
Repository layout
Tripo3D-Plugin-dsh/
├── plugin/ npm package tripo-dsh, the only distributable
│ ├── package.json dsh.bundle manifest and "files" allowlist
│ ├── cordis.patch.yml bundle layer: inserts one row that loads index.js
│ ├── index.js SkillProvider: reads the SKILL.md files, registers on ctx.skills
│ ├── README.md npm page for end users
│ └── skills/
│ ├── tripo-3d/
│ │ ├── SKILL.md base skill: setup, login, plan, run, credits, results
│ │ └── references/
│ │ └── capability.md models, parameters, steps, other commands (loaded on demand)
│ └── tripo-game-asset/
│ └── SKILL.md game recipes on top of tripo-3d
├── scripts/validate.mjs static checks plus a provider smoke test
├── .github/workflows/publish.yml validates on push and PR; publishes v* tags to npm (OIDC)
└── README.md this file
Only plugin/ is published; its files allowlist keeps everything else out of the package.
Install and verify
# From npm
dsh plugin --profile web add tripo-dsh
# From GitHub (the package lives in plugin/; pnpm path: syntax; no build script, so no build allowance)
dsh plugin --profile web add "github:Tripo-Developer/Tripo3D-Plugin-dsh#path:/plugin"
# From a local checkout (development; pnpm link, so skill edits apply immediately)
dsh plugin --profile web add /path/to/Tripo3D-Plugin-dsh/plugin
Three checks; the first two spend no credits:
# 1. The configuration layer is composed (no boot)
dsh --profile web --dump-config # shows a "# == tripo-dsh" layer
# 2. Both skills are in the catalog
dsh web # type / in the input box: tripo-3d and tripo-game-asset
# 3. End to end (spends real credits)
# Ask the agent: "make a low-poly treasure chest 3D model and export FBX"
# Expected: doctor, device login if needed, a plan to confirm, tripo make, preview.png
--profile and --patch are launcher flags and must come before app arguments such as web.
Development
- Edit files under
plugin/. Agent behavior lives in the skills: changeSKILL.mdorreferences/capability.md, not this README. - Run
node scripts/validate.mjs(Node.js 18 or later, nothing to install). CI runs the same script on every push tomaster, every pull request and every tag. - Try the change in dsh from a local checkout. Skill edits apply immediately; restart dsh after
changing
cordis.patch.ymlorpackage.json. - When
tripo-clichanges a flag or behavior the skills rely on, update the skills and bumpversioninplugin/package.jsonin the same change.
Release
The package tripo-dsh is published by GitHub Actions
through npm trusted publishing (OIDC, no token). One-time prerequisite: on npmjs.com, open the
package's Settings -> Trusted Publisher and bind Organization Tripo-Developer, Repository
Tripo3D-Plugin-dsh, Workflow publish.yml, Environment empty. Keep at least two package owners
(npm owner add <user> tripo-dsh).
To release, bump version in plugin/package.json, commit, and push a matching tag:
git tag v<version> && git push origin v<version>
publish.yml validates the plugin, checks that the tag matches
the package version, and runs npm publish; npm attaches provenance automatically.
Design notes
Why skills-only
A dsh plugin can register tools, connect MCP servers or add hooks. This plugin registers skills only, because the work splits cleanly:
tripo-cliowns the API contract: auth, region detection, task polling, downloads, exit codes and the--jsonstdout line. It runs throughnpx, so nothing is preinstalled.- The skills own the operating manual: when to use Tripo, what to run first, how to branch on results, how to spend the user's credits and how to present the result.
- dsh puts the skills in the model-visible catalog and provides the shell tool and sandbox.
As a result the plugin has no API code: when the CLI contract changes, update the skill text and bump the version. The agent uses the shell tool it already has, so no tool schema is added to every request, and a skill body enters the context only when the model selects that skill. The CLI's exit codes and final JSON stdout line are the protocol. The cost is that login and generation need a shell and network access, so every skill tells the agent to report honestly when either is unavailable.
How dsh loads the plugin
The runnable unit in dsh is a profile, composed from the configuration layers of its bundles in order. This package is one bundle:
plugin/package.json "dsh": { "bundle": { "patch": "./cordis.patch.yml" } } contributes a layer
plugin/cordis.patch.yml insert row { id: tripo-3d, name: 'tripo-dsh' } resolved by package name
plugin/index.js inject = ['skills']; apply(ctx) registers a SkillProvider on ctx.skills
dsh plugin --profile <name> add tripo-dsh installs the package into $DSH_HOME/profiles/<name>/
with pnpm and appends it to dsh.profile.bundles. On every boot the layers apply in this order:
@deepseek-ai/dsh-base(official base layer)@deepseek-ai/dsh-web-app(web profile only)tripo-dsh(this plugin, inserts one row)- the profile's own
cordis.patch.yml(user overrides) $DSH_HOME/cordis.patch.yml(machine-level overrides)--patch <file>overlays from the command line
Later layers override rows by id, so a user can disable this plugin by overriding the
tripo-3d row in their own cordis.patch.yml instead of uninstalling it.
The provider in index.js implements list() and get() of the dsh skills contract:
rank: 600mirrorsBUNDLED_SKILL_RANKin@deepseek-ai/dsh-skill. Within one layer the lower rank wins a duplicate name (project.dsh/skills100, project.agents/skills200, user-level 400 and 500, bundled 600), so a project can overridetripo-3dwith its own copy.source: 'bundled'follows the official skill-badge provider; the catalog showstripo-3d[bundled].resourceBasepoints at the skill directory, so theskilltool can load explicitly linked files such asreferences/capability.mdon demand.- The files are reread on every
list()andget(); dsh caches catalogs itself, and edits show up without a stale provider cache. - The skills registry lives at host level, so the provider registers globally and every agent
preset (
cordis,ptc,standard) sees the skills.
The model sees only each skill's name and description in the catalog and loads the body
through the skill tool when it decides the skill is relevant. The description is therefore the
only trigger surface, and dsh truncates it at catalogDescriptionMaxLength (500 characters by
default). The descriptions say "in any language" so that requests written in Chinese still select
the skills.
Hard constraints
scripts/validate.mjs enforces these; run it after every change.
- No
dependencies,devDependencies,peerDependenciesorscriptsinpackage.json. A git install fetches sources and runs no build; apreparescript would hit pnpm 10's build-permission gate and ask users to trust install-time code. With zero dependencies, npm, tarball, directory and git installs all work without any permission. - Pure ESM,
main: index.js, no TypeScript. Without build output there is no "source installed butlib/missing" failure. rankis the literal 600, not an import from@deepseek-ai/dsh-skill, to stay dependency-free. A change ofBUNDLED_SKILL_RANKwould be a dsh breaking change; sync it by hand.- Skill names are kebab-case and equal their directory names; the dsh registry fails fast on malformed candidates.
- Descriptions are single-line plain values of at most 500 characters after whitespace
normalization:
index.jsreads one line, and dsh truncates longer catalog entries. - A
SKILL.mdhas at most 500 lines; reference material goes into the skill'sreferences/directory, and relative links must resolve insideplugin/. - Every skill keeps the "cannot execute shell commands" clause; dsh sessions may run without network access or in a restricted sandbox.
- Both skills carry the DeepSeek attribution values (
TRIPO_CLIENT_APP=deepseek,TRIPO_DISTRIBUTION_CHANNEL=deepseek_plugin) and no other platform's values. tripo-3dnames both region consoles and keeps the npmmirror hint for China-mainland networks.- Skill files contain no local paths and no leftover names of other agent products; the text is ported from sister projects.
- No Chinese characters or full-width punctuation anywhere in the repository.
- The patch row has only
idandname; the plugin has no config schema.
Besides the static checks, the validator imports plugin/index.js, drives
registerProvider → list() → get() with a fake ctx, and asserts the candidate shape (rank,
source, invocation, resourceBase) and that the body has its frontmatter stripped.
Regions and attribution
Tripo runs two independent sites; accounts, consoles and payment methods do not carry over:
cn: https://developers.tripo3d.com, +86 SMS sign-in, Alipay top-upov: https://developers.tripo3d.ai, email sign-in, Stripe top-up
Most DeepSeek users are in mainland China, so both regions are a hard requirement. The skill asks
which site the account is on before starting a device login, because a device flow on the wrong
console sends the user to a site without their account. A wrong region is recoverable: the CLI
probes both regions when it verifies a key, and tripo doctor reports a key-versus-region
mismatch with the fix. When npx stalls on a China-mainland network, the skill switches to the
npmmirror registry.
Both skills set TRIPO_CLIENT_APP=deepseek and TRIPO_DISTRIBUTION_CHANNEL=deepseek_plugin on
every CLI call. The values carry no user data; the CLI's usage analytics read them, and
TRIPO_ANALYTICS_ENABLED=0 turns the analytics off. As of tripo-cli 0.7.1:
- analytics run only for
ovcalls, socnusage is never attributed; - since 0.7.1,
ovevents also carry the user's Tripo account id, looked up throughPOST https://apiplatform.tripo3d.ai/verify(the opt-out skips that lookup); - the CLI only recognizes
codex,workbuddy,zcodeandkimi(with their*_pluginchannels) and records any other value, includingdeepseek/deepseek_plugin, asunknown.
DeepSeek usage is therefore not attributed in either region until the CLI adds these values.
Related
tripo-cli: the CLI the skills drive and the authority on the command contract;tripo docs --topic commands/makeprints the flag reference.- DeepSeek Harness:
docs/user/develop/basic/publish.md(bundles, profiles, layer order),docs/subsystems/skills.md(provider contract, rank, catalog behavior),packages/experimental/skill-badge(the official bundled-skill example). - Discovery: GitHub topic
dsh-plugin.
License
MIT