Skip to content
Back to skills

Proposal Maker

ASecurity

Turn a raw commercial offer (client + line items + total) into an HTML proposal whose style copies a brand website. LLM-authored from a brand screenshot; --quick offline fallback. Output: proposal.html with clickable links + exact prices, prints to PDF. Use when: 'make a proposal', 'commercial offer', 'КП', 'коммерческое предложение'.

  • 19 stars
  • 0 votes
  • 0 copies
  • 3 views
  • Added August 31, 2026
ai-agentspythonrustgobashapi

Works with

  • cli
  • api

Security analysis

A100/100

Pro scans all 12 files and shows the line behind each finding

Scanned August 31, 2026

npx -y skills add Mikefluff/skills --skill proposal-maker --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Proposal Maker?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Proposal Maker
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/mikefluff-proposal-maker/badge)](https://www.skillsdirectory.com/skills/mikefluff-proposal-maker)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: proposal-maker
description: "Turn a raw commercial offer (client + line items + total) into an HTML proposal whose style copies a brand website. LLM-authored from a brand screenshot; --quick offline fallback. Output: proposal.html with clickable links + exact prices, prints to PDF. Use when: 'make a proposal', 'commercial offer', 'КП', 'коммерческое предложение'."

license: MIT
allowed-tools:
  - Read
  - Write
  - Edit
  - Bash
  - Grep
  - Glob
---

<objective>
End-to-end commercial-proposal generator. Input: a free-form offer (client block +
itemised order with prices + total, usually pasted from Telegram/WhatsApp) and a brand
site to copy the look from. Output: a single self-contained `proposal.html` that genuinely
**looks like that brand** and prints to a clean PDF.

The default is **LLM-authored, screenshot-driven**. A deterministic template can't capture
"dark, bold, dramatic brand with a green accent and uppercase display type" — it reads
colours by frequency and gets the mood wrong. So instead: a Python step assembles a
**brand kit**, and you (the orchestrator) *look at the brand* and *write the markup*.

Execute-layer modules under `common/runners/`:
1. `proposal/parse.py` — offer text → structured `skills.proposal.plan.v1` (items, prices,
   recomputed subtotal, mismatch + outlier flags).
2. `proposal/brand.py` — scrape brand tokens (accent / fonts / logo / name) + enrich each
   item with its real catalogue photo + description (`og:` tags).
3. `proposal/kit.py` — screenshot the brand site (headless Chrome), download the logo,
   write `BRIEF.md` bundling tokens + the item table + authoring rules.
4. `proposal/render.py` — the `--quick` deterministic themed template + HTML→PDF helper.

Why a document and NOT an image deck: a proposal carries **exact prices** and **clickable
product links**. AI image generation garbles both. You write real HTML text.

This skill does NOT: generate slides/images (use `carousel-builder`/`flyer-maker`); invent
prices or discounts; silently rewrite a suspicious number (it flags, you ask); log into a
CRM or send anything; compute tax/VAT.
</objective>

## ROLE

Build the brand kit → **look at the brand screenshot** → surface data-quality warnings to
the user → **author a bespoke `proposal.html` that mirrors the brand** → verify it by
screenshotting your own output → deliver. Fall back to `--quick` only when there's no LLM
loop or no network.

## PIPELINE (default — LLM-authored)

1. **Capture the offer.** Save the user's pasted offer verbatim to a temp file (or pipe via
   stdin). Don't reformat — the parser handles emoji headers, RU/EN keys, `Name (url) qty —
   price CUR` lines, and `Total:`.

2. **Build the brand kit:**
   ```bash
   python3 proposal-maker/scripts/run.py --offer /tmp/offer.txt
   # brand site auto-detected from the offer footer; or pass --brand-url <site>
   ```
   This writes to `./generated/proposal/<slug>/`: `site.png` (the brand screenshot),
   `logo.*`, `brand.json`, `offer.json` (enriched with per-item photo URLs), and
   `BRIEF.md`.

3. **Look at the brand.** `Read` `site.png` — actually view it. Note: dark vs light mood,
   type weight/case, where/how the logo sits, accent colour usage, imagery feel. Then read
   `BRIEF.md` for the tokens + the full item table (names, qty, prices, links, photo URLs).

4. **Surface warnings.** If the run printed `⚠ stated total ≠ computed` or `⚠ '<item>' is
   N% of the total — possible typo`, **tell the user and ask** before using that number.
   (The seed Double D offer has `Логистика 5 000 000` — 97% of the total — almost certainly
   `5 000`.) Never auto-fix; confirm, then correct the offer text and re-run if needed.

5. **Author `proposal.html`** into the kit folder. House rules:
   - **Mirror the screenshot.** Same mood (dark canvas if the site is dark), same type
     personality (the brand font from `BRIEF.md` via its Google Fonts link), the accent as
     the one hot colour, the logo placed like the site places it.
   - **Logo treatment.** Brand logos are often monochrome/white SVGs. On a dark header use
     as-is; on a light header tint to white via `filter:brightness(0) invert(1)` or set it
     on a dark/accent plate. **Always show the brand name beside it** so identity survives.
   - **Prominent key facts.** Lead the hero with a big Date / Time / Location block — the
     fields the client checks first — above smaller secondary pills (guests, phone).
   - **Group by category.** Split the items into 4–7 logical categories named for the
     client's domain (e.g. Звук и свет / Доп оборудование / Артисты / Декорации / Сервис),
     each with a **large, scannable header** (big type + accent marker), item count, and
     **per-category subtotal**. Never one long pile.
   - **Vary density.** Showpiece / high-value items → big photo cards; utility / low-cost
     items (controllers, stands, staff, logistics) → compact 2-column rows (small thumb +
     name + price). Don't render everything large — it reads as sprawling.
   - **Real photos.** Each item gets its `og:image` from `BRIEF.md` (Tilda URLs hotlink
     fine). Items the kit could not photograph from a link get an **auto-generated on-brand
     image** (kit fills these; marked in `BRIEF.md`) — use it and tell the user they can
     swap a real one. Never a blank/placeholder if a photo can be sourced.
   - **Exact data.** Prices and links exactly as parsed; the computed subtotal is the total;
     quantity chips where given.
   - **Self-contained.** One file: inline `<style>`, the Google Fonts `<link>`, CSS custom
     properties for the tokens.
   - **Print CSS (required — the PDF depends on it).** `@page{size:A4;margin:0}` to kill
     white margins (full-bleed). Running header **and** footer on every page via the
     **table `<thead>`/`<tfoot>`** pattern (`display:table-header-group`/`-footer-group` in
     print) — a `position:fixed` band can't reserve per-page space and looks broken on
     inner pages. `break-inside:avoid` on cards/total. `BRIEF.md` ships the exact recipe.

6. **Verify your output.** Screenshot the HTML you wrote and look at it:
   ```bash
   "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" --headless --disable-gpu \
     --hide-scrollbars --window-size=1100,3600 --screenshot=/tmp/check.png \
     "file://$PWD/generated/proposal/<slug>/proposal.html"
   ```
   `Read` `/tmp/check.png`. Iterate until it genuinely reads as the brand. (`proposal/kit`
   exposes `find_browser()` for the binary path across platforms.)

7. **PDF (optional).** Render the authored HTML to PDF via the system browser (no extra
   deps — keeps clickable links + the dark background):
   ```bash
   python3 proposal-maker/scripts/run.py --pdf-from generated/proposal/<slug>/proposal.html
   # → proposal.pdf next to it
   ```
   No headless browser? Tell the user to open `proposal.html` and Cmd/Ctrl+P → Save as PDF.

8. **Deliver.** Print the paths (`proposal.html` + `proposal.pdf`).

## --quick (deterministic, offline / no-LLM)

Renders one of three CSS themes (editorial / invoice / dark) from `proposal/render.py` —
no screenshot, no authoring. Use when offline, when there's no LLM loop, or for a fast
draft. Themes + auto-pick: see `references/templates.md`.

```bash
python3 proposal-maker/scripts/run.py --offer /tmp/offer.txt --quick --template dark --pdf
```

## MODES

### Required
- `--offer <path|->` or `--offer-text "<…>"`.

### Brand (overrides stack on top)
- `--brand-url <site>` (else auto-detected from the offer footer) · `--brand-file <brand.json>` ·
  `--no-brand` (defaults, no network) · `--accent <#hex>` · `--font "<Family>"` ·
  `--logo <url|path>` · `--brand-name "<Name>"`.

### Saved brand profiles (`brands/`)
- Reusable profiles live in [`brands/_index.md`](brands/_index.md) — each `brands/<slug>/` holds a corrected `brand.json` + an authored `template.html` to clone + cached assets + reuse README.
- When a profile exists for the client's brand, PREFER `--brand-file brands/<slug>/brand.json` over a fresh scrape: profiles encode manual corrections a live scrape gets wrong (dark themes read as light on Tilda/Webflow, vanishing white SVG logos).
- After any client-ready proposal for a NEW brand, offer to save it as a profile (see the checklist in `brands/_index.md`).

### Build / look
- (default) brand-kit mode · `--quick` deterministic template · `--template auto|editorial|invoice|dark` (quick only) ·
  `--lang auto|ru|en` · `--no-thumbnails` · `--embed-images` (quick) · `--currency <CODE>`.

### Output / inspection
- `--pdf` (quick mode: render PDF via the system browser) · `--pdf-from <html>` (render any
  HTML file to PDF and exit — the default-mode PDF step) · `--output <dir>` ·
  `--parse-only` (parsed JSON, no network — best first dry-run) · `--check` (deps +
  `--brand-url` reachability).

## REFERENCES (load on demand)

| File | When |
|---|---|
| `BRIEF.md` (generated per run) | The live authoring brief — tokens, item table, rules. Read it every run. |
| [references/offer-format.md](references/offer-format.md) | Parse contract — header keys, item grammar, qty vs line-total, total/outlier policy. |
| [references/brand-extraction.md](references/brand-extraction.md) | What's scraped + manual overrides + the screenshot/kit step. |
| [references/templates.md](references/templates.md) | The 3 `--quick` themes + auto-pick. |
| [references/troubleshoot.md](references/troubleshoot.md) | Fonts/photos/logo/PDF/encoding issues. |

## EXAMPLES

See [examples/before-after.md](examples/before-after.md) — the Double D Project event offer:
the deterministic template (the wrong, light read) vs. the LLM-authored, brand-faithful
dark proposal, plus the logistics-outlier handling.

## CONSTRAINTS

- **Look before you build.** In default mode you MUST view `site.png` before authoring.
  Don't trust `brand.json.is_dark` over your own eyes — the colour heuristic misreads
  dark Tilda/Webflow sites as light.
- **Copying the site's style is the whole point.** Match its mood, type, accent, logo.
- **Exact prices + clickable links.** Never render them as generated images.
- **Recompute, never silently rewrite.** Show the computed subtotal; flag a disagreeing
  stated total and any line ≥60% of the total; ask the user.
- **Verify by screenshot.** Author → screenshot → look → iterate. Don't ship unseen.
- **Enrichment is best-effort.** A dead catalogue link leaves that item text-only.
- **Output is `./generated/proposal/<slug>/`**; slug from client name + event + date.
- **No secrets.** Pure public-web scraping; no API keys.

## INVOCATION HINTS

Trigger when the user says: "make a proposal / commercial offer / quote", "turn this offer
into a nice document", "КП", "коммерческое предложение", "оффер для клиента", "смету
покрасивее", "proposal in the style of <site>", "копируй стиль с сайта"; or pastes a
Telegram/WhatsApp offer with 📆/👤/🧾/💰 fields + a price list.

Default: build the kit, view the screenshot, author the HTML. Recommend `--parse-only`
first if the offer formatting looks unusual. Reach for `--quick` only when offline or when
no authoring loop is available.

Distinct from `flyer-maker`/`carousel-builder`/`cover-maker` (those generate IMAGES) and
`landing-copy`/`cold-email` (those write prose).

Files in this skill

  • SKILL.md11.3 KB
  • brands/_index.md2 KB
  • brands/inite/README.md3.5 KB
  • brands/inite/brand.json2 KB
  • brands/inite/img/hero.jpg94.1 KB
  • brands/inite/template.html20.2 KB
  • examples/before-after.md3.1 KB
  • references/brand-extraction.md3.5 KB
  • references/offer-format.md3.7 KB
  • references/templates.md1.9 KB
  • references/troubleshoot.md3.7 KB
  • scripts/run.py806 B

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.