Free The World is a SolidJS research site that tracks which large companies still capture massive value from products and services that are becoming easier to replace with open, automated, federated, or Bitcoin-native alternatives.
- Primary site: freetheworld.ai
- GitHub Pages mirror: prizz.github.io/free-the-world
- SolidStart
- Bun
- Tailwind CSS
- shadcn-style UI patterns with typed utility components
- Static export for GitHub Pages
bun install
bun run devbun run lint
bun run typecheck
bun run test
bun run buildThe initial Biome rollout is intentionally code-scoped. It covers the TypeScript/TSX app, scripts,
tests, and root config files, while leaving editorial content under content/, generated runtime
data under src/lib/generated/, and build/deploy artifacts outside the lint baseline for now.
bun run buildThe build pipeline:
- builds the Solid app
- prerenders the route set from
src/lib/site-routes.ts - writes the deployable artifact to
.output/public - creates
.nojekyllfor GitHub Pages compatibility
scripts/build-site.ts is the canonical build entrypoint. The legacy scripts/export-static.ts command is kept as a compatibility alias to the same flow.
Pushes to main trigger .github/workflows/deploy.yml, which:
- installs dependencies with Bun
- validates the JSON content graph
- runs
typecheck, unit tests, and Playwright - builds two target-specific artifacts under
.artifacts/deploy/ - deploys the primary canonical
https://freetheworld.airoot-path build to AWS/CloudFront while keepinghttps://free-the-world.comlive on the same stack - deploys the repo-path mirror to GitHub Pages only when the live Pages manifest has changed
Deployment runbook: docs/deployment.md
The .ai domain rollout is staged so repo changes can land before Route 53 registration or delegation finishes. Until the new hosted zones exist, the AWS setup/bootstrap scripts stay in report-only mode and the verification command surfaces a domain-readiness blocker instead of a generic fetch error.
Canonical editorial data lives under content/ as validated JSON and is compiled into src/lib/generated/content-graph.ts for app/runtime use. UI-domain types still live under src/lib/domain/types.ts.
The current launch snapshot includes:
- top 10 S&P 500 companies by market cap (curated early-2026 snapshot)
- sectors and industries as first-class metadata
- visible source breadcrumbs
- product and alternative analyses
- technology-wave assumptions used in scoring
The repository separates published content from draft research:
content/→ canonical JSON content and taxonomysrc/lib/generated/content-graph.ts→ generated runtime graph for the appresearch/→ notes and tracked research run artifactsprompts/→ reusable prompt templatesscripts/compile-content.ts→ validator/compiler for raw contentscripts/ralph-loop.ts→ low-level repeatable AI prompt loopscripts/sync-company.ts/scripts/sync-all.ts→ structured research-to-publish commands
Prompt assets for reusing this project's formula in other repos:
prompts/gsd-new-project-research-registry.md→ generic$gsd-new-projectseed for thesis-driven research registry sites using this repo's stack and architecture defaultsprompts/gsd-new-project-politician-wealth-example.md→ worked example for a US politician wealth and holdings research site using the same stack pattern
Core content commands:
bun run migrate:content
bun run content:validate
bun run content:compileRepo-local manifest intake guidance lives in .codex/skills/company-manifest-queue/SKILL.md.
Start from raw names, tickers, or group phrases and let the repo create an unverified request, prepare validated queue entries, and optionally hand off to the full pipeline:
bun run company:intake --raw="Visa, Oracle, next 10 S&P 500 companies" --mode=prepare --provider=autocompany:intake writes repo-tracked unverified requests to content/manifests/unverified/ and
local run summaries to .codex/logs/company-intake/<request-id>/summary.{json,md}.
Use --already-researched=refresh when you want companies with published bundles to be re-run
through the research pipeline instead of being skipped.
Resume a prepared request and run research without publishing:
bun run company:intake --request=<request-id> --mode=dry-run --provider=autoResume a prepared request and publish website content:
bun run company:intake --request=<request-id> --mode=publish --provider=auto --no-commit=truecompany:intake defaults to:
--mode=prepare--provider=auto(Codex first, then Claude fallback)--loop-tasks=company-overview--concurrency=5--already-researched=skip--no-commit=true
Refresh the currently modeled S&P 500 catalog without publishing:
bun run sync:all --target=all --provider=codex --mode=dry-run --no-commit=truePrepare a frozen top-50 expansion before any publish run:
bun run company:intake --raw="S&P 500 top 50 companies by market cap as of 2026-05-24" --mode=prepare --provider=codex --already-researched=refresh --batch-id=sp500-top50-2026-05-24 --group-label="S&P 500 Top 50 by market cap" --request-notes="Freeze and refresh the top-50 market-cap cohort." --loop-tasks=company-overview --concurrency=5Review the prepared request summary and candidate roster, then resume the printed request id with --mode=dry-run before publishing.
Queue a net-new company from a draft manifest file:
bun run company:queue --manifest=./drafts/some-company.jsonQueue, promote, run a lightweight Ralph loop, and kick off structured sync in one command:
bun run company:pipeline --manifest=./drafts/some-company.json --batch-id=top25-refresh --group-label="S&P 500 Top 25 refresh" --request-notes="Frozen market-cap snapshot." --provider=autocompany:pipeline defaults to:
--loop-tasks=company-overview--concurrency=5--mode=dry-run--no-commit=true
Use --batch-id=<id> by itself to process an already queued batch. --concurrency=<n> applies to the low-level loop phase and to dry-run syncs; publish syncs still run serially even if you request a higher concurrency.
Use --mode=publish --no-commit=false only when you are ready to persist website content and push it.
Promote a queued manifest into the canonical manifest set:
bun run company:init --queued=some-companyIf you need to bypass the queue and promote a manifest file directly:
bun run company:init --manifest=./some-company.jsonAfter promotion, run the normal Ralph sync:
bun run sync:company --company=some-company --provider=auto --mode=dry-runGenerate prompt artifacts for one company and task:
bun run loop --company=microsoft --task=moat-analysisExecute the low-level loop with a configured provider:
bun run loop --company=microsoft --task=moat-analysis --provider=auto --execute=trueThe loop runs up to 5 companies in parallel by default. Override that with --concurrency=<n> when you want a lower or higher provider fan-out:
bun run loop --batch-id=top25-refresh --task=company-overview --provider=auto --execute=true --concurrency=10Run the full structured sync pipeline for one company:
bun run sync:company --company=microsoft --provider=auto --mode=dry-runGenerate low-level loop artifacts for every seeded company:
bun run loopProvider defaults live in config/ralph.providers.example.json; auto tries Cursor Agent first (default model grok-4.5-xhigh), then Codex, then Claude. Authenticate Cursor via agent login or CURSOR_API_KEY. Machine-local overrides in .codex/ralph.providers.local.json merge on top of the example (provider entries and optional defaultProviderOrder), so older local files still pick up newly added backends like Cursor.
Claude provider entries can also set env overrides; the default profile now disables nonessential traffic and official marketplace autoinstall so Ralph runs are less exposed to local Claude plugin state.
Theme tokens live in src/lib/theme.ts and CSS variables in src/app.css. The default palette uses near-black violet backgrounds with deep-indigo accents, but the token layer is meant to keep that swappable.