| name | stock-research-publish |
| description | Publish a generated equity research report as either a professional PDF or a magazine-quality HTML page, then optionally deploy the HTML to Netlify and return a live URL. Use after the stock-research-pipeline has produced NLM query answers (Business Model, Industry, Management, Financials, Growth Triggers / VP, Risks / Bull-Base-Bear) for a SYMBOL, OR when the user says "publish report for [SYMBOL]", "deploy report to netlify", "html version of [SYMBOL] report", "ship the [SYMBOL] research", "make the [SYMBOL] report shareable", or "/stock-research-publish [SYMBOL]". Asks the user upfront whether they want PDF, HTML, or both. |
Stock Research Publish
Take the analysis outputs produced by stock-research-pipeline and turn them into a deliverable
the user can read or share. Two output modes — PDF (print-style) or HTML (web-style with optional
Netlify deploy). The user picks.
Prerequisites
- An NLM analysis already exists for the SYMBOL — i.e. the 6 query answers from
stock-research-pipeline are available in this session OR can be re-derived from
data/companies/{SYMBOL}/. If neither is true, run /stock-research-pipeline {SYMBOL} first.
- For PDF: Python venv at
.venv/ with reportlab installed.
- For HTML deploy:
netlify CLI on PATH OR a Netlify access token in $NETLIFY_AUTH_TOKEN.
If the CLI is missing, the skill installs it (with user confirmation) — see Step 4 pre-flight.
Requires npm on PATH (Node ≥ 18).
Step 1: Ask the user what they want
Use AskUserQuestion with one question, three options:
- PDF only — print-style A4 report (existing reportlab generator).
- HTML only — single-file, magazine-quality web page with optional Netlify deploy.
- Both — produce PDF first, then HTML, then ask about deploy.
Also ask whether to deploy the HTML to Netlify if HTML is selected (yes / no). Do not branch
on whether netlify is installed at this stage — the Step 4 pre-flight handles install + auth +
site name + deploy scope interactively.
Do not proceed until you have explicit answers. No defaults.
Step 2: Locate the analysis inputs
Resolve the SYMBOL from the user's request and gather the 6 NLM answers. Sources, in order:
- The current conversation (if
/stock-research-pipeline just ran in this session).
data/companies/{SYMBOL}/analysis/ — look for any of:
business_model.md, industry.md, management.md, financials.md, growth_triggers.md,
risks_scenarios.md, or a single nlm_answers.json if the pipeline saved one.
- As a last resort, re-run only the missing NLM queries from the pipeline (do NOT re-download
PDFs or recreate the notebook). Use the existing notebook ID from
data/companies/{SYMBOL}/analysis/notebook.txt if present.
If you can't gather all 6 answers, stop and ask the user to run /stock-research-pipeline first.
Also load data/companies/{SYMBOL}/screener_data.md for headline metrics (PE, ROE, ROCE, market
cap, latest revenue/PAT) — these populate the KPI cards.
Step 3a: PDF path
Use the existing reportlab generator at scripts/generators/equity_report_pdf.py (or, if absent,
the working reference at data/companies/GRAVITA/analysis/generate_report.py). Render to:
data/companies/{SYMBOL}/analysis/{SYMBOL}_Equity_Analysis_{YYYY-MM-DD}.pdf
Then open the file and tell the user the path. Done if PDF-only was chosen.
Step 3b: HTML path — design rules
Generate a single self-contained .html file (no external assets except Google Fonts and one
optional Mermaid CDN). Apply the visual-explainer playbook — these are not suggestions.
Aesthetic — pick ONE per generation. Vary across runs.
- Editorial (default for equity reports): Instrument Serif or Crimson Pro headlines,
IBM Plex Sans body, JetBrains Mono for monospace. Generous whitespace, deep navy + muted gold,
serif drop-caps on the executive summary.
- Blueprint: subtle grid background, deep slate/blue, monospace labels, precise borders.
Good for technical/cyclical companies.
- Paper/ink: warm cream
#faf7f5 background, terracotta + sage accents. Good for
consumer / FMCG names where warmth fits.
Forbidden — do not produce these.
- Inter / Roboto / system-ui as
--font-body. Pick a real pairing.
- Indigo/violet accents (
#8b5cf6, #7c3aed, #a78bfa), cyan-magenta-pink neon, gradient text
on headings.
- Emoji icons in section headers. Use styled monospace labels with colored dot indicators or
numbered badges.
- "Neon dashboard" or gradient-mesh backgrounds. Use subtle radial glows or faint grid only.
- Animated glowing box-shadows or pulsing effects on static content.
- Three-dot window chrome on code/quote blocks.
Required structure (mirror the PDF section list, but use web idioms):
- Hero — Company name (serif, 48–64px), SYMBOL in monospace, sector tag, report date.
One-line investment thesis as a lead paragraph (larger, dimmer body color).
- KPI strip — 4–6 cards: CMP, MCap, P/E, ROE, ROCE, latest QoQ growth. Hero number large;
label small and dim. Vary one card as the "primary" with accent-tinted background.
- Executive summary — 2–3 short paragraphs synthesizing the thesis. Optional pull quote
for the single most important management line.
- Business model & value chain (Query 1) — CSS Grid cards, not prose dump. Extract the
revenue streams, unit economics, key cost drivers. If there's a flow (input → processing →
output → customer), use a small Mermaid
graph LR (≤6 nodes) with the full
diagram-shell zoom container — never bare <pre class="mermaid">.
- Industry & competitive positioning (Query 2) — 2-column layout: structure cards on left,
peer comparison
<table> on right (sticky header, alternating rows, right-aligned numbers
with tabular-nums).
- Financial deep dive (Query 4) — A real
<table> for the quarterly P&L. Add a Chart.js
line chart for revenue + margin trajectory if 4+ quarters available. Margin trend gets its
own KPI callout.
- Management quality & execution (Query 3) — Guidance-vs-delivery as a striped table.
Italic gray management quotes inset with a subtle left-accent bar (no quote-mark emoji).
- Growth triggers (Query 5) — Card grid, each card = one trigger with: name, evidence,
sizing, kill-switch. Color the left border by conviction (high / medium / watch).
- Variant perception scorecard (Query 5) — This is a flagship section, not a quick table.
It must include:
(a) A 1–2 sentence methodology note explaining what "consensus" means here (sell-side target,
peer trading multiple, common buy-side view) and what the edge is being measured against.
(b) A wide
<table> with at least these columns: factor | consensus view (with a
sourceable anchor — sell-side target, peer multiple, prior management commentary) |
variant view (the differentiated take) | quantitative evidence (specific numbers, dates,
data points that support variant) | edge size (in EPS / multiple / target terms — i.e. how
much this factor moves the price if right) | time horizon (when this should resolve) |
falsification (what would prove the variant wrong).
(c) A minimum of 5 factors, not 3. Cover at least: valuation multiple, the most-feared
risk (commodity / cyclical / regulatory), execution / capex, demand durability, and one
sector-specific factor.
(d) Below the table, a short "consensus build vs variant build" comparison — two side-by-side
mini-tables showing the EPS/revenue/multiple stack each view implies for the next 2 years.
- Bull / Base / Bear scenarios (Query 6) — Two complementary views, both required:
(a) Three side-by-side scenario cards with FY+1/+2/+3 headline numbers, probability
weight, return %, and one-line trigger. Bear uses rose/cranberry, base neutral, bull
sage/emerald — border color only, never red/green emoji or arrows.
(b) A detailed scenario
<table> below the cards, with scenarios as columns and rows
covering at minimum: Revenue FY+1/+2/+3, Revenue CAGR, EBITDA FY+3, EBITDA margin %,
PAT FY+3, EPS FY+3, EPS CAGR, exit P/E multiple, target price, implied return %,
and probability. Numbers are right-aligned with tabular-nums. Header row tinted to match
the scenario card colors so the table is visually anchored to the cards above.
(c) A scenario assumptions sub-table listing the 4–6 key driver assumptions per
scenario (e.g. for a recycler: spread per kg, capacity utilization %, organized share %,
non-core revenue mix, tax rate). This makes the scenarios reproducible — the reader can
challenge any single assumption.
(d) A probability-weighted target line below the table, with the math shown explicitly
(e.g. 0.20 × 1,500 + 0.55 × 2,400 + 0.25 × 3,500 = 2,495). Show the implied upside vs CMP.
(e) A short "what moves us between scenarios" note — 2–3 bullets describing the specific
observable that would shift the base case toward bull or bear.
- Key risks (Query 6) — Color-coded callout boxes (rose for high severity, amber for
medium, slate for informational). Each risk has a 1-line "monitor via" line.
- Investment thesis summary — Closing prose, 4–6 sentences max, with the kill-switches
explicit.
- Footer — sources (concall dates analyzed, screener URL, disclaimer "not investment
advice").
Page mechanics
- Sticky sidebar TOC on desktop ≥1024px (linking to each section); horizontal scrollable bar
on mobile. See visual-explainer's
references/responsive-nav.md pattern.
- Light + dark via
@media (prefers-color-scheme). Both must look intentional.
- Staggered
fadeUp on cards via --i CSS variable; respect prefers-reduced-motion.
- Every grid/flex child needs
min-width: 0 to prevent overflow on narrow viewports.
- Tabular numbers everywhere (
font-variant-numeric: tabular-nums).
Output location
data/companies/{SYMBOL}/analysis/{SYMBOL}_Equity_Analysis_{YYYY-MM-DD}.html
After writing, open the file locally so the user can preview before deploy.
Step 4: Netlify deploy (HTML path only, if user said yes)
This step has two phases: a pre-flight that gathers everything Netlify needs from the user
(CLI, auth, site name, deploy scope), then the deploy itself. Do not skip the pre-flight —
it produces the variables the deploy command consumes. Each AskUserQuestion below is
mandatory; do not invent defaults the user did not pick.
4.1 Pre-flight: Netlify CLI
command -v netlify >/dev/null 2>&1 && netlify --version
If the command is missing, ask the user via AskUserQuestion:
Netlify CLI is not installed. Install it now?
- Install globally — runs
npm install -g netlify-cli (one-time, ~30 MB). Requires npm.
- Install locally to project — runs
npm install --save-dev netlify-cli and uses npx netlify thereafter. No global pollution.
- Skip deploy — keep HTML local only, print manual install + deploy commands.
If the user picks an install option:
- First verify npm exists:
command -v npm — if missing, abort with the Node install link
(https://nodejs.org/) and fall back to "skip deploy".
- Run the install. If it fails with
EACCES, do NOT use sudo automatically — instead tell the
user to either fix npm prefix (npm config set prefix ~/.npm-global) or pick local install
instead, then re-ask.
- After successful install, re-check
netlify --version to confirm.
4.2 Pre-flight: Authentication
netlify status --json 2>/dev/null
If the JSON shows "NetlifyUser" with an email, the user is authed — continue.
If not authed, ask via AskUserQuestion:
Netlify needs to authenticate. Which method?
- Interactive login — runs
netlify login, opens a browser, paste-back token flow. Best for personal use.
- Personal access token — paste a token from
https://app.netlify.com/user/applications#personal-access-tokens. Best for CI / scripted use. The skill will export NETLIFY_AUTH_TOKEN for the session and remind the user to add it to their shell profile if they want it persistent.
- Skip deploy — same as above, keep local only.
If interactive login: run netlify login (it opens the browser; the user pastes the auth code
back into the terminal). Wait for it to complete. Re-check netlify status.
If token: prompt the user to paste the token (do NOT log it; treat it like a password). Set it
in the current shell only:
export NETLIFY_AUTH_TOKEN="<token>"
Tell the user this is session-scoped — to make it persistent, they should add the export to
~/.zshrc or use a tool like direnv themselves. Do not modify their shell profile without
explicit permission.
4.3 Pre-flight: Site name
Ask via AskUserQuestion:
What site name should this report deploy to? (becomes the public URL: https://{name}.netlify.app)
- Default —
{symbol-lower}-equity-{yyyymmdd} — date-stamped, new URL per run. Good for ad-hoc reports.
- Stable per-symbol —
{symbol-lower}-equity — reused on every re-publish for this stock. Good if you want a consistent URL to share.
- Custom — user supplies the name (must be globally unique on netlify.app).
- Reuse existing site — only offer this option if
data/companies/{SYMBOL}/analysis/netlify_site.txt exists with a previously-deployed site name; auto-fill it.
After the user picks, save the chosen site name to
data/companies/{SYMBOL}/analysis/netlify_site.txt so future runs can offer "reuse existing".
4.4 Pre-flight: Deploy scope
Ask via AskUserQuestion:
Deploy as production or preview?
- Production (
--prod) — replaces the live URL with this build. Use for the canonical version.
- Preview — creates a one-off
https://<hash>--{site}.netlify.app URL that won't replace prod. Good for sharing a draft for feedback before publishing.
4.5 Deploy
Stage the HTML, ensure the site exists, deploy.
DEPLOY_DIR=$(mktemp -d)
trap 'rm -rf "$DEPLOY_DIR"' EXIT
cp "data/companies/{SYMBOL}/analysis/{SYMBOL}_Equity_Analysis_{YYYY-MM-DD}.html" \
"$DEPLOY_DIR/index.html"
SITE_NAME="<from 4.3>"
netlify sites:create --name "$SITE_NAME" 2>/dev/null || true
PROD_FLAG="<--prod or empty per 4.4>"
netlify deploy --dir="$DEPLOY_DIR" --site="$SITE_NAME" $PROD_FLAG \
--message "Equity report {SYMBOL} {YYYY-MM-DD}"
Parse the output for Website URL (production) or Website Draft URL (preview). Print:
✓ Published to Netlify
Live URL: https://{site-name}.netlify.app # or the draft URL
Local: data/companies/{SYMBOL}/analysis/{SYMBOL}_Equity_Analysis_{YYYY-MM-DD}.html
Site name: {site-name} (saved to netlify_site.txt for reuse)
4.6 Sensitive content warning
Always show this before running 4.5, even if the user already opted into deploy:
Netlify URLs are public and crawlable. This report contains analysis of {SYMBOL} based on
public concalls and screener data — no proprietary data — but if you've added private notes or
internal commentary to the HTML, abort the deploy now.
If the user has not seen this warning in this session, ask one final yes/no confirmation before
calling netlify deploy.
Step 5: Confirm and summarize
Report back, in 3–4 lines max:
- What was generated (PDF path / HTML path / Netlify URL).
- Number of sections rendered.
- Any sections that were thin because NLM didn't return useful content (so the user knows where
to push deeper next time).
Quality checks before delivery (HTML)
Before claiming done, mentally run the visual-explainer checks:
- Squint test: hierarchy still readable when blurred?
- Swap test: would replacing fonts + colors with a generic dark theme make this
indistinguishable? If yes, push the aesthetic further.
- Both themes: does it look intentional in light AND dark?
- No overflow: nothing escapes its container at 375px width.
- No slop signals: no Inter, no purple gradients, no emoji headers, no glowing shadows.
If two or more slop signals are present, regenerate with a different aesthetic.
Error handling
- Missing analysis inputs: stop, tell user to run
/stock-research-pipeline first.
- Reportlab missing:
pip install reportlab in the venv, then retry.
- Netlify CLI missing: Step 4.1 handles this — ask the user via
AskUserQuestion whether to
install globally (npm install -g netlify-cli), install locally to project, or skip deploy.
Never auto-install without asking.
- npm missing: if the user picks an install option but
npm is not on PATH, abort the
install and fall back to "skip deploy" with a pointer to https://nodejs.org/.
- npm EACCES on global install: do NOT escalate with
sudo. Show the user the npm-prefix
fix (npm config set prefix ~/.npm-global + add to PATH) or offer the local install path,
then re-ask.
- Netlify auth missing: Step 4.2 asks the user to pick interactive
netlify login or paste
a personal access token.
- Token paste: treat the token like a password — never log, never echo, never write to disk.
Set as
NETLIFY_AUTH_TOKEN for the session only. Tell the user how to make it persistent
themselves; never edit ~/.zshrc automatically.
- Netlify site name collision: if the user chose "default" or "custom" and that name is
taken, ask whether to append a suffix (
-v2, -v3) or pick a new name.
Example usage
User: "publish the GRAVITA report"
User: "deploy the GRAVITA report to netlify"
User: "I want an html version of the TCS report"
User: "/stock-research-publish RELIANCE"