- name
- caffeine-app
- description
- Scaffold and build a complete Caffeine app (caffeine.ai) from scratch — the project layout, the caffeine.toml workspace + canister manifests, the mops.toml for the single Motoko `backend` canister, the React/Vite frontend, and the caffeine CLI build loop (auth login, doctor, install, check --fix, preview --build). Use whenever the user wants to create, scaffold, set up, or build a Caffeine app or a caffeine.ai project, asks about caffeine.toml or mops.toml structure, or needs the caffeine CLI workflow — even if they do not say the words 'from scratch'. Always pair it with the `writing-motoko` skill for the backend code. Do NOT use it for Motoko language syntax or compiler errors (use the `writing-motoko` skill), and do NOT use it for generic Internet Computer / dfx / icp deployment (use the `icp-cli` skill).
- license
- Apache-2.0
- compatibility
- @caffeineai/cli (the `caffeine` command), Node.js >= 18.17, pnpm, network access + a caffeine.ai account
- metadata
- {"title":"Caffeine App (build from scratch)","category":"Integration"}
# Caffeine App (build from scratch)
Caffeine (caffeine.ai) builds and hosts full-stack apps on the Internet Computer: a
single **Motoko backend canister** plus a **React/Vite frontend** served as an assets
canister. This skill teaches the exact **project shape** and the **CLI build loop** so
you can produce a buildable Caffeine app from nothing.
**This skill owns the project shape and the build workflow. It does NOT own the Motoko
language.** Before you write or edit any backend code, fetch and follow the `writing-motoko`
skill: <https://skills.internetcomputer.org/skills/writing-motoko/SKILL.md>. That skill is
authoritative for actor syntax, stable state, `mo:core`, and compiler errors. This
skill only shows the minimal empty actor and where it lives.
## When to use this skill
- Creating/scaffolding a new Caffeine app or caffeine.ai project from scratch.
- Writing or fixing `caffeine.toml` (workspace or canister manifest) or `mops.toml`.
- Running the caffeine CLI loop: `auth login`, `doctor`, `install`, `check`, `preview`.
Do **not** use it for Motoko language details (use `writing-motoko`) or for raw IC/`dfx`/`icp`
deployment (use `icp-cli`). Caffeine apps are built and deployed through the `caffeine`
CLI and the caffeine.ai web app, **not** through `dfx`.
## Critical facts
- **There is no `caffeine init` / `caffeine new`.** "From scratch" means you create the
files in this skill by hand, then run the build loop. (`caffeine projects clone <id>`
only downloads an *existing* cloud project — it is not a greenfield scaffold.)
- **Exactly one backend canister, and it must be named `backend`.** `mops.toml` declares
a single `[canisters.backend]`.
- **The frontend↔backend binding files are generated, never hand-written.**
`src/frontend/src/backend.ts` and `src/frontend/src/declarations/` are produced by
`caffeine-bindgen` during the build. Editing them is pointless — they are overwritten.
- **Deploying to a live URL is done in the caffeine.ai web app, not the CLI.** The CLI
takes you as far as a built **draft** (`caffeine preview --build`, which needs a cloud
`project.id` — see the build loop). There is no `caffeine deploy`/`publish` command.
## Prerequisites (run once)
```bash
# Install the CLI (public npm package). The binary is `caffeine`.
npm install -g @caffeineai/cli
# Authenticate against caffeine.ai (opens a browser; use --device on headless hosts).
caffeine auth login
caffeine auth status
# Check the environment: Node, pnpm, mops, caffeine-bindgen, that you are logged in,
# and that the Caffeine API is reachable (installs/repairs what it can).
caffeine doctor --fix
```
If a global install is undesirable or fails, run every `caffeine` command through an
`npx -y @caffeineai/cli@latest` prefix instead — e.g. `npx -y @caffeineai/cli@latest auth status`.
`caffeine doctor --fix` checks Node.js, pnpm, mops, and caffeine-bindgen, confirms you
are logged in, and verifies the Caffeine API is reachable — installing or repairing what
it can. It does **not** install the Motoko compiler (`moc`) or linter (`lintoko`): mops
fetches those automatically from the `[toolchain]` pins in `mops.toml` on the first
`mops install` / build. `dfx` is not part of the Caffeine build.
## Project shape
A Caffeine app is a pnpm workspace with a root manifest and two canisters. Create this
exact tree (file contents below):
```text
my-app/
├── caffeine.toml # root workspace manifest — MUST contain [workspace]
├── mops.toml # Motoko build config — ONE per project, at the root
├── package.json # pnpm workspace root + the `bindgen` script
├── pnpm-workspace.yaml # declares src/**/* as workspace packages
├── tsconfig.json # root TS config
└── src/
├── backend/ # the single Motoko canister, named "backend"
│ ├── caffeine.toml # canister manifest: type = "motoko"
│ ├── main.mo # actor entry point (write with the `writing-motoko` skill)
│ └── system-idl/ # Candid for IC system canisters (see note below)
│ └── aaaaa-aa.did # IC management canister interface
└── frontend/ # the assets canister (React + Vite)
├── caffeine.toml # canister manifest: type = "assets"
├── package.json # frontend deps + scripts (see references/frontend-template.md)
├── vite.config.js # (see references/frontend-template.md)
├── tsconfig.json # (see references/frontend-template.md)
├── biome.json # (see references/frontend-template.md)
├── tailwind.config.js # (see references/frontend-template.md)
├── postcss.config.js # (see references/frontend-template.md)
├── index.html
├── env.json # runtime config — copied into dist/ on build
└── src/
├── main.tsx # React entry (providers)
├── App.tsx
├── index.css
├── backend.ts # GENERATED by caffeine-bindgen — do NOT edit
└── declarations/ # GENERATED by caffeine-bindgen — do NOT edit
```
Only the **root** manifest, the two **canister** manifests, `mops.toml`, `main.mo`, and
the small root config files are shown inline below. The full frontend boilerplate
(`package.json`, `vite.config.js`, the Tailwind/PostCSS/Biome configs, `index.html`,
`env.json`, `main.tsx`, a starter `App.tsx`) is in
[`references/frontend-template.md`](references/frontend-template.md) — read it when you
create the frontend.
## Manifests
### Root `caffeine.toml` — the workspace
The root manifest **must** contain a `[workspace]` section. That section is what marks
it as the workspace root; without it, the CLI treats this file as an ordinary canister
manifest and discovery fails.
```toml
manifest_version = "0.1.0"
[project]
name = "My App"
# id is assigned by the cloud after your first `caffeine preview`/create — omit it for
# a brand-new local project; the CLI fills it in.
[workspace]
include = [ "src/**" ]
# Build the backend before the frontend, because the frontend imports generated
# bindings produced from the backend's Candid interface.
[canisters.frontend]
depends_on = [ "backend" ]
```
`[workspace].include` is a list of globs the CLI scans for nested canister manifests.
`src/**` finds `src/backend/caffeine.toml` and `src/frontend/caffeine.toml`.
### `src/backend/caffeine.toml` — the Motoko canister
```toml
manifest_version = "0.1.0"
[project]
name = "backend"
type = "motoko"
main = "main.mo"
[build]
commands = ["mops build", "pnpm bindgen"]
out = "dist"
[check]
commands = ["mops check"]
[check.fix]
commands = ["mops check --fix"]
```
`[build].commands` run in order: `mops build` compiles `main.mo` to Wasm + Candid, then
`pnpm bindgen` (defined in the root `package.json`) turns that Candid into the frontend's
TypeScript client. `caffeine check --fix` runs `[check.fix].commands`.
### `src/frontend/caffeine.toml` — the assets canister
```toml
manifest_version = "0.1.0"
[project]
name = "frontend"
type = "assets"
[build]
commands = ["pnpm build"]
out = "dist"
[check]
commands = ["pnpm typecheck", "pnpm check"]
[check.fix]
commands = ["pnpm typecheck", "pnpm fix"]
```
### `mops.toml` — the Motoko build (one per project, at the root)
There is exactly **one** `[canisters.backend]`. The structural pieces are invariant —
the single `[canisters.backend]`, `[canisters.backend.check-stable]`, and the `[moc]`
flags `--default-persistent-actors`, `--actor-idl=src/backend/system-idl`, and
`--implicit-package=core`. The **toolchain versions, the `-E`/`-W`/`-A` diagnostic codes,
and the dependency list are a current snapshot** that the Caffeine template bumps over
time — see "Versions and dependencies drift" below.
```toml
[package]
name = "backend"
version = "0.1.0"
[build]
outputDir = "src/backend/dist"
args = ["--release"]
[canisters.backend]
main = "src/backend/main.mo"
[canisters.backend.check-stable]
path = ".old/src/backend/dist/backend.most"
skipIfMissing = true
[toolchain]
moc = "1.8.1"
lintoko = "0.10.0"
[lint]
extends = true
[moc]
args = [
"--default-persistent-actors",
"--actor-idl=src/backend/system-idl",
"--implicit-package=core",
"-no-check-ir",
"-E=M0236,M0223,M0237,M0254",
"-W=M0235",
"-A=M0241",
"--generate-view-queries",
]
[dependencies]
core = "2.5.0"
caffeineai-data-viewer = "0.1.0"
```
Notes:
- **`check-stable`** points at `.old/src/backend/dist/backend.most`. The CLI saves the
previous build's `.most` (stable-signature snapshot) under `.old/` so the next build
can verify your stable state did not change incompatibly. Do not delete `.old/` between
builds; do not commit it as source — it is build state. **`skipIfMissing = true` is
required for a from-scratch project:** on the first run that snapshot does not exist
yet, and without it `caffeine check` fails with
`Deployed file not found: .old/src/backend/dist/backend.most`.
- **`--actor-idl=src/backend/system-idl`** tells `moc` where to find the Candid interfaces
of IC system canisters. `src/backend/system-idl/` must exist; the canonical template
ships `aaaaa-aa.did` (the IC management-canister interface). A minimal backend needs only
the directory.
- **`core = "2.5.0"`** is the `mo:core` standard library. Use `mo:core`, never the
deprecated `mo:base` — see the `writing-motoko` skill. **`caffeineai-data-viewer`** backs the
built-in data-viewer mixin used by the default `main.mo` (below) and pairs with the
`--generate-view-queries` flag.
> **Versions and dependencies drift.** The `[toolchain]` versions, the `[moc]`
> `-E`/`-W`/`-A` codes, and the frontend dependency set are template-managed and change
> over time (e.g. the `@dfinity/*` → `@icp-sdk/*` migration, moc/core bumps). Treat the
> exact values here as a snapshot — for current ones, `caffeine projects clone` a recent
> project and copy its `mops.toml` + `src/frontend/package.json`. Stable across versions:
> the file layout, the single `backend` canister, the structural `[moc]` flags,
> `check-stable` with `skipIfMissing`, `mo:core`, and `useActor(createActor)`.
### `package.json` (root) — pnpm workspace + the `bindgen` script
The `bindgen` script is the bridge from backend Candid to the frontend TS client. It is
invoked by the backend canister's `[build]` step (`pnpm bindgen`).
```json
{
"name": "@caffeine/template-app",
"type": "module",
"engines": {
"node": ">=18.17.0",
"pnpm": ">=7.0.0",
"npm": "please use pnpm"
},
"scripts": {
"build": "pnpm -r --if-present run build",
"typecheck": "pnpm -r --if-present run typecheck",
"check": "pnpm -r --if-present run check",
"fix": "pnpm -r --if-present run fix",
"bindgen": "caffeine-bindgen --did-file ./src/backend/dist/backend.did --out-dir ./src/frontend/src --actor-interface-file --force"
},
"devDependencies": {
"sharp": "^0.34.4"
}
}
```
### `pnpm-workspace.yaml`
```yaml
packages:
- src/**/*
onlyBuiltDependencies:
- esbuild
```
### `tsconfig.json` (root)
```json
{
"compilerOptions": {
"strict": true,
"target": "ES2020",
"experimentalDecorators": true,
"strictPropertyInitialization": false,
"moduleResolution": "node",
"allowJs": true,
"outDir": "HACK_BECAUSE_OF_ALLOW_JS"
}
}
```
### `src/backend/main.mo` — the starting backend
The canonical template's starting `main.mo` includes the built-in **data-viewer mixin**
(`include MixinViews()`), which pairs with the `caffeineai-data-viewer` dependency and the
`--generate-view-queries` flag in `mops.toml`. With `--default-persistent-actors` the
actor is already persistent. Add your own functions inside the actor, following the
**`writing-motoko` skill**.
```motoko
import MixinViews "mo:caffeineai-data-viewer/MixinViews";
actor {
include MixinViews();
};
```
(A bare `actor {}` also compiles if you drop the `caffeineai-data-viewer` dependency and
the `--generate-view-queries` flag.) Do not write more Motoko than this without loading
the `writing-motoko` skill — it covers persistent actors, stable types, `mo:core`, and the
compiler-error pitfalls that an agent will otherwise hallucinate.
## The frontend
**Fetch this skill's companion reference file** —
[`references/frontend-template.md`](references/frontend-template.md), which sits next to
this `SKILL.md` (i.e. `…/skills/caffeine-app/references/frontend-template.md`) — and create
the frontend files from it; it holds the verified `package.json`, the Vite/Tailwind/Biome
configs, `main.tsx`, and the worked `useActor(createActor)` backend call. The essentials:
- The entry point `src/frontend/src/main.tsx` wraps the app in
`InternetIdentityProvider` (from `@caffeineai/core-infrastructure`) and a TanStack
`QueryClientProvider`.
- The frontend talks to the backend through the **generated** module
`src/frontend/src/backend.ts` (and `src/frontend/src/declarations/`), which exports a
View on GitHub