diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 4690eec..a9f5657 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -156,6 +156,11 @@ jobs:
steps:
- name: Check out code
uses: actions/checkout@v5
+ - name: Set up Go
+ uses: actions/setup-go@v5
+ with:
+ go-version-file: go.mod
+ cache: true
- name: Set up Bun
uses: oven-sh/setup-bun@v2
diff --git a/.gitignore b/.gitignore
index b7febfe..3617ff2 100644
--- a/.gitignore
+++ b/.gitignore
@@ -48,3 +48,6 @@ Thumbs.db
/build/
/website/dist/
/packages/profitctl/native/
+
+# Browser CLI assets are generated from the current Go source.
+/website/public/demo/
diff --git a/examples/website_demo/baseline.yml b/examples/website_demo/baseline.yml
new file mode 100644
index 0000000..7db3d3b
--- /dev/null
+++ b/examples/website_demo/baseline.yml
@@ -0,0 +1,37 @@
+# Fictional AI SaaS scenario. These rates are illustrative, not vendor quotes.
+project:
+ name: Fictional Research SaaS - Baseline
+fixed_costs:
+ - name: Sample monthly infrastructure
+ amount: 400
+ period: monthly
+ layer: infrastructure
+variable_costs:
+ - name: Sample research requests
+ cost_per_unit: 0.08
+ units_per_user: 60
+ distribution: uniform
+ min: 59
+ max: 61
+ layer: service
+ - name: Sample other costs per user
+ cost_per_unit: 1.50
+ units_per_user: 1
+ distribution: uniform
+ min: 0.99
+ max: 1.01
+ layer: application
+pricing:
+ plans:
+ - name: Standard
+ price: 20
+covenants:
+ - type: threshold
+ field: operating_margin
+ operator: gte
+ value: 60
+ message: Operating margin must be at least 60%
+simulation:
+ base_users: 1000
+ growth_factor: 1
+ iterations: 100
diff --git a/examples/website_demo/growth.yml b/examples/website_demo/growth.yml
new file mode 100644
index 0000000..afe30b9
--- /dev/null
+++ b/examples/website_demo/growth.yml
@@ -0,0 +1,37 @@
+# Fictional AI SaaS scenario. Usage rises from 60 to 300 requests per user.
+project:
+ name: Fictional Research SaaS - More Usage
+fixed_costs:
+ - name: Sample monthly infrastructure
+ amount: 400
+ period: monthly
+ layer: infrastructure
+variable_costs:
+ - name: Sample research requests
+ cost_per_unit: 0.08
+ units_per_user: 300
+ distribution: uniform
+ min: 299
+ max: 301
+ layer: service
+ - name: Sample other costs per user
+ cost_per_unit: 1.50
+ units_per_user: 1
+ distribution: uniform
+ min: 0.99
+ max: 1.01
+ layer: application
+pricing:
+ plans:
+ - name: Standard
+ price: 20
+covenants:
+ - type: threshold
+ field: operating_margin
+ operator: gte
+ value: 60
+ message: Operating margin must be at least 60%
+simulation:
+ base_users: 1000
+ growth_factor: 1
+ iterations: 100
diff --git a/examples/website_demo/optimized.yml b/examples/website_demo/optimized.yml
new file mode 100644
index 0000000..f021232
--- /dev/null
+++ b/examples/website_demo/optimized.yml
@@ -0,0 +1,37 @@
+# Fictional AI SaaS scenario. A cheaper request path preserves the same usage.
+project:
+ name: Fictional Research SaaS - Cheaper Route
+fixed_costs:
+ - name: Sample monthly infrastructure
+ amount: 400
+ period: monthly
+ layer: infrastructure
+variable_costs:
+ - name: Sample research requests
+ cost_per_unit: 0.02
+ units_per_user: 300
+ distribution: uniform
+ min: 299
+ max: 301
+ layer: service
+ - name: Sample other costs per user
+ cost_per_unit: 1.50
+ units_per_user: 1
+ distribution: uniform
+ min: 0.99
+ max: 1.01
+ layer: application
+pricing:
+ plans:
+ - name: Standard
+ price: 20
+covenants:
+ - type: threshold
+ field: operating_margin
+ operator: gte
+ value: 60
+ message: Operating margin must be at least 60%
+simulation:
+ base_users: 1000
+ growth_factor: 1
+ iterations: 100
diff --git a/website/README.md b/website/README.md
index 50e1678..8d48ad4 100644
--- a/website/README.md
+++ b/website/README.md
@@ -1,21 +1,57 @@
# ProfitCtl Website
-Standalone landing page app for ProfitCtl.
+Static product website for ProfitCTL, with a real CLI terminal demo, a separate
+cost calculator, and local documentation at `/docs/`.
## Env
- `PUBLIC_REPO_URL` for GitHub button links
-- `PUBLIC_SITE_ORIGIN` for canonical metadata
+- `PUBLIC_SITE_ORIGIN` for canonical metadata, the sitemap, and crawler guidance.
+ The production origin defaults to `https://profitctl.com`.
+ Set it to the actual public origin before deploying elsewhere.
+- Cloudflare Pages: set `GO_VERSION=1.26.8` to match `go.mod`.
## Run
+Install the Go version specified by `go.mod` and Bun 1.3.3. Both development and
+production builds compile the current CLI for the browser.
```bash
-npm install
-npm run dev
+bun install --frozen-lockfile
+bun run dev
```
## Build
```bash
-npm run build
+bun run build
+bun run typecheck
```
+
+The build produces static files in `dist/`, including `robots.txt` and
+`sitemap.xml`. It checks the demo calculations, page metadata, social image,
+headings, structured data, and local links. The terminal runs the actual CLI as
+WebAssembly in a worker, against the fictional files in `examples/website_demo/`.
+It validates a baseline, simulates rising usage, and compares a cheaper route.
+The story loops automatically. Selecting a step holds its result. Reduced-motion
+settings show a single comparison without looping. Playback pauses when the demo is off screen or
+the page is hidden. No provider calls or local-file access are enabled.
+
+The build generates compressed WebAssembly, its matching Go runtime and
+license, and scenario downloads in `public/demo/`. These assets are ignored by
+Git and rebuilt for each deployment. The loader accepts either an already
+decoded HTTP response or a compressed file. The real WebAssembly commands and
+read-only workspace are checked by `scripts/check-terminal-demo.mjs`.
+
+The separate calculator remains a simplified illustration. Neither it nor the
+terminal scenario uses live provider prices.
+
+The header and footer pair the ProfitCTL wordmark with the approved bold-plus
+calculator mark. Browser icons and the sharing thumbnail use muted sage and
+forest colors. Icon links and the sharing image are versioned to refresh caches. Development credit appears on
+both pages and in their structured metadata: IntelIP and Hudson Aikins.
+
+Local source and a successful build do not establish publication
+or search indexing. Deployment and domain changes require maintainer approval.
+
+The homepage and documentation follow the browser light or dark preference through
+native CSS, including cards, controls, text, and browser theme colors.
diff --git a/website/astro.config.mjs b/website/astro.config.mjs
index 7b42345..a607118 100644
--- a/website/astro.config.mjs
+++ b/website/astro.config.mjs
@@ -1,6 +1,8 @@
import { defineConfig } from "astro/config";
export default defineConfig({
+ site: process.env.PUBLIC_SITE_ORIGIN || "https://profitctl.com",
+ trailingSlash: "always",
compressHTML: true,
devToolbar: {
enabled: false,
diff --git a/website/package.json b/website/package.json
index 1e44a57..e19b461 100644
--- a/website/package.json
+++ b/website/package.json
@@ -5,8 +5,8 @@
"type": "module",
"packageManager": "bun@1.3.3",
"scripts": {
- "dev": "astro dev",
- "build": "astro build",
+ "dev": "node scripts/build-terminal-demo.mjs && astro dev",
+ "build": "node scripts/build-terminal-demo.mjs && bun scripts/check-terminal-demo.mjs && astro build && bun scripts/check-demo.mjs && node scripts/check-seo.mjs",
"preview": "astro preview",
"typecheck": "astro check && tsc --noEmit"
},
diff --git a/website/public/apple-touch-icon.png b/website/public/apple-touch-icon.png
new file mode 100644
index 0000000..bdd292b
Binary files /dev/null and b/website/public/apple-touch-icon.png differ
diff --git a/website/public/favicon-96.png b/website/public/favicon-96.png
new file mode 100644
index 0000000..5bae826
Binary files /dev/null and b/website/public/favicon-96.png differ
diff --git a/website/public/favicon.ico b/website/public/favicon.ico
new file mode 100644
index 0000000..1b6f7c8
Binary files /dev/null and b/website/public/favicon.ico differ
diff --git a/website/public/favicon.svg b/website/public/favicon.svg
new file mode 100644
index 0000000..ea856a8
--- /dev/null
+++ b/website/public/favicon.svg
@@ -0,0 +1 @@
+ProfitCtl
diff --git a/website/public/icons/profitctl-192.png b/website/public/icons/profitctl-192.png
new file mode 100644
index 0000000..a6cc351
Binary files /dev/null and b/website/public/icons/profitctl-192.png differ
diff --git a/website/public/images/profitctl-social-calculator.jpg b/website/public/images/profitctl-social-calculator.jpg
new file mode 100644
index 0000000..8d1d563
Binary files /dev/null and b/website/public/images/profitctl-social-calculator.jpg differ
diff --git a/website/public/images/profitctl-social-calculator.svg b/website/public/images/profitctl-social-calculator.svg
new file mode 100644
index 0000000..f15ed9e
--- /dev/null
+++ b/website/public/images/profitctl-social-calculator.svg
@@ -0,0 +1,15 @@
+
+
+
+
+ ProfitCTL
+ OPEN-SOURCE COST MODELING FOR AI PRODUCTS
+ Know your AI costs.
+ Protect your margin.
+ Model a change. Compare your options. Decide before you ship.
+
+
+
+
+ ProfitCTL · MIT licensed
+
diff --git a/website/public/images/profitctl-social.jpg b/website/public/images/profitctl-social.jpg
new file mode 100644
index 0000000..1d2eaca
Binary files /dev/null and b/website/public/images/profitctl-social.jpg differ
diff --git a/website/public/images/profitctl-social.svg b/website/public/images/profitctl-social.svg
new file mode 100644
index 0000000..ebc9feb
--- /dev/null
+++ b/website/public/images/profitctl-social.svg
@@ -0,0 +1,13 @@
+
+
+
+
+ ProfitCTL
+ OPEN-SOURCE COST MODELING FOR AI PRODUCTS
+ Know your AI costs.
+ Protect your margin.
+ Model a change. Compare your options. Decide before you ship.
+
+
+ ProfitCTL · MIT licensed
+
diff --git a/website/scripts/build-terminal-demo.mjs b/website/scripts/build-terminal-demo.mjs
new file mode 100644
index 0000000..0d285e8
--- /dev/null
+++ b/website/scripts/build-terminal-demo.mjs
@@ -0,0 +1,37 @@
+import { execFileSync } from "node:child_process";
+import { mkdir, mkdtemp, readFile, rm, writeFile } from "node:fs/promises";
+import { tmpdir } from "node:os";
+import { join } from "node:path";
+import { fileURLToPath } from "node:url";
+import { gzipSync } from "node:zlib";
+
+const repository = fileURLToPath(new URL("../../", import.meta.url));
+const output = new URL("../public/demo/", import.meta.url);
+const temporary = await mkdtemp(join(tmpdir(), "profitctl-browser-"));
+try {
+ execFileSync("go", ["build", "-ldflags=-s -w -X main.version=browser-demo", "-o", join(temporary, "profitctl.wasm"), "."], {
+ cwd: repository,
+ env: { ...process.env, GOOS: "js", GOARCH: "wasm", CGO_ENABLED: "0" },
+ stdio: "inherit",
+ });
+ const compressed = gzipSync(await readFile(join(temporary, "profitctl.wasm")), { level: 9 });
+ if (compressed.length > 25 * 1024 * 1024) throw new Error("Browser demo exceeds the Pages asset limit.");
+ await mkdir(output, { recursive: true });
+ await writeFile(new URL("profitctl.wasm.gz", output), compressed);
+ const goRoot = execFileSync("go", ["env", "GOROOT"], { cwd: repository, encoding: "utf8" }).trim();
+ for (const [source, name] of [["lib/wasm/wasm_exec.js", "wasm_exec.js"], ["LICENSE", "GO-LICENSE.txt"]]) {
+ const destination = new URL(name, output);
+ await rm(destination, { force: true });
+ await writeFile(destination, await readFile(join(goRoot, source)));
+ }
+ const scenarios = {};
+ for (const name of ["baseline", "growth", "optimized"]) {
+ const text = await readFile(join(repository, "examples/website_demo", `${name}.yml`), "utf8");
+ scenarios[`demo/${name}.yml`] = text;
+ await writeFile(new URL(`${name}.yml`, output), text);
+ }
+ await writeFile(new URL("scenarios.json", output), JSON.stringify(scenarios));
+ console.log(`Real ProfitCTL browser demo built (${(compressed.length / 1024 / 1024).toFixed(2)} MiB compressed).`);
+} finally {
+ await rm(temporary, { recursive: true, force: true });
+}
diff --git a/website/scripts/check-demo.mjs b/website/scripts/check-demo.mjs
new file mode 100644
index 0000000..8ee6e51
--- /dev/null
+++ b/website/scripts/check-demo.mjs
@@ -0,0 +1,26 @@
+import assert from "node:assert/strict";
+import { calculateExample } from "../src/scripts/demo.ts";
+
+const feature = calculateExample({ users: 1000, requests: 60, price: 20 });
+assert.equal(feature.revenue, 20000);
+assert.equal(feature.baseline.cost, 2500);
+assert.equal(feature.candidate.cost, 6700);
+assert.equal(feature.candidate.margin, 66.5);
+assert.equal(feature.addedCost, 4200);
+assert.equal(feature.minimumPrice, 16.75);
+assert.equal(feature.passes, true);
+
+const pricing = calculateExample({ users: 1000, requests: 60, price: 12 });
+assert.ok(Math.abs(pricing.candidate.margin - 44.1666666667) < 1e-8);
+assert.equal(pricing.passes, false);
+const growth = calculateExample({ users: 10000, requests: 220, price: 20 });
+assert.equal(growth.candidate.cost, 191400);
+assert.equal(growth.candidate.margin, 4.3);
+assert.equal(growth.passes, false);
+assert.equal(calculateExample({ users: 1000, requests: 0, price: 20 }).addedCost, 0);
+for (const bad of [0, -1, NaN, Infinity]) {
+ assert.throws(() => calculateExample({ users: bad, requests: 60, price: 20 }), RangeError);
+ assert.throws(() => calculateExample({ users: 1000, requests: 60, price: bad }), RangeError);
+}
+assert.throws(() => calculateExample({ users: 1000, requests: -1, price: 20 }), RangeError);
+console.log("Interactive example: costs, margin decisions, and invalid inputs verified.");
diff --git a/website/scripts/check-seo.mjs b/website/scripts/check-seo.mjs
new file mode 100644
index 0000000..42195a1
--- /dev/null
+++ b/website/scripts/check-seo.mjs
@@ -0,0 +1,90 @@
+import assert from "node:assert/strict";
+import { readFile, stat } from "node:fs/promises";
+
+const output = new URL("../dist/", import.meta.url);
+const [html, robots, sitemap] = await Promise.all(
+ ["index.html", "robots.txt", "sitemap.xml"].map((file) =>
+ readFile(new URL(file, output), "utf8"),
+ ),
+);
+const origin = process.env.PUBLIC_SITE_ORIGIN || "https://profitctl.com";
+const canonical = new URL("./", origin).href;
+assert.ok(html.includes(`rel="canonical" href="${canonical}"`));
+assert.ok(html.includes(`property="og:url" content="${canonical}"`));
+assert.ok(html.includes('name="robots" content="index, follow"'));
+assert.ok(robots.includes("User-agent: *\nAllow: /\n"));
+assert.ok(robots.includes(`Sitemap: ${new URL("sitemap.xml", origin)}`));
+assert.ok(sitemap.includes(`${canonical} `));
+const schema = JSON.parse(
+ html.match(/
+
diff --git a/website/src/layouts/ProductLayout.astro b/website/src/layouts/ProductLayout.astro
index 47a5dac..35057c3 100644
--- a/website/src/layouts/ProductLayout.astro
+++ b/website/src/layouts/ProductLayout.astro
@@ -4,63 +4,114 @@ import "@fontsource/instrument-sans";
export interface Props {
title: string;
description: string;
+ pageType?: "product" | "docs";
}
-const { title, description } = Astro.props;
-const canonicalOrigin = import.meta.env.PUBLIC_SITE_ORIGIN || Astro.url.origin;
+const { title, description, pageType = "product" } = Astro.props;
+const repoUrl = import.meta.env.PUBLIC_REPO_URL || "https://github.com/IntelIP/ProfitCtl";
+const canonicalOrigin = Astro.site || Astro.url.origin;
const canonicalURL = new URL(Astro.url.pathname, canonicalOrigin);
-const favicon =
- "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 64 64'%3E%3Crect width='64' height='64' rx='12' fill='%23090B05'/%3E%3Crect x='12' y='12' width='40' height='40' rx='8' fill='none' stroke='%23B8FF18' stroke-width='4'/%3E%3Ctext x='32' y='41' text-anchor='middle' font-family='Arial,sans-serif' font-size='30' font-weight='700' fill='%23B8FF18'%3EP%3C/text%3E%3C/svg%3E";
+const imageURL = new URL("/images/profitctl-social-calculator.jpg", canonicalOrigin);
+const iconURL = new URL("/icons/profitctl-192.png", canonicalOrigin);
+const developer = { "@type": "Person", name: "Hudson Aikins" };
+const publisher = { "@type": "Organization", name: "IntelIP", url: "https://github.com/IntelIP" };
+const siteSchema = {
+ "@context": "https://schema.org", "@type": "WebSite", name: "ProfitCTL",
+ url: new URL("/", canonicalOrigin).href,
+};
+const schema = pageType === "docs" ? {
+ "@context": "https://schema.org", "@type": "TechArticle", headline: title,
+ description, url: canonicalURL.href, image: imageURL.href,
+ author: developer, publisher,
+} : {
+ "@context": "https://schema.org", "@type": "SoftwareApplication", name: "ProfitCTL",
+ applicationCategory: "DeveloperApplication", operatingSystem: "macOS, Linux, Windows",
+ description, url: canonicalURL.href, image: [iconURL.href, imageURL.href],
+ license: repoUrl + "/blob/main/LICENSE", downloadUrl: repoUrl + "/releases",
+ author: developer, publisher, sameAs: repoUrl,
+ isAccessibleForFree: true,
+ offers: { "@type": "Offer", price: "0", priceCurrency: "USD" },
+};
---
-
+
+
+
+
{title}
-
+
-
+
-
+
+
+
+
+
+
-
+
+
+
+
+ {pageType === "product" && (
+
+ )}
-
+ Skip to content
+
+
+
diff --git a/website/src/pages/docs.astro b/website/src/pages/docs.astro
new file mode 100644
index 0000000..5b9f9df
--- /dev/null
+++ b/website/src/pages/docs.astro
@@ -0,0 +1,33 @@
+---
+import ProductLayout from "../layouts/ProductLayout.astro";
+const repoUrl = import.meta.env.PUBLIC_REPO_URL || "https://github.com/IntelIP/ProfitCtl";
+const quickStart = ["git clone " + repoUrl, "cd ProfitCtl", "go run . compare examples/hybrid_steady_profit.yml examples/hybrid_profit.yml"].join("\n");
+---
+
+
+
+ 1. Choose how to run it. For a native binary, use the release installation guide. It covers version pinning, checksum verification, macOS and Linux installation, and Windows archives. Evaluator prereleases must be selected explicitly.
Release installation guide ↗ To run the current source, install Git and Go, then use the commands below in your terminal.
Get the source on GitHub ↗ {quickStart}Native CLI startup needs no provider key. Paid assessment features use separate provider configuration.
+ 2. Read the decision, not just the revenue. The saved examples compare a steady-state contract with a pilot contract. These are synthetic fixtures, so their numbers illustrate the model.
Steady-state recurring revenue $2,000 / month
Operating margin 95%
Cost per user $2.00
The pilot example books more revenue, while the steady-state example has the higher operating margin and lower cost per user. This shows why an up-front payment and sustainable recurring economics are different questions.
The comparison output includes revenue, recurring revenue, fees, booked and operating margins, cost per user, covenant results, and the leaders for each metric.
+ 3. Replace the assumptions. A scenario is a YAML file containing the business inputs you want to test.
Costs: fixed and variable costs, including infrastructure, model calls, tools, and payment fees.Pricing: subscriptions, usage pricing, plan mixes, or contract terms.Usage: users, growth, and simulation inputs.Targets: the margin and cost limits that define an acceptable outcome.Evidence: sources, capture dates, confidence, and notes for your cost assumptions.profitctl simulate -f your-scenario.yml
+profitctl compare baseline.yml candidate.yml
+profitctl validate -f your-scenario.ymlUse the installed CLI for these commands. The equivalent source invocation begins with go run ..
+ 4. Know what the website demo shows. The guided terminal runs the real ProfitCTL CLI in your browser. It validates a fictional scenario, simulates a baseline, shows a margin failure as usage grows, and compares a cheaper request route. The story repeats automatically. Select a step to hold its result. With reduced motion enabled, the demo shows a single comparison without looping.
The demo uses bundled, read-only scenario files and made-up rates. It does not call AI providers, fetch live prices, or give access to your local files. Download a scenario to inspect its inputs or run the same commands with the installed CLI.
The separate cost calculator is a simplified gross-margin illustration. Your CLI scenarios can include payment fees, contract effects, cost provenance, and simulation settings. Check assumptions against your own usage and rates before relying on an estimate.
The local CLI, Codex skill, and CI output are available today. Hosted team workspaces and approvals are planned.
+
+
+
diff --git a/website/src/pages/index.astro b/website/src/pages/index.astro
index b48cd5e..7ecc11d 100644
--- a/website/src/pages/index.astro
+++ b/website/src/pages/index.astro
@@ -1,1603 +1,155 @@
---
import ProductLayout from "../layouts/ProductLayout.astro";
+import TerminalDemo from "../components/TerminalDemo.astro";
+import { calculateExample, money, percent } from "../scripts/demo";
const repoUrl = import.meta.env.PUBLIC_REPO_URL || "https://github.com/IntelIP/ProfitCtl";
-const providers = [
- {
- name: "Cloudflare Workers",
- shortName: "Workers",
- logo: "/logos/profitctl/cloudflare-workers.svg",
- logoAlt: "Cloudflare Workers",
- fixed: "$24",
- variable: "$6.30",
- monthly: "$87",
- margin: "78%",
- p95: "62%",
- activeCost: "$9.40",
- delta: "best",
- state: "pass",
- stateLabel: "Pass",
- series: "workers",
- },
- {
- name: "Google Cloud Run",
- shortName: "Cloud Run",
- logo: "/logos/profitctl/google-cloud.svg",
- logoAlt: "Google Cloud",
- fixed: "$38",
- variable: "$8.10",
- monthly: "$128",
- margin: "66%",
- p95: "52%",
- activeCost: "$12.30",
- delta: "+47%",
- state: "pass",
- stateLabel: "Pass",
- series: "cloud",
- },
- {
- name: "Vercel",
- shortName: "Vercel",
- logo: "/logos/profitctl/vercel.svg",
- logoAlt: "Vercel",
- fixed: "$52",
- variable: "$11.40",
- monthly: "$162",
- margin: "58%",
- p95: "41%",
- activeCost: "$16.80",
- delta: "+86%",
- state: "watch",
- stateLabel: "Watch",
- series: "vercel",
- },
-];
-
-const heroMetrics = [
- { label: "Monthly cost", value: "$87", detail: "best option" },
- { label: "Gross margin", value: "78%", detail: "meets >= 60%" },
- { label: "p95 margin", value: "62%", detail: "meets >= 40%" },
- { label: "Cost / active user", value: "$9.40", detail: "meets <= $18" },
-];
-
-const deliveryModes = ["CLI today", "Codex skill", "CI output"];
-
-const evidenceCards = [
- {
- badge: "Deploy choice",
- title: "Workers vs Vercel for this Next.js app",
- logos: [
- { src: "/logos/profitctl/cloudflare-workers.svg", alt: "Cloudflare Workers" },
- { src: "/logos/profitctl/vercel.svg", alt: "Vercel" },
- ],
- bars: [
- { label: "Workers", value: 31, amount: "$87", tone: "workers" },
- { label: "Cloud Run", value: 46, amount: "$128", tone: "cloud" },
- { label: "Vercel", value: 58, amount: "$162", tone: "vercel" },
- ],
- metrics: [
- { label: "Margin", value: "78%" },
- { label: "p95", value: "62%" },
- { label: "Cost / user", value: "$9.40" },
- ],
- action: "See comparison",
- },
- {
- badge: "Deep research risk",
- title: "What is the cost risk of adding deep research?",
- logos: [
- { src: "/logos/profitctl/openai.svg", alt: "OpenAI" },
- { src: "/logos/profitctl/google-cloud.svg", alt: "Google Cloud" },
- ],
- bars: [
- { label: "Base", value: 18, amount: "$9.40", tone: "neutral" },
- { label: "+ light research", value: 36, amount: "$17.80", tone: "cloud" },
- { label: "+ deep research", value: 52, amount: "$26.60", tone: "risk" },
- ],
- metrics: [
- { label: "Margin", value: "42%" },
- { label: "p95", value: "28%" },
- { label: "Cost / user", value: "$26.60" },
- ],
- action: "Run this scenario",
- },
- {
- badge: "Pricing model",
- title: "Which pricing model keeps 60%+ margin?",
- pricingRows: [
- { label: "Pro plan ($20/mo)", value: 78, tone: "workers" },
- { label: "Team plan ($40/mo)", value: 64, tone: "cloud" },
- { label: "Usage ($0.10 / msg)", value: 38, tone: "risk" },
- ],
- metrics: [
- { label: "Best option", value: "Pro plan" },
- { label: "ARR potential", value: "$2.4M" },
- { label: "Confidence", value: "Medium" },
- ],
- action: "Model your pricing",
- },
-];
-
-const standards = [
- { label: "Provenance", detail: "Every cost line has source, capture date, and note." },
- { label: "Confidence", detail: "Low, medium, high based on actual evidence, not guesswork." },
- { label: "Covenants", detail: "Margins, p95, and user cost tracked against explicit targets." },
- { label: "Decision artifact", detail: "Shareable output with assumptions, tables, and charts." },
- { label: "No hand-wave claims", detail: "Judge blocks precise claims without trustworthy evidence." },
-];
-
-const productSurfaces = [
- {
- status: "Open source now",
- title: "CLI",
- detail: "Run compare, simulate, and validate locally.",
- items: [
- "compare, simulate, validate",
- "Scenario templates",
- "Local modeling",
- "JSON output",
- "Standards judge",
- ],
- },
- {
- status: "Open source now",
- title: "Codex skill",
- detail: "Pull repo context into cost-aware agent decisions.",
- items: [
- "Repo-aware cost decisions",
- "Architecture comparisons",
- "Assumption-aware output",
- "Temporary scenario edits",
- "No new CLI command in v1",
- ],
- },
- {
- status: "Open source now",
- title: "CI / PR check",
- detail: "Turn scenarios into gates before spend lands.",
- items: [
- "JSON output in CI",
- "Recurring margin checks",
- "Covenant failures in PRs",
- "Saved scenario files",
- "Decision evidence in reviews",
- ],
- },
- {
- status: "Hosted later",
- title: "Team workflow",
- detail: "Keep history, approvals, and calibration in one place.",
- items: [
- "Team workspaces",
- "Saved runs and history",
- "Policies and approvals",
- "Calibration connectors",
- "RBAC and SSO",
- ],
- },
-];
-
-const footerLinks = [
- { label: "GitHub", href: repoUrl, external: true },
- { label: "Get started", href: "#get-started" },
+const example = calculateExample({ users: 1000, requests: 60, price: 20 });
+const command = ["git clone \\" , " " + repoUrl, "cd ProfitCtl", "go run . compare \\", " examples/hybrid_steady_profit.yml \\", " examples/hybrid_profit.yml"].join("\n");
+const steps = [
+ { number: "01", title: "Start with what changes.", detail: "Describe usage, pricing, model calls, and infrastructure. Keep each cost tied to its source and assumptions.", mark: "Usage + rates + pricing" },
+ { number: "02", title: "Put the options side by side.", detail: "Compare a feature, model, deployment, or pricing plan. See the effect on revenue, recurring margin, and cost per user.", mark: "Baseline → candidate" },
+ { number: "03", title: "Set the limits before you ship.", detail: "Test margin and cost targets, including growth and tail risk. Keep the decision evidence in your review.", mark: "Margins + cost targets" },
];
---
-
-
-
-
-
-
-
Compare spend before it ships.
-
- ProfitCtl helps AI-native teams compare infrastructure, model, API, and pricing
- choices with unit economics that hold under real usage.
-
-
-
-
-
-
Use it as
-
- {deliveryModes.map((mode) => {mode} )}
-
-
-
-
-
-
- Open source
- MIT licensed
-
-
-
- Unit economics
- Not vibes
-
-
-
- Decision evidence
- For teams and agents
-
-
-
-
-
-
- $ profitctl compare examples/mix_profit.yml examples/hybrid_profit.yml --json
- recommended: Workers
-
-
-
- {
- heroMetrics.map((metric) => (
-
- {metric.label}
- {metric.value}
- {metric.detail}
-
- ))
- }
-
-
-
-