Skip to content

ADR 0022: Every Project starts from an empty repository

Agent tools need a repository to write to. A Project without a repository in the git service gives agents no place for files. Its test Tasks fail, and no live app can start. The product has no templates and no prefilled files.

  • A Project is a name and a slug. POST /v1/projects has no template field (the API ignores unknown fields). The create form has no template choice.

  • Each Project gets a repository in the git service with one commit that holds only .gitignore (node_modules). That commit is Canonical Generation 0. project.provision makes it.

  • Seed rule (workers/integration/src/source-seed.ts, critical test): seed only when the canonical source is unassigned at Generation 0. ProjectRootDO assignSource enforces the same rule at the write. A repeat never changes a Project that has source.

  • Backfill: POST /v1/projects/:id/provision (no body) and POST /v1/projects/:id/app (“Deploy app”) both make the empty repository when the source is unassigned. bun scripts/seed-repo.ts <projectId> local [--user <Clerk user ID or email>] calls them.

  • The app conventions are model instructions (APP_CONVENTIONS in packages/protocol/src/app.ts), and they add no files. They ask for these items:

    • a Worker with src/worker.ts and a Hono app from src/app.ts;
    • static files in public/;
    • the package.json scripts typecheck, test, contract, and dev;
    • a scripts/contract.ts that prints {"routes":[...]};
    • at least one test;
    • env.DATA for storage;
    • a fake identity only.

    The Root Planner and the Context Compiler both give the conventions to the model.

  • The Root Planner sees the canonical file list. For an empty repository (no root package.json), t1 must be an implement bootstrap Task, and every other Task must depend on it. Application code checks this and asks for one repair turn when the plan breaks the rule.

  • Verification of the first Change: the contract check treats a base without package.json as a base with no contract. It passes when the Candidate prints a valid route table. A missing Candidate table is a gap.

  • The browser check runs one flow for every app. It is a required check for each Candidate whose Change touches UI, at every risk tier. The flow has three steps:

    1. The home page shows text.
    2. GET /api/health answers.
    3. Every linked page opens, by a click and by a direct load. The check explores breadth first from the home page, up to 8 pages, and submits up to 3 forms per page with sample values.
  • Live app: for a tree with no code file, the production row is ready with no bundle. The router answers 200 “Nothing built yet. Tell Rhumbatron what to make.” The first release moves the pointer to a bundle.

  • Goal suggestions (GET /v1/projects/:id/suggestions, workers/agents/src/suggestions.ts). A Clef question is a bounded choice and returns no text. So clef-flash ranks a fixed list of short goals: “start” goals for a repository with no code, “extend” goals for other repositories. The inputs are the Project name, up to 200 file paths, and the last 5 goals. The top 4 goals show as pills under the goal box. A click puts the goal in the box. The product database caches the result per Project and Canonical Generation (goal_suggestions, migration 0020). The cap is 100 calls per UTC day (usage_counters goal-suggestions). When the cap is reached or the call fails, the page shows no pills.

  • Agents always have a repository to write to. A blank Project’s first Change must build the app in the conventions’ shape, or the build, unit, and contract checks fail.
  • Each Project costs one small repository at creation. This includes scratch and smoke Projects. Archive cleanup deletes the repository.
  • A rollback to Generation 0 of a blank Project builds an empty tree, and the build fails. The release is failed, and the pointer does not move.