Tensile Docs
Concepts

Templates and the manifest

How a template declares its services, modes, database, and seeds — and the six that ship today.

A template is a directory that knows how to be cloned. It contains the app's code (backend, optional frontend, MCP server) plus a clone.manifest.json that tells the CLI everything it needs to spin, migrate, health-check, and seed it.

Templates live under the templates directory (the monorepo apps/ by default; override with ASYM_TEMPLATES_DIR). The published CLI bundles each manifest with its compose file, so it resolves templates from its own bundle with no monorepo present. The CLI discovers a template by reading each manifest's name — so apps/slack-clone/ declares the name slack, which is what you type in hone env spin slack.

The manifest

Here's the Slack template's clone.manifest.json, annotated:

{
  "name": "slack",                         // canonical id used on the CLI
  "displayName": "Slack",
  "realProduct": "slack",                  // what `verify` scores fidelity against
  "services": {
    "backend": {
      "image": "ghcr.io/asymmetric-ai/asymmetric-slack-backend:latest", // pulled, not built
      "port": 3001,                        // container port
      "health": "/api/health"              // polled until healthy on spin
    },
    "frontend": {
      "build": "./frontend",               // the one service still built from source
      "port": 5173,
      "optional": true
    }
  },
  "modes": {                               // named service sets
    "api": ["backend"],
    "full": ["backend", "frontend"]
  },
  "database": {
    "migrations": "./supabase/migrations", // .sql files, run in sorted order
    "nameTemplate": "clone_{id}"           // per-clone database name
  },
  "redis": {
    "prefixTemplate": "{id}:"              // per-clone key prefix
  },
  "seed": {
    "fixtures": "./seeds/*.sql",           // deterministic fixture packs
    "ai": {
      "entities": ["users", "channels", "messages"]
    }
  }
}

Backends declare an image (pulled and digest-pinned at spin). A service can instead declare build for a local build context — today only Slack's optional frontend does.

Fields that matter

FieldDrives
nameThe identifier you type (spin <name>, verify <name>).
services[].imageThe published image the CLI pulls and runs (digest-pinned).
services[].healthThe endpoint spin and reset poll before declaring the clone healthy.
modesWhat --mode accepts; the first key is the default.
database.migrationsThe .sql files run on create and replayed on reset.
database.nameTemplateHow the per-clone database is named ({id} is substituted).
redis.prefixTemplateThe per-clone Redis key namespace.
seed.fixturesThe glob of named fixture packs seed --fixture can load.
seed.ai.entitiesWhat AI seeding generates for this template.

Ready-made templates

Six templates ship today. Each backend is a published image; verify scores it against the real product's live API documentation.

Default container ports are slack 3001, linear 3002, stripe 3003, notion 3004, hubspot 3005, github 3006; the host port for each clone is allocated at spin time from your range (default 3000–3999).

Templates are built and maintained by Tensile — you spin and use them, you don't author your own.

On this page