Make Python runtime probes work across Bash and PowerShell by handling failures inside valid Python try/except blocks and updating the canonical skill-authoring examples.
- actions/checkout v4 -> v7, actions/setup-node v4 -> v7
- pnpm 11.1.2 -> 11.20.0
- CI node-version 22 -> 24, and engines.node >=22 -> >=24 to match
BREAKING: Node 22 is no longer supported — Node 22 users will get an
engine error on `opencli plugin install`. Node 22 entered maintenance in
Oct 2025; 24 is the current Active LTS.
Docs updated to match, including the tradingview-reader skill (which
installs this repo's plugin, so engines.node — not opencli's own ">= 21"
floor — is the binding constraint) and stale rationales that justified
the old floor ("built-in fetch"/"built-in WebSocket" stabilised in Node
22; Bun 1.0 does not satisfy engines.node >= 24).
The social readers keep ">= 21 (or Bun >= 1.0)" — they install no plugin
from this repo, so opencli's own floor applies.
ccbump@0.2.1 and skill-lint@v3 were already latest; the opencli
">=1.8.0" peer range is a minimum floor, not a pin, and already admits
1.8.6.
New data-providers skill for Fintel's institutional market intelligence:
short interest, borrow rates, short volume, fails-to-deliver, 13F
institutional ownership, insider transactions, analyst targets, and
calendars. Read-only by policy — GET endpoints only.
Built from Fintel's public MCP capability catalog and OpenAPI spec.
Supports the REST API (api.fintel.io/v1, X-API-KEY) as the default
surface and the official MCP server (mcp.fintel.io/mcp) as an optional
alternative.
* feat: add hyperliquid-reader skill + opencli plugin
Add a read-only Hyperliquid (app.hyperliquid.xyz) reader, mirroring the
tradingview-reader pattern. Unlike TradingView's CDP attach, Hyperliquid
exposes a fully public info API (POST https://api.hyperliquid.xyz/info),
so this needs no API key, wallet, login, or desktop app.
opencli plugin (opencli-plugins/hyperliquid/) — 12 read-only commands:
- Market data: markets, spot-markets, mids, book, candles,
funding-history, funding-compare (cross-venue HL/Binance/Bybit
funding-arb screen).
- Account by 0x address: account, positions, spot-balances,
open-orders, fills.
Skill (plugins/data-providers/skills/hyperliquid-reader/) — SKILL.md
(5-step + error reference), README.md, references/commands.md.
Registrations: root opencli-plugin.json, data-providers plugin.json
(description + keywords), marketplace.json, root README table.
Verification: 31 unit tests pass against captured live wire shapes;
all 12 command data paths smoke-tested end-to-end against the live API.
SKILL.md description is 1019 chars (< 1024 lint cap), no angle brackets.
No trade execution: the plugin exposes no write/exchange endpoints.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
* refactor: scope hyperliquid-reader to market data only
Drop the account-by-address commands (account, positions, spot-balances,
open-orders, fills) and their lib/account.js + lib/orders.js helpers and
tests. Remove the now-unused normalizeAddress helper from lib/api.js.
The reader is now market-data only: markets, spot-markets, mids, book,
candles, funding-history, funding-compare (7 commands). Updated SKILL.md,
both READMEs, references/commands.md, the plugin/marketplace manifests,
and the root README table accordingly.
21 unit tests pass; all 7 market-data data paths re-verified live.
1.8.0 ships reliability fixes that benefit the CDP-attach adapter:
retryable CDP -32000, Page.goto stale-identity self-recovery, and
undici pinned back to 6.x so Node 20 users stay supported.
opencli runtime (1.7.19) calls `cmd.func(kwargs, debug)` for `browser: false`
commands, but every data command in this plugin declared the legacy
two-arg `(_page, args)` form. That made `args` receive `debug` (undefined)
and every ticker / strike / filter argument deserialize to `undefined` —
e.g. `quote --ticker SMTC` failed with `No quote returned for UNDEFINED:UNDEFINED`.
Drop the unused `_page` parameter so the signature matches the runtime
contract for non-browser commands. Affected commands: alerts, chart-state,
launch, news, options-chain, options-expiries, quote, screener, screenshot,
search, watchlists. (status was already correct — takes no args.)
Verified: `opencli tradingview quote --ticker SMTC --exchange NASDAQ` returns
`NASDAQ:SMTC close 139.74` after the fix. Plugin tests (42/42) still pass.
- yc-reader: document per-company endpoint (batches/{batch}/{slug}.json),
refresh batch examples to 2026 cohorts, fix batch field example
("Winter 2026"/"Summer 2009", not "W25"/"S24"), remove outdated
"no individual company endpoint" limitation
- twitter-reader: drop stale "opencli 1.7.7" version qualifier on
media_urls (opencli is now v1.7.18)
- opencli-reader: extend adapter shortlist with v1.7.18 additions
(rednote, doubao, yuanbao, gemini, notebooklm, claude, tieba, hupu,
xianyu, 1688, gitee, quark, baidu-scholar, nowcoder, wanfang)
Fixes#64. README already declares MIT, but without a LICENSE file
GitHub reports the repo as unlicensed, which blocks downstream reuse
under default copyright.
* Add MCP support to ; keep REST as raw-data fallback
exposes two surfaces backed by the same data:
- MCP server at https:///api/mcp — single agent_chat tool for
analyst-grade research synthesis (DCF, sector deep-dives, transcript
digestion, etc.). OAuth via `claude mcp add`, no API key.
- REST API at https://api./v1 — 60+ endpoints for raw structured
data. Bearer auth.
The skill now routes by intent: prefer MCP for synthesis/analysis
questions, fall back to REST for raw data the MCP declines (real-time
quotes, intraday candles, raw options chains, single line items, bulk
downloads, AI-company hiring signals).
Structure:
- Step 1 — decide surface (MCP vs REST)
- Step 2 — MCP flow (verify, frame, call), with budget-awareness and
multi-turn guidance
- Step 3 — REST flow (key resolution, endpoint table, curl)
- Step 4 — shared response formatting
Other fixes:
- MCP-detection grep was `^[[:space:]]` but `claude mcp list`
outputs `:` (colon, not whitespace) — fixed to `^:`.
- Conversation URL was `agent-chat/<id>` but the route reads `c` from
query params (chat-v2-layout.tsx) — fixed to `agent-chat?c=<id>`.
- Subscription_required (403) note moved from Step 1 (registration) to
Step 2c (tool call) where the error actually fires.
Adds research-topics.md reference for the MCP path; keeps the 11
existing REST endpoint references in place.
* Fix date-bound test in tradingview summarizeExpiries
`summarizeExpiries` called `daysToExpiry(expiry)` without forwarding the
caller's `now` reference, so the function used wall-clock time. The
matching test pinned `NOW = 2026-05-10` and asserted `dte === 12` for an
expiry of 2026-05-22 — passed on 2026-05-10, started failing on
2026-05-11 as the calendar advanced. Caught by CI on PR #60 today.
Forward `now` through to `daysToExpiry` (which already supports the
optional second arg) and pass `NOW` from the test. Same pattern the rest
of the file already uses for `normalizeChainRow(..., NOW)` and the
`daysToExpiry — future / past` tests.
42/42 tradingview tests pass locally and on any future date.
- Switch README link from finance-skills.himself65.com to skills.himself65.com
- Add tradingview-reader and skill-creator to apps/web skill data
- Extend PluginGroup type and pluginOrder with skill-creator group
* Add tradingview-reader skill
Read-only skill for the TradingView desktop macOS app via opencli + the
opencli-plugin-tradingview plugin. Exposes spot quotes, full options chains
with greeks/IV, expiries, chart state, and screenshots — all by attaching
to a logged-in TradingView.app over Chrome DevTools Protocol (no API key).
The plugin lives in a separate repo (himself65/opencli-plugin-tradingview)
and must be installed before this skill is functional.
* Add tradingview opencli plugin under opencli-plugins/ monorepo
Scaffolds the actual TradingView adapter the tradingview-reader skill
depends on, inside this repo via opencli's monorepo subpath syntax.
Install path becomes:
opencli plugin install github:himself65/finance-skills/tradingview
What's in opencli-plugins/tradingview/:
- 7 commands (launch, status, quote, options-chain, options-expiries,
chart-state, screenshot) following opencli's cli({...}) registry API
- lib/scanner.js + lib/symbols.js — POST helpers, {fields,symbols}
decoder, OPRA parser, ATM-band slicer
- 15 node:test units covering the pure helpers, all passing
Top-level opencli-plugin.json declares the monorepo. CLAUDE.md gets a
new "opencli plugins" section explaining the layout, install path, and
authoring flow. Skill SKILL.md/README.md/commands.md updated to use the
new monorepo install command.
The Node port of the data-path logic follows the spec from the original
PoC handoff but has not been smoke-tested against a live TradingView.app
yet — needs PoC verification before users rely on it. Lib unit tests
pass; integration (CDP attach + scanner replay) is unverified.
* Add 5 Tier-1 tradingview commands: screener, search, news, watchlists, alerts
Expands the plugin from 7 → 12 commands, covering the highest-value
research surface beyond options chains and chart state.
New commands:
- screener: generic stock/crypto/forex/futures/bond screener via
scanner.tradingview.com/{market}/scan2 — supports the full scan2
grammar (timeframe-suffixed columns, filter clauses, sort, pagination).
~70 country codes + cross-class markets. The same backend powers all of
TradingView's movers, heatmaps, and screener pages.
- search: symbol/instrument autocomplete via symbol-search/v3 — useful
before any other command when the ticker is ambiguous.
- news: /v2/headlines list mode + /v2/story detail mode (--id <story-id>).
Filterable by symbol, category, area, section, provider. Story body
flattened from TradingView's AST to plain text.
- watchlists: read-only access to user's custom watchlists (all, by id,
or by colored flag). Write endpoints (append/replace) intentionally
not exposed.
- alerts: read-only access to pricealerts.tradingview.com — list, active,
triggered, offline-fires, and full log. Write endpoints
(create/edit/remove) intentionally not exposed.
lib/scanner.js: buildScreenerBody() builder with proper limit clamping
(1..500), filter/filter2 passthrough, explicit-tickers mode, and offset.
scannerFetch() now accepts an optional labelProduct (defaults to
symbols-options for backward compat).
lib/news.js: new module — buildHeadlinesUrl, buildStoryUrl,
normalizeHeadline, astToText (recursive AST walker handling p/h*/list/br/
text nodes), epochToIso (auto seconds-vs-ms detection).
Tests: 18 new node:test units covering AST flattening, headline
normalization, screener body builder. Total now 33/33 passing.
Skill docs (SKILL.md + references/commands.md) updated with the new
commands' tables, output schemas, key rules, presentation guidance, and
detailed reference sections per command. Plugin README updated to list
the new commands and tests in the layout tree.
All commands remain unverified against a live TradingView.app — pure
helpers (lib/) are unit-tested but the wire shapes (response field
names, especially for /list_alerts and /api/v1/symbols_list/all/) follow
community-documented conventions and may need adjustment after first
PoC run.
* Fix tradingview-reader skill-lint failures
skill-lint v2 enforces:
- description ≤ 1024 chars (was 1070)
- no angle brackets in description (had "RSI < 30" in a trigger phrase)
Trim trigger list and replace the "<" example with "oversold stocks".
Now 987 chars, no angle brackets.
* Add CI workflow for opencli plugin unit tests
New workflow walks opencli-plugins/*/ and runs `npm test` for each
plugin that has a package.json and tests/*.test.js. Currently exercises
the 33 pure-helper tests under opencli-plugins/tradingview/.
Coverage scope (intentional):
- ✅ Pure data-transformation helpers: parsers, decoders, normalizers,
URL builders, AST walkers
- ❌ cli({...}) registration, page.evaluate, real network responses,
CDP attach — those need PoC verification against a live desktop app
CLAUDE.md CI section updated to document the new workflow and call out
that wire-level integration is out of test scope.
* Fix tradingview plugin: cookies-from-CDP path, working live against MU
The previous architecture (Strategy.UI + page.evaluate(fetch)) does not
work — browser CORS preflight rejects cross-origin POSTs from any
tradingview.com page to scanner.tradingview.com, even from the
options-chain page itself. Verified by direct CDP test on every TV tab.
How TradingView's own pages get around this: their Electron main process
makes the requests via Node's network stack, bypassing browser CORS.
This commit replicates that path:
1. Connect to CDP /json/version
2. Open browser-level WebSocket
3. Storage.getCookies → harvest .tradingview.com cookies
4. fetch() from Node directly with Cookie header
Smoke-tested live against MU on TradingView desktop:
quote → $746.81 (+15.49%)
options-chain → 7,426 contracts; ATM band on 2026-05-15 returns 10 rows
news --symbol NASDAQ:MU → 200 headlines, top "Chip-Stock Juggernaut..."
options-expiries → 22 expiries
screener (top mcap) → NVDA $5.23T, GOOGL $4.84T, AAPL $4.31T, MSFT $3.08T
search Micron → NASDAQ:MU
watchlists → 4 lists with section markers
alerts → KORU cross_down (read-only)
chart-state → layout 5DjR42GB, symbol EWY
screenshot → 350KB PNG
What changed:
- New lib/cookies.js: CDP Storage.getCookies harvest + tradingViewFetch
helper. Caches cookie header per process. Uses Node 22's built-in
WebSocket (no `ws` dep).
- New lib/cdp.js: CDP tab finder, Runtime.evaluate, Page.captureScreenshot.
Eliminates the apps.yaml registration requirement — plugin works with
zero opencli config beyond install.
- lib/scanner.js: scannerFetch signature dropped `page`; uses
tradingViewFetch. buildChainBody rewritten to use the live wire shape
(index_filters: [{name:'underlying_symbol', values:[...]}] + filter2
boolean composition + ignore_unknown_fields). The prior {markets,
filter, range} shape returns HTTP 400.
- lib/news.js: added fetchHeadlines() and fetchStory() routed via
tradingViewFetch.
- 8 data commands (quote, options-chain, options-expiries, screener,
search, news, alerts, watchlists): converted from Strategy.UI +
browser:true to Strategy.PUBLIC + browser:false. No more `domain`
field, no `page` arg in func.
- chart-state and screenshot: also Strategy.PUBLIC now, using lib/cdp.js
helpers directly. Multi-selector cascade for chart-state symbol detection.
- alerts.js normalizeAlerts: response key is `r` (live shape:
{s:"ok", r:[...]}), with fallbacks. Symbol parsing extracts ticker
from JSON-encoded resolution blobs.
- options-chain + options-expiries: added --include-expired flag,
default false (filters out DTE < 0).
Tests: +12 cases (cookies endpoint resolution, alerts normalizer with
live `r:[]` shape, buildChainBody wire-shape regression, buildQuoteBody).
42/42 passing.
Engines: Node ≥22 required (built-in WebSocket).
Setup is now: `opencli plugin install ...` + `opencli tradingview launch`.
No apps.yaml, no Browser Bridge, no other config.
* Fix CI: move alerts normalizer to lib/ so tests don't load opencli
CI exit 1 — tests/alerts.test.js was importing normalizeAlerts from
../alerts.js, which loaded the cli({...}) registration and pulled in
@jackwener/opencli. CI doesn't install opencli before running plugin
tests (and doesn't need to), so the import failed.
Move normalizeAlerts (+ its private helpers) to lib/alerts.js. The
command file now imports from there. Test imports from ./lib/alerts.js
so it never touches opencli.
Verified: `grep -E "^import.*@jackwener" lib/ tests/` is empty. 42/42
passing locally; CI should now match.
* Add gamma squeeze decomposition to etf-premium skill
Adds Sub-Skill E that decomposes a single-day ETF surge into NAV-driven
vs structural components, quantifies dealer gamma exposure (GEX) from
the options chain, and assesses an hours/days/weeks convergence timeline.
The existing snapshot/comparison/screener/deep-dive sub-skills handle
the resting case; this new flow is for the dynamic case where an ETF
has moved much more than its underlying basket and the user wants to
attribute how much of the move was structural and when it will revert.
* Trim etf-premium description under 1024 char lint limit
* Add company-valuation skill
DCF + relative (peer multiples) + SOTP triangulation with blended implied
share price, WACC × g sensitivity matrix, and Bull/Base/Bear scenarios.
Sourced from Notion DCF and SOTP guides; includes sector-specific guidance
(software, retail, financials, healthcare, energy, manufacturing, CPG,
telecom, REITs, streaming) in references/.
Also registers the skill on the website (data/skills.ts) with a mock
terminal demo for the detail page.
* Remove Chinese triggers from company-valuation description
Update the hormuz-strait skill to match the live
hormuzstraitmonitor.com/api/dashboard response. Documents the new
`tankerRates` section, corrects enum casing for `straitStatus.status`,
`insurance.level`, `diplomacy.status`, `affectedRegions[].severity`,
and `crisisTimeline.events[].type`, adds the observed `EXTREME`
insurance level, and clarifies that `data.lastUpdated` is a string on
`data`, not a nested object.
* feat: add opencli-reader fallback skill
Generic read-only fallback for any site opencli supports but this repo
doesn't have a dedicated reader for. Routes to the right adapter by
discovering commands at runtime via `opencli list -f json` and
`opencli <site> --help` — never relying on a hand-maintained list.
Covers 90+ sources including Yahoo Finance, Bloomberg, Reuters,
Barchart, Eastmoney, Xueqiu, Sinafinance, Reddit, HackerNews, Substack,
Medium, arXiv, Google Scholar, Weibo, Bilibili, Xiaohongshu, Zhihu,
36kr, Jike, Bluesky, Apple Podcasts, Xiaoyuzhou, Spotify, YouTube,
Amazon, Taobao, JD, etc.
The skill explicitly defers to dedicated readers when the source
matches one (twitter-reader, linkedin-reader, discord-reader,
telegram-reader, yc-reader) and forbids write operations across all
adapters.
Two reference files:
- discovery.md: how to navigate `opencli list` and distinguish read
vs write commands
- finance-sources.md: curated per-adapter notes for finance-heavy
sources with read/write split
* fix: shorten opencli-reader description to pass lint
Lint requires description under 1024 chars and no angle brackets.
Previous description was 1424 chars and contained `<site>` placeholder.
* fix: trim opencli-reader description further to pass lint
Previous shortening only got to 1035 chars per the linter's measurement
(likely counting the full folded content including triggers). Removed
a few less-essential site names and redundant trigger examples to bring
the description comfortably under the 1024-char limit.
* feat(web): list opencli-reader skill on finance-skills.himself65.com
- Adds opencli-reader to the skills data with 'new' badge, sentiment
category, and social-readers plugin group
- Adds a mock terminal session showing the discover → fetch flow
(opencli list -> eastmoney hot-rank -> hackernews top)
Verified with `pnpm build`: now generates 22 static skill pages (was 21).
yfinance returns tz-aware datetime indices (America/New_York), but
the skill had no guidance about this. Generated code would compare
tz-naive Timestamps against tz-aware indices, causing:
TypeError: Cannot compare tz-naive and tz-aware datetime-like objects
Added timezone handling as a key rule in SKILL.md and a dedicated
section with code examples in the API reference.
SKILL.md body was 530 lines, exceeding the 500-line lint limit.
Move the options_spread_analysis and order_book_proxy code blocks
to references/liquidity_reference.md, replacing them with brief
descriptions and pointers. Brings the body down to 497 lines.
* Split startup-tools into separate startup-tools and ui-tools plugins
Move generative-ui from finance-startup-tools into its own
finance-ui-tools plugin — they serve different audiences
(startup evaluation vs Claude widget design system).
Now 5 plugins: market-analysis (10), social-readers (5),
data-providers (3), startup-tools (1), ui-tools (1).
* Group homepage skill list by plugin instead of category
- SkillList now groups and filters by plugin (Market Analysis,
Social Readers, Data Providers, Startup Tools, UI Tools)
- Filter pills switch from category to plugin-based
- Each skill row shows its category as a subtle tag
- Skill detail page sidebar and tag links updated to use ?plugin=
* Add ETF Premium/Discount skill and website listing
New skill that calculates the premium or discount of an ETF's market
price relative to its NAV using yfinance. Includes four sub-skills:
single ETF snapshot with peer comparison, multi-ETF comparison,
cross-category screener (90+ ETFs), and deep-dive analysis.
- skills/etf-premium/ — SKILL.md, reference file, README
- Website: skill card with "New" badge in Analysis category
- Website: terminal animation showing BITO premium with peer table
- Root README: added to Analysis & Data table
* Trim SKILL.md description to fit 1024 char lint limit
* Fix terminal height overflow and show SEPA strategy on homepage
- Change terminal window from minHeight to fixed height so it doesn't
grow as lines animate in, causing page layout shifts
- Add overflow-y-auto with auto-scroll to keep latest output visible
- Add "strategy" to categoryOrder so SEPA skill appears on homepage
* Auto-compute fixed terminal height on skill detail pages
When minHeight is "auto" (used on /skills/[name] pages), compute a
fixed height from the tab's line count so the terminal doesn't grow
during animation.