CLAUDE.md · diff

git:20260924.582cb02 to git:20260924.27bf710

4 added, 4 removed. Audit B to B.

# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## Commands
```bash
npm test # Run all unit tests (skill/structure + install script)
npm run test:skills # Skill/structure tests only (270+ checks)
npm run test:install # install.sh tests (static checks + sandboxed runs)
npm run validate # Validate prompt file contents and format
npm run pre-release # Full pre-release check: pre-release-check + validate + test
npm run verify # Verify local setup is correct
npm run release:dry-run # Preview release without making changes
npm run integration-tests # Run integration tests
```
Validate JSON manifests manually:
```bash
jq empty plugins/us-stock-analysis/.claude-plugin/plugin.json
jq empty .claude-plugin/marketplace.json
```
## Architecture
InvestSkill is a **prompt-engineering plugin**, not traditional software. There is no application runtime — the "skills" are structured markdown frameworks that guide AI assistants through investment analysis workflows.
### Skill Distribution Model
Each skill lives in two forms simultaneously:
1. **`plugins/us-stock-analysis/skills/<name>/SKILL.md`** — Claude Code form, includes YAML frontmatter (`---\ndescription: ...\n---`) and uses slash command syntax
2. **`prompts/<name>.md`** — Universal form, identical content but with frontmatter stripped, AI-agnostic (no slash commands)
These two files must stay in sync. The `prompts/` version is what Cursor, Gemini CLI, GitHub Copilot, and ChatGPT users access.
### Platform Config Files
| File | Platform |
|------|----------|
| `plugins/us-stock-analysis/.claude-plugin/plugin.json` | Claude Code plugin manifest |
| `.claude-plugin/marketplace.json` | Claude marketplace listing |
| `.cursor/rules/invest-skill.mdc` | Cursor IDE auto-loading rules |
| `.github/copilot-instructions.md` | GitHub Copilot auto-loading |
| `GEMINI.md` | Gemini CLI auto-loading |
### Signal Block Requirement
Every SKILL.md and every `prompts/*.md` must close with the standardized Investment Signal section: the box-drawn block (UTF-8 box-drawing characters), followed only by the Score Guide / Confidence / Horizon lines, an optional one-paragraph mapping note, and the `**Disclaimer:**` line. Nothing else may follow the block. `check-skill-contract.js` and Test 5/7 validate the block's presence; the closing order is a convention every skill follows.
## Adding a New Skill (12-step process)
See `ADDING-NEW-SKILLS.md` for the full walkthrough. Key steps:
1. Create `plugins/us-stock-analysis/skills/<name>/SKILL.md` with frontmatter
2. Create `prompts/<name>.md` — same content, no frontmatter, no platform-specific syntax
3. Skills are auto-discovered from the `skills/` directory — no changes needed in `plugin.json`
4. Bump version in **all three**: `plugin.json`, `.claude-plugin/marketplace.json` (both `metadata.version` and the plugin entry), and `package.json` (must match — see Version Consistency Rule)
5. Update `.cursor/rules/invest-skill.mdc`, `.github/copilot-instructions.md`, `GEMINI.md` (table row + example + directory tree)
6. Update `README.md` and platform-specific `README-*.md` files (framework table row + count)
7. **Update the site** (both English and Traditional Chinese — see Site Update Rule)
8. Add entry to `CHANGELOG.md`
9. Run `npm run pre-release` (pre-release-check + validate + `npm test`) to confirm all tests pass
10. Run `npm run build:site` to confirm the site builds and the new skill lands in the right category
## Site Update Rule
The public site (`site/`) is generated by `site/build/build-site.js` and deployed by CI — the `_site/` output is gitignored, so you commit **source**, not built HTML. **Whenever a skill is added, renamed, or removed, update the site in the same change:**
1. **`site/build/build-site.js` → `SKILL_CATEGORIES`** — add the skill to the correct category so it appears in the right group on `skills.html` (an unlisted skill still renders, but falls into a generic "Other" bucket). Keep these categories mirroring the README's framework table.
2. **`site/content/CHOOSE-A-SKILL.md` and `CHOOSE-A-SKILL-zh-TW.md`** — add a "goal → skill" row so users can discover it (both languages).
3. **`site/content/COOKBOOK.md` and `COOKBOOK-zh-TW.md`** — update the framework count and, if the skill warrants it, add a usage recipe (both languages).
4. Per-skill reference pages (`skill-<name>.html`) are auto-generated from `prompts/<name>.md` — no manual page needed.
5. Run `npm run build:site` and confirm: `All N frameworks` shows the new count, `skill-<name>.html` is generated, and the skill is not stranded under "Other".
Always update **both** the English and Traditional Chinese (`-zh-TW`) variants of any site content file you touch.
## QA Report Retention Rule
The daily site review (`npm run review` / `.github/workflows/site-review.yml`) writes `qa/site_review_YYYYMMDD.md`. **Only the last 5 days are kept** — `scripts/site-review.js` prunes older reports on every run (`RETENTION_DAYS`), and the workflow stages `qa/` with `git add -A` so those deletions land in the same commit. `qa/PROJECT-REVIEW.md` is the hand-written qualitative review and is never pruned.
## Install Script Rule
`install.sh` is the one-command curl installer (`curl -fsSL .../install.sh | bash -s -- -a <agent>`). It is tested by `scripts/test-install.js` (`npm run test:install`) and by `.github/workflows/install-script.yml`.
When you touch `install.sh`:
1. **Adding or renaming an agent** means four places, or the tests fail: the `AGENTS` list in `install.sh`, its branch in the per-agent `case` block, its row in `list_agents()`, and the matching entry in `INSTALL_TARGETS` in `site/build/build-site.js` (id + advertised `path`). The parity checks in `scripts/test-install.js` compare all of these.
2. **Keep it shellcheck-clean** at `--severity=warning` (`shellcheck --severity=warning --shell=bash install.sh`) — CI fails otherwise.
3. **Never overwrite a user's file.** Existing instruction files are appended to inside the `MARK_BEGIN`/`MARK_END` block, and a second run must leave the tree byte-identical. Both properties are asserted.
4. `rm -rf` may only ever target the script's own `mktemp -d` directory (`$TMP`). Enforced by both the test suite and the lint job.
5. The tests run `install.sh` for real in a sandbox with a `curl` test double serving a tarball built from the working tree — no network, but the actual download → extract → copy → wire path executes. `KEEP_INSTALL_TEST_DIR=1` keeps the sandbox for inspection.
Documented curl commands in `README*.md` and `site/content/COOKBOOK*.md` are checked too: the URL must be the `raw.githubusercontent.com/yennanliu/InvestSkill/<ref>/install.sh` form and every `-a AGENT` must be a supported agent.
## Version Consistency Rule
All three version fields must match at all times:
- `plugins/us-stock-analysis/.claude-plugin/plugin.json` → `"version"`
- `.claude-plugin/marketplace.json` → `"metadata.version"` (and the plugin entry's `version`)
- `package.json` → `"version"`
Verify with: `jq '.version' plugins/us-stock-analysis/.claude-plugin/plugin.json && jq '.metadata.version' .claude-plugin/marketplace.json && jq '.version' package.json`
This is enforced by the consistency checks in `npm test`.
## Release Timing Rule
Choosing the version number and *when* to cut the release both matter — don't tag prematurely.
**Which number to bump (SemVer):**
- **MINOR** (`1.8.x → 1.9.0`) — a new skill/framework, or a meaningful new capability. (Adding `bear-case` and `position-ladder` were minor bumps.)
- **PATCH** (`1.9.0 → 1.9.1`) — fixes, doc/site tweaks, prompt refinements with no new skill.
- **MAJOR** (`1.x → 2.0.0`) — breaking changes to skill names, output contracts, or the plugin layout.
**When to stamp the date and tag:**
- The `## [X.Y.Z] - YYYY-MM-DD` heading in `CHANGELOG.md` must carry the **actual release date**, not the day you started the work. If the ship date is uncertain, keep the changes under `## [Unreleased]` and let the release step stamp the date when the release is actually cut.
- The git tag `vX.Y.Z` is created by `npm run release` (`release-interactive.js`), which commits the version bump, tags, and triggers CI. **Create the tag at release time — do not tag ahead of merge.** Preview first with `npm run release:dry-run`.
- Feature work lands on a branch → PR → merge to `main`; the tag/release is cut from `main` once merged. The manifest version can be bumped in the feature branch (tests require CHANGELOG ↔ manifest version parity), but the *tag* waits until the release is genuinely happening.
- Batch small changes: prefer one clean `1.9.0` release over tagging every intermediate commit. Cut the release when the set of changes is coherent and green (`npm run pre-release` passes).
## Framework Count Rule
- The **advertised framework count** = number of skills in `plugins/us-stock-analysis/skills/` **minus output-only tools** (`report-generator`) **minus alias/redirect stubs** (`fundamental-analysis`, `dcf-valuation`, `research-bundle`). It is currently **29 analysis frameworks** (33 skill directories − 1 output tool − 3 aliases). The classification lives in one place — `scripts/lib/skill-registry.js` (`OUTPUT_TOOLS`, `ALIAS_SKILLS`, `META_SKILLS`) — and is imported by `test-skills.js`, `test-install.js`, `check-skill-contract.js`, and `site/build/build-site.js`. The alias list is mirrored in `install.sh`'s `case` block (the install tests check parity).
+ The **advertised framework count** = number of skills in `plugins/us-stock-analysis/skills/` **minus output-only tools** (`report-generator`) **minus alias/redirect stubs** (`fundamental-analysis`, `dcf-valuation`, `research-bundle`). It is currently **30 analysis frameworks** (33 skill directories − 1 output tool − 3 aliases). The classification lives in one place — `scripts/lib/skill-registry.js` (`OUTPUT_TOOLS`, `ALIAS_SKILLS`, `META_SKILLS`) — and is imported by `test-skills.js`, `test-install.js`, `check-skill-contract.js`, and `site/build/build-site.js`. The alias list is mirrored in `install.sh`'s `case` block (the install tests check parity).
- Keep this number consistent across `README.md`, `README-zh-TW.md`, `site/content/CHOOSE-A-SKILL(-zh-TW).md`, `site/content/COOKBOOK(-zh-TW).md`, and `plugin.json`'s description.
- `site/build/build-site.js` derives it automatically (`FRAMEWORK_COUNT`) — never hardcode a count there.
- Enforced by the consistency checks in `npm test` (stale totals like 18/21 will fail):
- **Test 11** checks the six site-facing `COUNT_DOCS` for "N frameworks" claims.
- **Test 13** checks the cross-AI configs (`GEMINI.md`, `.cursor/rules/invest-skill.mdc`, `.github/copilot-instructions.md`) — every prompt must be referenced (a new skill can't be silently omitted from a platform), and every "N frameworks" claim must equal the advertised count. It also checks the COOKBOOK plugin-list skill counts equal the skill-directory count.
## Current State
- **Version**: 1.11.0 (plugin.json = marketplace.json = package.json)
- - **Skills**: 33 directories in `plugins/us-stock-analysis/skills/` (auto-discovered)
- - **Advertised frameworks**: 29 analysis frameworks (33 − `report-generator` − 3 aliases)
- - **Prompts**: 33 universal files in `prompts/` — **generated** from SKILL.md by `scripts/sync-prompts.js` (never hand-edit them; `--check` runs in `npm test`)
+ - **Skills**: 34 directories in `plugins/us-stock-analysis/skills/` (auto-discovered)
+ - **Advertised frameworks**: 30 analysis frameworks (33 − `report-generator` − 3 aliases)
+ - **Prompts**: 34 universal files in `prompts/` — **generated** from SKILL.md by `scripts/sync-prompts.js` (never hand-edit them; `--check` runs in `npm test`)
- **Node**: ≥18.0.0 required