diff --git a/README.md b/README.md index 7c0a830..860cd5f 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ Drop your pitch deck, market research, business plan, competitor notes and call > Every company, customer, metric and transcript used as an example in this repo is invented. Nothing here is drawn from any real client engagement. -[**New to working with AI**](docs/ai-basics.md) · [**What the words mean**](docs/what-things-are.md) · [**The method**](docs/method.md) · [**Build the knowledge base**](docs/knowledge-base.md) · [**Prompt library**](prompts/INDEX.md) · [**For coaches**](docs/for-coaches.md) · [**Quickstart**](QUICKSTART.md) +[**New to working with AI**](docs/ai-basics.md) · [**What the words mean**](docs/what-things-are.md) · [**The method**](docs/method.md) · [**Build the knowledge base**](docs/knowledge-base.md) · [**Prompt library**](prompts/INDEX.md) · [**For coaches**](docs/for-coaches.md) · [**For programmes**](docs/for-portfolios.md) · [**Quickstart**](QUICKSTART.md) [![Read it as a site](https://img.shields.io/badge/read%20it%20as%20a%20site-fritzhand.github.io%2Fstartup--stack-0b5a86?style=flat-square)](https://fritzhand.github.io/startup-stack/) ![No code required](https://img.shields.io/badge/code%20required-none-0E6B63?style=flat-square) @@ -28,6 +28,8 @@ Meanwhile the advice they need is not exotic. It is the same twenty things, aske `startup-stack` makes those questions answerable from one place. +There is a second reader, and the repo now serves them too: the **programme** running a portfolio of these companies — an incubator, accelerator, studio or university venture programme, whose coaching team meets the same founders in recurring sessions and whose institutional memory currently lives in scattered notes. [The page written for them](docs/for-portfolios.md) is the deeper end of the same method. A founder can ignore it entirely. + ## The three loops ``` @@ -39,7 +41,7 @@ Meanwhile the advice they need is not exotic. It is the same twenty things, aske business plan ──┼─▶ CONTEXT.md ← the one-pager ├─▶ list of 100 market research │ 01-company … 10-pulse │ unit economics competitor notes │ ↑ one .md per section, front-mattered │ investor one-pager - call transcripts │ ↑ tagged: confirmed / unverified / TBD │ weekly recap + call transcripts │ ↑ confirmed / unverified / TBD / clash │ weekly recap spreadsheets │ │ design refs │ │ └──────────────────────────────────────────┘ @@ -48,7 +50,7 @@ Meanwhile the advice they need is not exotic. It is the same twenty things, aske real happens) every week) ``` -**Loop 1 — Build.** You put raw material in `_inbox/`. One prompt reads it and writes the stack: ten numbered sections, one markdown file each, every fact tagged as confirmed, unverified or missing. Takes an afternoon. The output is deliberately incomplete — the gaps are the point, because a gap you can see is a task. +**Loop 1 — Build.** You put raw material in `_inbox/`. One prompt reads it and writes the stack: ten numbered sections, one markdown file each, every fact tagged confirmed, unverified, missing, or in conflict where two of your own documents disagree. Takes an afternoon. The output is deliberately incomplete — the gaps are the point, because a gap you can see is a task. **Loop 2 — Enrich.** Every real thing that happens — a customer call, a supplier quote, a rejected ad campaign, a new competitor — goes back into the stack. The base is never finished. Each addition makes the next request cheaper and better, because the AI stops guessing about your business. @@ -58,10 +60,10 @@ Meanwhile the advice they need is not exotic. It is the same twenty things, aske | Folder | What it is | | --- | --- | -| [`stack/`](stack/) | **The templates.** Ten numbered sections — company, customer, market, product, GTM, operations, money, capital, brand, pulse — one markdown file each, with front matter. This *becomes* your knowledge base; you fill it in, you do not copy it out. | -| [`prompts/`](prompts/INDEX.md) | **The prompt library.** 19 prompts that run on top of a filled-in stack: bootstrap, gap scan, competitive intelligence, unit economics, list of 100, pitch deck, fundraise readiness, weekly recap, and the adversarial review that tells you what an investor will attack. The last three are for programmes rather than founders. | +| [`stack/`](stack/) | **The templates.** Ten numbered sections — company, customer, market, product, GTM, operations, money, capital, brand, pulse — one markdown file each, with front matter. [`stack/INDEX.md`](stack/INDEX.md) is the router an AI reads first, and [`stack/CONTEXT.md`](stack/CONTEXT.md) is the one-pager it reads next. This *becomes* your knowledge base; you fill it in, you do not copy it out. | +| [`prompts/`](prompts/INDEX.md) | **The prompt library.** 19 prompts: bootstrap, gap scan, competitive intelligence, unit economics, the list of 100, the pitch deck, fundraise readiness, the weekly recap, meeting-to-actions, and the adversarial review that tells you what an investor will attack. Each opens with a `Requires:` line and stops if what it needs is missing. Most want a filled-in stack; [`00`](prompts/00-bootstrap-the-stack.md), [`14`](prompts/14-meeting-to-actions.md) and [`15`](prompts/15-scrape-a-site.md) run against an empty one, which is how a stack starts to fill. The last three belong to `portfolio/` and never touch a founder's stack. | | [`worksheets/`](worksheets/) | **The repeatable artifacts.** Fill-in files you produce over and over: startup-prep, customer interview, competitor profile, two-week experiment, SOP entry, trade/order sheet, advisor scope letter, one-pager, list of 100, weekly recap. | -| [`docs/`](docs/) | **The method.** Why front matter and an index make the base cheap to run; how to build it in your first hour; how a coach runs this with a cohort; the safety rules for giving an AI access to your files; plus [AI basics](docs/ai-basics.md) for anyone who has only ever used a chat window, [getting your material in](docs/getting-material-in.md) — mail, drive, chat exports and connectors, source by source — and [what the words mean](docs/what-things-are.md) — the terminal, an editor, Git, GitHub, connectors, model tiers — each answered in plain language with a diagram. | +| [`docs/`](docs/) | **The method, in thirteen pages.** New to any of this: [AI basics](docs/ai-basics.md) and [what the words mean](docs/what-things-are.md) — the terminal, an editor, Git, GitHub, connectors, model tiers — each in plain language with a diagram. The method: [why it works](docs/method.md), [building the knowledge base](docs/knowledge-base.md), [the front-matter schema](docs/front-matter.md), [getting your material in](docs/getting-material-in.md) source by source, and [website to inbox](docs/scraping.md). Running it: [the weekly recap](docs/weekly-recap.md), [for coaches](docs/for-coaches.md), [the safety rules](docs/safety.md) for giving an AI access to your files, and [on a schedule](docs/automation.md) — recipes for Microsoft 365, Google Workspace, Zoom, Slack, and none of them. Two are for programmes only: [for programmes](docs/for-portfolios.md) and [the exchange folder](docs/exchange.md). | | [`portfolio/`](portfolio/) | **Optional — for a programme, not a founder.** The templates an incubator, accelerator or studio uses to run this across many companies: a router, a 1-to-5 maturity rubric per function, the cross-company theme scan, and a company folder to copy. Delete it if you are a founder. See [docs/for-portfolios.md](docs/for-portfolios.md). | | [`_inbox/`](_inbox/) | Where raw material lands before it is processed. Git-ignored by default. | | [`tools/`](tools/) | **Optional.** One script that turns a website into citable markdown in `_inbox/`. You never need it — it saves an hour of copy-and-paste. See [docs/scraping.md](docs/scraping.md). | @@ -105,21 +107,23 @@ Nobody should tell you this is free. The AI drafts; you validate. A stack you ha 4. **Enrich, don't perfect.** Ship the skeleton. Add to it forever. 5. **One index, one summary line per file.** This is what keeps the base cheap: the AI reads a small router and opens one section, instead of re-reading everything you own on every question. 6. **Private master, shared derived.** Every file declares a sensitivity. What you share with a coach, an investor or a customer is carved from the master — never the master itself. -7. **Scope the AI to one folder.** Start narrow. Widen only as fast as your confidence. See [docs/safety.md](docs/safety.md). +7. **Scope the AI to one folder.** Start narrow. Widen only as fast as your confidence. See [the safety rules](docs/safety.md). ## Reading it as a site -Everything in this repo is also published at **[fritzhand.github.io/startup-stack](https://fritzhand.github.io/startup-stack/)** — the same markdown, with search, a filterable prompt library, and light and dark themes. +The method is published at **[fritzhand.github.io/startup-stack](https://fritzhand.github.io/startup-stack/)** — every page in `docs/`, every prompt, every worksheet, and this file, with search, a filterable prompt library, and light and dark themes. + +**Generated from these files, not written twice.** Each page is its markdown rendered; the home page is assembled out of this README's own sections. Edit the markdown and the page changes — and if a heading the home page depends on is renamed, the build fails rather than shipping an empty section. -The site is generated *from these files*, so it cannot drift from the repo: edit the markdown, and the page changes. There is no second copy of the prose anywhere. +What is deliberately *not* published: the section templates in `stack/` and the company templates in `portfolio/`. Those are files you fill in with your own business, so the site lists them with their status instead of their contents. That matters if you fork this and publish your own — [`web/build.mjs`](web/build.mjs) withholds the `summary:` of any section that is not `public` once it has been filled in, and prints what it withheld. ```bash node web/build.mjs # markdown + web/assets → _site/ (zero dependencies, Node 18+) ``` -`.github/workflows/pages.yml` runs that on every push to `main` and publishes the result. The build fails loudly on a broken internal link or a missing diagram rather than shipping a quietly wrong page. +[`.github/workflows/pages.yml`](.github/workflows/pages.yml) runs that on every push to every branch and on every pull request, so a broken page is caught before it is merged; only `main` publishes. The build fails loudly on a broken internal link, a missing diagram, a prompt not routed to a group or a page with no title, rather than shipping a quietly wrong page. -**When you fork this as your own company's stack, delete `web/` and `.github/`.** They belong to this project, not to yours. +**When you fork this as your own company's stack, delete `web/` and `.github/` — and `portfolio/` unless you are a programme.** They belong to this project, not to yours. ## Where this came from diff --git a/web/assets/site.css b/web/assets/site.css index 66ee209..06e3ca1 100644 --- a/web/assets/site.css +++ b/web/assets/site.css @@ -99,13 +99,20 @@ img, svg, video { max-width: 100%; height: auto; } .nav-toggle:hover { background: var(--surface-alt); } .brand { display: flex; align-items: center; gap: 10px; color: var(--text); font-weight: 600; white-space: nowrap; min-width: 0; } .brand:hover { text-decoration: none; color: var(--text); } +/* The mark sits on the hero gradient, which is dark in BOTH themes — so the + glyph takes --hero-text rather than inheriting --text from .brand, which + would paint it near-black on near-black in light mode. Same reason the + favicon is drawn from these two values. */ .brand-mark { width: 30px; height: 30px; border-radius: var(--radius-sm); flex: none; background: var(--hero-bg); + color: var(--hero-text); display: grid; place-items: center; box-shadow: inset 0 0 0 1.5px color-mix(in srgb, var(--hero-text) 18%, transparent); } -.brand-mark svg { display: block; } +/* sized rather than left to fill the box, so the glyph keeps the same breathing + room the favicon has — the two are meant to be the same mark */ +.brand-mark svg { display: block; width: 19px; height: 19px; } .brand-name { font-family: var(--font-display); font-size: 0.98rem; letter-spacing: -0.01em; overflow: hidden; text-overflow: ellipsis; } .brand-name .thin { color: var(--text-faint); font-weight: 500; } .topbar-spacer { flex: 1; } diff --git a/web/build.mjs b/web/build.mjs index 69ea30b..8e178d5 100644 --- a/web/build.mjs +++ b/web/build.mjs @@ -758,7 +758,40 @@ ${table} })); } -/* ---- 5. home --------------------------------------------------- */ +/* ---- 5. home ---------------------------------------------------- + The prose on this page is lifted out of README.md and rendered through + the same renderer as every other page. It used to be typed out here as + HTML, which quietly falsified the contract at the top of this file — + and the two copies had already drifted: "Enrich, don't perfect." against + "Enrich, do not perfect.", and two different endings to rule 7. + + What stays hand-written below is the site's own furniture — the hero + buttons, the step cards, the stat block, the "where to start" cards. + None of it has a counterpart in the README, so none of it can drift + from one. Anything that does have a counterpart is pulled, not copied, + and the build fails if the README heading it anchors to is renamed. */ +const README = read("README.md"); +const rctx = () => ({ src: "README.md", dir: ".", root: "", toc: [], ids: new Set(), kind: "Page" }); + +/* everything under `## ` up to the next `## ` */ +function readmeSection(heading) { + const lines = README.split("\n"); + const start = lines.findIndex((l) => l.trim() === `## ${heading}`); + if (start < 0) { fail(`README.md has no "## ${heading}" section, and the home page is built from it`); return ""; } + let end = start + 1; + while (end < lines.length && !/^##\s/.test(lines[end])) end++; + const block = lines.slice(start + 1, end).join("\n").trim(); + if (!block) { fail(`README.md section "${heading}" is empty`); return ""; } + return mdToHtml(block, rctx()); +} + +/* one paragraph, found by how it opens — for the bits that sit outside any heading */ +function readmeParagraph(prefix, { raw = false } = {}) { + const para = README.split(/\n{2,}/).map((p) => p.trim()).find((p) => p.startsWith(prefix)); + if (!para) { fail(`README.md has no paragraph starting "${prefix}", and the home page is built from it`); return ""; } + return raw ? para : mdToHtml(para, rctx()); +} + { const counts = { sections: stackSections.length, @@ -767,11 +800,22 @@ ${table} docs: DOC_PAGES.length, }; const card = (href, title, text) => `

${esc(title)}

${esc(text)}

`; + + /* the three loops are cards on the site and paragraphs in the README, so the + title is split off the front of each rather than written twice */ + const LOOP_CLASS = ["loop-build", "loop-enrich", "loop-pulse"]; + const loopCards = [1, 2, 3].map((n) => { + const para = readmeParagraph(`**Loop ${n} — `, { raw: true }); + const m = para.match(/^\*\*Loop (\d) — ([^.]+)\.\*\*\s*([\s\S]*)$/); + if (!m) { fail(`README.md: the "Loop ${n}" paragraph does not open "**Loop N — Name.**", so the card has no title`); return ""; } + return `

Loop ${m[1]} · ${esc(m[2])}

${mdToHtml(m[3], rctx())}
`; + }).join("\n"); + const body = `
-

The documents every startup should have — compiled into a knowledge base an AI can actually read.

-

Drop your pitch deck, market research, business plan, competitor notes and call transcripts into one folder. An AI turns them into a structured, front-mattered knowledge base. Then a library of prompts runs on top of it to produce the work: the deck, the list of 100, the unit economics, the weekly recap.

+

${esc(TAGLINE)}

+ ${readmeParagraph("Drop your pitch deck")}
Start with your first hour ${ICONS.arrow} New to working with AI @@ -786,7 +830,7 @@ ${table} @@ -800,15 +844,12 @@ ${table}

The problem this solves

-

Most early founders are carrying their company in their head and in twelve unrelated files. The pitch deck says one number, the projections say another, the market research lives in a PDF nobody has opened since March, and every AI conversation starts from zero — so every answer is generic, and the founder pays for the model to re-read everything, every time.

-

Meanwhile the advice they need is not exotic. It is the same twenty things, asked in the same order, by every coach who has ever sat across from an early-stage founder: who exactly is the customer, what does a unit cost you, who else is doing this, how many prospects are on your list, and what happens when the money runs out.

+${readmeSection("The problem this solves")}

The three loops

-

Loop 1 · Build

Raw material goes into _inbox/. One prompt reads it and writes the stack — ten sections, every fact tagged confirmed, unverified or missing. An afternoon. The output is deliberately incomplete, because a gap you can see is a task.

-

Loop 2 · Enrich

Every real thing that happens — a customer call, a supplier quote, a rejected campaign, a new competitor — goes back in. The base is never finished. Each addition makes the next request cheaper and better.

-

Loop 3 · Pulse

Once a week, one prompt reads the stack and what changed, and writes the recap: what moved, what did not, what you learned, and how many weeks of money are left. Thirty minutes.

+${loopCards}

Where to start

@@ -824,18 +865,9 @@ ${card("for-coaches.html", "You are running this with a cohort", "How the method

The honest cost

-

Skeleton in an hour. A working v1 in a few focused sessions. A stack you actually trust in about a month, because the long pole is you correcting what the AI got wrong — not the AI writing it. Then roughly thirty minutes a week to keep it alive.

-

Nobody should tell you this is free. The AI drafts; you validate. A stack you have not corrected is a confident-sounding guess about your own company, and that is worse than no stack at all.

+${readmeSection("The honest cost")}

The rules this runs on

-
    -
  1. The document is the data. If a metric needs special effort to gather, it is the wrong metric.
  2. -
  3. AI drafts, the founder validates. Nothing is true because the model wrote it.
  4. -
  5. Tag honestly. needs-verification and tbd are the quality system, not failures.
  6. -
  7. Enrich, do not perfect. Ship the skeleton. Add to it forever.
  8. -
  9. One index, one summary line per file. This is what keeps the base cheap to run.
  10. -
  11. Private master, shared derived. Every file declares a sensitivity; what you share is carved from the master.
  12. -
  13. Scope the AI to one folder. Start narrow, widen as fast as your confidence and no faster.
  14. -
+${readmeSection("The rules this system runs on")}

The full reasoning is in the method; the rules the AI itself must follow are in rules for the AI.

`; write("index.html", shell({ @@ -876,8 +908,27 @@ for (const dir of stackSections) { cpSync(ASSETS, join(OUT, "assets"), { recursive: true, filter: (src) => !src.includes("diagrams") }); writeFileSync(join(OUT, "assets", "search-index.js"), `window.SEARCH_INDEX=${JSON.stringify(searchIndex)};`); +/* The favicon IS the header mark: same stack glyph as ICONS.stack, on the same + hero gradient, at the same proportion inside the same rounded square. The + values are literal because a standalone SVG document cannot read tokens.css — + they are copied from --hero-bg and --hero-text, light stops then dark, and + the media query is what the theme toggle does in the page. + Stroke is 2.4 rather than the header's 2 so the glyph survives being drawn at + 16px in a browser tab; everything else is scaled from the header exactly. */ +const FAVICON_GLYPH = ICONS.stack.replace(/^]*>|<\/svg>$/g, ""); writeFileSync(join(OUT, "assets", "favicon.svg"), - ``); + `` + + `` + + `` + + `` + + `` + + `` + + `` + + `` + + `` + + `` + + FAVICON_GLYPH + + ``); writeFileSync(join(OUT, ".nojekyll"), ""); writeFileSync(join(OUT, "robots.txt"), `User-agent: *\nAllow: /\nSitemap: ${SITE_BASE}sitemap.xml\n`); writeFileSync(join(OUT, "sitemap.xml"),