035 — create Scaffolds a Tenant Project from the Fixture Tenant
Defines the create-manychat-ai-agent package: what it generates, where its content comes from, and how it is released beside the agent. It leaves out what a tenant project is and the package it depends on, which are 033, and the plugins a tenant may add later, which are 036.
Starting from someone else's deployment is how tenant data leaks
Without a scaffolder, the quickest way to start a tenant project is to copy one that works. The only one that works is a live deployment, so the copy starts with a real business's prompt, prices and schedule, and the new tenant deletes what they notice. What they miss ships under their name, and whatever reaches this repository as an example breaks C1.
So the rule is:
A new tenant project starts from the fictional demo tenant, generated, and never from a copy of a live one.
create scaffolds from the fixture tenant, never from a live one
npm create manychat-ai-agent@latest my-agent generates a tenant project and nothing else. It is a second package, create-manychat-ai-agent, in a packages/create/ workspace, released together with the agent at the same version.
It writes:
config/from the committedconfig/*.examplefiles, byte for byte. There is no second copy of the example tenant: the scaffolder reads the same filespnpm bootstrapcopies, so the fictional demo tenant has one source (C1, C9)..envwith the offline defaultsscripts/setup.mjswrites today: the mock model, PGlite, a random shared secret and contact tokens unenforced, so the project runs before any account exists.evals/<name>/cases.jsonlwith a few cases against the demo tenant, soagent evalhas a suite to run on the first day.package.jsondepending onmanychat-ai-agentat^<version>, the version of the scaffolder that ran.docker-compose.ymlrunning the image at the same version..github/workflows/ci.ymlrunningagent config check, the mock eval suite and the tenant tests.renovate.json, so a release arrives as a pull request..gitignoreexcluding.envand trackingconfig/.
It never writes allowUnusedPatches, for the reason 033 § An urgent fix is a pnpm patch and an upstream pull request, together gives.
Everything the scaffolder writes is English and invented (C9, C1). The tenant then replaces it with their own copy, in their own repository.
A tracked config/ is only safe in a private repository
The generated CI's first step fails when github.event.repository.private is false. A tenant who makes their repository public finds out on the next push, not after their prices have been indexed. The scaffolder does not ask about visibility, because an answer given once at creation says nothing about the repository a year later.
The two packages are released as one version
create-manychat-ai-agent@<version> scaffolds a project that depends on manychat-ai-agent@^<version> and runs the image tagged <version>, so the three must exist together. The release-please manifest gains packages/create/ beside ., with the two versions linked, and release.yml publishes both from the same tag. This is the monorepo manifest that 010 § Deliberately not in scope excluded while there was one package.
Verification
- A test runs the scaffolder into a temporary directory and asserts the generated
config/equalsconfig/*.examplebyte for byte, the generated CI fails on a public repository,agent config checkpasses, andagent evalagainst the mock model passes on the generated suite. It also asserts the generated project does not setallowUnusedPatches. - A test asserts the
release-pleaseconfiguration releases.andpackages/create/at one linked version.
What this does not catch. The public-repository check runs only in a tenant's GitHub Actions, and a tenant who deletes that step, or does not use GitHub, is not covered. Nothing stops a tenant from copying a live project instead of running create; the scaffolder makes the safe start the easy one, and that is all.