一键导入
x-poster
Mirror the Telegram briefing to X (Twitter) as a thread. Adds a hashtag preamble —
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Mirror the Telegram briefing to X (Twitter) as a thread. Adds a hashtag preamble —
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Replay trade-journal records from bt-gateway's Firestore into the graphiti graph memory. Use this once at initial setup to seed graphiti with historical trades, and ad-hoc whenever a multi-day graphiti outage caused real-time ingests to be lost. Trigger when the user says "backfill graphiti", "seed the graph", "replay missed ingestions", or after standing up a new graphiti instance.
For every skipped setup whose invalidation window has elapsed, fetch the price now and attach a Counterfactual edge in graphiti recording what the stock did since the skip. This is the feedback signal for "we decided not to act — was that right?" Run this skill daily, typically as part of the evening routine after trade-journal but before retrospective. Trigger when the user asks "what did we miss?", "show counterfactuals", or wants to evaluate the engine's non-action decisions.
Weekly pattern-mining pass over the trade journal. Reads the journal via bt-gateway (`store.listJournal()`), clusters closed trades by trade_type, sector, exit_reason, and thesis_verdict, identifies patterns that repeat (both successes and failures), and appends distilled observations to `LESSONS.md`. Run this skill once a week, typically Friday evening after the post-close run, or on-demand when the user asks for a performance review, a post-mortem on a losing streak, or wants to revisit what the strategy has learned. Also trigger before making larger-than-usual strategy changes — the lessons are the empirical grounding for any rule adjustments.
Build the engine's working memory at the start of every routine run. Fetches current positions from bt-gateway and per-position theses + recent exits from the Firestore trade journal (both source-of-truth); reads active priors and themes from LESSONS.md / THEMES.md; best-effort pulls prior news and open skipped-setups from graphiti (degraded — graphiti is enrichment only, never load-bearing). Emits a structured brief that every downstream skill reads before acting. Trigger this skill as Step 1 of the morning run and Step 1 of the evening run, immediately after the gateway preflight (Step 0) and before any analyst, scanner, or decision-making skill. Also trigger when the user asks "what does the engine know right now?", "what's our current context?", or wants to inspect the engine's working memory before a manual decision.
Record the full story behind every trade — entry thesis, market context at entry, exit reason, and outcome — to build a corpus the strategy can learn from. Trigger this skill in two places. First, at ENTRY: whenever trade-executor fills a new position, immediately append an entry record with the thesis and context. Second, at EXIT: whenever portfolio-manager detects a position has been closed (sold, stopped out, or taken profit), append an exit record that closes the loop with outcome and lessons. This skill is the raw material the retrospective skill consumes weekly. Also trigger when the user asks to review past trades, search the journal, or understand why a particular trade was entered or exited.
Format and send trading briefings via Telegram. Use this skill at the end of every morning and evening trading run to deliver the daily analysis, decisions, and portfolio status to the user. It compiles outputs from all other skills into a clear, actionable Telegram message. Also use for urgent alerts (stop-loss hits, override notifications, gateway errors). Trigger at the end of every daily run, or when an urgent alert needs to be sent.
| name | x-poster |
| description | Mirror the Telegram briefing to X (Twitter) as a thread. Adds a hashtag preamble — |
Posts the exact same body that telegram-reporter just sent — as an X thread, with a hashtag preamble for filterability.
OAuth 1.0a user context credentials (set on the routine env, never in the repo):
X_API_KEY — consumer key (a.k.a. "API Key")X_API_SECRET — consumer secretX_ACCESS_TOKEN — user access tokenX_ACCESS_TOKEN_SECRET — user access token secretMode detection (one of these must be set):
EXECUTION_MODE — demo or live (preferred)BT_GATEWAY_API_KEY — falls back to inferring from the bvb_demo_ / bvb_live_ prefixOptional — discoverability tuning:
X_HASHTAGS — full custom hashtag set (space-separated, with or without #). When set, replaces the default #BVB #stocks #fintwit #Romania #algotrading. The #<mode> tag (#demo / #live) is always appended regardless.X_VENUE_HASHTAG — only the venue tag (default BVB). Ignored when X_HASHTAGS is set.X_MENTIONS — comma- or space-separated list of @-handles to prepend to every post (with or without @). Use for accounts that should be tagged regardless of which tickers the post discusses — e.g. the exchange itself, the central bank, regulator. Example: X_MENTIONS="@BVBRomania @bnr_ro". Empty / unset → no static mentions.scripts/ticker_x_handles.json — ticker → handle map for per-post dynamic mentions. When a post discusses TLV, x-poster auto-adds the @ from this file's "TLV" entry. Empty string = no @ for that ticker. Fill in handles only after verifying them yourself. See "Dynamic ticker mentions" below.Optional — testing:
X_DRY_RUN=1 — log the composed tweets but don't actually postBVB-Plus tickers in the body are automatically converted to FinTwit-style $TICKER cashtags before the body is split. This makes posts indexable by per-symbol pages on X, StockTwits, TradingView, etc.
Handled tickers (BET-Plus universe):
Special cases:
M (Medlife) — only matched when not preceded by digit/dot, so EUR 60.4M is NOT converted but M (Medlife) RSI 25 IS.BVB — excluded from auto-conversion because every briefing title is "BVB ENGINE…" and the venue hashtag is #BVB. If the engine ever trades the exchange's own ticker, add it back with stricter context.Body content writers don't need to manually $-prefix anything — the publisher does it on the way out.
X's anti-spam policy (introduced 2024) rejects any tweet with 2+ $TICKER references — HTTP 403 from POST /2/tweets. Our publisher handles this AFTER splitting the thread: per tweet, the first $TICKER is kept intact; every subsequent cashtag in the same tweet is reverted to plain TICKER. The same ticker usually appears cashtagged in another tweet of the same thread (different section), so discoverability is preserved across the thread even if a single tweet only carries one cashtag.
The relevant tradeoff: a portfolio-section tweet listing 4 holdings will only auto-link the first one to X's per-symbol page. Acceptable because the ticker @-handles (see "Dynamic ticker mentions" below) already notify each company's account anyway, and the same tickers are usually cashtagged in news/conviction sections.
After detecting tickers in the body, the publisher looks up each one in scripts/ticker_x_handles.json and appends a trailing reply tweet carrying the corresponding @-handles. This means a post discussing TLV automatically tags @TLVbank (or whatever's in the JSON), surfacing it to that account's followers — without burying the whole thread under "Replies" on the user's profile.
Detection runs before cashtag conversion, so the regex sees the original BRD not $BRD — handles are looked up correctly regardless of cashtagging.
X classifies a tweet that starts with @username as a reply, not an original post — it gets routed to the "Replies" tab on the author's profile and is downranked in followers' main timelines. Putting our @-mentions in a trailing reply (chained via in_reply_to_tweet_id so it stays in the thread) keeps the first tweet a proper top-level post while still notifying every tagged account.
The trailing mentions tweet is composed as:
<static mentions from X_MENTIONS> + <ticker mentions from JSON, ordered by first appearance in body>
Caps (to prevent spammy posts):
Excess handles beyond the cap are dropped silently. If a post mentions 7 tickers, only the first 5 (by body order) get @-tagged. If there are no handles to tag, the trailing tweet is omitted entirely.
Open scripts/ticker_x_handles.json and replace empty strings with verified handles:
{
"TLV": "@TLVbank",
"BRD": "", ← still unverified, no @ will be added
"ONE": "@OneUnitedProp"
}
Don't guess. Wrong @ is worse than no @.
getTickerMentions() logs a warning and returns no mentions. Static mentions (from X_MENTIONS) still work. The post goes out, just without ticker-specific tagging. Safe default.
telegram-reporter writes the body it just sent to /tmp/last_telegram_message.md. This skill reads that file and pipes it into the publisher script. If the file is missing or empty, log it and skip — never block the run.
node scripts/x_publisher.mjs --file /tmp/last_telegram_message.md
The script handles:
#BVB #demo (or #BVB #live) to the first tweetreply.in_reply_to_tweet_idtelegram-reporter. Last step.telegram-reporter. Last step (after retrospective on Fridays)./tmp/last_telegram_message.md.The user has explicitly chosen to mirror the Telegram content identically. This means cash balances, position sizes, broker IDs, and verbatim theses are posted publicly. If that ever changes, this skill is where to redact — pre-process the body before passing it to x_publisher.mjs. Until then, no filtering happens here.
Each run posts a JSON line to stdout:
{"ok": true, "tweet_ids": ["1234567890...", "..."], "count": 3}
telegram-reporter can include the count in its briefing footer ("📡 also posted to X (3 tweets)") so the user gets confirmation in the channel they're already watching.