{"id":"b5e01e41-640e-4e47-a683-820a81fbc87e","entityType":"agent","slug":"clawhub-guangfuwu-privora-cn-quant","name":"Privora · A股/港股/黄金/基金 多资产 量化分析 · 量化回测 · 模拟盘 · 实时告警 · 风险监控 · Python 策略 · AI Agent","canonicalUrl":"https://www.xpersona.co/agent/clawhub-guangfuwu-privora-cn-quant","canonicalPath":"/agent/clawhub-guangfuwu-privora-cn-quant","generatedAt":"2026-10-09T22:12:16.137Z","source":"CLAWHUB","claimStatus":"UNCLAIMED","verificationTier":"NONE","summary":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-09T06:16:00.576Z","emptyReason":null},"description":"Privora · AI Agent 投资工作流平台 — Bearer Token 即接入 /agent/skills/execute 通用 dispatcher，覆盖 A 股/港股/美股/黄金/基金/财报数据 + Python 回测（含 sandbox）+ 模拟交易 + 组合归因（α/β TWR）+ 云端告警 + 流程编排。Hermes / Claude / GPT / OpenClaw 全兼容。","descriptionLabel":"Source description","evidenceSummary":"Capability contract not published. No trust telemetry is available yet. 4K downloads reported by the source. Last updated 10/9/2026.","installCommand":"clawhub skill install s176cdswsdgj9mhn1fnmzjqmqn83x50d:privora-cn-quant","sourceUrl":"https://clawhub.ai/guangfuwu/privora-cn-quant","homepage":"https://clawhub.ai/guangfuwu/skills/privora-cn-quant","primaryLinks":[{"label":"View on ClawHub","url":"https://clawhub.ai/guangfuwu/privora-cn-quant","kind":"source"},{"label":"Homepage","url":"https://clawhub.ai/guangfuwu/skills/privora-cn-quant","kind":"homepage"}],"safetyScore":84,"overallRank":62,"popularityScore":72,"trustScore":null,"claimedByName":null,"isOwner":false,"seoDescription":"Privora · A股/港股/黄金/基金 多资产 量化分析 · 量化回测 · 模拟盘 · 实时告警 · 风险监控 · Python 策略 · AI Agent technical dossier on Xpersona with agent coverage, OPENCLEW support, and live t"},"coverage":{"evidence":{"source":"public-profile","verified":false,"confidence":"medium","updatedAt":"2026-10-09T06:16:00.576Z","emptyReason":null},"protocols":[{"protocol":"OPENCLEW","label":"OpenClaw","status":"self-declared","notes":"Declared in the public agent profile."}],"capabilities":[],"verifiedCount":0,"selfDeclaredCount":1,"capabilityMatrix":{"rows":[{"key":"OPENCLEW","type":"protocol","support":"unknown","confidenceSource":"profile","notes":"Listed on profile"}],"flattenedTokens":"protocol:OPENCLEW|unknown|profile"}},"adoption":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-09T06:16:00.576Z","emptyReason":null},"stars":null,"forks":null,"downloads":3968,"packageName":null,"latestVersion":"1.0.57","tractionLabel":"4K downloads"},"release":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-09T06:16:00.576Z","emptyReason":null},"lastUpdatedAt":"2026-10-09T06:16:00.576Z","lastCrawledAt":"2026-10-09T06:16:00.576Z","lastIndexedAt":null,"nextCrawlAt":"2026-10-10T06:16:00.576Z","lastVerifiedAt":null,"highlights":[{"version":"1.0.57","createdAt":"2026-09-21T09:28:02.096Z","changelog":"## v1.0.57 · 2026-09-18 Host-consent MCP tool annotations + honesty pass on the confirm-handshake wording (#1462 ① route — ClawHub had flagged v1.0.56 `suspicious` for \"agent can complete destructive workflow/scheduler operations without independent human approval\"). - **MCP server (`mcp-server/`) now discloses a risk signal to the host it never gave it before.** Every tool in `tools/list` carries an `annotations` object (`readOnlyHint:true` on the 10 read-only tools; `destructiveHint:true` on the new dispatcher below). A new tool, `execute_confirm_required_skill`, is restricted — via a live per-call catalog lookup, never a static list — to the ~20 `confirmRequired:true` skills (the same destructive/high-risk set this package's own two-step approval handshake already gates); `execute_skill` now refuses those skillIds client-side and points the caller at the new tool instead. **These annotations are a disclosure, not a security boundary** — a host is free to ignore them, exactly like this package's own packaging-time skill allowlist; the actual, unbypassable authorization check has always been and remains the server-side scope check. `mcp-server`'s `tools/list` is now 12 tools, not 11 — see `mcp-server/README.md` and `mcp-server/CHANGELOG.md` (`0.1.2`). - **Corrected an over-strong claim in a live, machine-readable API field, not just prose**: the token-mode 409's `next` field used to read `'human-approves-then-resend-see-nextAction'`. It does not — `AgentApprovalService. selfConfirm()` sets `approver_user` to the SAME identity as the requester; the two-step handshake this package documents can be, and normally is, completed by the same agent that triggered it. Now reads `'self-confirm-or-await-admin-then-resend'`. The §高风险操作确认握手 409 example in this file is updated to match. - **《🛡️ Scope 与操作者责任》一节补上同一句逐字遵从的魔鬼在细节里：**“平台强制两步确认握手” 指的是“强制两步”，不是“强制两个主体”——补上一句明确说明：这道门防的是单次误触，不是 他人审批；要真正的人工把关，只有两条路：不授予这些 scope，或走平台 UI 由管理员 approve/reject。 - 无行为变化：本包自己的 REST/shell 调用链路不受影响，上述两条都是 MCP 新增能力 + 文档误差修正。","fileCount":5,"zipByteSize":111719},{"version":"1.0.56","createdAt":"2026-09-18T07:09:01.733Z","changelog":"## v1.0.56 · 2026-09-18 Fixes the request-body temp-file exposure `1.0.55` disclosed and deferred (#1411) -- the same finding kept sibling package `privora-alert` at `suspicious`/`fail` on ClawHub since its `1.0.6`. - **The request body no longer touches disk.** `scripts/lg_agent_exec.sh` and `scripts/lg_agent_approval.sh` used to write the outgoing JSON body to a temp file (`--data-binary \"@file\"`), which on Windows/MSYS2 inherited its `%TEMP%` directory's ACL (any local principal could read it) instead of a private mode bit. The body now joins the same `-K -` config stream the credential already travels over (`data-binary = \"<escaped>\"`, reusing `1.0.55`'s CR/LF-rejecting, `\\`/`\"`-escaping function), and the EXIT cleanup trap this removes was itself an injection surface -- both are gone, not patched. - **BREAKING (loopback / self-hosted only): a request body between roughly 77KB and 256KB can no longer be sent through a loopback or self-hosted Express connection** (this repo's own way of pushing large `stepConf` / pipeline-registration payloads, e.g. `process.pipeline.build`, `process.pipeline.update` — see `lib/body-parser-limits.js`'s `LARGE_JSON_LIMIT='256kb'`, which is why *this* endpoint feels this more than most: it is one of the few routes allowed a body bigger than the default 100KB in the first place). Escaping for the config stream roughly doubles a quote-dense JSON body's size, so bodies above ~77KB can produce a config line over the new 102,400-byte local ceiling this release adds. On curl 7.81–8.1.x (Ubuntu 22.04, Debian 12) that number is curl's own real `MAX_CONFIG_LINE_LENGTH`; curl 8.2.0 (2023-07) onward raised that internal ceiling to 10 MiB, so on a newer curl this ceiling is this wrapper's OWN conservative, version-independent choice (applied uniformly rather than probing the local curl version), not a curl limitation on that host. The public entry point is unaffected either way: `privora.cn` already 414s anything over ~5–8KB at the nginx layer before this ceiling would matter. Split a large payload into smaller calls, or use the platform UI, if you hit this. - No change to the 20-skill catalog or any skill's own behavior. This file starts at `1.0.54` because that is the first release cut after `publish.sh` stopped hard-coding its changelog string as a Bash variable (see that release's own entry below for why). `1.0.52` and `1.0.53` were bumped in `SKILL.md`'s frontmatter but never actually published to ClawHub — for anything before this file existed, `git log -- agent-skill/SKILL.md` is the record, not this file.","fileCount":5,"zipByteSize":110520},{"version":"1.0.55","createdAt":"2026-09-15T12:16:18.287Z","changelog":"## v1.0.55 · 2026-09-15 **BREAKING CHANGE.** ClawHub's automated re-scan of `1.0.54` dropped this package's rating from `pass`/`clean`/`benign`/high-confidence to `fail`/`suspicious`/medium-confidence. Two of three independent scan samples pointed at the same finding, and the scanner spelled out the fix: the umbrella package's destination check \"permits arbitrary HTTPS credential recipients without an explicit custom-host opt-in in this package.\" - 🔒⚠️ **`LG_AGENT_BASE_URL`'s host now defaults to an allowlist, not \"anything syntactically valid https\".** `scripts/lg_agent_exec.sh`, `scripts/lg_agent_list.sh`, and `scripts/lg_agent_approval.sh` now accept, by default, only the official domains (`privora.cn`, `www.privora.cn`, `lg-data.cc`) and loopback (`localhost`, `127.0.0.1`, `[::1]`). Any other host is rejected before any request is dispatched — the bearer token/cookie never leaves the process. - 🆕 **New env var: `LG_AGENT_ALLOWED_HOSTS`** — whitespace-separated list of additional hosts to accept, exact match, case-insensitive (`LG_AGENT_ALLOWED_HOSTS=\"my-lg.internal.example another.example\"`). No wildcards: `*`, `*.example.com`, and the empty string are all invalid and are rejected outright, never treated as \"accept anything.\" This variable has **no effect** on the narrow-package release shape (`privora-alert`, identified by a shipped `allowed-skills.txt`) — that package continues to pin its host to the official domains unconditionally, exactly as before. - 🚨 **Migration required if you self-host:** if your `LG_AGENT_BASE_URL` already points at a domain other than the three official ones or a loopback address, upgrading to `1.0.55` without also setting `LG_AGENT_ALLOWED_HOSTS` will make every call fail closed with a clear error naming the rejected host and the exact env var + syntax needed to restore access. Self-hosting itself is not removed — it now requires one explicit env var instead of being silently accepted. - ℹ️ Out of scope for this release: `mcp-server/src/config.js` uses the same `LG_AGENT_TOKEN`/`LG_AGENT_BASE_URL` credential model but has its own, currently unvalidated, destination handling — tracked separately (#1424), not fixed here.","fileCount":5,"zipByteSize":108865},{"version":"1.0.54","createdAt":"2026-09-15T09:47:27.298Z","changelog":"## v1.0.54 · 2026-09-15 Republish, not a version-by-version catch-up. ClawHub's last published `privora-cn-quant` is `1.0.51` (2026-08-31); `1.0.52`/`1.0.53` were bumped in `SKILL.md`'s frontmatter but never published (`git log -- agent-skill/SKILL.md` is the record). So from an installed user's perspective this one release covers everything below, plus three security fixes to the two wrapper scripts this package ships (`scripts/lg_agent_list.sh`, `scripts/lg_agent_exec.sh`) that already shipped to the sibling `privora-alert` package (its `1.0.5`/`1.0.6`) but had never reached this umbrella package. **Doc/scope changes carried over from the unpublished 1.0.52/1.0.53 bumps** (verify against `git show <sha> -- agent-skill/SKILL.md`, not this summary — that's what the commits below are for): - **MCP server discovery section** (§1, \"🔌 用 MCP 客户端？有原生通道，两条并存\"), added in `f57e35b6` (#1140/#1141 — the actual `1.0.51→1.0.52` content change): documents a native MCP (stdio) channel alongside this package's existing env-var/shell channel — same two HTTP routes, same two env variables, same server-decided authorization either way — but that MCP package is **not published to npm** (`mcp-server/package.json` still carries `\"private\": true`). `6cba3638` (#1123/#1142 — the `1.0.52→1.0.53` bump) then renamed the npm package name this section cites, from the placeholder `lg-agent-mcp-server` to the now-claimed `@privora/mcp-server`; it does not change the \"not published yet\" fact. Either way: check out the repo and point your MCP client at the absolute path of `mcp-server/README.md` — do not `npx` it, that command does not resolve to anything usable today. - **Scope preset quick-reference table locked to `SCOPE_PRESETS`** (`83d6aef9`, #1290): the table is now mechanically guarded against drifting from `lib/skill-catalog.js` (`test/skill-md-scope-preset-table.test.js`). The `subscribe-and-read` preset's row is now bolded **含写权限**: it can subscribe to and unsubscribe from marketplace items, and **unsubscribing deletes your team's cloned copy of that asset** — despite the name, it is not read-only. The token-create UI's wildcard (`*`) checkbox now shows an inline warning that `*` grants every scope, including the reserved `paper.*` namespace and every confirm-gated destructive skill. - **`portfolio` preset gained two read scopes** it was actually missing by the time this package's table caught up: `investment.stock.watchlist.list` (`ee8701d4`, #1307) and `investment.stock.signal.{list,get}` (`f4533182`, #1342) — both land inside the existing `portfolio` scope preset; no new preset was added and no write scope changed. **Security fixes (#1408, #1410) to the shared wrapper scripts this package ships** — what they mean if you already installed this package: - **Destination validation.** `LG_AGENT_BASE_URL` is now checked before your bearer token is ever sent anywhere: a non-`http(s)` scheme, a URL with embedded credentials (`https://user:pass@host`), or plaintext `http://` against anything other than a loopback host are all rejected outright. ⚠️ **This package does NOT pin the host to an official domain list** — self-hosting your own backend (documented in `mcp-server/README.md`'s `https://your-lg-web-host` example) keeps working exactly as before. The host pin only activates when the script ships next to a sibling `allowed-skills.txt` file (the narrower `privora-alert` package's shape); this umbrella package ships no such file, so self-hosted users are unaffected. - **Default destination flipped** from `lg-data.cc` to `privora.cn` — both domains serve this API path directly, so this is a no-op for anyone who already sets `LG_AGENT_BASE_URL`, and a no-behavior-change default for anyone who doesn't. - **Credentials no longer appear in `curl`'s command-line arguments.** Your bearer token now travels to `curl` via a piped `-K -` config stream instead of a `-H \"Authorization: Bearer ...\"` argv element — any other local process on the same host could previously read your token straight out of `/proc/*/cmdline` (Linux) or a Windows process listing, no elevation required. Every value written into that config stream is also now CR/LF-rejected and `\\`/`\"`-escaped, closing a config-stream injection that this same fix's first pass introduced and a second pass then closed. - **The cleanup trap no longer re-parses a hostile `TMPDIR`-derived path as shell syntax.** A `TMPDIR` environment value containing shell metacharacters could previously run arbitrary commands when the script's temp request-body file cleanup fired at exit. - **Not fixed — disclosed, not implied-fixed:** the request body still touches disk via a temp file, and on Windows/MSYS2 that file still inherits its `%TEMP%` directory's ACL instead of getting a private mode bit (tracked separately, #1411). POSIX hosts already get a real `mktemp` `0600` file and are unaffected either way. `SKILL.md` bumped to `1.0.54`, `updatedAt: 2026-09-15`. No skill/scope behavior changes beyond what's listed above — everything else is the carried-over 1.0.52/1.0.53 content plus the shared-script security fixes.","fileCount":5,"zipByteSize":103933},{"version":"1.0.51","createdAt":"2026-08-31T07:51:30.567Z","changelog":"修正破坏性操作披露的三处不实陈述。§Scope 此前声称本 skill「不暴露」持久化记录的删除/撤销/reset、调度器 online/offline 状态转移、以及 webhook 插件生命周期变更 —— 三条均与本文档自身其它章节矛盾:前两类共 14 个技能 Bearer token 可达(需两步确认握手),而 schedule.job.plugins.save / depends.save 是全量替换(旧绑定先整体删除)且不经任何确认门槛。「管理员级账户操作不暴露」属实,原样保留。另:确认握手可达技能数由 13 更正为 14(补上此前从未文档化的 team.python.method.delete,不可逆、会使依赖它的脚本从下次运行起 ImportError),新增 team.python.method.* 全部 5 个技能的说明表,并新增「409 响应辨析」一节 —— 破坏性路径上 409 有六种互不相关的含义,其中一种是终态(永远无法完成握手),此前无从区分。","fileCount":5,"zipByteSize":89071},{"version":"1.0.50","createdAt":"2026-08-27T08:48:04.593Z","changelog":"v1.0.50 · Fixes documentation that sent readers to an asset id belonging to the publisher rather than themselves. Subscribing clones an asset into your own tenant under a different id (asset-1 is id 1 to the publisher, 398 / 268 / 402 to three different subscribers), so the first call after subscribing was a guaranteed 404. Section 0 now leads with marketplace.item.subscribe's clonedAssetId response field -- the subscribe upsert is idempotent, so an existing subscriber gets it by calling again -- with dataasset.list plus the Subscribed tag as the fallback. Section 4 was already correct and is unchanged in that respect. Also corrects the paper-trading token guidance: one line told readers to mint a PAT carrying paper.* scopes, which two other sections correctly say is impossible (rejectReservedScopes rejects the paper. prefix unconditionally). And discloses, for the first time, which skills fall outside the default read-data preset and will therefore 403 on a token created by accepting the defaults: datasource.list, datasource.get, datasource.list.active, datasource.connection.test, dataasset.metadata.get, dataasset.history.field-as-of, and marketplace.item.subscribe.","fileCount":5,"zipByteSize":84964},{"version":"1.0.48","createdAt":"2026-08-11T06:49:16.237Z","changelog":"v1.0.48 · Corrects the paper-trading section (scenario 6), which previously showed paper.account.create / paper.order.place / paper.order.get — none of which exist in the catalog (they return 400 Skill not found), and paper.* is a reserved scope namespace that cannot be self-minted (400 RESERVED_SCOPE). Rewritten to the real path: investment.paper.* is reached only from inside a Process python_script node via the lg.paper.* SDK (the platform auto-injects a scope-limited short-lived Bearer at run time), or by subscribing the starter_paper_trade_strategy template — an external Agent cannot call it by changing an id. Also folds in changes accumulated since 1.0.47 but never released: a 场景→scope 速查表 (a freshly-created token's default read-data scope already fetches data; per-scenario preset buttons; GET /agent/scope-presets and a full GET /agent/skills catalogue annotated with granted; 403/400 self-healing via requiredScope / didYouMean); schedule.job.depends now documents dependGroup (OR within a group, AND across groups); and a cross-reference to the new scenario-shaped package privora-alert for the alert-only use case.","fileCount":5,"zipByteSize":68771},{"version":"1.0.47","createdAt":"2026-07-30T09:05:15.440Z","changelog":"v1.0.47 · 「数据资产可用性」快照节与 Quick Start §0 各新增一条指引:完整覆盖范围、分市场明细、更新频率与数据起始日期改以持续维护的公开清单页 privora.cn/features/realtime-minute-data-coverage 为权威口径(按六类分组)。快照节本身标注为 2026-07-17 的一次性盘点,不再作为权威数据。","fileCount":5,"zipByteSize":65335}]},"execution":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No published capability contract is available yet."},"installCommand":"clawhub skill install s176cdswsdgj9mhn1fnmzjqmqn83x50d:privora-cn-quant","setupComplexity":"low","setupSteps":["Install using `clawhub skill install s176cdswsdgj9mhn1fnmzjqmqn83x50d:privora-cn-quant` in an isolated environment before connecting it to live workloads.","No published capability contract is available yet, so validate auth and request/response behavior manually.","Review the upstream CLAWHUB listing at https://clawhub.ai/guangfuwu/privora-cn-quant before using production credentials."],"contract":{"contractStatus":"missing","authModes":[],"requires":[],"forbidden":[],"supportsMcp":false,"supportsA2a":false,"supportsStreaming":false,"inputSchemaRef":null,"outputSchemaRef":null,"dataRegion":null,"contractUpdatedAt":null,"sourceUpdatedAt":null,"freshnessSeconds":null},"invocationGuide":{"preferredApi":{"snapshotUrl":"https://www.xpersona.co/api/v1/agents/clawhub-guangfuwu-privora-cn-quant/snapshot","contractUrl":"https://www.xpersona.co/api/v1/agents/clawhub-guangfuwu-privora-cn-quant/contract","trustUrl":"https://www.xpersona.co/api/v1/agents/clawhub-guangfuwu-privora-cn-quant/trust"},"curlExamples":["curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-guangfuwu-privora-cn-quant/snapshot\"","curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-guangfuwu-privora-cn-quant/contract\"","curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-guangfuwu-privora-cn-quant/trust\""],"jsonRequestTemplate":{"query":"summarize this repo","constraints":{"maxLatencyMs":2000,"protocolPreference":["OPENCLEW"]}},"jsonResponseTemplate":{"ok":true,"result":{"summary":"...","confidence":0.9},"meta":{"source":"CLAWHUB","generatedAt":"2026-10-09T22:12:16.133Z"}},"retryPolicy":{"maxAttempts":3,"backoffMs":[500,1500,3500],"retryableConditions":["HTTP_429","HTTP_503","NETWORK_TIMEOUT"]}},"endpoints":{"dossierUrl":"https://www.xpersona.co/api/v1/agents/clawhub-guangfuwu-privora-cn-quant/dossier","snapshotUrl":"https://www.xpersona.co/api/v1/agents/clawhub-guangfuwu-privora-cn-quant/snapshot","contractUrl":"https://www.xpersona.co/api/v1/agents/clawhub-guangfuwu-privora-cn-quant/contract","trustUrl":"https://www.xpersona.co/api/v1/agents/clawhub-guangfuwu-privora-cn-quant/trust"}},"reliability":{"evidence":{"source":"runtime-metrics","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No trust, reliability, or runtime telemetry is available."},"trust":{"status":"unavailable","handshakeStatus":"UNKNOWN","verificationFreshnessHours":null,"reputationScore":null,"p95LatencyMs":null,"successRate30d":null,"fallbackRate":null,"attempts30d":null,"trustUpdatedAt":null,"trustConfidence":"unknown","sourceUpdatedAt":null,"freshnessSeconds":null},"decisionGuardrails":{"doNotUseIf":["Contract metadata is missing or unavailable for deterministic execution."],"safeUseWhen":[],"riskFlags":["missing_or_unavailable_contract","trust_data_unavailable","schema_references_missing"],"operationalConfidence":"low"},"executionMetrics":{"observedLatencyMsP50":null,"observedLatencyMsP95":null,"estimatedCostUsd":null,"uptime30d":null,"rateLimitRpm":null,"rateLimitBurst":null,"lastVerifiedAt":null,"verificationSource":null},"runtimeMetrics":{"successRate":null,"avgLatencyMs":null,"avgCostUsd":null,"hallucinationRate":null,"retryRate":null,"disputeRate":null,"p50Latency":null,"p95Latency":null,"lastUpdated":null}},"benchmarks":{"evidence":{"source":"no-benchmark-data","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No benchmark suites or observed failure patterns are available."},"suites":[],"failurePatterns":[]},"artifacts":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-09T06:16:00.576Z","emptyReason":null},"readme":"Skill: Privora · A股/港股/黄金/基金 多资产 量化分析 · 量化回测 · 模拟盘 · 实时告警 · 风险监控 · Python 策略 · AI Agent\n\nOwner: guangfuwu\n\nSummary: Privora · AI Agent 投资工作流平台 — Bearer Token 即接入 /agent/skills/execute 通用 dispatcher，覆盖 A 股/港股/美股/黄金/基金/财报数据 + Python 回测（含 sandbox）+ 模拟交易 + 组合归因（α/β TWR）+ 云端告警 + 流程编排。Hermes / Claude / GPT / OpenClaw 全兼容。\n\nTags: latest:1.0.57\n\nVersion history:\n\nv1.0.57 | 2026-09-21T09:28:02.096Z | user\n\n## v1.0.57 · 2026-09-18\n\nHost-consent MCP tool annotations + honesty pass on the confirm-handshake wording\n(#1462 ① route — ClawHub had flagged v1.0.56 `suspicious` for \"agent can complete\ndestructive workflow/scheduler operations without independent human approval\").\n\n- **MCP server (`mcp-server/`) now discloses a risk signal to the host it never\n  gave it before.** Every tool in `tools/list` carries an `annotations` object\n  (`readOnlyHint:true` on the 10 read-only tools; `destructiveHint:true` on the\n  new dispatcher below). A new tool, `execute_confirm_required_skill`, is\n  restricted — via a live per-call catalog lookup, never a static list — to the\n  ~20 `confirmRequired:true` skills (the same destructive/high-risk set this\n  package's own two-step approval handshake already gates); `execute_skill` now\n  refuses those skillIds client-side and points the caller at the new tool\n  instead. **These annotations are a disclosure, not a security boundary** — a\n  host is free to ignore them, exactly like this package's own packaging-time\n  skill allowlist; the actual, unbypassable authorization check has always been\n  and remains the server-side scope check. `mcp-server`'s `tools/list` is now\n  12 tools, not 11 — see `mcp-server/README.md` and `mcp-server/CHANGELOG.md`\n  (`0.1.2`).\n- **Corrected an over-strong claim in a live, machine-readable API field, not\n  just prose**: the token-mode 409's `next` field used to read\n  `'human-approves-then-resend-see-nextAction'`. It does not — `AgentApprovalService.\n  selfConfirm()` sets `approver_user` to the SAME identity as the requester; the\n  two-step handshake this package documents can be, and normally is, completed\n  by the same agent that triggered it. Now reads\n  `'self-confirm-or-await-admin-then-resend'`. The §高风险操作确认握手 409 example\n  in this file is updated to match.\n- **《🛡️ Scope 与操作者责任》一节补上同一句逐字遵从的魔鬼在细节里：**“平台强制两步确认握手”\n  指的是“强制两步”，不是“强制两个主体”——补上一句明确说明：这道门防的是单次误触，不是\n  他人审批；要真正的人工把关，只有两条路：不授予这些 scope，或走平台 UI 由管理员 approve/reject。\n- 无行为变化：本包自己的 REST/shell 调用链路不受影响，上述两条都是 MCP 新增能力 + 文档误差修正。\n\nv1.0.56 | 2026-09-18T07:09:01.733Z | user\n\n## v1.0.56 · 2026-09-18\n\nFixes the request-body temp-file exposure `1.0.55` disclosed and deferred\n(#1411) -- the same finding kept sibling package `privora-alert` at\n`suspicious`/`fail` on ClawHub since its `1.0.6`.\n\n- **The request body no longer touches disk.** `scripts/lg_agent_exec.sh`\n  and `scripts/lg_agent_approval.sh` used to write the outgoing JSON body to\n  a temp file (`--data-binary \"@file\"`), which on Windows/MSYS2 inherited\n  its `%TEMP%` directory's ACL (any local principal could read it) instead\n  of a private mode bit. The body now joins the same `-K -` config stream\n  the credential already travels over (`data-binary = \"<escaped>\"`, reusing\n  `1.0.55`'s CR/LF-rejecting, `\\`/`\"`-escaping function), and the EXIT\n  cleanup trap this removes was itself an injection surface -- both are\n  gone, not patched.\n- **BREAKING (loopback / self-hosted only): a request body between roughly\n  77KB and 256KB can no longer be sent through a loopback or self-hosted\n  Express connection** (this repo's own way of pushing large `stepConf` /\n  pipeline-registration payloads, e.g. `process.pipeline.build`,\n  `process.pipeline.update` — see `lib/body-parser-limits.js`'s\n  `LARGE_JSON_LIMIT='256kb'`, which is why *this* endpoint feels this more\n  than most: it is one of the few routes allowed a body bigger than the\n  default 100KB in the first place). Escaping for the config stream roughly\n  doubles a quote-dense JSON body's size, so bodies above ~77KB can produce\n  a config line over the new 102,400-byte local ceiling this release adds.\n  On curl 7.81–8.1.x (Ubuntu 22.04, Debian 12) that number is curl's own\n  real `MAX_CONFIG_LINE_LENGTH`; curl 8.2.0 (2023-07) onward raised that\n  internal ceiling to 10 MiB, so on a newer curl this ceiling is this\n  wrapper's OWN conservative, version-independent choice (applied uniformly\n  rather than probing the local curl version), not a curl limitation on\n  that host. The public entry point is unaffected either way: `privora.cn`\n  already 414s anything over ~5–8KB at the nginx layer before this ceiling\n  would matter. Split a large payload into smaller calls, or use the\n  platform UI, if you hit this.\n- No change to the 20-skill catalog or any skill's own behavior.\n\nThis file starts at `1.0.54` because that is the first release cut after\n`publish.sh` stopped hard-coding its changelog string as a Bash variable (see\nthat release's own entry below for why). `1.0.52` and `1.0.53` were bumped in\n`SKILL.md`'s frontmatter but never actually published to ClawHub — for\nanything before this file existed, `git log -- agent-skill/SKILL.md` is the\nrecord, not this file.\n\nv1.0.55 | 2026-09-15T12:16:18.287Z | user\n\n## v1.0.55 · 2026-09-15\n\n**BREAKING CHANGE.** ClawHub's automated re-scan of `1.0.54` dropped this\npackage's rating from `pass`/`clean`/`benign`/high-confidence to\n`fail`/`suspicious`/medium-confidence. Two of three independent scan samples\npointed at the same finding, and the scanner spelled out the fix: the\numbrella package's destination check \"permits arbitrary HTTPS credential\nrecipients without an explicit custom-host opt-in in this package.\"\n\n- 🔒⚠️ **`LG_AGENT_BASE_URL`'s host now defaults to an allowlist, not\n  \"anything syntactically valid https\".** `scripts/lg_agent_exec.sh`,\n  `scripts/lg_agent_list.sh`, and `scripts/lg_agent_approval.sh` now accept,\n  by default, only the official domains (`privora.cn`, `www.privora.cn`,\n  `lg-data.cc`) and loopback (`localhost`, `127.0.0.1`, `[::1]`). Any other\n  host is rejected before any request is dispatched — the bearer token/cookie\n  never leaves the process.\n- 🆕 **New env var: `LG_AGENT_ALLOWED_HOSTS`** — whitespace-separated list of\n  additional hosts to accept, exact match, case-insensitive\n  (`LG_AGENT_ALLOWED_HOSTS=\"my-lg.internal.example another.example\"`). No\n  wildcards: `*`, `*.example.com`, and the empty string are all invalid and\n  are rejected outright, never treated as \"accept anything.\" This variable\n  has **no effect** on the narrow-package release shape (`privora-alert`,\n  identified by a shipped `allowed-skills.txt`) — that package continues to\n  pin its host to the official domains unconditionally, exactly as before.\n- 🚨 **Migration required if you self-host:** if your `LG_AGENT_BASE_URL`\n  already points at a domain other than the three official ones or a\n  loopback address, upgrading to `1.0.55` without also setting\n  `LG_AGENT_ALLOWED_HOSTS` will make every call fail closed with a clear\n  error naming the rejected host and the exact env var + syntax needed to\n  restore access. Self-hosting itself is not removed — it now requires one\n  explicit env var instead of being silently accepted.\n- ℹ️ Out of scope for this release: `mcp-server/src/config.js` uses the same\n  `LG_AGENT_TOKEN`/`LG_AGENT_BASE_URL` credential model but has its own,\n  currently unvalidated, destination handling — tracked separately (#1424),\n  not fixed here.\n\nv1.0.54 | 2026-09-15T09:47:27.298Z | user\n\n## v1.0.54 · 2026-09-15\n\nRepublish, not a version-by-version catch-up. ClawHub's last published\n`privora-cn-quant` is `1.0.51` (2026-08-31); `1.0.52`/`1.0.53` were bumped in\n`SKILL.md`'s frontmatter but never published (`git log -- agent-skill/SKILL.md`\nis the record). So from an installed user's perspective this one release\ncovers everything below, plus three security fixes to the two wrapper\nscripts this package ships (`scripts/lg_agent_list.sh`,\n`scripts/lg_agent_exec.sh`) that already shipped to the sibling\n`privora-alert` package (its `1.0.5`/`1.0.6`) but had never reached this\numbrella package.\n\n**Doc/scope changes carried over from the unpublished 1.0.52/1.0.53 bumps**\n(verify against `git show <sha> -- agent-skill/SKILL.md`, not this summary —\nthat's what the commits below are for):\n\n- **MCP server discovery section** (§1, \"🔌 用 MCP 客户端？有原生通道，两条并存\"),\n  added in `f57e35b6` (#1140/#1141 — the actual `1.0.51→1.0.52` content\n  change): documents a native MCP (stdio) channel alongside this package's\n  existing env-var/shell channel — same two HTTP routes, same two env\n  variables, same server-decided authorization either way — but that MCP\n  package is **not published to npm** (`mcp-server/package.json` still\n  carries `\"private\": true`). `6cba3638` (#1123/#1142 — the `1.0.52→1.0.53`\n  bump) then renamed the npm package name this section cites, from the\n  placeholder `lg-agent-mcp-server` to the now-claimed `@privora/mcp-server`;\n  it does not change the \"not published yet\" fact. Either way: check out the\n  repo and point your MCP client at the absolute path of\n  `mcp-server/README.md` — do not `npx` it, that command does not resolve to\n  anything usable today.\n- **Scope preset quick-reference table locked to `SCOPE_PRESETS`** (`83d6aef9`,\n  #1290): the table is now mechanically guarded against drifting from\n  `lib/skill-catalog.js` (`test/skill-md-scope-preset-table.test.js`). The\n  `subscribe-and-read` preset's row is now bolded **含写权限**: it can\n  subscribe to and unsubscribe from marketplace items, and **unsubscribing\n  deletes your team's cloned copy of that asset** — despite the name, it is\n  not read-only. The token-create UI's wildcard (`*`) checkbox now shows an\n  inline warning that `*` grants every scope, including the reserved `paper.*`\n  namespace and every confirm-gated destructive skill.\n- **`portfolio` preset gained two read scopes** it was actually missing by\n  the time this package's table caught up: `investment.stock.watchlist.list`\n  (`ee8701d4`, #1307) and `investment.stock.signal.{list,get}` (`f4533182`,\n  #1342) — both land inside the existing `portfolio` scope preset; no new\n  preset was added and no write scope changed.\n\n**Security fixes (#1408, #1410) to the shared wrapper scripts this package\nships** — what they mean if you already installed this package:\n\n- **Destination validation.** `LG_AGENT_BASE_URL` is now checked before your\n  bearer token is ever sent anywhere: a non-`http(s)` scheme, a URL with\n  embedded credentials (`https://user:pass@host`), or plaintext `http://`\n  against anything other than a loopback host are all rejected outright.\n  ⚠️ **This package does NOT pin the host to an official domain list** —\n  self-hosting your own backend (documented in `mcp-server/README.md`'s\n  `https://your-lg-web-host` example) keeps working exactly as before. The\n  host pin only activates when the script ships next to a sibling\n  `allowed-skills.txt` file (the narrower `privora-alert` package's shape);\n  this umbrella package ships no such file, so self-hosted users are\n  unaffected.\n- **Default destination flipped** from `lg-data.cc` to `privora.cn` — both\n  domains serve this API path directly, so this is a no-op for anyone who\n  already sets `LG_AGENT_BASE_URL`, and a no-behavior-change default for\n  anyone who doesn't.\n- **Credentials no longer appear in `curl`'s command-line arguments.** Your\n  bearer token now travels to `curl` via a piped `-K -` config stream instead\n  of a `-H \"Authorization: Bearer ...\"` argv element — any other local\n  process on the same host could previously read your token straight out of\n  `/proc/*/cmdline` (Linux) or a Windows process listing, no elevation\n  required. Every value written into that config stream is also now\n  CR/LF-rejected and `\\`/`\"`-escaped, closing a config-stream injection that\n  this same fix's first pass introduced and a second pass then closed.\n- **The cleanup trap no longer re-parses a hostile `TMPDIR`-derived path as\n  shell syntax.** A `TMPDIR` environment value containing shell\n  metacharacters could previously run arbitrary commands when the script's\n  temp request-body file cleanup fired at exit.\n- **Not fixed — disclosed, not implied-fixed:** the request body still\n  touches disk via a temp file, and on Windows/MSYS2 that file still\n  inherits its `%TEMP%` directory's ACL instead of getting a private mode\n  bit (tracked separately, #1411). POSIX hosts already get a real `mktemp`\n  `0600` file and are unaffected either way.\n\n`SKILL.md` bumped to `1.0.54`, `updatedAt: 2026-09-15`. No skill/scope\nbehavior changes beyond what's listed above — everything else is the\ncarried-over 1.0.52/1.0.53 content plus the shared-script security fixes.\n\nv1.0.51 | 2026-08-31T07:51:30.567Z | user\n\n修正破坏性操作披露的三处不实陈述。§Scope 此前声称本 skill「不暴露」持久化记录的删除/撤销/reset、调度器 online/offline 状态转移、以及 webhook 插件生命周期变更 —— 三条均与本文档自身其它章节矛盾:前两类共 14 个技能 Bearer token 可达(需两步确认握手),而 schedule.job.plugins.save / depends.save 是全量替换(旧绑定先整体删除)且不经任何确认门槛。「管理员级账户操作不暴露」属实,原样保留。另:确认握手可达技能数由 13 更正为 14(补上此前从未文档化的 team.python.method.delete,不可逆、会使依赖它的脚本从下次运行起 ImportError),新增 team.python.method.* 全部 5 个技能的说明表,并新增「409 响应辨析」一节 —— 破坏性路径上 409 有六种互不相关的含义,其中一种是终态(永远无法完成握手),此前无从区分。\n\nv1.0.50 | 2026-08-27T08:48:04.593Z | user\n\nv1.0.50 · Fixes documentation that sent readers to an asset id belonging to the publisher rather than themselves. Subscribing clones an asset into your own tenant under a different id (asset-1 is id 1 to the publisher, 398 / 268 / 402 to three different subscribers), so the first call after subscribing was a guaranteed 404. Section 0 now leads with marketplace.item.subscribe's clonedAssetId response field -- the subscribe upsert is idempotent, so an existing subscriber gets it by calling again -- with dataasset.list plus the Subscribed tag as the fallback. Section 4 was already correct and is unchanged in that respect. Also corrects the paper-trading token guidance: one line told readers to mint a PAT carrying paper.* scopes, which two other sections correctly say is impossible (rejectReservedScopes rejects the paper. prefix unconditionally). And discloses, for the first time, which skills fall outside the default read-data preset and will therefore 403 on a token created by accepting the defaults: datasource.list, datasource.get, datasource.list.active, datasource.connection.test, dataasset.metadata.get, dataasset.history.field-as-of, and marketplace.item.subscribe.\n\nv1.0.48 | 2026-08-11T06:49:16.237Z | user\n\nv1.0.48 · Corrects the paper-trading section (scenario 6), which previously showed paper.account.create / paper.order.place / paper.order.get — none of which exist in the catalog (they return 400 Skill not found), and paper.* is a reserved scope namespace that cannot be self-minted (400 RESERVED_SCOPE). Rewritten to the real path: investment.paper.* is reached only from inside a Process python_script node via the lg.paper.* SDK (the platform auto-injects a scope-limited short-lived Bearer at run time), or by subscribing the starter_paper_trade_strategy template — an external Agent cannot call it by changing an id. Also folds in changes accumulated since 1.0.47 but never released: a 场景→scope 速查表 (a freshly-created token's default read-data scope already fetches data; per-scenario preset buttons; GET /agent/scope-presets and a full GET /agent/skills catalogue annotated with granted; 403/400 self-healing via requiredScope / didYouMean); schedule.job.depends now documents dependGroup (OR within a group, AND across groups); and a cross-reference to the new scenario-shaped package privora-alert for the alert-only use case.\n\nv1.0.47 | 2026-07-30T09:05:15.440Z | user\n\nv1.0.47 · 「数据资产可用性」快照节与 Quick Start §0 各新增一条指引:完整覆盖范围、分市场明细、更新频率与数据起始日期改以持续维护的公开清单页 privora.cn/features/realtime-minute-data-coverage 为权威口径(按六类分组)。快照节本身标注为 2026-07-17 的一次性盘点,不再作为权威数据。\n\nv1.0.45 | 2026-07-17T03:10:13.871Z | user\n\nv1.0.45 - Named-param flat calling convention for lg_agent_exec.sh (skillId key=value key:=json --json), replacing hand-assembled envelope JSON as the default call shape - the gateway auto-classifies flat keys into pathParams/query/body per each skill's path template + method, eliminating a class of 500s from params landing in the wrong envelope layer. Per-skill params are now discoverable: GET /agent/skills returns params + exampleInvocation for every skill, and lg_agent_list.sh describe <skillId> shows one skill's schema + example on demand. key=value is always a JSON string (protects leading zeros like stock_num=000135); key:=value parses as raw JSON (number/bool/array/object) and fails loud on parse error instead of silently degrading to a string; --json '<obj>' remains the escape hatch for array/nested bodies and can be mixed with flat keys in the same call. The old full-envelope invocation (single JSON-object argument) is 100% backward compatible and unaffected. SKILL.md slimmed down accordingly: flat-key form is now the primary Quick Start path, with the envelope form demoted to a compatibility appendix.\n\nv1.0.44 | 2026-07-11T12:56:36.871Z | user\n\nv1.0.44 · Restore v1.0.42 UX (byte-identical content). v1.0.43 briefly rolled back to v1.0.40 SAFE content aiming to restore the SAFE badge, but SkillSpector v2.3.5 has today shown non-determinism — same byte-identical content scanned today returns CAUTION 4 findings score 41 regardless. Since rollback cannot restore the badge, choosing to keep the v1.0.42 usability improvements: Chinese-fied §Scope + §Not investment advice, What's-New moved to §最近更新 at bottom, Quick Start §0 marketplace UI redirect. No further disclosure-based iteration planned; next SkillSpector work needs to happen at the OpenClaw manifest permission-declaration layer (out of scope for doc-only SKILL.md changes).\n\nv1.0.43 | 2026-07-11T12:48:05.803Z | user\n\nv1.0.43 · Rollback to v1.0.40 SAFE content. v1.0.41 (§0 anon curl) and v1.0.42 (Chinese-fy Scope + §最近更新 restructure + explicit dispatcher description) both regressed to CAUTION on SkillSpector — v1.0.41 = 2 findings score 32, v1.0.42 = 4 findings score 41. v1.0.40 SAFE content restored (Path B structural reframe: primary framing to AI Agent workflow, encryption section rewrite, remove 3 只读能力 contradictions, keep First Call Recipe from v1.0.38). SEE memory clawhub_skillspector_response_playbook.md — every honest-disclosure attempt gets penalized by scanner; v1.0.40 minimal content is the maximum-badge-value baseline until we design a differently-structured next version.\n\nv1.0.42 | 2026-07-11T12:43:15.085Z | user\n\nv1.0.42 · Documentation reorganization + SkillSpector regression fix. (1) Removed the 4 What's-New blocks (v1.0.31/32/36/37) that sat at top pushing value pitch down; consolidated 8 version entries at the bottom section 最近更新. (2) Chinese-fied §Scope 与操作者责任 and §输出仅供分析参考 — no more dual-language duplicate content. (3) Rewrote Quick Start §0 30-second-try to point at privora.cn/marketplace UI instead of quoting /agent/skills/execute dispatcher at top-of-doc (which reintroduced MCP Tool Poisoning finding at 84% confidence in v1.0.41). Added explicit loop-back sentence linking §0 marketplace discovery back to §4 curl recipe so the anonymous preview is a funnel connector, not a one-way exit. LM 2 rounds of review — round-A caught version mismatch + broken §最近更新 anchor + §0 one-way exit; all 3 resolved before ship.\n\nv1.0.41 | 2026-07-11T10:30:28.959Z | user\n\nv1.0.41 · Activation-rate fix — move anonymous curl try-it-now flow to Quick Start §0 (before token registration). Root cause data measured 2026-07-11: ClawHub Downloads 30d = 574 but distinct /agent/skills/execute users = 4 (0.7% activation), and the anonymous mode advertised in v1.0.34-v1.0.36 got zero events over 30 days because the section was buried at line 200+ far below Quick Start. This version puts three ready-to-run curl examples using the anonymous whitelist (marketplace.item.list → dataasset.data.get sample data) as the very first thing an installer sees, so users can validate value in 30 seconds without hitting the register wall. Rate-limit and shape restrictions are called out inline. No capability change; discoverability restructuring only. Follow-up telemetry: watch tracking_events with properties.mode='anonymous' — currently 0 events over 30d; any positive number after v1.0.41 validates the discoverability hypothesis.\n\nv1.0.40 | 2026-07-11T08:00:27.124Z | user\n\nv1.0.40 · SkillSpector response — structural reframe. v1.0.39 disclosure approach was documented ineffective (confidence UP not down; playbook memory clawhub_skillspector_response_playbook.md). This version instead: (1) title/H1/description primary framing flipped from finance-first to AI-agent-workflow-first so the marketing claim STRUCTURALLY matches the /agent/skills/execute dispatcher capability, addressing MCP Tool Poisoning and Description-Behavior Mismatch. (2) Encryption section §2 fully rewritten to encryption-at-rest + authenticated-boundary decryption; removed the '均为密文形式' phrasing that scanner quoted at 95% confidence. (3) Deleted three copies of '只读能力与常规非破坏性写操作' paragraphs which contradicted the code-execution capability the same doc exposes elsewhere. Kept First Call Recipe (v1.0.38) and authenticated-flow disclaimer (v1.0.39) unchanged since Tp5 exfiltration was the only finding those addressed successfully. No code / no capability change; documentation restructure only.\n\nv1.0.39 | 2026-07-10T13:58:30.815Z | user\n\nv1.0.39 · Documentation clarity + SkillSpector response. (1) Full-transparency block placed after the value bullets (before What's-New history): makes the two-tier capability (finance data + backtest + paper trading, plus workflow / state-changing / outbound-webhook operations sharing the same /agent/skills/execute endpoint) explicit so operators scope tokens with full information. (2) Rewrite the '字段级加密' bullet to distinguish encryption-at-rest from authenticated-boundary decryption; explicit that holding the token = holding decrypt right, with closing reassurance about what the protection covers. (3) Update title/H1 to '量化数据 + Agent 工作流平台' — honest positioning of the two-tier capability without diluting finance keywords. (4) Add Quick Start §4 First Call Recipe (3-step curl: list → get id → data.get) that fixes the most common first-call 500 error — callers passing an asset name string (e.g. 'fund_day') instead of a numeric asset ID for the {id} path variable — plus inline note that authenticated Bearer-token curl is standard authenticated access, not data exfiltration. No code / no capability change; documentation-only clarification of what the skill has always done. Companion backend friendly-error handler (400 vs 500 on MethodArgumentTypeMismatch) landed separately (PR #507).\n\nv1.0.38 | 2026-07-10T13:25:10.895Z | user\n\nv1.0.38 · UX fix — Add First Call Recipe (Quick Start §4) explaining that URL {id} must be numeric asset ID (e.g. 42) not assetName (e.g. fund_day). Root cause: 2026-07-10 observed new user zjthaha888 hit 3 consecutive 500s and abandoned — Spring MVC @PathVariable Long conversion fails on string names, GlobalExceptionHandler returns 500 without hinting at the id format issue. New recipe shows the 3-step list → get id → data.get workflow explicitly. Backend-side friendly-error (400 vs 500) is a follow-up.\n\nv1.0.37 | 2026-07-08T11:53:33.544Z | user\n\nTighten safety language — replace absolute agent-safe claims with precise per-category side-effect descriptions (read / idempotent write / workflow state transition / outbound webhook). Addresses SkillSpector SDI-4 review.llm_review.\n\nv1.0.36 | 2026-07-08T10:19:31.695Z | user\n\nTighten safety language — replace absolute agent-safe claims with precise per-category side-effect descriptions (read / idempotent write / workflow state transition / outbound webhook). Addresses SkillSpector SDI-4 review.llm_review.\n\nv1.0.33 | 2026-07-02T01:47:57.763Z | user\n\nv1.0.33 · Positioning patch — SKILL.md 现在显式说明覆盖 AkShare / Tushare 同数据源（合作定位，非替代/对标）；关键词加入 AkShare / Tushare (22→24)，让搜索这两个工具的用户能发现 Privora 作为 hosted backend + AI Agent 接入方案。Data / features unchanged from v1.0.32.\n\nv1.0.32 | 2026-07-02T01:39:03.123Z | user\n\nv1.0.32 · New capabilities: portfolio attribution (α/β + TWR benchmark), NAV history curve, cash dividend attribution (stock_dividend), backtest sandbox mode, alert governance (snooze/ack + freemarker webhook + freshness gate), realtime dataasset dual routing, dashboard freshness auto-derive. Keywords expanded 12→22 covering 分钟K线 / 组合归因 / 净值曲线 / 现金分红 / 策略沙盒 / Python回测 / A股模拟盘 / 数据新鲜度. Description now leads with attribution + sandbox.\n\nv1.0.31 | 2026-06-25T02:13:40.658Z | user\n\nTighten safety language — replace absolute agent-safe claims with precise per-category side-effect descriptions (read / idempotent write / workflow state transition / outbound webhook). Addresses SkillSpector SDI-4 review.llm_review.\n\nv1.0.30 | 2026-06-24T01:45:00.363Z | user\n\nTighten safety language — replace absolute agent-safe claims with precise per-category side-effect descriptions (read / idempotent write / workflow state transition / outbound webhook). Addresses SkillSpector SDI-4 review.llm_review.\n\nv1.0.29 | 2026-06-23T11:10:20.495Z | user\n\nTighten safety language — replace absolute agent-safe claims with precise per-category side-effect descriptions (read / idempotent write / workflow state transition / outbound webhook). Addresses SkillSpector SDI-4 review.llm_review.\n\nv1.0.27 | 2026-06-23T08:30:46.052Z | user\n\nfeat(alerts): freshness gate reads data_asset.last_data_refresh_at (no SQL probe); per-rule snooze + acknowledge governance v1.\n\nv1.0.22 | 2026-06-12T07:29:25.460Z | user\n\nTighten safety language — replace absolute agent-safe claims with precise per-category side-effect descriptions (read / idempotent write / workflow state transition / outbound webhook). Addresses SkillSpector SDI-4 review.llm_review.\n\nv1.0.21 | 2026-06-12T06:43:22.420Z | user\n\nDisplay title expansion — add 量化分析 + 多资产 + 风险监控 (3 more 0-competitor empty-market terms).\n\nv1.0.20 | 2026-06-12T06:37:24.150Z | user\n\nDisplay title expansion — add 模拟盘 + 实时告警 to capture 0-competitor empty markets in clawhub search.\n\nv1.0.19 | 2026-06-12T06:27:48.649Z | user\n\nDisplay title experiment — pass Chinese keyword-rich title via CLI --name flag to surface in clawhub search for A股 / 量化回测 / Python 策略 query intent.\n\nv1.0.18 | 2026-06-12T06:14:42.825Z | user\n\nNarrow the documented agent surface to read + idempotent write + workflow execution. Broader platform management routes through the platform UI for human operators.\n\nv1.0.17 | 2026-06-12T03:31:23.521Z | user\n\nAdd explicit Scope & Safety section per SkillSpector audit guidance: operation category table (read-only / idempotent / confirmation-required / destructive), audit-aligned dedicated-Bearer-Token recommendation, and rollback plan. Display name updated; slug unchanged.\n\nv1.0.16 | 2026-06-12T02:30:42.360Z | user\n\nMake the public skill token-only by removing session/cookie fallback from published scripts and docs, while keeping the public scope limited to read-only and regular non-destructive writes.\n\nv1.0.14 | 2026-06-12T02:29:50.278Z | user\n\nMake the public skill token-only by removing session/cookie fallback from published scripts and docs, while keeping the public scope limited to read-only and regular non-destructive writes.\n\nv1.0.15 | 2026-06-12T01:33:39.247Z | user\n\nMake the public skill token-only by removing session/cookie fallback from published scripts and docs, while keeping the public scope limited to read-only and regular non-destructive writes.\n\nv1.0.13 | 2026-06-06T11:52:40.269Z | user\n\nMake the public skill token-only by removing session/cookie fallback from published scripts and docs, while keeping the public scope limited to read-only and regular non-destructive writes.\n\nv1.0.12 | 2026-05-20T11:35:05.939Z | user\n\nMake the public skill token-only by removing session/cookie fallback from published scripts and docs, while keeping the public scope limited to read-only and regular non-destructive writes.\n\nv1.0.11 | 2026-04-22T10:09:21.036Z | user\n\nMake the public skill token-only by removing session/cookie fallback from published scripts and docs, while keeping the public scope limited to read-only and regular non-destructive writes.\n\nv1.0.10 | 2026-04-22T09:42:30.647Z | user\n\nLimit the public skill to read-only and regular non-destructive write operations, remove high-risk admin actions from the published catalog, and publish only user-facing helper scripts.\n\nv1.0.9 | 2026-04-22T09:01:35.124Z | user\n\nReduce install-time security suspicion by requiring only Bearer-token metadata, clarifying cookie/CSRF as optional compatibility fallback, and tightening published skill contents.\n\nv1.0.8 | 2026-04-21T07:32:00.178Z | auto\n\n- Added support and documentation mentions for GitHub Copilot as a compatible AI Agent.\n- Expanded quick start examples to include GitHub Copilot in environment variable setup.\n- Added new skill: process.pipeline.update，with detail on behavior and usage.\n- Included latest regression test report file for improved test tracking.\n\nv1.0.7 | 2026-04-20T06:13:27.322Z | auto\n\nVersion 1.0.7 (lg-agent-platform)\n\n- Added Python策略回测 (strategy backtesting) feature for historical analysis.\n- Expanded and clarified documentation with richer use case scenarios and quick start examples.\n- Enhanced compatibility details—now highlighting integration with all major AI Agent platforms, not just a single ecosystem.\n- Improved security section, emphasizing bank-level privacy: financial data remains cloud-side, never disclosed to language models.\n- Included full REST skill reference with risk levels, and expanded instructions on agent configuration and workflow automation.\n- Updated metadata and licensing information.\n\nv1.0.6 | 2026-04-09T04:02:40.038Z | user\n\nASO (App Store Optimization) update: Refined description and keywords to improve vector search ranking for 'stock' and 'quant' queries.\n\nv1.0.5 | 2026-04-09T03:57:25.013Z | user\n\nFixed registry metadata to properly declare required environment variables (LG_AGENT_BASE_URL, LG_AGENT_TOKEN, etc.) resolving scanner inconsistencies.\n\nv1.0.4 | 2026-04-09T03:50:56.489Z | user\n\nSecurity patch: hardcoded default BASE_URL to resolve scanner false positives for credential exfiltration.\n\nv1.0.3 | 2026-04-08T14:20:05.920Z | user\n\nAdded feedback.submit and feedback.list skills for zero-friction user feedback tracking.\n\nv1.0.2 | 2026-04-02T11:41:34.291Z | user\n\nImprove title, search keywords, quick start, and positioning for stock alerts / Feishu webhook / portfolio PnL\n\nv1.0.1 | 2026-03-30T03:03:07.146Z | user\n\n添加演示GIF\n\nv1.0.0 | 2026-03-30T02:56:28.276Z | auto\n\nLG Data 量化平台首发版本上线！\n\n- 首次发布支持自动股票盯盘、量化策略、盈亏/持仓查询。\n- 实现A股/H股实时行情与分钟线数据，无需第三方API。\n- 支持飞书/微信Webhook推送，策略触发即时通知。\n- 采用云端Serverless架构，免服务器部署，7x24小时运行。\n- 一句话创建股票监控，策略场景丰富，适用于实时监控和自动化交易。\n\nArchive index:\n\nArchive v1.0.57: 5 files, 111719 bytes\n\nFiles: scripts/lg_agent_exec.sh (37715b), scripts/lg_agent_list.sh (18459b), skill-card.md (2950b), SKILL.md (212108b), _meta.json (136b)\n\nFile v1.0.57:SKILL.md\n\n---\r\nname: Privora · 数据驱动投资工作流平台 for AI Agents\r\ntitle: 🔬 Privora · AI Agent 投资工作流平台（A股/港股/美股/黄金/基金/财报数据 + Python 回测 + 模拟交易 + 组合归因 + 云端告警 + 流程编排）\r\nversion: 1.0.57\r\nupdatedAt: 2026-09-18\r\nkeywords:\r\n  - A股\r\n  - 港股\r\n  - 美股\r\n  - 基金\r\n  - 黄金\r\n  - 财报数据\r\n  - 业绩预告\r\n  - 现金分红\r\n  - 分钟K线\r\n  - K线\r\n  - 实时行情\r\n  - 量化回测\r\n  - 策略沙盒\r\n  - Python回测\r\n  - A股模拟盘\r\n  - 模拟交易\r\n  - 持仓监控\r\n  - 组合归因\r\n  - 净值曲线\r\n  - AI Agent\r\n  - MCP\r\n  - MCP Server\r\n  - Claude Code\r\n  - Codex\r\n  - Cursor\r\n  - 数据后端\r\n  - 股票\r\n  - 告警\r\n  - 数据新鲜度\r\ndescription: Privora · AI Agent 投资工作流平台 — Bearer Token 即接入 /agent/skills/execute 通用 dispatcher，覆盖 A 股/港股/美股/黄金/基金/财报数据 + Python 回测（含 sandbox）+ 模拟交易 + 组合归因（α/β TWR）+ 云端告警 + 流程编排。Hermes / Claude / GPT / OpenClaw 全兼容。\r\nlicense: MIT-0\r\nmetadata:\r\n  {\r\n    \"openclaw\": {\r\n      \"emoji\": \"📈\",\r\n      \"requires\": {\r\n        \"env\": [\"LG_AGENT_BASE_URL\", \"LG_AGENT_TOKEN\"]\r\n      }\r\n    }\r\n  }\r\n---\r\n\r\n# Privora · AI Agent 投资工作流平台（Bearer Token 即接入 · A股/港股/美股/黄金/基金 数据 + 回测 + 模拟交易 + 告警 + 流程编排）\r\n\r\n**给你的 AI Agent 一个统一的投资研究工作流后端 —— 数据查询 + 策略回测 + 组合归因 + 云端告警 + 流程编排一个 Token 全覆盖。**\r\n\r\nHermes / Claude / GPT / OpenClaw 任何 Agent，通过一个 Bearer Token 即可访问：\r\n\r\n- 📊 **多资产数据（按市场段分别发布，均 🟢 生产可用）**：**日线** A 股 5500+ 股票（`stock_day`，含沪深300 / 上证综指 / 中证A500 / 深证成指 4 主要指数）+ 港股（`stock_day_hk`，如 `00700.HK`）+ 美股（`stock_day_us`，如 `AAPL`）；**分钟 K 线** A 股（`stock_kline`）+ 港股（`stock_kline_hk`），1/5/15/30/60 分钟；**持仓**、**黄金**、**基金**、**财报事件**（业绩预告 / 快报）——一个 API 全覆盖，详见下方「数据资产可用性」表。场内基金（ETF/LOF）日线（`fund_quote_day`）+ 分钟 K 线（`fund_kline`）表已就绪（🟡 尚未开放跨团队订阅，见下方表格）。\r\n- 🔔 **7×24 云端监控**：Serverless 策略托管，飞书 / 微信毫秒级预警，零服务器运维\r\n- 🧪 **Python 策略回测**：用同一份平台数据跑回测，输出 Sharpe / 最大回撤 / 交易明细\r\n- 🔒 **加密静态、认证边界返明文**：持仓数据在数据库中以 per-account 独立密钥密文存储（防 DB 层泄露 + 平台 admin 跨账户读取）；**持有你 Bearer Token 的 Agent 通过 API 认证后，平台按调用者身份解密并返回明文** —— 这不是 E2E 加密，Token 授权即数据访问权。\r\n- 🎯 **1-click subscribe→alert**：Agent 帮用户从\"订阅 dashboard\"到\"配置 alert 上线\"降到 1 step (2026-06-05 新增)\r\n- 🧾 **模拟交易 (Paper Trading)**：MARKET / LIMIT 委托类型 + 调度器驱动 + 真实涨跌停 / 停牌信号，账户 + 订单 DB-level 幂等。\r\n\r\n> **让普通人也能拥有私募级别的工作流**——不需要私募的预算，就能像私募研究员一样在同一条流水线里跑数据 + 分析 + Agent + 告警。\r\n\r\n🆕 **版本与变更历史**：当前版本号以文件头 frontmatter 的 `version:` 字段为准，正文不重复这个数字；每次发布的完整变更说明见仓库内 [`CHANGELOG.md`](./CHANGELOG.md)，随包分发的历史摘要见文末 [§最近更新](#最近更新)。\r\n\r\n🎯 **最适合**：想把整个投研工作流（数据查询 + 回测 + 模拟交易 + 告警 + 流程编排）交给 AI Agent 自动化的散户 / 小工作室；把 Hermes / Claude / GPT / OpenClaw 当量化助手用的开发者。**注意**：Bearer Token 是\"工作流授权凭证\"，不只是\"数据 API key\" —— 授予前先按 [§Scope](#scope--operator-responsibility) 分类明白**要给 Agent 哪些能力**。\r\n\r\n🌐 **产品主页**：[https://privora.cn](https://privora.cn) · 注册即拿 Token\r\n\r\n![演示](./lg-data-demo.gif)\r\n\r\n---\r\n\r\n## 🌟 核心亮点\r\n\r\n### 1. 🤖 兼容所有主流通用 AI Agent\r\n打破生态壁垒，本技能不仅专供某一平台，而是**完美兼容 Hermes、OpenClaw、Claude Code、GitHub Copilot 等所有支持外挂工具/技能的通用大模型 Agent**。只需简单配置环境变量，您的通用 AI 助手瞬间化身专业量化分析师。\r\n\r\n#### 🔌 用 MCP 客户端？有原生通道，两条并存\r\n\r\n如果你的 Agent 是 **Codex CLI / Claude Code / Cursor / Windsurf / Cline**，除了本包的环境变量 + 脚本方式，还有一个**原生 MCP** 通道:一个 stdio MCP server，把同一个 dispatcher 直接暴露成 `tools/list` / `tools/call` 工具，你的 Agent 不必再学 shell 脚本的调用形状。\r\n\r\n**两条通道并存，没有一条被弃用**，而且它们是同一个后端接口的两个门:\r\n\r\n- **接口完全相同** —— 都是 `GET /agent/skills` + `POST /agent/skills/execute` 这两条路由。\r\n- **环境变量完全相同** —— 都是 `LG_AGENT_BASE_URL` + `LG_AGENT_TOKEN`。**配好了本包，就等于配好了 MCP server**，不用重新申请或配置任何东西。\r\n- **权限完全相同** —— scope、租户绑定、`403`、`remediation` 全由后端裁定并原样返回;MCP server 自己不计算也不缓存任何授权判断。**换通道不会让同一个 token 多拿到或少拿到任何能力。**\r\n- **新能力两边同时出现** —— MCP 的工具面是覆盖整个 catalog 的固定 dispatcher，不是手工维护的镜像。\r\n\r\n⚠️ 它目前**还没发布到 npm**（`npm view @privora/mcp-server` 返回 404），需要从仓库检出后用绝对路径接入。用法见仓库里的 `mcp-server/README.md`（安装、客户端配置块、12 个工具、每个工具的 `annotations` 披露信号——只读 / 破坏性——以及错误映射，以及两个值得在第一次调用前读的平台坑）。annotations 是**披露，不是安全边界**：宿主可以完全忽略它们，真正且唯一不可绕过的授权判定始终在服务端 scope 校验。\r\n\r\n**该选哪条?** 如果你的客户端原生支持 MCP，用 MCP —— Agent 少一层要学的东西。其它情况（Hermes、OpenClaw、自己写的脚本、CI 里直接 curl）继续用本包，它不会走。\r\n\r\n### 2. 🔒 加密静态 · 认证边界返明文（Encryption-at-rest, not E2E）\r\n\r\n每个账户的持仓数据在数据库中以 per-account 独立密钥密文存储。**这是防\"库泄露 / 平台 admin 跨账户读取\"的加密，不是 E2E 加密**：\r\n\r\n- **持有你 Bearer Token 的 Agent 通过 API 认证后，平台按调用者身份解密并返回明文** —— Token 是解密权的钥匙，保管好 Token 就是保管加密防线\r\n- 每个账户的加密密钥独立，平台管理员账号无法跨账户读取持仓明细（DB 层保证）\r\n- 订阅他人发布资产时，发布方看不到你的查询内容或账户信息（widget config 对订阅方 sanitize）\r\n- **给不可信 Agent 的 Token = 给它明文数据**。按 [§Scope](#scope--operator-responsibility) 授予最小 scope，不要 bundle 无关能力\r\n\r\n### 3. ⚡ Serverless 极速预警与零部署\r\n策略云端托管运行，无需您购买第三方行情 API，无需自建服务器维护 Cron 任务，无 Token 消耗税。策略触发后，毫秒级推送到您的飞书机器人或微信 Webhook。\r\n\r\n---\r\n\r\n## 🛠️ 能做什么\r\n\r\n| 核心功能 | 详细说明 |\r\n| :--- | :--- |\r\n| **资产盈亏巡航** | 一键查询持仓明细、当日盈亏、历史收益率，数据由 privora.cn 闭环处理。 |\r\n| **云端自动盯盘** | 设置预警条件（突破均线、涨跌幅、换手率等），触发即通知，7x24小时云端值守。 |\r\n| **多终端实时推送** | 策略触发毫秒级推送到飞书、微信 Webhook，不错过任何交易信号。 |\r\n| **行情数据** | 日线按市场段分别发布，均 🟢 生产可用：A 股（`stock_day`，沪深京 5500+ 股票 + 4 指数）、港股（`stock_day_hk`，如 `00700.HK`）、美股（`stock_day_us`，如 `AAPL`）；分钟 K 线：A 股（`stock_kline`）+ 港股（`stock_kline_hk`），1/5/15/30/60 分钟；基金日 NAV（`fund_day`）；场内基金（ETF/LOF）日线（`fund_quote_day`）+ 分钟 K 线（`fund_kline`，🟡 已建库尚未开放订阅）；SGE 黄金日线（`metal_day`）；财报事件（`stock_forecast` 业绩预告 + `stock_express` 业绩快报，11 年历史已回填）。详见下方「数据资产可用性」表。 |\r\n| **Python 策略回测** ✨ | 用平台日线数据跑单股 / 多股组合回测，输出 Sharpe / 最大回撤 / 交易明细 / equity curve；结果持久化到 `process_backtest_result`，可通过 `investment.stock.backtest.list` 检索历史审计记录（平台已积累 44+ 次持久化回测）。 |\r\n| **模拟交易 (Paper Trading)** ✨ | MARKET / LIMIT 两种委托类型，调度器驱动，模拟完整委托 → 成交 → 盈亏核算链路；账户按 `user_name` 唯一（DB-level UNIQUE），订单按 `(user_name, client_order_id)` 幂等，Agent 重复调用不重建。适合策略 6 阶段验证的最终纸面交易关卡。 |\r\n| **用户声音收集** | 支持 Agent 代客户提交 Bug 和需求，无缝对接后台反馈系统。 |\r\n\r\n### 数据资产可用性（2026-07-17 platform check）\r\n\r\n> **发布模型说明**：底层物理表按市场是合表存储的（同一张表可能物理上含多市场行），但**对外发布是按市场段分别发布为独立 DataAsset 的**。`stock_day` 段族现已全市场覆盖并各自独立上线：A 股段 = `stock_day`，港股段 = `stock_day_hk`，美股段 = `stock_day_us`；分钟 K 线段族同理：A 股段 = `stock_kline`，港股段 = `stock_kline_hk`。三段各自独立发布、独立 asset id，调用时请用下表的 assetName，不要假设同一 asset 覆盖多市场。\r\n\r\n| DataAsset | 状态 | 覆盖 | 频率 | 备注 |\r\n|---|---|---|---|---|\r\n| `stock_day` | 🟢 **生产可用** | **A 股（沪深京）5500+** 股票日线 + 4 主要指数（沪深300 `1B0300` / 上证综指 `1A0001` / 中证A500 `1B0510` / 深证成指 `399001`） | 日 | id=1；`000001` 等 A 股 ticker 自动路由（`segmentValues` SH/SZ/BJ）；`399001` 自 2026-03-17 起停更，请求会返回 `meta.benchmarkWarning` |\r\n| `stock_day_hk` | 🟢 **生产可用** | 港股日线（如 `00700.HK`） | 日 | id=204；数据新鲜（2026-07-16 校验通过） |\r\n| `stock_day_us` | 🟢 **生产可用** | 美股日线（如 `AAPL`） | 日 | id=206；由 `stock_day_us_backfill_to_mc` 任务从 PG 同步至 MC |\r\n| `stock_kline` | 🟢 **生产可用** | A 股 1/5/15/30/60 分钟 K 线（`interval_type` 区分周期） | 分钟 | id=202；日线 + 日内同步，由 `stock_kline_daily_sync` 等调度维护 |\r\n| `stock_kline_hk` | 🟢 **生产可用** | 港股 1/5/15/30/60 分钟 K 线 | 分钟 | id=207；与 `stock_kline` 同结构，段独立 |\r\n| `stock_minutes` | ⚪ **已弃用** | (旧) 分钟 K 线，已被 `stock_kline` / `stock_kline_hk` 取代 | — | id=154；仅历史兼容保留，新集成请改用 `stock_kline`/`stock_kline_hk` |\r\n| `fund_day` | 🟢 **生产可用** | 公募基金日 NAV | 日 (T+1) | 数据延迟约 1 个工作日；**长期回测/算收益率必须用 `adj_nav`（复权净值），不能用 `unit_nav`（会被拆分/分红污染，且约 49% 行 `adj_nav` 为 NULL）**——详见下方「`adj_nav` 缺失信号」一节 |\r\n| `fund_quote_day` | 🟡 **数据已就绪，尚未开放跨团队订阅** | 场内基金（ETF/LOF）价格日线；PG 单表不分区；`market` ∈ {ETF, LOF}——**与 `fund_day`/`fund_codes` 的 `{E,O}` 词表不同，跨表 join 只能用 `fund_code`**；`turnover` 是成交额（元），不是换手率 | 日 | `source` 分 `akshare_hist_em`（官方历史，`is_final=true`/`calibration_status='confirmed'`）与 `fund_realtime_t0`（当日 T+0 推导，`is_final=false`/`pending`）；两者交叉验证收盘价/成交量完全一致；详见下方「场内基金 K 线」一节 |\r\n| `fund_kline` | 🟡 **数据已就绪，尚未开放跨团队订阅** | 场内基金（ETF/LOF）分钟 K 线，`interval_type` ∈ {1m,5m,15m,30m,60m}（无 1d，日线见 `fund_quote_day`） | 分钟 | PG 原生 RANGE 分区表（按 `day_id`），**保留期仅 3 天**（非 MC 资产，不受 ODPS 分区自动注入影响）；`bar_time` 是 VARCHAR 不是 timestamp；`tick_count` 量化稀疏度；详见下方「场内基金 K 线」一节 |\r\n| `metal_day` | 🟢 **生产可用** | SGE 黄金 / 白银日线 | 日 | 上海黄金交易所 |\r\n| `stock_forecast` | 🟢 **生产可用** (NEW 2026-06-22) | A 股上市公司业绩预告；11 年历史 82,457 行已回填 | 日 | 财报季 (1/4/7/10 月底前后) 集中发布 |\r\n| `stock_express` | 🟢 **生产可用** (NEW 2026-06-22) | A 股上市公司业绩快报；11 年历史 19,945 行已回填 | 日 | 比业绩预告更精确但发布更稀疏 |\r\n| `stock_dividend` | 🟢 **生产可用** (NEW v1.0.32) | A 股上市公司现金分红事件；进入 `portfolio.attribution` 归因 | 事件驱动 | 除权除息日发布 |\r\n\r\n**对 Agent 的指导**：调用 `dataasset.list` 看完整列表；标 🔴 / ⚫ / ⚪ 的资产请避免在策略里硬编码依赖（⚪ = 已弃用，改用其后继 asset）。`dataasset.metadata.get` (2026-06-22 新上) 可查每张表的 `lastUpdated` / `expectedUpdateCadence` / `cronExpression` 来判断当前状态——**2026-09 起这个 scope 已在默认 `read-data` 预设里**，用默认预设建的 token 直接调即可，无需额外勾选。\r\n\r\n> 📌 本节是 **2026-07-17 的一次平台盘点快照**，随时间推移可能与实际覆盖漂移。各已发布资产的完整覆盖范围、分市场明细、更新频率与数据起始日期，见持续维护的公开清单页：[privora.cn/features/realtime-minute-data-coverage](https://privora.cn/features/realtime-minute-data-coverage)（按六类分组，含 A股/港股/美股/北交所分市场明细）。\r\n\r\n---\r\n\r\n## 🛡️ Scope 与操作者责任\r\n\r\n本 skill 是通过 Bearer Token 对接 Privora 平台的能力。操作类别的副作用不同，**操作者负责按类别 scope token 并为需要的类别加入确认门槛**：\r\n\r\n- **只读**（Read-only）—— 数据 API、回测结果查询、流程/调度/数据源/仪表盘/市场的 list/get。**平台状态零副作用**。\r\n- **幂等写**（Idempotent write）—— 模拟交易下单（DB 层 UNIQUE on `user_name` + `client_order_id`，同 key 重试返回同一记录）、marketplace subscribe（ON CONFLICT 返回已有订阅）、告警配置更新。**同输入多次调用只产生一次逻辑效果，可安全重试**。\r\n- **流程状态转移**（Workflow state transition）—— `process.ingestion.execute` 触发已授权 python_script 运行并写入 `process_backtest_result` 表；scheduler-instance 的 `redo / hold / resume / reset-priority` 转移 trigger row 状态。**每次调用创建或修改持久化记录**。\r\n- **确认门槛类**（Confirm-gated destructive/high-risk）—— 一小撮删除 / 撤销 / reset / 调度作业上下线操作 Bearer token **可达**，但单次调用永远不会直接执行——必须先完成两步确认握手，完整列表见下方 [§高风险操作确认握手](#高风险操作确认握手-confirm-handshake)。\r\n- **外发 webhook**（Outbound webhook）—— `schedule.job.plugin.webhook.trigger` 与告警评估路径向操作者配置的外部端点（飞书 / 微信 / 通用 webhook）发送通知。**副作用在 Privora 之外，平台不可撤销**。\r\n\r\n**本 skill 部分暴露**（其余需人在 platform UI 手动完成）：\r\n- 持久化记录的删除 / 撤销 / reset 操作 —— **一小撮**（流程删除、告警规则删除、team Python 模块删除、订阅 token 撤销、模拟盘账户 reset 等）经两步确认握手后可达，见上方「确认门槛类」；**多数**删除操作（如投资组合 / 交易记录删除）仍不在本 skill 范围内。\r\n- 调度器 online / offline 状态转移 —— `schedule.job.online` / `schedule.job.offline` **可达**，同样需要两步确认握手，见上方「确认门槛类」——这两个操作不是\"不暴露\"。\r\n- Webhook 插件生命周期变更（删除 / 禁用）—— `schedule.job.plugins.save`（详见下方作业插件小节，[§调度作业字段契约](#调度作业字段契约)）可全量替换一个作业绑定的插件列表（旧绑定先整体删除再写入新列表），**且不经确认握手**——传入的数组即视为该作业插件的完整期望状态，遗漏的既有绑定会被静默清空，不是增量操作。调用前请先 `schedule.job.plugins.list` 确认当前绑定，再拼出完整数组。\r\n- 管理员级账户操作 —— 不暴露，需通过 platform UI 完成。\r\n\r\n本 skill **不预先声明**任何操作是\"agent-safe\"——这个分类取决于操作者的风险偏好、agent 的可靠性、以及具体用例。**推荐姿势**：只读 + 幂等写允许 agent 自主调用；流程状态转移和外发 webhook 建议先经过用户确认门槛（约定俗成，非平台强制）；标记 `confirmRequired:true` 的高风险操作则由**平台强制**要求两步确认握手，不依赖操作者自律——**但这道门防的是单次误触，不是他人审批**：两步可以由同一个 agent 完成（`approval_mode='self-confirm'`，`approver_user` 就是 requester 本人，见下方 [§高风险操作确认握手](#高风险操作确认握手-confirm-handshake)）；要真正的人工把关，只有两条路：不授予这些 scope，或走平台 UI 由管理员 approve/reject。另外请注意上面「Webhook 插件生命周期变更」是**例外**：风险不低（全量替换、旧绑定先删），却不在 `confirmRequired` 名单内，调用前务必自行核实完整期望状态。\r\n\r\n### 📋 场景 → scope 速查表\r\n\r\n**新建 token 的默认 scope 就能取数**（2026-08-03 起）。点\"创建\"不改任何选项，你会得到\r\n`read-data` 这一组：\r\n\r\n```\r\ndataasset.list  dataasset.get  dataasset.schema.get  dataasset.metadata.get\r\ndataasset.data.get  dataasset.data.getRealtime  marketplace.item.list\r\n```\r\n\r\n需要别的能力时，按场景挑一组（token 创建页有同名的场景按钮，点一下即可全选）：\r\n\r\n| 场景 | preset id | scopes |\r\n|---|---|---|\r\n| 取行情 / 资产数据（**默认**） | `read-data` | `dataasset.list` `dataasset.get` `dataasset.schema.get` `dataasset.metadata.get` `dataasset.data.get` `dataasset.data.getRealtime` `marketplace.item.list` |\r\n| 读取数据 + 管理市场订阅（**含写权限**：订阅市场条目拿自己团队的 `clonedAssetId` 等；取消订阅会**删除**该团队克隆副本） | `subscribe-and-read` | `read-data` 全部 + `marketplace.item.subscribe` `marketplace.item.unsubscribe` |\r\n| 读仪表板 | `read-dashboard` | `read-data` 全部 + `dashboard.list` `dashboard.get` `dashboard.data.get` |\r\n| 触发并追踪流程 | `run-process` | `process.ingestion.list` `process.ingestion.get` `process.component.list` `process.ingestion.execute` `process.ingestion.execute.log.get` |\r\n| 配置指标告警（不含建通知通道） | `manage-alerts` | `metric.alert.list` `metric.alert.get` `metric.alert.create` `metric.alert.update` `metric.alert.toggle` `metric.alert.test` |\r\n| 实时告警（通道 + 规则，端到端） | `realtime-alerting` | `dataasset.{list,get,schema.get,metadata.get,data.get}` `datasource.list` `alert.channel.create` `plugin.webhook.send` `metric.alert.{list,get,create,update,patch,toggle,test,snooze,unsnooze,acknowledge}` |\r\n| 读写持仓与交易（**含写权限**） | `portfolio` | `investment.stock.portfolio.{list,create,update}` `investment.stock.trading.{list,create}` `investment.stock.watchlist.list` `investment.stock.signal.{list,get}` `investment.fund.portfolio.{list,create}` `investment.fund.trading.{list,create}` `investment.gold.portfolio.{list,create}` `investment.gold.trading.{list,create}` |\r\n\r\n**三个查询入口**（三处读的是同一份定义，不会互相打架）：\r\n\r\n| 你是谁 | 去哪查 |\r\n|---|---|\r\n| 人 | [privora.cn/profile/tokens](https://privora.cn/profile/tokens) 创建 token 时的场景按钮 |\r\n| Agent | `GET /agent/scope-presets` —— 返回 `{presets[], defaultScopes[], grantedScopes[]}`，每个 preset 带 `scopes[]`、`skillIds[]` 和 `satisfied`（当前 token 是否已满足） |\r\n| Agent | `GET /agent/skills` —— **全量**技能目录。每条带 `granted`（你现在能不能跑）、`scope`（需要哪个 scope）、`params` schema、`exampleInvocation`。跑不了的条目额外带 `presetsGrantingScope` |\r\n\r\n> `GET /agent/skills` 过去只返回你**已有** scope 的技能，所以 scope 不足时你根本看不到目标技能存在，\r\n> 只能靠猜 skillId。现在默认返回全量并用 `granted` 标注；要恢复旧行为传 `?granted=true`。\r\n\r\n**scope 不足时不用猜**：403 响应体直接给出 `requiredScope`、你当前的 `grantedScopes`、\r\n哪个 preset 含它（`presetsGrantingScope`）以及去哪改（`remediationUrl`）。\r\nskillId 写错时 400 响应体给 `didYouMean[]` 候选。\r\n\r\n**Token 使用建议**：\r\n\r\n1. 在 [privora.cn/profile/tokens](https://privora.cn/profile/tokens) 创建专用 Bearer Token\r\n2. **最小 scope 原则** —— 只授予当前 use case 需要的 scope。只读分析用默认的 `read-data` 就够；\r\n   要跑流程再加 `run-process`；agent 真的要下模拟单才加 `paper.*`（该命名空间由平台内部签发，\r\n   见下方\"模拟交易\"章节）。**不要为\"以防万一\"打包无关 scope**。\r\n3. 明确设置 `LG_AGENT_BASE_URL=https://privora.cn`\r\n4. **Token 泄露立即 rotate** —— Token Management 页面列出所有活跃 token 及最后使用时间戳和 revoke 按钮\r\n\r\n> 🛑 **绝对不要让你的 agent 代替你 mint token**。Token 创建是 operator 动作，不是 agent 动作。Agent 应该消费 operator 签发的 Bearer Token，**不应该**自己调 `POST /api/subscription/tokens`。\r\n\r\n### 📑 输出仅供分析参考，不构成投资建议\r\n\r\n本 skill 的输出（行情数据 / 组合分析 / 回测报告 / 模拟交易 / 告警评估）是**供操作者审查的分析结果**，不是投资建议、不是交易指令、也不能替代持牌财务咨询。\r\n\r\n- **把结果作为你自己决策过程的输入** —— 使用前请自行验证数据新鲜度、假设、边界情况\r\n- **实盘交易和不可逆的财务决策不应放在 agent 自动执行链路里** —— 模拟交易只是模拟；真钱交易必须走由操作者控制的券商链路并显式确认\r\n- **回测反映的是历史条件** —— 过去表现不预测未来结果。使用前请确认数据窗口、策略逻辑、以及生存偏差 / look-ahead 假设\r\n- **无监管咨询声明** —— 本平台是数据基础设施；下游任何投资决策由操作者本人（你）负责\r\n\r\n---\r\n\r\n## 🚀 快速接入 (Quick Start)\r\n\r\n### 0) ⚡ 30 秒试一下（不需要注册 / 不需要 Token）\r\n\r\n装完 skill 想立刻看看能干什么？**打开** [privora.cn/marketplace](https://privora.cn/marketplace)：\r\n\r\n- 无需登录，直接浏览公开挂牌的 A 股 / 港股 / 美股 / 黄金 / 基金 / 财报事件等数据资产\r\n- 想一眼看完**全部已发布资产**的覆盖范围 / 更新频率 / 数据起始日期，不用一个个点开？看公开清单页 [privora.cn/features/realtime-minute-data-coverage](https://privora.cn/features/realtime-minute-data-coverage)\r\n- 每个资产可以点进去看 25 行样本数据 + 20 字段元信息（`lastUpdated` / 数据源 / cron 表达式等）\r\n- 看到有价值的资产？**不要记这里显示的 numeric id**：那是发布方团队的 id，拿去调你自己的 Bearer Token 接口只会 404——订阅后你自己团队会拿到一份**全新数字 id** 的克隆资产，两者不是同一个数。**拿自己团队 id 最直接的办法**：走 §1 - §3 注册拿 Token——**`marketplace.item.subscribe` 不在默认 `read-data` 预设里**，预设场景按钮里只有 `subscribe-and-read` 带它，创建 token 时请选 `subscribe-and-read` 预设（或手动勾选 `marketplace.item.subscribe` / `marketplace.item.unsubscribe` 这两个 scope），用默认 `read-data` 预设建的 token 调这一步会 403——然后调 `marketplace.item.subscribe`（幂等——哪怕你之前已经订阅过，重复调用同一个 item 也照样成功），响应体里的 `clonedAssetId` 就是你自己团队里那份克隆资产的数字 id，直接拿去跑 §4 First Call Recipe（2 步 / 约 1 分钟）验证 Bearer Token 对同一资产能跑通。**兜底路径**：如果响应丢了这个字段、或你不想再调一次 subscribe，`dataasset.list` 里按 `tags` 含 `Subscribed` 也能扫到同一份克隆资产的 id\r\n- 觉得样本还不够？往下走 §1 - §4 注册生成 Bearer Token 拿完整访问权（分页 / 过滤 / 更高 rate limit / 写操作 / Agent 集成）\r\n\r\n**为什么先看再注册**：Privora 是投研工作流平台，\"你的数据是否值得订阅\"应该 30 秒能判断 —— 不需要注册墙。marketplace UI 是**发现工具**，Bearer Token 是**同一批数据的程序化访问入口**，两者对应关系明确。\r\n\r\n### 1) 获取您的专属 Token\r\n1. 注册并登录 [privora.cn](https://privora.cn)\r\n2. 在侧边栏点击你的用户名 → API Token Management，或直接访问 `https://privora.cn/profile/tokens`\r\n3. 创建一个仅包含所需 scopes 的专用 Token（建议先用只读或低权限 Token）\r\n4. 复制您的专属 `LG_AGENT_TOKEN`\r\n\r\n### 2) 为您的 Agent 配置环境变量\r\n在您使用的 Agent 终端（如 Hermes、Claude Code、GitHub Copilot 或 OpenClaw）中注入以下环境变量：\r\n```bash\r\nexport LG_AGENT_BASE_URL=\"https://privora.cn\"\r\nexport LG_AGENT_TOKEN=\"***\"\r\n```\r\n公开版主要走以上 Bearer Token 方式；如果 Agent 只是浏览 marketplace / 预览已发布看板 & 资产，也可以走**匿名模式**（不需要 token，见下方 [§🌐 匿名预览](#anonymous-preview)）。session cookie / CSRF 兼容调用不支持。\r\n\r\n### 3) 唤醒 Agent，开始对话\r\n现在，您可以直接用自然语言向您的 Agent 下达指令了！\r\n\r\n### 4) ⚠️ 做出你的第一次成功 API 调用（2 步走 + 1 步可选 / 避免最常见的 500 和 403）\r\n\r\n**最容易踩的坑**：URL 里的 `{id}` 必须是**数字型 asset ID**（如 `42`），**不是 asset 名字**（如 `fund_day` / `stock_day`）。传成名字后端 Spring 转 Long 失败会返回 500——错误信息不会明确告诉你原因。\r\n\r\n**正确的 recipe**（用默认 `read-data` 预设的 token 即可全部跑通）：\r\n\r\n```bash\r\n# Step 1: 先 list 拿数字 id ← 别跳过这步\r\ncurl -H \"Authorization: Bearer $LG_AGENT_TOKEN\" \\\r\n  https://privora.cn/api/data-assets | jq '.data[] | {id, assetName}'\r\n# 输出示例：\r\n# {\"id\": 42, \"assetName\": \"fund_day\"}\r\n# {\"id\": 8,  \"assetName\": \"stock_day\"}\r\n# {\"id\": 15, \"assetName\": \"stock_dividend\"}\r\n\r\n# Step 2: 用数字 id (不是 assetName!) 查实际数据\r\ncurl -H \"Authorization: Bearer $LG_AGENT_TOKEN\" \\\r\n  \"https://privora.cn/api/data-assets/42/data?page=1&size=10\"\r\n```\r\n\r\n**Step 1 返回 `[]`？** 这对刚注册、没有自有资产、也没有订阅任何 marketplace 条目的团队是预期结果，不是 bug——你的团队此时确实没有任何 `dataasset.list` 能看到的资产。见上方 [§0](#0-⚡-30-秒试一下不需要注册-不需要-token) 的 subscribe → `clonedAssetId` 路径：调 `marketplace.item.subscribe` 需要持有该 scope 的 token（预设场景按钮里只有 `subscribe-and-read` 带它，默认 `read-data` 预设没有），拿到 `clonedAssetId` 后回来重跑本节 Step 1，这时就能在列表里看到刚订阅的克隆资产了。\r\n\r\n**（可选）Step 3：查富元数据**——`GET /api/data-assets/{id}/metadata`（对应 skill `dataasset.metadata.get`）**2026-09 起已在** Token Management 页面 `read-data` 默认预设里，用默认预设建的 token 直接调即可：\r\n\r\n```bash\r\ncurl -H \"Authorization: Bearer $LG_AGENT_TOKEN\" \\\r\n  https://privora.cn/api/data-assets/42/metadata\r\n```\r\n\r\n**Agent 侧用 `lg_agent_exec.sh` 调用同理**（v1.0.45 起支持命名参数扁平写法，不用手拼 JSON）：\r\n\r\n```bash\r\nscripts/lg_agent_exec.sh dataasset.list\r\nscripts/lg_agent_exec.sh dataasset.data.get id=42 filter_column=stock_num filter_value=600519\r\n# scripts/lg_agent_exec.sh dataasset.metadata.get id=42  ← 可选；2026-09 起已在默认 read-data 预设里，直接跑即可\r\n```\r\n\r\n`id` **必须是数字**（先 `dataasset.list` 拿到再传，不是资产名字如 `fund_day`）。想看某个 skill 接受哪些 key，先 `scripts/lg_agent_list.sh describe dataasset.data.get` 看 schema + 示例，再照着填。\r\n\r\n**如果你已经踩到 500**：不用改代码逻辑，只需把 `{name}` 换成对应的数字 id 即可。数据资产的可用列表见下方「[数据资产可用性](#数据资产可用性2026-06-22-audit--triage-t-1)」表 —— 那里的名字对应 `dataasset.list` 返回的 `assetName` 字段，需要先 list 拿到本 team 里对应的数字 id。\r\n\r\n---\r\n\r\n<a name=\"anonymous-preview\"></a>\r\n## 🌐 匿名预览（无 token）\r\n\r\n如果 Agent 只是想**浏览 marketplace 或预览已发布的看板/数据资产/流程**——比如帮用户看看 Privora 有什么数据源、有哪些现成看板可订阅、某个流程做什么用——**不需要 Bearer Token 也能直接跑**。这条通路和 [privora.cn/marketplace](https://privora.cn/marketplace) 页面上未登录访客看到的内容是**同一套数据**，只是把它变成 machine-readable 的 skill 调用。\r\n\r\n### 什么时候用\r\n\r\n- 用户还没注册，Agent 想先展示\"这平台上有啥\"\r\n- 用户已注册但当前 session 没配 token，你想让 Agent 先给个 marketplace 摘要\r\n- Agent 在做 discovery / recommendation，不需要写权限、也不涉及用户私有数据\r\n\r\n### 怎么用\r\n\r\n**留空 `LG_AGENT_TOKEN` 或直接不传 `Authorization` header** 即可：\r\n\r\n```bash\r\n# 无 token 调用 —— 直接返回 mode:\"anonymous\" + 10 个可用 skill\r\ncurl https://privora.cn/agent/skills\r\n\r\n# 无 token 拿 marketplace 列表\r\n# Windows Git Bash 提醒：curl.exe 是原生 Windows 程序，MSYS2 会按本地 ANSI 代码页重编码命令行参数，\r\n# 如果把下面的 body 换成含中文/非 ASCII 的内容（如搜索关键字），-d '...' 会被静默改坏——改用 --data-binary @file。\r\nprintf '%s' '{\"skillId\":\"marketplace.item.list\"}' > /tmp/lg_body.json\r\ncurl -X POST https://privora.cn/agent/skills/execute \\\r\n  -H \"Content-Type: application/json\" \\\r\n  --data-binary @/tmp/lg_body.json\r\n\r\n# 无 token 拿某个已发布看板的 widget 数据（同上：非 ASCII 内容一律 --data-binary @file，不要用 -d）\r\nprintf '%s' '{\"skillId\":\"dashboard.data.get\",\"params\":{\"pathParams\":{\"id\":\"<published-dashboard-uuid>\"}}}' > /tmp/lg_body.json\r\ncurl -X POST https://privora.cn/agent/skills/execute \\\r\n  -H \"Content-Type: application/json\" \\\r\n  --data-binary @/tmp/lg_body.json\r\n```\r\n\r\n响应体的 `mode` 字段会明确标 `\"anonymous\"`，`grantedScopes` 列出下方 10 个允许的 skill。\r\n\r\n### 匿名模式可用的 skill（全部只读）\r\n\r\n| skillId | 用途 |\r\n|---|---|\r\n| `marketplace.item.list` | 列出所有可订阅的 marketplace 条目（看板 / 资产 / 流程）—— **discovery 入口** |\r\n| `dashboard.get` | 按 id 拿某个已发布看板的元数据 + widget 定义 |\r\n| `dashboard.data.get` | 一次拿某个已发布看板所有 widget 的数据 |\r\n| `dataasset.get` | 拿某个 `allowSubscription=true` 资产的详情 |\r\n| `dataasset.schema.get` | 拿该资产的列 schema |\r\n| `dataasset.metadata.get` | 拿该资产的富元数据（`lastUpdated` / `expectedUpdateCadence` / cron / 数据源描述等 20 字段）|\r\n| `dataasset.data.get` | 拿该资产的历史数据（预览有效范围内）|\r\n| `dataasset.data.getRealtime` | 拿该资产的实时镜像数据（若配置了 realtime mirror）|\r\n| `process.ingestion.get` | 拿某个 `allowSubscription=true` 流程的结构（**不含 stepCfg 源码**）|\r\n| `process.component.list` | 列平台可用的步骤组件类型（rendering diagram preview 用）|\r\n\r\n### 硬性约束\r\n\r\n- **只读白名单**：**仅上表 10 个 skill** 可调，其余 skill（包括其它只读 GET，如 `investment.stock.portfolio.list` / `dashboard.list` / `dataasset.list`）无论是否存在都返回 403 `missing-scope`。任何写操作（subscribe / create / update / delete）同样 403；哪怕手工构造匿名 PUT/POST 到底层 `/api/**`，Node 代理层也会先 401 拦截，不会到 Spring。\r\n- **每 IP 限流（三桶，任一超限即 429）**：\r\n\r\n  | 桶 | 范围 | 限额 | 429 响应体 |\r\n  |---|---|---|---|\r\n  | 通用桶 | 所有匿名 skill | 60 / IP / 分钟 | `{\"success\":false, \"message\":\"Too many anonymous agent requests, ...\"}` (无 `bucket` 字段) |\r\n  | 数据爆发桶 | `dataasset.data.get` + `dataasset.data.getRealtime` | 10 / IP / 分钟 | `{\"success\":false, \"traceId\":\"...\", \"message\":\"Anonymous data-fetch burst-limit exhausted (10/min per IP). ...\", \"bucket\":\"burst\"}` |\r\n  | 数据日总桶 | 同上 | 100 / IP / 天 | `{\"success\":false, \"traceId\":\"...\", \"message\":\"Anonymous data-fetch daily budget exhausted (100/day per IP). ...\", \"bucket\":\"daily\"}` |\r\n\r\n  收到 429 时读 `response.body.bucket` 判断：`\"burst\"` 等 60 秒重试；`\"daily\"` 今日不再放行该 skill，建议引导用户注册 Bearer Token；无 `bucket` 字段则是通用 60/min 桶命中。\r\n\r\n  **Rate-limit 存储：** v1.0.37 起三桶都存 Redis sorted sets (`anonratelimit:{burst,daily,general}:<ip>`)，通过 Lua 原子脚本实现 sliding window。fleet 内所有 Node worker + 所有 host 共享一份 counter，反爬承诺**真的**成立。**Redis 不可用时 fail-open**：静默放行 + ERROR 日志 `event:\"rate-limit-redis-fail\"`，反爬承诺仅在 Redis 健康时有效（运维监控 fail-open 日志识别异常）。\r\n- **preview token 服务端自动签**：不用你手工去 `/preview-token` 拿；Node 按 skill 类型选：dashboard 类（`dashboard.get` / `dashboard.data.get`）**要求调用方在 `params.pathParams.id` 里传目标看板 id**，Node 会用该 id 签 dashboardId-bound token；未传 id 或其它 skill 一律降级为 `standalone` sentinel（等同 dataasset 类行为）。\r\n- **无效 Bearer 不降级**：如果传了 `Authorization: Bearer <bogus>`，返回 401 而**不会**悄悄退回匿名模式给你部分数据。要匿名就别传 header。\r\n- **无跨租户 leak**：所有资产读都走 `canReadAsset` gate；只有 `allowSubscription=true` 的资产/看板/流程会被返回，其它一律 404。跟浏览器 `/marketplace` 未登录访客看到的是同一套子集。\r\n- **Dashboard-scoped token 不能跨团枚举**：dashboard-A（发布者 = team-A）签的 preview token 无法通过 `dataasset.metadata.get` 读到 team-B 的资产元信息，哪怕 team-B 资产 `allowSubscription=true`。仅 `standalone` sentinel token 可读所有公开挂牌资产。\r\n\r\n### 匿名模式下的**能力受限**（订阅后才解锁）\r\n\r\n数据获取类 skill（`dataasset.data.get` / `dataasset.data.getRealtime` / `dataasset.get` / `dataasset.metadata.get` / `process.ingestion.get`）在匿名模式下**服务端会自动应用以下约束**，参数会被静默改写或剥离——不是 400，你的 curl 依然能正常拿到响应，但拿到的不是你请求的形状：\r\n\r\n- **分页强制固定 `page=1, size=25`**：传任何其他值都被服务端硬覆盖。响应 `pageSize=25, currentPage=1`。想拿更多请订阅后用 Bearer Token 调。\r\n- **过滤 / 排序参数被静默清空**：`filterColumn / filterValue / filterOp / orderBy / orderDirection` 一律置 `null` 再进服务层。想按条件过滤请订阅后再来。\r\n- **发布者身份字段被剥离**（`dataasset.get`）：`dataSource / realtimeDataSource / businessOwner / technicalOwner / teamName / jobCode / createdBy / createdDate / updatedBy / updatedDate` 一律返回 `null`。Metadata map 中 `teamName / dataSource / jobCode / createdBy / createdDate / sourceDescription` 也被剥离。\r\n- **`process.ingestion.get` 的 `stepCfg` 被剥离**：匿名调用者拿不到 process step 的源码 / SQL / Python 内容。\r\n- **`totalElements` 是哨兵值 `0`，不是真实总数**：匿名调用不消耗后端 `COUNT(*)` 查询（防止 JDBC 池 DoS）。分页导航请以 `data.length` 为准。\r\n\r\n配合分页固定 + rate limit，匿名调用者理论上每 IP 每天最多拿到 2,500 行数据（100 次 × 25 行）——真的想跑分析请注册。\r\n\r\n### 匿名模式下常见的误用\r\n\r\n- ❌ 不要**基于匿名 preview 数据做投资决策** —— 25 行不是完整数据集，这只是\"试读\"，不是\"取样\"。\r\n- ❌ 不要**用多 IP 池绕 rate limit** —— 我们记录并封 IP 池行为，正确路径是注册 Bearer Token。\r\n- ❌ 不要**期望 `totalElements` 反映真实行数** —— 匿名调用永远返回 0，这是设计意图，不是 bug。\r\n- ❌ 不要**在匿名模式下尝试 `filterColumn=...`** —— 参数会被静默丢弃，返回的是无过滤的前 25 行，不是过滤后的结果。\r\n\r\n> **技术契约锚点**（review 用）：匿名 skill 白名单 = Node `app.js` 的 `ANONYMOUS_SKILL_SCOPES` 常量；匿名 rate limit = `canAnonymousAgentCall` (60/min) + `canAnonymousDataFetchCall` (10/min burst + 100/day daily)；preview + HMAC 验证 = `docs/auth-flow-invariants.md` §1 + §2.6 + §2.6.1；能力锁定实现与残留 test 缺口 = `docs/plans/2026-07-07-anon-preview-dataasset-lockdown.md`。\r\n\r\n### 从匿名 → 注册的漏斗\r\n\r\n匿名浏览完，如果用户想真正订阅一个看板 / 用私有数据 / 跑回测，需要**注册并领 token**：\r\n\r\n- 引导用户去 `https://privora.cn/register`（`marketplace.item.subscribe` 是 🟡 写操作，不在匿名 scope 里）\r\n- 或直接调 `auth.user.register` skill（也在匿名 scope 之外 —— 需要一层 signup 意图确认，见 §用户注册 & 反馈）\r\n\r\n---\r\n\r\n## 💬 典型应用场景\r\n\r\n### 场景 1：查询账户今日盈亏（个人数据，仅自己可见）\r\n> **您：** “帮我查下今天的账户盈亏情况。”\r\n> \r\n> **Agent（调用 `dataasset.data.get`）：** \r\n> “为您同步 privora.cn 的最新分析结果：\r\n> 💰 **当日盈亏：** +319 元 | **累计浮动：** -19,135 元\r\n> 📊 **持仓明细：** \r\n> - 中国核电：+2.06%\r\n> - 永和股份：-32.45%\r\n> - 中国联通：-16.25%”\r\n\r\n### 场景 2：设定云端智能监控\r\n> **您：** “帮我监控贵州茅台，只要突破MA20均线就通知我。”\r\n> \r\n> **Agent（调用监控接口）：** \r\n> “✅ 已在云端成功创建监控任务：\r\n> - **标的**：贵州茅台 (SH600519)\r\n> - **条件**：价格突破 MA20\r\n> - **通知**：飞书/微信推送\r\n> *任务将在 Serverless 云端静默运行，触发时您将立刻收到推送。*”\r\n\r\n### 场景 3：测试流程并抓取执行日志\r\n\r\n```bash\r\n# 触发执行（异步），记下返回的 executionId\r\n# 自定义 CLI 参数直接当 flat key 传（key 以 - / -- 开头，与 process.ingestion.execute\r\n# 的 Map<String,String> body 逐字对应）。后端会自动注入 `-f <procName>` —— 不用自己传 -f。\r\nRESP=$(scripts/lg_agent_exec.sh process.ingestion.execute id=123 \\\r\n  -start_date=20260419 -end_date=20260420 --env=dev)\r\nEXEC_ID=$(echo \"$RESP\" | jq -r '.executionId')\r\n\r\n# 轮询日志，直到 completed=true\r\nOFFSET=0\r\nwhile :; do\r\n  LOG=$(scripts/lg_agent_exec.sh process.ingestion.execute.log.get \\\r\n    id=123 executionId=\"$EXEC_ID\" offset=\"$OFFSET\")\r\n  echo \"$LOG\" | jq -r '.logLines[]'\r\n  [ \"$(echo \"$LOG\" | jq -r '.completed')\" = \"true\" ] && break\r\n  OFFSET=$(echo \"$LOG\" | jq -r '.nextOffset')\r\n  sleep 1\r\ndone\r\necho \"exitCode=$(echo \"$LOG\" | jq -r '.exitCode')\"\r\n```\r\n\r\n返回：`status` 由 `running` 过渡到 `completed` 或 `failed`，`exitCode` 为脚本退出码，`logLines` 为增量日志行。\r\n\r\n### 场景 4：策略回测（双均线跑茅台）\r\n\r\n> **您：** “用双均线（5日/20日）对茅台 SH600519 过去三年跑个回测”\r\n\r\n在平台新建一个 `python_script` 流程节点，脚本如下（`lg_utils` 已预装）：\r\n\r\n> 💡 **`stock_day` 回测用现成的 `run_stock_day_backtest` 就好**——它已经把列名大小写（`STOCK_NUM` / `OPEN_PRICE` / `CLOSE_PRICE`）和日期格式（`day_id` 的 `YYYYMMDD`）配好了，别再手动传 `price_columns={“open”:”open_price”,...}` 或 ISO 日期，那些是 2026-04-21 踩过的坑。\r\n\r\n```python\r\nfrom lg_utils import get_variable\r\nfrom lg_utils.backtest_examples.dual_ma import DualMA\r\nfrom lg_utils.backtest_examples.stock_day import run_stock_day_backtest\r\n\r\nresult = run_stock_day_backtest(\r\n    strategy=DualMA(fast=5, slow=20),\r\n    stock_num=”600519”,\r\n    start=”20220101”,\r\n    end=”20241231”,\r\n    initial_cash=1_000_000,\r\n    commission_bps=3, slippage_bps=1,\r\n    benchmark_asset=”stock_day”,            # 可选：跟某只指数/股票对比\r\n    benchmark_filter_column=”STOCK_NUM”,\r\n    benchmark_filter_value=”000001”,\r\n)\r\nprint(result.summary())\r\nresult.export_to_context(“maotai_ma520”)   # stdout 日志快照\r\nresult.persist(name=”maotai_ma520”)         # 持久化到 process_backtest_result 表\r\n```\r\n\r\n**组合回测**（共享现金池、多标的同时跑）：\r\n\r\n```python\r\nfrom lg_utils.backtest_examples.stock_day import run_stock_day_portfolio_backtest\r\nfrom lg_utils.backtest_examples.dual_ma import DualMA\r\n\r\nresult = run_stock_day_portfolio_backtest(\r\n    strategies={“600519”: DualMA(5, 20), “000001”: DualMA(10, 30)},\r\n    stock_nums=[“600519”, “000001”],   # 决定 size='all' 结算先后\r\n    start=”20240101”, end=”20241231”,\r\n    initial_cash=1_000_000,\r\n)\r\n# result.metrics[“per_asset”] 给出每只股票的贡献度/回撤/交易数\r\n```\r\n\r\n任务日志里会出现：\r\n\r\n```\r\n=== Backtest Summary ===\r\nasset           : stock_day\r\nperiod          : 20220101 ~ 20241231  (bars=725)\r\ntotal_return    : 23.1500%\r\nsharpe          : 0.8412\r\nmax_drawdown    : 18.2300%\r\nnum_trades      : 14\r\nwin_rate        : 57.1429%\r\n__LG_BACKTEST_RESULT__:maotai_ma520:{\"metrics\":...,\"trades\":...}\r\n```\r\n\r\n完整 JSON（含 `trades` / `equity_curve`）会被下游节点或监控面板消费。\r\n\r\n### 场景 5：一键 subscribe→alert deeplink (NEW v1.0.13)\r\n\r\n> **您：** \"帮我配个告警，招商银行股价跌破 30 通知我。\"\r\n\r\nAgent 调用流程（之前 6 步深埋，2026-06-05 起 1 步）：\r\n\r\n```bash\r\n# 1) Agent 帮用户订阅相关 dashboard\r\nRESP=$(scripts/lg_agent_exec.sh marketplace.item.subscribe itemId=dashboard-china-merchants-bank-watch)\r\n\r\n# 2) 从 response 拿到本租户的 cloned dashboard ID\r\nDASH_ID=$(echo \"$RESP\" | jq -r '.clonedDashboardId')\r\n\r\n# 3) 构造 1-click deeplink — Agent 把这个 URL 给用户\r\nDEEPLINK=\"https://privora.cn/dashboards?selectId=${DASH_ID}&openAlerts=true\"\r\necho \"请打开此链接配置告警：${DEEPLINK}\"\r\n```\r\n\r\n用户点链接进去，metric alert modal **自动打开**——已经对准刚订阅的 dashboard，剩下用户填阈值 + 选 webhook 渠道 finalize 就完。**user-in-the-loop 边界保留**（敏感操作仍需用户在 web 上确认），但 5 步导航 + 选 dashboard + 翻 toolbar 找 \"Alerts\" button 这些都省了。\r\n\r\n这是平台活跃用户反馈最集中的需求——以前的路径是：订阅 → 跳到 dashboard 列表 → 找到目标 dashboard → 打开 toolbar → 找 \"Alerts\" button → （第一次还要去 `/datasources` 配 webhook，回来再继续）→ 配置 → 保存。这次更新把这条路径压到 **1 步**。\r\n\r\n### 场景 6：模拟交易（paper trading）—— 暂不可自助，走 Process Python 节点（#787）\r\n\r\n> **您：** \"用模拟账户跑一笔 600519 的市价买单 100 股，看看现在能不能成交。\"\r\n\r\n**这条路径目前不能靠通用 Agent + 本包 Bearer Token 一次调用走完。** 本节曾给出一段示例，调用 `paper.account.create` / `paper.order.place` / `paper.order.get` 三个 id —— **均不存在于 catalog**，跑起来只会拿到 `400 Skill not found`（#787）。而且光改 id 也走不通：`paper.*` 是**保留 scope 命名空间**——自己去 个人设置 → Token 管理 创建一个带 `paper.account.read` / `paper.orders.write` 的 PAT，后端会直接拒绝 `400 RESERVED_SCOPE`，不存在\"自助签发\"这条路。\r\n\r\n真实能力叫 `investment.paper.*`（见下方「investment.paper.\\* — 模拟盘交易」小节，含真实 skillId `investment.paper.account.get` / `investment.paper.orders.submit` / `investment.paper.orders.list` / `investment.paper.positions.list`），但入口不是 `scripts/lg_agent_exec.sh`，而是**一个 Process 里的 `python_script` 节点**，节点里用 `lg.paper.*` SDK（`lg.paper.get_account()` / `lg.paper.submit_order(...)` / `lg.paper.get_orders(...)`）发起调用。Process 起跑时，后端会给这个节点自动注入一个 scope 限定的短期 Bearer（`paper.orders.write paper.account.read dataasset.read`）——Agent 不需要、也不能自己去申请这个 token。\r\n\r\n**该怎么做**：\r\n\r\n1. 市场已有现成模板 `starter_paper_trade_strategy`——`marketplace.item.subscribe` 一键复制到你的 tenant，改写里面的 `lg.paper.submit_order(...)` 调用即可，不需要从零搭 Process。\r\n2. 若要从零建：用 `process.create`（`kind: \"run_python\"`）建一个含模拟下单脚本的步骤，`process.ingestion.execute` 跑起来——节点内的 `lg.paper.*` 调用由平台自动授权，不经过本包的 Bearer。\r\n3. 若确实需要在 Process 之外、从外部 Agent 直接调 `investment.paper.*`：只能由平台管理员按\"策略绑定模拟账户\"流程走 UI 手动铸一个 process-execution token 再转交给你的 Agent——**这不是本包能自助完成的操作**，不要承诺用户\"改个 id 就行\"。\r\n\r\n支持涨跌停 / 停牌 / suspended-stocks 信号、scheduler-driven 撮合。适合的 use case：策略上真实交易前 12 个月 paper trade 验证（per 6 阶段量化研究流水线最终关卡）——但入口是 Process 编排，不是本包 Bearer 的直接调用。\r\n\r\n## 技能列表\r\n\r\n### REST 技能（`scripts/lg_agent_exec.sh` 调用）\r\n\r\n> 公开版 skill 覆盖 4 类操作，见 [§🛡️ Scope & Operator Responsibility](#scope--operator-responsibility) 完整的 read / idempotent-write / workflow-transition / outbound-webhook 分类。**大部分**删除、撤销等破坏性/管理类操作不在本 skill 范围内，需通过 platform UI 或 admin 工具完成；**例外**是标记 🔴/🟡 且 `confirmRequired:true` 的一小撮 workflow-transition 类操作（`process.ingestion.delete` 等 14 个，见下方 [§高风险操作确认握手](#高风险操作确认握手-confirm-handshake)），这些 Bearer token 可达，但必须先完成两步确认握手——单次调用不会直接执行。系统级审批（管理员 approve/reject 一个陌生人发起的请求）仍然不在本 skill 范围内，需要 platform UI。\r\n> 风险标记：🟢 low / 🟡 medium / 🔴 high。所有 `GET` 技能默认对会话用户开放；写操作需显式授予 scope。\r\n\r\n> 📦 **Request shape (v1.0.45+)**: 命名参数扁平写法 —— 直接用 `key=value` 传参，不用手拼 JSON：\r\n> ```bash\r\n> scripts/lg_agent_exec.sh dataasset.data.get id=42 filter_column=code filter_value=000135\r\n> ```\r\n> 等价于旧 envelope 形式 `{\"skillId\":\"dataasset.data.get\",\"params\":{\"pathParams\":{\"id\":42},\"query\":{\"filter_column\":\"code\",\"filter_value\":\"000135\"}}}`——网关会按每个 skill 的 path 模板自动把 flat key 分类到 `pathParams` / `query` / `body`。`key=value` 一律当字符串（保留 `stock_num=000135` 这类前导零）；数字/布尔/数组用 `key:=value`（如 `qty:=100`）。**旧 envelope 形式 100% 继续可用，两种写法可以在同一次调用里混用**（例：数组 body 用 `--json`，path 参数用 flat key）。想看某个 skill 接受哪些 key，跑 `scripts/lg_agent_list.sh describe <skillId>`。完整规则 + 历史踩坑 + envelope 手工写法见文末 [§高级 / 兼容性附录](#高级--兼容性附录)。\r\n\r\n#### 高风险操作确认握手 (confirm handshake)\r\n\r\n14 个标记 `confirmRequired:true` 的技能对 Bearer token 可达（`process.ingestion.delete`、`schedule.job.{online,offline,delete}`、`schedule.instance.{redo,hold,kill,cancel,force_start,mark_success}`、`subscription.token.revoke`、`metric.alert.delete`、`investment.paper.account.reset`、`team.python.method.delete`），但**单次调用永远不会直接执行**——第一次调用总是返回 HTTP 409，必须完成两步握手才能真正执行。（另有 6 个 `investment.{stock,fund,gold}.{portfolio,trading}.delete` 目前设计上暂不对 token 开放，见下方「不可达」说明。）\r\n\r\n**① 第一次调用（不带 `approvalId`）→ 总是 409：**\r\n\r\n```bash\r\nscripts/lg_agent_exec.sh process.ingestion.delete id=42\r\n```\r\n\r\n```json\r\n{\r\n  \"success\": false,\r\n  \"traceId\": \"...\",\r\n  \"message\": \"Approval required for high-risk action\",\r\n  \"requiredScope\": \"process.ingestion.delete\",\r\n  \"confirmRequired\": true,\r\n  \"approvalId\": 27,\r\n  \"expiresAt\": \"2026-08-18T19:30:00\",\r\n  \"skillId\": \"process.ingestion.delete\",\r\n  \"next\": \"self-confirm-or-await-admin-then-resend\",\r\n  \"nextAction\": {\r\n    \"method\": \"POST\",\r\n    \"url\": \"/agent/skills/execute\",\r\n    \"body\": {\r\n      \"skillId\": \"process.ingestion.delete\",\r\n      \"params\": { \"pathParams\": { \"id\": 42 }, \"approvalId\": 27 }\r\n    }\r\n  },\r\n  \"hint\": \"approvalId must be nested inside \\\"params\\\" (params.approvalId), never a sibling of \\\"skillId\\\" — see nextAction for the exact resend request. Optionally POST /api/agent/approvals/27/confirm ahead of time to self-confirm without waiting for the resend (idempotent — resending via nextAction afterwards still succeeds either way). Window closes at expiresAt.\"\r\n}\r\n```\r\n\r\n**② 把 ① 的内容原样展示给人类，等待其同意**（这是防误操作装置，不是授权检查——真正的权限仍然是 token 的 scope；见 [§🛡️ Scope & Operator Responsibility](#scope--operator-responsibility)）。\r\n\r\n**③ 重发，把 `approvalId` 嵌进 `params` 里 → 200：**\r\n\r\n`nextAction.body` 就是可以直接拿去重发的完整请求体——**逐字**用它，不要自己重新拼：\r\n\r\n```bash\r\n# Windows Git Bash 提醒：--data '...' 把 body 放进命令行参数，curl.exe 是原生 Windows 程序，\r\n# MSYS2 会按本地 ANSI 代码页重编码 argv——如果 approve/reject 理由等字段含中文/非 ASCII，\r\n# 内容会被静默改坏。优先用下面的 lg_agent_exec.sh；必须裸 curl 时改用 --data-binary @file。\r\ncurl -X POST \"$LG_AGENT_BASE_URL/agent/skills/execute\" \\\r\n  -H \"Authorization: Bearer $LG_AGENT_TOKEN\" -H \"Content-Type: application/json\" \\\r\n  --data '{\"skillId\":\"process.ingestion.delete\",\"params\":{\"pathParams\":{\"id\":42},\"approvalId\":27}}'\r\n```\r\n\r\n优先用 `lg_agent_exec.sh` 的扁平写法（也修好了上面这个 Windows 编码坑），`approvalId` 作为一个 flat key 传即可（网关不会把它当作业务参数转发下游，也不会因为它出现在 `params` 顶层而拒绝识别）：\r\n\r\n```bash\r\nscripts/lg_agent_exec.sh process.ingestion.delete id=42 approvalId:=27\r\n```\r\n\r\n**唯一会生效的判据是 `params.approvalId`。**踩坑记录（issue #74，2026-08-18 修复）：\r\n\r\n- ❌ `{\"skillId\":\"process.ingestion.delete\",\"approvalId\":27,\"params\":{\"pathParams\":{\"id\":42}}}`——`approvalId` 和 `skillId` 同级、不在 `params` 里，**网关只会把顶层的 `pathParams`/`query`/`body` 折进 `params`，`approvalId` 不在这个白名单内**，会被静默丢弃，网关认为你还没有 approvalId，重新建一条 pending 审批（`approvalId` 会一次次往上涨），永远卡在 ①。\r\n- ❌ 单独发 `confirm:true`（不带 approvalId，或 approvalId 放错位置）——`confirm` 字段本身**不会被读取**，只是网关内部保留字（防止它泄漏到下游请求），加不加、真不真都不影响判定。\r\n- ✅ 只有 `params.approvalId`（嵌套在 `params` 内）才会被网关识别为「已经有一个待处理的审批」。\r\n\r\n`expiresAt` 是这条审批任务的过期时间（TTL 10 分钟）——超时后 `approvalId` 失效，重发 ③ 也会 409，须重新走 ①。\r\n\r\n**（可选）提前自确认**：`agent-skill/scripts/lg_agent_approval.sh confirm <approvalId>` 直接命中 `POST /api/agent/approvals/{id}/confirm`（同一 requester 才能确认自己发起的审批），可以在等待人类确认期间提前调用；之后按 ③ 正常重发仍会成功（幂等）。这**不是**必需步骤——③ 本身已经原子地完成\"自确认 + 消费\"，`confirm` 只是给需要分两次操作的场景用的便利工具。管理员批准/拒绝走 `lg_agent_approval.sh approve|reject`（需要 `userLevel>=8`，非管理员 token 调用会 403——这不是本 skill 的入口，除非你就是管理员）。\r\n\r\n**不可达（暂不支持）**：`investment.{stock,fund,gold}.{portfolio,trading}.delete`（6 个）目前设计上对 token 模式仍然 409——它们背后共用的几个 handler 目前只能声明单一权限校验字符串，无法表达\"以下 12 个 scope 名中的任意一个\"，属于已知限制，不是本次修复范围。\r\n\r\n##### 409 响应辨析（仅限 token 模式的确认握手 409）\r\n\r\n本节只覆盖上面**确认握手**流程里出现的 409——即 `confirmRequired:true` 技能在 token 模式下走 ①/②/③ 过程中收到的 409。判别请优先看 `status` 字段；只有响应没带 `status` 时才退回看 `message` 原文。\r\n\r\n| 情形 | 信号 | 可恢复？ |\r\n|---|---|---|\r\n| 技能不在可握手集合内（即那 6 个 `investment.*.delete`） | 无 `status`；`message` 原文为 `\"High-risk approval flow for token mode is not enabled yet for this skill\"` | **否 —— 终态**，换个技能/等待后端扩大集合，重试无用 |\r\n| ① 第一次调用的响应 | 带 `approvalId` + `nextAction` | 是 —— 照 §②③ 走握手 |\r\n| `status:\"expired\"` | `message` 为 `\"approval task expired\"` | 是 —— 从 ① 重新开始 |\r\n| `status:\"rejected\"` / `\"consumed\"` / `\"unknown\"`（resend 时先命中 self-confirm 端点，这是 token 模式下**最常见**的一类） | `message` 原文为 `\"approval task is not pending\"`，仅靠 `status` 字段区分三种原因；同一状态族在更窄的竞态窗口下（confirm 成功后、consume 执行前被并发消费）也可能改由 consume 端点报出 `message` 原文 `\"approval is not approved\"`——两种 message 字符串对应同一组 `status` 取值，都只能靠 `status` 区分 | 是 —— 从 ① 重新开始 |\r\n| `\"approval task not found\"` / `\"approval task owner mismatch\"` / `\"approval skill mismatch\"` / `\"approval team mismatch\"` / `\"approval scope mismatch\"` / `\"approval payload hash missing or mismatched\"` | 只有 `message`，无 `status` | **否 —— 调用方自身的 bug**，不是重试能解决的（`approvalId` 传错、跨用户/跨团队复用、resend body 与①不一致等） |\r\n| `PROCESS_NAME_EXISTS`（`process.create` / `process.pipeline.build`） | `code:\"PROCESS_NAME_EXISTS\"` | 与确认握手无关，非破坏性——换个 `name` 重试即可 |\r\n\r\n**范围声明**：session 模式（Cookie 会话）另有一条独立的幂等冲突 409（`app.js:2854`，仅在 `mode !== 'token'` 时触发），本节**不覆盖**——它对本 skill 的 Bearer token 使用者结构性不可达（公开版 skill 只支持 Bearer Token 模式，见 [§Security Notes](#security-notes)），是一个本 PR 不修的、独立的既有未文档化缺口，这里明确写出原因而不是略过不提。\r\n\r\n### 流程 (Process / Ingestion)\r\n\r\n| skillId | method | 功能 | 风险 |\r\n|---|---|---|---|\r\n| `process.ingestion.list` | GET | 列出所有流程 | 🟢 |\r\n| `process.ingestion.get` | GET | 根据 id 获取流程详情 | 🟢 |\r\n| `process.ingestion.execute` | POST | 异步触发流程执行（返回 executionId）。`body` 接收自定义 CLI 参数，如 `{\"-start_date\":\"20260419\",\"--env\":\"dev\"}`。后端自动注入 `-f <procName>`，不要自己传 `-f`。 | 🟡 |\r\n| `process.ingestion.execute.log.get` | GET | 按 `executionId` 拉取日志+状态，支持 `offset` 增量轮询。记录持久化在 `process_execution` 表 + 磁盘文件，重启不丢。 | 🟢 |\r\n| `process.component.list` | GET | 列出当前团队可用的步骤组件（含 Markdown 使用说明） | 🟢 |\r\n| `process.pipeline.build` | POST | 一次性创建完整 pipeline（节点+组件+边）。**`python_script` 节点的 `stepCfg` 必须使用执行器字段名 `\"script\"`（不是 `\"pythonScript\"`）**，例：`{\"script\":\"import sys\\nprint(sys.version)\",\"requirements\":\"pandas\"}`。`process.component.list` 返回的 form-schema 中的显示名 `pythonScript` 是 UI 表单专用名，不等于执行器运行时 JSON key——混用会导致执行时报 \"Python script is empty or NULL\"（2026-07-10 incident，已在后端加翻译层向前兼容，但规范写法仍推荐用 `script`）。 | 🟡 |\r\n| `process.create` | POST | **业务字段封装层**（`POST /api/ingestions/create-simple`），比 `process.pipeline.build` 更简单：不需要知道 node id / stepSeq / `aftId`/`sStep`/`nStep`/`fStep` 拓扑字段 / 画布坐标 / 执行器 stepCfg 信封——只填 `{name, description?, steps:[{kind, label?, ...}]}`，后端自动组装成 `process.pipeline.build` 同款请求并复用同一条持久化路径。`kind` 是封闭枚举，只支持**单链路顺序执行**（不支持分支/for 循环/if 节点，那些场景仍用 `process.pipeline.build`）。详见下方 [`process.create` 详情](#processcreate-详情)。 | 🟡 |\r\n| `process.pipeline.update` | PUT | **全量更新已有 pipeline**（`PUT /api/ingestions/{id}`，同形 `BuildPipelineRequest`）。`nodes` 省略=仅改名/描述，保留现有步骤；`nodes=[]` 显式清空；`nodes=[...]` 全量替换。每次 PUT 自动写一条 `dacp_meta_proc_version`，可 `/versions/{n}/restore` 回滚。legacy `team_name IS NULL` 的流程会直接 403，需先 backfill。**想只改一个步骤的 label/conf/remark 而保留 DAG？用 `process.pipeline.update_node` PATCH，避免 aftId 等拓扑字段被默认值 `\"-1\"` 误清空。想只改流程名称/描述？用 `process.pipeline.patch_meta`。** | 🟡 |\r\n| `process.pipeline.update_node` | PATCH | 部分更新单个步骤（`PATCH /api/processes/{procId}/steps/{stepId}`）。**字段掩码语义**：仅 `stepLabel` / `stepConf` / `remark` 三个安全字段可被更新；缺失字段、显式 `null`、**以及空字符串 `\"\"`** 都视为\"跳过\"（**不**清空）。**严格拒绝**：`aftId` / `sStep` / `nStep` / `fStep`（DAG 拓扑）出现在 body 即返回 HTTP 200 `success:false, code:\"TOPOLOGY_FIELD_REJECTED\"` —— 要改变 DAG 拓扑请用 PUT `process.pipeline.update` 全量替换所有节点。`stepName` / `stepSeq` / `parentId` 静默丢弃。**要清空 stepLabel/stepConf/remark 字段也必须走 PUT 全量替换** —— PATCH 设计为\"只增改、不清空\"。**此 skill 需要 `process.pipeline.update_node` scope（独立于 `process.pipeline.update`），现有 token 须重新签发方可使用。** | 🟢 |\r\n| `process.pipeline.patch_meta` | PATCH | 部分更新流程级别元数据（`PATCH /api/ingestions/{id}/meta`）。**字段掩码语义**：仅 `procLabel` / `procDescr` 两个安全字段可被更新；缺失字段、显式 `null`、**以及空字符串 `\"\"`** 都视为\"跳过\"（**不**清空）。**严格拒绝**：`nodes`（拓扑变更）/ `procName`（标识符）/ `creater`（归属）/ `teamName` 出现在 body 即返回 HTTP 200 `success:false, code:\"FIELD_NOT_PATCHABLE\"` —— 要改名称/DAG 结构请用 PUT `process.pipeline.update`。**此 skill 需要 `process.pipeline.patch_meta` scope（独立于 `process.pipeline.update`），现有 token 须重新签发方可使用。** | 🟢 |\r\n\r\n> ⚠️ **推大 `stepCfg` / pipeline 载荷（`process.pipeline.build` / `process.pipeline.update` /\r\n> `process.pipeline.update_node` / `process.create`）之前请先看这条（v1.0.56 起）：**\r\n> `POST /agent/skills/execute` 是这几个 skill 共用的唯一 dispatcher，后端专门为它把 JSON body\r\n> 上限放宽到 **262,144 字节**（`lib/body-parser-limits.js` 的 `LARGE_JSON_LIMIT='256kb'`，\r\n> 平台大多数路由是 100KB 默认值）——这也是为什么这几个 skill 的 payload 会比大多数 skill\r\n> 更容易撞到本节要说的这条**更窄**的本地限制：`scripts/lg_agent_exec.sh` / `lg_agent_approval.sh`\r\n> 把请求体和凭据一起放进同一条 curl `-K -` 配置流发送，转义后的那一行不能超过 **102,400 字节**——\r\n> 引号密集的 JSON（`stepCfg`/SQL/脚本正文常见）转义后大约翻倍，所以**原始 body 约 77KB 起就可能\r\n> 撞上这条本地限制**，即使后端本可以收下（262,144 字节上限还没到）。这条限制在 curl 7.81–8.1.x\r\n> （Ubuntu 22.04、Debian 12 的系统自带版本）上是 curl 自己真实的配置行上限；curl 8.2.0（2023-07）\r\n> 起该上限被 curl 官方抬到 10 MiB，但这个 wrapper **不探测本地 curl 版本**，对所有宿主统一取较低的\r\n> 那个数字（换取\"同一份脚本到处行为一致\"），所以在新版 curl 上这条 102,400 是 wrapper 自己的保守\r\n> 选择，不是 curl 的限制。**遇到时的可行做法**：把大 `stepCfg` 拆成多次 `process.pipeline.update_node`\r\n> PATCH 调用，或改走平台网页 UI 直接编辑；不要指望升级本机 curl 能绕开（本 wrapper 不会因此放宽）。\r\n> 公网 `privora.cn` 入口不受影响——那里 nginx 在约 5–8KB 就已经 414（见下方\"最近更新\"）。\r\n\r\n#### `process.create` 详情\r\n\r\n路径：`POST /api/ingestions/create-simple`，scope `process.create`（独立于 `process.pipeline.build`，现有 token 须重新签发方可使用）。\r\n\r\n**为什么需要它**：`process.pipeline.build` 要求调用方懂平台内部的 DAG 拓扑（node id、`stepSeq`、`aftId`/`sStep`/`nStep`/`fStep` 边字段、画布 x/y/width/height）和执行器 `stepCfg` JSON 信封格式。`process.create` 只暴露业务字段——一个有序、有类型的步骤列表；封装层在服务端补平台管道，不生成任何业务代码（SQL/Python/消息文本仍由调用方自己写）。\r\n\r\n**请求体**：\r\n\r\n```json\r\n{\r\n  \"name\": \"fund_dividend_wrapper_test\",\r\n  \"description\": \"可选描述\",\r\n  \"steps\": [\r\n    { \"kind\": \"run_sql\", \"label\": \"create tables\", \"sql\": \"CREATE TABLE IF NOT EXISTS ...\", \"dataSourceName\": \"pg_main\" },\r\n    { \"kind\": \"run_python\", \"label\": \"fetch akshare\", \"script\": \"import akshare as ak\\nprint(ak.fund_fh_em())\", \"pipRequirements\": [\"akshare\"] },\r\n    { \"kind\": \"run_python\", \"label\": \"tushare enrich\", \"script\": \"import tushare as ts\\n# ...\", \"pipRequirements\": [\"tushare\"] },\r\n    { \"kind\": \"print_summary\", \"label\": \"done\", \"message\": \"fund_dividend ingest complete\" }\r\n  ]\r\n}\r\n```\r\n\r\n`kind` 封闭枚举，映射到真实平台组件（已核实执行器 `*StepMeta` 字段名，不是猜的）：\r\n\r\n| `kind` | 平台组件 | 必填业务字段 | 可选字段 | 组装出的 stepCfg 信封 |\r\n|---|---|---|---|---|\r\n| `run_sql` | `sql` | `sql`、`dataSourceName` | — | `{\"sql\":..,\"dsName\":..,\"needSplit\":\"true\"}` |\r\n| `run_python` | `python_script` | `script` | `pipRequirements`（字符串数组，pip 包名） | `{\"script\":..,\"requirements\":\"..\"}`（`requirements` 由 `pipRequirements` 换行 join；未提供则省略该 key）。**注意 key 是 `script` 不是 `pythonScript`** —— 同 `process.pipeline.build` 那条 2026-07-10 坑，封装层已按执行器真实字段名组装，调用方不会踩到。 |\r\n| `print_summary` | `print` | `message` | — | `{\"message\":..}` |\r\n\r\n**body 里没有 `teamName` / `userName` 字段**——不是被忽略，是这个 DTO 上根本没有这个属性。租户归属 100% 走鉴权上下文（同 `process.pipeline.build`），payload 传了也不会被采纳。\r\n\r\n**拓扑组装（调用方不需要关心，仅供理解结果）**：第 `i` 步（1-based）node id = `\"<name>_step<i>\"`，`stepSeq=\"<i>\"`，画布自动横向布局（120×60，间距 220）。相邻两步之间只支持**单链路顺序执行**——`step[i]` 的 `sStep` 与 `aftId` 都指向 `step[i+1]` 的 `stepSeq`，`nStep`/`fStep` 保持 `\"-1\"`。这是 **fail-fast** 语义：任一步骤失败即中止整个 pipeline，不会静默跳到下一步。**不支持分支 / for 循环 / if 节点 / 并行**——那些场景请用 `process.pipeline.build` 或先用 `process.create` 建好线性骨架、再用 `process.pipeline.update` 全量替换加拓扑。\r\n\r\n**返回**：与 `process.pipeline.build` 相同的信封 `{success, data:{id,name,description,created,teamName}, message}`。`name` 冲突返回 HTTP 409 `{success:false, code:\"PROCESS_NAME_EXISTS\"}`；`steps` 缺失某个 `kind` 必填字段返回 HTTP 400 `{success:false, code:\"VALIDATION_FAILED\", message:\"...\"}`。\r\n\r\n**示例调用：**\r\n\r\n```bash\r\nscripts/lg_agent_exec.sh process.create name=fund_dividend_wrapper_test --json '{\"body\":{\r\n  \"description\":\"fund dividend ingest\",\r\n  \"steps\":[\r\n    {\"kind\":\"run_sql\",\"label\":\"create tables\",\"sql\":\"CREATE TABLE IF NOT EXISTS fund_dividend (...)\",\"dataSourceName\":\"pg_main\"},\r\n    {\"kind\":\"run_python\",\"label\":\"fetch akshare\",\"script\":\"import akshare as ak\\nprint(ak.fund_fh_em())\",\"pipRequirements\":[\"akshare\"]},\r\n    {\"kind\":\"run_python\",\"label\":\"tushare enrich\",\"script\":\"import tushare as ts\\n# ...\",\"pipRequirements\":[\"tushare\"]},\r\n    {\"kind\":\"print_summary\",\"label\":\"done\",\"message\":\"fund_dividend ingest complete\"}\r\n  ]\r\n}}'\r\n```\r\n\r\n### 团队 Python 模块 (Team Python Methods)\r\n\r\n团队级可复用 Python 模块（`team_lib`）——`enabled` 的模块可在 `python_script` 流程步骤里以 `from team_lib.<name> import ...` 导入。执行器每次运行前都会把所有 `enabled` 行重新物化成 `team_lib` 包（先整体删除、再重建），所以这里的改动从**下一次**运行才生效，不是立即生效。跨团队或不存在的 id 一律返回 403（不是 404，避免 id 枚举）。\r\n\r\n| skillId | method | 功能 | 风险 |\r\n|---|---|---|---|\r\n| `team.python.method.list` | GET | 列出当前团队的可复用 Python 模块。返回 `id` / `name` / `code`（完整源码，不截断）/ `description` / `enabled` / `created_by` / `updated_at`。 | 🟢 |\r\n| `team.python.method.get` | GET | 按 id 获取单个模块详情（含完整 `code`）。 | 🟢 |\r\n| `team.python.method.create` | POST | 新建一个团队级可复用 Python 模块。`name` 必须匹配 `^[a-z][a-z0-9_]{0,127}$`；撞上保留包名（`team_lib`/`__init__`/`__main__`）或 Python 关键字/软关键字（如 `class`/`import`/`match`/`case`）会 400（会成为字面上的 `team_lib/<name>.py` 模块文件）；同团队内 `name` 唯一，重复返回 409 \"Module name already exists\"。`code` 落库前会过一遍安全黑名单（`os.system(`、`subprocess.*(`、`eval(`、`exec(`、`__import__(`、`os.environ`、`socket.socket(`、`shutil.rmtree(` 等），命中即 400 \"Security check failed: code contains forbidden pattern [...]\"——这是防误用护栏，不是沙箱边界。`enabled` 默认 `true`；设为 `false` 可先保存、暂不物化进 `team_lib`。 | 🟡 |\r\n| `team.python.method.update` | PUT | 按 id 部分更新（**字段掩码语义**：只有 body 里出现的字段会被改；`name` / `team_name` 通过此接口不可改）。`code` 若出现须非空，且过与 create 相同的安全黑名单。 | 🟡 |\r\n| `team.python.method.delete` | DELETE | **永久删除**一个团队 Python 模块。**不可恢复**——代码行被硬删（`repo.delete`，无软删除/版本历史），且从**下一次** `python_script` 执行开始，任何依赖 `from team_lib.<name> import ...` 的脚本都会抛 `ImportError`（物化是\"每次运行先删再重建\"，正在跑的执行不受影响，但之后每一次都会受影响）。经两步确认握手，见 [§高风险操作确认握手](#高风险操作确认握手-confirm-handshake)。 | 🔴 |\r\n\r\n### 调度 (Schedule)\r\n\r\n| skillId | method | 功能 | 风险 |\r\n|---|---|---|---|\r\n| `schedule.job.list` | GET | 列出调度作业 | 🟢 |\r\n| `schedule.job.get` | GET | 获取调度作业详情 | 🟢 |\r\n| `schedule.workgroup.list` | GET | **发现** 当前平台注册的 workgroup / namespace（从已注册 broker 聚合），是 `schedule.job.create` 两个必填字段的唯一合法来源 | 🟢 |\r\n| `schedule.scripts.get` | GET | **发现** 平台配置的 `jobScript` 默认模板（`{dp, sh, py}`），给 `schedule.job.create` 的 `jobScript` 字段用 | 🟢 |\r\n| `schedule.job.create` | POST | 创建调度作业（`POST /api/schedule/jobs`）。**新建后 `state=\"0\"`**，上线操作需通过平台 UI 执行。 | 🟡 |\r\n| `schedule.job.update` | PUT | 全量替换作业配置（`PUT /api/schedule/job/{jobId}`）。**全部字段都会被覆盖**——缺失字段会被写成 null，可能清空 cronExp 等关键字段。**推荐用 `schedule.job.patch` 做部分更新**；PUT 只在需要显式清空某字段时使用。`state` 字段静默丢弃。 | 🟡 |\r\n| `schedule.job.patch` | PATCH | 部分更新作业配置（`PATCH /api/schedule/job/{jobId}`）。**字段掩码语义**：只有非 null 字段会被覆盖到已存在的行，缺失字段和显式 `null` 都视为\"跳过\"。要清空字段请用 PUT `schedule.job.update`。`state` / `teamName` 同样静默丢弃（与 PUT 一致）。**此 skill 需要 `schedule.job.patch` scope（独立于 `schedule.job.update`），现有 token 须重新签发方可使用。** | 🟢 |\r\n| `schedule.job.depends.list` | GET | 列出作业依赖（按 jobCode）。每行带 `dependGroup`——同组 OR、组间 AND | 🟢 |\r\n| `schedule.job.depends.save` | POST | 全量替换作业依赖列表（旧的先删再写，不经确认握手——传入数组即为完整期望状态，遗漏的依赖会被静默清空）。支持按 `dependGroup` 分组做 OR/AND 组合 | 🟡 |\r\n| `schedule.job.plugins.list` | GET | 列出作业绑定的插件（按 jobCode） | 🟢 |\r\n| `schedule.job.plugins.save` | POST | 全量替换作业插件列表（旧的先删再写，不经确认握手——传入数组即为完整期望状态，遗漏的绑定会被静默清空） | 🟡 |\r\n| `schedule.instance.list` | GET | 列出作业实例（一次运行=一条 trigger 行）；ops 操作所需的 `jobTriggerId` 都从这里拿 | 🟢 |\r\n| `schedule.instance.status.get` | GET | 按 `(jobCode, batchNo)` 查单条最新状态，用于轮询 | 🟢 |\r\n| `schedule.instance.log.get` | GET | 按 `jobTriggerId` 拉取执行日志 | 🟢 |\r\n| `schedule.instance.redo` | POST | **重跑**失败/已完成实例（保留依赖链语义） | 🟡 |\r\n| `schedule.instance.hold` | POST | **暂停**运行中的实例（不杀进程，可恢复） | 🟡 |\r\n| `schedule.instance.resume` | POST | 恢复之前 hold 住的实例 | 🟡 |\r\n| `schedule.instance.reset_priority` | POST | 调等待队列里实例的优先级（`priority` 1-9，越小越先跑） | 🟡 |\r\n| `schedule.job.lineage` | GET | 作业的上下游依赖图（`includeAssets=true` 时附带每个节点的输出资产） | 🟢 |\r\n| `schedule.job.by_process` | GET | 用 process 名反查 jobCode（拿到后才能调 ops skill） | 🟢 |\r\n| `schedule.broker.list` | GET | 列当前注册的 broker（排\"无人认领 workgroup\"类问题时用） | 🟢 |\r\n| `schedule.broker.latency` | GET | Broker 队列长度 + 消费速率 + 推算的等待延迟（诊断\"上线但跑得慢\"类问题） | 🟢 |\r\n| `schedule.job.plugin.webhook.trigger` | POST | 手动触发作业绑定的 webhook 插件 | 🟡 |\r\n\r\n\r\n#### 调度作业字段契约\r\n\r\n**外部 agent 在调 `schedule.job.create` 之前，先走一遍\"发现\"**（这几个字段没有硬编码枚举，值取决于当前部署）：\r\n\r\n1. `schedule.workgroup.list` → 拿到 `{workgroups, namespaces}`，从中各选一个赋给 `workgroup` / `namespace`。**传一个没人认领的 workgroup 不会报错，但没 broker 会去跑**——这是最典型的\"创建完成但永远不执行\"陷阱。\r\n2. `schedule.scripts.get` → 拿到 `{dp, sh, py}`，按 `jobType` 选对应字段赋给 `jobScript`（`dp` 作业用 `dp`，`python` 作业用 `py`，`shell` 作业用 `sh`；空字符串表示该类型没有在这套部署上配好）。\r\n3. 如需参考现有同类 job：`schedule.job.list` + `schedule.job.get` 挑一个已上线的作业 clone 一份。\r\n\r\n**`schedule.job.create` / `schedule.job.update` 的 body**（DataflowJob 形）：\r\n\r\n| 字段 | 必填 | 说明 |\r\n|---|:-:|---|\r\n| `jobCode` | 后端强制 | 团队内唯一业务编码。已存在时 create 幂等返回旧 jobId。 |\r\n| `jobLabel` | UI 强制 | 展示名 |\r\n| `jobType` | UI 强制 | 枚举：`dp` / `datastash` / `python` / `shell` |\r\n| `workgroup` | UI 强制 | 集群组名。**合法值来自 `schedule.workgroup.list`**，不要自己编 |\r\n| `namespace` | UI 强制 | 命名空间。**合法值来自 `schedule.workgroup.list`** |\r\n| `jobScript` | UI 强制 | 执行命令行。**默认模板来自 `schedule.scripts.get`**（按 jobType 取对应字段） |\r\n| `batchType` | UI 强制 | 枚举：`monthly` / `daily` / `hourly` / `minutely` / `once` / `daemon` |\r\n| `cronExp` | 条件 | Quartz 6 段式（秒起头），如 `0 5 15 * * ?` |\r\n| `jobParam` | 条件 | JSON 字符串 **数组**：`\"[{\\\"paramName\\\":\\\"-f\\\",\\\"paramVal\\\":\\\"my_proc\\\"}, ...]\"`；`jobType=dp` 时后端按 `paramName=\"-f\"` 自动回写 `procName` |\r\n| `procName` | 可选 | `dp` 作业通常交给后端从 `jobParam` 反推；其他 type 可显式传 |\r\n| `runConstraint` | 可选 | `\"1\"`=顺序执行（默认），`\"2\"`=并发执行 |\r\n| `batchNo` / `batchOffset` / `batchStep` | 可选 | 批次计算相关 |\r\n| `jobPriority` | 可选 | 1–9，数字越小越高（默认 5） |\r\n| `redoNum` | 可选 | 失败重试次数 |\r\n| `lastdtOffset` | 可选 | 最晚启动偏移（秒），0 为不宽限 |\r\n| `maxElapsed` | 可选 | 最长运行时间（秒） |\r\n| `jobExtCfg` | 可选 | ≤1024 字符的扩展配置 JSON |\r\n| `tag` | 可选 | 自由标签 |\r\n| `jobDescr` | 可选 | 描述 |\r\n| ~~`state`~~ | — | **update 时静默丢弃**，上下线状态变更需通过平台 UI 操作 |\r\n| 服务端自动填充 | — | `jobId`（UUID）、`state=\"0\"`、`version=1`、`teamName` / `memberName` / `createUser`（取自会话） |\r\n\r\n**`schedule.job.depends.save` 的 body**（JSON 数组，**全量替换**）：\r\n\r\n```json\r\n[\r\n  { \"dependCode\": \"upstream_a\", \"dependType\": \"10\", \"dependGroup\": \"g1\" },\r\n  { \"dependCode\": \"upstream_b\", \"dependType\": \"10\", \"dependGroup\": \"g1\" },\r\n  { \"dependCode\": \"20260424\",   \"dependType\": \"20\",\r\n    \"batchCalExp\": \"${batchNo?calDate(-1,'d','yyyyMMdd')}\" }\r\n]\r\n```\r\n上面这份表示 `(upstream_a OR upstream_b) AND 时间依赖`。\r\n\r\n- `dependType=\"10\"` — 任务依赖，`dependCode` 是**另一个 jobCode**（同团队内可见）\r\n- `dependType=\"20\"` — 时间/批次依赖，`dependCode` 是时间字符串，`batchCalExp` 是批次偏移表达式（`${batchNo?calDate(...)}`）\r\n- `dependGroup`（可选）——**分组键：同组 OR、组间 AND**。同一个非空 `dependGroup` 的多行任一满足即算该组满足；不同组（包括每一行 `dependGroup` 为空/不传，各自独立成组）之间要求全部满足——即退化为原来的全 AND 语义。合\n\nFile v1.0.57:_meta.json\n\n{\n  \"ownerId\": \"kn74934h6ss8z6cng1bphdygvs83xrs8\",\n  \"slug\": \"privora-cn-quant\",\n  \"version\": \"1.0.57\",\n  \"publishedAt\": 1789982882096\n}\n\nFile v1.0.57:skill-card.md\n\n## Description:\n\nPrivora connects AI agents to a bearer-token investment workflow platform for A-share, Hong Kong, U.S., gold, fund, and financial-event data, plus Python backtesting, paper trading, portfolio attribution, cloud alerts, and workflow orchestration.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[guangfuwu](https://clawhub.ai/user/guangfuwu)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nExternal users, developers, and AI-agent operators use this skill to query market and portfolio data, run quantitative analysis and backtests, manage simulated trading workflows, and configure alerts through a Privora-issued bearer token.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: The skill can give an agent broad Privora platform authority, including persistent remote changes.\n\nMitigation: Install it with a dedicated least-privilege Privora token, start with read-only scopes, and add write scopes only for a specific workflow.\n\nRisk: Some scheduler, dependency, and plugin operations can replace persistent state and may not have enforced confirmation.\n\nMitigation: List current scheduler dependencies and plugin bindings first, then submit the complete intended state after operator review.\n\nRisk: A bearer token grants access to the data and capabilities in its scopes, including sensitive portfolio data when those scopes are granted.\n\nMitigation: Treat the token as a secret, avoid giving it to untrusted agents, rotate it after exposure, and avoid wildcard or unrelated scopes.\n\nRisk: Analysis, backtest, alert, and simulated-trading outputs can be incomplete, stale, or misleading if used without review.\n\nMitigation: Verify data freshness, strategy assumptions, and scope of results before acting; do not treat outputs as investment advice or live trading instructions.\n\n## Reference(s):\n\n- [ClawHub Skill Page](https://clawhub.ai/guangfuwu/skills/privora-cn-quant)\n- [Privora Product Homepage](https://privora.cn)\n- [Privora Data Coverage](https://privora.cn/features/realtime-minute-data-coverage)\n- [Privora Token Management](https://privora.cn/profile/tokens)\n- [Privora Marketplace](https://privora.cn/marketplace)\n\n## Skill Output:\n\n**Output Type(s):** [Text, Markdown, Code, Shell commands, Configuration, Guidance]\n\n**Output Format:** [Markdown guidance with shell command examples and JSON API responses]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [Requires LG_AGENT_BASE_URL and LG_AGENT_TOKEN; available actions depend on the scopes granted to the Privora bearer token.]\n\n## Skill Version(s):\n\n1.0.57 (source: server release metadata and SKILL.md frontmatter)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment.\n\nArchive v1.0.56: 5 files, 110520 bytes\n\nFiles: scripts/lg_agent_exec.sh (37715b), scripts/lg_agent_list.sh (18459b), skill-card.md (2699b), SKILL.md (209926b), _meta.json (136b)\n\nFile v1.0.56:SKILL.md\n\n---\r\nname: Privora · 数据驱动投资工作流平台 for AI Agents\r\ntitle: 🔬 Privora · AI Agent 投资工作流平台（A股/港股/美股/黄金/基金/财报数据 + Python 回测 + 模拟交易 + 组合归因 + 云端告警 + 流程编排）\r\nversion: 1.0.56\r\nupdatedAt: 2026-09-18\r\nkeywords:\r\n  - A股\r\n  - 港股\r\n  - 美股\r\n  - 基金\r\n  - 黄金\r\n  - 财报数据\r\n  - 业绩预告\r\n  - 现金分红\r\n  - 分钟K线\r\n  - K线\r\n  - 实时行情\r\n  - 量化回测\r\n  - 策略沙盒\r\n  - Python回测\r\n  - A股模拟盘\r\n  - 模拟交易\r\n  - 持仓监控\r\n  - 组合归因\r\n  - 净值曲线\r\n  - AI Agent\r\n  - MCP\r\n  - MCP Server\r\n  - Claude Code\r\n  - Codex\r\n  - Cursor\r\n  - 数据后端\r\n  - 股票\r\n  - 告警\r\n  - 数据新鲜度\r\ndescription: Privora · AI Agent 投资工作流平台 — Bearer Token 即接入 /agent/skills/execute 通用 dispatcher，覆盖 A 股/港股/美股/黄金/基金/财报数据 + Python 回测（含 sandbox）+ 模拟交易 + 组合归因（α/β TWR）+ 云端告警 + 流程编排。Hermes / Claude / GPT / OpenClaw 全兼容。\r\nlicense: MIT-0\r\nmetadata:\r\n  {\r\n    \"openclaw\": {\r\n      \"emoji\": \"📈\",\r\n      \"requires\": {\r\n        \"env\": [\"LG_AGENT_BASE_URL\", \"LG_AGENT_TOKEN\"]\r\n      }\r\n    }\r\n  }\r\n---\r\n\r\n# Privora · AI Agent 投资工作流平台（Bearer Token 即接入 · A股/港股/美股/黄金/基金 数据 + 回测 + 模拟交易 + 告警 + 流程编排）\r\n\r\n**给你的 AI Agent 一个统一的投资研究工作流后端 —— 数据查询 + 策略回测 + 组合归因 + 云端告警 + 流程编排一个 Token 全覆盖。**\r\n\r\nHermes / Claude / GPT / OpenClaw 任何 Agent，通过一个 Bearer Token 即可访问：\r\n\r\n- 📊 **多资产数据（按市场段分别发布，均 🟢 生产可用）**：**日线** A 股 5500+ 股票（`stock_day`，含沪深300 / 上证综指 / 中证A500 / 深证成指 4 主要指数）+ 港股（`stock_day_hk`，如 `00700.HK`）+ 美股（`stock_day_us`，如 `AAPL`）；**分钟 K 线** A 股（`stock_kline`）+ 港股（`stock_kline_hk`），1/5/15/30/60 分钟；**持仓**、**黄金**、**基金**、**财报事件**（业绩预告 / 快报）——一个 API 全覆盖，详见下方「数据资产可用性」表。场内基金（ETF/LOF）日线（`fund_quote_day`）+ 分钟 K 线（`fund_kline`）表已就绪（🟡 尚未开放跨团队订阅，见下方表格）。\r\n- 🔔 **7×24 云端监控**：Serverless 策略托管，飞书 / 微信毫秒级预警，零服务器运维\r\n- 🧪 **Python 策略回测**：用同一份平台数据跑回测，输出 Sharpe / 最大回撤 / 交易明细\r\n- 🔒 **加密静态、认证边界返明文**：持仓数据在数据库中以 per-account 独立密钥密文存储（防 DB 层泄露 + 平台 admin 跨账户读取）；**持有你 Bearer Token 的 Agent 通过 API 认证后，平台按调用者身份解密并返回明文** —— 这不是 E2E 加密，Token 授权即数据访问权。\r\n- 🎯 **1-click subscribe→alert**：Agent 帮用户从\"订阅 dashboard\"到\"配置 alert 上线\"降到 1 step (2026-06-05 新增)\r\n- 🧾 **模拟交易 (Paper Trading)**：MARKET / LIMIT 委托类型 + 调度器驱动 + 真实涨跌停 / 停牌信号，账户 + 订单 DB-level 幂等。\r\n\r\n> **让普通人也能拥有私募级别的工作流**——不需要私募的预算，就能像私募研究员一样在同一条流水线里跑数据 + 分析 + Agent + 告警。\r\n\r\n🆕 **版本与变更历史**：当前版本号以文件头 frontmatter 的 `version:` 字段为准，正文不重复这个数字；每次发布的完整变更说明见仓库内 [`CHANGELOG.md`](./CHANGELOG.md)，随包分发的历史摘要见文末 [§最近更新](#最近更新)。\r\n\r\n🎯 **最适合**：想把整个投研工作流（数据查询 + 回测 + 模拟交易 + 告警 + 流程编排）交给 AI Agent 自动化的散户 / 小工作室；把 Hermes / Claude / GPT / OpenClaw 当量化助手用的开发者。**注意**：Bearer Token 是\"工作流授权凭证\"，不只是\"数据 API key\" —— 授予前先按 [§Scope](#scope--operator-responsibility) 分类明白**要给 Agent 哪些能力**。\r\n\r\n🌐 **产品主页**：[https://privora.cn](https://privora.cn) · 注册即拿 Token\r\n\r\n![演示](./lg-data-demo.gif)\r\n\r\n---\r\n\r\n## 🌟 核心亮点\r\n\r\n### 1. 🤖 兼容所有主流通用 AI Agent\r\n打破生态壁垒，本技能不仅专供某一平台，而是**完美兼容 Hermes、OpenClaw、Claude Code、GitHub Copilot 等所有支持外挂工具/技能的通用大模型 Agent**。只需简单配置环境变量，您的通用 AI 助手瞬间化身专业量化分析师。\r\n\r\n#### 🔌 用 MCP 客户端？有原生通道，两条并存\r\n\r\n如果你的 Agent 是 **Codex CLI / Claude Code / Cursor / Windsurf / Cline**，除了本包的环境变量 + 脚本方式，还有一个**原生 MCP** 通道:一个 stdio MCP server，把同一个 dispatcher 直接暴露成 `tools/list` / `tools/call` 工具，你的 Agent 不必再学 shell 脚本的调用形状。\r\n\r\n**两条通道并存，没有一条被弃用**，而且它们是同一个后端接口的两个门:\r\n\r\n- **接口完全相同** —— 都是 `GET /agent/skills` + `POST /agent/skills/execute` 这两条路由。\r\n- **环境变量完全相同** —— 都是 `LG_AGENT_BASE_URL` + `LG_AGENT_TOKEN`。**配好了本包，就等于配好了 MCP server**，不用重新申请或配置任何东西。\r\n- **权限完全相同** —— scope、租户绑定、`403`、`remediation` 全由后端裁定并原样返回;MCP server 自己不计算也不缓存任何授权判断。**换通道不会让同一个 token 多拿到或少拿到任何能力。**\r\n- **新能力两边同时出现** —— MCP 的工具面是覆盖整个 catalog 的固定 dispatcher，不是手工维护的镜像。\r\n\r\n⚠️ 它目前**还没发布到 npm**（`npm view @privora/mcp-server` 返回 404），需要从仓库检出后用绝对路径接入。用法见仓库里的 `mcp-server/README.md`（安装、客户端配置块、11 个工具、错误映射，以及两个值得在第一次调用前读的平台坑）。\r\n\r\n**该选哪条?** 如果你的客户端原生支持 MCP，用 MCP —— Agent 少一层要学的东西。其它情况（Hermes、OpenClaw、自己写的脚本、CI 里直接 curl）继续用本包，它不会走。\r\n\r\n### 2. 🔒 加密静态 · 认证边界返明文（Encryption-at-rest, not E2E）\r\n\r\n每个账户的持仓数据在数据库中以 per-account 独立密钥密文存储。**这是防\"库泄露 / 平台 admin 跨账户读取\"的加密，不是 E2E 加密**：\r\n\r\n- **持有你 Bearer Token 的 Agent 通过 API 认证后，平台按调用者身份解密并返回明文** —— Token 是解密权的钥匙，保管好 Token 就是保管加密防线\r\n- 每个账户的加密密钥独立，平台管理员账号无法跨账户读取持仓明细（DB 层保证）\r\n- 订阅他人发布资产时，发布方看不到你的查询内容或账户信息（widget config 对订阅方 sanitize）\r\n- **给不可信 Agent 的 Token = 给它明文数据**。按 [§Scope](#scope--operator-responsibility) 授予最小 scope，不要 bundle 无关能力\r\n\r\n### 3. ⚡ Serverless 极速预警与零部署\r\n策略云端托管运行，无需您购买第三方行情 API，无需自建服务器维护 Cron 任务，无 Token 消耗税。策略触发后，毫秒级推送到您的飞书机器人或微信 Webhook。\r\n\r\n---\r\n\r\n## 🛠️ 能做什么\r\n\r\n| 核心功能 | 详细说明 |\r\n| :--- | :--- |\r\n| **资产盈亏巡航** | 一键查询持仓明细、当日盈亏、历史收益率，数据由 privora.cn 闭环处理。 |\r\n| **云端自动盯盘** | 设置预警条件（突破均线、涨跌幅、换手率等），触发即通知，7x24小时云端值守。 |\r\n| **多终端实时推送** | 策略触发毫秒级推送到飞书、微信 Webhook，不错过任何交易信号。 |\r\n| **行情数据** | 日线按市场段分别发布，均 🟢 生产可用：A 股（`stock_day`，沪深京 5500+ 股票 + 4 指数）、港股（`stock_day_hk`，如 `00700.HK`）、美股（`stock_day_us`，如 `AAPL`）；分钟 K 线：A 股（`stock_kline`）+ 港股（`stock_kline_hk`），1/5/15/30/60 分钟；基金日 NAV（`fund_day`）；场内基金（ETF/LOF）日线（`fund_quote_day`）+ 分钟 K 线（`fund_kline`，🟡 已建库尚未开放订阅）；SGE 黄金日线（`metal_day`）；财报事件（`stock_forecast` 业绩预告 + `stock_express` 业绩快报，11 年历史已回填）。详见下方「数据资产可用性」表。 |\r\n| **Python 策略回测** ✨ | 用平台日线数据跑单股 / 多股组合回测，输出 Sharpe / 最大回撤 / 交易明细 / equity curve；结果持久化到 `process_backtest_result`，可通过 `investment.stock.backtest.list` 检索历史审计记录（平台已积累 44+ 次持久化回测）。 |\r\n| **模拟交易 (Paper Trading)** ✨ | MARKET / LIMIT 两种委托类型，调度器驱动，模拟完整委托 → 成交 → 盈亏核算链路；账户按 `user_name` 唯一（DB-level UNIQUE），订单按 `(user_name, client_order_id)` 幂等，Agent 重复调用不重建。适合策略 6 阶段验证的最终纸面交易关卡。 |\r\n| **用户声音收集** | 支持 Agent 代客户提交 Bug 和需求，无缝对接后台反馈系统。 |\r\n\r\n### 数据资产可用性（2026-07-17 platform check）\r\n\r\n> **发布模型说明**：底层物理表按市场是合表存储的（同一张表可能物理上含多市场行），但**对外发布是按市场段分别发布为独立 DataAsset 的**。`stock_day` 段族现已全市场覆盖并各自独立上线：A 股段 = `stock_day`，港股段 = `stock_day_hk`，美股段 = `stock_day_us`；分钟 K 线段族同理：A 股段 = `stock_kline`，港股段 = `stock_kline_hk`。三段各自独立发布、独立 asset id，调用时请用下表的 assetName，不要假设同一 asset 覆盖多市场。\r\n\r\n| DataAsset | 状态 | 覆盖 | 频率 | 备注 |\r\n|---|---|---|---|---|\r\n| `stock_day` | 🟢 **生产可用** | **A 股（沪深京）5500+** 股票日线 + 4 主要指数（沪深300 `1B0300` / 上证综指 `1A0001` / 中证A500 `1B0510` / 深证成指 `399001`） | 日 | id=1；`000001` 等 A 股 ticker 自动路由（`segmentValues` SH/SZ/BJ）；`399001` 自 2026-03-17 起停更，请求会返回 `meta.benchmarkWarning` |\r\n| `stock_day_hk` | 🟢 **生产可用** | 港股日线（如 `00700.HK`） | 日 | id=204；数据新鲜（2026-07-16 校验通过） |\r\n| `stock_day_us` | 🟢 **生产可用** | 美股日线（如 `AAPL`） | 日 | id=206；由 `stock_day_us_backfill_to_mc` 任务从 PG 同步至 MC |\r\n| `stock_kline` | 🟢 **生产可用** | A 股 1/5/15/30/60 分钟 K 线（`interval_type` 区分周期） | 分钟 | id=202；日线 + 日内同步，由 `stock_kline_daily_sync` 等调度维护 |\r\n| `stock_kline_hk` | 🟢 **生产可用** | 港股 1/5/15/30/60 分钟 K 线 | 分钟 | id=207；与 `stock_kline` 同结构，段独立 |\r\n| `stock_minutes` | ⚪ **已弃用** | (旧) 分钟 K 线，已被 `stock_kline` / `stock_kline_hk` 取代 | — | id=154；仅历史兼容保留，新集成请改用 `stock_kline`/`stock_kline_hk` |\r\n| `fund_day` | 🟢 **生产可用** | 公募基金日 NAV | 日 (T+1) | 数据延迟约 1 个工作日；**长期回测/算收益率必须用 `adj_nav`（复权净值），不能用 `unit_nav`（会被拆分/分红污染，且约 49% 行 `adj_nav` 为 NULL）**——详见下方「`adj_nav` 缺失信号」一节 |\r\n| `fund_quote_day` | 🟡 **数据已就绪，尚未开放跨团队订阅** | 场内基金（ETF/LOF）价格日线；PG 单表不分区；`market` ∈ {ETF, LOF}——**与 `fund_day`/`fund_codes` 的 `{E,O}` 词表不同，跨表 join 只能用 `fund_code`**；`turnover` 是成交额（元），不是换手率 | 日 | `source` 分 `akshare_hist_em`（官方历史，`is_final=true`/`calibration_status='confirmed'`）与 `fund_realtime_t0`（当日 T+0 推导，`is_final=false`/`pending`）；两者交叉验证收盘价/成交量完全一致；详见下方「场内基金 K 线」一节 |\r\n| `fund_kline` | 🟡 **数据已就绪，尚未开放跨团队订阅** | 场内基金（ETF/LOF）分钟 K 线，`interval_type` ∈ {1m,5m,15m,30m,60m}（无 1d，日线见 `fund_quote_day`） | 分钟 | PG 原生 RANGE 分区表（按 `day_id`），**保留期仅 3 天**（非 MC 资产，不受 ODPS 分区自动注入影响）；`bar_time` 是 VARCHAR 不是 timestamp；`tick_count` 量化稀疏度；详见下方「场内基金 K 线」一节 |\r\n| `metal_day` | 🟢 **生产可用** | SGE 黄金 / 白银日线 | 日 | 上海黄金交易所 |\r\n| `stock_forecast` | 🟢 **生产可用** (NEW 2026-06-22) | A 股上市公司业绩预告；11 年历史 82,457 行已回填 | 日 | 财报季 (1/4/7/10 月底前后) 集中发布 |\r\n| `stock_express` | 🟢 **生产可用** (NEW 2026-06-22) | A 股上市公司业绩快报；11 年历史 19,945 行已回填 | 日 | 比业绩预告更精确但发布更稀疏 |\r\n| `stock_dividend` | 🟢 **生产可用** (NEW v1.0.32) | A 股上市公司现金分红事件；进入 `portfolio.attribution` 归因 | 事件驱动 | 除权除息日发布 |\r\n\r\n**对 Agent 的指导**：调用 `dataasset.list` 看完整列表；标 🔴 / ⚫ / ⚪ 的资产请避免在策略里硬编码依赖（⚪ = 已弃用，改用其后继 asset）。`dataasset.metadata.get` (2026-06-22 新上) 可查每张表的 `lastUpdated` / `expectedUpdateCadence` / `cronExpression` 来判断当前状态——**2026-09 起这个 scope 已在默认 `read-data` 预设里**，用默认预设建的 token 直接调即可，无需额外勾选。\r\n\r\n> 📌 本节是 **2026-07-17 的一次平台盘点快照**，随时间推移可能与实际覆盖漂移。各已发布资产的完整覆盖范围、分市场明细、更新频率与数据起始日期，见持续维护的公开清单页：[privora.cn/features/realtime-minute-data-coverage](https://privora.cn/features/realtime-minute-data-coverage)（按六类分组，含 A股/港股/美股/北交所分市场明细）。\r\n\r\n---\r\n\r\n## 🛡️ Scope 与操作者责任\r\n\r\n本 skill 是通过 Bearer Token 对接 Privora 平台的能力。操作类别的副作用不同，**操作者负责按类别 scope token 并为需要的类别加入确认门槛**：\r\n\r\n- **只读**（Read-only）—— 数据 API、回测结果查询、流程/调度/数据源/仪表盘/市场的 list/get。**平台状态零副作用**。\r\n- **幂等写**（Idempotent write）—— 模拟交易下单（DB 层 UNIQUE on `user_name` + `client_order_id`，同 key 重试返回同一记录）、marketplace subscribe（ON CONFLICT 返回已有订阅）、告警配置更新。**同输入多次调用只产生一次逻辑效果，可安全重试**。\r\n- **流程状态转移**（Workflow state transition）—— `process.ingestion.execute` 触发已授权 python_script 运行并写入 `process_backtest_result` 表；scheduler-instance 的 `redo / hold / resume / reset-priority` 转移 trigger row 状态。**每次调用创建或修改持久化记录**。\r\n- **确认门槛类**（Confirm-gated destructive/high-risk）—— 一小撮删除 / 撤销 / reset / 调度作业上下线操作 Bearer token **可达**，但单次调用永远不会直接执行——必须先完成两步确认握手，完整列表见下方 [§高风险操作确认握手](#高风险操作确认握手-confirm-handshake)。\r\n- **外发 webhook**（Outbound webhook）—— `schedule.job.plugin.webhook.trigger` 与告警评估路径向操作者配置的外部端点（飞书 / 微信 / 通用 webhook）发送通知。**副作用在 Privora 之外，平台不可撤销**。\r\n\r\n**本 skill 部分暴露**（其余需人在 platform UI 手动完成）：\r\n- 持久化记录的删除 / 撤销 / reset 操作 —— **一小撮**（流程删除、告警规则删除、team Python 模块删除、订阅 token 撤销、模拟盘账户 reset 等）经两步确认握手后可达，见上方「确认门槛类」；**多数**删除操作（如投资组合 / 交易记录删除）仍不在本 skill 范围内。\r\n- 调度器 online / offline 状态转移 —— `schedule.job.online` / `schedule.job.offline` **可达**，同样需要两步确认握手，见上方「确认门槛类」——这两个操作不是\"不暴露\"。\r\n- Webhook 插件生命周期变更（删除 / 禁用）—— `schedule.job.plugins.save`（详见下方作业插件小节，[§调度作业字段契约](#调度作业字段契约)）可全量替换一个作业绑定的插件列表（旧绑定先整体删除再写入新列表），**且不经确认握手**——传入的数组即视为该作业插件的完整期望状态，遗漏的既有绑定会被静默清空，不是增量操作。调用前请先 `schedule.job.plugins.list` 确认当前绑定，再拼出完整数组。\r\n- 管理员级账户操作 —— 不暴露，需通过 platform UI 完成。\r\n\r\n本 skill **不预先声明**任何操作是\"agent-safe\"——这个分类取决于操作者的风险偏好、agent 的可靠性、以及具体用例。**推荐姿势**：只读 + 幂等写允许 agent 自主调用；流程状态转移和外发 webhook 建议先经过用户确认门槛（约定俗成，非平台强制）；标记 `confirmRequired:true` 的高风险操作则由**平台强制**要求两步确认握手，不依赖操作者自律——但请注意上面「Webhook 插件生命周期变更」是**例外**：风险不低（全量替换、旧绑定先删），却不在 `confirmRequired` 名单内，调用前务必自行核实完整期望状态。\r\n\r\n### 📋 场景 → scope 速查表\r\n\r\n**新建 token 的默认 scope 就能取数**（2026-08-03 起）。点\"创建\"不改任何选项，你会得到\r\n`read-data` 这一组：\r\n\r\n```\r\ndataasset.list  dataasset.get  dataasset.schema.get  dataasset.metadata.get\r\ndataasset.data.get  dataasset.data.getRealtime  marketplace.item.list\r\n```\r\n\r\n需要别的能力时，按场景挑一组（token 创建页有同名的场景按钮，点一下即可全选）：\r\n\r\n| 场景 | preset id | scopes |\r\n|---|---|---|\r\n| 取行情 / 资产数据（**默认**） | `read-data` | `dataasset.list` `dataasset.get` `dataasset.schema.get` `dataasset.metadata.get` `dataasset.data.get` `dataasset.data.getRealtime` `marketplace.item.list` |\r\n| 读取数据 + 管理市场订阅（**含写权限**：订阅市场条目拿自己团队的 `clonedAssetId` 等；取消订阅会**删除**该团队克隆副本） | `subscribe-and-read` | `read-data` 全部 + `marketplace.item.subscribe` `marketplace.item.unsubscribe` |\r\n| 读仪表板 | `read-dashboard` | `read-data` 全部 + `dashboard.list` `dashboard.get` `dashboard.data.get` |\r\n| 触发并追踪流程 | `run-process` | `process.ingestion.list` `process.ingestion.get` `process.component.list` `process.ingestion.execute` `process.ingestion.execute.log.get` |\r\n| 配置指标告警（不含建通知通道） | `manage-alerts` | `metric.alert.list` `metric.alert.get` `metric.alert.create` `metric.alert.update` `metric.alert.toggle` `metric.alert.test` |\r\n| 实时告警（通道 + 规则，端到端） | `realtime-alerting` | `dataasset.{list,get,schema.get,metadata.get,data.get}` `datasource.list` `alert.channel.create` `plugin.webhook.send` `metric.alert.{list,get,create,update,patch,toggle,test,snooze,unsnooze,acknowledge}` |\r\n| 读写持仓与交易（**含写权限**） | `portfolio` | `investment.stock.portfolio.{list,create,update}` `investment.stock.trading.{list,create}` `investment.stock.watchlist.list` `investment.stock.signal.{list,get}` `investment.fund.portfolio.{list,create}` `investment.fund.trading.{list,create}` `investment.gold.portfolio.{list,create}` `investment.gold.trading.{list,create}` |\r\n\r\n**三个查询入口**（三处读的是同一份定义，不会互相打架）：\r\n\r\n| 你是谁 | 去哪查 |\r\n|---|---|\r\n| 人 | [privora.cn/profile/tokens](https://privora.cn/profile/tokens) 创建 token 时的场景按钮 |\r\n| Agent | `GET /agent/scope-presets` —— 返回 `{presets[], defaultScopes[], grantedScopes[]}`，每个 preset 带 `scopes[]`、`skillIds[]` 和 `satisfied`（当前 token 是否已满足） |\r\n| Agent | `GET /agent/skills` —— **全量**技能目录。每条带 `granted`（你现在能不能跑）、`scope`（需要哪个 scope）、`params` schema、`exampleInvocation`。跑不了的条目额外带 `presetsGrantingScope` |\r\n\r\n> `GET /agent/skills` 过去只返回你**已有** scope 的技能，所以 scope 不足时你根本看不到目标技能存在，\r\n> 只能靠猜 skillId。现在默认返回全量并用 `granted` 标注；要恢复旧行为传 `?granted=true`。\r\n\r\n**scope 不足时不用猜**：403 响应体直接给出 `requiredScope`、你当前的 `grantedScopes`、\r\n哪个 preset 含它（`presetsGrantingScope`）以及去哪改（`remediationUrl`）。\r\nskillId 写错时 400 响应体给 `didYouMean[]` 候选。\r\n\r\n**Token 使用建议**：\r\n\r\n1. 在 [privora.cn/profile/tokens](https://privora.cn/profile/tokens) 创建专用 Bearer Token\r\n2. **最小 scope 原则** —— 只授予当前 use case 需要的 scope。只读分析用默认的 `read-data` 就够；\r\n   要跑流程再加 `run-process`；agent 真的要下模拟单才加 `paper.*`（该命名空间由平台内部签发，\r\n   见下方\"模拟交易\"章节）。**不要为\"以防万一\"打包无关 scope**。\r\n3. 明确设置 `LG_AGENT_BASE_URL=https://privora.cn`\r\n4. **Token 泄露立即 rotate** —— Token Management 页面列出所有活跃 token 及最后使用时间戳和 revoke 按钮\r\n\r\n> 🛑 **绝对不要让你的 agent 代替你 mint token**。Token 创建是 operator 动作，不是 agent 动作。Agent 应该消费 operator 签发的 Bearer Token，**不应该**自己调 `POST /api/subscription/tokens`。\r\n\r\n### 📑 输出仅供分析参考，不构成投资建议\r\n\r\n本 skill 的输出（行情数据 / 组合分析 / 回测报告 / 模拟交易 / 告警评估）是**供操作者审查的分析结果**，不是投资建议、不是交易指令、也不能替代持牌财务咨询。\r\n\r\n- **把结果作为你自己决策过程的输入** —— 使用前请自行验证数据新鲜度、假设、边界情况\r\n- **实盘交易和不可逆的财务决策不应放在 agent 自动执行链路里** —— 模拟交易只是模拟；真钱交易必须走由操作者控制的券商链路并显式确认\r\n- **回测反映的是历史条件** —— 过去表现不预测未来结果。使用前请确认数据窗口、策略逻辑、以及生存偏差 / look-ahead 假设\r\n- **无监管咨询声明** —— 本平台是数据基础设施；下游任何投资决策由操作者本人（你）负责\r\n\r\n---\r\n\r\n## 🚀 快速接入 (Quick Start)\r\n\r\n### 0) ⚡ 30 秒试一下（不需要注册 / 不需要 Token）\r\n\r\n装完 skill 想立刻看看能干什么？**打开** [privora.cn/marketplace](https://privora.cn/marketplace)：\r\n\r\n- 无需登录，直接浏览公开挂牌的 A 股 / 港股 / 美股 / 黄金 / 基金 / 财报事件等数据资产\r\n- 想一眼看完**全部已发布资产**的覆盖范围 / 更新频率 / 数据起始日期，不用一个个点开？看公开清单页 [privora.cn/features/realtime-minute-data-coverage](https://privora.cn/features/realtime-minute-data-coverage)\r\n- 每个资产可以点进去看 25 行样本数据 + 20 字段元信息（`lastUpdated` / 数据源 / cron 表达式等）\r\n- 看到有价值的资产？**不要记这里显示的 numeric id**：那是发布方团队的 id，拿去调你自己的 Bearer Token 接口只会 404——订阅后你自己团队会拿到一份**全新数字 id** 的克隆资产，两者不是同一个数。**拿自己团队 id 最直接的办法**：走 §1 - §3 注册拿 Token——**`marketplace.item.subscribe` 不在默认 `read-data` 预设里**，预设场景按钮里只有 `subscribe-and-read` 带它，创建 token 时请选 `subscribe-and-read` 预设（或手动勾选 `marketplace.item.subscribe` / `marketplace.item.unsubscribe` 这两个 scope），用默认 `read-data` 预设建的 token 调这一步会 403——然后调 `marketplace.item.subscribe`（幂等——哪怕你之前已经订阅过，重复调用同一个 item 也照样成功），响应体里的 `clonedAssetId` 就是你自己团队里那份克隆资产的数字 id，直接拿去跑 §4 First Call Recipe（2 步 / 约 1 分钟）验证 Bearer Token 对同一资产能跑通。**兜底路径**：如果响应丢了这个字段、或你不想再调一次 subscribe，`dataasset.list` 里按 `tags` 含 `Subscribed` 也能扫到同一份克隆资产的 id\r\n- 觉得样本还不够？往下走 §1 - §4 注册生成 Bearer Token 拿完整访问权（分页 / 过滤 / 更高 rate limit / 写操作 / Agent 集成）\r\n\r\n**为什么先看再注册**：Privora 是投研工作流平台，\"你的数据是否值得订阅\"应该 30 秒能判断 —— 不需要注册墙。marketplace UI 是**发现工具**，Bearer Token 是**同一批数据的程序化访问入口**，两者对应关系明确。\r\n\r\n### 1) 获取您的专属 Token\r\n1. 注册并登录 [privora.cn](https://privora.cn)\r\n2. 在侧边栏点击你的用户名 → API Token Management，或直接访问 `https://privora.cn/profile/tokens`\r\n3. 创建一个仅包含所需 scopes 的专用 Token（建议先用只读或低权限 Token）\r\n4. 复制您的专属 `LG_AGENT_TOKEN`\r\n\r\n### 2) 为您的 Agent 配置环境变量\r\n在您使用的 Agent 终端（如 Hermes、Claude Code、GitHub Copilot 或 OpenClaw）中注入以下环境变量：\r\n```bash\r\nexport LG_AGENT_BASE_URL=\"https://privora.cn\"\r\nexport LG_AGENT_TOKEN=\"***\"\r\n```\r\n公开版主要走以上 Bearer Token 方式；如果 Agent 只是浏览 marketplace / 预览已发布看板 & 资产，也可以走**匿名模式**（不需要 token，见下方 [§🌐 匿名预览](#anonymous-preview)）。session cookie / CSRF 兼容调用不支持。\r\n\r\n### 3) 唤醒 Agent，开始对话\r\n现在，您可以直接用自然语言向您的 Agent 下达指令了！\r\n\r\n### 4) ⚠️ 做出你的第一次成功 API 调用（2 步走 + 1 步可选 / 避免最常见的 500 和 403）\r\n\r\n**最容易踩的坑**：URL 里的 `{id}` 必须是**数字型 asset ID**（如 `42`），**不是 asset 名字**（如 `fund_day` / `stock_day`）。传成名字后端 Spring 转 Long 失败会返回 500——错误信息不会明确告诉你原因。\r\n\r\n**正确的 recipe**（用默认 `read-data` 预设的 token 即可全部跑通）：\r\n\r\n```bash\r\n# Step 1: 先 list 拿数字 id ← 别跳过这步\r\ncurl -H \"Authorization: Bearer $LG_AGENT_TOKEN\" \\\r\n  https://privora.cn/api/data-assets | jq '.data[] | {id, assetName}'\r\n# 输出示例：\r\n# {\"id\": 42, \"assetName\": \"fund_day\"}\r\n# {\"id\": 8,  \"assetName\": \"stock_day\"}\r\n# {\"id\": 15, \"assetName\": \"stock_dividend\"}\r\n\r\n# Step 2: 用数字 id (不是 assetName!) 查实际数据\r\ncurl -H \"Authorization: Bearer $LG_AGENT_TOKEN\" \\\r\n  \"https://privora.cn/api/data-assets/42/data?page=1&size=10\"\r\n```\r\n\r\n**Step 1 返回 `[]`？** 这对刚注册、没有自有资产、也没有订阅任何 marketplace 条目的团队是预期结果，不是 bug——你的团队此时确实没有任何 `dataasset.list` 能看到的资产。见上方 [§0](#0-⚡-30-秒试一下不需要注册-不需要-token) 的 subscribe → `clonedAssetId` 路径：调 `marketplace.item.subscribe` 需要持有该 scope 的 token（预设场景按钮里只有 `subscribe-and-read` 带它，默认 `read-data` 预设没有），拿到 `clonedAssetId` 后回来重跑本节 Step 1，这时就能在列表里看到刚订阅的克隆资产了。\r\n\r\n**（可选）Step 3：查富元数据**——`GET /api/data-assets/{id}/metadata`（对应 skill `dataasset.metadata.get`）**2026-09 起已在** Token Management 页面 `read-data` 默认预设里，用默认预设建的 token 直接调即可：\r\n\r\n```bash\r\ncurl -H \"Authorization: Bearer $LG_AGENT_TOKEN\" \\\r\n  https://privora.cn/api/data-assets/42/metadata\r\n```\r\n\r\n**Agent 侧用 `lg_agent_exec.sh` 调用同理**（v1.0.45 起支持命名参数扁平写法，不用手拼 JSON）：\r\n\r\n```bash\r\nscripts/lg_agent_exec.sh dataasset.list\r\nscripts/lg_agent_exec.sh dataasset.data.get id=42 filter_column=stock_num filter_value=600519\r\n# scripts/lg_agent_exec.sh dataasset.metadata.get id=42  ← 可选；2026-09 起已在默认 read-data 预设里，直接跑即可\r\n```\r\n\r\n`id` **必须是数字**（先 `dataasset.list` 拿到再传，不是资产名字如 `fund_day`）。想看某个 skill 接受哪些 key，先 `scripts/lg_agent_list.sh describe dataasset.data.get` 看 schema + 示例，再照着填。\r\n\r\n**如果你已经踩到 500**：不用改代码逻辑，只需把 `{name}` 换成对应的数字 id 即可。数据资产的可用列表见下方「[数据资产可用性](#数据资产可用性2026-06-22-audit--triage-t-1)」表 —— 那里的名字对应 `dataasset.list` 返回的 `assetName` 字段，需要先 list 拿到本 team 里对应的数字 id。\r\n\r\n---\r\n\r\n<a name=\"anonymous-preview\"></a>\r\n## 🌐 匿名预览（无 token）\r\n\r\n如果 Agent 只是想**浏览 marketplace 或预览已发布的看板/数据资产/流程**——比如帮用户看看 Privora 有什么数据源、有哪些现成看板可订阅、某个流程做什么用——**不需要 Bearer Token 也能直接跑**。这条通路和 [privora.cn/marketplace](https://privora.cn/marketplace) 页面上未登录访客看到的内容是**同一套数据**，只是把它变成 machine-readable 的 skill 调用。\r\n\r\n### 什么时候用\r\n\r\n- 用户还没注册，Agent 想先展示\"这平台上有啥\"\r\n- 用户已注册但当前 session 没配 token，你想让 Agent 先给个 marketplace 摘要\r\n- Agent 在做 discovery / recommendation，不需要写权限、也不涉及用户私有数据\r\n\r\n### 怎么用\r\n\r\n**留空 `LG_AGENT_TOKEN` 或直接不传 `Authorization` header** 即可：\r\n\r\n```bash\r\n# 无 token 调用 —— 直接返回 mode:\"anonymous\" + 10 个可用 skill\r\ncurl https://privora.cn/agent/skills\r\n\r\n# 无 token 拿 marketplace 列表\r\n# Windows Git Bash 提醒：curl.exe 是原生 Windows 程序，MSYS2 会按本地 ANSI 代码页重编码命令行参数，\r\n# 如果把下面的 body 换成含中文/非 ASCII 的内容（如搜索关键字），-d '...' 会被静默改坏——改用 --data-binary @file。\r\nprintf '%s' '{\"skillId\":\"marketplace.item.list\"}' > /tmp/lg_body.json\r\ncurl -X POST https://privora.cn/agent/skills/execute \\\r\n  -H \"Content-Type: application/json\" \\\r\n  --data-binary @/tmp/lg_body.json\r\n\r\n# 无 token 拿某个已发布看板的 widget 数据（同上：非 ASCII 内容一律 --data-binary @file，不要用 -d）\r\nprintf '%s' '{\"skillId\":\"dashboard.data.get\",\"params\":{\"pathParams\":{\"id\":\"<published-dashboard-uuid>\"}}}' > /tmp/lg_body.json\r\ncurl -X POST https://privora.cn/agent/skills/execute \\\r\n  -H \"Content-Type: application/json\" \\\r\n  --data-binary @/tmp/lg_body.json\r\n```\r\n\r\n响应体的 `mode` 字段会明确标 `\"anonymous\"`，`grantedScopes` 列出下方 10 个允许的 skill。\r\n\r\n### 匿名模式可用的 skill（全部只读）\r\n\r\n| skillId | 用途 |\r\n|---|---|\r\n| `marketplace.item.list` | 列出所有可订阅的 marketplace 条目（看板 / 资产 / 流程）—— **discovery 入口** |\r\n| `dashboard.get` | 按 id 拿某个已发布看板的元数据 + widget 定义 |\r\n| `dashboard.data.get` | 一次拿某个已发布看板所有 widget 的数据 |\r\n| `dataasset.get` | 拿某个 `allowSubscription=true` 资产的详情 |\r\n| `dataasset.schema.get` | 拿该资产的列 schema |\r\n| `dataasset.metadata.get` | 拿该资产的富元数据（`lastUpdated` / `expectedUpdateCadence` / cron / 数据源描述等 20 字段）|\r\n| `dataasset.data.get` | 拿该资产的历史数据（预览有效范围内）|\r\n| `dataasset.data.getRealtime` | 拿该资产的实时镜像数据（若配置了 realtime mirror）|\r\n| `process.ingestion.get` | 拿某个 `allowSubscription=true` 流程的结构（**不含 stepCfg 源码**）|\r\n| `process.component.list` | 列平台可用的步骤组件类型（rendering diagram preview 用）|\r\n\r\n### 硬性约束\r\n\r\n- **只读白名单**：**仅上表 10 个 skill** 可调，其余 skill（包括其它只读 GET，如 `investment.stock.portfolio.list` / `dashboard.list` / `dataasset.list`）无论是否存在都返回 403 `missing-scope`。任何写操作（subscribe / create / update / delete）同样 403；哪怕手工构造匿名 PUT/POST 到底层 `/api/**`，Node 代理层也会先 401 拦截，不会到 Spring。\r\n- **每 IP 限流（三桶，任一超限即 429）**：\r\n\r\n  | 桶 | 范围 | 限额 | 429 响应体 |\r\n  |---|---|---|---|\r\n  | 通用桶 | 所有匿名 skill | 60 / IP / 分钟 | `{\"success\":false, \"message\":\"Too many anonymous agent requests, ...\"}` (无 `bucket` 字段) |\r\n  | 数据爆发桶 | `dataasset.data.get` + `dataasset.data.getRealtime` | 10 / IP / 分钟 | `{\"success\":false, \"traceId\":\"...\", \"message\":\"Anonymous data-fetch burst-limit exhausted (10/min per IP). ...\", \"bucket\":\"burst\"}` |\r\n  | 数据日总桶 | 同上 | 100 / IP / 天 | `{\"success\":false, \"traceId\":\"...\", \"message\":\"Anonymous data-fetch daily budget exhausted (100/day per IP). ...\", \"bucket\":\"daily\"}` |\r\n\r\n  收到 429 时读 `response.body.bucket` 判断：`\"burst\"` 等 60 秒重试；`\"daily\"` 今日不再放行该 skill，建议引导用户注册 Bearer Token；无 `bucket` 字段则是通用 60/min 桶命中。\r\n\r\n  **Rate-limit 存储：** v1.0.37 起三桶都存 Redis sorted sets (`anonratelimit:{burst,daily,general}:<ip>`)，通过 Lua 原子脚本实现 sliding window。fleet 内所有 Node worker + 所有 host 共享一份 counter，反爬承诺**真的**成立。**Redis 不可用时 fail-open**：静默放行 + ERROR 日志 `event:\"rate-limit-redis-fail\"`，反爬承诺仅在 Redis 健康时有效（运维监控 fail-open 日志识别异常）。\r\n- **preview token 服务端自动签**：不用你手工去 `/preview-token` 拿；Node 按 skill 类型选：dashboard 类（`dashboard.get` / `dashboard.data.get`）**要求调用方在 `params.pathParams.id` 里传目标看板 id**，Node 会用该 id 签 dashboardId-bound token；未传 id 或其它 skill 一律降级为 `standalone` sentinel（等同 dataasset 类行为）。\r\n- **无效 Bearer 不降级**：如果传了 `Authorization: Bearer <bogus>`，返回 401 而**不会**悄悄退回匿名模式给你部分数据。要匿名就别传 header。\r\n- **无跨租户 leak**：所有资产读都走 `canReadAsset` gate；只有 `allowSubscription=true` 的资产/看板/流程会被返回，其它一律 404。跟浏览器 `/marketplace` 未登录访客看到的是同一套子集。\r\n- **Dashboard-scoped token 不能跨团枚举**：dashboard-A（发布者 = team-A）签的 preview token 无法通过 `dataasset.metadata.get` 读到 team-B 的资产元信息，哪怕 team-B 资产 `allowSubscription=true`。仅 `standalone` sentinel token 可读所有公开挂牌资产。\r\n\r\n### 匿名模式下的**能力受限**（订阅后才解锁）\r\n\r\n数据获取类 skill（`dataasset.data.get` / `dataasset.data.getRealtime` / `dataasset.get` / `dataasset.metadata.get` / `process.ingestion.get`）在匿名模式下**服务端会自动应用以下约束**，参数会被静默改写或剥离——不是 400，你的 curl 依然能正常拿到响应，但拿到的不是你请求的形状：\r\n\r\n- **分页强制固定 `page=1, size=25`**：传任何其他值都被服务端硬覆盖。响应 `pageSize=25, currentPage=1`。想拿更多请订阅后用 Bearer Token 调。\r\n- **过滤 / 排序参数被静默清空**：`filterColumn / filterValue / filterOp / orderBy / orderDirection` 一律置 `null` 再进服务层。想按条件过滤请订阅后再来。\r\n- **发布者身份字段被剥离**（`dataasset.get`）：`dataSource / realtimeDataSource / businessOwner / technicalOwner / teamName / jobCode / createdBy / createdDate / updatedBy / updatedDate` 一律返回 `null`。Metadata map 中 `teamName / dataSource / jobCode / createdBy / createdDate / sourceDescription` 也被剥离。\r\n- **`process.ingestion.get` 的 `stepCfg` 被剥离**：匿名调用者拿不到 process step 的源码 / SQL / Python 内容。\r\n- **`totalElements` 是哨兵值 `0`，不是真实总数**：匿名调用不消耗后端 `COUNT(*)` 查询（防止 JDBC 池 DoS）。分页导航请以 `data.length` 为准。\r\n\r\n配合分页固定 + rate limit，匿名调用者理论上每 IP 每天最多拿到 2,500 行数据（100 次 × 25 行）——真的想跑分析请注册。\r\n\r\n### 匿名模式下常见的误用\r\n\r\n- ❌ 不要**基于匿名 preview 数据做投资决策** —— 25 行不是完整数据集，这只是\"试读\"，不是\"取样\"。\r\n- ❌ 不要**用多 IP 池绕 rate limit** —— 我们记录并封 IP 池行为，正确路径是注册 Bearer Token。\r\n- ❌ 不要**期望 `totalElements` 反映真实行数** —— 匿名调用永远返回 0，这是设计意图，不是 bug。\r\n- ❌ 不要**在匿名模式下尝试 `filterColumn=...`** —— 参数会被静默丢弃，返回的是无过滤的前 25 行，不是过滤后的结果。\r\n\r\n> **技术契约锚点**（review 用）：匿名 skill 白名单 = Node `app.js` 的 `ANONYMOUS_SKILL_SCOPES` 常量；匿名 rate limit = `canAnonymousAgentCall` (60/min) + `canAnonymousDataFetchCall` (10/min burst + 100/day daily)；preview + HMAC 验证 = `docs/auth-flow-invariants.md` §1 + §2.6 + §2.6.1；能力锁定实现与残留 test 缺口 = `docs/plans/2026-07-07-anon-preview-dataasset-lockdown.md`。\r\n\r\n### 从匿名 → 注册的漏斗\r\n\r\n匿名浏览完，如果用户想真正订阅一个看板 / 用私有数据 / 跑回测，需要**注册并领 token**：\r\n\r\n- 引导用户去 `https://privora.cn/register`（`marketplace.item.subscribe` 是 🟡 写操作，不在匿名 scope 里）\r\n- 或直接调 `auth.user.register` skill（也在匿名 scope 之外 —— 需要一层 signup 意图确认，见 §用户注册 & 反馈）\r\n\r\n---\r\n\r\n## 💬 典型应用场景\r\n\r\n### 场景 1：查询账户今日盈亏（个人数据，仅自己可见）\r\n> **您：** “帮我查下今天的账户盈亏情况。”\r\n> \r\n> **Agent（调用 `dataasset.data.get`）：** \r\n> “为您同步 privora.cn 的最新分析结果：\r\n> 💰 **当日盈亏：** +319 元 | **累计浮动：** -19,135 元\r\n> 📊 **持仓明细：** \r\n> - 中国核电：+2.06%\r\n> - 永和股份：-32.45%\r\n> - 中国联通：-16.25%”\r\n\r\n### 场景 2：设定云端智能监控\r\n> **您：** “帮我监控贵州茅台，只要突破MA20均线就通知我。”\r\n> \r\n> **Agent（调用监控接口）：** \r\n> “✅ 已在云端成功创建监控任务：\r\n> - **标的**：贵州茅台 (SH600519)\r\n> - **条件**：价格突破 MA20\r\n> - **通知**：飞书/微信推送\r\n> *任务将在 Serverless 云端静默运行，触发时您将立刻收到推送。*”\r\n\r\n### 场景 3：测试流程并抓取执行日志\r\n\r\n```bash\r\n# 触发执行（异步），记下返回的 executionId\r\n# 自定义 CLI 参数直接当 flat key 传（key 以 - / -- 开头，与 process.ingestion.execute\r\n# 的 Map<String,String> body 逐字对应）。后端会自动注入 `-f <procName>` —— 不用自己传 -f。\r\nRESP=$(scripts/lg_agent_exec.sh process.ingestion.execute id=123 \\\r\n  -start_date=20260419 -end_date=20260420 --env=dev)\r\nEXEC_ID=$(echo \"$RESP\" | jq -r '.executionId')\r\n\r\n# 轮询日志，直到 completed=true\r\nOFFSET=0\r\nwhile :; do\r\n  LOG=$(scripts/lg_agent_exec.sh process.ingestion.execute.log.get \\\r\n    id=123 executionId=\"$EXEC_ID\" offset=\"$OFFSET\")\r\n  echo \"$LOG\" | jq -r '.logLines[]'\r\n  [ \"$(echo \"$LOG\" | jq -r '.completed')\" = \"true\" ] && break\r\n  OFFSET=$(echo \"$LOG\" | jq -r '.nextOffset')\r\n  sleep 1\r\ndone\r\necho \"exitCode=$(echo \"$LOG\" | jq -r '.exitCode')\"\r\n```\r\n\r\n返回：`status` 由 `running` 过渡到 `completed` 或 `failed`，`exitCode` 为脚本退出码，`logLines` 为增量日志行。\r\n\r\n### 场景 4：策略回测（双均线跑茅台）\r\n\r\n> **您：** “用双均线（5日/20日）对茅台 SH600519 过去三年跑个回测”\r\n\r\n在平台新建一个 `python_script` 流程节点，脚本如下（`lg_utils` 已预装）：\r\n\r\n> 💡 **`stock_day` 回测用现成的 `run_stock_day_backtest` 就好**——它已经把列名大小写（`STOCK_NUM` / `OPEN_PRICE` / `CLOSE_PRICE`）和日期格式（`day_id` 的 `YYYYMMDD`）配好了，别再手动传 `price_columns={“open”:”open_price”,...}` 或 ISO 日期，那些是 2026-04-21 踩过的坑。\r\n\r\n```python\r\nfrom lg_utils import get_variable\r\nfrom lg_utils.backtest_examples.dual_ma import DualMA\r\nfrom lg_utils.backtest_examples.stock_day import run_stock_day_backtest\r\n\r\nresult = run_stock_day_backtest(\r\n    strategy=DualMA(fast=5, slow=20),\r\n    stock_num=”600519”,\r\n    start=”20220101”,\r\n    end=”20241231”,\r\n    initial_cash=1_000_000,\r\n    commission_bps=3, slippage_bps=1,\r\n    benchmark_asset=”stock_day”,            # 可选：跟某只指数/股票对比\r\n    benchmark_filter_column=”STOCK_NUM”,\r\n    benchmark_filter_value=”000001”,\r\n)\r\nprint(result.summary())\r\nresult.export_to_context(“maotai_ma520”)   # stdout 日志快照\r\nresult.persist(name=”maotai_ma520”)         # 持久化到 process_backtest_result 表\r\n```\r\n\r\n**组合回测**（共享现金池、多标的同时跑）：\r\n\r\n```python\r\nfrom lg_utils.backtest_examples.stock_day import run_stock_day_portfolio_backtest\r\nfrom lg_utils.backtest_examples.dual_ma import DualMA\r\n\r\nresult = run_stock_day_portfolio_backtest(\r\n    strategies={“600519”: DualMA(5, 20), “000001”: DualMA(10, 30)},\r\n    stock_nums=[“600519”, “000001”],   # 决定 size='all' 结算先后\r\n    start=”20240101”, end=”20241231”,\r\n    initial_cash=1_000_000,\r\n)\r\n# result.metrics[“per_asset”] 给出每只股票的贡献度/回撤/交易数\r\n```\r\n\r\n任务日志里会出现：\r\n\r\n```\r\n=== Backtest Summary ===\r\nasset           : stock_day\r\nperiod          : 20220101 ~ 20241231  (bars=725)\r\ntotal_return    : 23.1500%\r\nsharpe          : 0.8412\r\nmax_drawdown    : 18.2300%\r\nnum_trades      : 14\r\nwin_rate        : 57.1429%\r\n__LG_BACKTEST_RESULT__:maotai_ma520:{\"metrics\":...,\"trades\":...}\r\n```\r\n\r\n完整 JSON（含 `trades` / `equity_curve`）会被下游节点或监控面板消费。\r\n\r\n### 场景 5：一键 subscribe→alert deeplink (NEW v1.0.13)\r\n\r\n> **您：** \"帮我配个告警，招商银行股价跌破 30 通知我。\"\r\n\r\nAgent 调用流程（之前 6 步深埋，2026-06-05 起 1 步）：\r\n\r\n```bash\r\n# 1) Agent 帮用户订阅相关 dashboard\r\nRESP=$(scripts/lg_agent_exec.sh marketplace.item.subscribe itemId=dashboard-china-merchants-bank-watch)\r\n\r\n# 2) 从 response 拿到本租户的 cloned dashboard ID\r\nDASH_ID=$(echo \"$RESP\" | jq -r '.clonedDashboardId')\r\n\r\n# 3) 构造 1-click deeplink — Agent 把这个 URL 给用户\r\nDEEPLINK=\"https://privora.cn/dashboards?selectId=${DASH_ID}&openAlerts=true\"\r\necho \"请打开此链接配置告警：${DEEPLINK}\"\r\n```\r\n\r\n用户点链接进去，metric alert modal **自动打开**——已经对准刚订阅的 dashboard，剩下用户填阈值 + 选 webhook 渠道 finalize 就完。**user-in-the-loop 边界保留**（敏感操作仍需用户在 web 上确认），但 5 步导航 + 选 dashboard + 翻 toolbar 找 \"Alerts\" button 这些都省了。\r\n\r\n这是平台活跃用户反馈最集中的需求——以前的路径是：订阅 → 跳到 dashboard 列表 → 找到目标 dashboard → 打开 toolbar → 找 \"Alerts\" button → （第一次还要去 `/datasources` 配 webhook，回来再继续）→ 配置 → 保存。这次更新把这条路径压到 **1 步**。\r\n\r\n### 场景 6：模拟交易（paper trading）—— 暂不可自助，走 Process Python 节点（#787）\r\n\r\n> **您：** \"用模拟账户跑一笔 600519 的市价买单 100 股，看看现在能不能成交。\"\r\n\r\n**这条路径目前不能靠通用 Agent + 本包 Bearer Token 一次调用走完。** 本节曾给出一段示例，调用 `paper.account.create` / `paper.order.place` / `paper.order.get` 三个 id —— **均不存在于 catalog**，跑起来只会拿到 `400 Skill not found`（#787）。而且光改 id 也走不通：`paper.*` 是**保留 scope 命名空间**——自己去 个人设置 → Token 管理 创建一个带 `paper.account.read` / `paper.orders.write` 的 PAT，后端会直接拒绝 `400 RESERVED_SCOPE`，不存在\"自助签发\"这条路。\r\n\r\n真实能力叫 `investment.paper.*`（见下方「investment.paper.\\* — 模拟盘交易」小节，含真实 skillId `investment.paper.account.get` / `investment.paper.orders.submit` / `investment.paper.orders.list` / `investment.paper.positions.list`），但入口不是 `scripts/lg_agent_exec.sh`，而是**一个 Process 里的 `python_script` 节点**，节点里用 `lg.paper.*` SDK（`lg.paper.get_account()` / `lg.paper.submit_order(...)` / `lg.paper.get_orders(...)`）发起调用。Process 起跑时，后端会给这个节点自动注入一个 scope 限定的短期 Bearer（`paper.orders.write paper.account.read dataasset.read`）——Agent 不需要、也不能自己去申请这个 token。\r\n\r\n**该怎么做**：\r\n\r\n1. 市场已有现成模板 `starter_paper_trade_strategy`——`marketplace.item.subscribe` 一键复制到你的 tenant，改写里面的 `lg.paper.submit_order(...)` 调用即可，不需要从零搭 Process。\r\n2. 若要从零建：用 `process.create`（`kind: \"run_python\"`）建一个含模拟下单脚本的步骤，`process.ingestion.execute` 跑起来——节点内的 `lg.paper.*` 调用由平台自动授权，不经过本包的 Bearer。\r\n3. 若确实需要在 Process 之外、从外部 Agent 直接调 `investment.paper.*`：只能由平台管理员按\"策略绑定模拟账户\"流程走 UI 手动铸一个 process-execution token 再转交给你的 Agent——**这不是本包能自助完成的操作**，不要承诺用户\"改个 id 就行\"。\r\n\r\n支持涨跌停 / 停牌 / suspended-stocks 信号、scheduler-driven 撮合。适合的 use case：策略上真实交易前 12 个月 paper trade 验证（per 6 阶段量化研究流水线最终关卡）——但入口是 Process 编排，不是本包 Bearer 的直接调用。\r\n\r\n## 技能列表\r\n\r\n### REST 技能（`scripts/lg_agent_exec.sh` 调用）\r\n\r\n> 公开版 skill 覆盖 4 类操作，见 [§🛡️ Scope & Operator Responsibility](#scope--operator-responsibility) 完整的 read / idempotent-write / workflow-transition / outbound-webhook 分类。**大部分**删除、撤销等破坏性/管理类操作不在本 skill 范围内，需通过 platform UI 或 admin 工具完成；**例外**是标记 🔴/🟡 且 `confirmRequired:true` 的一小撮 workflow-transition 类操作（`process.ingestion.delete` 等 14 个，见下方 [§高风险操作确认握手](#高风险操作确认握手-confirm-handshake)），这些 Bearer token 可达，但必须先完成两步确认握手——单次调用不会直接执行。系统级审批（管理员 approve/reject 一个陌生人发起的请求）仍然不在本 skill 范围内，需要 platform UI。\r\n> 风险标记：🟢 low / 🟡 medium / 🔴 high。所有 `GET` 技能默认对会话用户开放；写操作需显式授予 scope。\r\n\r\n> 📦 **Request shape (v1.0.45+)**: 命名参数扁平写法 —— 直接用 `key=value` 传参，不用手拼 JSON：\r\n> ```bash\r\n> scripts/lg_agent_exec.sh dataasset.data.get id=42 filter_column=code filter_value=000135\r\n> ```\r\n> 等价于旧 envelope 形式 `{\"skillId\":\"dataasset.data.get\",\"params\":{\"pathParams\":{\"id\":42},\"query\":{\"filter_column\":\"code\",\"filter_value\":\"000135\"}}}`——网关会按每个 skill 的 path 模板自动把 flat key 分类到 `pathParams` / `query` / `body`。`key=value` 一律当字符串（保留 `stock_num=000135` 这类前导零）；数字/布尔/数组用 `key:=value`（如 `qty:=100`）。**旧 envelope 形式 100% 继续可用，两种写法可以在同一次调用里混用**（例：数组 body 用 `--json`，path 参数用 flat key）。想看某个 skill 接受哪些 key，跑 `scripts/lg_agent_list.sh describe <skillId>`。完整规则 + 历史踩坑 + envelope 手工写法见文末 [§高级 / 兼容性附录](#高级--兼容性附录)。\r\n\r\n#### 高风险操作确认握手 (confirm handshake)\r\n\r\n14 个标记 `confirmRequired:true` 的技能对 Bearer token 可达（`process.ingestion.delete`、`schedule.job.{online,offline,delete}`、`schedule.instance.{redo,hold,kill,cancel,force_start,mark_success}`、`subscription.token.revoke`、`metric.alert.delete`、`investment.paper.account.reset`、`team.python.method.delete`），但**单次调用永远不会直接执行**——第一次调用总是返回 HTTP 409，必须完成两步握手才能真正执行。（另有 6 个 `investment.{stock,fund,gold}.{portfolio,trading}.delete` 目前设计上暂不对 token 开放，见下方「不可达」说明。）\r\n\r\n**① 第一次调用（不带 `approvalId`）→ 总是 409：**\r\n\r\n```bash\r\nscripts/lg_agent_exec.sh process.ingestion.delete id=42\r\n```\r\n\r\n```json\r\n{\r\n  \"success\": false,\r\n  \"traceId\": \"...\",\r\n  \"message\": \"Approval required for high-risk action\",\r\n  \"requiredScope\": \"process.ingestion.delete\",\r\n  \"confirmRequired\": true,\r\n  \"approvalId\": 27,\r\n  \"expiresAt\": \"2026-08-18T19:30:00\",\r\n  \"skillId\": \"process.ingestion.delete\",\r\n  \"next\": \"human-approves-then-resend-see-nextAction\",\r\n  \"nextAction\": {\r\n    \"method\": \"POST\",\r\n    \"url\": \"/agent/skills/execute\",\r\n    \"body\": {\r\n      \"skillId\": \"process.ingestion.delete\",\r\n      \"params\": { \"pathParams\": { \"id\": 42 }, \"approvalId\": 27 }\r\n    }\r\n  },\r\n  \"hint\": \"approvalId must be nested inside \\\"params\\\" (params.approvalId), never a sibling of \\\"skillId\\\" — see nextAction for the exact resend request. Optionally POST /api/agent/approvals/27/confirm ahead of time to self-confirm without waiting for the resend (idempotent — resending via nextAction afterwards still succeeds either way). Window closes at expiresAt.\"\r\n}\r\n```\r\n\r\n**② 把 ① 的内容原样展示给人类，等待其同意**（这是防误操作装置，不是授权检查——真正的权限仍然是 token 的 scope；见 [§🛡️ Scope & Operator Responsibility](#scope--operator-responsibility)）。\r\n\r\n**③ 重发，把 `approvalId` 嵌进 `params` 里 → 200：**\r\n\r\n`nextAction.body` 就是可以直接拿去重发的完整请求体——**逐字**用它，不要自己重新拼：\r\n\r\n```bash\r\n# Windows Git Bash 提醒：--data '...' 把 body 放进命令行参数，curl.exe 是原生 Windows 程序，\r\n# MSYS2 会按本地 ANSI 代码页重编码 argv——如果 approve/reject 理由等字段含中文/非 ASCII，\r\n# 内容会被静默改坏。优先用下面的 lg_agent_exec.sh；必须裸 curl 时改用 --data-binary @file。\r\ncurl -X POST \"$LG_AGENT_BASE_URL/agent/skills/execute\" \\\r\n  -H \"Authorization: Bearer $LG_AGENT_TOKEN\" -H \"Content-Type: application/json\" \\\r\n  --data '{\"skillId\":\"process.ingestion.delete\",\"params\":{\"pathParams\":{\"id\":42},\"approvalId\":27}}'\r\n```\r\n\r\n优先用 `lg_agent_exec.sh` 的扁平写法（也修好了上面这个 Windows 编码坑），`approvalId` 作为一个 flat key 传即可（网关不会把它当作业务参数转发下游，也不会因为它出现在 `params` 顶层而拒绝识别）：\r\n\r\n```bash\r\nscripts/lg_agent_exec.sh process.ingestion.delete id=42 approvalId:=27\r\n```\r\n\r\n**唯一会生效的判据是 `params.approvalId`。**踩坑记录（issue #74，2026-08-18 修复）：\r\n\r\n- ❌ `{\"skillId\":\"process.ingestion.delete\",\"approvalId\":27,\"params\":{\"pathParams\":{\"id\":42}}}`——`approvalId` 和 `skillId` 同级、不在 `params` 里，**网关只会把顶层的 `pathParams`/`query`/`body` 折进 `params`，`approvalId` 不在这个白名单内**，会被静默丢弃，网关认为你还没有 approvalId，重新建一条 pending 审批（`approvalId` 会一次次往上涨），永远卡在 ①。\r\n- ❌ 单独发 `confirm:true`（不带 approvalId，或 approvalId 放错位置）——`confirm` 字段本身**不会被读取**，只是网关内部保留字（防止它泄漏到下游请求），加不加、真不真都不影响判定。\r\n- ✅ 只有 `params.approvalId`（嵌套在 `params` 内）才会被网关识别为「已经有一个待处理的审批」。\r\n\r\n`expiresAt` 是这条审批任务的过期时间（TTL 10 分钟）——超时后 `approvalId` 失效，重发 ③ 也会 409，须重新走 ①。\r\n\r\n**（可选）提前自确认**：`agent-skill/scripts/lg_agent_approval.sh confirm <approvalId>` 直接命中 `POST /api/agent/approvals/{id}/confirm`（同一 requester 才能确认自己发起的审批），可以在等待人类确认期间提前调用；之后按 ③ 正常重发仍会成功（幂等）。这**不是**必需步骤——③ 本身已经原子地完成\"自确认 + 消费\"，`confirm` 只是给需要分两次操作的场景用的便利工具。管理员批准/拒绝走 `lg_agent_approval.sh approve|reject`（需要 `userLevel>=8`，非管理员 token 调用会 403——这不是本 skill 的入口，除非你就是管理员）。\r\n\r\n**不可达（暂不支持）**：`investment.{stock,fund,gold}.{portfolio,trading}.delete`（6 个）目前设计上对 token 模式仍然 409——它们背后共用的几个 handler 目前只能声明单一权限校验字符串，无法表达\"以下 12 个 scope 名中的任意一个\"，属于已知限制，不是本次修复范围。\r\n\r\n##### 409 响应辨析（仅限 token 模式的确认握手 409）\r\n\r\n本节只覆盖上面**确认握手**流程里出现的 409——即 `confirmRequired:true` 技能在 token 模式下走 ①/②/③ 过程中收到的 409。判别请优先看 `status` 字段；只有响应没带 `status` 时才退回看 `message` 原文。\r\n\r\n| 情形 | 信号 | 可恢复？ |\r\n|---|---|---|\r\n| 技能不在可握手集合内（即那 6 个 `investment.*.delete`） | 无 `status`；`message` 原文为 `\"High-risk approval flow for token mode is not enabled yet for this skill\"` | **否 —— 终态**，换个技能/等待后端扩大集合，重试无用 |\r\n| ① 第一次调用的响应 | 带 `approvalId` + `nextAction` | 是 —— 照 §②③ 走握手 |\r\n| `status:\"expired\"` | `message` 为 `\"approval task expired\"` | 是 —— 从 ① 重新开始 |\r\n| `status:\"rejected\"` / `\"consumed\"` / `\"unknown\"`（resend 时先命中 self-confirm 端点，这是 token 模式下**最常见**的一类） | `message` 原文为 `\"approval task is not pending\"`，仅靠 `status` 字段区分三种原因；同一状态族在更窄的竞态窗口下（confirm 成功后、consume 执行前被并发消费）也可能改由 consume 端点报出 `message` 原文 `\"approval is not approved\"`——两种 message 字符串对应同一组 `status` 取值，都只能靠 `status` 区分 | 是 —— 从 ① 重新开始 |\r\n| `\"approval task not found\"` / `\"approval task owner mismatch\"` / `\"approval skill mismatch\"` / `\"approval team mismatch\"` / `\"approval scope mismatch\"` / `\"approval payload hash missing or mismatched\"` | 只有 `message`，无 `status` | **否 —— 调用方自身的 bug**，不是重试能解决的（`approvalId` 传错、跨用户/跨团队复用、resend body 与①不一致等） |\r\n| `PROCESS_NAME_EXISTS`（`process.create` / `process.pipeline.build`） | `code:\"PROCESS_NAME_EXISTS\"` | 与确认握手无关，非破坏性——换个 `name` 重试即可 |\r\n\r\n**范围声明**：session 模式（Cookie 会话）另有一条独立的幂等冲突 409（`app.js:2854`，仅在 `mode !== 'token'` 时触发），本节**不覆盖**——它对本 skill 的 Bearer token 使用者结构性不可达（公开版 skill 只支持 Bearer Token 模式，见 [§Security Notes](#security-notes)），是一个本 PR 不修的、独立的既有未文档化缺口，这里明确写出原因而不是略过不提。\r\n\r\n### 流程 (Process / Ingestion)\r\n\r\n| skillId | method | 功能 | 风险 |\r\n|---|---|---|---|\r\n| `process.ingestion.list` | GET | 列出所有流程 | 🟢 |\r\n| `process.ingestion.get` | GET | 根据 id 获取流程详情 | 🟢 |\r\n| `process.ingestion.execute` | POST | 异步触发流程执行（返回 executionId）。`body` 接收自定义 CLI 参数，如 `{\"-start_date\":\"20260419\",\"--env\":\"dev\"}`。后端自动注入 `-f <procName>`，不要自己传 `-f`。 | 🟡 |\r\n| `process.ingestion.execute.log.get` | GET | 按 `executionId` 拉取日志+状态，支持 `offset` 增量轮询。记录持久化在 `process_execution` 表 + 磁盘文件，重启不丢。 | 🟢 |\r\n| `process.component.list` | GET | 列出当前团队可用的步骤组件（含 Markdown 使用说明） | 🟢 |\r\n| `process.pipeline.build` | POST | 一次性创建完整 pipeline（节点+组件+边）。**`python_script` 节点的 `stepCfg` 必须使用执行器字段名 `\"script\"`（不是 `\"pythonScript\"`）**，例：`{\"script\":\"import sys\\nprint(sys.version)\",\"requirements\":\"pandas\"}`。`process.component.list` 返回的 form-schema 中的显示名 `pythonScript` 是 UI 表单专用名，不等于执行器运行时 JSON key——混用会导致执行时报 \"Python script is empty or NULL\"（2026-07-10 incident，已在后端加翻译层向前兼容，但规范写法仍推荐用 `script`）。 | 🟡 |\r\n| `process.create` | POST | **业务字段封装层**（`POST /api/ingestions/create-simple`），比 `process.pipeline.build` 更简单：不需要知道 node id / stepSeq / `aftId`/`sStep`/`nStep`/`fStep` 拓扑字段 / 画布坐标 / 执行器 stepCfg 信封——只填 `{name, description?, steps:[{kind, label?, ...}]}`，后端自动组装成 `process.pipeline.build` 同款请求并复用同一条持久化路径。`kind` 是封闭枚举，只支持**单链路顺序执行**（不支持分支/for 循环/if 节点，那些场景仍用 `process.pipeline.build`）。详见下方 [`process.create` 详情](#processcreate-详情)。 | 🟡 |\r\n| `process.pipeline.update` | PUT | **全量更新已有 pipeline**（`PUT /api/ingestions/{id}`，同形 `BuildPipelineRequest`）。`nodes` 省略=仅改名/描述，保留现有步骤；`nodes=[]` 显式清空；`nodes=[...]` 全量替换。每次 PUT 自动写一条 `dacp_meta_proc_version`，可 `/versions/{n}/restore` 回滚。legacy `team_name IS NULL` 的流程会直接 403，需先 backfill。**想只改一个步骤的 label/conf/remark 而保留 DAG？用 `process.pipeline.update_node` PATCH，避免 aftId 等拓扑字段被默认值 `\"-1\"` 误清空。想只改流程名称/描述？用 `process.pipeline.patch_meta`。** | 🟡 |\r\n| `process.pipeline.update_node` | PATCH | 部分更新单个步骤（`PATCH /api/processes/{procId}/steps/{stepId}`）。**字段掩码语义**：仅 `stepLabel` / `stepConf` / `remark` 三个安全字段可被更新；缺失字段、显式 `null`、**以及空字符串 `\"\"`** 都视为\"跳过\"（**不**清空）。**严格拒绝**：`aftId` / `sStep` / `nStep` / `fStep`（DAG 拓扑）出现在 body 即返回 HTTP 200 `success:false, code:\"TOPOLOGY_FIELD_REJECTED\"` —— 要改变 DAG 拓扑请用 PUT `process.pipeline.update` 全量替换所有节点。`stepName` / `stepSeq` / `parentId` 静默丢弃。**要清空 stepLabel/stepConf/remark 字段也必须走 PUT 全量替换** —— PATCH 设计为\"只增改、不清空\"。**此 skill 需要 `process.pipeline.update_node` scope（独立于 `process.pipeline.update`），现有 token 须重新签发方可使用。** | 🟢 |\r\n| `process.pipeline.patch_meta` | PATCH | 部分更新流程级别元数据（`PATCH /api/ingestions/{id}/meta`）。**字段掩码语义**：仅 `procLabel` / `procDescr` 两个安全字段可被更新；缺失字段、显式 `null`、**以及空字符串 `\"\"`** 都视为\"跳过\"（**不**清空）。**严格拒绝**：`nodes`（拓扑变更）/ `procName`（标识符）/ `creater`（归属）/ `teamName` 出现在 body 即返回 HTTP 200 `success:false, code:\"FIELD_NOT_PATCHABLE\"` —— 要改名称/DAG 结构请用 PUT `process.pipeline.update`。**此 skill 需要 `process.pipeline.patch_meta` scope（独立于 `process.pipeline.update`），现有 token 须重新签发方可使用。** | 🟢 |\r\n\r\n> ⚠️ **推大 `stepCfg` / pipeline 载荷（`process.pipeline.build` / `process.pipeline.update` /\r\n> `process.pipeline.update_node` / `process.create`）之前请先看这条（v1.0.56 起）：**\r\n> `POST /agent/skills/execute` 是这几个 skill 共用的唯一 dispatcher，后端专门为它把 JSON body\r\n> 上限放宽到 **262,144 字节**（`lib/body-parser-limits.js` 的 `LARGE_JSON_LIMIT='256kb'`，\r\n> 平台大多数路由是 100KB 默认值）——这也是为什么这几个 skill 的 payload 会比大多数 skill\r\n> 更容易撞到本节要说的这条**更窄**的本地限制：`scripts/lg_agent_exec.sh` / `lg_agent_approval.sh`\r\n> 把请求体和凭据一起放进同一条 curl `-K -` 配置流发送，转义后的那一行不能超过 **102,400 字节**——\r\n> 引号密集的 JSON（`stepCfg`/SQL/脚本正文常见）转义后大约翻倍，所以**原始 body 约 77KB 起就可能\r\n> 撞上这条本地限制**，即使后端本可以收下（262,144 字节上限还没到）。这条限制在 curl 7.81–8.1.x\r\n> （Ubuntu 22.04、Debian 12 的系统自带版本）上是 curl 自己真实的配置行上限；curl 8.2.0（2023-07）\r\n> 起该上限被 curl 官方抬到 10 MiB，但这个 wrapper **不探测本地 curl 版本**，对所有宿主统一取较低的\r\n> 那个数字（换取\"同一份脚本到处行为一致\"），所以在新版 curl 上这条 102,400 是 wrapper 自己的保守\r\n> 选择，不是 curl 的限制。**遇到时的可行做法**：把大 `stepCfg` 拆成多次 `process.pipeline.update_node`\r\n> PATCH 调用，或改走平台网页 UI 直接编辑；不要指望升级本机 curl 能绕开（本 wrapper 不会因此放宽）。\r\n> 公网 `privora.cn` 入口不受影响——那里 nginx 在约 5–8KB 就已经 414（见下方\"最近更新\"）。\r\n\r\n#### `process.create` 详情\r\n\r\n路径：`POST /api/ingestions/create-simple`，scope `process.create`（独立于 `process.pipeline.build`，现有 token 须重新签发方可使用）。\r\n\r\n**为什么需要它**：`process.pipeline.build` 要求调用方懂平台内部的 DAG 拓扑（node id、`stepSeq`、`aftId`/`sStep`/`nStep`/`fStep` 边字段、画布 x/y/width/height）和执行器 `stepCfg` JSON 信封格式。`process.create` 只暴露业务字段——一个有序、有类型的步骤列表；封装层在服务端补平台管道，不生成任何业务代码（SQL/Python/消息文本仍由调用方自己写）。\r\n\r\n**请求体**：\r\n\r\n```json\r\n{\r\n  \"name\": \"fund_dividend_wrapper_test\",\r\n  \"description\": \"可选描述\",\r\n  \"steps\": [\r\n    { \"kind\": \"run_sql\", \"label\": \"create tables\", \"sql\": \"CREATE TABLE IF NOT EXISTS ...\", \"dataSourceName\": \"pg_main\" },\r\n    { \"kind\": \"run_python\", \"label\": \"fetch akshare\", \"script\": \"import akshare as ak\\nprint(ak.fund_fh_em())\", \"pipRequirements\": [\"akshare\"] },\r\n    { \"kind\": \"run_python\", \"label\": \"tushare enrich\", \"script\": \"import tushare as ts\\n# ...\", \"pipRequirements\": [\"tushare\"] },\r\n    { \"kind\": \"print_summary\", \"label\": \"done\", \"message\": \"fund_dividend ingest complete\" }\r\n  ]\r\n}\r\n```\r\n\r\n`kind` 封闭枚举，映射到真实平台组件（已核实执行器 `*StepMeta` 字段名，不是猜的）：\r\n\r\n| `kind` | 平台组件 | 必填业务字段 | 可选字段 | 组装出的 stepCfg 信封 |\r\n|---|---|---|---|---|\r\n| `run_sql` | `sql` | `sql`、`dataSourceName` | — | `{\"sql\":..,\"dsName\":..,\"needSplit\":\"true\"}` |\r\n| `run_python` | `python_script` | `script` | `pipRequirements`（字符串数组，pip 包名） | `{\"script\":..,\"requirements\":\"..\"}`（`requirements` 由 `pipRequirements` 换行 join；未提供则省略该 key）。**注意 key 是 `script` 不是 `pythonScript`** —— 同 `process.pipeline.build` 那条 2026-07-10 坑，封装层已按执行器真实字段名组装，调用方不会踩到。 |\r\n| `print_summary` | `print` | `message` | — | `{\"message\":..}` |\r\n\r\n**body 里没有 `teamName` / `userName` 字段**——不是被忽略，是这个 DTO 上根本没有这个属性。租户归属 100% 走鉴权上下文（同 `process.pipeline.build`），payload 传了也不会被采纳。\r\n\r\n**拓扑组装（调用方不需要关心，仅供理解结果）**：第 `i` 步（1-based）node id = `\"<name>_step<i>\"`，`stepSeq=\"<i>\"`，画布自动横向布局（120×60，间距 220）。相邻两步之间只支持**单链路顺序执行**——`step[i]` 的 `sStep` 与 `aftId` 都指向 `step[i+1]` 的 `stepSeq`，`nStep`/`fStep` 保持 `\"-1\"`。这是 **fail-fast** 语义：任一步骤失败即中止整个 pipeline，不会静默跳到下一步。**不支持分支 / for 循环 / if 节点 / 并行**——那些场景请用 `process.pipeline.build` 或先用 `process.create` 建好线性骨架、再用 `process.pipeline.update` 全量替换加拓扑。\r\n\r\n**返回**：与 `process.pipeline.build` 相同的信封 `{success, data:{id,name,description,created,teamName}, message}`。`name` 冲突返回 HTTP 409 `{success:false, code:\"PROCESS_NAME_EXISTS\"}`；`steps` 缺失某个 `kind` 必填字段返回 HTTP 400 `{success:false, code:\"VALIDATION_FAILED\", message:\"...\"}`。\r\n\r\n**示例调用：**\r\n\r\n```bash\r\nscripts/lg_agent_exec.sh process.create name=fund_dividend_wrapper_test --json '{\"body\":{\r\n  \"description\":\"fund dividend ingest\",\r\n  \"steps\":[\r\n    {\"kind\":\"run_sql\",\"label\":\"create tables\",\"sql\":\"CREATE TABLE IF NOT EXISTS fund_dividend (...)\",\"dataSourceName\":\"pg_main\"},\r\n    {\"kind\":\"run_python\",\"label\":\"fetch akshare\",\"script\":\"import akshare as ak\\nprint(ak.fund_fh_em())\",\"pipRequirements\":[\"akshare\"]},\r\n    {\"kind\":\"run_python\",\"label\":\"tushare enrich\",\"script\":\"import tushare as ts\\n# ...\",\"pipRequirements\":[\"tushare\"]},\r\n    {\"kind\":\"print_summary\",\"label\":\"done\",\"message\":\"fund_dividend ingest complete\"}\r\n  ]\r\n}}'\r\n```\r\n\r\n### 团队 Python 模块 (Team Python Methods)\r\n\r\n团队级可复用 Python 模块（`team_lib`）——`enabled` 的模块可在 `python_script` 流程步骤里以 `from team_lib.<name> import ...` 导入。执行器每次运行前都会把所有 `enabled` 行重新物化成 `team_lib` 包（先整体删除、再重建），所以这里的改动从**下一次**运行才生效，不是立即生效。跨团队或不存在的 id 一律返回 403（不是 404，避免 id 枚举）。\r\n\r\n| skillId | method | 功能 | 风险 |\r\n|---|---|---|---|\r\n| `team.python.method.list` | GET | 列出当前团队的可复用 Python 模块。返回 `id` / `name` / `code`（完整源码，不截断）/ `description` / `enabled` / `created_by` / `updated_at`。 | 🟢 |\r\n| `team.python.method.get` | GET | 按 id 获取单个模块详情（含完整 `code`）。 | 🟢 |\r\n| `team.python.method.create` | POST | 新建一个团队级可复用 Python 模块。`name` 必须匹配 `^[a-z][a-z0-9_]{0,127}$`；撞上保留包名（`team_lib`/`__init__`/`__main__`）或 Python 关键字/软关键字（如 `class`/`import`/`match`/`case`）会 400（会成为字面上的 `team_lib/<name>.py` 模块文件）；同团队内 `name` 唯一，重复返回 409 \"Module name already exists\"。`code` 落库前会过一遍安全黑名单（`os.system(`、`subprocess.*(`、`eval(`、`exec(`、`__import__(`、`os.environ`、`socket.socket(`、`shutil.rmtree(` 等），命中即 400 \"Security check failed: code contains forbidden pattern [...]\"——这是防误用护栏，不是沙箱边界。`enabled` 默认 `true`；设为 `false` 可先保存、暂不物化进 `team_lib`。 | 🟡 |\r\n| `team.python.method.update` | PUT | 按 id 部分更新（**字段掩码语义**：只有 body 里出现的字段会被改；`name` / `team_name` 通过此接口不可改）。`code` 若出现须非空，且过与 create 相同的安全黑名单。 | 🟡 |\r\n| `team.python.method.delete` | DELETE | **永久删除**一个团队 Python 模块。**不可恢复**——代码行被硬删（`repo.delete`，无软删除/版本历史），且从**下一次** `python_script` 执行开始，任何依赖 `from team_lib.<name> import ...` 的脚本都会抛 `ImportError`（物化是\"每次运行先删再重建\"，正在跑的执行不受影响，但之后每一次都会受影响）。经两步确认握手，见 [§高风险操作确认握手](#高风险操作确认握手-confirm-handshake)。 | 🔴 |\r\n\r\n### 调度 (Schedule)\r\n\r\n| skillId | method | 功能 | 风险 |\r\n|---|---|---|---|\r\n| `schedule.job.list` | GET | 列出调度作业 | 🟢 |\r\n| `schedule.job.get` | GET | 获取调度作业详情 | 🟢 |\r\n| `schedule.workgroup.list` | GET | **发现** 当前平台注册的 workgroup / namespace（从已注册 broker 聚合），是 `schedule.job.create` 两个必填字段的唯一合法来源 | 🟢 |\r\n| `schedule.scripts.get` | GET | **发现** 平台配置的 `jobScript` 默认模板（`{dp, sh, py}`），给 `schedule.job.create` 的 `jobScript` 字段用 | 🟢 |\r\n| `schedule.job.create` | POST | 创建调度作业（`POST /api/schedule/jobs`）。**新建后 `state=\"0\"`**，上线操作需通过平台 UI 执行。 | 🟡 |\r\n| `schedule.job.update` | PUT | 全量替换作业配置（`PUT /api/schedule/job/{jobId}`）。**全部字段都会被覆盖**——缺失字段会被写成 null，可能清空 cronExp 等关键字段。**推荐用 `schedule.job.patch` 做部分更新**；PUT 只在需要显式清空某字段时使用。`state` 字段静默丢弃。 | 🟡 |\r\n| `schedule.job.patch` | PATCH | 部分更新作业配置（`PATCH /api/schedule/job/{jobId}`）。**字段掩码语义**：只有非 null 字段会被覆盖到已存在的行，缺失字段和显式 `null` 都视为\"跳过\"。要清空字段请用 PUT `schedule.job.update`。`state` / `teamName` 同样静默丢弃（与 PUT 一致）。**此 skill 需要 `schedule.job.patch` scope（独立于 `schedule.job.update`），现有 token 须重新签发方可使用。** | 🟢 |\r\n| `schedule.job.depends.list` | GET | 列出作业依赖（按 jobCode）。每行带 `dependGroup`——同组 OR、组间 AND | 🟢 |\r\n| `schedule.job.depends.save` | POST | 全量替换作业依赖列表（旧的先删再写，不经确认握手——传入数组即为完整期望状态，遗漏的依赖会被静默清空）。支持按 `dependGroup` 分组做 OR/AND 组合 | 🟡 |\r\n| `schedule.job.plugins.list` | GET | 列出作业绑定的插件（按 jobCode） | 🟢 |\r\n| `schedule.job.plugins.save` | POST | 全量替换作业插件列表（旧的先删再写，不经确认握手——传入数组即为完整期望状态，遗漏的绑定会被静默清空） | 🟡 |\r\n| `schedule.instance.list` | GET | 列出作业实例（一次运行=一条 trigger 行）；ops 操作所需的 `jobTriggerId` 都从这里拿 | 🟢 |\r\n| `schedule.instance.status.get` | GET | 按 `(jobCode, batchNo)` 查单条最新状态，用于轮询 | 🟢 |\r\n| `schedule.instance.log.get` | GET | 按 `jobTriggerId` 拉取执行日志 | 🟢 |\r\n| `schedule.instance.redo` | POST | **重跑**失败/已完成实例（保留依赖链语义） | 🟡 |\r\n| `schedule.instance.hold` | POST | **暂停**运行中的实例（不杀进程，可恢复） | 🟡 |\r\n| `schedule.instance.resume` | POST | 恢复之前 hold 住的实例 | 🟡 |\r\n| `schedule.instance.reset_priority` | POST | 调等待队列里实例的优先级（`priority` 1-9，越小越先跑） | 🟡 |\r\n| `schedule.job.lineage` | GET | 作业的上下游依赖图（`includeAssets=true` 时附带每个节点的输出资产） | 🟢 |\r\n| `schedule.job.by_process` | GET | 用 process 名反查 jobCode（拿到后才能调 ops skill） | 🟢 |\r\n| `schedule.broker.list` | GET | 列当前注册的 broker（排\"无人认领 workgroup\"类问题时用） | 🟢 |\r\n| `schedule.broker.latency` | GET | Broker 队列长度 + 消费速率 + 推算的等待延迟（诊断\"上线但跑得慢\"类问题） | 🟢 |\r\n| `schedule.job.plugin.webhook.trigger` | POST | 手动触发作业绑定的 webhook 插件 | 🟡 |\r\n\r\n\r\n#### 调度作业字段契约\r\n\r\n**外部 agent 在调 `schedule.job.create` 之前，先走一遍\"发现\"**（这几个字段没有硬编码枚举，值取决于当前部署）：\r\n\r\n1. `schedule.workgroup.list` → 拿到 `{workgroups, namespaces}`，从中各选一个赋给 `workgroup` / `namespace`。**传一个没人认领的 workgroup 不会报错，但没 broker 会去跑**——这是最典型的\"创建完成但永远不执行\"陷阱。\r\n2. `schedule.scripts.get` → 拿到 `{dp, sh, py}`，按 `jobType` 选对应字段赋给 `jobScript`（`dp` 作业用 `dp`，`python` 作业用 `py`，`shell` 作业用 `sh`；空字符串表示该类型没有在这套部署上配好）。\r\n3. 如需参考现有同类 job：`schedule.job.list` + `schedule.job.get` 挑一个已上线的作业 clone 一份。\r\n\r\n**`schedule.job.create` / `schedule.job.update` 的 body**（DataflowJob 形）：\r\n\r\n| 字段 | 必填 | 说明 |\r\n|---|:-:|---|\r\n| `jobCode` | 后端强制 | 团队内唯一业务编码。已存在时 create 幂等返回旧 jobId。 |\r\n| `jobLabel` | UI 强制 | 展示名 |\r\n| `jobType` | UI 强制 | 枚举：`dp` / `datastash` / `python` / `shell` |\r\n| `workgroup` | UI 强制 | 集群组名。**合法值来自 `schedule.workgroup.list`**，不要自己编 |\r\n| `namespace` | UI 强制 | 命名空间。**合法值来自 `schedule.workgroup.list`** |\r\n| `jobScript` | UI 强制 | 执行命令行。**默认模板来自 `schedule.scripts.get`**（按 jobType 取对应字段） |\r\n| `batchType` | UI 强制 | 枚举：`monthly` / `daily` / `hourly` / `minutely` / `once` / `daemon` |\r\n| `cronExp` | 条件 | Quartz 6 段式（秒起头），如 `0 5 15 * * ?` |\r\n| `jobParam` | 条件 | JSON 字符串 **数组**：`\"[{\\\"paramName\\\":\\\"-f\\\",\\\"paramVal\\\":\\\"my_proc\\\"}, ...]\"`；`jobType=dp` 时后端按 `paramName=\"-f\"` 自动回写 `procName` |\r\n| `procName` | 可选 | `dp` 作业通常交给后端从 `jobParam` 反推；其他 type 可显式传 |\r\n| `runConstraint` | 可选 | `\"1\"`=顺序执行（默认），`\"2\"`=并发执行 |\r\n| `batchNo` / `batchOffset` / `batchStep` | 可选 | 批次计算相关 |\r\n| `jobPriority` | 可选 | 1–9，数字越小越高（默认 5） |\r\n| `redoNum` | 可选 | 失败重试次数 |\r\n| `lastdtOffset` | 可选 | 最晚启动偏移（秒），0 为不宽限 |\r\n| `maxElapsed` | 可选 | 最长运行时间（秒） |\r\n| `jobExtCfg` | 可选 | ≤1024 字符的扩展配置 JSON |\r\n| `tag` | 可选 | 自由标签 |\r\n| `jobDescr` | 可选 | 描述 |\r\n| ~~`state`~~ | — | **update 时静默丢弃**，上下线状态变更需通过平台 UI 操作 |\r\n| 服务端自动填充 | — | `jobId`（UUID）、`state=\"0\"`、`version=1`、`teamName` / `memberName` / `createUser`（取自会话） |\r\n\r\n**`schedule.job.depends.save` 的 body**（JSON 数组，**全量替换**）：\r\n\r\n```json\r\n[\r\n  { \"dependCode\": \"upstream_a\", \"dependType\": \"10\", \"dependGroup\": \"g1\" },\r\n  { \"dependCode\": \"upstream_b\", \"dependType\": \"10\", \"dependGroup\": \"g1\" },\r\n  { \"dependCode\": \"20260424\",   \"dependType\": \"20\",\r\n    \"batchCalExp\": \"${batchNo?calDate(-1,'d','yyyyMMdd')}\" }\r\n]\r\n```\r\n上面这份表示 `(upstream_a OR upstream_b) AND 时间依赖`。\r\n\r\n- `dependType=\"10\"` — 任务依赖，`dependCode` 是**另一个 jobCode**（同团队内可见）\r\n- `dependType=\"20\"` — 时间/批次依赖，`dependCode` 是时间字符串，`batchCalExp` 是批次偏移表达式（`${batchNo?calDate(...)}`）\r\n- `dependGroup`（可选）——**分组键：同组 OR、组间 AND**。同一个非空 `dependGroup` 的多行任一满足即算该组满足；不同组（包括每一行 `dependGroup` 为空/不传，各自独立成组）之间要求全部满足——即退化为原来的全 AND 语义。合法格式 `^[A-Za-z0-9_-]{1,32}$`；空白会被规范化为 `null`。**任何一行格式不合法，整次保存都会失败**（`{success:false, message}`），且**不会删除任何已有依赖行**——可以放心重试。\r\n- 其他字段：`procName`、`output`、`isDefault`（`\"1\"` 标默认）都可选\r\n- `dependId` 每次保存都由服务端重新生成（UUID16），不用自己传，也不要依赖它在两次保存之间保持不变\r\n\r\n**`schedule.job.plugins.save` 的 body**（JSON 数组，**全量替换**）：\r\n\r\n```json\r\n[\r\n \n\nFile v1.0.56:_meta.json\n\n{\n  \"ownerId\": \"kn74934h6ss8z6cng1bphdygvs83xrs8\",\n  \"slug\": \"privora-cn-quant\",\n  \"version\": \"1.0.56\",\n  \"publishedAt\": 1789715341733\n}\n\nFile v1.0.56:skill-card.md\n\n## Description:\n\nPrivora gives AI agents a Bearer-token workflow backend for A-share, Hong Kong, U.S. equity, gold, fund, financial-event, Python backtesting, paper-trading, portfolio-attribution, alerting, and workflow-orchestration tasks.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[guangfuwu](https://clawhub.ai/user/guangfuwu)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nExternal developers, AI-agent operators, and quantitative-investment users use this skill to let an agent discover Privora capabilities, query market and portfolio data, run backtests, manage paper-trading workflows, and configure alerts through scoped Privora API calls.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: A token can expose broad financial-data and workflow-changing capabilities to an autonomous agent.\n\nMitigation: Use a dedicated least-privilege Privora token, start with read-only scopes, and avoid wildcard or bundled write scopes unless the use case requires them.\n\nRisk: Some destructive, reset, revoke, scheduling, datasource, dashboard, webhook, or team-Python actions may be reachable without an independently enforced human approval step.\n\nMitigation: Keep those scopes out of autonomous-agent tokens unless there is a separate human approval process outside the skill.\n\nRisk: Loopback or self-hosted requests with large JSON bodies can exceed the wrapper's conservative curl config-line limit.\n\nMitigation: Split large payloads into smaller calls or use the Privora platform UI for oversized workflow changes.\n\n## Reference(s):\n\n- [ClawHub Skill Page](https://clawhub.ai/guangfuwu/skills/privora-cn-quant)\n- [Privora Product Homepage](https://privora.cn)\n- [Privora Data Coverage](https://privora.cn/features/realtime-minute-data-coverage)\n- [Privora Token Management](https://privora.cn/profile/tokens)\n- [Privora Public Agent Capabilities](https://privora.cn/api/public/agent/capabilities)\n\n## Skill Output:\n\n**Output Type(s):** [text, markdown, code, shell commands, configuration, guidance]\n\n**Output Format:** [Markdown guidance, shell command invocations, and JSON API responses]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [Requires LG_AGENT_TOKEN and optionally LG_AGENT_BASE_URL; API calls are authorized by the token's Privora scopes.]\n\n## Skill Version(s):\n\n1.0.56 (source: server release metadata and SKILL.md frontmatter)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment.\n\nArchive v1.0.55: 5 files, 108865 bytes\n\nFiles: scripts/lg_agent_exec.sh (36252b), scripts/lg_agent_list.sh (18496b), skill-card.md (3629b), SKILL.md (206602b), _meta.json (136b)\n\nFile v1.0.55:SKILL.md\n\n---\r\nname: Privora · 数据驱动投资工作流平台 for AI Agents\r\ntitle: 🔬 Privora · AI Agent 投资工作流平台（A股/港股/美股/黄金/基金/财报数据 + Python 回测 + 模拟交易 + 组合归因 + 云端告警 + 流程编排）\r\nversion: 1.0.55\r\nupdatedAt: 2026-09-15\r\nkeywords:\r\n  - A股\r\n  - 港股\r\n  - 美股\r\n  - 基金\r\n  - 黄金\r\n  - 财报数据\r\n  - 业绩预告\r\n  - 现金分红\r\n  - 分钟K线\r\n  - K线\r\n  - 实时行情\r\n  - 量化回测\r\n  - 策略沙盒\r\n  - Python回测\r\n  - A股模拟盘\r\n  - 模拟交易\r\n  - 持仓监控\r\n  - 组合归因\r\n  - 净值曲线\r\n  - AI Agent\r\n  - MCP\r\n  - MCP Server\r\n  - Claude Code\r\n  - Codex\r\n  - Cursor\r\n  - 数据后端\r\n  - 股票\r\n  - 告警\r\n  - 数据新鲜度\r\ndescription: Privora · AI Agent 投资工作流平台 — Bearer Token 即接入 /agent/skills/execute 通用 dispatcher，覆盖 A 股/港股/美股/黄金/基金/财报数据 + Python 回测（含 sandbox）+ 模拟交易 + 组合归因（α/β TWR）+ 云端告警 + 流程编排。Hermes / Claude / GPT / OpenClaw 全兼容。\r\nlicense: MIT-0\r\nmetadata:\r\n  {\r\n    \"openclaw\": {\r\n      \"emoji\": \"📈\",\r\n      \"requires\": {\r\n        \"env\": [\"LG_AGENT_BASE_URL\", \"LG_AGENT_TOKEN\"]\r\n      }\r\n    }\r\n  }\r\n---\r\n\r\n# Privora · AI Agent 投资工作流平台（Bearer Token 即接入 · A股/港股/美股/黄金/基金 数据 + 回测 + 模拟交易 + 告警 + 流程编排）\r\n\r\n**给你的 AI Agent 一个统一的投资研究工作流后端 —— 数据查询 + 策略回测 + 组合归因 + 云端告警 + 流程编排一个 Token 全覆盖。**\r\n\r\nHermes / Claude / GPT / OpenClaw 任何 Agent，通过一个 Bearer Token 即可访问：\r\n\r\n- 📊 **多资产数据（按市场段分别发布，均 🟢 生产可用）**：**日线** A 股 5500+ 股票（`stock_day`，含沪深300 / 上证综指 / 中证A500 / 深证成指 4 主要指数）+ 港股（`stock_day_hk`，如 `00700.HK`）+ 美股（`stock_day_us`，如 `AAPL`）；**分钟 K 线** A 股（`stock_kline`）+ 港股（`stock_kline_hk`），1/5/15/30/60 分钟；**持仓**、**黄金**、**基金**、**财报事件**（业绩预告 / 快报）——一个 API 全覆盖，详见下方「数据资产可用性」表。场内基金（ETF/LOF）日线（`fund_quote_day`）+ 分钟 K 线（`fund_kline`）表已就绪（🟡 尚未开放跨团队订阅，见下方表格）。\r\n- 🔔 **7×24 云端监控**：Serverless 策略托管，飞书 / 微信毫秒级预警，零服务器运维\r\n- 🧪 **Python 策略回测**：用同一份平台数据跑回测，输出 Sharpe / 最大回撤 / 交易明细\r\n- 🔒 **加密静态、认证边界返明文**：持仓数据在数据库中以 per-account 独立密钥密文存储（防 DB 层泄露 + 平台 admin 跨账户读取）；**持有你 Bearer Token 的 Agent 通过 API 认证后，平台按调用者身份解密并返回明文** —— 这不是 E2E 加密，Token 授权即数据访问权。\r\n- 🎯 **1-click subscribe→alert**：Agent 帮用户从\"订阅 dashboard\"到\"配置 alert 上线\"降到 1 step (2026-06-05 新增)\r\n- 🧾 **模拟交易 (Paper Trading)**：MARKET / LIMIT 委托类型 + 调度器驱动 + 真实涨跌停 / 停牌信号，账户 + 订单 DB-level 幂等。\r\n\r\n> **让普通人也能拥有私募级别的工作流**——不需要私募的预算，就能像私募研究员一样在同一条流水线里跑数据 + 分析 + Agent + 告警。\r\n\r\n🆕 **版本与变更历史**：当前版本号以文件头 frontmatter 的 `version:` 字段为准，正文不重复这个数字；每次发布的完整变更说明见仓库内 [`CHANGELOG.md`](./CHANGELOG.md)，随包分发的历史摘要见文末 [§最近更新](#最近更新)。\r\n\r\n🎯 **最适合**：想把整个投研工作流（数据查询 + 回测 + 模拟交易 + 告警 + 流程编排）交给 AI Agent 自动化的散户 / 小工作室；把 Hermes / Claude / GPT / OpenClaw 当量化助手用的开发者。**注意**：Bearer Token 是\"工作流授权凭证\"，不只是\"数据 API key\" —— 授予前先按 [§Scope](#scope--operator-responsibility) 分类明白**要给 Agent 哪些能力**。\r\n\r\n🌐 **产品主页**：[https://privora.cn](https://privora.cn) · 注册即拿 Token\r\n\r\n![演示](./lg-data-demo.gif)\r\n\r\n---\r\n\r\n## 🌟 核心亮点\r\n\r\n### 1. 🤖 兼容所有主流通用 AI Agent\r\n打破生态壁垒，本技能不仅专供某一平台，而是**完美兼容 Hermes、OpenClaw、Claude Code、GitHub Copilot 等所有支持外挂工具/技能的通用大模型 Agent**。只需简单配置环境变量，您的通用 AI 助手瞬间化身专业量化分析师。\r\n\r\n#### 🔌 用 MCP 客户端？有原生通道，两条并存\r\n\r\n如果你的 Agent 是 **Codex CLI / Claude Code / Cursor / Windsurf / Cline**，除了本包的环境变量 + 脚本方式，还有一个**原生 MCP** 通道:一个 stdio MCP server，把同一个 dispatcher 直接暴露成 `tools/list` / `tools/call` 工具，你的 Agent 不必再学 shell 脚本的调用形状。\r\n\r\n**两条通道并存，没有一条被弃用**，而且它们是同一个后端接口的两个门:\r\n\r\n- **接口完全相同** —— 都是 `GET /agent/skills` + `POST /agent/skills/execute` 这两条路由。\r\n- **环境变量完全相同** —— 都是 `LG_AGENT_BASE_URL` + `LG_AGENT_TOKEN`。**配好了本包，就等于配好了 MCP server**，不用重新申请或配置任何东西。\r\n- **权限完全相同** —— scope、租户绑定、`403`、`remediation` 全由后端裁定并原样返回;MCP server 自己不计算也不缓存任何授权判断。**换通道不会让同一个 token 多拿到或少拿到任何能力。**\r\n- **新能力两边同时出现** —— MCP 的工具面是覆盖整个 catalog 的固定 dispatcher，不是手工维护的镜像。\r\n\r\n⚠️ 它目前**还没发布到 npm**（`npm view @privora/mcp-server` 返回 404），需要从仓库检出后用绝对路径接入。用法见仓库里的 `mcp-server/README.md`（安装、客户端配置块、11 个工具、错误映射，以及两个值得在第一次调用前读的平台坑）。\r\n\r\n**该选哪条?** 如果你的客户端原生支持 MCP，用 MCP —— Agent 少一层要学的东西。其它情况（Hermes、OpenClaw、自己写的脚本、CI 里直接 curl）继续用本包，它不会走。\r\n\r\n### 2. 🔒 加密静态 · 认证边界返明文（Encryption-at-rest, not E2E）\r\n\r\n每个账户的持仓数据在数据库中以 per-account 独立密钥密文存储。**这是防\"库泄露 / 平台 admin 跨账户读取\"的加密，不是 E2E 加密**：\r\n\r\n- **持有你 Bearer Token 的 Agent 通过 API 认证后，平台按调用者身份解密并返回明文** —— Token 是解密权的钥匙，保管好 Token 就是保管加密防线\r\n- 每个账户的加密密钥独立，平台管理员账号无法跨账户读取持仓明细（DB 层保证）\r\n- 订阅他人发布资产时，发布方看不到你的查询内容或账户信息（widget config 对订阅方 sanitize）\r\n- **给不可信 Agent 的 Token = 给它明文数据**。按 [§Scope](#scope--operator-responsibility) 授予最小 scope，不要 bundle 无关能力\r\n\r\n### 3. ⚡ Serverless 极速预警与零部署\r\n策略云端托管运行，无需您购买第三方行情 API，无需自建服务器维护 Cron 任务，无 Token 消耗税。策略触发后，毫秒级推送到您的飞书机器人或微信 Webhook。\r\n\r\n---\r\n\r\n## 🛠️ 能做什么\r\n\r\n| 核心功能 | 详细说明 |\r\n| :--- | :--- |\r\n| **资产盈亏巡航** | 一键查询持仓明细、当日盈亏、历史收益率，数据由 privora.cn 闭环处理。 |\r\n| **云端自动盯盘** | 设置预警条件（突破均线、涨跌幅、换手率等），触发即通知，7x24小时云端值守。 |\r\n| **多终端实时推送** | 策略触发毫秒级推送到飞书、微信 Webhook，不错过任何交易信号。 |\r\n| **行情数据** | 日线按市场段分别发布，均 🟢 生产可用：A 股（`stock_day`，沪深京 5500+ 股票 + 4 指数）、港股（`stock_day_hk`，如 `00700.HK`）、美股（`stock_day_us`，如 `AAPL`）；分钟 K 线：A 股（`stock_kline`）+ 港股（`stock_kline_hk`），1/5/15/30/60 分钟；基金日 NAV（`fund_day`）；场内基金（ETF/LOF）日线（`fund_quote_day`）+ 分钟 K 线（`fund_kline`，🟡 已建库尚未开放订阅）；SGE 黄金日线（`metal_day`）；财报事件（`stock_forecast` 业绩预告 + `stock_express` 业绩快报，11 年历史已回填）。详见下方「数据资产可用性」表。 |\r\n| **Python 策略回测** ✨ | 用平台日线数据跑单股 / 多股组合回测，输出 Sharpe / 最大回撤 / 交易明细 / equity curve；结果持久化到 `process_backtest_result`，可通过 `investment.stock.backtest.list` 检索历史审计记录（平台已积累 44+ 次持久化回测）。 |\r\n| **模拟交易 (Paper Trading)** ✨ | MARKET / LIMIT 两种委托类型，调度器驱动，模拟完整委托 → 成交 → 盈亏核算链路；账户按 `user_name` 唯一（DB-level UNIQUE），订单按 `(user_name, client_order_id)` 幂等，Agent 重复调用不重建。适合策略 6 阶段验证的最终纸面交易关卡。 |\r\n| **用户声音收集** | 支持 Agent 代客户提交 Bug 和需求，无缝对接后台反馈系统。 |\r\n\r\n### 数据资产可用性（2026-07-17 platform check）\r\n\r\n> **发布模型说明**：底层物理表按市场是合表存储的（同一张表可能物理上含多市场行），但**对外发布是按市场段分别发布为独立 DataAsset 的**。`stock_day` 段族现已全市场覆盖并各自独立上线：A 股段 = `stock_day`，港股段 = `stock_day_hk`，美股段 = `stock_day_us`；分钟 K 线段族同理：A 股段 = `stock_kline`，港股段 = `stock_kline_hk`。三段各自独立发布、独立 asset id，调用时请用下表的 assetName，不要假设同一 asset 覆盖多市场。\r\n\r\n| DataAsset | 状态 | 覆盖 | 频率 | 备注 |\r\n|---|---|---|---|---|\r\n| `stock_day` | 🟢 **生产可用** | **A 股（沪深京）5500+** 股票日线 + 4 主要指数（沪深300 `1B0300` / 上证综指 `1A0001` / 中证A500 `1B0510` / 深证成指 `399001`） | 日 | id=1；`000001` 等 A 股 ticker 自动路由（`segmentValues` SH/SZ/BJ）；`399001` 自 2026-03-17 起停更，请求会返回 `meta.benchmarkWarning` |\r\n| `stock_day_hk` | 🟢 **生产可用** | 港股日线（如 `00700.HK`） | 日 | id=204；数据新鲜（2026-07-16 校验通过） |\r\n| `stock_day_us` | 🟢 **生产可用** | 美股日线（如 `AAPL`） | 日 | id=206；由 `stock_day_us_backfill_to_mc` 任务从 PG 同步至 MC |\r\n| `stock_kline` | 🟢 **生产可用** | A 股 1/5/15/30/60 分钟 K 线（`interval_type` 区分周期） | 分钟 | id=202；日线 + 日内同步，由 `stock_kline_daily_sync` 等调度维护 |\r\n| `stock_kline_hk` | 🟢 **生产可用** | 港股 1/5/15/30/60 分钟 K 线 | 分钟 | id=207；与 `stock_kline` 同结构，段独立 |\r\n| `stock_minutes` | ⚪ **已弃用** | (旧) 分钟 K 线，已被 `stock_kline` / `stock_kline_hk` 取代 | — | id=154；仅历史兼容保留，新集成请改用 `stock_kline`/`stock_kline_hk` |\r\n| `fund_day` | 🟢 **生产可用** | 公募基金日 NAV | 日 (T+1) | 数据延迟约 1 个工作日；**长期回测/算收益率必须用 `adj_nav`（复权净值），不能用 `unit_nav`（会被拆分/分红污染，且约 49% 行 `adj_nav` 为 NULL）**——详见下方「`adj_nav` 缺失信号」一节 |\r\n| `fund_quote_day` | 🟡 **数据已就绪，尚未开放跨团队订阅** | 场内基金（ETF/LOF）价格日线；PG 单表不分区；`market` ∈ {ETF, LOF}——**与 `fund_day`/`fund_codes` 的 `{E,O}` 词表不同，跨表 join 只能用 `fund_code`**；`turnover` 是成交额（元），不是换手率 | 日 | `source` 分 `akshare_hist_em`（官方历史，`is_final=true`/`calibration_status='confirmed'`）与 `fund_realtime_t0`（当日 T+0 推导，`is_final=false`/`pending`）；两者交叉验证收盘价/成交量完全一致；详见下方「场内基金 K 线」一节 |\r\n| `fund_kline` | 🟡 **数据已就绪，尚未开放跨团队订阅** | 场内基金（ETF/LOF）分钟 K 线，`interval_type` ∈ {1m,5m,15m,30m,60m}（无 1d，日线见 `fund_quote_day`） | 分钟 | PG 原生 RANGE 分区表（按 `day_id`），**保留期仅 3 天**（非 MC 资产，不受 ODPS 分区自动注入影响）；`bar_time` 是 VARCHAR 不是 timestamp；`tick_count` 量化稀疏度；详见下方「场内基金 K 线」一节 |\r\n| `metal_day` | 🟢 **生产可用** | SGE 黄金 / 白银日线 | 日 | 上海黄金交易所 |\r\n| `stock_forecast` | 🟢 **生产可用** (NEW 2026-06-22) | A 股上市公司业绩预告；11 年历史 82,457 行已回填 | 日 | 财报季 (1/4/7/10 月底前后) 集中发布 |\r\n| `stock_express` | 🟢 **生产可用** (NEW 2026-06-22) | A 股上市公司业绩快报；11 年历史 19,945 行已回填 | 日 | 比业绩预告更精确但发布更稀疏 |\r\n| `stock_dividend` | 🟢 **生产可用** (NEW v1.0.32) | A 股上市公司现金分红事件；进入 `portfolio.attribution` 归因 | 事件驱动 | 除权除息日发布 |\r\n\r\n**对 Agent 的指导**：调用 `dataasset.list` 看完整列表；标 🔴 / ⚫ / ⚪ 的资产请避免在策略里硬编码依赖（⚪ = 已弃用，改用其后继 asset）。`dataasset.metadata.get` (2026-06-22 新上) 可查每张表的 `lastUpdated` / `expectedUpdateCadence` / `cronExpression` 来判断当前状态——**2026-09 起这个 scope 已在默认 `read-data` 预设里**，用默认预设建的 token 直接调即可，无需额外勾选。\r\n\r\n> 📌 本节是 **2026-07-17 的一次平台盘点快照**，随时间推移可能与实际覆盖漂移。各已发布资产的完整覆盖范围、分市场明细、更新频率与数据起始日期，见持续维护的公开清单页：[privora.cn/features/realtime-minute-data-coverage](https://privora.cn/features/realtime-minute-data-coverage)（按六类分组，含 A股/港股/美股/北交所分市场明细）。\r\n\r\n---\r\n\r\n## 🛡️ Scope 与操作者责任\r\n\r\n本 skill 是通过 Bearer Token 对接 Privora 平台的能力。操作类别的副作用不同，**操作者负责按类别 scope token 并为需要的类别加入确认门槛**：\r\n\r\n- **只读**（Read-only）—— 数据 API、回测结果查询、流程/调度/数据源/仪表盘/市场的 list/get。**平台状态零副作用**。\r\n- **幂等写**（Idempotent write）—— 模拟交易下单（DB 层 UNIQUE on `user_name` + `client_order_id`，同 key 重试返回同一记录）、marketplace subscribe（ON CONFLICT 返回已有订阅）、告警配置更新。**同输入多次调用只产生一次逻辑效果，可安全重试**。\r\n- **流程状态转移**（Workflow state transition）—— `process.ingestion.execute` 触发已授权 python_script 运行并写入 `process_backtest_result` 表；scheduler-instance 的 `redo / hold / resume / reset-priority` 转移 trigger row 状态。**每次调用创建或修改持久化记录**。\r\n- **确认门槛类**（Confirm-gated destructive/high-risk）—— 一小撮删除 / 撤销 / reset / 调度作业上下线操作 Bearer token **可达**，但单次调用永远不会直接执行——必须先完成两步确认握手，完整列表见下方 [§高风险操作确认握手](#高风险操作确认握手-confirm-handshake)。\r\n- **外发 webhook**（Outbound webhook）—— `schedule.job.plugin.webhook.trigger` 与告警评估路径向操作者配置的外部端点（飞书 / 微信 / 通用 webhook）发送通知。**副作用在 Privora 之外，平台不可撤销**。\r\n\r\n**本 skill 部分暴露**（其余需人在 platform UI 手动完成）：\r\n- 持久化记录的删除 / 撤销 / reset 操作 —— **一小撮**（流程删除、告警规则删除、team Python 模块删除、订阅 token 撤销、模拟盘账户 reset 等）经两步确认握手后可达，见上方「确认门槛类」；**多数**删除操作（如投资组合 / 交易记录删除）仍不在本 skill 范围内。\r\n- 调度器 online / offline 状态转移 —— `schedule.job.online` / `schedule.job.offline` **可达**，同样需要两步确认握手，见上方「确认门槛类」——这两个操作不是\"不暴露\"。\r\n- Webhook 插件生命周期变更（删除 / 禁用）—— `schedule.job.plugins.save`（详见下方作业插件小节，[§调度作业字段契约](#调度作业字段契约)）可全量替换一个作业绑定的插件列表（旧绑定先整体删除再写入新列表），**且不经确认握手**——传入的数组即视为该作业插件的完整期望状态，遗漏的既有绑定会被静默清空，不是增量操作。调用前请先 `schedule.job.plugins.list` 确认当前绑定，再拼出完整数组。\r\n- 管理员级账户操作 —— 不暴露，需通过 platform UI 完成。\r\n\r\n本 skill **不预先声明**任何操作是\"agent-safe\"——这个分类取决于操作者的风险偏好、agent 的可靠性、以及具体用例。**推荐姿势**：只读 + 幂等写允许 agent 自主调用；流程状态转移和外发 webhook 建议先经过用户确认门槛（约定俗成，非平台强制）；标记 `confirmRequired:true` 的高风险操作则由**平台强制**要求两步确认握手，不依赖操作者自律——但请注意上面「Webhook 插件生命周期变更」是**例外**：风险不低（全量替换、旧绑定先删），却不在 `confirmRequired` 名单内，调用前务必自行核实完整期望状态。\r\n\r\n### 📋 场景 → scope 速查表\r\n\r\n**新建 token 的默认 scope 就能取数**（2026-08-03 起）。点\"创建\"不改任何选项，你会得到\r\n`read-data` 这一组：\r\n\r\n```\r\ndataasset.list  dataasset.get  dataasset.schema.get  dataasset.metadata.get\r\ndataasset.data.get  dataasset.data.getRealtime  marketplace.item.list\r\n```\r\n\r\n需要别的能力时，按场景挑一组（token 创建页有同名的场景按钮，点一下即可全选）：\r\n\r\n| 场景 | preset id | scopes |\r\n|---|---|---|\r\n| 取行情 / 资产数据（**默认**） | `read-data` | `dataasset.list` `dataasset.get` `dataasset.schema.get` `dataasset.metadata.get` `dataasset.data.get` `dataasset.data.getRealtime` `marketplace.item.list` |\r\n| 读取数据 + 管理市场订阅（**含写权限**：订阅市场条目拿自己团队的 `clonedAssetId` 等；取消订阅会**删除**该团队克隆副本） | `subscribe-and-read` | `read-data` 全部 + `marketplace.item.subscribe` `marketplace.item.unsubscribe` |\r\n| 读仪表板 | `read-dashboard` | `read-data` 全部 + `dashboard.list` `dashboard.get` `dashboard.data.get` |\r\n| 触发并追踪流程 | `run-process` | `process.ingestion.list` `process.ingestion.get` `process.component.list` `process.ingestion.execute` `process.ingestion.execute.log.get` |\r\n| 配置指标告警（不含建通知通道） | `manage-alerts` | `metric.alert.list` `metric.alert.get` `metric.alert.create` `metric.alert.update` `metric.alert.toggle` `metric.alert.test` |\r\n| 实时告警（通道 + 规则，端到端） | `realtime-alerting` | `dataasset.{list,get,schema.get,metadata.get,data.get}` `datasource.list` `alert.channel.create` `plugin.webhook.send` `metric.alert.{list,get,create,update,patch,toggle,test,snooze,unsnooze,acknowledge}` |\r\n| 读写持仓与交易（**含写权限**） | `portfolio` | `investment.stock.portfolio.{list,create,update}` `investment.stock.trading.{list,create}` `investment.stock.watchlist.list` `investment.stock.signal.{list,get}` `investment.fund.portfolio.{list,create}` `investment.fund.trading.{list,create}` `investment.gold.portfolio.{list,create}` `investment.gold.trading.{list,create}` |\r\n\r\n**三个查询入口**（三处读的是同一份定义，不会互相打架）：\r\n\r\n| 你是谁 | 去哪查 |\r\n|---|---|\r\n| 人 | [privora.cn/profile/tokens](https://privora.cn/profile/tokens) 创建 token 时的场景按钮 |\r\n| Agent | `GET /agent/scope-presets` —— 返回 `{presets[], defaultScopes[], grantedScopes[]}`，每个 preset 带 `scopes[]`、`skillIds[]` 和 `satisfied`（当前 token 是否已满足） |\r\n| Agent | `GET /agent/skills` —— **全量**技能目录。每条带 `granted`（你现在能不能跑）、`scope`（需要哪个 scope）、`params` schema、`exampleInvocation`。跑不了的条目额外带 `presetsGrantingScope` |\r\n\r\n> `GET /agent/skills` 过去只返回你**已有** scope 的技能，所以 scope 不足时你根本看不到目标技能存在，\r\n> 只能靠猜 skillId。现在默认返回全量并用 `granted` 标注；要恢复旧行为传 `?granted=true`。\r\n\r\n**scope 不足时不用猜**：403 响应体直接给出 `requiredScope`、你当前的 `grantedScopes`、\r\n哪个 preset 含它（`presetsGrantingScope`）以及去哪改（`remediationUrl`）。\r\nskillId 写错时 400 响应体给 `didYouMean[]` 候选。\r\n\r\n**Token 使用建议**：\r\n\r\n1. 在 [privora.cn/profile/tokens](https://privora.cn/profile/tokens) 创建专用 Bearer Token\r\n2. **最小 scope 原则** —— 只授予当前 use case 需要的 scope。只读分析用默认的 `read-data` 就够；\r\n   要跑流程再加 `run-process`；agent 真的要下模拟单才加 `paper.*`（该命名空间由平台内部签发，\r\n   见下方\"模拟交易\"章节）。**不要为\"以防万一\"打包无关 scope**。\r\n3. 明确设置 `LG_AGENT_BASE_URL=https://privora.cn`\r\n4. **Token 泄露立即 rotate** —— Token Management 页面列出所有活跃 token 及最后使用时间戳和 revoke 按钮\r\n\r\n> 🛑 **绝对不要让你的 agent 代替你 mint token**。Token 创建是 operator 动作，不是 agent 动作。Agent 应该消费 operator 签发的 Bearer Token，**不应该**自己调 `POST /api/subscription/tokens`。\r\n\r\n### 📑 输出仅供分析参考，不构成投资建议\r\n\r\n本 skill 的输出（行情数据 / 组合分析 / 回测报告 / 模拟交易 / 告警评估）是**供操作者审查的分析结果**，不是投资建议、不是交易指令、也不能替代持牌财务咨询。\r\n\r\n- **把结果作为你自己决策过程的输入** —— 使用前请自行验证数据新鲜度、假设、边界情况\r\n- **实盘交易和不可逆的财务决策不应放在 agent 自动执行链路里** —— 模拟交易只是模拟；真钱交易必须走由操作者控制的券商链路并显式确认\r\n- **回测反映的是历史条件** —— 过去表现不预测未来结果。使用前请确认数据窗口、策略逻辑、以及生存偏差 / look-ahead 假设\r\n- **无监管咨询声明** —— 本平台是数据基础设施；下游任何投资决策由操作者本人（你）负责\r\n\r\n---\r\n\r\n## 🚀 快速接入 (Quick Start)\r\n\r\n### 0) ⚡ 30 秒试一下（不需要注册 / 不需要 Token）\r\n\r\n装完 skill 想立刻看看能干什么？**打开** [privora.cn/marketplace](https://privora.cn/marketplace)：\r\n\r\n- 无需登录，直接浏览公开挂牌的 A 股 / 港股 / 美股 / 黄金 / 基金 / 财报事件等数据资产\r\n- 想一眼看完**全部已发布资产**的覆盖范围 / 更新频率 / 数据起始日期，不用一个个点开？看公开清单页 [privora.cn/features/realtime-minute-data-coverage](https://privora.cn/features/realtime-minute-data-coverage)\r\n- 每个资产可以点进去看 25 行样本数据 + 20 字段元信息（`lastUpdated` / 数据源 / cron 表达式等）\r\n- 看到有价值的资产？**不要记这里显示的 numeric id**：那是发布方团队的 id，拿去调你自己的 Bearer Token 接口只会 404——订阅后你自己团队会拿到一份**全新数字 id** 的克隆资产，两者不是同一个数。**拿自己团队 id 最直接的办法**：走 §1 - §3 注册拿 Token——**`marketplace.item.subscribe` 不在默认 `read-data` 预设里**，预设场景按钮里只有 `subscribe-and-read` 带它，创建 token 时请选 `subscribe-and-read` 预设（或手动勾选 `marketplace.item.subscribe` / `marketplace.item.unsubscribe` 这两个 scope），用默认 `read-data` 预设建的 token 调这一步会 403——然后调 `marketplace.item.subscribe`（幂等——哪怕你之前已经订阅过，重复调用同一个 item 也照样成功），响应体里的 `clonedAssetId` 就是你自己团队里那份克隆资产的数字 id，直接拿去跑 §4 First Call Recipe（2 步 / 约 1 分钟）验证 Bearer Token 对同一资产能跑通。**兜底路径**：如果响应丢了这个字段、或你不想再调一次 subscribe，`dataasset.list` 里按 `tags` 含 `Subscribed` 也能扫到同一份克隆资产的 id\r\n- 觉得样本还不够？往下走 §1 - §4 注册生成 Bearer Token 拿完整访问权（分页 / 过滤 / 更高 rate limit / 写操作 / Agent 集成）\r\n\r\n**为什么先看再注册**：Privora 是投研工作流平台，\"你的数据是否值得订阅\"应该 30 秒能判断 —— 不需要注册墙。marketplace UI 是**发现工具**，Bearer Token 是**同一批数据的程序化访问入口**，两者对应关系明确。\r\n\r\n### 1) 获取您的专属 Token\r\n1. 注册并登录 [privora.cn](https://privora.cn)\r\n2. 在侧边栏点击你的用户名 → API Token Management，或直接访问 `https://privora.cn/profile/tokens`\r\n3. 创建一个仅包含所需 scopes 的专用 Token（建议先用只读或低权限 Token）\r\n4. 复制您的专属 `LG_AGENT_TOKEN`\r\n\r\n### 2) 为您的 Agent 配置环境变量\r\n在您使用的 Agent 终端（如 Hermes、Claude Code、GitHub Copilot 或 OpenClaw）中注入以下环境变量：\r\n```bash\r\nexport LG_AGENT_BASE_URL=\"https://privora.cn\"\r\nexport LG_AGENT_TOKEN=\"***\"\r\n```\r\n公开版主要走以上 Bearer Token 方式；如果 Agent 只是浏览 marketplace / 预览已发布看板 & 资产，也可以走**匿名模式**（不需要 token，见下方 [§🌐 匿名预览](#anonymous-preview)）。session cookie / CSRF 兼容调用不支持。\r\n\r\n### 3) 唤醒 Agent，开始对话\r\n现在，您可以直接用自然语言向您的 Agent 下达指令了！\r\n\r\n### 4) ⚠️ 做出你的第一次成功 API 调用（2 步走 + 1 步可选 / 避免最常见的 500 和 403）\r\n\r\n**最容易踩的坑**：URL 里的 `{id}` 必须是**数字型 asset ID**（如 `42`），**不是 asset 名字**（如 `fund_day` / `stock_day`）。传成名字后端 Spring 转 Long 失败会返回 500——错误信息不会明确告诉你原因。\r\n\r\n**正确的 recipe**（用默认 `read-data` 预设的 token 即可全部跑通）：\r\n\r\n```bash\r\n# Step 1: 先 list 拿数字 id ← 别跳过这步\r\ncurl -H \"Authorization: Bearer $LG_AGENT_TOKEN\" \\\r\n  https://privora.cn/api/data-assets | jq '.data[] | {id, assetName}'\r\n# 输出示例：\r\n# {\"id\": 42, \"assetName\": \"fund_day\"}\r\n# {\"id\": 8,  \"assetName\": \"stock_day\"}\r\n# {\"id\": 15, \"assetName\": \"stock_dividend\"}\r\n\r\n# Step 2: 用数字 id (不是 assetName!) 查实际数据\r\ncurl -H \"Authorization: Bearer $LG_AGENT_TOKEN\" \\\r\n  \"https://privora.cn/api/data-assets/42/data?page=1&size=10\"\r\n```\r\n\r\n**Step 1 返回 `[]`？** 这对刚注册、没有自有资产、也没有订阅任何 marketplace 条目的团队是预期结果，不是 bug——你的团队此时确实没有任何 `dataasset.list` 能看到的资产。见上方 [§0](#0-⚡-30-秒试一下不需要注册-不需要-token) 的 subscribe → `clonedAssetId` 路径：调 `marketplace.item.subscribe` 需要持有该 scope 的 token（预设场景按钮里只有 `subscribe-and-read` 带它，默认 `read-data` 预设没有），拿到 `clonedAssetId` 后回来重跑本节 Step 1，这时就能在列表里看到刚订阅的克隆资产了。\r\n\r\n**（可选）Step 3：查富元数据**——`GET /api/data-assets/{id}/metadata`（对应 skill `dataasset.metadata.get`）**2026-09 起已在** Token Management 页面 `read-data` 默认预设里，用默认预设建的 token 直接调即可：\r\n\r\n```bash\r\ncurl -H \"Authorization: Bearer $LG_AGENT_TOKEN\" \\\r\n  https://privora.cn/api/data-assets/42/metadata\r\n```\r\n\r\n**Agent 侧用 `lg_agent_exec.sh` 调用同理**（v1.0.45 起支持命名参数扁平写法，不用手拼 JSON）：\r\n\r\n```bash\r\nscripts/lg_agent_exec.sh dataasset.list\r\nscripts/lg_agent_exec.sh dataasset.data.get id=42 filter_column=stock_num filter_value=600519\r\n# scripts/lg_agent_exec.sh dataasset.metadata.get id=42  ← 可选；2026-09 起已在默认 read-data 预设里，直接跑即可\r\n```\r\n\r\n`id` **必须是数字**（先 `dataasset.list` 拿到再传，不是资产名字如 `fund_day`）。想看某个 skill 接受哪些 key，先 `scripts/lg_agent_list.sh describe dataasset.data.get` 看 schema + 示例，再照着填。\r\n\r\n**如果你已经踩到 500**：不用改代码逻辑，只需把 `{name}` 换成对应的数字 id 即可。数据资产的可用列表见下方「[数据资产可用性](#数据资产可用性2026-06-22-audit--triage-t-1)」表 —— 那里的名字对应 `dataasset.list` 返回的 `assetName` 字段，需要先 list 拿到本 team 里对应的数字 id。\r\n\r\n---\r\n\r\n<a name=\"anonymous-preview\"></a>\r\n## 🌐 匿名预览（无 token）\r\n\r\n如果 Agent 只是想**浏览 marketplace 或预览已发布的看板/数据资产/流程**——比如帮用户看看 Privora 有什么数据源、有哪些现成看板可订阅、某个流程做什么用——**不需要 Bearer Token 也能直接跑**。这条通路和 [privora.cn/marketplace](https://privora.cn/marketplace) 页面上未登录访客看到的内容是**同一套数据**，只是把它变成 machine-readable 的 skill 调用。\r\n\r\n### 什么时候用\r\n\r\n- 用户还没注册，Agent 想先展示\"这平台上有啥\"\r\n- 用户已注册但当前 session 没配 token，你想让 Agent 先给个 marketplace 摘要\r\n- Agent 在做 discovery / recommendation，不需要写权限、也不涉及用户私有数据\r\n\r\n### 怎么用\r\n\r\n**留空 `LG_AGENT_TOKEN` 或直接不传 `Authorization` header** 即可：\r\n\r\n```bash\r\n# 无 token 调用 —— 直接返回 mode:\"anonymous\" + 10 个可用 skill\r\ncurl https://privora.cn/agent/skills\r\n\r\n# 无 token 拿 marketplace 列表\r\n# Windows Git Bash 提醒：curl.exe 是原生 Windows 程序，MSYS2 会按本地 ANSI 代码页重编码命令行参数，\r\n# 如果把下面的 body 换成含中文/非 ASCII 的内容（如搜索关键字），-d '...' 会被静默改坏——改用 --data-binary @file。\r\nprintf '%s' '{\"skillId\":\"marketplace.item.list\"}' > /tmp/lg_body.json\r\ncurl -X POST https://privora.cn/agent/skills/execute \\\r\n  -H \"Content-Type: application/json\" \\\r\n  --data-binary @/tmp/lg_body.json\r\n\r\n# 无 token 拿某个已发布看板的 widget 数据（同上：非 ASCII 内容一律 --data-binary @file，不要用 -d）\r\nprintf '%s' '{\"skillId\":\"dashboard.data.get\",\"params\":{\"pathParams\":{\"id\":\"<published-dashboard-uuid>\"}}}' > /tmp/lg_body.json\r\ncurl -X POST https://privora.cn/agent/skills/execute \\\r\n  -H \"Content-Type: application/json\" \\\r\n  --data-binary @/tmp/lg_body.json\r\n```\r\n\r\n响应体的 `mode` 字段会明确标 `\"anonymous\"`，`grantedScopes` 列出下方 10 个允许的 skill。\r\n\r\n### 匿名模式可用的 skill（全部只读）\r\n\r\n| skillId | 用途 |\r\n|---|---|\r\n| `marketplace.item.list` | 列出所有可订阅的 marketplace 条目（看板 / 资产 / 流程）—— **discovery 入口** |\r\n| `dashboard.get` | 按 id 拿某个已发布看板的元数据 + widget 定义 |\r\n| `dashboard.data.get` | 一次拿某个已发布看板所有 widget 的数据 |\r\n| `dataasset.get` | 拿某个 `allowSubscription=true` 资产的详情 |\r\n| `dataasset.schema.get` | 拿该资产的列 schema |\r\n| `dataasset.metadata.get` | 拿该资产的富元数据（`lastUpdated` / `expectedUpdateCadence` / cron / 数据源描述等 20 字段）|\r\n| `dataasset.data.get` | 拿该资产的历史数据（预览有效范围内）|\r\n| `dataasset.data.getRealtime` | 拿该资产的实时镜像数据（若配置了 realtime mirror）|\r\n| `process.ingestion.get` | 拿某个 `allowSubscription=true` 流程的结构（**不含 stepCfg 源码**）|\r\n| `process.component.list` | 列平台可用的步骤组件类型（rendering diagram preview 用）|\r\n\r\n### 硬性约束\r\n\r\n- **只读白名单**：**仅上表 10 个 skill** 可调，其余 skill（包括其它只读 GET，如 `investment.stock.portfolio.list` / `dashboard.list` / `dataasset.list`）无论是否存在都返回 403 `missing-scope`。任何写操作（subscribe / create / update / delete）同样 403；哪怕手工构造匿名 PUT/POST 到底层 `/api/**`，Node 代理层也会先 401 拦截，不会到 Spring。\r\n- **每 IP 限流（三桶，任一超限即 429）**：\r\n\r\n  | 桶 | 范围 | 限额 | 429 响应体 |\r\n  |---|---|---|---|\r\n  | 通用桶 | 所有匿名 skill | 60 / IP / 分钟 | `{\"success\":false, \"message\":\"Too many anonymous agent requests, ...\"}` (无 `bucket` 字段) |\r\n  | 数据爆发桶 | `dataasset.data.get` + `dataasset.data.getRealtime` | 10 / IP / 分钟 | `{\"success\":false, \"traceId\":\"...\", \"message\":\"Anonymous data-fetch burst-limit exhausted (10/min per IP). ...\", \"bucket\":\"burst\"}` |\r\n  | 数据日总桶 | 同上 | 100 / IP / 天 | `{\"success\":false, \"traceId\":\"...\", \"message\":\"Anonymous data-fetch daily budget exhausted (100/day per IP). ...\", \"bucket\":\"daily\"}` |\r\n\r\n  收到 429 时读 `response.body.bucket` 判断：`\"burst\"` 等 60 秒重试；`\"daily\"` 今日不再放行该 skill，建议引导用户注册 Bearer Token；无 `bucket` 字段则是通用 60/min 桶命中。\r\n\r\n  **Rate-limit 存储：** v1.0.37 起三桶都存 Redis sorted sets (`anonratelimit:{burst,daily,general}:<ip>`)，通过 Lua 原子脚本实现 sliding window。fleet 内所有 Node worker + 所有 host 共享一份 counter，反爬承诺**真的**成立。**Redis 不可用时 fail-open**：静默放行 + ERROR 日志 `event:\"rate-limit-redis-fail\"`，反爬承诺仅在 Redis 健康时有效（运维监控 fail-open 日志识别异常）。\r\n- **preview token 服务端自动签**：不用你手工去 `/preview-token` 拿；Node 按 skill 类型选：dashboard 类（`dashboard.get` / `dashboard.data.get`）**要求调用方在 `params.pathParams.id` 里传目标看板 id**，Node 会用该 id 签 dashboardId-bound token；未传 id 或其它 skill 一律降级为 `standalone` sentinel（等同 dataasset 类行为）。\r\n- **无效 Bearer 不降级**：如果传了 `Authorization: Bearer <bogus>`，返回 401 而**不会**悄悄退回匿名模式给你部分数据。要匿名就别传 header。\r\n- **无跨租户 leak**：所有资产读都走 `canReadAsset` gate；只有 `allowSubscription=true` 的资产/看板/流程会被返回，其它一律 404。跟浏览器 `/marketplace` 未登录访客看到的是同一套子集。\r\n- **Dashboard-scoped token 不能跨团枚举**：dashboard-A（发布者 = team-A）签的 preview token 无法通过 `dataasset.metadata.get` 读到 team-B 的资产元信息，哪怕 team-B 资产 `allowSubscription=true`。仅 `standalone` sentinel token 可读所有公开挂牌资产。\r\n\r\n### 匿名模式下的**能力受限**（订阅后才解锁）\r\n\r\n数据获取类 skill（`dataasset.data.get` / `dataasset.data.getRealtime` / `dataasset.get` / `dataasset.metadata.get` / `process.ingestion.get`）在匿名模式下**服务端会自动应用以下约束**，参数会被静默改写或剥离——不是 400，你的 curl 依然能正常拿到响应，但拿到的不是你请求的形状：\r\n\r\n- **分页强制固定 `page=1, size=25`**：传任何其他值都被服务端硬覆盖。响应 `pageSize=25, currentPage=1`。想拿更多请订阅后用 Bearer Token 调。\r\n- **过滤 / 排序参数被静默清空**：`filterColumn / filterValue / filterOp / orderBy / orderDirection` 一律置 `null` 再进服务层。想按条件过滤请订阅后再来。\r\n- **发布者身份字段被剥离**（`dataasset.get`）：`dataSource / realtimeDataSource / businessOwner / technicalOwner / teamName / jobCode / createdBy / createdDate / updatedBy / updatedDate` 一律返回 `null`。Metadata map 中 `teamName / dataSource / jobCode / createdBy / createdDate / ...","readmeExcerpt":"Skill: Privora · A股/港股/黄金/基金 多资产 量化分析 · 量化回测 · 模拟盘 · 实时告警 · 风险监控 · Python 策略 · AI Agent Owner: guangfuwu Summary: Privora · AI Agent 投资工作流平台 — Bearer Token 即接入 /agent/skills/execute 通用 dispatcher，覆盖 A 股/港股/美股/黄金/基金/财报数据 + Python 回测（含 sandbox）+ 模拟交易 + 组合归因（α/β TWR）+ 云端告警 + 流程编排。Hermes / Claude / GPT / OpenClaw 全兼容。 Tags: latest:1.0.57 Version history: v1.0.57 | 2026-09-21T09:28:02.096Z | user v1.0.57 · 2026-09-18 Host","codeSnippets":[],"executableExamples":[],"parameters":null,"dependencies":[],"permissions":[],"extractedFiles":[{"path":"SKILL.md","content":"---\r\nname: Privora · 数据驱动投资工作流平台 for AI Agents\r\ntitle: 🔬 Privora · AI Agent 投资工作流平台（A股/港股/美股/黄金/基金/财报数据 + Python 回测 + 模拟交易 + 组合归因 + 云端告警 + 流程编排）\r\nversion: 1.0.57\r\nupdatedAt: 2026-09-18\r\nkeywords:\r\n  - A股\r\n  - 港股\r\n  - 美股\r\n  - 基金\r\n  - 黄金\r\n  - 财报数据\r\n  - 业绩预告\r\n  - 现金分红\r\n  - 分钟K线\r\n  - K线\r\n  - 实时行情\r\n  - 量化回测\r\n  - 策略沙盒\r\n  - Python回测\r\n  - A股模拟盘\r\n  - 模拟交易\r\n  - 持仓监控\r\n  - 组合归因\r\n  - 净值曲线\r\n  - AI Agent\r\n  - MCP\r\n  - MCP Server\r\n  - Claude Code\r\n  - Codex\r\n  - Cursor\r\n  - 数据后端\r\n  - 股票\r\n  - 告警\r\n  - 数据新鲜度\r\ndescription: Privora · AI Agent 投资工作流平台 — Bearer Token 即接入 /agent/skills/execute 通用 dispatcher，覆盖 A 股/港股/美股/黄金/基金/财报数据 + Python 回测（含 sandbox）+ 模拟交易 + 组合归因（α/β TWR）+ 云端告警 + 流程编排。Hermes / Claude / GPT / OpenClaw 全兼容。\r\nlicense: MIT-0\r\nmetadata:\r\n  {\r\n    \"openclaw\": {\r\n      \"emoji\": \"📈\",\r\n      \"requires\": {\r\n        \"env\": [\"LG_AGENT_BASE_URL\", \"LG_AGENT_TOKEN\"]\r\n      }\r\n    }\r\n  }\r\n---\r\n\r\n# Privora · AI Agent 投资工作流平台（Bearer Token 即接入 · A股/港股/美股/黄金/基金 数据 + 回测 + 模拟交易 + 告警 + 流程编排）\r\n\r\n**给你的 AI Agent 一个统一的投资研究工作流后端 —— 数据查询 + 策略回测 + 组合归因 + 云端告警 + 流程编排一个 Token 全覆盖。**\r\n\r\nHermes / Claude / GPT / OpenClaw 任何 Agent，通过一个 Bearer Token 即可访问：\r\n\r\n- 📊 **多资产数据（按市场段分别发布，均 🟢 生产可用）**：**日线** A 股 5500+ 股票（`stock_day`，含沪深300 / 上证综指 / 中证A500 / 深证成指 4 主要指数）+ 港股（`stock_day_hk`，如 `00700.HK`）+ 美股（`stock_day_us`，如 `AAPL`）；**分钟 K 线** A 股（`stock_kline`）+ 港股（`stock_kline_hk`），1/5/15/30/60 分钟；**持仓**、**黄金**、**基金**、**财报事件**（业绩预告 / 快报）——一个 API 全覆盖，详见下方「数据资产可用性」表。场内基金（ETF/LOF）日线（`fund_quote_day`）+ 分钟 K 线（`fund_kline`）表已就绪（🟡 尚未开放跨团队订阅，见下方表格）。\r\n- 🔔 **7×24 云端监控**：Serverless 策略托管，飞书 / 微信毫秒级预警，零服务器运维\r\n- 🧪 **Python 策略回测**：用同一份平台数据跑回测，输出 Sharpe / 最大回撤 / 交易明细\r\n- 🔒 **加密静态、认证边界返明文**：持仓数据在数据库中以 per-account 独立密钥密文存储（防 DB 层泄露 + 平台 admin 跨账户读取）；**持有你 Bearer Token 的 Agent 通过 API 认证后，平台按调用者身份解密并返回明文** —— 这不是 E2E 加密，Token 授权即数据访问权。\r\n- 🎯 **1-click subscribe→alert**：Agent 帮用户从\"订阅 dashboard\"到\"配置 alert 上线\"降到 1 step (2026-06-05 新增)\r\n- 🧾 **模拟交易 (Paper Trading)**：MARKET / LIMIT 委托类型 + 调度器驱动 + 真实涨跌停 / 停牌信号，账户 + 订单 DB-level 幂等。\r\n\r\n> **让普通人也能拥有私募级别的工作流**——不需要私募的预算，就能像私募研究员一样在同一条流水线里跑数据 + 分析 + Agent + 告警。\r\n\r\n🆕 **版本与变更历史**：当前版本号以文件头 frontmatter 的 `version:` 字段为准，正文不重复这个数字；每次发布的完整变更说明见仓库内 [`CHANGELOG.md`](./CHANGELOG.md)，随包分发的历史摘要见文末 [§最近更新](#最近更新)。\r\n\r\n🎯 **最适合**：想把整个投研工作流（数据查询 + 回测 + 模拟交易 + 告警 + 流程编排）交给 AI Agent 自动化的散户 / 小工作室；把 Hermes / Claude / GPT / OpenClaw 当量化助手用的开发者。**注意**：Bearer Token 是\"工作流授权凭证\"，不只是\"数据 API key\" —— 授予前先按 [§Scope](#scope--operator-responsibility) 分类明白**要给 Agent 哪些能力**。\r\n\r\n🌐 **产品主页**：[https://privora.cn](https://privora.cn) · 注册即拿 Token\r\n\r\n![演示](./lg-data-demo.gif)\r\n\r\n---\r\n\r\n## 🌟 核心亮点\r\n\r\n### 1. 🤖 兼容所有主流通用 AI Agent\r\n打破生态壁垒，本技能不仅专供某一平台，而是**完美兼容 Hermes、OpenClaw、Claude Code、GitHub Copilot 等所有支持外挂工具/技能的通用大模型 Agent**。只需简单配置环境变量，您的通用 AI 助手瞬间化身专业量化分析师。\r\n\r\n#### 🔌 用 MCP 客户端？有原生通道，两条并存\r\n\r\n如果你的 Agent 是 **Codex CLI / Claude Code / Cursor / Windsurf / Cline**，除了本包的环境变量 + 脚本方式，还有一个**原生 MCP** 通道:一个 stdio MCP server，把同一个 dispatcher 直接暴露成 `tools/list` / `tools/call` 工具，你的 Agent 不必再学 shell 脚本的调用形状。\r\n\r\n**两条通道并"},{"path":"_meta.json","content":"{\n  \"ownerId\": \"kn74934h6ss8z6cng1bphdygvs83xrs8\",\n  \"slug\": \"privora-cn-quant\",\n  \"version\": \"1.0.57\",\n  \"publishedAt\": 1789982882096\n}"},{"path":"skill-card.md","content":"## Description:\n\nPrivora connects AI agents to a bearer-token investment workflow platform for A-share, Hong Kong, U.S., gold, fund, and financial-event data, plus Python backtesting, paper trading, portfolio attribution, cloud alerts, and workflow orchestration.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[guangfuwu](https://clawhub.ai/user/guangfuwu)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nExternal users, developers, and AI-agent operators use this skill to query market and portfolio data, run quantitative analysis and backtests, manage simulated trading workflows, and configure alerts through a Privora-issued bearer token.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: The skill can give an agent broad Privora platform authority, including persistent remote changes.\n\nMitigation: Install it with a dedicated least-privilege Privora token, start with read-only scopes, and add write scopes only for a specific workflow.\n\nRisk: Some scheduler, dependency, and plugin operations can replace persistent state and may not have enforced confirmation.\n\nMitigation: List current scheduler dependencies and plugin bindings first, then submit the complete intended state after operator review.\n\nRisk: A bearer token grants access to the data and capabilities in its scopes, including sensitive portfolio data when those scopes are granted.\n\nMitigation: Treat the token as a secret, avoid giving it to untrusted agents, rotate it after exposure, and avoid wildcard or unrelated scopes.\n\nRisk: Analysis, backtest, alert, and simulated-trading outputs can be incomplete, stale, or misleading if used without review.\n\nMitigation: Verify data freshness, strategy assumptions, and scope of results before acting; do not treat outputs as investment advice or live trading instructions.\n\n## Reference(s):\n\n- [ClawHub Skill Page](https://clawhub.ai/guangfuwu/skills/privora-cn-quant)\n- [Privora Product Homepage](https://privora.cn)\n- [Privora Data Coverage](https://privora.cn/features/realtime-minute-data-coverage)\n- [Privora Token Management](https://privora.cn/profile/tokens)\n- [Privora Marketplace](https://privora.cn/marketplace)\n\n## Skill Output:\n\n**Output Type(s):** [Text, Markdown, Code, Shell commands, Configuration, Guidance]\n\n**Output Format:** [Markdown guidance with shell command examples and JSON API responses]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [Requires LG_AGENT_BASE_URL and LG_AGENT_TOKEN; available actions depend on the scopes granted to the Privora bearer token.]\n\n## Skill Version(s):\n\n1.0.57 (source: server release metadata and SKILL.md frontmatter)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment."}],"languages":[],"docsSourceLabel":"CLAWHUB","editorialOverview":null,"editorialQuality":{"score":100,"threshold":65,"status":"thin","wordCount":3136,"uniquenessScore":41,"reasons":["uniqueness-below-45"]}},"media":{"evidence":{"source":"no-media","verified":false,"confidence":"low","updatedAt":"2026-10-09T06:16:00.576Z","emptyReason":"No screenshots, media assets, or demo links are available."},"primaryImageUrl":null,"mediaAssetCount":0,"assets":[],"demoUrl":null},"ownerResources":{"evidence":{"source":"unclaimed","verified":false,"confidence":"low","updatedAt":"2026-10-09T06:16:00.576Z","emptyReason":"This page has not been claimed by the agent owner."},"hasCustomPage":false,"customPageUpdatedAt":null,"customLinks":[],"structuredLinks":{"docsUrl":null,"demoUrl":null,"supportUrl":null,"pricingUrl":null,"statusUrl":null},"customPage":null},"relatedAgents":{"evidence":{"source":"protocol-neighbors","verified":false,"confidence":"medium","updatedAt":"2026-10-09T22:12:16.137Z","emptyReason":null},"items":[{"id":"8ebccd8e-3863-4187-8355-c3f14e1f9edf","entityType":"agent","canonicalPath":"/agent/iofficeai-aionui","slug":"iofficeai-aionui","name":"AionUi","description":"Free, local, open-source 24/7 Cowork app and OpenClaw for Gemini CLI, Claude Code, Codex, OpenCode, Qwen Code, Goose CLI, Auggie, and more | 🌟 Star if you like it!","url":"https://github.com/iOfficeAI/AionUi","homepage":"https://www.aionui.com","source":"GITHUB_REPOS","protocols":["MCP","OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-10-09T19:11:12.944Z","createdAt":"2026-02-25T03:38:16.584Z","downloads":null},{"id":"b917f68a-ebff-438e-84f8-3f4b2494c0bc","entityType":"agent","canonicalPath":"/agent/activepieces-activepieces","slug":"activepieces-activepieces","name":"activepieces","description":"AI Agents & MCPs & AI Workflow Automation • (~400 MCP servers for AI agents) • AI Automation / AI Agent with MCPs • AI Workflows & AI Agents • MCPs for AI Agents","url":"https://github.com/activepieces/activepieces","homepage":"https://www.activepieces.com","source":"GITHUB_REPOS","protocols":["OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-04-15T02:22:12.426Z","createdAt":"2026-02-25T03:38:12.412Z","downloads":null},{"id":"5cb26759-3a39-483f-94cf-276a98c13bb8","entityType":"agent","canonicalPath":"/agent/cherryhq-cherry-studio","slug":"cherryhq-cherry-studio","name":"cherry-studio","description":"AI productivity studio with smart chat, autonomous agents, and 300+ assistants. Unified access to frontier LLMs","url":"https://github.com/CherryHQ/cherry-studio","homepage":"https://cherry-ai.com","source":"GITHUB_REPOS","protocols":["MCP","OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-04-11T14:38:40.986Z","createdAt":"2026-02-25T03:38:19.379Z","downloads":null},{"id":"6f6582d0-5d76-4f0f-b81d-86520247950b","entityType":"agent","canonicalPath":"/agent/copilotkit-copilotkit","slug":"copilotkit-copilotkit","name":"CopilotKit","description":"The Frontend for Agents & Generative UI. React + Angular","url":"https://github.com/CopilotKit/CopilotKit","homepage":"https://docs.copilotkit.ai","source":"GITHUB_REPOS","protocols":["OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-03-25T09:50:57.846Z","createdAt":"2026-02-25T03:39:14.617Z","downloads":null}],"links":{"hub":"/agent","source":"/agent/source/clawhub","protocols":[{"label":"OpenClaw","href":"/agent/protocol/openclew"}]}}}