Skip to content

About

Trader's Agent for DeepSeek Harness — the Vela/LuxAlgo chart console as an installable DSH plugin bundle (mcp__traders-chart__* tools)

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

Trader's Agent — a Hermes Desktop plugin

A Hermes Desktop plugin that opens a chart-first trading console: Vela-rendered candlesticks, and the LuxAlgo Library on top of them.

licence: MIT python: 3.11+ hermes desktop: 0.21.3+ kind: desktop plugin

The console, chart-first: Vela candlesticks filling the pane

This is the DeepSeek Harness fork (tradersagent-plugin-dsh) of the Trader's Agent plugin. The Hermes Desktop original lives at godzillacode0000/tradersagent-plugin; this fork keeps the same console and adds the DSH bundle — jump to DeepSeek Harness below.

A sidebar entry that docks a full trading console beside your conversation: Vela-rendered candlesticks and the LuxAlgo Library (800+ concepts and indicators, served live by LuxAlgo's own MCP server) in one local web app — your chat session is left exactly where it was.

  • Chart-first by design. Vela gets the whole pane. The Library and the item detail panel are two small toggles in the top bar, never permanent columns.
  • Everything local. One Python process on 127.0.0.1:8787 proxies LuxAlgo's MCP server and serves the frontend. No account, no key, no telemetry. The chart engine (Vela, Apache-2.0) and the Pine runtime (pinets, AGPL-3.0 — a patched build) are vendored under console/frontend/vendor/ and served from this machine; no engine code is fetched at run time (market bars come from Binance and Library scripts from LuxAlgo's MCP — both over the network by design, and the console says which provider answered). The patches and their published chain: THIRD-PARTY.md and console/frontend/vendor/pinets/PROVENANCE.md.
  • The agent can drive the chart. console/bin/trader-chart reads what the chart is showing and puts indicator scripts on it through a small file bridge, so you prompt your agent instead of clicking around. console/bin/library-indicator pulls an indicator's Pine source by name.

Unofficial. This project is not affiliated with, endorsed by, or sponsored by LuxAlgo. It uses the LuxAlgo name descriptively ("compatible with LuxAlgo MCP") and ships no LuxAlgo logo. See THIRD-PARTY.md for the licences and the attribution each piece requires.

DeepSeek Harness

The same console runs under DeepSeek Harness too. There, an installable DSH bundle (dsh/) does two things: it mounts the console's MCP server into a profile, so the model gets the full chart toolset as mcp__traders-chart__<tool>, and it ships a chart panel — a sidebar row that puts the live console in a harness pane, the same chart, in the same place:

./install.sh           # MCP runtime + launcher + desk skill + bundle registration
dsh web                # restart once so the profile recomposes, then pick "Trader's Agent"

--dsh is still accepted — it is simply this checkout's default, whose other half is the Hermes Desktop plugin (installed only with an explicit --hermes).

Then just talk to it — "what's on the chart?", "switch to SOLUSDT 1h", "put an EMA on it", "screenshot the chart" — and it calls the tools by itself. The full mapping (what ports unchanged, why MCP rather than native tools, what still did not port) is in docs/DSH.md; the bundle's own notes are in dsh/README.md.

Requirements

Hermes Desktop v0.21.3 or newer (the plugin uses the sidebar.nav + routes contribution areas)
Python 3.11+ with the mcp client: pip install mcp (a venv is fine — point PY= at it)
Network for LuxAlgo's MCP endpoint and the Binance data feed; the chart falls back to synthetic bars when the provider is unreachable. The chart engine and Pine runtime are served locally
Preview resizer (optional) libvips (or ImageMagick, or ffmpeg) — see Catalogue previews. With none of them the console still shows every preview, just at the catalogue's original size
OS Linux — built and verified on Omarchy (Arch + Hyprland). macOS and Windows are out of scope.

Install

This checkout is the DeepSeek Harness variant of the repository, so it installs there by default: ./install.sh sets up the dsh/ bundle and never writes into $HERMES_HOME. The Hermes Desktop half still ships — it is upstream's — but it is installed only when --hermes is passed explicitly, and that overwrites $HERMES_HOME/desktop-plugins/traders-desk/.

DeepSeek Harness (the default here):

git clone https://github.com/godzillacode0000/tradersagent-plugin-dsh
cd tradersagent-plugin-dsh

./console/start.sh        # terminal 1 — the console on http://127.0.0.1:8787/
./install.sh              # DSH bundle + launcher + desk skill
dsh web                   # restart once so the profile recomposes

Hermes Desktop (the upstream target — opt-in, and an overwrite):

./install.sh --hermes     # the plugin -> ~/.hermes/desktop-plugins/traders-desk/
                          #   and the desk skill -> ~/.hermes/skills/trading/trader-desk/

Then in Hermes Desktop:

  1. Ctrl+K → Reload desktop plugins
  2. Capabilities → Plugins → enable Trader's Agent
  3. Click Trader's Agent in the left sidebar — the chart docks beside your conversation

Step 2 is not optional, and it is the step that gets skipped. Hermes Desktop ships every desktop plugin disabled by default: an installed plugin is inventoried but contributes nothing — no sidebar row, no pane, no error — until you switch it on. Enabling is a decision the app stores itself, so install.sh --doctor cannot see it. To ask directly:

./bin/is-enabled.sh          # files ok? decision on/off? what to do about it

If the pane is enabled but still does not dock, that is a different, app-side interaction — see docs/INSTALL-ENABLE.md for both failure modes side by side.

The browser builds are committed under console/frontend/vendor/ — the console loads them from there. ./install.sh --vendor refreshes those exact files from the pinned CDN versions (see the licence note in THIRD-PARTY.md).

Verify it worked

curl -s localhost:8787/api/health                    # {"ok": true, "data": {"status": "ok", ...}}
node tools/verify-plugin.mjs plugin/plugin.js        # OK — 7 contributions
console/bin/trader-chart state                       # symbol, timeframe, price, bars, indicators on

Then, in the app: the Trader's Agent row is in the left sidebar, the console frame shows Vela bars with the ▲ mark, and the status-bar chip reads Trader's Agent. If the frame is blank, the console process is not running — start it again.

Run the console as a service (optional)

# ~/.config/systemd/user/traders-agent.service
[Unit]
Description=Trader's Agent console (LuxAlgo MCP proxy + Vela chart)
After=network-online.target

[Service]
ExecStart=%h/tradersagent-plugin/console/start.sh
Restart=always
WorkingDirectory=%h/tradersagent-plugin

[Install]
WantedBy=default.target
systemctl --user enable --now traders-agent.service

Using it

Where What it does
Left sidebar → Trader's Agent reveals the chart pane beside your chat, then hands you back to the chat you were on — your session is not switched
Status bar → Trader's Agent chip same, from anywhere in the app
Ctrl+K → Trading: open Trader's Agent same, from the palette
Ctrl+K → Trading: toggle chart reveal on launch stop the console opening by itself at app start
Top bar → ☰ Library the Library panel: search 800+ concepts and indicators
Top bar → ▤ Details the selected item: write-up, full Pine source, licence badge, Run PineTS
Chart top bar → Layout Vela's own grid picker — presets and custom g<cols>x<rows> grids. The console boots at 2h (two side by side); the same door is chart_set_layout / trader-chart layout
Chart top bar → ⌗ Indicators One surface for both halves: Favourites (your own ☆), BUILT-INS (Vela's natives for this market, read live from the frame) and LIBRARY (the 806-row LuxAlgo catalogue). Every LIBRARY card carries the catalogue's own chart preview above its name — and the Details pane shows it full size — so "how does this look applied?" is answered before running anything. The LIBRARY arrives grouped into families (SMC / ICT 74, Trend 108, Volume & Flow 96, …) with a rail down the left to jump between them, and each family opens into its own clusters ("Moving-average lineage", "Candlestick catalog"); every card has a Reading button that unfolds what the indicator is and how it is read, in place. Star the ones you reach for; clicking a built-in mounts it, a Library row opens the Details pane with its Run PineTS / Add to chart. The same door is chart_indicators / trader-chart indicators (--family trend --reading mlma --fold trend:on)
Chart top bar → ⛶ Full screen Gives the chart the whole pane — and the whole display: the console's chrome, panels and statusbar step aside and the page asks the browser for fullscreen. Esc (or the floating ✕, or the same button) comes back. Docked on Vela's own toolbar row beside <> Script and ☰ catalogue; the door is chart_fullscreen / trader-chart fullscreen [--off]
The chart's own bottom bar Vela's range buttons, timezone clock and settings (not ours)

Chat beside the chart

The chart is a pane docked to the right of the conversation (traders-desk:chart, 620px, collapsed until you ask for it — your call, 19 Sep: it does not open with the app), so the app's own composer keeps the left and the chart reads on the right — drag the divider to re-balance, or collapse the pane with the app's own control. Clicking the sidebar row re-opens it (host.revealPane, the app's door for "an explicit user action happened") and leaves your session alone: it used to jump to a dedicated desk chat on every click, which pulled you out of whatever you were doing. Any session can drive the chart through the tools — the pane is chart, not conversation.

That chat is the "connected, sees, understands" part, and it needs no bespoke composer: the tools below answer over the console's push channel, so the round trip is local.

Run PineTS executes the script over the chart's live bars with the vendored, patched Pine runtime and paints it as a native series; it says plainly when a script uses something the runtime refuses (import is the one). Add to chart asks Vela's own Pine engine, which here is the workspace's PineEngine — built on that same patched runtime. (vela-pinets' PineWorkerEngine would run its copy inlined in vela-pinets, without the patches; the console therefore does not use it.) The app reports what actually happened rather than pretending. (A heavy script can be run off the page's main thread instead with ?engine=worker on the console URL, or localStorage luxalgo-web:pine-engine = worker — at the cost of running vela-pinets' copy, which does not carry the patches.)

Letting your agent drive the chart

Two ways in, and they share one path underneath. Preferred: the MCP server — Hermes (or any MCP client) gets the chart as real tools:

hermes mcp add traders-chart --command "$HOME/.hermes/bin/uvx" \
    --args fastmcp run "$PWD/console/mcp/server.py"      # run this from the repo root
hermes mcp test traders-chart          # start a new session afterwards
Tool What it does
chart_views is a view attached to push into? (0 = the console is not open)
chart_caps what the attached page will actually execute — read it before drawing
chart_natives what Vela can put on this chart from its own side (the built-ins for this market)
chart_studies everything on the chart, each row labelled with the reader that saw it — ask this before calling a chart clean
chart_state symbol, timeframe, last price, bars, indicators on the chart
chart_shot one PNG of the chart (returned as an image, plus the path)
chart_apply_pine run Pine over the chart's live bars and paint a matching native
chart_add_indicator add a Vela native (ema, supertrend, donchian-channels, …)
chart_remove_indicator take indicators off the chart — one by name, or all for every study (reports the chart's before → after list)
chart_set_market switch symbol / timeframe
chart_set_layout read or set the workspace grid — 1, 2h, 2v, 4, 8, or g<cols>x<rows> (no argument reads it)
chart_indicators the Indicators surface — sections favorites/builtins/library, q for the search box, family to open one group of the catalogue, reading SLUG to unfold a card's write-up, fold FAMILY[:on] to fold a group, star/unstar KIND:ID, mount a built-in; answers with the rows it painted, the groups it drew and the reading it left open
chart_fullscreen give the chart the whole pane / the whole screen (on=False comes back) — hides the console chrome and asks the browser for fullscreen; the answer says whether the display was taken or only the page
chart_reload remount every attached console (picks up new frontend files)
chart_palette what colours the chart is wearing (try_apply asserts the console theme)
chart_theme read or set the console theme — light / dark (no argument reports what is worn); the console palette, Vela's chrome and the chart's own colours move together, and the choice survives a reload
chart_browse open the Library concept list in the pane (optional family)
chart_draw run Pine and paint the boxes/lines/labels it builds on the chart overlay
chart_clear clear the overlay and the indicators our paint layer added (then report what is left)
chart_batch run several chart actions in ONE call, in order ([{"action": "market", …}, …]), stopping at the first failure unless told otherwise
chart_snapshot remember the chart's market + indicators as a restore point
chart_undo put the chart back to that point, reporting the chart's own before → after lists
chart_watch watch for a spell and answer with a diff (what changed), not another snapshot
chart_alert wait for price to move (by a move_pct, or at all) and report the move
library_search search the LuxAlgo Library
library_indicator one indicator's write-up, licence and Pine source
library_list browse indicators with filters and paging (family, text, concept, tier, sort, page)
library_taxonomy the Library's own families or concepts — read before filtering, so a name is the Library's
library_concept one concept by slug: what it means and which indicators implement it
library_source Pine source by exact slug — no name resolution to get wrong
edge_presets LuxAlgo's measured edge presets and their categories
edge_report one preset's measured edge on one symbol
edge_symbols which symbols the edge reports cover
propfirms prop-firm directory, with an optional filter
bt_run run one vectorbt MA-cross backtest; returns metrics
bt_optimize sweep MA pairs at once and rank by return
bt_status read a saved backtest result (run_id or newest)
bt_data_list list the operator's local OHLC files
propfirm_offers current prop-firm offers from LuxAlgo's own tracker

Same surface from a shell: trader-chart remove MACD | --all, add ema, apply file.pine, draw file.pine, shot, market SYMBOL TF, layout 2h, layout (read the grid), state. Which of those actually paint in this Vela build — and which calls return cleanly while doing nothing — is written down in docs/vela-chart-api-notes.md, measured from the running app.

Every tool carries MCP annotations (title, readOnlyHint, destructiveHint, openWorldHint), and the mutating ones answer with what the chart looks like after the call — a request echoed back is not a painted pane. Failures come back as a code beside the prose (NOT_RUNNABLE[while], RUNTIME_CRASH[pinets-get_v], TOO_FEW_BARS, ENGINE_UNAVAILABLE, TIMEOUT), so a caller can branch without regex-matching a sentence.

Or the CLIs, if you would rather shell out:

console/bin/trader-chart state                      # symbol, timeframe, price, bars, indicators on
console/bin/trader-chart shot --out /tmp/chart.png   # capture the chart for vision
console/bin/trader-chart apply script.pine           # run Pine over the chart's bars and paint it
console/bin/library-indicator "killzone"             # fetch an indicator's Pine source

Both paths go through the console's push channel (Server-Sent Events): the chart page holds one long-lived connection open, so a command lands in tens of milliseconds instead of waiting for a poll tick — measured 37-156 ms on the wire for add / market / apply, ~65-80 ms for a capture, against ~1.0 s on the old 2-second poll. Polling stays on as a safety net (every 15 s while the stream is healthy, 2 s if it drops) and the file bridge is untouched, so an older view still works. The bridge is still not a headless renderer: with no view attached, commands fail fast and say so.

Screenshots

in Hermes Desktop chart-first
In Hermes Desktop — the sidebar row docks the chart beside the chat Chart-first — Vela gets the whole pane; panels are opt-in
Library open detail panel
Library open — search across the LuxAlgo Library Detail panel — write-up, licence badge, Run PineTS / Add to chart

Library text and Pine sources shown in these screenshots are LuxAlgo's — Source: LuxAlgo Library.

Update / Uninstall

cd tradersagent-plugin-dsh && git pull   # update
./install.sh --hermes                    # redeploy the Hermes plugin (hot-reloads in ~3 s)
./install.sh                             # …or the DSH bundle, which is this checkout's default
systemctl --user restart traders-agent.service   # only if you run the console as a service

Uninstall: delete ~/.hermes/desktop-plugins/traders-desk/ in Hermes Desktop (Capabilities → Plugins), then remove the console's service (systemctl --user disable --now traders-agent.service). Nothing else is written outside the repo; console/agents/ holds the runtime state you can delete.

Repository layout

plugin/            the Hermes Desktop plugin: plugin.js + its harness expectations
console/frontend/  the web app: Vela chart, Library panel, detail panel, PineTS paint layer
console/backend/   one stdlib HTTP server proxying LuxAlgo's MCP + the chart bridge + the push channel
console/mcp/       trader-chart-mcp — the chart as MCP tools (stdio, FastMCP)
console/bin/       agent-side CLIs (trader-chart, library-indicator)
tools/             verify-plugin.mjs — runs a plugin in Node against SDK stubs (used by CI)
tools/             verify-plugin-hook.mjs — the resolve hook it registers; only the three allowed specifiers resolve
tools/             verify-plugin-selftest.mjs — crafted-copy battery for the import gate (evasions fail, lookalikes pass)
install.sh         installs the DSH bundle by default; `--hermes` installs the plugin into
                   $HERMES_HOME/desktop-plugins/ instead (upstream's target)
dsh/               the DeepSeek Harness bundle: manifest, cordis patch, and the stdio launcher

Configuration

Env Default Meaning
PY python3 the interpreter for console/start.sh (must have mcp)
PORT 8787 console port — the plugin's frame points at http://127.0.0.1:8787/
LUXALGO_AGENTS_DIR console/agents runtime state: chart bridge files, study threads, shots
HERMES_CLI hermes on PATH CLI the in-app study bridge shells out to
LUXALGO_CHART_INLINE_WAIT 8 seconds a command holds its request open waiting for the chart's pushed answer
TRADERS_AGENT_THUMB_WARM 1 0 turns off warming the catalogue's previews in the background at start-up
TRADERS_AGENT_THUMB_WARM_PAGES 0 (all) how many catalogue pages to warm; set a small number on a metered link
TRADERS_AGENT_THUMBS ~/.local/share/traders-agent/thumbs where the shrunk previews live
--mcp-url https://mcp.luxalgo.com/mcp point at a different (or local) MCP server

Catalogue previews are kept on your machine

The Indicators modal shows each card the way LuxAlgo's own library does, with a chart preview. Those pictures are 1600×1000 PNGs on LuxAlgo's S3 (~29 KB each) and they are slow to fetch one by one — about 1–2 s each from a home connection, and a browser only opens six connections per host, so sixty cards used to fill in while you watched. The console therefore fetches each picture once, shrinks it to the width it is actually painted at (480 px for a card, 960 px for the Details pane), and serves it from http://127.0.0.1:8787/api/library/thumb: ~5 ms warm instead of ~2 s.

  • Every machine keeps its own copy. A fresh install warms the whole catalogue (806 rows, roughly 5 MB) in the background on first start — a few minutes on a slow link, invisible while it works — and every start after that finds the files already there. Nothing is shared between installs and nothing is downloaded twice.
  • The resizer is a CLI, not a Python package: vips, else ImageMagick, else ffmpeg. If none is installed the console serves the catalogue's original PNG — bigger, exactly as slow as upstream, but never a broken or blank tile.
  • A replaced picture is never stale: the cache key carries a tag of the source URL, and the response is immutable, so new artwork is a new file.
  • curl localhost:8787/api/library/thumbs reports what is cached and what the warmer is doing. TRADERS_AGENT_THUMB_WARM=0 switches warming off entirely.

Limits

  • The Pine runtime is a subset of Pine. import is refused outright; while and for…in run. Anything heavier only runs in TradingView's own Pine engine.
  • "Add to chart" is experimental. It hands the script to Vela's Pine engine; some scripts paint nothing. Run PineTS is the reliable path.
  • The bridge is not a headless renderer. trader-chart and the MCP tools only take effect while a chart view is mounted (the Hermes pane or a browser tab); with none attached they fail fast with "no chart view attached" rather than hanging. Commands are pushed, so a view answers in tens of ms.
  • One console per machine on one port. No order placement, no account, no positions — it is read-only market data plus rendering.
  • The Library is non-commercial. Its content is CC BY-NC-SA 4.0 — fine to read and cite here, not to resell or ship inside a paid product.
  • Linux only, on purpose. Built and verified on Omarchy (Arch + Hyprland) with Hermes Desktop. macOS and Windows are out of scope, not merely untested: the ops story here is a systemd user unit and a shell script, and the machine this desk was built for is the one running it.

Development

node tools/verify-plugin.mjs plugin/plugin.js                                      # plugin harness (same check CI runs)
python3 -m unittest discover -s console/backend/tests -t console/backend/tests -v   # the unit suite (no dependencies)
uv run --with fastmcp python -m unittest discover \
    -s console/backend/tests -t console/backend/tests -p 'test_mcp_server.py' -v     # the MCP tool layer
python3 console/backend/server.py --port 8899 --no-mcp                             # console without the MCP backend
python3 -m compileall console/backend                                              # syntax pass

The suite is stdlib-only on purpose — the study store, the chat bridge, the chart bridge and the push channel are covered without a browser, a network, or the app — and the MCP tool layer runs against a stub console. ≈350 tests; the MCP ones skip themselves when fastmcp is absent (CI sets TRADER_CHART_REQUIRE_MCP=1 so they cannot silently skip there).

CI (.github/workflows/ci.yml) has three jobs: the plugin harness (Node 20 — the real plugin first, then the crafted-copy battery verify-plugin-selftest.mjs), the backend (compile, boot and a /api/health smoke test on Python 3.11), and the unit suite (the MCP step installs fastmcp). Workflow when editing: change the repo, run ./install.sh --hermes to deploy the Hermes plugin; the app re-registers the plugin about 3 seconds after plugin.js changes. Console-only changes need the frame remounted (switch session and back).

Troubleshooting

  • The sidebar row does nothing / the pane shows an old layout. The frame keeps the copy it loaded. Switch to another session and back, or restart the app.
  • start.sh: 'python3' has no 'mcp' client. pip install mcp, or PY=/path/to/venv/bin/python ./console/start.sh.
  • The plugin never appears in Capabilities → Plugins. Ctrl+K → Reload desktop plugins; if it still does not show up, the folder was dropped after a failed load — rename ~/.hermes/desktop-plugins/traders-desk and set id: inside plugin.js to the same new name.
  • The chart is empty and the log says provider: synthetic. Binance's data provider was unreachable; the chart still renders deterministic bars so the page never comes up blank.
  • Port 8787 busy. PORT=9000 ./console/start.sh, then point the plugin's CONSOLE_ORIGIN at it.

Licence & credits

This project's own code is MIT (that is what the licence badge means — the combined distribution is AGPL where it redistributes PineTS; see THIRD-PARTY.md) — see LICENSE. It builds on LuxAlgo's work: Vela (Apache-2.0, with its own attribution requirement — the ▲ mark on the chart stays), vela-pinets and pinets (AGPL-3.0; pinets is vendored here as a patched build whose patches are published on the fork, and vela-pinets is vendored unmodified), the LuxAlgo MCP server (MIT, @luxalgo/mcp) and the LuxAlgo Library (free with attribution — Source: LuxAlgo Library — luxalgo.com/library/…). Full details, quotes and links: THIRD-PARTY.md.

Charts are not financial advice; the Library is an encyclopedia, not a signal service.

Known Hermes Desktop interaction: a collapsed pane can stay hidden

A pane contributed with defaultCollapsed: true is adopted into a layout group carrying "minimized": true (persisted under hermes.desktop.layoutTree.v2). On Hermes Desktop 0.17.0 revealPane() — the documented call for an explicit user action — reveals the pane and its zone but does not clear that group flag, so after a layout reset the sidebar row can land with the pane still hidden: the route page then renders the console itself in the main zone instead of docking the chart beside the chat.

Measured 19 Sep 2026 on Omarchy + Hermes Desktop 0.17.0: after Layouts -> Reset, the row's revealPane call left {"id":"g-...","panes":["traders-desk:chart"],"minimized":true} in the store and the chart opened as the main page. Clearing the flag and reloading the window docks the pane beside the chat as intended.

The plugin handles it as far as it can: the page asks for adoption and reveal, retries once a beat later (the app may still be rebuilding the tree when a page mounts), and when the pane is still not visible it renders the console itself under a short note that says why — with Ask again and Open in a browser in reach. The note only appears when the pane API exists and reports the pane hidden, so a build without panes gets the plain console and no nagging.

Recovery for a user who hits it: un-minimize the pane's group in hermes.desktop.layoutTree.v2 (DevTools / a CDP session on --remote-debugging-port) or pick a layout template that re-adopts contributed panes, then reload the window. The plugin asks for the documented reveal first and cannot clear the flag itself — the renderer's layout atoms own that state.

About

Trader's Agent for DeepSeek Harness — the Vela/LuxAlgo chart console as an installable DSH plugin bundle (mcp__traders-chart__* tools)

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages