AgentStack
Browse Sign in
Browse Why AgentStack Sell Docs
Sign in
SKILL verified MIT Self-run

Proposal

skill-kurenn-claude-skill-proposal-claude-skill-proposal · by kurenn

Generate beautiful single-page client proposals as a document-format replacement for PDFs and Google Docs. Persists answers, fetches brand colors from the client's site (with WCAG contrast warnings), generates a Tailwind-built single-page HTML, and runs the `/critique` design skill via the Skill tool to grade and fix the output. Includes dynamic OG images for unfurls and version-history snapshots…

No reviews yet
0 installs
4 views
0.0% view→install

Install

$ agentstack add skill-kurenn-claude-skill-proposal-claude-skill-proposal

✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access No
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets No
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

View the full security report →

Verified badge

Passed review? Show it. Paste this badge into your README, it links to the public security report.

AgentStack Verified badge Links to your public security report.
[![AgentStack Verified](https://agentstack.voostack.com/badges/verified.svg)](https://agentstack.voostack.com/security/report/skill-kurenn-claude-skill-proposal-claude-skill-proposal)

Reliability & compatibility

Security review passed
0 installs to date
no reviews yet
3mo ago

Declared compatibility

Claude CodeClaude Desktop

Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.

Preview Execution monitoring

We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.

How agent discovery & health will work →
Are you the author of Proposal? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

/proposal

Generate single-page client proposals as a beautiful, branded HTML document — the replacement for PDF / Google Doc proposals. Static, no live actions, just a polished read.

Operating principle

A proposal does not close a deal — the conversation does. The proposal is the artifact your champion hands to people who weren't in the room. Its job is to reduce career risk for the champion by giving them ammunition to defend the choice. Every section earns its place by pre-empting an objection the champion will face.

This skill is document-replacement, not a SaaS product. There are no live buttons, no accept tracking, no view analytics. The output is a beautifully formatted page deployed to a URL the seller emails or pastes in Slack. The buyer reads it the way they'd read a PDF and replies through the existing email thread.

If the seller can't answer the discovery questions in the buyer's own words, the proposal won't save the deal. Push back. Don't generate from a thin brief.

Skill assets (in ~/.claude/skills/proposal/)

SKILL.md                          ← you are here
template.html                     ← the single-page proposal template
tailwind-input.css                ← Tailwind source for precompiled CSS
tailwind.config.js                ← content paths for JIT
discovery-schema.json             ← canonical schema for discovery.json
extract-colors.sh                 ← multi-source brand color extractor (WCAG-aware)
seller-defaults.json              ← persisted seller info — auto-loaded if present
examples/
  ├── saas-acme.html              ← reference: SaaS implementation pattern
  ├── agency-globex.html          ← reference: agency/creative pattern
  └── services-initech.html       ← reference: professional services pattern
vercel-starter/
  ├── vercel.json                 ← clean URLs + security headers + asset caching
  ├── index.html                  ← private root landing page
  ├── package.json                ← @vercel/og dependency for OG image route
  ├── assets/tailwind.css         ← precompiled, production-ready
  └── api/
      └── og.tsx                  ← dynamic OG image route (only runtime asset)

Read examples/*.html before generating. They are the canonical reference for what a good filled-in proposal looks like across industries.

When to use / when NOT to

  • ✅ Sending a proposal, scope of work, SOW, quote, or pitch document
  • ✅ User has had a discovery call and needs to put it in writing
  • ❌ Marketing landing page → /copy-board or /prototype
  • ❌ Internal planning docs → write directly
  • ❌ Multi-page deck → this skill is single-page only by design
  • ❌ User has not had any conversation with the prospect → tell them to have one first

Argument routing

| Invocation | Behavior | |---|---| | /proposal | Full new-proposal flow (Steps 0–7) | | /proposal Acme Corp | Same, with client name pre-filled | | /proposal --revise | Load proposals//discovery.json, ask what's changed, snapshot current to versions/v{n}.html, regenerate, redeploy | | /proposal --clone | Load proposals//discovery.json as a starting point, ask what's different, save to a NEW slug | | /proposal --meetings [,...] | New-proposal flow with discovery answers drafted from one or more transcripts. Each chunk presents the draft and waits for seller confirmation/edits before saving. | | /proposal "Acme Corp" --meetings , | Same as above, with client name pre-filled. | | /proposal --revise --meetings ,... | Revise existing proposal using new meeting context. Diffs the saved discovery against extracted transcript answers and asks the seller which sections to update. |

`` accepts:

  • Circleback URL — e.g., https://app.circleback.ai/meetings/. Resolved via the Circleback MCP connector (ReadMeetings + GetTranscriptsForMeetings). The connector must be authorized in the user's environment.
  • Local file path.txt, .md, .vtt, .srt, or .json (Circleback export format). Use this for offline notes or transcripts from other tools.

Combinability rules:

  • --meetings IS allowed with: a positional client name, --revise .
  • --meetings is NOT allowed with --clone. If both are passed, abort with: "--clone and --meetings are not compatible. Use --meetings with --revise to layer new context onto an existing proposal, or omit --clone to start fresh from transcripts."

The flow

0. Bootstrap working dir         → scaffold vercel.json, assets, api/og.tsx
1. Load seller-defaults.json     → auto-fill seller's company info (skip questions)
1.5 Transcript ingestion         → (only if --meetings) fetch + normalize sources,
                                   pre-extract candidate answers w/ provenance,
                                   flag cross-meeting conflicts
2. Discovery (3 chunks)          → Setup batch → Story (1-by-1) → Scope (1-by-1)
                                   (with --meetings: each chunk runs as
                                   draft → seller review → confirm)
3. Brand color extraction        → multi-source w/ WCAG flag, present candidates
4. Generate single-page HTML     → adapt template.html with discovery JSON
5. Self-check + tone enforcement → strip banned words, regenerate-and-rank
6. /critique design pass         → invoke critique skill VIA Skill TOOL (REQUIRED)
7. Review with seller            → iterate
8. Deploy to Vercel              → preview then prod via /vercel:deploy

STEP 0 — Bootstrap

If the user's CWD does not contain vercel.json, scaffold from the starter:

SKILL_DIR="$HOME/.claude/skills/proposal"
cp "$SKILL_DIR/vercel-starter/vercel.json" ./vercel.json
cp "$SKILL_DIR/vercel-starter/index.html" ./index.html
cp "$SKILL_DIR/vercel-starter/package.json" ./package.json
mkdir -p ./assets ./api
cp "$SKILL_DIR/vercel-starter/assets/tailwind.css" ./assets/tailwind.css
cp "$SKILL_DIR/vercel-starter/api/og.tsx" ./api/og.tsx

Add .gitignore if missing: .vercel/, .DS_Store, node_modules/.

STEP 1 — Load seller defaults

Before any discovery questions, check for ~/.claude/skills/proposal/seller-defaults.json:

  • If it exists: load it. Show the seller a one-line summary ("Defaults loaded for Vertex Studio · Owen Rivera · owen@vertex.studio. Use these? (Y/n)"). If yes, skip the seller-info questions in Chunk A. If no, ask normally and offer to update the defaults at the end.
  • If it doesn't exist: ask the seller-info questions normally. After the proposal is done, ask: "Save these as defaults for next time? (Y/n)" — if yes, write ~/.claude/skills/proposal/seller-defaults.json with company name, tagline, seller name, seller title, seller email.

Schema for seller-defaults.json:

{
  "company": {
    "name": "Vertex Studio",
    "tagline": "Conversion-driven product design for B2B fintech.",
    "seller_name": "Owen Rivera",
    "seller_title": "Partner",
    "seller_email": "owen@vertex.studio"
  }
}

STEP 1.5 — Transcript ingestion (only if --meetings was passed)

If the user did not pass --meetings, skip this step entirely and proceed to Step 2 unchanged.

1.5a — Resolve every source

For each comma-separated value in --meetings:

| Pattern | How to resolve | |---|---| | Starts with http:// or https:// and host contains circleback | Extract the meeting ID from the URL path. Call ReadMeetings with that ID for metadata (date, participants, title). Call GetTranscriptsForMeetings for the full transcript. | | Resolves to an existing local file (.txt, .md, .vtt, .srt, .json) | Read directly. For .vtt/.srt, strip timestamps and speaker tags into plain prose. For .json, expect Circleback export schema (participants, transcript, meeting_date); fall back to dumping all string values if shape is unknown. | | Anything else | Fail loudly for that single source — print: "Could not resolve ``. Expected a Circleback URL or a local file path (.txt, .md, .vtt, .srt, .json)." |

If every source fails, abort the skill before discovery. If some succeed, continue with the survivors and tell the seller which were dropped.

Circleback connector failure: if ReadMeetings returns auth errors, tell the seller: "The Circleback connector isn't authorized in this environment. Run the connector setup or paste the transcript as a local file."

1.5b — Normalize into a unified extraction context

Build an in-memory list of normalized sources:

[
  {
    "source_type": "circleback" | "file",
    "ref": "",
    "meeting_date": "YYYY-MM-DD" | null,
    "participants": ["..."] | null,
    "transcript": ""
  },
  ...
]

Sort by meeting_date ascending so "most recent" is unambiguous in conflict resolution.

1.5c — Pre-extract candidate answers

Read all transcripts together and extract candidate answers for every discovery field, with provenance:

| Discovery field | What to look for | |---|---| | client.name, client.website | Mentions of the buyer's company; URLs | | champion.name, champion.title, champion.email | Speaker introductions, signature blocks, "I'm , at..." | | champion.stakeholders | "I'll need to run this by...", "the CFO won't approve unless...", "legal will want to see..." | | situation.problem_in_buyer_words | The buyer (not the seller) describing pain. Verbatim, not paraphrased. | | situation.buyer_quote + buyer_quote_source | A single line that captures the problem in the buyer's voice. Must include the source meeting. | | outcome.metrics | Specific numbers the buyer wants (% lift, time-to-X, $ saved). | | approach.phases | Phasing the seller proposed and the buyer reacted to. | | deliverables.items | Concrete artifacts named in the call. | | timeline.total_duration, milestones, dependencies | Dates discussed, blockers raised. | | investment.model, tiers[].headline_price, payment_terms | Pricing the seller floated and the buyer's reaction. | | risks | Hesitations the buyer voiced + any mitigation the seller offered. |

For every extracted candidate, attach:

  • source: which meeting (URL or filename) it came from
  • confidence: high (direct verbatim quote), medium (clear paraphrase), low (inferred from context)
  • quote_span: the exact transcript text (required for situation.buyer_quote — used as the pull quote in the template)

If a field has no candidate, leave it empty. Do not fabricate from a single passing mention.

1.5d — Conflict scan

Compare candidates across sources for these high-stakes fields:

  • investment.tiers[].headline_price
  • timeline.total_duration and milestone dates
  • approach.phases (count and names)
  • champion.stakeholders (different sets of stakeholders implies the deal shape changed)
  • client.name and project.codename

If two sources disagree, record a conflict entry:

{
  "field": "investment.tiers[0].headline_price",
  "candidates": [
    { "value": "$48,000 fixed", "source": "circleback:...", "date": "2026-04-22" },
    { "value": "$52,000 + 10% retainer", "source": "circleback:...", "date": "2026-05-15" }
  ]
}

Conflicts are surfaced to the seller in Step 2, not auto-resolved by recency.

1.5e — Cross-meeting client-mismatch check

If extracted client.name candidates disagree across sources (different companies), stop and ask the seller: "These transcripts reference different clients (X, Y). Which proposal are we drafting? Or did you mean to pass these as separate proposals?" Do not continue until clarified.

1.5f — Persist sources for audit

When discovery.json is eventually written in Step 2, include a top-level sources array (see schema). The proposal HTML itself does not display source info — provenance stays in the JSON for the seller's audit trail only.

STEP 2 — Discovery (three chunks)

When --meetings was passed: confirmation-per-chunk mode

Instead of asking each question, run each chunk as draft → seller review → confirm:

  1. Present the pre-extracted candidate answers for the chunk in a compact, scannable format. Show the source and confidence next to each value. For high-stakes fields with conflicts (from Step 1.5d), surface every candidate side-by-side and ask the seller to pick.
  2. Quote situation.buyer_quote verbatim with its source attribution — this is the pull quote in the template, it cannot be paraphrased.
  3. The seller can: accept, edit a specific field, reject and ask normally, or add fields the transcript missed.
  4. For any field with no candidate (or only low confidence), ask the seller normally — same questions as the no-meetings flow.
  5. Only when the seller confirms the chunk is correct, write its fields to discovery.json and proceed to the next chunk.

The B3 gate still fires. If no high-confidence buyer-language quote about the problem can be extracted from the transcripts, stop and tell the seller: "The transcripts don't contain a clean problem quote in the buyer's own words. Paste one (or go get one). The proposal will read generic without it." Do not let --meetings bypass this gate.

Chunk A — Setup (one batch, 4 questions)

If seller-defaults.json was loaded and confirmed, skip A4.

A1. Client company name + their website URL
A2. Industry — pick one: saas | agency_creative | professional_services
    | consulting | implementation | ecommerce | other
A3. Project codename / working title.
A4. (skip if seller-defaults loaded) Your company info — name, tagline,
    your name + title, contact email.

After A: kick off brand extraction (Step 3) in parallel with Chunk B.

Chunk B — Story (ONE QUESTION PER TURN)

Critical: ask Chunk B questions one at a time, waiting for the seller's reply before asking the next. This is the difference between a chat and a tax form.

B1. Champion: name, title, email of the person on the buyer side advocating
    for this. They are who the proposal serves.
B2. Stakeholders who must say yes — list each (CFO, CTO, board, legal,
    procurement) and the likely objection from each.
B3. The problem — IN THE BUYER'S WORDS. Paste the actual quote from
    the call/email. If they don't have one, say "I don't have a quote"
    and the skill will push back.
B4. Buyer quote — a single line + its source (will appear as a pull quote).
B5. The outcome they're buying — measurable. 3 specific metrics if possible.
B6. Hesitations they voiced. Cost? Timeline? "We tried this before"?
B7. What's already been agreed in conversation. What's still soft.

Gate: If B3 is paraphrased corporate-speak, stop and tell the seller: "The proposal will read generic. Go get the actual quote, then come back." Then wait. Don't continue.

After B: ask "Ready for the scope chunk? (Y/n)". Do not advance until confirmed.

Chunk C — Scope (ONE QUESTION PER TURN)

Same one-at-a-time discipline as Chunk B. Industry-aware emphasis based on A2.

C1. Approach — 2 to 5 phases. Each: name, duration, what happens, why.
C2. Deliverables — concrete, countable. 5 to 12 items.
C3. Out of scope — what's explicitly NOT included.
C4. Timeline — total duration + 4 to 8 milestones with dates.
    Plus dependencies that could slip.
C5. Pricing — model (fixed | T&M | retainer | tiered | subscription),
    headline price (already formatted with the currency symbol),
    payment terms, scope-change policy.
C6. Proof points — 2 to 3 named case studies.
C7. Risks — top 2-3 honest risks + the mitigation MECHANISM (not a hope).
C8. Next-step paragraph — what's the simple, dated invitation? (No CTA
    button — proposal is read-only. Just text + email + valid-until date.)
C9. Validity period — most proposals say 14-30 days. Ask the seller to pick.
    NOTE: this is informational only — the page displays "Valid until "
    but doesn't enforce it. Buyers can still read the page after that date.
C10. Optional T&C appendix? If yes: IP ownership, confide

…

## Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [kurenn](https://github.com/kurenn)
- **Source:** [kurenn/claude-skill-proposal](https://github.com/kurenn/claude-skill-proposal)
- **License:** MIT

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet, be the first.

Versions

  • v0.1.0 Imported from the upstream source.