factory0.ventures · FZ/01
Factory Zero is an AI-native venture studio. It creates, launches and operates companies through a shared network of autonomous agents.
The company is becoming software. Software automated the worker. Agents automate the organization. The traditional company coordinates humans. The AI-native company coordinates intelligence.
Historically, software automated individual workflows. The next step is software coordinating the organization itself. Factory Zero builds real companies around that transition.
Factory Zero OS runs as five layers. Each function in each layer is an agent.
| Layer | Agents |
|---|---|
DISCOVER |
Research · Strategy · Analytics |
BUILD |
Product · Engineering · Design · QA |
OPERATE |
Infrastructure · Security · Support · Finance |
DISTRIBUTE |
Growth · Content · Sales |
LEARN |
Legal · Knowledge · Optimization |
Every venture inherits the same foundation, so nothing is rebuilt. Identity, payments and billing, analytics, deployment, observability, agent orchestration, customer support, marketing automation, finance, knowledge, security, experimentation and internal tooling are all shared.
Each venture runs with its own brand, product, customers, data boundaries and strategy.
FZ-001 Kontinuum. An AI composer performing on a deterministic real-time engine. Music written and performed continuously, personalised to the listener, and playable offline. Not a streaming app and not a DAW: a living instrument. Currently at prototype stage, with no public surface yet.
SIGNAL → VALIDATION → PROTOTYPE → LAUNCH → AUTONOMY → SCALE
| Level | ||
|---|---|---|
LEVEL 0 |
Human-operated | |
LEVEL 1 |
AI-assisted | |
LEVEL 2 |
Agent workflows | |
LEVEL 3 |
Agent-operated | target |
LEVEL 4 |
Self-optimizing | target |
LEVEL 5 |
Autonomous company | target |
Ventures are designed to run at levels 3 to 5. Humans can intervene at every level, and a named human is accountable for every venture.
HUMAN LAYER |
AGENT LAYER |
|---|---|
| Mission · Capital · Governance · Judgment | Research · Build · Operate · Optimize |
| Humans define mission, capital, ethics, ownership, risk boundaries, high-impact decisions and relationships. | Agents execute within those boundaries. Every action is logged, observable and reversible. |
This repo is the Factory Zero marketing site. Static HTML, CSS and vanilla JavaScript. No build step, no framework, no dependencies. Serve the directory and it runs.
It was implemented from the Claude Design source Factory Zero.dc.html, which
targets the dc-runtime preview environment (<x-dc> templates, {{ }}
bindings, <sc-for> loops, a React DCLogic class). That runtime is a
design-time dependency, so the component logic was ported to plain JavaScript.
Timings, easing, canvas geometry, colour thresholds and copy carry over
unchanged.
The site uses the design system documented in DESIGN.md: dark,
square, hairline grid, one lime accent, Inter Tight, imagery generated with MiniMax.
The 3D hero network (fz-hero3d.js) and the hero canvas (fz-app.js) are gone.
index.html home
ventures/index.html the venture registry
system/index.html three-layer architecture + design principles
thesis/index.html the working paper, 7 sections
about/index.html what Factory Zero is and is not
enter/index.html access request
404.html styled not-found page
assets/
fz-ui.css the design system (see DESIGN.md), loaded by every page
fz-ui.js reveal, count-up, hero loop, venture grid filters, live log
fz-data.js ← venture data lives here (single source of truth)
fz-common.js loaded on every page
fz-ventures.js venture-page activity charts and the shared chart helpers
ui/ generated imagery and the hero loop (MiniMax; prompts in DESIGN.md)
fz-timeline.js home: draws the venture chart in, crosshair and focus
fz-stack.css the /stack/ page: KPI band, map, panel, walk, catalogue (tools/stack-page.js)
fz-stack.js the /stack/ page map: tiles, links between them, filters, panel
timeline-data.json org creation dates and commits per day (counts only)
fz-enter.js access-request form
films/ venture films (MP4 + poster); listed in fz-data.js `films`
kontinuum-animated.svg FZ-001 brand mark (animated, self-contained)
favicon.svg
og.png, og-*.png per-page 1200x630 Open Graph cards (generated)
readme-banner.png the banner above (generated)
apple-touch-icon.png, icon-512.png
robots.txt allows AI and answer-engine crawlers explicitly
sitemap.xml all six pages
llms.txt plain-text summary for machine readers
stack.json what each venture is built with (generated)
site.webmanifest
_headers Cloudflare Pages response headers
.well-known/
security.txt RFC 9116
tools/
og-render.html OG card template (takes ?t=&k=&s= overrides)
banner-render.html README banner
render-og.sh regenerates every raster asset
sync-ventures.js writes fz-data.js into the static HTML
ui.js shared header, footer, venture card and filter markup
stack-page.js writes stack/index.html from the registry (run by sync-ventures.js)
timeline.js draws the home-page venture chart (used by sync-ventures.js)
sync-timeline.js rebuilds timeline-data.json from the GitHub API
build-dist.sh assembles dist/ (allowlist + cache-bust stamping)
i18n.js renders every page in 11 languages (dist/<code>/...), keys, alternates, sitemap
check-i18n.js checks locales/ against the English strings and placeholders
locales/ languages.json (codes, names, hreflang), en.json (the keys), <code>.json
English is the source; the site is also published in Dutch, German, French,
Spanish, Brazilian Portuguese, Russian, Indonesian, Japanese, Korean and
Simplified Chinese (/nl/, /de/, ..., /zh/).
- The English HTML is the source.
tools/i18n.jstreats each text block as a unit keyed by its English markup. Inline elements become{n}...{/n}markers and keep their attributes. Attributes such asaltandaria-labelare units too.translate="no"leaves an element alone. - Client scripts call
FZ_I18N.t('English text', { name })(assets/fz-i18n.js). Dates and numbers useIntlwith the page language. - To change English copy: edit the HTML (or
fz-data.js), runnode tools/i18n.js extract, then translate the new keys in eachlocales/<code>.json.node tools/check-i18n.jsmust pass before merging. - To add a language: add it to
locales/languages.json, addlocales/<code>.jsonwith every key, then add its font stack inassets/fz-ui.cssif the script needs one.
### Run it locally
```sh
python3 -m http.server 8099
# → http://127.0.0.1:8099/
Paths are absolute (/assets/...), so open it through a server rather than
file://.
Nearly everything is data:
assets/fz-data.jsholdsventuresandlayers(the agent grid; each agent's line says what it does, never a made-up event or number). Add real ventures there. The pipeline, the branch list and the hero counters all derive from that array.- After editing
ventures, runnode tools/sync-ventures.js. The registry grid of venture cards is written intoventures/index.htmland the chips intosystem/index.htmlas static HTML so they are indexable with JavaScript off. That script regenerates them fromfz-data.js, which stays the only place venture data is authored. It only rewrites the regions between the<!-- fz:*:start -->/<!-- fz:*:end -->markers. The same run writes one product page per venture atventures/<slug>/index.html(icon, pitch, aims, film, built-with list, activity charts and related ventures, plus its own title, description, canonical URL and structured data), the venture entries insitemap.xml, andfunctions/api/activity-sources.json. Commit all of it; never edit the generated venture pages by hand. - What each venture is built with is the
usesarray on its record inassets/fz-data.js: sister ventures by id (FZ-013) and third parties by a key ofservices(polar,cloudflare,google-fonts,aws-ses, …), each with a role (framework,email,support,bug-reports,payments,security-screening,secrets-handoff,agents,deploys,fonts,hosting) and a status,live(in use today, and checked) orplanned.sync-ventures.jsrenders it as the "Built with" row on each venture page and writes/stack.json, which each venture site vendors into a footer strip and its subprocessors list with its owntools/script (no runtime fetch). An unknown id, role or status stops the sync. The evidence for every entry is intools/STACK-SOURCES.md(not published); update it with the entry, and never mark an entrylivewithout a check you could repeat. - The venture chart on the home page (full width, under "The factory never
stops.") is static markup that
sync-ventures.jsdraws throughtools/timeline.jsfromassets/timeline-data.json: one smooth line per venture, from the day its GitHub org was created, its commits per day, and a bold line for the total; the launch strip names every venture. It also writes the legend and a small JSON block of counts thatassets/fz-timeline.jsreads. The file holds counts only, never repository names; private repositories count by number, as in the activity chart. Refresh it withnode tools/sync-timeline.js(needsghlogged in; it rewrites the data and rerunssync-ventures.js; a refresh across every branch of the larger orgs takes a good while). With JavaScript off or motion reduced the finished chart shows; with motion allowed the lines draw in on scroll, and hovering or arrow-keying the chart reads a day, while hovering a name dims the other lines. - GitHub activity. The detail panel charts weekly commits and issues (open count, opened/closed per week, the five newest open ones; titles that look like security reports are left out of that list) across a
venture's public repositories (its
githublinks; an owner-only link means all of that owner's public, non-fork repositories).functions/api/activity.jsfetches them from GitHub and keeps the last good result in Workers KV (bindingACTIVITY, declared inwrangler.toml). Visitors are always served that copy; once it is a day old the next request refreshes it in the background, and a failed refresh keeps the old copy and retries in 10 minutes, so a GitHub outage or expired token makes the chart older, never empty. - Private repositories count, by number only. With the
GH_APP_IDandGH_APP_PRIVATE_KEY(PKCS#8 PEM) Pages secrets set, every venture org that installed the read-only Factory Zero Activity GitHub App (Metadata: read, Issues: read) is read through that app, so its private repositories add to the commit and issue totals. Private repository names, issue titles and links are never published: the issue list shows public repositories only and error messages carry status codes, not names. Orgs without the app count public repositories only. Set it up withnode tools/setup-github-app.mjs(creates the app, stores both secrets without writing the key to disk, opens the install page); after a deploy,node tools/setup-github-app.mjs --refreshmakes every venture refetch. It only queries the owners and repositories inactivity-sources.json. Set aGITHUB_TOKENPages secret (a fine-grained token with no permissions is enough) to lift GitHub's 60-requests-an-hour anonymous limit. - Venture films are the
filmsarray inassets/fz-data.js: each names a venture record and a film and poster inassets/films/.sync-ventures.jswrites the home-page "Films" grid and each venture's own film panel, and it stops if a film's venture is unknown or a file is missing or over 25 MiB. Add a film there, then run the sync. window.FZ_CONFIGat the bottom of the same file holds the headline and factory status. These mirror the editabledata-propsfrom the design source; the headline is also written statically inindex.html.- The home page's generated regions (
fz:herocards,fz:stats,fz:marquee,fz:vtools,fz:vgrid,fz:steps,fz:films,fz:timeline,fz:footer) are written bysync-ventures.jsfrom the records. The stats band counts ventures, sectors, FZ STACK ventures, ventures that "run on a sister venture" (records with at least oneusesentry that names another venture and islive, so aplannedlink never inflates it) and films. The hero's "most used" card is the FZ STACK venture with the most liveusesfrom other ventures. - All prose (thesis, human role, footer) is plain HTML in
index.html.
./tools/render-og.shUses headless Chrome. ImageMagick cannot rasterize these correctly on macOS: it silently falls back to its internal renderer and drops colour.
| File | Purpose |
|---|---|
llms.txt |
Structured plain-text summary for LLM readers |
robots.txt |
Explicit allow for GPTBot, ClaudeBot, PerplexityBot, Google-Extended and others |
JSON-LD in index.html |
Organization, WebSite, WebPage, and a DefinedTermSet for the autonomy levels |
og.png, og-*.png |
A 1200x630 card per page, generated from the real hero visual |
| JSON-LD per page | Page type plus BreadcrumbList; the thesis also emits an Article |
| Directory-style URLs | /ventures/ rather than /ventures.html, so nothing needs redirecting later |
.well-known/security.txt |
RFC 9116 contact |
Three deliberate changes, each fixing something that did not work in the preview runtime:
style-hover. The design source setsstyle-hover="..."on the footer CTA and pipeline units, butdc-runtimeimplements no such attribute, so those hovers never fired. Reimplemented as real CSS:hover.fzScan. The pipeline scan line animatedtranslateY(-100%)totranslateY(100%)on a 120px band, so it only ever travelled 240px inside a much taller grid. Reimplemented withbackground-positionso it sweeps the full container height.- Responsive behaviour. The design is desktop-only. Added a wrapping
header, stacking breakpoints,
minmax(min(Npx, 100%), 1fr)andmin-width: 0on grid tracks. Verified: no horizontal overflow from 320px to 1440px.
/enter/ posts JSON to functions/api/contact.js, a Cloudflare Pages Function
that verifies Turnstile and sends the mail through Owlpost (POST https://api.owlpost.to/v1/emails, Factory Zero's own email API, FZ-013) on the
transactional stream, with an Idempotency-Key derived from the submission so
a retry or double submit is mailed once.
Security properties, since this is a public unauthenticated endpoint:
| Concern | How it is handled |
|---|---|
| Open relay | The recipient is fixed server-side. It is never read from the request. |
| Secret exposure | OWLPOST_API_KEY and TURNSTILE_SECRET are Pages secrets (encrypted). Only the public Turnstile sitekey appears in the HTML. |
| Bots | Cloudflare Turnstile, verified server-side, plus an off-screen honeypot field that is silently accepted so bots learn nothing. |
| Flooding | A zone rate-limit rule: 3 POSTs per 10s per IP. |
| Header injection | Every value that could reach a mail header is stripped of CR, LF and NUL. |
| DMARC | from is always our own verified domain. The submitter's address goes in reply_to only, never in from. |
| Cross-origin abuse | Requests with a foreign Origin are rejected. |
| Oversized input | Body capped at 20KB, message at 5,000 chars. |
| Information leak | Client errors are generic. Detail is logged server-side only. |
If Owlpost is unreachable or unconfigured the form falls back to showing
contact@factory0.ventures rather than pretending the message was sent.
Setup that is not in this repo (do not commit any of it):
bunx wrangler pages secret put OWLPOST_API_KEY --project-name factory-zero
bunx wrangler pages secret put TURNSTILE_SECRET --project-name factory-zeroOptional overrides, as plain Pages env vars: CONTACT_TO (default
contact@factory0.ventures), CONTACT_FROM (default
noreply@send.factory0.ventures) and OWLPOST_BASE_URL (default
https://api.owlpost.to).
The sending domain must be verified in Owlpost, and this is the part with a
trap. Verify the subdomain send.factory0.ventures, not the apex.
Verifying the apex puts sending records on factory0.ventures itself, and an
MX there would displace Cloudflare Email Routing and break inbound mail to
contact@factory0.ventures. Using a subdomain keeps the two entirely separate.
Twenty-three ventures are listed, and all twenty-three are real and named:
| Venture | Stage | Target | Site | Source | |
|---|---|---|---|---|---|
FZ-001 |
Kontinuum | PROTOTYPE |
L4 | kontinuum.audio | Kontinuum-ai/kontinuum-engine |
FZ-002 |
Undercover Rockstars | LAUNCH |
L3 | undercoverrockstars.com | Undercover-Rockstars/website |
FZ-003 |
Yoginini | VALIDATION |
L3 | yoginini.us | Yoginini/website |
FZ-004 |
Cratefield | VALIDATION |
L4 | cratefield.com | Cratefield/harness |
FZ-005 |
VibeCaddie | VALIDATION |
L5 | vibecaddie.com | VibeCaddie/website |
FZ-006 |
Colonizer | PROTOTYPE |
L4 | colonizer.dev | Colonizer-dev/harness |
FZ-007 |
FindsYou.work | VALIDATION |
L4 | findsyou.work | FindsYou-Work/website |
FZ-008 |
SupportGenius | VALIDATION |
L4 | supportgeni.us | SupportGenius/website |
FZ-009 |
promptdecode | VALIDATION |
L4 | promptdeco.de | PromptDecode/website |
FZ-010 |
Groove Guru | VALIDATION |
L4 | groove.guru | Groove-Guru/website |
FZ-011 |
PosPlugin | VALIDATION |
L4 | posplug.in | POSplugin/website |
FZ-012 |
Keep Shipping | VALIDATION |
L4 | keepshipping.run | Keep-Shipping/website |
FZ-013 |
Owlpost | VALIDATION |
L4 | owlpost.to | Owlpost-to |
FZ-014 |
Bloodrank | VALIDATION |
L3 | bloodrank.dev | Bloodrank |
FZ-015 |
ratecla.im | VALIDATION |
L4 | ratecla.im | Rateclaim |
FZ-016 |
Sealbin | VALIDATION |
L4 | sealb.in | sealbin |
FZ-017 |
release.show | VALIDATION |
L4 | release.show | Release-Show |
FZ-018 |
Living Brain | VALIDATION |
L4 | livingbrain.wiki | Livingbrain-wiki/livingbrain |
FZ-019 |
Shoal | VALIDATION |
L4 | shoal.ing | shoal-ing/website |
FZ-020 |
Tokker | VALIDATION |
L4 | tokker.dev | Tokker-dev/tokker |
FZ-021 |
Ledgers | VALIDATION |
L4 | ledgers.sh | Ledgers-sh |
FZ-022 |
Ghostwritin' | VALIDATION |
L4 | ghostwrit.in | Ghostwritin |
FZ-023 |
Squeezin | VALIDATION |
L4 | squeez.in | Sqeezin |
autonomy is null on every one of them: no venture has a measured figure,
and the registry does not show one. Set a figure in fz-data.js when there
is one. What each record shows instead:
target: the autonomy level (0–5) the venture is designed to reach. A stated aim, labelledAUTONOMY TARGET, never a measurement.aims.operate,aims.intelligence,aims.growth: in words, what the venture should run on its own, the kind of intelligence that takes, and what will count as growth. The growth line names what gets counted, not a count.github: public repositories only. Private backends are not linked.
Nothing else is listed: the registry shows only what exists, so a venture with nothing public yet does not get a placeholder row.
None of the twenty-three can be bought from today, and their records and llms.txt
say so, and do not let any of them read as shipped.
Nothing on the home page is simulated. The FZ/LOG band shows real public
GitHub activity across the ventures, from functions/api/log.js (logic in
functions/api/_log-core.js, checked by node tools/test-log.mjs): a KPI strip
over a feed of merged pull requests and opened issues, newest first, each line
linking to GitHub. Only public repositories are searched, so no private name or
title can appear. The response is cached in KV (log:v2) and refreshed every
15 minutes. A KPI is left out (shown as a dash) when the search behind it was
cut off, rather than counted from a partial list.
The KPI strip, every figure from the same searches (days are WITA, UTC+8):
- Merged · 24h: merged pull requests whose merge time is within the last 24 hours.
- Merged · 7d: merged pull requests merged in the last 7 days. Its 14-day sparkline is the merged count for each WITA day, today last.
- Issues opened · 7d: issues (not pull requests) created in the last 7 days.
- Issues closed · 7d: issues closed in the last 7 days (GitHub's total).
- Active ventures · 7d: ventures with at least one merge or opened issue in the last 7 days, of the 23 in the allowlist.
- Median to merge · 7d: median of (merged time minus created time) over the pull requests merged in the last 7 days.
- Ship streak: consecutive WITA days with at least one merged pull request, counted back from today; a day with no merge yet today starts the count at yesterday. The search covers 15 days, so the streak reads "the 14-day window is full" at 14.
- Most active · 7d: the venture with the most merged pull requests in the last 7 days (ties go to the lower venture id).
The response also carries merged30d (merged pull requests in the last 30 days).
No element on the page reads it today.
Requests to GitHub search per refresh: one paged search for merged pull requests
(last 15 days), one paged search for issues (last 7 days), and one count-only
search each for merged pull requests (30 days) and closed issues (7 days), each
repeated per query batch. The allowlist needs three batches, so a refresh makes
about 16 to 20 requests (19 when measured on 20 October 2026), against 8 before.
The first request after a cold cache waits for the whole refresh, which took about
28 seconds in that measurement. Without a GITHUB_TOKEN secret, GitHub's
unauthenticated search limit (10 a minute) is shorter than that burst.
The venture chart on the home page is a dated snapshot of commit counts, private repositories included by number only; its date range is printed above it.
Live at https://factory0.ventures, on Cloudflare Pages (project
factory-zero, account "Kontinuum"). www 301s to the apex via a Single
Redirect rule.
Deploys are direct upload, not git-connected:
./tools/build-dist.sh
bunx wrangler pages deploy dist --project-name factory-zero --branch maintools/build-dist.sh assembles dist/ from an explicit allowlist, so repo
tooling (tools/, README.md, .git) can never end up on the site. It also
stamps every CSS/JS reference with a short content hash (?v=…). That matters:
asset filenames are not versioned in the repo, so without the stamp a deploy
cannot invalidate a cached file and visitors keep running the old JavaScript.
With it, _headers can cache /assets/*.css and *.js immutably.
_routes.json sends only /api/* to the Pages Functions Worker; every other path is
served from the asset cache. Keep it in step with functions/.
dist/ is gitignored. The repo root stays the thing you serve locally, with
no build step.
Other notes:
- Cloudflare Email Routing already handles
contact@factory0.ventures(MX, SPF, DKIM and DMARC records exist on the zone). Do not disturb those. - HSTS is deliberately not set in
_headers. Turn it on in the Cloudflare dashboard (SSL/TLS, Edge Certificates) where it can be rolled back. - To connect git deploys instead, link the repo in the Pages dashboard with
build command
./tools/build-dist.shand output directorydist.
GitHub Pages was enabled briefly while this repo was named
Factory-Zero.github.io; it has been deleted and the repo renamed to website.
