dsh-plugin
DayuanJiang/next-ai-draw-iodsh 的 draw.io 绘图插件:通过 next-ai-drawio MCP 服务器作图,点回复里的链接在右侧栏打开实时预览,可以手动修改图,AI 的每次修改都是可以恢复的版本。需 Node.js 18+,首次使用由 npx 下载 MCP 服务器。
自托管加密资产仪表盘:BTC、EVM(DeBank 73 条链)、Solana、狗狗币、艾达币、Hyperliquid L1、五家交易所(Binance / Bybit / Backpack / OKX / Bitget)与代币化股票统一视图;多数据源自动切换、自定义资产类别标签、可调阈值的资产健康度报告、可分享的 PNG 卡片、每个数据源独立连通性测试、多 Profile 配置、定时刷新、零依赖图表(Python 标准库 + 原生 JS,无 CDN)。
English | 中文
A free, 100% self-hosted DeepSeek Harness (DSH) plugin that unifies your on-chain and CEX assets into one self-contained web dashboard.
Requires dsh 0.1.1-rc.2 (Node ^22.19 || >=24) · Python 3.9+ · pip3 install requests pynacl
dsh plugin --profile demo add dsh-crypto-portfolio # npm
dsh --profile demo # dashboard at http://127.0.0.1:8080
Twin project. This dashboard is the twin of the SmartFolio Chrome extension: the extension puts the same wallets in your toolbar, this one is the self-hosted, all-chains view that runs on your own machine. Same idea, two shells — the dashboard is a DSH plugin and follows the DSH plugin conventions, so it keeps its own name.



Unofficial project, independently developed and maintained by community members.
I built it because the pain points are real.
EVM assets in DeBank, SOL and staking on-chain, BTC in a block explorer, plus Binance / Bybit / Backpack / OKX / Bitget — each with its own app. Checking "how much do I actually have" meant hopping between six pages, and it was easy to miss a wallet along the way.
This plugin puts all of it on a single screen.
Some money is genuinely invisible: native Solana stake accounts (getParsedStakeAccounts misses them), Hyperliquid L1 staked HYPE and spot balances, exchange earn/funding accounts. None of these are plain SPL/ERC-20 tokens, so ordinary tools never read them.
This plugin digs them out and prices them into your total — including the 12.1 SOL staked in the account above and the ~318 HYPE staked on Hyperliquid.
DeBank lists plenty of fake tokens — ETHG, for example, is a phishing token with a manipulated price that once inflated one account by $570K.
One-click blacklisting: every token you blacklist is removed from totals, trends and historical snapshots instantly.
Without history there's no peace of mind.
Every refresh saves the last snapshot of the day (SQLite, deduplicated by day); over time it draws a trend line that is uniquely yours:
<exchange>_read). Five exchanges are supported (Binance, Bybit, Backpack, OKX, Bitget). Read-only CEX keys cover spot, OKX's funding sub-account and Backpack's futures collateral account, including tokenised equities; on Bitget the spot account is summed with the real futures accounts and the S* demo products are skipped, so play money never enters the total.debank-pro (badged "PAID", with a registration link) and free keyless debank-public fallback; CEX rows always show Binance/Bybit/Backpack/OKX/Bitget with "get API key" links to each exchange (OKX and Bitget also take the key's passphrase). Each source displays when it last succeeded.default profile ships with public template wallets (vitalik.eth, genesis BTC, public SOL, public DOGE, public ADA) and empty keys; each profile can be renamed — its snapshots move with it — and keeps its own daily refresh time; your private wallets and keys live in a separately named profile with its own snapshot history.127.0.0.1 and masks API keys in its responses; writes are refused for cross-site requests (Sec-Fetch-Site: cross-site, foreign or opaque Origin, non-JSON bodies) and refresh is rate-limited to one run per minute. Snapshot history is kept as a 90-day window plus one per month, so the database does not grow without bound.manual with it) until you register it again. Registrations count from their own date onwards, so a position added today does not rewrite last month's history.plan.json): where each coin's price tiers sit, what a week costs in every tier, how new money is split, which cash and equity positions count as ammo, and what the goals are. After every refresh it answers the only question that matters — what do I do with the next dollar? — with the week's buy per coin (BTC 40% / ETH 35% / HYPE+SOL 25%), the tier each coin sits in (judged on its own price; HYPE+SOL follows BTC), which ammo source pays for it and how much of that source is left, how much of the quarter's deployment cap is gone, where the portfolio sits against each goal's path and what CAGR is still needed, and every rule from the take-profit / rebalance / drawdown sets that applies right now. Executions are logged (plan_log.jsonl) and consume the pool by source, so "left to deploy" is a real number rather than a guess. Cash and equities the tracker cannot see are declared as manual assets, which is how they join the total and the goal maths. The shipped defaults are illustrative placeholders — the equities and amounts are examples you replace in Plan settings — and the tab reproduces the worked example it ships with exactly: BTC $80,422 sits in T2 and ETH $2,353 in T3, so the week costs $160 + $280 + $100 = $540.html2canvas, no CDN, and no wallet address in the image.#pagePlan opens the plan, #pageSettings opens Settings and #pageSettings/secWallets opens one section, so a refresh (or a bookmark) returns you to the same place.Every box in the diagram is a real data pipeline:
Not a wrapper — a real plugin:
The dashboard also watches its own Python sources: editing tracker/*.py restarts
it within a couple of seconds (same process, no DSH restart), and static files are
read from disk on every request, so a UI change is a page reload. Settings → Service
has a Restart the service button for the cases where you want to force it.
dsh.bundle manifest (cordis.patch.yml), so it installs with dsh plugin add.apply(ctx) hooks into the Cordis lifecycle: seeds user-local profiles/default from public templates on first run, spawns the dashboard as a child process, and stops it cleanly on ctx.on('dispose').GET /api/refresh, /api/history, /api/tokens, ...) that an agent can call directly, in addition to the web UI.This repository contains no private keys, no private wallets, no balances — tracker/config.py ships with WALLETS = [] and empty keys. All private configs live in git-ignored local profiles/. Clone it, review it, run it with confidence.
dsh 0.1.1-rc.2 (or a compatible release within the same pre-release line)
and Node ^22.19.0 || >=24.0.0 — the range DSH itself declares.
Python 3.9+ with two pip packages:
pip3 install requests pynacl
These are ordinary runtime dependencies, not vendored, so pip can pick the
build that matches your platform.
Installs prebuilt code and needs no build permission:
dsh plugin --profile demo add dsh-crypto-portfolio
dsh --profile demo
pnpm pack # produces dsh-crypto-portfolio-0.1.0.tgz
dsh plugin --profile demo add ./dsh-crypto-portfolio-0.1.0.tgz
dsh plugin --profile demo add github:0xRabit/dsh-crypto-portfolio#<commit-sha>
This package is plain JavaScript + Python with no build step, so its
prepare is a no-op and pnpm does not need you to allowlist a build script —
unlike plugins that ship TypeScript sources. Pin a commit SHA anyway, so a
later push cannot change what runs on your machine.
dsh --profile demo --dump-config # look for: # == dsh-crypto-portfolio
If that line is missing, the bundle did not activate — the package installed as a
plain dependency instead. Re-run the add and check the warning it printed.
A patch replaces the whole config of a row, so restate every key you need.
Put this in $DSH_HOME/profiles/demo/cordis.patch.yml:
- id: portfolio-tracker
name: dsh-crypto-portfolio
config:
port: 8199
host: 127.0.0.1
Or set PORTFOLIO_PORT in the environment.
python3 run.py --init-template --port 8080 # seeds profiles/default from public templates
profiles/default/ sources.json + wallets.json (public template, auto-seeded)
templates/ public example configs (no secrets)
tracker/ backend fetchers (debank/btc/solana/hyperliquid/cex/prices)
static/ web dashboard (vanilla JS, no external deps)
run.py / fetch.py web server / CLI snapshot
One command from the maintainer's working tree (the release scripts live there, not in this published bundle), and the flow is deliberately split in two:
scripts/sync_public.sh --push # publish code — the version does NOT move
scripts/sync_public.sh --push --release # bump + tag + refresh every market listing
| Action | Version | Changelog | Tag | Market listings |
|---|---|---|---|---|
--push | unchanged | unchanged | — | untouched |
--push --release | bumped | [Unreleased] stamped | vX.Y.Z | branch pushed, PR prepared per market |
package.json exactly as it is, so
installed users see no update until a version is cut on purpose.market/, so it is versioned with the code it describes and always matches
the version being shipped. A market whose text did not change is skipped instead of
getting an empty pull request.| Market | How it is fed | What the release does |
|---|---|---|
| awesome-dsh-plugin | one YAML file per plugin | market/awesome-dsh-plugin.yml → data/plugins/0xRabit__dsh-crypto-portfolio.yml |
| awesome-deepseek-harness | curated bilingual tables | market/awesome-deepseek-harness.json → the row in each language's 🧩 Tools, Workflows & Presets table |
| awesome-dsh-hub | hourly scrape of the dsh-plugin topic | nothing to submit — the release only verifies the entry is present and current |
MIT — see LICENSE.