kelly-invest-webull · git:20260711.c9add96 · 2026-07-11 · sha256 cff9269bc25711df

kelly-invest-webull git:20260711.c9add96A

Immutable. This exact content is served forever at /api/v1/blob/cff9269bc25711df.

---
name: kelly-invest-webull
description: Personal read-only App-in-Skill portfolio dashboard that aggregates Webull brokerage holdings into a local view. Use when the user invokes $kelly-invest-webull or /kelly-invest-webull, wants to review their Webull portfolio, holdings, positions, accounts (cash/margin), asset allocation, market value, unrealized P/L, day change, cash, or buying power. Read-only aggregation only — it never places, modifies, or cancels orders and never moves money.
---

# Kelly Invest (Webull)

## Overview

Use this skill as Kelly's local, read-only Webull portfolio operator. It aggregates
personal Webull brokerage accounts and holdings into one file-backed App-in-Skill
dashboard with an Overview (totals, unrealized P/L, day change, cash, allocation
donut), a sortable Positions table, an Accounts view (cash and margin), and a
per-symbol Position detail pane.

Default interaction mode: App UI. Unless the user explicitly asks for chat-only
handling, check onboarding/config, refresh or load the local portfolio snapshot,
start/reuse the local app with `app/start.sh`, and give the actual local URL. Use
chat-only mode only when the user says "纯聊天", "chat only", "不要打开 UI", or
similar.

This is a monitoring dashboard: there is no approval lifecycle and no
`decisions.json`.

## App UI Screenshots

<table>
  <tr>
    <td width="50%"><img src="assets/screenshots/overview.webp" alt="Kelly Invest overview"></td>
    <td width="50%"><img src="assets/screenshots/positions.webp" alt="Kelly Invest positions"></td>
  </tr>
  <tr>
    <td><strong>Overview</strong><br>Portfolio command desk with market value, unrealized P/L, day change, cash, an allocation-by-asset-type donut, and top day movers.</td>
    <td><strong>Positions</strong><br>Sortable holdings table across symbol, asset type, quantity, average cost, last price, market value, unrealized P/L, and portfolio weight.</td>
  </tr>
  <tr>
    <td width="50%"><img src="assets/screenshots/accounts.webp" alt="Kelly Invest accounts"></td>
    <td width="50%"><img src="assets/screenshots/detail.webp" alt="Kelly Invest position detail"></td>
  </tr>
  <tr>
    <td><strong>Accounts</strong><br>Per-account view (cash and margin) with net liquidation, total cash, buying power, and the positions held in each account.</td>
    <td><strong>Position detail</strong><br>Single-symbol view with cost basis, market value, unrealized P/L and percentage, day change, weight, and holding account.</td>
  </tr>
</table>

## Boundary

- Read-only aggregation only. The skill may read Webull account/balance/position
  data, normalize it, and write local handoff files.
- NEVER place, modify, or cancel orders. NEVER move money, transfer, withdraw, or
  change account settings. There is no trading path in this skill by design.
- The app reads and writes local files only. It must not call Webull or any remote
  system; it only renders the normalized snapshot and the demo payload.
- Treat all holdings/account data as sensitive. Do not commit `config.local.json`,
  env files, `app/.data/`, exports, or raw Webull responses.

## First Run And Onboarding

On invocation, check `app/.data/onboarding.json` and private config readiness. If
onboarding is absent/incomplete, guide setup before syncing real holdings.

To connect Webull, the user needs a Webull OpenAPI **App Key** and **App Secret**
from Webull's OpenAPI Management/Portal (region id `us`; approval typically takes
1-2 business days). A UAT test host exists at
`us-openapi-alb.uat.webullbroker.com`.

Private config priority:

1. `KELLY_INVEST_WEBULL_CONFIG=/absolute/path/to/config.json`
2. `skills/kelly-invest-webull/config.local.json`
3. `~/.config/kelly-invest-webull/config.json`
4. `skills/kelly-invest-webull/config.example.json` as template only

Env priority:

1. Existing environment variables
2. `KELLY_INVEST_WEBULL_ENV_FILE=/absolute/path/to/.env`
3. Repository root `.env`
4. `skills/kelly-invest-webull/.env.local`
5. `~/.config/kelly-invest-webull/.env`

Ask for non-secret setup details only: region, base URL, base currency, account
allowlist, and which env var names hold the App Key / App Secret. Never ask the
user to paste secret values into chat. Secrets belong only in local env files, and
config references them by name (`app_key_env`, `app_secret_env`).

When setup is complete and the user confirms, write `app/.data/onboarding.json`:

```json
{
  "completed": true,
  "completed_at": "ISO timestamp",
  "config_version": "1"
}
```

## Local App

Start the dashboard with:

```bash
skills/kelly-invest-webull/app/start.sh
```

The app uses local HTTP on `127.0.0.1`, preferring port `3000` through `4000`, or
`KELLY_INVEST_WEBULL_UI_PORT` when set. First run installs `hono` and
`@hono/node-server`; the frontend is zero-build vanilla.

## Demo Mode

- `?demo=1` opens a deterministic, fully offline mock portfolio (~10 positions
  across STOCK/ETF/CRYPTO in one cash and one margin account) with computed P/L for
  documentation and screenshots.
- `?demo=positions`, `?demo=accounts`, and `?demo=detail` select named mock scenes.
- `lang=en` or `lang=zh` forces UI chrome language for screenshots.
- Demo API responses never read or write live Webull data or local private files.

UI language: support English and Chinese chrome with `Auto` default. The user is
Chinese; keep symbols and provider values in their original form.

## Data Provider

The skill reads Webull; the app only ever reads the normalized snapshot.

- Provider selector env: `KELLY_INVEST_WEBULL_DATA_PROVIDER=local` (default).
  Reserve `webull` as the live provider name. Config `data_provider` mirrors this.
- Webull field-mapping lives in `lib/data-provider/webull.ts` (the adapter). It
  reads Webull via the official `webull-openapi-python-sdk`-style client
  (`get_account_list()`, `get_account_balance()`, `get_account_positions()`) and
  writes a normalized snapshot. Rate limit is ~10 requests / 30 seconds per App ID;
  batch and back off.
- Store secrets only via env; reference env var names in config
  (`app_key_env`, `app_secret_env`). Never hardcode credentials.

Read `references/portfolio-schema.md` before editing the app, scripts, or the
adapter. Primary local files:

- `app/.data/snapshot.json`: canonical normalized portfolio snapshot.
- `app/.data/onboarding.json`: onboarding completion marker.
- `app/.data/sync_report.json`: latest sync run result.
- `app/.data/agent.lock`: temporary lock while the skill is syncing.
- `config.local.json`: private Webull configuration, ignored by git.

Use `scripts/validate_ui_schema.ts app/.data/snapshot.json` before relying on a
snapshot in the UI. `scripts/generate_demo_snapshot.ts` writes a consistent demo
snapshot to `app/.data/snapshot.json`.

## Views

- `#/overview`: total market value, total unrealized P/L (color + %), day change,
  cash, and allocation-by-asset-type donut plus top day movers.
- `#/positions`: sortable table (symbol, name, qty, avg cost, last, market value,
  unrealized P/L %, weight).
- `#/accounts`: cash and margin accounts with net liquidation, cash, buying power.
- `#/accounts/<account_id>`: account summary and its filtered positions.
- `#/positions/<symbol>`: per-symbol detail pane.
- `#/settings`: sanitized setup summary — data provider, config path, Webull region
  and base URL, credential-readiness booleans, and onboarding state. Never expose
  secret values.

## Safety

- Read-only by design. Prefer read-only Webull scopes/credentials.
- Do not invent prices or fills. If a price or balance looks stale or missing, add
  a snapshot warning instead of guessing.
- Redact credential-like strings in logs, reports, and UI state.
- Keep local exports minimal and use stable ids so repeated syncs are idempotent.