Image To Editable Ppt
ningzimu/image-to-editable-ppt-skill
Rebuild slide images, scanned or image-based PPT/PPTX files, and PDF decks into object-level editable PowerPoint (.pptx), preserving speaker notes when supplied.
One-page company profile slide, four quadrants of overview, financial summary, share price chart and key facts.
$ npx skills add ginlix-ai/LangAlpha --skill company-profile -a claude-codeProject install by default; add -g for ~/.claude/skills/.
$ gh skill install ginlix-ai/LangAlpha company-profile --agent claude-codeProject scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).
$ git clone --depth 1 https://github.com/ginlix-ai/LangAlpha.git skills-src && mkdir -p .claude/skills && cp -r skills-src/plugins/langalpha_research/skills/company-profile .claude/skills/company-profile && rm -rf skills-srcUse ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.
Claude Code skills documentation · loads skills from .claude/skills/
Install the "company-profile" agent skill from https://github.com/ginlix-ai/LangAlpha/tree/main/plugins/langalpha_research/skills/company-profile into .claude/skills/company-profile/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "company-profile", then confirm the skill loads.Claude Code copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$skill-installer install https://github.com/ginlix-ai/LangAlpha/tree/main/plugins/langalpha_research/skills/company-profileType this inside Codex. $skill-installer <name> installs a curated skill from openai/skills. The installer writes to $CODEX_HOME/skills (default ~/.codex/skills). Restart Codex if the skill does not show up.
$ npx skills add ginlix-ai/LangAlpha --skill company-profile -a codexProject install goes to .agents/skills/; add -g for ~/.codex/skills/.
$ gh skill install ginlix-ai/LangAlpha company-profile --agent codexProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/ginlix-ai/LangAlpha.git skills-src && mkdir -p .agents/skills && cp -r skills-src/plugins/langalpha_research/skills/company-profile .agents/skills/company-profile && rm -rf skills-srcUse ~/.agents/skills/ instead of .agents/skills for a personal install.
Codex skills documentation · loads skills from .agents/skills/
Install the "company-profile" agent skill from https://github.com/ginlix-ai/LangAlpha/tree/main/plugins/langalpha_research/skills/company-profile into .agents/skills/company-profile/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "company-profile", then confirm the skill loads.Codex copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add ginlix-ai/LangAlpha --skill company-profile -a cursorProject install goes to .agents/skills/; add -g for ~/.cursor/skills/.
$ gh skill install ginlix-ai/LangAlpha company-profile --agent cursorProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/ginlix-ai/LangAlpha.git skills-src && mkdir -p .cursor/skills && cp -r skills-src/plugins/langalpha_research/skills/company-profile .cursor/skills/company-profile && rm -rf skills-srcUse ~/.cursor/skills/ instead of .cursor/skills for a personal install.
Cursor skills documentation · loads skills from .cursor/skills/, .agents/skills/, .claude/skills/, .codex/skills/
Install the "company-profile" agent skill from https://github.com/ginlix-ai/LangAlpha/tree/main/plugins/langalpha_research/skills/company-profile into .cursor/skills/company-profile/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "company-profile", then confirm the skill loads.Cursor copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gemini skills install https://github.com/ginlix-ai/LangAlpha.git --path plugins/langalpha_research/skills/company-profile--scope user (default) or --scope workspace; --path is the subfolder of the repo that holds the skill; --consent skips the security confirmation prompt.
$ npx skills add ginlix-ai/LangAlpha --skill company-profile -a gemini-cliProject install goes to .agents/skills/; add -g for ~/.gemini/skills/.
$ gh skill install ginlix-ai/LangAlpha company-profile --agent gemini-cliProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/ginlix-ai/LangAlpha.git skills-src && mkdir -p .gemini/skills && cp -r skills-src/plugins/langalpha_research/skills/company-profile .gemini/skills/company-profile && rm -rf skills-srcUse ~/.gemini/skills/ instead of .gemini/skills for a personal install, then run /skills reload.
Gemini CLI skills documentation · loads skills from .gemini/skills/, .agents/skills/
Install the "company-profile" agent skill from https://github.com/ginlix-ai/LangAlpha/tree/main/plugins/langalpha_research/skills/company-profile into .gemini/skills/company-profile/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "company-profile", then confirm the skill loads.Gemini CLI copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gh skill install ginlix-ai/LangAlpha company-profileInstalls for Copilot at project scope by default; add --scope user for a personal install. Preview a skill first with gh skill preview. Needs GitHub CLI 2.90.0 or later (public preview).
$ npx skills add ginlix-ai/LangAlpha --skill company-profile -a github-copilotProject install goes to .agents/skills/; add -g for ~/.copilot/skills/.
$ git clone --depth 1 https://github.com/ginlix-ai/LangAlpha.git skills-src && mkdir -p .github/skills && cp -r skills-src/plugins/langalpha_research/skills/company-profile .github/skills/company-profile && rm -rf skills-srcUse ~/.copilot/skills/ instead of .github/skills for a personal install. Commit .github/skills so cloud agent and code review can use it.
GitHub Copilot skills documentation · loads skills from .github/skills/, .claude/skills/, .agents/skills/
Install the "company-profile" agent skill from https://github.com/ginlix-ai/LangAlpha/tree/main/plugins/langalpha_research/skills/company-profile into .github/skills/company-profile/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "company-profile", then confirm the skill loads.GitHub Copilot copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add ginlix-ai/LangAlpha --skill company-profile -a opencodeOpenCode documents no install command of its own. Project install goes to .agents/skills/; add -g for ~/.config/opencode/skills/.
$ gh skill install ginlix-ai/LangAlpha company-profile --agent opencodeProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/ginlix-ai/LangAlpha.git skills-src && mkdir -p .opencode/skills && cp -r skills-src/plugins/langalpha_research/skills/company-profile .opencode/skills/company-profile && rm -rf skills-srcUse ~/.config/opencode/skills/ instead of .opencode/skills for a personal install.
OpenCode skills documentation · loads skills from .opencode/skills/, .claude/skills/, .agents/skills/
Install the "company-profile" agent skill from https://github.com/ginlix-ai/LangAlpha/tree/main/plugins/langalpha_research/skills/company-profile into .opencode/skills/company-profile/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "company-profile", then confirm the skill loads.OpenCode copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
company-profileOne-page company profile slide, four quadrants of overview, financial summary, share price chart and key facts.
Company Profile is an agent skill from ginlix-ai/LangAlpha. One-page company profile slide, four quadrants of overview, financial summary, share price chart and key facts. Also the compact profile paragraph when it has to sit inside a memo, a deck or a chat reply. Triggers on one-page profile, tear sheet, company snapshot, profile slide, quick profile of [company].
Its SKILL.md is about 6.2k tokens, which your agent loads only when the skill is triggered. It is a single SKILL.md file with no bundled scripts.
It sits in Documents & Office, covering Slides and decks. The repository describes itself as: Claude Code for Financial Market. The licence is Apache-2.0.
4 steps, taken from the step headings in SKILL.md.
Read from SKILL.md and the folder at commit 2855e43. It shows what the files ask for, not the result of running them.
Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.
From allowed-tools in the SKILL.md frontmatter.
Shell commands in SKILL.md call:
pythonnpmFrom the folder's file list and the shell code blocks in SKILL.md.
No URLs in SKILL.md. Its commands use npm, which can reach the network depending on how they are called.
From URLs in SKILL.md, links to its own repository left out.
Names no API keys, tokens, secrets or passwords.
From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.
Company Profile loads about 6.2k tokens when it runs. Until then it costs about 81 tokens; SKILL.md has 3,067 words of instructions outside code blocks.
Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.
The automated check found no risky patterns in SKILL.md.
Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.
The full file from ginlix-ai/LangAlpha at commit 2855e43, republished under its Apache-2.0 licence (© ginlix-ai). 3,067 words, ~6,182 tokens.
.claude/skills/company-profile/SKILL.md (or your agent's skills folder).A single slide that answers "what is this company" for a reader with thirty seconds. Four quadrants, all four full: overview, financial summary, share price or valuation chart, key facts. This is the front page of a pitch book and the first page of a diligence pack, and it is the one slide in a deck allowed to be a document, because nobody presents from it, they read it off the page.
Build it with the pptx skill. Its geometry, palette, build-script discipline and verification scripts all apply unchanged, and this file only describes what goes inside that frame. Reach for html-report instead when the answer wants two pages of prose, and comps-analysis when the question is how the company prices against its peers rather than what it is.
Evidence labels, source tiers, staleness, the readiness posture and the intake limits: .agents/skills/research-conventions/SKILL.md, read before the first deliverable.
The profile is a baseline: what is true about this company, sourced, on one page. It is not a recommendation, and it holds no view. The moment the work turns into a thesis, a scenario set, a valuation argument or a call on the stock, it has stopped being a profile: finish the baseline, then hand off and say so. .agents/skills/initiating-coverage/SKILL.md owns the thesis, .agents/skills/comps-analysis/SKILL.md owns relative valuation, .agents/skills/earnings-preview/SKILL.md owns the setup into a print. Expanding the slide to carry a view is the failure this rule exists to catch, because a one-pager that argues reads as fact to everyone downstream of it.
Confirm the entity first, then ask what the slide is for.
Entity identity. Establish, before any pull: the exact issuer (a similarly named parent, subsidiary or unrelated company is the classic wrong answer), the listing line (ticker and exchange, and which share class where more than one trades), and the fiscal year end. Everything downstream carries this, and a profile of the wrong listing line is wrong in every quadrant at once.
Then run intake per .agents/skills/research-conventions/references/intake.md: read the mandate memory, ask only about the forks it leaves open, recommended option first, and start on the recommendation when no answer comes back, disclosing it as a default. Two forks are worth a question here:
Whether the company is public or private is settled from the pull rather than asked: a private company has no share price, so quadrant 4 becomes holders, funding history and recent developments.
Asking after the research is doing the research twice.
| Need | Source |
|---|---|
| Profile, sector, market cap, consensus estimates, price targets, earnings history | get_company_overview |
| Revenue, EBITDA, margins, EPS, FCF across three years | get_financial_statements and get_growth_metrics from the fundamentals MCP server |
| Forward-year revenue and EPS | yf_analysis MCP get_revenue_estimates and get_earnings_estimates, the +1y record's avg, labelled E with numberofanalysts; forward EBITDA, margins and FCF have no consensus feed, so those cells carry an evidence gap rather than a derived figure |
| EV | get_historical_valuation (enterpriseValue, alongside the DCF fair value) |
| EV/EBITDA, P/E | get_financial_ratios (evToEBITDA from key_metrics, priceToEarningsRatio from ratios) |
| EV/Revenue | computed from enterpriseValue and the revenue line, since no tool returns the ratio |
| Share count and float | get_shares_float (outstandingShares, floatShares, freeFloat) |
| Insider buying and selling | get_insider_trades (transactions plus the buy/sell statistics) |
| Institutional holdings | yf_analysis MCP get_institutional_holders (holder, shares, value, pctheld), labelled with the record's date_reported, which is the filing quarter and not today; empty data is a company with none reported rather than an evidence gap |
| Named officers | get_key_executives |
| One year of daily closes for the price chart | get_stock_data from the price-data MCP server (interval="1day"), called inside execute_code so the rows land in Python where the chart step can save them |
| Business description, segment and geographic mix | get_sec_filing (10-K, Item 1 Business and MD&A) |
| Recent news, private-company facts, brand colour | WebSearch and WebFetch |
Normalise before writing anything down: one currency, one scale ($mm or $bn, never mixed on one slide), one fiscal-year convention, and every figure labelled A for actual or E for estimate. Mark unaudited, preliminary, pro-forma, adjusted and company-defined figures as such in the bullet itself, since a pro-forma revenue figure sitting unlabelled beside a reported one is two different metrics in one column.
Provenance travels with every metric, even though the slide shows only the number. Keep period, units, source and confidence beside each figure while researching: the slide prints the number, the source line prints the tools and documents behind it, and the outline you show the user carries all four so a wrong figure is traceable in seconds rather than re-pulled.
Flag a conflict rather than picking silently. Two sources disagreeing on revenue, EBITDA, debt, share count or market cap; a data tool differing from the filing; the company's deck differing from its filing; a newer filing superseding the figure already written down. Resolve down the tier list and record the selection per .agents/skills/research-conventions/references/evidence.md, and where the conflict is material to the slide, say which figure was used in the source line.
Write the four quadrants out as plain text with the real numbers already in place. No placeholders: a bullet you cannot fill is a bullet the slide does not get. Show the outline and the accent colour, then build.
Follow the pptx loop exactly:
<task>/build_<name>.js and run it with NODE_PATH=$(npm root -g) node <task>/build_<name>.js.python .agents/skills/pptx/scripts/check.py <task>/<name>.pptx --strict, which reads the written file and reports anything off the slide, overlapping or overflowing.python .agents/skills/pptx/scripts/render.py <task>/<name>.pptx --montage, then open the PNG and read it. Look for a bullet wrapping into the quadrant below it, a table row crossing the footer, an axis label clipped at the bottom, and a title sitting on top of the first quadrant header.Steps 3 and 4 are not optional and neither is the looking. check.py estimates overflow from font size and character count, so a pass is a reason to look, not a substitute for looking. A profile slide is the densest thing this repo produces, and density is exactly where the estimate and the renderer disagree.
16:9, LAYOUT_WIDE, 13.333 x 7.5 in, with the 0.6 in side margins and the title band from the pptx skill left alone. The content band, y 1.75 to 6.60, splits into four equal quadrants:
x=0.600 x=6.833 x=12.733
+--------------------------------+------------------------------+ y=1.75
| 1 Company Overview | 2 Business and Positioning |
| w=5.90 h=2.30 | w=5.90 h=2.30 |
+--------------------------------+------------------------------+ y=4.05
| 3 Financial Summary | 4 Share Price / Key Facts |
| w=5.90 h=2.35 | w=5.90 h=2.35 |
+--------------------------------+------------------------------+ y=6.60| Element | x | y | w | h | Type |
|---|---|---|---|---|---|
Title, Company Name (TICKER) | 0.60 | 0.45 | 12.13 | 0.60 | 28pt bold |
| Kicker: units, periods, as-of date | 0.60 | 1.05 | 12.13 | 0.35 | 14pt |
| Rule | 0.60 | 1.42 | 12.13 | 0.02 | |
| Quadrant header, top row | col x | 1.75 | 5.90 | 0.40 | 16pt bold |
| Quadrant hairline, top row | col x | 2.17 | 5.90 | 0.01 | |
| Quadrant body, top row | col x | 2.23 | 5.90 | 1.82 | 12pt |
| Quadrant header, bottom row | col x | 4.25 | 5.90 | 0.40 | 16pt bold |
| Quadrant hairline, bottom row | col x | 4.67 | 5.90 | 0.01 | |
| Quadrant body, bottom row | col x | 4.73 | 5.90 | 1.87 | 12pt |
| Source line | 0.60 | 6.95 | 12.13 | 0.30 | 10pt |
Column x is 0.600 for quadrants 1 and 3, 6.833 for quadrants 2 and 4. The 0.333 in gutter is the only thing between the columns: white background, no fills, no shading, no boxes drawn around the quadrants.
Header boxes are 0.40 in and not a hair less. check.py measures a box against its text after taking off the 0.05 in inset top and bottom, so a 16pt line needs 19.2pt of clear height, and a 0.32 in box fails the overflow check even though the render looks fine.
12pt body is a deliberate exception to the deck-wide 16 to 18pt in pptx, and it is the only slide that gets it. check.py holds the hard floors either way: 10pt for body text, 14pt for table text.
A quadrant that looks sparse has not been researched. Fill all four, then measure each against the column width.
| Quadrant | Content | Target |
|---|---|---|
| 1 Company Overview | HQ, founded, employees, CEO and CFO, exchange and ticker, market cap, industry, one defining statistic | 6 to 8 bullets |
| 2 Business and Positioning | revenue drivers, product or segment mix with percentages, market share, the moat in one clause, customer count or concentration, geographic mix | 6 to 8 bullets |
| 3 Financial Summary | Revenue, growth, EBITDA, EBITDA margin, EPS, FCF, EV/EBITDA over three columns (FY-1A, FY0A, FY+1E) | a table of header plus 6 rows, or a chart, never both |
| 4 Share Price or Key Facts | one year of daily closes; for a private company, top holders with percentages, funding history, recent developments | a chart, or 5 to 7 bullets |
At 12pt across a 5.90 in column, check.py fits roughly 70 characters on a line (width_in * 72 / (pt * 0.5)), so a bullet over 70 characters takes two lines and costs the quadrant a fact. Counting paragraph spacing, each body box holds 7 to 8 one-line bullets. Write to that budget: pack facts, never pad them.
HQ Austin, TX; founded 2003; 14,200 employees is one bullet, not three.$4.0bn revenue beats large revenue, and +28% y/y beats growing fast.EBITDA margin 25.4% (peer median 18%).{ text: "Market position: ", options: { bold: true } }, so the quadrant scans as a list of labels.bullet: { indent: 12 }. The pptxgenjs default leaves about a third of an inch of white between the glyph and the text, which is four characters of a 70-character line spent on nothing.Never silently omitted. These are either on the slide with their as-of, or named in the evidence gaps: market cap, float, average daily volume and days to exit, index membership, passive and ETF ownership, top holders, short interest, borrow, analyst coverage count, and the consensus setup. A missing one of these changes what a reader can do with the page, so its absence is information.
Pair the fact with the decision wherever the decision is not obvious from the number: float speaks to capacity and squeeze risk, days to exit answers whether a position can be built or unwound at all, borrow prices the other side of the trade. Float 62%; 14 days to exit at 20% ADV is one bullet doing two jobs, which is how a data table becomes a decision aid inside a 70-character line.
Evidence gaps. One compact block, never a table of empty fields. Where there are one or two gaps, they ride at the end of the source line: Not sourced: short interest, borrow (as of unavailable). Where there are more, they take the last bullet of quadrant 4 as a single line starting Not sourced:. Each gap names what is missing and, where it is not obvious, what would supply it. A gap that costs the reader a decision is worth a bullet more than the least surprising fact on the slide.
If a quadrant still runs short, the facts usually missing are segment percentages, customer concentration, guidance against consensus, and insider ownership. If it runs long, cut the least surprising fact before you cut the font.
Every adjective carries its number. Best-in-class margins becomes EBITDA margin 25.4% (peer median 18%); dominant becomes 41% share, next largest 17%; high quality becomes the metric that makes it so. Where the number does not exist, the claim does not go on the slide.
Title the valuation block by what the evidence supports. With only historical financials and derived LTM multiples behind it, the heading is Valuation Context or LTM Multiples, and it stays that way until forward estimates, peer evidence, target-price evidence or an explicit statement of market expectations is actually sourced. A heading promising a forward debate the sourcing cannot carry is the one place a factual page can mislead without printing a single wrong number.
Contain a live event. A pending transaction, a rumour, an activist position or a regulatory action that is material but is not what the user asked about goes in exactly three places: one line in the read, the catalyst or risk bullet, and the evidence gap for whatever primary document is still missing. It does not get threaded through the business description, the financial summary and the valuation block as well, which is how one unresolved event takes over a page that was asked to describe a company.
Reader-facing labels. The slide prints the reader's word for each evidence label, one per label, per Reader-facing labels in .agents/skills/research-conventions/references/evidence.md, where a model-derived figure prints as derived in the space a slide has.
The chart series comes from Python, not from the direct tool. get_daily_prices answers in Markdown, and past fourteen trading days that answer is a summary rather than the rows, so a year of closes never reaches the build script through it. Pull the series with get_stock_data on the price-data MCP server instead: it returns {symbol, interval, currency, timezone, count, data, source}, where data is a list of {date, open, high, low, close, volume} bars, oldest first. The research step keeps the two fields the chart reads and writes them to <ticker>/prices.json; the axis range then comes from the data, never from a typed bound.
import json
from tools.price_data import get_stock_data
bars = get_stock_data("ACME", interval="1day",
start_date="2025-09-05", end_date="2026-09-05")["data"]
with open("acme/prices.json", "w") as f:
json.dump([{"date": b["date"], "close": b["close"]} for b in bars], f)const PptxGenJS = require("pptxgenjs");
const fs = require("fs");
const prices = JSON.parse(fs.readFileSync("acme/prices.json", "utf8"));
const months = prices.map((p) => p.date);
const closes = prices.map((p) => p.close);
const lo = Math.floor(Math.min(...closes) * 0.9), hi = Math.ceil(Math.max(...closes) * 1.1);
const INK = "1A1A1A", MUTED = "5A5A5A", RULE = "D8D5D0", ACCENT = "1F4E79";
const FONT = "Arial", M = 0.6, W = 13.333, CONTENT_W = W - 2 * M;
const COL_W = 5.9, COL_X = [M, 6.833];
const ROW = [{ head: 1.75, rule: 2.17, body: 2.23, h: 1.82 },
{ head: 4.25, rule: 4.67, body: 4.73, h: 1.87 }];
const pptx = new PptxGenJS();
pptx.layout = "LAYOUT_WIDE";
const slide = pptx.addSlide();
slide.background = { color: "FFFFFF" };
slide.addText("Acme Corporation (ACME)", { x: M, y: 0.45, w: CONTENT_W, h: 0.6,
fontFace: FONT, fontSize: 28, bold: true, color: INK, valign: "middle" });
slide.addText("$ in millions unless noted; FY2026E is consensus; prices as of 2026-09-05",
{ x: M, y: 1.05, w: CONTENT_W, h: 0.35, fontFace: FONT, fontSize: 14, color: MUTED, valign: "top" });
slide.addShape("rect", { x: M, y: 1.42, w: CONTENT_W, h: 0.02, fill: { color: RULE } });
// One helper for all four quadrants, so no header can drift from its neighbour.
function quadrant(col, row, heading) {
const x = COL_X[col], r = ROW[row];
slide.addText(heading, { x, y: r.head, w: COL_W, h: 0.40,
fontFace: FONT, fontSize: 16, bold: true, color: ACCENT, valign: "middle" });
slide.addShape("rect", { x, y: r.rule, w: COL_W, h: 0.01, fill: { color: RULE } });
return { x, y: r.body, w: COL_W, h: r.h };
}
const bullets = (lines) => lines.map((t) => ({ text: t, options: { bullet: { indent: 12 } } }));
const q1 = quadrant(0, 0, "Company Overview");
slide.addText(bullets([
"HQ Austin, TX; founded 2003; 14,200 employees",
"CEO J. Rivera (2019); CFO M. Osei (2022)",
"NASDAQ: ACME; market cap $18.4bn; float 92%",
]), { ...q1, fontFace: FONT, fontSize: 12, color: INK, valign: "top", paraSpaceAfter: 3 });
const q2 = quadrant(1, 0, "Business and Positioning");
slide.addText(bullets([
"Industrial sensors and controls; 61% of revenue is recurring service",
"Second by share in North American process automation",
"Installed base of 40k sites; switching cost is recertification",
]), { ...q2, fontFace: FONT, fontSize: 12, color: INK, valign: "top", paraSpaceAfter: 3 });
const q3 = quadrant(0, 1, "Financial Summary");
const head = { fill: { color: ACCENT }, color: "FFFFFF", bold: true };
slide.addTable(
[[{ text: "$mm", options: head }, { text: "FY2024A", options: head },
{ text: "FY2025A", options: head }, { text: "FY2026E", options: head }],
["Revenue", "3,410", "4,020", "4,610"],
["EBITDA", "742", "928", "1,105"]],
{ ...q3, colW: [2.0, 1.3, 1.3, 1.3], fontFace: FONT, fontSize: 14, color: INK,
rowH: 0.26, valign: "middle", border: { type: "solid", pt: 1, color: RULE } }
);
const q4 = quadrant(1, 1, "Share Price, Last 12 Months");
slide.addChart(pptx.ChartType.line, [{ name: "ACME", labels: months, values: closes }],
{ ...q4, chartColors: [ACCENT], showLegend: false, lineSmooth: false, lineDataSymbol: "none",
valAxisMinVal: lo, valAxisMaxVal: hi, // never zero-based; see below
catAxisLabelFontFace: FONT, catAxisLabelFontSize: 12, catAxisLabelColor: MUTED,
valAxisLabelFontFace: FONT, valAxisLabelFontSize: 12, valAxisLabelColor: MUTED,
valGridLine: { color: RULE, style: "solid", size: 1 }, catGridLine: { style: "none" } }
);
slide.addText("Source: company filings, fundamentals MCP server, get_stock_data. Prices as of 2026-09-05.",
{ x: M, y: 6.95, w: CONTENT_W, h: 0.3, fontFace: FONT, fontSize: 10, color: MUTED });
pptx.writeFile({ fileName: "acme/acme_profile.pptx" })
.then(() => console.log("written"));A table is as tall as rowH times its row count whatever h says, so header plus 6 rows at 0.26 is 1.82 in inside the 1.87 in body box. A seventh row pushes it past the content band toward the footer, which check.py reports as out of bounds.
Quadrant 3 is a table by default: it carries nine numbers in the space a chart spends on one series. Swap in a chart only when the shape of the trend is the point, and then drop the table rather than shrinking both.
| Data | Chart |
|---|---|
| One year of daily closes | line, unsmoothed, no markers |
| Revenue or EBITDA over five periods | column |
| Segment or geographic mix | horizontal bar, sorted |
| Product mix, four slices or fewer | pie with percentages shown |
Charts are native addChart parts, one colour per series, axis labels at 12pt. Units go in the kicker or the axis title, not on every data label.
A price line is never zero-based. pptxgenjs starts the value axis at 0 by default, which pins a year of trading into the top fifth of the box and draws every stock as a flat line. Set valAxisMinVal and valAxisMaxVal around the series, roughly 10 percent outside the low and the high. This is the defect the render catches and check.py never will: the geometry is perfect and the chart says nothing.
The house palette in pptx is the default and it is enough: ink, grey, paper, one accent. When the user asks for the company's brand colour, search for the actual hex rather than guessing, use it as the single accent (quadrant headers, table header fill, the price line) and leave the rest in the house greys. One accent, one meaning, and green and red still mean gain and loss and nothing else.
Quadrant 4 has no share price, so it becomes holders and history: top five holders with percentages, funding rounds with dates and amounts, and the two or three developments from the last ninety days a reader would ask about. The sources shift to the corporate site, press releases and news search, so the source line names them and the kicker says which figures are estimates.
When the profile has to sit inside a memo, a deck or a chat message rather than on its own page, compress it to one paragraph in a fixed order: what the company does and how it makes money, scale (revenue, growth, margin) with the period, the balance-sheet and positioning facts that bear on the reader's decision, the valuation context with its as-of, and the one thing that would change the picture. Two hundred words or fewer, every number carrying its period and source, and the same never-silently-omit list applies: what is not sourced is named in the last sentence.
When the user asked for two or three more slides, the profile slide does not change. The rest are ordinary pptx content slides at 16 to 18pt body, one claim each, in the order business and market, financial detail, then leadership or ownership. Every one elaborates something the profile slide already claimed, so a reader who stops after the first page has still been told the truth.
check.py --strict passes.Content, before the render is looked at:
.agents/skills/research-conventions/SKILL.md.© ginlix-ai, Apache-2.0. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file
Just SKILL.md in plugins/langalpha_research/skills/company-profile of ginlix-ai/LangAlpha.
Open the folder on GitHubat commit 2855e43
Company Profile next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.
| Skill | Stars | Used in | Tokens | Auto-check | Licence | Repo updated |
|---|---|---|---|---|---|---|
| Company Profile this skillginlix-ai/LangAlpha | 1.8k | — | ~6.2k | Automated safety check: Pass | Apache-2.0 | |
| Image To Editable Pptningzimu/image-to-editable-ppt-skill | 2.9k | — | ~4.3k | Automated safety check: Pass | MIT | |
| Slidesfcakyon/claude-codex-settings | 1.2k | 1 repos | ~1.1k | Automated safety check: Pass | MIT | |
| Ppt Image FirstNyxTides/ppt-image-first | 1.2k | — | ~1.6k | Automated safety check: Pass | Apache-2.0 | |
| Vibe to Agentic Engineering Frameworkshanraisshan/claude-code-best-practice | 67k | — | ~3.3k | Automated safety check: Pass | MIT | |
| Gpt Image2 PptJuneYaooo/gpt-image2-ppt-skills | 1.3k | — | ~8.9k | Automated safety check: Notes | Apache-2.0 |
ningzimu/image-to-editable-ppt-skill
Rebuild slide images, scanned or image-based PPT/PPTX files, and PDF decks into object-level editable PowerPoint (.pptx), preserving speaker notes when supplied.
fcakyon/claude-codex-settings
Create and edit presentation slide decks (.pptx) with PptxGenJS, bundled layout helpers, and render/validation utilities.
NyxTides/ppt-image-first
Build presentation plans for PPT / slides / decks through a conversation-first workflow, then propose multiple visual directions with preview images before writing deck specs.
shanraisshan/claude-code-best-practice
Explains the conceptual model behind a presentation on moving from unstructured vibe coding to fully configured agentic engineering, including its 4-level scoring system and slide conventions.
JuneYaooo/gpt-image2-ppt-skills
Generate visually striking PPT slides via OpenAI's gpt-image-2 -- use any style in styles/<collection/STYLEID.md or mimic a user-supplied .pptx template; outputs high-res slide PNGs and a 16:9 .pptx.
scunning1975/MixtapeTools
Create and compile beautiful Beamer presentations following the Rhetoric of Decks philosophy.
ginlix-ai/LangAlpha
Quality-checks an investment deck in .pptx form before it goes out: number consistency, chart and narrative alignment, source coverage, language and a circulation verdict.
ginlix-ai/LangAlpha
Produces a first-time equity research initiation report in five tasks: company research, financial model, valuation, charts and a DOCX report.
ginlix-ai/LangAlpha
Builds or repairs an integrated income statement, balance sheet and cash flow model in Excel with live formulas, supporting schedules, scenarios and a Checks sheet.
ginlix-ai/LangAlpha
Audits an existing Excel financial model without editing it, checking structure, formulas, integrity identities and source tie-out, and ends in a prioritized issue log.
ginlix-ai/LangAlpha
Builds a live Excel DCF valuation workbook with free cash flow projections, WACC, terminal value, three scenarios, sensitivity grids and a reverse DCF.
ginlix-ai/LangAlpha
Builds Word files with python-docx, edits existing ones in place with tracked changes and comments, then renders and validates the result.
Categories
One-page company profile slide, four quadrants of overview, financial summary, share price chart and key facts. Company Profile is an agent skill from ginlix-ai/LangAlpha. One-page company profile slide, four quadrants of overview, financial summary, share price chart and key facts.
Company Profile fits situations like: one-page profile; company snapshot; quick profile of [company].
Run `npx skills add ginlix-ai/LangAlpha --skill company-profile -a claude-code`. Or copy the skill folder (plugins/langalpha_research/skills/company-profile in ginlix-ai/LangAlpha) into .claude/skills/company-profile in your project. Claude Code loads it when a task matches its description.
Run `npx skills add ginlix-ai/LangAlpha --skill company-profile -a codex`. Or copy the skill folder (plugins/langalpha_research/skills/company-profile in ginlix-ai/LangAlpha) into .agents/skills/company-profile in your project. Codex loads it when a task matches its description.
Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add ginlix-ai/LangAlpha --skill company-profile -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/company-profile, .gemini/skills/company-profile, .github/skills/company-profile and .opencode/skills/company-profile in your project.
Going by SKILL.md and its folder, Company Profile needs the command-line tools its instructions call (python and npm). Our summary lists: Python 3.
SKILL.md contains no URLs. Its commands use npm, which can reach the network depending on how they are called. This is read from the text; nothing was executed.
Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.
Company Profile is published under the Apache-2.0 licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.
About 6.2k tokens (SKILL.md is roughly 25k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.
Skills that share tags, products or a category with Company Profile: Image To Editable Ppt (ningzimu/image-to-editable-ppt-skill, 2.9k stars), Slides (fcakyon/claude-codex-settings, 1.2k stars), Ppt Image First (NyxTides/ppt-image-first, 1.2k stars) and Vibe to Agentic Engineering Framework (shanraisshan/claude-code-best-practice, 67k stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.
ginlix-ai (a GitHub organization) maintains it in ginlix-ai/LangAlpha, which has 1,811 GitHub stars. The repository holds 37 skills in this directory. The repository was last updated on October 10, 2026.
Source: ginlix-ai/LangAlpha on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.