
Gangtise Copilot
- 474 installs
- 1.3k repo stars
- Updated August 4, 2026
- daymade/claude-code-skills
gangtise-copilot is a Claude Code skill that helps developers build Gangtise-aware copilots pulling market, company, and research signals into analyst workflows and automated finance briefings.
About
gangtise-copilot is a Claude Code skill for constructing finance copilots grounded in Gangtise market, company, and research data. It guides developers embedding those signals into analyst workflows, scheduled briefings, or internal chat agents that answer sector and issuer questions with sourced context. Engineers reach for gangtise-copilot when prototyping institutional research assistants, automating morning market summaries, or wiring proprietary terminals into agent toolchains. The skill assumes familiarity with Gangtise as a data source and focuses on copilot architecture rather than generic LLM prompting.
- Gangtise data source integration patterns
- Tool schemas for market and company queries
- Retrieval and citation guardrails
- Multi-step analyst workflow orchestration
- Compliance-aware prompt and output framing
Gangtise Copilot by the numbers
- 474 all-time installs (skills.sh)
- Ranked #1,835 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/daymade/claude-code-skills --skill gangtise-copilotAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 474 |
|---|---|
| repo stars | ★ 1.3k |
| Last updated | August 4, 2026 |
| Repository | daymade/claude-code-skills ↗ |
How do you build a finance copilot with market data?
Build a Gangtise-aware copilot that pulls market, company, and research signals into analyst workflows, automated briefings, or internal finance chat agents.
Who is it for?
Developers building internal finance or equity-research agents that must surface Gangtise market, company, and research signals on demand.
Skip if: General-purpose chatbots without a Gangtise data subscription or teams that only need public web scraping for market quotes.
When should I use this skill?
A user asks to build a Gangtise copilot, finance briefing agent, or market-research chat integration using Gangtise signals.
What you get
Gangtise-aware agent workflows, briefing pipelines, and finance chat integrations with market and research context.
- finance copilot workflow
- briefing automation
- agent integration plan
Files
Gangtise Copilot
One-command installer, credential configurator, and diagnostic layer for the full Gangtise (岗底斯投研) OpenAPI skill suite.
---
🚀 One-shot installation (complete flow)
This is the only section you need to read to go from zero to fully working Gangtise. Follow steps in order.
Step 1 — Download this skill to your agent's skills directory
Primary method (git clone):
git clone --depth 1 https://github.com/daymade/claude-code-skills.git /tmp/gangtise-repo
cp -r /tmp/gangtise-repo/gangtise-copilot <your-agent-skills-dir>/Fallback method (when git clone times out or is unavailable — use GitHub API directly):
# Python one-liner to download and write any file from GitHub:
import urllib.request, json, base64, os
def fetch_github_file(repo_path, local_path):
url = f"https://api.github.com/repos/daymade/claude-code-skills/contents/{repo_path}"
req = urllib.request.Request(url, headers={"User-Agent": "Mozilla/5.0"})
d = json.loads(urllib.request.urlopen(req, timeout=20).read())
content = base64.b64decode(d["content"]).decode("utf-8")
os.makedirs(os.path.dirname(local_path), exist_ok=True)
open(local_path, "w").write(content)
return len(content)
# Download all files:
for path, local in [
("gangtise-copilot/SKILL.md", "<skills-dir>/gangtise-copilot/SKILL.md"),
("gangtise-copilot/scripts/install_gangtise.sh", "<skills-dir>/gangtise-copilot/scripts/install_gangtise.sh"),
("gangtise-copilot/scripts/configure_auth.sh", "<skills-dir>/gangtise-copilot/scripts/configure_auth.sh"),
("gangtise-copilot/scripts/diagnose.sh", "<skills-dir>/gangtise-copilot/scripts/diagnose.sh"),
("gangtise-copilot/references/installation_flow.md", "<skills-dir>/gangtise-copilot/references/installation_flow.md"),
("gangtise-copilot/references/credentials_setup.md", "<skills-dir>/gangtise-copilot/references/credentials_setup.md"),
("gangtise-copilot/references/skill_registry.md", "<skills-dir>/gangtise-copilot/references/skill_registry.md"),
("gangtise-copilot/references/known_issues.md", "<skills-dir>/gangtise-copilot/references/known_issues.md"),
("gangtise-copilot/references/best_practices.md", "<skills-dir>/gangtise-copilot/references/best_practices.md"),
("gangtise-copilot/config-template/authorization.json.example", "<skills-dir>/gangtise-copilot/config-template/authorization.json.example"),
]:
size = fetch_github_file(path, local)
print(f"OK {path} → {local} ({size} bytes)")Important: Network to GitHub may be unstable. If any file fails, retry the specific file up to 3 times with a 2-second delay between attempts. Do NOT abort the whole process for a single file failure.
Step 2 — Register this skill with your agent
For OpenClaw: create a symlink in the agent's skills directory and enable it in gateway config:
# Find the OpenClaw skills directory
ls ~/workspace/agent/skills/ # or ls ~/.openclaw/skills/
# Symlink this skill
ln -sf <gangtise-copilot-source-dir> <openclaw-skills-dir>/gangtise-copilot
# Enable in OpenClaw gateway config (if the agent supports skill entries in config)
# Run: openclaw config set 'skills.entries.gangtise-copilot' '{}'
# Then restart the gateway: sh scripts/restart.shStep 3 — Install all 19 Gangtise official skills
bash <gangtise-copilot-dir>/scripts/install_gangtise.sh --preset fullWhat it does: Downloads 4 ZIP bundles from the official Huawei Cloud OBS bucket, extracts 19 skill directories, and symlinks them into detected agent skills directories (~/.openclaw/skills/, ~/.claude/skills/, etc.).
Known agent skills directory paths (if auto-detection misses yours):
| Agent | Skills directory |
|---|---|
| Claude Code | ~/.claude/skills/ |
| Codex | ~/.agents/skills/ |
| OpenClaw | ~/.openclaw/skills/ or <agent-workspace>/skills/ |
If install fails, check references/installation_flow.md.
Step 4 — Configure credentials
bash <gangtise-copilot-dir>/scripts/configure_auth.sh \
--access-key <your-accessKey> \
--secret-key <your-secretAccessKey>What it does: 1. Writes ~/.config/gangtise/authorization.json (mode 600) 2. Performs live auth call to verify credentials work 3. Writes ~/.GTS_AUTHORIZATION runtime token 4. Creates symlinks from every installed skill's scripts/.authorization to the shared credential file
⚠️ Critical: After Step 3,diagnose.shmay report "19 skill(s) missing .authorization" even if credentials exist. Run Step 4 even when~/.config/gangtise/authorization.jsonalready exists —configure_auth.shcreates the missing symlinks.
Step 5 — Verify installation
bash <gangtise-copilot-dir>/scripts/diagnose.shExpected output: 9 pass ✅, 0 fail ❌ — all 19 skills present, credentials valid, RAG reachable.
If any ❌ or ⚠️ remains, cross-reference with references/known_issues.md.
Step 6 — Test with a real query
# Example: query latest research report for 宁德时代
# Use gangtise-file-client with its report runner:
cd <gangtise-copilot-dir>/references/
# See skill_registry.md for the exact command per skill---
Overview
Gangtise is a Chinese professional investment-research data platform. It publishes an OpenAPI that covers research reports, company announcements, meeting summaries, chief analyst opinions, financial statements, valuation metrics, OHLC market data, shareholder data, industry indicators, and a catalog of pre-built research workflow skills. The underlying API is well-designed, but the skill ecosystem is not discoverable: there is no public manifest listing the 19 skills, the skills are distributed as independent ZIP files on a Huawei Cloud OBS bucket with listing permission disabled, and the skills live in two parallel naming conventions (gangtise-<name> for the minimal line, gangtise-<name>-client for the full-capability line) that carry different feature sets. A first-time user has to reverse-engineer the complete skill inventory before they can install it.
Gangtise Copilot solves this in one command:
1. Installs all 19 official Gangtise skills to Claude Code, OpenClaw, and Codex via a single bundled-download + distribute pipeline. 2. Walks the user through accessKey + secretAccessKey setup with a live authentication call against open.gangtise.com/application/auth/oauth/open/loginV2. 3. Provides a read-only diagnostic script that reports which skills are installed, which credentials are valid, and which capability tiers are reachable. 4. Exposes preset install modes (minimal / workshop / full) so users can match the install size to what their account license actually permits — see ISSUE-007 in references/known_issues.md for why "biggest install" is not the safe default.
Runtime note from April 2026 usage: after installing skills, run configure_auth.sh even if ~/.config/gangtise/authorization.json already exists. Upstream CLI scripts also read ~/.GTS_AUTHORIZATION, a bare runtime token file. The configurator refreshes both files.
Architectural principles (do not violate)
This skill is a wrapper layer around the Gangtise OpenAPI skill suite. The wrapper contract is non-negotiable:
- Never vendor upstream files. This skill directory contains no copy, fork, or excerpt of any Gangtise skill content. When Gangtise ships a new release, users get the new release without any interference from this wrapper — the installer re-downloads from the canonical OBS URL every run.
- Repairs (if any arise) happen at runtime, not at ship time. This wrapper was distilled from a session that encountered no actual upstream bugs — the friction was discoverability and install orchestration, not broken files. If future upstream bugs arise, they will be added to
references/known_issues.mdwith runtime repair instructions, not patched at ship time. - Always ask before touching upstream files. Modifying any installed
gangtise-*skill directory requires explicit user consent via AskUserQuestion. - Teach rather than hide. Every installation step shows the user exactly which skills were downloaded, from where, and where the credential file was saved. This is how users learn to maintain their own installs.
What this skill does
| Capability | Entry point | Detail |
|---|---|---|
1. Install Gangtise skills (minimal default, workshop alias, full, or --only custom) | scripts/install_gangtise.sh | See references/installation_flow.md |
| 2. Configure accessKey + secretAccessKey credentials | scripts/configure_auth.sh | See references/credentials_setup.md |
| 3. Diagnose install state, credential validity, and capability tiers | scripts/diagnose.sh | See references/known_issues.md |
| 4. Look up which Gangtise skill answers a specific data question | Skill registry below + references/skill_registry.md | — |
Routing
When this skill is triggered, classify the user's intent and jump to the corresponding capability:
| User says something like… | Go to |
|---|---|
| "装 gangtise"、"install gangtise"、"我想用 gangtise 的数据"、"把 gangtise 的 skill 都装上" | One-shot installation (Step 1–5 above) |
| "配 gangtise 的 key"、"configure gangtise credentials"、"gangtise accessKey"、"secretAccessKey" | Capability 2 |
| "gangtise 报错"、"token is invalid"、"接口地址错误"、"gangtise skill 加载失败"、"我的 gangtise 装得不对" | Capability 3 |
| "宁德时代的研报"、"过去 30 天的首席观点"、"OHLC 蜡烛图"、"个股研究报告 L2"、"对宁德时代做观点 PK" | Capability 4 → skill registry → invoke the matching upstream skill |
| "帮我从头跑一遍 gangtise" | One-shot installation (Step 1–5 in sequence) |
When in doubt, start with Capability 3 (diagnose.sh) — it is the only read-only entry point and it surfaces exactly which installs and credentials are currently blocked. Running it never has a destructive side effect.
Capability 1: Install Gangtise skills
Gangtise publishes 19 independent skills on a Huawei Cloud OBS bucket. They are organized into 3 bundle ZIPs plus 1 standalone ZIP. The installer downloads the 4 archives, extracts the 19 skill directories, and symlinks each one into the detected agents' skills directories.
Distribution source
All skills come from the official Gangtise OBS bucket:
https://gts-download.obs.myhuaweicloud.com/skills/No mirrors. The installer uses this URL directly.
Bundle map
| Bundle | Size | Contains |
|---|---|---|
gangtise-skills-client.zip | 160 KB | data-client, kb-client, file-client, file-client-no-download, stockpool-client |
gangtise-research.zip | 220 KB | stock-research, opinion-pk, thematic-research, stock-selector, event-review, interview-outline, announcement-digest, opinion-summarizer, wechat-summary, data-processor |
gangtise-skills.zip | 118 KB | data (v1.2.0), file, kb — the legacy "minimal" parallel line |
gangtise-web-client.zip | 8 KB | web-client (standalone, not in any bundle) |
Total: 4 HTTP requests → 19 skill directories.
Two skills (gangtise-file-client-no-download and gangtise-stockpool-client) only exist inside the `gangtise-skills-client` bundle — they do not have standalone ZIPs. A naive "list the standalone ZIP for each skill" approach would miss them entirely. See references/known_issues.md ISSUE-002 for the full explanation.
One-command install
bash scripts/install_gangtise.shFlags:
bash scripts/install_gangtise.sh --preset minimal # default — 3 skills via public open-* endpoints
bash scripts/install_gangtise.sh --preset workshop # alias for minimal (same 3 skills)
bash scripts/install_gangtise.sh --preset full # all 19 skills (most -client will fail without skills-backend ACL)
bash scripts/install_gangtise.sh --only data-client,kb-client,file-client # custom subset
bash scripts/install_gangtise.sh --no-openclaw # skip OpenClaw even if detected
bash scripts/install_gangtise.sh --target claude-code # force single targetPreset contents
| Preset | Skills | Intended for |
|---|---|---|
| minimal (default) | gangtise-data, gangtise-file, gangtise-kb | Conservative install that works on any account that can authenticate. Uses public open-* endpoints only — immune to ISSUE-007. Covers OHLC, financials, announcements, foreign reports, RAG retrieval. |
| workshop | (alias for minimal — same 3 skills) | Historical preset bundled 7 -client-heavy skills, but those are blocked by ISSUE-007 on most accounts and produce a broken live demo. The preset now points at the same 3 skills as minimal so it can no longer footgun a workshop. |
| full | All 19 skills | Both lines side-by-side. Useful for exploring the full Gangtise catalog. *Most `-client` skills will fail at runtime if your account lacks `skills-backend/` ACL** — confirm with the diagnostic in ISSUE-007 first. |
Capability 2: Configure credentials
Every Gangtise skill needs an .authorization credential file colocated with its Python runtime, in one of two shapes:
Shape A — accessKey + secretAccessKey (most common, auto-refreshes tokens):
{
"accessKey": "<your-accessKey>",
"secretAccessKey": "<your-secretAccessKey>"
}Shape B — long-term token (advanced, for pre-generated long-lived tokens):
{
"long-term-token": "Bearer <token>"
}Because 19 skills each need the same .authorization file, the wrapper stores one shared file at ~/.config/gangtise/authorization.json (XDG standard, mode 600) and symlinks every skill's local credential file to it. Rotating credentials means editing one file, not 19.
Run the configurator:
bash scripts/configure_auth.shIt will:
1. Prompt for accessKey and secretAccessKey (or read from the GANGTISE_ACCESS_KEY / GANGTISE_SECRET_KEY environment variables if set). 2. Write to ~/.config/gangtise/authorization.json with mode 600. 3. Perform a live authentication call to https://open.gangtise.com/application/auth/oauth/open/loginV2 to verify the credentials actually work. 4. Write ~/.GTS_AUTHORIZATION with the bare runtime token required by upstream CLI scripts. 5. Create symlinks from every installed skill's local credential file to the shared XDG file. 6. Report success with the uid + userName returned by the Gangtise auth server.
Credential rotation
# Edit one file:
$EDITOR ~/.config/gangtise/authorization.json
# Re-verify against the live server:
bash scripts/configure_auth.sh --verify-onlyNo other files need to change — the symlinks still point at the updated file.
Capability 3: Diagnose install state
bash scripts/diagnose.shThe diagnostic script is strictly read-only. It checks:
- Which of the 19 skills are present in each detected agent's
skills/directory - Whether
~/.config/gangtise/authorization.jsonexists with mode 600 - Whether each skill's local credential file is a valid symlink pointing at the shared XDG file
- Whether the stored credentials pass a live authentication call (short probe that only needs
oauth/open/loginV2) - Whether the canonical RAG endpoint responds to a minimal query (scoped liveness check — proves the credential has
ragscope, not just auth scope)
Exit codes:
0— all healthy1— one or more issues need user action2— diagnostic itself failed (network error, no internet, etc.)
If diagnose reports issues, cross-reference the output against references/known_issues.md. Each reported issue maps to a specific remediation section.
Capability 4: Skill registry — "which skill answers my data question?"
This is the non-obvious value of the wrapper. Gangtise's 19 skills form a two-dimensional matrix (data tier × operation type) that is not clearly documented. Use this table to route a user question to the right skill:
Data-layer skills (6)
| Want to… | Upstream skill | Invoke |
|---|---|---|
| Query semantic content across knowledge base (reports + opinions + minutes) | gangtise-kb-client | kb runner with -q query + optional --file-types / --securities |
| List documents by type + date + security (reports, announcements, summaries, opinions, roadshows) | gangtise-file-client | dedicated runners per document type (report / opinion / summary / announcement / investment_calendar / foreign_report / internal_report / wechat_message) |
| Pull OHLC daily candles for an A-share or HK stock | gangtise-data-client | quote runner with --securities {name} + -sd / -ed date range |
| Pull financial statements (income / balance / cash flow indicators) | gangtise-data-client | financial runner with --securities {name} + --indicators |
| Pull valuation metrics (PE / PS / PB / PEG + historical percentiles) | gangtise-data-client | valuation runner with --securities {name} |
| Pull main business composition (by product / industry / region) | gangtise-data-client | main_business runner with --securities {name} + --classify-method |
| Pull shareholder / top-holder data | gangtise-data-client | shareholder runner with --securities {name} |
| Pull macro / industry indicators (GDP, CPI, vehicle sales, commodity prices) | gangtise-data-client | industry_indicator runner with -k {keyword} |
| Look up security standard codes by name | gangtise-data-client | security runner with -k {name} |
| List sector constituent stocks by theme or industry | gangtise-data-client | block_component runner with -k {theme} |
| List index members by category | gangtise-data-client | index runner with -k {index type} |
| Search the open web for public information not in Gangtise's internal KB | gangtise-web-client | web runner with -q {query} |
See `references/skill_registry.md` for the full per-runner parameter reference and cross-skill composition examples.
Workflow-layer skills (10) — higher-order research workflows
These skills orchestrate the data-layer skills into end-to-end research workflows. They produce Markdown + HTML reports following Gangtise's professional investment-research templates and built-in compliance guardrails (no "买入 / 卖出 / 目标价 / 推荐" language).
| Want to… | Use |
|---|---|
| Generate a stock research report at L1-L4 depth (L1 = 1-page framework, L4 = full institutional coverage) | gangtise-stock-research |
| Do adversarial analysis on an investment thesis ("play devil's advocate for this long call") | gangtise-opinion-pk |
| Do thematic / sector research (driver analysis, enumeration phase, stock screening, performance check) | gangtise-thematic-research |
| Screen stocks based on research criteria | gangtise-stock-selector |
| Write an 800-1000 word event review / post-mortem for a market event | gangtise-event-review |
| Generate a company-meeting outline (3-step workflow: data → topics → questions) | gangtise-interview-outline |
| Track recent announcements for a stock pool and produce a daily digest | gangtise-announcement-digest |
| Summarize a chief analyst's recent opinions | gangtise-opinion-summarizer |
| Turn a WeChat chat-group discussion log into a structured investment daily | gangtise-wechat-summary |
| Get methodology guidance on how to design a custom data-processing workflow | gangtise-data-processor |
Utility skills (3)
| Skill | Purpose |
|---|---|
gangtise-stockpool-client | Create / rename / delete a stock pool; add or remove stocks from it. Only distributed inside gangtise-skills-client.zip. |
gangtise-file-client-no-download | Variant of file-client that disables the download capability — useful in read-only environments or compliance-sensitive contexts. |
Legacy gangtise-data / gangtise-file / gangtise-kb | The older minimal parallel line. data is v1.2.0 with strictly-typed security codes (no name resolution). Only install if the user wants the smaller feature footprint. |
See references/skill_registry.md for the full per-skill script catalog, versions, and capability matrix.
What this skill refuses to do
- Vendor, fork, or mirror any
gangtise-*skill's content into this directory — only the canonical OBS URLs are referenced. - Pin an upstream skill version in SKILL.md — the installer always downloads the current OBS artifact.
- Silently patch upstream files — every modification path (if any are ever added) would require explicit consent via AskUserQuestion.
- Hardcode personal accessKey / secretAccessKey values.
- Make investment recommendations or trading decisions. Gangtise's own skills already enforce these compliance rules; this wrapper strictly delegates.
File layout
gangtise-copilot/
├── SKILL.md # This file
├── scripts/
│ ├── install_gangtise.sh # Download bundles → stage → distribute
│ ├── configure_auth.sh # Set up + verify credentials
│ └── diagnose.sh # Read-only health report
├── references/
│ ├── installation_flow.md # How the installer works, flag reference, troubleshooting
│ ├── credentials_setup.md # accessKey / secretAccessKey, XDG paths, liveness check
│ ├── skill_registry.md # Complete per-skill capability matrix
│ ├── known_issues.md # Two parallel product lines, bundle-only skills, and other gotchas
│ └── best_practices.md # How to combine stock-research + opinion-pk + data-client effectively
└── config-template/
└── authorization.json.example # Credential file template (placeholder values only)Security scan passed
Scanned at: 2026-05-17T16:03:14.139633
Tool: gitleaks + pattern-based validation
Content hash: ee0d8a18a6deb2e6d64cbfadfd7e0e35caa72152829abf7fd222a62b571ad4ab
{
"_comment_accessKey": "Your Gangtise accessKey. Get from your Gangtise account administrator or the Gangtise OpenAPI portal. REPLACE the placeholder value below with your real accessKey before use.",
"accessKey": "REPLACE_WITH_YOUR_ACCESS_KEY",
"_comment_secretAccessKey": "Your Gangtise secretAccessKey. This is a private credential — treat it like a password. REPLACE the placeholder value below with your real secretAccessKey before use.",
"secretAccessKey": "REPLACE_WITH_YOUR_SECRET_KEY",
"_comment_long-term-token_alt_shape": "Alternative shape — if you have a pre-generated long-lived Bearer token from a different part of the Gangtise infrastructure, you can use this shape instead of accessKey+secretAccessKey. In that case REMOVE accessKey and secretAccessKey above and keep only the long-term-token field below. Otherwise leave this commented-out example alone.",
"_example_long-term-token": "Bearer REPLACE_WITH_YOUR_TOKEN"
}
Gangtise Copilot — Best Practices
Non-obvious patterns for getting the most value out of the Gangtise skill catalog after installation. Read this when you've installed the skills and are wondering "okay, now what do I actually do with them?"
The two-level mental model
Gangtise's 19 skills are organized into two layers that you should think of differently:
1. Data-layer skills (gangtise-data-client, gangtise-kb-client, gangtise-file-client, gangtise-web-client, gangtise-stockpool-client) — primitive operations. Each script returns a specific data structure (CSV, file list, text chunks). Don't call them directly in a live demo unless you're teaching the primitive; they're building blocks, not finished products.
2. *Workflow-layer skills (the 10 `gangtise-` in the research bundle)* — finished research deliverables. Each one encodes a full professional workflow — data retrieval, analysis, writing, formatting — and outputs an MD + HTML report. Call these in live demos because they produce something the audience can see*.
The mistake a new user makes: invoking gangtise-data-client/quote.py directly, getting back a CSV of 252 rows of OHLC data, and thinking "now what?" The workflow-layer skill gangtise-stock-research L2 answers "now what" — it wraps the same quote data into a research narrative.
Skill composition patterns
Pattern 1: Single flagship skill for quick wins
For a 10-minute demo, invoke a single workflow-layer skill end-to-end:
- Stock research report:
gangtise-stock-researchL2 on any named stock → complete investment view in one invocation. - Daily monitoring digest:
gangtise-announcement-digestwith a stock pool → daily push to Feishu. - Devil's advocate review:
gangtise-opinion-pkon a named stock with user's thesis → risk scan MD + HTML.
The workflow-layer skills are designed for single-shot use and produce publication-ready output. Don't try to chain them together in a first demo — the output of one is not the input of another by default.
Pattern 2: Data → workflow → revision
For deeper research, pair a data-layer skill with a workflow-layer skill:
1. Use gangtise-data-client/financial.py to pull specific metrics you care about (e.g., operating margin over 8 quarters). 2. Feed those numbers as context into gangtise-stock-research — the workflow skill will incorporate them into its narrative. 3. Run gangtise-opinion-pk on the resulting thesis for a risk scan.
This three-step composition produces a "my view + adversarial critique" pair that reads far more like institutional research than a single skill call.
Pattern 3: Enumerate → filter → deepen
For industry research, fan out with the enumeration skills:
1. gangtise-data-client/block_component.py -k 新能源汽车 → get constituent stocks 2. gangtise-data-client/valuation.py --securities-file block_component_1.csv → valuation data for each 3. Sort, filter, pick the top 3 by your criterion 4. gangtise-stock-research L2 on each of the top 3 5. gangtise-thematic-research on the sector as a whole
This is the pattern that gangtise-stock-selector and gangtise-thematic-research encode internally — knowing the decomposition lets you intervene at any step.
Credential scope gotchas
The accessKey + secretAccessKey you get from Gangtise has scopes attached to it. Common scopes (from observation):
- auth — can call
loginV2to mint a token. Every account has this. - rag — can call
knowledge_basesemantic search. Most accounts have this. - data — can call structured data scripts (
quote,financial,valuation, etc.). Paid accounts. - file — can call file-center scripts (
report,opinion,summary, etc.). Paid accounts. - openapi — aggregate name for the above three. This is what
skills-backend/version?skill=openapireports.
If your account is missing a scope, the affected scripts will return an error at call time, not at auth time. diagnose.sh probes only the rag scope by default (because that's the one most skills need), so a partial-scope account will show "✅ RAG liveness passed" and then fail when you try to call a data skill.
Best practice: When onboarding a new user, ask their Gangtise admin explicitly: "Does this account have data and file scopes in addition to rag?" If they don't know, the fastest way to find out is to call one of each tier and observe:
# Tier: rag (should work)
cd ~/.local/share/gangtise-copilot/skills/gangtise-kb-client
python3 scripts/kb.py -q "test" -l 1
# Tier: data (fails if no data scope)
cd ../gangtise-data-client
python3 scripts/quote.py --securities 宁德时代 -sd 2026-04-01 -ed 2026-04-10
# Tier: file (fails if no file scope)
cd ../gangtise-file-client
python3 scripts/report.py -k 宁德时代 -l 3Working around the OBS LIST block
gts-download.obs.myhuaweicloud.com/skills/ has its LIST permission disabled (403 on any listing request). This means:
- You cannot programmatically discover new skills by crawling the bucket.
- The installer's bundle list is hand-maintained.
- A new Gangtise skill release will not be detected automatically by the wrapper.
When you hear about a new Gangtise skill (via WeChat, Gangtise's own announcements, or a user report), update scripts/install_gangtise.sh:
1. Try to HEAD the new standalone ZIP: curl -I https://gts-download.obs.myhuaweicloud.com/skills/gangtise-<new-name>.zip 2. If it returns 200, add it to the bundle map under the appropriate bundle (or under its own standalone line if it's truly independent). 3. Re-test the install flow end-to-end with --only <new-skill> to confirm it unpacks cleanly. 4. Add it to the preset lists if it's workshop-relevant. 5. Bump the wrapper version in marketplace.json and commit.
NO_PROXY for macOS / Linux users with local HTTP proxies
If you run a local HTTP proxy (Shadowrocket, Clash, Surge, v2ray, etc.) that intercepts .com traffic, every call to open.gangtise.com or gts-download.obs.myhuaweicloud.com goes through the proxy. Depending on your proxy's TLS handling, this can:
- Corrupt download responses (proxy truncates or re-encodes HTTPS bodies) — the installer's size sanity check catches this, but only after a failure.
- Fail auth calls (proxy terminates TLS and Gangtise rejects the resulting cert chain).
- Add 500-2000 ms latency to every API call, making live demos feel sluggish.
The fix:
export NO_PROXY="open.gangtise.com,gts-download.obs.myhuaweicloud.com,$NO_PROXY"
export no_proxy="open.gangtise.com,gts-download.obs.myhuaweicloud.com,$no_proxy"Or add these to your shell init (~/.zshrc, ~/.bashrc). gangtise-copilot's scripts do NOT set this for you — setting NO_PROXY globally is a user-level decision.
Performance reference
Approximate wall-clock timings for live invocations of each workflow skill (based on staging tests; will vary with query complexity, account quota, and network):
| Skill | Typical wall time | What the audience sees |
|---|---|---|
gangtise-stock-research L1 | 30-60 sec | 1-page MD + rendered HTML |
gangtise-stock-research L2 | 2-4 min | Full investment view MD + HTML |
gangtise-stock-research L3 | 5-10 min | Institutional first-coverage MD + HTML |
gangtise-opinion-pk | 2-4 min | Adversarial analysis MD + HTML |
gangtise-thematic-research | 3-5 min | Theme analysis MD + HTML |
gangtise-announcement-digest | 1-2 min | Stock pool digest MD + HTML |
gangtise-event-review | 1-2 min | Event post-mortem MD + HTML |
Data-layer call (e.g., quote.py) | 3-10 sec | CSV file on disk |
Demo tip: Use gangtise-stock-research L1 for "hello world" because it's fast enough to not break audience attention, and use L2 for the "wow" moment because the output is institutional-grade but doesn't take so long that you lose the room.
What NOT to do in a live demo
- Don't call 18 data-layer scripts in a row. The audience will see 18 CSV files and think "I could have done this in Excel." Always wrap data calls in a workflow-layer skill.
- Don't claim the workflow skills are making investment recommendations. They explicitly avoid this (the compliance guardrails in their templates forbid "买入 / 卖出 / 目标价"). Calling the output a "recommendation" in front of an audience defeats the purpose of the guardrails and puts you at compliance risk.
- *Don't pick `-client` skills before verifying your account has `skills-backend/
ACL.** If you're affected by ISSUE-007, the-clientline will fail with0000001009mid-demo. Run the diagnostic inreferences/known_issues.mdISSUE-007 first; if you're affected, the legacy minimal line (gangtise-data,gangtise-file,gangtise-kb`) is the working surface and they cover the most common queries (OHLC, financials, announcements, RAG retrieval). - Don't pair `gangtise-stock-research` with a stock that has sparse coverage. The workflow needs at least 20 recent research reports + opinions to produce a good L2 output. Pick large-cap A-share names with active analyst coverage for guaranteed data density.
- Don't demonstrate the `opinion-pk` adversarial analysis on a stock the audience has strong personal opinions about. It produces a devil's-advocate view by design, which can read as an attack on whoever recommended the stock. Stay with neutral or unfamiliar names.
What TO do after install
1. Run `diagnose.sh` once to confirm everything is healthy (9 checks should pass). 2. Try one workflow skill on one stock — pick gangtise-stock-research L1 宁德时代 as a smoke test. You should get a ~1 minute run and an MD + HTML pair on disk. 3. Open the HTML in a browser to see Gangtise's professional report template render. This is the output your workshop audience will see. 4. Read the MD file's "data sources" section at the bottom — it lists which underlying skills were called. Use this to build intuition about the workflow → data-layer mapping. 5. Go back and re-read `skill_registry.md` with fresh eyes — the capability matrix makes more sense after you've seen one workflow in action.
Gangtise Copilot — Credentials Setup Reference
Deep-dive documentation for scripts/configure_auth.sh. Read this to understand the credential file format, where it's stored, how liveness checks work, and how to rotate credentials without breaking any installed skill.
Credential shapes
Every Gangtise skill's scripts/utils.py looks for scripts/.authorization and accepts one of two shapes:
Shape A — accessKey + secretAccessKey (recommended)
{
"accessKey": "YOUR_ACCESS_KEY_HERE",
"secretAccessKey": "YOUR_SECRET_ACCESS_KEY_HERE"
}The skill calls https://open.gangtise.com/application/auth/oauth/open/loginV2 with this payload, gets back a Bearer token (TTL: 10800 seconds / 3 hours), and uses that token for subsequent API calls. The token is refreshed automatically when it expires.
Use this shape unless you have a specific reason to use Shape B. It's the simplest to set up and it has no manual rotation step.
Shape B — long-term token (advanced)
{
"long-term-token": "Bearer YOUR_LONG_TERM_TOKEN_HERE"
}If your organization issues pre-generated long-lived tokens through a separate process (e.g., an SSO integration that mints Gangtise Bearer tokens), store them in this shape. The skill will use the token verbatim and skip the OAuth dance.
Limitation: configure_auth.sh --verify-only cannot re-verify long-term tokens because it doesn't know which endpoint to probe for arbitrary scope. Shape B users should run their own liveness checks via the tool that issued the token.
Storage location (XDG standard)
The wrapper stores one shared credential file at:
~/.config/gangtise/authorization.jsonThis location follows the XDG Base Directory specification ($XDG_CONFIG_HOME/gangtise/ defaulting to ~/.config/gangtise/). It is respected on macOS, Linux, and WSL. Windows users should set %LOCALAPPDATA% equivalently or pass --access-key / --secret-key flags directly (the file path logic uses $XDG_CONFIG_HOME when set).
Why a shared file and not per-skill files?
Each Gangtise skill (19 of them) has its own scripts/ subdirectory, and each one looks for .authorization in that subdirectory. The naive approach would be to write 19 independent credential files, but that has three problems:
1. Rotation is painful. Changing your credentials means editing 19 files. 2. Drift is easy. If even one file gets out of sync during rotation, one skill will fail while the others work, and debugging it is miserable. 3. Security surface is larger. 19 files means 19 places a leak can happen.
The wrapper solves this by writing a single file to the XDG location and then creating symlinks from each skill's scripts/.authorization to the shared file:
~/.local/share/gangtise-copilot/skills/
├── gangtise-data-client/
│ └── scripts/
│ └── .authorization → ~/.config/gangtise/authorization.json
├── gangtise-kb-client/
│ └── scripts/
│ └── .authorization → ~/.config/gangtise/authorization.json
└── ... (17 more)Rotate credentials = edit one file. All 19 skills pick up the change instantly.
Permission mode
configure_auth.sh writes the credential file with mode 600 (owner read+write, no group, no other). The parent directory ~/.config/gangtise/ is created with mode 700.
If you copy the file manually or modify it with a tool that doesn't preserve mode, fix it with:
chmod 700 ~/.config/gangtise
chmod 600 ~/.config/gangtise/authorization.jsondiagnose.sh will warn you if the mode drifts from 600.
Input precedence (how configure_auth.sh gets the credentials)
The configurator accepts credentials from three sources, in this precedence order:
1. Flag arguments (highest): --access-key KEY --secret-key KEY 2. Environment variables: GANGTISE_ACCESS_KEY / GANGTISE_SECRET_ACCESS_KEY 3. Interactive prompt (lowest): if neither of the above is set, the script asks you to type each value. The secretAccessKey prompt uses stty -echo to hide the input.
This lets you automate bootstrap in CI (flags or env vars) while still having a clean interactive flow for first-time local setup.
Liveness verification
After writing the file, configure_auth.sh performs a live authentication call to verify the credentials actually work. This is done by POST-ing the credential payload to:
https://open.gangtise.com/application/auth/oauth/open/loginV2Critical detail: Gangtise returns HTTP 200 for both success and failure — the server responds with a JSON body containing a code field that is "000000" on success and something else on failure (often a validation error code). A liveness check that only looks at HTTP status will pass for an invalid credential and produce a broken install.
The configurator matches on "code":"000000" in the response body, not on HTTP status, and extracts the userName + uid from a successful response to echo back to the user as confirmation.
This is a scope-level verification — it proves that the accessKey + secretAccessKey can mint an OAuth token. It does NOT prove that the resulting token has rag scope (which is what most Gangtise skills actually need). That second-level check is performed by diagnose.sh, which calls the RAG search endpoint after obtaining a token.
Rotation procedure
# 1. Edit the shared credential file:
$EDITOR ~/.config/gangtise/authorization.json
# 2. Re-verify the new credentials against the live server:
bash scripts/configure_auth.sh --verify-only
# 3. If verification passes, every installed skill is already picking up
# the new values via the symlink — nothing else to do.If verification fails, the old credential file is left in place and you can revert the edit.
What to do when credentials are rejected
configure_auth.sh will print the server's response when authentication fails. The most common error shapes are:
| Server response contains | Meaning | Fix |
|---|---|---|
"code":"999991" or similar non-zero code | accessKey or secretAccessKey is wrong | Re-check the values; watch for trailing whitespace |
| HTTP 5xx | Gangtise server is down | Wait and retry |
| Network error / timeout | Local network or proxy issue | Check your connectivity; add the Gangtise host to your NO_PROXY list if you have a local HTTP proxy |
"code":"000000" but subsequent skill calls fail | Account doesn't have the scope the skill needs | Contact your Gangtise account administrator to add the rag / data / file scope |
NO_PROXY configuration (macOS / Linux with a local HTTP proxy)
If you run a local HTTP proxy (Shadowrocket, Clash, etc.) that intercepts *.com traffic, Gangtise API calls may fail because the proxy terminates TLS incorrectly. Add the Gangtise host to your NO_PROXY list:
export NO_PROXY="open.gangtise.com,$NO_PROXY"
export no_proxy="open.gangtise.com,$no_proxy"The wrapper's scripts do not automatically set NO_PROXY — doing so would be overreach. But if you hit persistent network errors during the liveness check on a machine with a local proxy, this is almost always the fix.
Security considerations
- Never commit `authorization.json` to version control. The example template at
config-template/authorization.json.exampleuses placeholder values and is safe to commit; the real file in~/.config/gangtise/must never leave your machine. - Rotate immediately if you suspect a leak. Gangtise's admin portal has a "regenerate key" option — do that, then re-run
configure_auth.sh. - The mode-600 check exists for a reason. If you see a warning that the file has wrong permissions (e.g., mode 644 after copying from another machine), fix it immediately. Shared credentials in user home directories are a common target for unprivileged escalation.
- Don't paste your credentials into a chat, issue tracker, or log file. If you need to share a repro, substitute placeholder values first.
Gangtise Copilot — Installation Flow Reference
Deep-dive documentation for scripts/install_gangtise.sh. Read this when the installer behaves unexpectedly, when you want to understand why the wrapper downloads 4 archives instead of 19, or when you need to adapt the install flow for a non-standard environment.
Table of contents
1. What the installer actually does 2. Why 4 bundles instead of 19 direct downloads 3. Target agent detection 4. Canonical install pattern + symlinks 5. Preset contents 6. Flag reference 7. Idempotency — what happens on re-run 8. Troubleshooting common install failures
What the installer actually does
The installer is a single Bash script that performs these steps in order:
1. Parse flags — --preset, --only, --target, --no-openclaw. 2. Prerequisite check — verifies curl and unzip are on PATH, fails fast with actionable messages if either is missing. 3. Detect target agents — walks $HOME/.claude, $HOME/.openclaw, $HOME/.agents and builds an ordered target list. Honors --target and --no-openclaw overrides. 4. Compute required bundle set — only downloads the bundles that contain at least one skill in the requested list. For example, --preset minimal only downloads gangtise-skills.zip and skips the other 3 archives entirely. 5. Download each required bundle from https://gts-download.obs.myhuaweicloud.com/skills/<bundle>.zip into a timestamped staging directory under /tmp/gangtise-copilot-staging/. Uses curl --fail to surface HTTP errors and a wc -c size check to reject suspiciously small downloads (defense against OBS returning a 200 with an HTML error body). 6. Extract all bundles into the staging directory. Bundles may deposit skills at the staging root (gangtise-skills-client.zip does this) or nested one level deep — the locator function locate_skill_src handles both layouts. 7. Copy each requested skill from the staging directory into the canonical install location ($HOME/.local/share/gangtise-copilot/skills/<skill>/), replacing any existing copy. This is a fresh-each-run copy, not an in-place update — the canonical location is always a faithful mirror of the bundle's current contents. 8. Create symlinks in every detected agent's skills directory pointing to the canonical location. Existing non-symlink installs are backed up to /tmp/gangtise-copilot-backups/<timestamp>/ before being replaced. 9. Clean up the staging directory via trap EXIT. 10. Report which skills were installed, which were skipped (if any), and the next-step commands.
Why 4 bundles instead of 19 direct downloads
Each skill also exists as a standalone gangtise-<skill-name>.zip on the same OBS bucket, so in theory the installer could do 19 direct downloads. It does not, for three reasons:
1. Two skills are bundle-only. gangtise-file-client-no-download and gangtise-stockpool-client do not have standalone ZIPs on the OBS bucket — they are only distributed inside gangtise-skills-client.zip. A naive "one HTTP request per skill" installer would silently miss them. See known_issues.md ISSUE-002 for the discovery story.
2. 4 HTTP requests instead of 19 are faster, more reliable, and easier to retry. Each additional HTTP request is an additional failure point — network flakiness, OBS throttling, bucket eventual-consistency. Downloading 4 pre-assembled bundles is materially more reliable than downloading 19 independent files, especially over a VPN or a throttled corporate network.
3. Bundles are the canonical distribution unit. Gangtise itself maintains gangtise-skills-client.zip, gangtise-research.zip, and gangtise-skills.zip as official aggregate archives. Using them directly means the wrapper never fights with upstream over which-skill-is-in-which-archive — if Gangtise rebalances the bundle contents in a future release, the wrapper picks it up automatically.
The installer computes the minimum bundle set needed to satisfy the --preset or --only list. A --preset minimal install downloads only gangtise-skills.zip (3 skills, ~118 KB); --preset workshop is an alias for minimal and downloads the same single bundle; --preset full downloads all 4 bundles.
Target agent detection
The installer walks three candidate directories in order and adds each that exists to its target list:
| Agent | Probe path | Added to target list when |
|---|---|---|
| Claude Code | $HOME/.claude | Directory exists |
| Codex | $HOME/.agents | Directory exists |
| OpenClaw | $HOME/.openclaw OR openclaw on PATH | Either condition is true |
Override flags:
--target <agent>— install to a single named target, regardless of what's detected. Use this when you have all three agents installed but only want to update one.--no-openclaw— skip OpenClaw even if detected. Useful when you're maintaining an OpenClaw install separately (e.g., via Gangtise's own installer) and don't want the wrapper to stomp on it.
Zero-agents fallback: if none of the three candidates are detected, the installer does not abort. Instead it prints a loud warning naming the paths it looked at and defaults to claude-code. Three strategies were considered here:
| Strategy | Behavior | Why rejected |
|---|---|---|
| Abort | Fail with "no target agent found" | Too strict — a user who just installed Claude Code and hasn't restarted their shell hits this and is confused |
| Silent skip | Install nothing, exit 0 | Most surprising behavior; user thinks it worked and then everything is broken |
| Default to claude-code ✓ | Install to ~/.claude/skills/ with a warning | Most common case when detection legitimately fails; a loud warning makes it debuggable |
Canonical install pattern + symlinks
The wrapper uses a single canonical install + one symlink per agent layout:
~/.local/share/gangtise-copilot/skills/ ← canonical install (real files)
├── gangtise-data-client/
├── gangtise-kb-client/
└── ... (up to 19 skills)
~/.claude/skills/gangtise-data-client → symlink to canonical
~/.openclaw/skills/gangtise-data-client → symlink to canonical
~/.agents/skills/gangtise-data-client → symlink to canonicalBenefits:
- One update, every agent gets it. When you upgrade a skill (re-run the installer), the canonical location changes and every symlink instantly points at the new version. No per-agent re-install.
- Credentials propagate automatically. The shared
.authorizationfile (~/.config/gangtise/authorization.json) is symlinked from each skill'sscripts/.authorization. Rotating the credential means editing one file; every skill in every agent picks up the new value on next use. - Safer than `cp -r`. If you re-run the installer with a different
--preset, the canonical location is rewritten and all symlinks continue to work. Acp -r-based install would leave stale copies in each agent's directory.
The canonical root can be overridden with GANGTISE_COPILOT_HOME for test isolation:
GANGTISE_COPILOT_HOME=/tmp/gangtise-test bash install_gangtise.shPreset contents
| Preset | Skills | Bundles downloaded | Use case |
|---|---|---|---|
minimal (default) | data, file, kb (3, legacy minimal line via public open-* endpoints) | skills | Conservative install that works on every account that can authenticate. Immune to ISSUE-007 (skills-backend/* ACL). Covers OHLC + financials + announcements + foreign reports + RAG. |
workshop | (alias for minimal — same 3 skills) | skills | Historical preset bundled 7 -client-heavy skills (data-client + kb-client + file-client + web-client + stock-research + opinion-pk + announcement-digest), but those are blocked by ISSUE-007 on most accounts. The preset now points at the same 3 skills as minimal to avoid footgunning live demos. |
full | All 19 skills (data layer + web + stockpool + file-no-download + 10 research workflows + 3 minimal) | All 4 bundles | Both lines side-by-side. *Most `-client` skills will fail at runtime if your account lacks `skills-backend/` ACL** — verify per ISSUE-007. |
Override with --only for a custom subset:
bash install_gangtise.sh --only gangtise-data-client,gangtise-stock-research,gangtise-opinion-pkThe --only list is taken literally — the installer downloads whichever bundles contain those skills and skips everything else.
Flag reference
| Flag | Purpose | Default |
|---|---|---|
--preset <mode> | Install preset: minimal, workshop (alias for minimal), full | minimal |
--only <list> | Comma-separated skill names. Overrides --preset. | none |
--target <agent> | Force single target: claude-code, openclaw, codex | auto-detect all |
--no-openclaw | Skip OpenClaw even if detected | include all detected |
--list-skills | Print the known 19-skill catalog and exit | — |
-h / --help | Show usage and exit | — |
Idempotency — what happens on re-run
Re-running the installer with the same arguments is safe. Every destructive step is guarded:
- Staging directory is timestamped + PID-scoped, so concurrent runs don't collide.
- Canonical install is rewritten fresh each run — any skill that was previously installed gets replaced, any skill that is no longer in the preset gets left alone (the installer only manages skills it just downloaded).
- Agent symlinks use
ln -sfnwhich replaces existing links atomically. - Non-symlink installations in agent dirs are backed up to
/tmp/gangtise-copilot-backups/<timestamp>/before being replaced, not silently deleted. - Credential file is never touched by the installer — that's
configure_auth.sh's responsibility.
If you re-run with a smaller preset (e.g., you first ran --preset full and now run --preset workshop), the extra skills from the first run remain in the canonical location and in the agent directories. The installer only manages skills it's currently installing — it does not remove skills it didn't download this run. To remove skills cleanly, delete the canonical directory and re-run:
rm -rf ~/.local/share/gangtise-copilot/skills
bash install_gangtise.sh --preset workshop
# Note: agent symlinks to deleted canonical dirs will dangle — diagnose.sh will flag them.Troubleshooting common install failures
Download failed (HTTP 404)
The OBS bucket layout changed or the bundle was renamed upstream. The installer points at hard-coded bundle names because the OBS LIST permission is disabled — the wrapper can't discover new bundle names automatically. Report the failure as an issue on the gangtise-copilot repo so the bundle list can be updated.
Downloaded file is suspiciously small
OBS returned a "200 OK" with a sub-1KB body. This usually means one of:
- The CDN redirected a yanked-version URL to an HTML error page.
- Huawei Cloud OBS is experiencing an outage.
- Your network is intercepting HTTPS responses (corporate proxy doing TLS inspection).
The installer rejects downloads under 1000 bytes pre-extraction to fail fast here, so you'll see a clear error instead of a confusing unzip failure downstream. Retry, and if it persists, check https://status.huaweicloud.com.
Could not locate <skill> in downloaded bundles
This happens when a requested skill name does not appear in any of the downloaded bundles. Causes:
- Typo in `--only` list. The installer does not do fuzzy matching —
gangtise-dataclient(missing hyphen) will not resolve togangtise-data-client. Use--list-skillsto see the exact names. - Skill was moved out of the bundle you expected. If upstream rebalances
gangtise-skills-client.zip's contents, the installer needs updating. Open an issue.
No supported agent detected
None of the three candidate agent directories exist. Most commonly this means Claude Code was just installed and the user hasn't actually opened it yet (the ~/.claude/ directory is created on first launch, not at install time). Open Claude Code once to create the directory, then re-run. Or pass --target claude-code to force the install ahead of directory creation.
Symlink creation fails on macOS System Integrity Protection
If your $HOME is on a read-only filesystem or has restricted permissions, the ln -sfn may fail. Check the output for "Operation not permitted" — if you see it, run the install with an explicit --target and ensure the target agent's skills/ directory is writable.
Known Issues in the Gangtise Ecosystem
This file is the source of truth for every upstream issue that gangtise-copilot is aware of. Unlike a typical wrapper skill, gangtise-copilot did not emerge from a session that fixed active upstream bugs — the Gangtise OpenAPI skills are well-maintained and there are no broken files to patch. The issues documented below are instead discoverability gaps and ecosystem traps that a first-time user is likely to fall into, along with the runtime workarounds that gangtise-copilot applies on their behalf.
How the agent should use this file
When scripts/diagnose.sh reports a ⚠️ or ❌ line, or when a user's question matches one of the issue patterns below, use this file as the lookup table:
1. Explain to the user in plain language what's going on and why it matters. 2. Execute the documented fix (for ISSUE-001, ISSUE-002, ISSUE-003, the "fix" is already baked into the installer — the user just needs to understand the what and why). 3. For newly-discovered issues, file a new ISSUE-NNN entry with the full schema.
Issue registry
ISSUE-001 — Two parallel product lines with overlapping names but different capabilities
Status: Observed on the Gangtise OpenAPI skill ecosystem as of April 2026. Likely permanent — these are two intentionally separate product lines, not a bug.
Symptom: A user installs gangtise-data (the short name) and then fails to find capabilities they expected to be there. They look at the 4 scripts shipped with gangtise-data and wonder where security.py, shareholder.py, industry_indicator.py, block_component.py, and index.py went. Or worse, they install both gangtise-data AND gangtise-data-client because they look unrelated, then can't tell which one to call for a given task.
Root cause: Gangtise maintains two parallel naming conventions for its data-retrieval skills:
| Naming pattern | Example | Positioning |
|---|---|---|
gangtise-<name> | gangtise-data, gangtise-file, gangtise-kb | Legacy minimal — strict codes only, CSV-focused, smaller scope |
gangtise-<name>-client | gangtise-data-client, gangtise-file-client, gangtise-kb-client | Full capability — name resolution, 2-3× more scripts, richer output |
Both lines are actively maintained. Their Last-Modified timestamps on the OBS bucket match exactly (2026-04-10), and they are distributed in two separate aggregate bundles (gangtise-skills.zip and gangtise-skills-client.zip respectively).
Capability gap (what the minimal line is missing vs the client line):
| Function | In -client | In minimal | Example script |
|---|---|---|---|
| Security code resolution | ✓ | ✗ | security.py |
| Sector / theme constituents | ✓ | ✗ | block_component.py |
| Index catalog | ✓ | ✗ | index.py |
| Industry + macro indicators | ✓ | ✗ | industry_indicator.py |
| Shareholder / holding data | ✓ | ✗ | shareholder.py |
| Chart data | ✓ | ✗ | chart.py (file-client only) |
| Internal reports | ✓ | ✗ | internal_report.py (file-client only) |
| WeChat messages | ✓ | ✗ | wechat_message.py (file-client only) |
| Opinion blocks | ✓ | ✗ | opinion_blocks.py (file-client only) |
Impact: A user who installs only the minimal line and then tries to do "standard" investment research will hit 5-9 dead ends (one per missing capability), with no upstream error message explaining why the capability isn't there.
Why upstream probably hasn't "fixed" it: This is not a bug — it's an intentional product-line decision. The minimal line exists for batch / pipeline use cases where strict inputs are a feature (preventing name-resolution ambiguity at scale), and the client line exists for interactive / research use cases. Gangtise has a legitimate reason to keep both. The problem is that the two lines look like one line with a suffix typo to new users, which leads to confusion.
How to explain it to the user (plain language):
Gangtise has two versions of every data skill: a short-name version (gangtise-data) that's for batch CSV work and requires strict stock codes, and a long-name version (gangtise-data-client) that's for interactive research and accepts Chinese names. Each line targets a different upstream service (open-*vsskills-backend/*), and your account may not have access to both — see ISSUE-007. The installer ships three presets (minimal/workshop/full) so you can pick whichever subset matches your account's actual access level.
Repair strategy (already baked into the installer):
--preset minimal(default) installs only the 3 legacyopen-*skills (gangtise-data,gangtise-file,gangtise-kb) — the conservative default that works on every account that can authenticate.--preset workshopis an alias for `minimal` — same 3 skills. The historical workshop bundle of 7-client-heavy skills was a footgun on accounts blocked by ISSUE-007.--preset fullinstalls both lines (all 19 skills) so users can compare them and understand the difference firsthand. Most-clientskills will fail at runtime if your account lacksskills-backend/*ACL.
No runtime file modification is needed. The wrapper's choice is at install-preset level.
---
ISSUE-002 — Two skills exist only inside a bundle ZIP, never standalone
Status: Observed on the Gangtise OpenAPI skill ecosystem as of April 2026.
Symptom: A diligent user enumerates gts-download.obs.myhuaweicloud.com/skills/gangtise-*.zip by trying every plausible skill name they've seen referenced in upstream SKILL.md files. They find standalone ZIPs for most skills, but `gangtise-stockpool-client` and `gangtise-file-client-no-download` return HTTP 403 (NoSuchKey in Huawei Cloud OBS's dialect). They assume these skills don't exist and write their installer without them, leaving users silently missing 2 capabilities.
Root cause: These two skills only exist inside the `gangtise-skills-client.zip` bundle. There are no corresponding standalone gangtise-stockpool-client.zip or gangtise-file-client-no-download.zip files on the OBS bucket. The only way to discover them is to:
1. Download gangtise-skills-client.zip 2. Unzip it 3. Find the 2 extra subdirectories alongside the expected data-client / kb-client / file-client
OBS has its LIST permission disabled (403 on ?list-type=2 and friends), so there is no way to programmatically enumerate the bucket. A naive "HEAD on each candidate name" enumerator will not discover these.
Impact: A wrapper that does "one HTTP request per expected skill name" will silently drop stockpool-client and file-client-no-download from the install, and users will not be able to manage stock pools or use the read-only variant of file-client.
Why upstream probably hasn't "fixed" it: This is a packaging choice, not a bug. Gangtise maintains gangtise-skills-client.zip as a curated bundle that pins a specific combination of skills (including the two that only exist in-bundle) as the recommended install. Standalone ZIPs for every skill would duplicate storage and introduce version-drift risk between the bundle and the standalone. The problem is again discoverability, not function.
How to explain it to the user (plain language):
Two of the Gangtise skills,gangtise-stockpool-clientandgangtise-file-client-no-download, don't have their own download ZIP — they only exist inside thegangtise-skills-client.zipbundle. Our installer downloads this bundle and unpacks all 5 skills from it, so you get them for free if you install with the wrapper. But if you were writing your own installer from scratch, you would miss them unless you knew to look inside the bundle.
Repair strategy (already baked into the installer):
The installer's bundle map in scripts/install_gangtise.sh hard-codes both hidden skills as contents of gangtise-skills-client.zip:
BUNDLES=(
"gangtise-skills-client:gangtise-data-client,gangtise-file-client,gangtise-file-client-no-download,gangtise-kb-client,gangtise-stockpool-client"
...
)When a preset requests gangtise-stockpool-client, the installer knows to download gangtise-skills-client.zip (not a non-existent gangtise-stockpool-client.zip) and extract the nested subdirectory.
---
ISSUE-003 — token is invalid when Authorization header has double Bearer prefix
Status: Not an upstream bug — it's a common mistake when integrating with the Gangtise OpenAPI from third-party code.
Symptom: User's integration code calls a Gangtise API endpoint with a valid accessToken but gets back:
{"code":"0000001008","status":false,"msg":"token is invalid"}…despite having just successfully authenticated and received a token from loginV2.
Root cause: The loginV2 response returns an accessToken value that already includes the Bearer prefix:
{"data":{"accessToken":"Bearer REDACTED-TOKEN-EXAMPLE",...}}Many integration guides for other OAuth APIs tell developers to "prepend Bearer to the token when setting the Authorization header". If a developer does this mechanically, they end up with:
Authorization: Bearer Bearer REDACTED-TOKEN-EXAMPLE…which Gangtise's auth middleware correctly rejects as invalid.
Impact: Every subsequent API call (RAG search, data queries, workflow invocations) fails with token is invalid, and the user thinks their credentials are broken when actually their integration code is wrong.
Why upstream probably hasn't "fixed" it: The API contract is consistent — accessToken is a full, ready-to-use Authorization header value. A developer who reads the Gangtise OpenAPI docs carefully will understand this. The mistake comes from developers copying OAuth integration patterns from other APIs.
How to explain it to the user (plain language):
Gangtise'sloginV2endpoint returns a token that already starts with the wordBearer. If you're copying OAuth integration patterns from Stripe or GitHub, you might be adding anotherBeareron top of it. Check your Authorization header — if it saysBearer Bearer <token>, remove one of them.
Repair strategy:
When integrating with Gangtise manually, use this pattern:
# CORRECT
raw_token = response.json()["data"]["accessToken"]
# raw_token already looks like "Bearer fb335616-..."
headers = {"Authorization": raw_token}
# WRONG
raw_token = response.json()["data"]["accessToken"]
headers = {"Authorization": f"Bearer {raw_token}"} # ❌ double prefixOr, defensively, strip any existing prefix first:
raw_token = response.json()["data"]["accessToken"]
bare_token = raw_token.replace("Bearer ", "", 1)
headers = {"Authorization": f"Bearer {bare_token}"}This issue does not affect gangtise-copilot itself — the wrapper's scripts do not touch the Authorization header directly because they delegate to each skill's own utils.py, which handles the token correctly. But if you're writing custom Gangtise integration code alongside the wrapper, watch for this.
---
ISSUE-004 — the uri can't be accessed on skills-backend admin endpoints
Status: Observed as of April 2026. Not a bug — an intentional access restriction.
Symptom: User tries to enumerate Gangtise's skill catalog by calling /application/skills-backend/list or similar admin endpoints with a valid Bearer token and gets:
{"code":"0000001009","status":false,"msg":"the uri can't be accessed"}Root cause: The skills-backend service is an internal admin API that is not exposed to regular OpenAPI users. The loginV2 auth path mints tokens with data-query scopes (rag, data, file, openapi) but not skills-backend-admin scope. Even with a valid token, regular users cannot list the skill manifest.
Impact: A developer trying to build a Gangtise skill listing tool by calling the admin API directly will be blocked. This is why gangtise-copilot's installer uses a hard-coded bundle list instead of querying a live manifest — the live manifest is not accessible.
Why upstream probably hasn't "fixed" it: This is a deliberate security boundary. skills-backend is the admin interface Gangtise's own internal tooling uses; exposing it to OpenAPI clients would leak information about internal skill naming, versioning, and distribution paths that isn't meant to be public.
How to explain it to the user (plain language):
Gangtise has an internal API for listing all available skills, but it's locked down — your OpenAPI account can't call it. The gangtise-copilot installer works around this by maintaining a hard-coded list of the 19 known skills. If Gangtise releases a new skill, the installer needs to be updated by hand (or you'll hit ISSUE-005).Repair strategy: None needed on the user side. gangtise-copilot maintains the bundle list in install_gangtise.sh and updates are pushed via the wrapper's own release cycle. Users who want to discover new skills should check the Gangtise OpenAPI portal or ask their Gangtise account administrator.
---
ISSUE-005 — New upstream skill added after installer release
Status: Hypothetical — hasn't happened yet, but will happen eventually.
Symptom: Gangtise releases a new skill (e.g., gangtise-hotspot-tracker) that isn't in gangtise-copilot's bundle map. Users who ran the installer before this release do not get the new skill. There is no automatic notification.
Root cause: ISSUE-004 combined with the lack of a public release feed from Gangtise. The installer can't enumerate the bucket; Gangtise doesn't publish RSS/webhook notifications for new skills.
Impact: Gradual drift between gangtise-copilot's bundle map and upstream reality. Users think they have "all Gangtise skills" but they actually have "all Gangtise skills as of the last wrapper release".
Why upstream probably hasn't "fixed" it: Because ISSUE-004. Upstream would need to open a public manifest feed or a release notification channel, which they currently don't offer.
How to explain it to the user (plain language):
gangtise-copilothas a hard-coded list of 19 Gangtise skills that were known to exist as of the wrapper's last release. If Gangtise publishes new skills after that, you won't get them automatically. When you hear about a new Gangtise skill, either updategangtise-copilotto the latest version (which should include the new skill) or install the new skill manually withcurl + unzipfrom the OBS URL.
Repair strategy:
- User side: File an issue on the
gangtise-copilotrepo mentioning the new skill's name (and, if known, its OBS URL). The maintainer will update the bundle map in the next release. - Manual fallback: Users who can't wait can do:
cd /tmp
curl -O https://gts-download.obs.myhuaweicloud.com/skills/gangtise-<new-skill>.zip
unzip gangtise-<new-skill>.zip -d $HOME/.claude/skills/
ln -sfn $HOME/.config/gangtise/authorization.json \
$HOME/.claude/skills/gangtise-<new-skill>/scripts/.authorizationThis installs the new skill manually; on the next gangtise-copilot upgrade the wrapper will take over management of it automatically (or the manual install will coexist harmlessly).
---
ISSUE-006 — CLI scripts fail after configure because ~/.GTS_AUTHORIZATION is missing
Status: Observed on 2026-04-12 while running a downstream data pipeline that imported -client scripts.
Symptom: diagnose.sh passes OAuth + RAG checks, but direct upstream CLI script calls fail at import time. Typical failure:
ImportError: cannot import name 'GTS_AUTHORIZATION' from 'utils'This was reproduced with:
python3 gangtise-data-client/scripts/quote.py --securities 宁德时代 -sd 2026-04-01 -ed 2026-04-10
python3 gangtise-file-client/scripts/report.py -k 宁德时代 -l 5
python3 gangtise-kb-client/scripts/kb.py -q "宁德时代" -l 5Root cause: Many upstream scripts read a bare token from ~/.GTS_AUTHORIZATION at module import time. The wrapper originally wrote only ~/.config/gangtise/authorization.json and per-skill .authorization symlinks. That is enough for OAuth verification, but not enough for scripts whose utils.py expects ~/.GTS_AUTHORIZATION.
Impact: A wrapper install can look healthy while the first real data call fails at runtime.
Repair strategy: Run the configurator after install. It now writes both:
~/.config/gangtise/authorization.json— durable accessKey + secretAccessKey config~/.GTS_AUTHORIZATION— short-lived bare runtime token for upstream CLI scripts
bash scripts/configure_auth.sh --verify-only
bash scripts/diagnose.shThe runtime token is refreshed every time configure_auth.sh succeeds.
---
ISSUE-007 — -client scripts default to skills-backend, which many OpenAPI accounts cannot access
Status: Observed 2026-04-12. Re-verified 2026-05-11: still reproducible. Confirmed not a token expiry / wiring issue — a freshly-minted OAuth token from loginV2 hits the same wall. The gateway-level ACL split appears permanent for accounts at certain license tiers; skills-backend/* likely requires a higher-tier license than the public open-* endpoints.
Symptom: After ~/.GTS_AUTHORIZATION exists and credentials are valid, the -client scripts start but every data/file/kb call returns:
{"code":"0000001009","status":false,"msg":"the uri can't be accessed"}Note: Error code is 1009 (uri ACL rejection), not 1008 (token invalid). If you see 1008, your token is genuinely expired — refresh via configure_auth.sh first. Only after seeing a fresh 1009 should you suspect this issue.
Root cause: gangtise-data-client, gangtise-file-client, gangtise-kb-client, gangtise-file-client-no-download, gangtise-stockpool-client, and gangtise-web-client all default GANGTISE_DOMAIN to https://open.gangtise.com/application/skills-backend. Regular OpenAPI credentials can authenticate (OAuth loginV2 returns a valid token) and may have RAG/data/file scope, but are blocked at the gateway from calling this skills-backend route — confirmed by the fact that a freshly-minted OAuth token still returns 1009. The legacy openapi skills (gangtise-data, gangtise-file, gangtise-kb) use public endpoints such as open-data, open-quote, open-fundamental, and work on the same account with the same credentials.
Impact: Affected accounts cannot use any of the 6 -client skills or the 9 workflow skills that wrap them — 16 of the 19 skills in the catalog become non-functional. The 3 legacy open-* skills (gangtise-data, gangtise-file, gangtise-kb) still work and form the realistic working surface. --preset minimal (now the default) installs exactly these 3.
Observed working commands:
python3 ~/.local/share/gangtise-copilot/skills/gangtise-data/scripts/quote.py \
--securities 300750.SZ -sd 2026-03-13 -ed 2026-04-11 --limit 100
python3 ~/.local/share/gangtise-copilot/skills/gangtise-file/scripts/report.py \
-k 宁德时代 --securities 300750.SZ -sd 2026-03-13 -ed 2026-04-11 -l 8 --rank_type 2
python3 ~/.local/share/gangtise-copilot/skills/gangtise-kb/scripts/kb.py \
-q "宁德时代 近30天 研报 共识 分歧" -sd 2026-03-13 -ed 2026-04-11 \
--file-types 研究报告,公司公告,会议纪要,调研纪要,首席观点 -l 8How to confirm this is your symptom (vs. a token problem):
# 1. Get a fresh OAuth token directly
FRESH=$(curl -sS -X POST "https://open.gangtise.com/application/auth/oauth/open/loginV2" \
-H "Content-Type: application/json" \
-d "{\"accessKey\":\"$AK\",\"secretAccessKey\":\"$SK\"}" \
| python3 -c "import json,sys;print(json.load(sys.stdin)['data']['accessToken'])")
# 2. Hit a skills-backend endpoint with the fresh token
curl -sS -X POST "https://open.gangtise.com/application/skills-backend/search/quote" \
-H "Authorization: $FRESH" -H "Content-Type: application/json" -d '{}'
# Expect: {"code":"0000001009","msg":"the uri can't be accessed"} → confirms ACL block
# 3. Hit a public endpoint with the SAME fresh token
curl -sS -X POST "https://open.gangtise.com/application/open-quote/kline/daily" \
-H "Authorization: $FRESH" -H "Content-Type: application/json" \
-d '{"securityList":["600519.SH"],"startDate":"2026-05-01","endDate":"2026-05-09"}'
# Expect: real K-line data → confirms token is valid, only the route is blockedIf step 2 returns 1009 AND step 3 returns real data, you have ISSUE-007. Workaround below.
Repair strategy:
- If you confirmed ISSUE-007 with the diagnostic above, the default `--preset minimal` is what you want. It installs only the 3 legacy skills (
gangtise-data,gangtise-file,gangtise-kb), which together cover OHLC + financials + announcements + foreign reports + RAG retrieval. This is the realistic working surface for accounts blocked atskills-backend/*. (--preset workshopis an alias forminimaland installs the same 3 skills.) - Avoid `--preset full` if you're affected — it works (it includes the 3 legacy skills) but pollutes the install with 16 skills that error on every call.
- Workflow skills that wrap
-client(e.g.gangtise-stock-research,gangtise-opinion-pk,gangtise-event-review) are also blocked because they invoke-clientscripts internally. The only workflow that bypassesskills-backendat the code level isgangtise-announcement-digest— but it requires a separategangtise_tokencredential, and the route it calls (application/investReport/api/queryClueListBySecurity) is also1009-blocked for affected accounts (confirmed with a fresh OAuth token). diagnose.shshowingOAuth liveness ✅+RAG liveness ✅is misleading for ISSUE-007 — those checks only validate the public RAG endpoint (open-data/ai/search/knowledge_base), not any-clientskill code path. A user can see all green diagnostics yet have 16/19 skills blocked at runtime.- Do not patch upstream scripts silently. A future wrapper revision may add a
client-livenesscheck that probesskills-backend/*directly and emits a clear ISSUE-007 verdict indiagnose.sh. - Record this fallback in any deployment runbook so a future agent does not waste time debugging valid credentials.
Adding new issues to this file
When you discover a new issue worth capturing:
1. Assign the next sequential ISSUE-<NNN> number. 2. Fill in the same schema: symptom, root cause, impact, plain-language explanation, at least one repair strategy with idempotent commands. 3. Update scripts/diagnose.sh if the issue has a detectable symptom — add a new scan_issue_NNN function that returns a distinct status code. 4. Do not vendor or patch upstream files as part of a repair. Keep all fixes at the wrapper layer or as documented runtime commands the user executes with explicit consent.
Gangtise Copilot — Skill Registry Reference
Complete per-skill capability matrix for all 19 Gangtise OpenAPI skills. Read this when you need to look up which skill answers a specific data question, or when you're routing a user request to the right upstream skill.
How to use this reference
The matrix is organized into 4 tiers:
1. Data-layer skills (6) — raw data retrieval: financials, valuations, OHLC quotes, file searches 2. Web layer (1) — public web search via Gangtise's own web service 3. Utility skills (2) — stock pool CRUD + a no-download file-client variant 4. Research workflow skills (10) — higher-order workflows that orchestrate the data layer into end-to-end investment research reports
Each skill row shows the canonical install path, version, script count, and a one-line description of what it's best for. Full script parameters are in the upstream SKILL.md under each skill's own directory.
Data-layer skills (6)
gangtise-data-client v1.1.2 ⭐ RECOMMENDED
What it does: Structured quantitative data retrieval with 9 capabilities. Accepts security names ("宁德时代") or codes ("300750.SZ") and auto-resolves to the correct standard code.
| Capability | Script | Use for |
|---|---|---|
| Security resolution | security.py | Look up code + basic info + concepts for a named entity |
| Sector constituents | block_component.py | List stocks in a theme or industry (-k 新能源汽车) |
| Index catalog | index.py | List all indices by category (-k 行业指数) |
| Financial statements | financial.py | Pull income / balance / cash flow indicators (--indicators 营业收入,净利润) |
| Industry indicators | industry_indicator.py | Macro data + industry metrics (GDP, CPI, 新能源汽车销量) |
| Main business composition | main_business.py | Revenue breakdown by product / industry / region |
| OHLC daily quote | quote.py | Historical daily candles (开高低收, 前复权) |
| Shareholder data | shareholder.py | Top-10 shareholders + circulating shareholders |
| Valuation metrics | valuation.py | PE / PS / PB / PEG / EV + historical percentiles |
gangtise-data v1.2.0 (legacy minimal)
What it does: A slimmed-down quantitative data skill with 4 capabilities. Requires strict security codes (600519.SH format) — does not resolve names. Output is explicitly CSV-focused for batch quantitative workflows.
| Capability | Script | Use for |
|---|---|---|
| Valuation | valuation.py | Same data as data-client, strict code input |
| OHLC quote | quote.py | Same data as data-client, supports --all-market |
| Main business | main_business.py | Same as data-client, requires --period Q2 or --period Q4 |
| Financial statements | financial.py | Same as data-client, income statement only |
When to use the minimal line instead: Batch CSV pipelines where strict code input is a feature (prevents ambiguous name resolution at scale). Not recommended for interactive or workshop use.
gangtise-kb-client v1.1.2 ⭐ RECOMMENDED
What it does: Semantic search across Gangtise's internal knowledge base (research reports, chief opinions, meeting summaries, etc.). Returns relevant text chunks, not file IDs.
| Script | Key parameters | Use for |
|---|---|---|
kb.py | -q 查询语句 --file-types "研究报告,首席观点,会议纪要" --securities "宁德时代" -l 20 | Find what documents actually say about a topic, for a specific security or time range |
When to use: When you want to read / cite / summarize the text content of research materials. If you want to list or download specific files instead, use gangtise-file-client.
gangtise-kb v1.1.2 (legacy minimal)
Same functionality as gangtise-kb-client but without the client-style parameter extensions. Use the client version unless you have a specific reason.
gangtise-file-client v1.1.2 ⭐ RECOMMENDED
What it does: File-center search across 10 document types. Returns file IDs + metadata + summaries. This is the richest skill in the catalog at 18 scripts.
| Script | Use for |
|---|---|
report.py | Research reports by keyword / security / date / broker / industry / rating |
foreign_report.py | Overseas (US/HK listed) research reports |
announcement.py | Company announcements |
summary.py | Meeting minutes (earnings calls, site visits, strategy meetings) |
opinion.py | Chief analyst opinions |
investment_calendar.py | Roadshows, site visits, strategy meetings, forums |
chart.py / get_chart.py | ⭐ Chart data (not in the minimal variant) |
internal_report.py + internal_report_types.py | ⭐ Internal research reports (not in minimal) |
wechat_message.py + wechat_message_blocks.py | ⭐ WeChat messages — group chat content (not in minimal) |
opinion_blocks.py | ⭐ Opinion content blocks (not in minimal) |
report_industries.py / report_types.py / announcement_types.py / summary_types.py / summary_industries.py | Enumeration helpers to get valid industry / type values before calling the main scripts |
get_file.py | Download a file by ID to local disk |
gangtise-file v1.1.3 (legacy minimal)
Same file-type coverage as gangtise-file-client for the 6 core types (reports, opinions, summaries, announcements, etc.) but missing 7 scripts: chart, internal_report, wechat_message, opinion_blocks, and several enumeration helpers. Use the client version unless you specifically need the smaller footprint.
Web layer (1)
gangtise-web-client v1.1.2
What it does: Public web search via Gangtise's own web search service. Used for information that doesn't exist inside Gangtise's internal knowledge base — breaking news, third-party articles, policy announcements.
| Script | Use for |
|---|---|
web.py | -q 查询 to search the open web |
Not a Google wrapper — this is Gangtise's own indexing service. Returns the same document-chunk shape as the internal RAG.
Utility skills (2, bundle-only)
gangtise-stockpool-client v1.1.2
Only distributed inside `gangtise-skills-client.zip`. Standalone ZIP does not exist.
What it does: Stock pool (watchlist) management. List, create, rename, delete pools; add or remove constituent stocks.
| Operation | Use for |
|---|---|
| List pools | See what watchlists your account has |
| Create pool | scripts/create_stockpool.py --name "新能源车" --stocks "比亚迪,宁德时代" |
| Add to pool | Append stocks to an existing pool |
| Remove from pool | Remove by code |
| Delete pool | Delete entirely |
gangtise-file-client-no-download v1.1.2
Only distributed inside `gangtise-skills-client.zip`. Standalone ZIP does not exist.
What it does: Same as gangtise-file-client but with the download capability disabled. Use this in read-only or compliance-sensitive environments where users should be able to search documents but not pull them to local disk.
Research workflow skills (10)
These skills are business-logic orchestrators. Each one reads its upstream SKILL.md, follows a documented workflow, and invokes the underlying data-layer skills in a prescribed order to produce an end-to-end research deliverable. All 10 produce Markdown + HTML output and enforce Gangtise's compliance guardrails (no "买入 / 卖出 / 目标价 / 加仓 / 梭哈" language).
gangtise-stock-research v1.1.2 ⭐ FLAGSHIP
Individual stock research report with 4 depth levels:
| Level | Scope | Triggered by |
|---|---|---|
| L1 | One-page recognition framework | "快速研究", "一页纸", "L1" |
| L2 | Complete investment view | "研究一下", "分析报告", "L2" |
| L3 | Institutional-grade first coverage | "深度报告", "首次覆盖", "L3" |
| L4 | Update on existing report | "财报更新", "跟踪一下", "L4" |
Data dependencies (this skill calls all of these):
data-client/security.py— base company datadata-client/financial.py— income statement metricsdata-client/main_business.py— product breakdowndata-client/valuation.py— PE/PS/PB percentilesdata-client/quote.py— past 1-year OHLCkb-client/kb.py— semantic search of research reports + opinions + minutesfile-client/report.py— last 3 months of reportsfile-client/opinion.py— chief opinions
And at L2+, additionally:
data-client/shareholder.py— top-10 holdersdata-client/industry_indicator.py— industry metricsfile-client/summary.py— meeting minutesfile-client/announcement.py— past 6 months of announcements
And at L3, additionally:
data-client/block_component.py— sector constituents for comparable analysis- Comparable company valuation table
gangtise-opinion-pk v1.1.2 ⭐ FLAGSHIP
Adversarial opinion analysis — "play devil's advocate" for an investment thesis. 5-step workflow:
1. Parse user intent — extract entity, entity type (STOCK / INDUSTRY / MACRO), sentiment (POSITIVE / NEGATIVE / NEUTRAL), rebuttal strategy 2. Generate ~10 multi-dimensional search queries tailored to the rebuttal strategy 3. Fan out data retrieval across data-client + kb-client + file-client + web-client 4. Write 4-section adversarial report (HTML template with dimensions / timeline_items / stress_tests / risk_signals placeholders) 5. Output MD + HTML
When to use: When the user says "帮我泼泼冷水", "有什么风险", "有什么机会", "对抗分析", "魔鬼代言人", or simply names a stock in neutral context (the workflow defaults to risk-focused analysis for neutral input).
gangtise-thematic-research v1.1.2
Sector / theme research. Covers: theme definition, selection rationale, drivers, performance phases, stock screening, performance verification, strength assessment, risks. Outputs MD + HTML.
gangtise-stock-selector v1.1.2
Stock screening methodology. Supports 4 common patterns (financial quality, growth, value, event-driven). Produces a screened list with scoring.
gangtise-event-review v1.1.2
Market event post-mortem — 800-1000 word professional investment-research style report on a news event / policy change / earnings announcement / site visit.
gangtise-interview-outline v1.1.2
Company-meeting interview outline generator. 3-step workflow: information gathering → topic classification → question list. Used before a site visit or management meeting.
gangtise-announcement-digest v1.1.2 ⭐ RECOMMENDED FOR DAILY DIGEST USE CASES
Announcement tracking + digest. Takes a stock pool (Excel / CSV / code list) as input and produces a daily digest with two sections: (1) announcements relevant to your pool in the past 3 days, and (2) market-wide important announcements with type breakdown. Output is structured, conclusion-first, with drill-down links.
gangtise-opinion-summarizer v1.1.2
Chief analyst opinion summarizer. Aggregates recent opinions from a named analyst, a named broker, or a named security / industry and produces a structured summary with per-opinion attribution.
gangtise-wechat-summary v1.1.2 (oldest skill — 3/23 timestamp)
WeChat group chat → investment daily. Takes raw group chat export, classifies messages, tags them, and produces a structured investment daily in MD + HTML.
Interesting metadata: This skill has a Last-Modified timestamp of 2026-03-23 on the Gangtise OBS bucket, while every other skill in the catalog shows 2026-04-10. It is the oldest skill in the collection and likely the origin point of the workflow-skill pattern Gangtise later generalized into the 10-skill research suite.
gangtise-data-processor v1.1.2
Meta-skill — provides methodology guidance for designing custom data-processing workflows. Does not itself call any data APIs; instead, it teaches the agent how to assemble the other skills into a custom pipeline (e.g., "get a sector list, rank by a metric, filter by another metric, output a report").
Cross-skill composition examples
The real power of the catalog comes from combining skills. Here are three concrete compositions:
Composition 1: Single-stock institutional research
User: "Research <SECURITY> at L2 depth"
└── gangtise-stock-research (workflow)
├── gangtise-data-client/security.py
├── gangtise-data-client/financial.py
├── gangtise-data-client/main_business.py
├── gangtise-data-client/valuation.py
├── gangtise-data-client/quote.py
├── gangtise-data-client/shareholder.py
├── gangtise-data-client/industry_indicator.py
├── gangtise-kb-client/kb.py (×20 queries)
├── gangtise-file-client/report.py
├── gangtise-file-client/opinion.py
├── gangtise-file-client/summary.py
└── gangtise-file-client/announcement.py
└── Output: <SECURITY>_研究_<DATE>.md + <SECURITY>_研究_<DATE>.htmlComposition 2: Adversarial review of your own thesis
User: "I'm long <SECURITY> because of <THESIS>. Find risks."
└── gangtise-opinion-pk (workflow)
├── Parse: entity=<SECURITY>, type=STOCK, sentiment=POSITIVE, strategy=FIND_RISKS
├── Generate 10 risk-focused queries
├── gangtise-data-client/security.py + financial.py + valuation.py + quote.py
├── gangtise-kb-client/kb.py (for each of 10 queries, file-types=研究报告,首席观点,会议纪要)
├── gangtise-file-client/report.py + opinion.py
└── gangtise-web-client/web.py (for public-web counterpoints)
└── Output: <SECURITY>_观点PK_<DATE>.md + <SECURITY>_观点PK_<DATE>.html
(with risk signals, timeline, stress tests, core contradiction)Composition 3: Daily digest machine
User: "Watch my portfolio daily"
└── gangtise-announcement-digest (workflow)
├── Read stock pool from Excel
├── gangtise-file-client/announcement.py (×N stocks, past 3 days)
├── Classify announcements by importance
└── Generate daily digest MD + HTML
└── Output: pipe to a chat bot / email / wiki via your own webhook (downstream wiring is out of scope)Compliance notes
Every workflow skill enforces these hard rules, copied from Gangtise's own compliance policy:
- Forbidden language: "推荐", "买入", "卖出", "目标价", "加仓", "潜伏", "建仓", "重仓", "梭哈"
- Required substitutions: 买入 → "关注" / "拥抱"; 卖出 → "警惕" / "风险释放"
- No stock-price predictions — analysis is limited to business-relevant factors
- Disclaimer required: "本分析基于公开数据,不构成投资建议"
If you're using these skills for a client-facing workshop, leave the compliance rules alone — they exist for good regulatory reasons.
#!/usr/bin/env bash
#
# configure_auth.sh — Set up Gangtise OpenAPI credentials + verify against
# the live authentication server + symlink each installed skill's
# scripts/.authorization to the shared XDG config file.
#
# Flow:
# 1. Read accessKey + secretAccessKey (from env vars, from flag, or
# prompt interactively)
# 2. Write to ~/.config/gangtise/authorization.json with mode 600
# 3. Write ~/.GTS_AUTHORIZATION runtime token for upstream CLI scripts
# 4. Perform a live auth call against open.gangtise.com to verify
# the credentials actually work (body-shape check, not just HTTP code)
# 5. Scan the canonical install location for installed skills
# 6. Create or refresh each skill's scripts/.authorization as a symlink to
# the shared XDG file
#
# Re-run safely — every step is idempotent.
set -euo pipefail
XDG_CONFIG_DIR="${XDG_CONFIG_HOME:-$HOME/.config}/gangtise"
AUTH_FILE="${XDG_CONFIG_DIR}/authorization.json"
RUNTIME_TOKEN_FILE="$HOME/.GTS_AUTHORIZATION"
CANONICAL_ROOT="${GANGTISE_COPILOT_HOME:-$HOME/.local/share/gangtise-copilot}"
CANONICAL_SKILLS_DIR="${CANONICAL_ROOT}/skills"
AUTH_ENDPOINT="https://open.gangtise.com/application/auth/oauth/open/loginV2"
# ============================================================================
# Usage
# ============================================================================
usage() {
cat <<'EOF'
Usage: configure_auth.sh [OPTIONS]
Configure Gangtise OpenAPI credentials and verify against the live server.
Options:
--access-key KEY Provide accessKey directly (otherwise prompt or env var)
--secret-key KEY Provide secretAccessKey directly
--verify-only Skip prompt; just re-run the live verification with
the credentials already on disk
--show Display the current credential file path and shape
(does not print the secret)
-h, --help Show this help
Environment variables:
GANGTISE_ACCESS_KEY If set, used as the default accessKey
GANGTISE_SECRET_ACCESS_KEY If set, used as the default secretAccessKey
Where credentials are stored:
~/.config/gangtise/authorization.json (single source of truth, mode 600)
~/.GTS_AUTHORIZATION (runtime token for upstream CLI scripts, mode 600)
Each installed Gangtise skill has a symlink at
<canonical>/scripts/.authorization → this file.
Rotating credentials:
Edit ~/.config/gangtise/authorization.json directly, then re-run:
bash configure_auth.sh --verify-only
EOF
}
# ============================================================================
# Parse flags
# ============================================================================
ACCESS_KEY_ARG=""
SECRET_KEY_ARG=""
VERIFY_ONLY=0
SHOW_ONLY=0
while [ $# -gt 0 ]; do
case "$1" in
--access-key) ACCESS_KEY_ARG="$2"; shift 2 ;;
--access-key=*) ACCESS_KEY_ARG="${1#*=}"; shift ;;
--secret-key) SECRET_KEY_ARG="$2"; shift 2 ;;
--secret-key=*) SECRET_KEY_ARG="${1#*=}"; shift ;;
--verify-only) VERIFY_ONLY=1; shift ;;
--show) SHOW_ONLY=1; shift ;;
-h|--help) usage; exit 0 ;;
*) echo "✗ unknown argument: $1" >&2; usage >&2; exit 1 ;;
esac
done
# ============================================================================
# Prerequisite checks
# ============================================================================
if ! command -v curl >/dev/null 2>&1; then
echo "✗ Required tool not found: curl" >&2
exit 1
fi
# python3 is used only for JSON parsing of the auth response. If not available,
# we fall back to a grep-based shape check.
HAS_PYTHON=0
if command -v python3 >/dev/null 2>&1; then
HAS_PYTHON=1
fi
# ============================================================================
# --show mode
# ============================================================================
if [ "$SHOW_ONLY" -eq 1 ]; then
if [ ! -f "$AUTH_FILE" ]; then
echo "✗ No credential file at $AUTH_FILE"
echo " Run: bash $(basename "$0") (without --show)"
exit 1
fi
echo "Credential file: $AUTH_FILE"
echo "Mode: $(stat -f '%Lp' "$AUTH_FILE" 2>/dev/null || stat -c '%a' "$AUTH_FILE" 2>/dev/null || echo "?")"
echo "Shape:"
if [ "$HAS_PYTHON" -eq 1 ]; then
python3 -c "
import json, sys
with open('$AUTH_FILE') as f:
d = json.load(f)
for k in d:
v = d[k]
if isinstance(v, str) and len(v) > 8:
v = v[:4] + '...' + v[-4:]
print(f' {k}: {v}')
" 2>/dev/null || cat "$AUTH_FILE"
else
cat "$AUTH_FILE"
fi
exit 0
fi
# ============================================================================
# Gather credentials (flag → env var → interactive prompt)
# ============================================================================
if [ "$VERIFY_ONLY" -eq 1 ]; then
if [ ! -f "$AUTH_FILE" ]; then
echo "✗ --verify-only requires $AUTH_FILE to already exist" >&2
exit 1
fi
ACCESS_KEY=""
SECRET_KEY=""
# Extract from existing file
if [ "$HAS_PYTHON" -eq 1 ]; then
ACCESS_KEY=$(python3 -c "import json; print(json.load(open('$AUTH_FILE')).get('accessKey',''))" 2>/dev/null || true)
SECRET_KEY=$(python3 -c "import json; print(json.load(open('$AUTH_FILE')).get('secretAccessKey',''))" 2>/dev/null || true)
fi
if [ -z "$ACCESS_KEY" ] || [ -z "$SECRET_KEY" ]; then
echo "✗ Could not extract accessKey/secretAccessKey from $AUTH_FILE" >&2
echo " The file may use the long-term-token shape, which can't be verified by re-auth." >&2
exit 1
fi
else
ACCESS_KEY="${ACCESS_KEY_ARG:-${GANGTISE_ACCESS_KEY:-}}"
SECRET_KEY="${SECRET_KEY_ARG:-${GANGTISE_SECRET_ACCESS_KEY:-}}"
if [ -z "$ACCESS_KEY" ]; then
echo "▶ Enter your Gangtise accessKey:"
echo " (Get this from your Gangtise account administrator or the Gangtise OpenAPI portal.)"
read -r ACCESS_KEY
fi
if [ -z "$SECRET_KEY" ]; then
echo "▶ Enter your Gangtise secretAccessKey:"
# Hide input — the secret should not be echoed to the terminal.
stty -echo 2>/dev/null || true
read -r SECRET_KEY
stty echo 2>/dev/null || true
echo
fi
if [ -z "$ACCESS_KEY" ] || [ -z "$SECRET_KEY" ]; then
echo "✗ Both accessKey and secretAccessKey are required" >&2
exit 1
fi
fi
# ============================================================================
# Live authentication call — verify credentials actually work
# ============================================================================
# This probes the OAuth endpoint, which is the lowest-privilege operation in
# the Gangtise OpenAPI. Passing this proves the keys exist and are valid, but
# does NOT prove the account has `rag` / `data` / `file` scopes. Those are
# checked separately in diagnose.sh.
echo "▶ Verifying credentials against $AUTH_ENDPOINT"
payload=$(printf '{"accessKey":"%s","secretAccessKey":"%s"}' "$ACCESS_KEY" "$SECRET_KEY")
response=$(curl -sS -X POST "$AUTH_ENDPOINT" \
-H "Content-Type: application/json" \
--data "$payload" \
--max-time 20 2>&1) || {
echo "✗ Network error calling $AUTH_ENDPOINT" >&2
echo " Response: $response" >&2
exit 1
}
# Shape check: Gangtise returns 200 HTTP with a JSON body whose `code` field
# is "000000" on success and something else on failure. Matching on body shape
# (not HTTP status) is the only reliable check because the server returns 200
# even for invalid credentials.
success=0
user_name=""
uid=""
access_token=""
if echo "$response" | grep -q '"code":"000000"'; then
success=1
if [ "$HAS_PYTHON" -eq 1 ]; then
user_name=$(python3 -c "
import json, sys
try:
d = json.loads('''$response''')
print(d.get('data',{}).get('userName',''))
except Exception:
pass
" 2>/dev/null || true)
uid=$(python3 -c "
import json, sys
try:
d = json.loads('''$response''')
print(d.get('data',{}).get('uid',''))
except Exception:
pass
" 2>/dev/null || true)
access_token=$(python3 -c "
import json, sys
try:
d = json.loads('''$response''')
token = d.get('data',{}).get('accessToken','')
print(token.replace('Bearer ', '', 1))
except Exception:
pass
" 2>/dev/null || true)
fi
fi
if [ "$success" -ne 1 ]; then
echo "✗ Authentication rejected by Gangtise server" >&2
echo "" >&2
echo "Server response:" >&2
echo " $response" >&2
echo "" >&2
echo "Common causes:" >&2
echo " - accessKey typo (most common)" >&2
echo " - secretAccessKey typo" >&2
echo " - Keys revoked or expired on the Gangtise side" >&2
echo " - Account suspended / not provisioned for OpenAPI" >&2
exit 1
fi
echo "✓ Authentication successful"
[ -n "$user_name" ] && echo " userName: $user_name"
[ -n "$uid" ] && echo " uid: $uid"
# ============================================================================
# Write the runtime token file expected by upstream CLI scripts
# ============================================================================
if [ -n "$access_token" ]; then
tmp_runtime=$(mktemp "${RUNTIME_TOKEN_FILE}.XXXXXX")
printf "%s" "$access_token" > "$tmp_runtime"
command mv "$tmp_runtime" "$RUNTIME_TOKEN_FILE"
chmod 600 "$RUNTIME_TOKEN_FILE"
echo "✓ Runtime token written to $RUNTIME_TOKEN_FILE (mode 600)"
else
echo "⚠ Could not extract accessToken for $RUNTIME_TOKEN_FILE; CLI scripts may fail" >&2
fi
# ============================================================================
# Write the shared credential file (mode 600, XDG location)
# ============================================================================
if [ "$VERIFY_ONLY" -eq 0 ]; then
mkdir -p "$XDG_CONFIG_DIR"
chmod 700 "$XDG_CONFIG_DIR"
# Idempotent write — use a temp file so partial writes don't corrupt an
# existing credential file.
tmpfile=$(mktemp "${AUTH_FILE}.XXXXXX")
cat > "$tmpfile" <<EOF
{
"accessKey": "$ACCESS_KEY",
"secretAccessKey": "$SECRET_KEY"
}
EOF
command mv "$tmpfile" "$AUTH_FILE"
chmod 600 "$AUTH_FILE"
echo "✓ Credentials written to $AUTH_FILE (mode 600)"
fi
# ============================================================================
# Symlink every installed Gangtise skill's scripts/.authorization
# ============================================================================
if [ ! -d "$CANONICAL_SKILLS_DIR" ]; then
echo ""
echo "⚠ No canonical skill install found at $CANONICAL_SKILLS_DIR"
echo " Run install_gangtise.sh first to install Gangtise skills, then re-run this." >&2
exit 0
fi
linked_count=0
for skill_dir in "$CANONICAL_SKILLS_DIR"/gangtise-*; do
[ -d "$skill_dir" ] || continue
scripts_dir="$skill_dir/scripts"
if [ ! -d "$scripts_dir" ]; then
# Some bundle-only skills may not have a scripts/ subdirectory.
continue
fi
auth_link="$scripts_dir/.authorization"
# Idempotent replace — always remove any existing file/symlink before
# creating a fresh link. This handles the case where the user manually
# wrote an .authorization file and now wants the wrapper to manage it.
if [ -e "$auth_link" ] || [ -L "$auth_link" ]; then
# Back up non-symlink files before replacing.
if [ ! -L "$auth_link" ]; then
backup_dir="/tmp/gangtise-copilot-backups/$(date +%Y%m%d-%H%M%S)"
mkdir -p "$backup_dir"
command cp "$auth_link" "$backup_dir/$(basename "$skill_dir")-authorization.bak"
echo " ℹ Backed up manual $(basename "$skill_dir")/.authorization → $backup_dir"
fi
command rm -f "$auth_link"
fi
command ln -s "$AUTH_FILE" "$auth_link"
linked_count=$((linked_count + 1))
done
echo "✓ Symlinked $linked_count skill(s) to shared credential file"
echo ""
echo "Next step: verify the full install with"
echo " bash $(dirname "$0")/diagnose.sh"
#!/usr/bin/env bash
#
# diagnose.sh — Read-only health check for Gangtise Copilot installs.
#
# Prints one status line per check, then a summary.
#
# Exit codes:
# 0 — all checks passed
# 1 — one or more issues need user action
# 2 — diagnostic itself failed (network error, missing tooling)
#
# This script is strictly read-only. It never modifies files.
set -uo pipefail
CANONICAL_ROOT="${GANGTISE_COPILOT_HOME:-$HOME/.local/share/gangtise-copilot}"
CANONICAL_SKILLS_DIR="${CANONICAL_ROOT}/skills"
XDG_CONFIG_DIR="${XDG_CONFIG_HOME:-$HOME/.config}/gangtise"
AUTH_FILE="${XDG_CONFIG_DIR}/authorization.json"
RUNTIME_TOKEN_FILE="$HOME/.GTS_AUTHORIZATION"
AUTH_ENDPOINT="https://open.gangtise.com/application/auth/oauth/open/loginV2"
RAG_ENDPOINT="https://open.gangtise.com/application/open-data/ai/search/knowledge_base"
PASS=0; WARN=0; FAIL=0
status_ok() { echo "✅ $1"; PASS=$((PASS + 1)); }
status_warn() { echo "⚠️ $1"; WARN=$((WARN + 1)); }
status_fail() { echo "❌ $1"; FAIL=$((FAIL + 1)); }
status_info() { echo "ℹ️ $1"; }
echo "=== Gangtise Copilot diagnostic report ==="
echo
# ============================================================================
# Prerequisites
# ============================================================================
echo "--- Prerequisites ---"
for tool in curl; do
if command -v "$tool" >/dev/null 2>&1; then
status_ok "$tool installed"
else
status_fail "$tool NOT installed — Gangtise skills need this to call the API"
fi
done
HAS_PYTHON=0
if command -v python3 >/dev/null 2>&1; then
HAS_PYTHON=1
status_ok "python3 installed ($(python3 --version 2>&1))"
else
status_warn "python3 NOT installed — Gangtise skills use python scripts; install python3"
fi
echo
# ============================================================================
# Canonical install location
# ============================================================================
echo "--- Canonical install ---"
if [ -d "$CANONICAL_SKILLS_DIR" ]; then
installed_count=$(find "$CANONICAL_SKILLS_DIR" -maxdepth 1 -type d -name "gangtise-*" 2>/dev/null | wc -l | tr -d ' ')
status_ok "Canonical skills dir: $CANONICAL_SKILLS_DIR ($installed_count skill(s))"
else
status_fail "Canonical skills dir not found: $CANONICAL_SKILLS_DIR"
status_info "Run: bash install_gangtise.sh"
fi
echo
# ============================================================================
# Per-agent symlinks — which agents have been configured
# ============================================================================
echo "--- Agent installs ---"
AGENTS=()
[ -d "$HOME/.claude/skills" ] && AGENTS+=("claude-code:$HOME/.claude/skills")
[ -d "$HOME/.agents/skills" ] && AGENTS+=("codex:$HOME/.agents/skills")
for openclaw_path in "$HOME/.openclaw/skills" "$HOME/.config/openclaw/skills" "$HOME/.local/share/openclaw/skills"; do
if [ -d "$openclaw_path" ]; then
AGENTS+=("openclaw:$openclaw_path")
break
fi
done
if [ ${#AGENTS[@]} -eq 0 ]; then
status_warn "No supported agent skills directory detected"
status_info "Supported: ~/.claude/skills (Claude Code), ~/.openclaw/skills (OpenClaw), ~/.agents/skills (Codex)"
fi
for entry in "${AGENTS[@]}"; do
agent="${entry%%:*}"
skills_dir="${entry#*:}"
linked_count=0
broken_count=0
for link in "$skills_dir"/gangtise-*; do
[ -e "$link" ] || continue
if [ -L "$link" ]; then
target=$(readlink "$link" 2>/dev/null || echo "")
if [ -d "$target" ]; then
linked_count=$((linked_count + 1))
else
broken_count=$((broken_count + 1))
fi
else
# Non-symlink install — either a manual install or a pre-wrapper install
linked_count=$((linked_count + 1))
fi
done
if [ "$linked_count" -gt 0 ]; then
status_ok "$agent: $linked_count Gangtise skill(s) at $skills_dir"
else
status_warn "$agent: no Gangtise skills installed at $skills_dir"
fi
if [ "$broken_count" -gt 0 ]; then
status_fail "$agent: $broken_count broken symlink(s) — re-run install_gangtise.sh to repair"
fi
done
echo
# ============================================================================
# Credentials file
# ============================================================================
echo "--- Credentials ---"
if [ ! -f "$AUTH_FILE" ]; then
status_fail "Credential file missing: $AUTH_FILE"
status_info "Run: bash configure_auth.sh"
else
mode=""
if stat -f '%Lp' "$AUTH_FILE" >/dev/null 2>&1; then
mode=$(stat -f '%Lp' "$AUTH_FILE")
else
mode=$(stat -c '%a' "$AUTH_FILE" 2>/dev/null || echo "?")
fi
if [ "$mode" = "600" ]; then
status_ok "Credential file present with mode 600: $AUTH_FILE"
else
status_warn "Credential file has mode $mode (expected 600): $AUTH_FILE"
status_info "Fix: chmod 600 $AUTH_FILE"
fi
# Verify the credential file structure
if [ "$HAS_PYTHON" -eq 1 ]; then
shape=$(python3 -c "
import json, sys
try:
d = json.load(open('$AUTH_FILE'))
if 'long-term-token' in d:
print('long-term-token')
elif 'accessKey' in d and 'secretAccessKey' in d:
print('accessKey+secretAccessKey')
else:
print('unknown')
except Exception as e:
print('invalid')
" 2>/dev/null || echo "invalid")
case "$shape" in
long-term-token)
status_ok "Credential shape: long-term-token"
;;
accessKey+secretAccessKey)
status_ok "Credential shape: accessKey + secretAccessKey"
;;
invalid)
status_fail "Credential file is not valid JSON — fix with 'configure_auth.sh'"
;;
unknown)
status_warn "Credential file has unknown shape (neither long-term-token nor accessKey/secretAccessKey)"
;;
esac
fi
fi
echo
# ============================================================================
# Runtime token file used by upstream CLI scripts
# ============================================================================
echo "--- Runtime token file ---"
if [ -f "$RUNTIME_TOKEN_FILE" ]; then
mode=""
if stat -f '%Lp' "$RUNTIME_TOKEN_FILE" >/dev/null 2>&1; then
mode=$(stat -f '%Lp' "$RUNTIME_TOKEN_FILE")
else
mode=$(stat -c '%a' "$RUNTIME_TOKEN_FILE" 2>/dev/null || echo "?")
fi
if [ "$mode" = "600" ]; then
status_ok "Runtime token file present with mode 600: $RUNTIME_TOKEN_FILE"
else
status_warn "Runtime token file has mode $mode (expected 600): $RUNTIME_TOKEN_FILE"
status_info "Fix: chmod 600 $RUNTIME_TOKEN_FILE"
fi
else
status_warn "Runtime token file missing: $RUNTIME_TOKEN_FILE"
status_info "Run: bash configure_auth.sh --verify-only"
fi
echo
# ============================================================================
# Per-skill .authorization symlink integrity
# ============================================================================
echo "--- Per-skill .authorization symlinks ---"
if [ -d "$CANONICAL_SKILLS_DIR" ]; then
correct=0
missing=0
wrong_target=0
for skill_dir in "$CANONICAL_SKILLS_DIR"/gangtise-*; do
[ -d "$skill_dir" ] || continue
scripts_dir="$skill_dir/scripts"
[ -d "$scripts_dir" ] || continue
auth_link="$scripts_dir/.authorization"
if [ -L "$auth_link" ]; then
target=$(readlink "$auth_link" 2>/dev/null || echo "")
if [ "$target" = "$AUTH_FILE" ]; then
correct=$((correct + 1))
else
wrong_target=$((wrong_target + 1))
fi
elif [ -f "$auth_link" ]; then
# Manual file — not managed by wrapper, but functional
correct=$((correct + 1))
else
missing=$((missing + 1))
fi
done
if [ "$correct" -gt 0 ]; then
status_ok "$correct skill(s) have .authorization configured"
fi
if [ "$missing" -gt 0 ]; then
status_warn "$missing skill(s) missing .authorization — run configure_auth.sh"
fi
if [ "$wrong_target" -gt 0 ]; then
status_warn "$wrong_target skill(s) point at the wrong auth file — run configure_auth.sh to refresh"
fi
else
status_info "Skip (canonical install missing)"
fi
echo
# ============================================================================
# Liveness check 1: OAuth endpoint (proves credentials are valid)
# ============================================================================
echo "--- Live credential verification ---"
if [ ! -f "$AUTH_FILE" ]; then
status_info "Skip (credential file missing)"
elif [ "$HAS_PYTHON" -ne 1 ]; then
status_info "Skip (python3 not available — cannot parse credential file)"
else
ACCESS_KEY=$(python3 -c "import json; print(json.load(open('$AUTH_FILE')).get('accessKey',''))" 2>/dev/null || echo "")
SECRET_KEY=$(python3 -c "import json; print(json.load(open('$AUTH_FILE')).get('secretAccessKey',''))" 2>/dev/null || echo "")
if [ -z "$ACCESS_KEY" ] || [ -z "$SECRET_KEY" ]; then
status_info "Skip (credential file uses long-term-token shape — cannot re-auth for liveness check)"
else
payload=$(printf '{"accessKey":"%s","secretAccessKey":"%s"}' "$ACCESS_KEY" "$SECRET_KEY")
response=$(curl -sS -X POST "$AUTH_ENDPOINT" \
-H "Content-Type: application/json" \
--data "$payload" \
--max-time 20 2>&1 || echo "NETWORK_ERROR")
if [ "$response" = "NETWORK_ERROR" ]; then
status_fail "Cannot reach Gangtise auth server — network or firewall issue"
elif echo "$response" | grep -q '"code":"000000"'; then
status_ok "OAuth liveness (scope: auth) — credentials accepted"
# Extract token for the next liveness check
TOKEN=$(python3 -c "
import json
try:
d = json.loads('''$response''')
t = d.get('data',{}).get('accessToken','')
print(t)
except Exception:
pass
" 2>/dev/null || echo "")
# ================================================================
# Liveness check 2: RAG endpoint (proves 'rag' scope works —
# this is the scope most Gangtise skills need)
# ================================================================
if [ -n "$TOKEN" ]; then
rag_headers="Authorization: $TOKEN"
rag_response=$(curl -sS -X POST "$RAG_ENDPOINT" \
-H "$rag_headers" \
-H "Content-Type: application/json" \
--data '{"query":"test","top":1}' \
--max-time 20 2>&1 || echo "NETWORK_ERROR")
if [ "$rag_response" = "NETWORK_ERROR" ]; then
status_warn "Cannot reach RAG endpoint — network issue on scoped liveness check"
elif echo "$rag_response" | grep -q '"code":"000000"'; then
status_ok "RAG liveness (scope: rag) — knowledge base search is reachable"
else
status_warn "RAG endpoint rejected the request — your account may not have 'rag' scope"
status_info "Response: $(echo "$rag_response" | head -c 200)"
fi
fi
else
status_fail "Credentials rejected by Gangtise auth server"
status_info "Response: $(echo "$response" | head -c 200)"
status_info "Run: bash configure_auth.sh to re-enter credentials"
fi
fi
fi
echo
# ============================================================================
# Summary
# ============================================================================
echo "--- Summary ---"
echo " ✅ ${PASS} pass ⚠️ ${WARN} warn ❌ ${FAIL} fail"
echo
if [ "$FAIL" -gt 0 ]; then
echo "Next step: fix the ❌ items above, then re-run diagnose.sh."
echo "If you're not sure what a specific item means, check references/known_issues.md"
exit 1
fi
if [ "$WARN" -gt 0 ]; then
echo "Warnings are non-blocking, but the affected capabilities may not work."
echo "Review the ⚠️ items above and follow the suggested fix, or ignore if you're"
echo "aware of why they apply to your install."
exit 1
fi
echo "All checks passed. Gangtise Copilot install is healthy."
exit 0
Related skills
How it compares
Use gangtise-copilot when Gangtise is the authoritative market and research feed; pick a generic RAG skill when data comes from arbitrary documents or public APIs.
FAQ
What does gangtise-copilot help developers build?
gangtise-copilot helps developers build Gangtise-aware copilots that ingest market, company, and research signals for analyst workflows, automated briefings, or internal finance chat agents with sourced financial context.
Is gangtise-copilot only for chat interfaces?
gangtise-copilot covers chat agents and broader analyst workflows, including automated briefings and internal tooling that surfaces Gangtise signals on a schedule or in response to user queries.