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 Codex first and then Claude. Machine-local overrides belong in .codex/ralph.providers.local.json.
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.