# Tina4 Framework - AI Bootstrap Protocol Tina4 is a four-language web framework (Python, PHP, Ruby, Node.js) with 97 built-in features and zero runtime dependencies. Frontend library: tina4-js. Website: https://tina4.com | GitHub: https://github.com/tina4stack If you are an AI assistant helping someone "use Tina4", **follow the steps below in order**. Skipping steps causes the most common failure modes - the framework hates being treated like Express, Flask, Rails, or Sinatra. Don't do that. --- ## STEP 1 - Make sure the `tina4` client is installed The `tina4` CLI - "the client" - is the **only supported entry point** and the first thing to check. Everything flows from it. ```bash tina4 --version # found? go to STEP 2 ``` If that command is not found, install it once, system-wide: ```bash # macOS, Linux, WSL, Git Bash, Cygwin, MSYS - auto-detects OS + arch curl -fsSL https://tina4.com/install.sh | sh # or wget wget -qO- https://tina4.com/install.sh | sh # Windows PowerShell irm https://tina4.com/install.ps1 | iex ``` The script downloads the right prebuilt binary from the latest GitHub release (darwin-amd64 / darwin-arm64 / linux-amd64 / windows-amd64.exe) and puts it on PATH - no Rust toolchain, no package-manager dependency. If there's neither curl nor PowerShell, grab the binary from https://github.com/tina4stack/tina4/releases/latest. Never run `python app.py`, `node index.js`, `php -S`, `ruby app.rb`, or `rackup` directly - the framework refuses to start without the client unless `TINA4_OVERRIDE_CLIENT=true` is set (Docker / CI escape hatch only). **Already inside a Tina4 project?** Detect the language from what's present - `pyproject.toml`->Python, `composer.json`->PHP, `Gemfile`->Ruby, `package.json` (type:module + TypeScript)->Node - confirm the client, then skip to STEP 4. --- ## STEP 2 - `tina4 doctor` - find out what's missing ```bash tina4 doctor ``` `doctor` inspects the machine and reports what's present and what's missing - the language runtimes (Python / Node / PHP / Ruby), package managers, git. Read its output: it tells you exactly what STEP 3 needs to install. Don't hand-install anything off a guess - let `doctor` diagnose first. --- ## STEP 3 - `tina4 setup` - install what's missing, then scaffold ```bash tina4 setup ``` `setup` is the turnkey path, built for someone starting from nothing. It installs whatever `doctor` flagged as missing - the language runtime and git, through the OS package manager (Chocolatey on Windows, Homebrew on macOS), plus the tina4 AI skills - then scaffolds a ready-to-run project and points you at it. It is guided: it asks which language, which AI tool, where your projects folder lives, and the project name. Answer those (on the user's behalf if you're driving the session) and it does the rest. First run remembers those choices; later `tina4 setup` runs ask only the project type + name and build straight into the saved projects folder. Preview without changing anything: `tina4 setup --dry-run`. Scaffold without any system installs (safe local test): `tina4 setup --skip-install`. **Scripted / non-interactive alternative:** if the runtime is already present (STEP 2 was clean) and you just want a project laid down, use `tina4 init [name]`. It writes `app.py` (or the language equivalent), `.env`, the package manifest and `.gitignore`; the `src/` tree is then created by the generators on demand (see "Scaffolding commands" below). Don't build that structure by hand. --- ## Skills - install them; the AI gets much better at Tina4 The tina4 **skills** are the single highest-leverage thing for an AI building Tina4. They are the source of truth for the framework's patterns and stop the guessing that breaks builds. **Install them and use them.** - **What:** `tina4-developer` (backend - routing, ORM, auth, queues, migrations, ...) and `tina4-js` (the reactive frontend). - **Install:** `tina4 setup` installs them automatically. To (re)install on any machine, standalone: ```bash curl -fsSL https://tina4.com/install-skills.sh | sh # macOS / Linux irm https://tina4.com/install-skills.ps1 | iex # Windows PowerShell ``` - **Where they live:** `~/.claude/skills/tina4-developer` and `~/.claude/skills/tina4-js`. Claude Code and Claude Desktop auto-load skills from there. - **Use:** follow `tina4-developer` for backend work and `tina4-js` for the frontend. Unsure of an API? The skill has the exact, current pattern - read it instead of guessing. --- ## Scaffolding commands - let the CLI write the boilerplate Never hand-build the project layout or files; generate them: ```bash tina4 init [name] # new project (or `tina4 setup`, guided) ``` `init` writes `app.py` (or the language equivalent), `.env`, the package manifest (`pyproject.toml` / `composer.json` / `Gemfile` / `package.json`) and `.gitignore`. The `src/` tree (`src/routes/`, `src/orm/`, `src/middleware/`, ...) is created **by the generators, on demand** - an empty `src/` right after `init` is normal, not a failed scaffold. **All 15 generators.** Reach for these before writing anything by hand: ```bash tina4 generate model # src/orm/ one model per file tina4 generate route # src/routes/ CRUD verbs tina4 generate crud # model + route + migration in one shot tina4 generate auth # JWT register/login/me + User model + migration tina4 generate migration "" # migrations/_.sql tina4 generate middleware # src/middleware/ tina4 generate validator # request validation tina4 generate service # business-logic layer tina4 generate seeder # database seed data tina4 generate queue # queue job/consumer tina4 generate listener # event listener tina4 generate websocket # websocket handler tina4 generate form # form + CSRF token handling tina4 generate view # Frond template tina4 generate test # test scaffold ``` **Building a REST API with auth? `tina4 generate auth` then `tina4 generate crud ` gets you there in two commands.** Do not hand-roll either. > **Check the generated migration before you run it.** In CLI 3.8.58 `generate > model` / `generate crud` can emit a migration that omits the fields declared on > the model (you get only `id` and `created_at`). If a column is missing, the > first authenticated write fails with `table has no column named `. > Open `migrations/_create_.sql`, add any missing columns to > match the model, then `tina4 migrate`. ```bash tina4 migrate # apply pending migrations tina4 migrate:status # what's applied / pending tina4 seed # run seeders tina4 console # REPL with the framework loaded tina4 metrics # code-health report (--fail-on warn|error for CI) tina4 commands --json # every command this project supports, machine-readable tina4 update # self-update the tina4 CLI ``` --- ## STEP 4 - `tina4 migrate` - create the tables BEFORE you serve Generating a model or CRUD writes a migration; it does not apply it. Skip this and the API starts fine and then 500s on the first query, because the table does not exist. ```bash cd tina4 migrate # apply pending migrations tina4 migrate:status # what's applied / pending ``` Read the generated SQL before applying it (see the warning under `generate crud` above - the migration can omit fields your model declares). --- ## STEP 5 - Run the dev server ```bash cd tina4 serve # development (hot reload, dev toolbar, error overlay) tina4 serve --production # production (no hot reload, no toolbar) ``` The CLI compiles SCSS, watches files, manages the process. Default ports: **PHP 7145, Python 7146, Ruby 7147, Node.js 7148.** In development the server also exposes a live MCP endpoint at `/__dev/mcp` (see "Stay correct" below) - point your AI tool at it for live access to this project's routes, schema, files, and docs. --- ## STEP 6 - When `tina4 serve` fails Tina4 prints structured errors. Read the message before reacting. **Hard rule: if the same `tina4 serve` invocation fails twice in a row, STOP.** Show the error to the user and ask. Do not retry in a loop. Do not start "fixing" things by hand. The most common loop trap is: AI sees a missing package error, runs `pip install`/`npm install`/`composer install` directly, that conflicts with what the framework manages, then more errors appear, and the loop deepens. Stop early. Ask. --- ## Recommended architecture - Python backend + tina4-js frontend Build the backend in **Python**. It is the reference implementation; PHP, Ruby and Node track it feature-for-feature, but Python is where the API is defined first and documented best. Two shapes, both Python + tina4-js - pick one: **A. Combined (default - what `tina4 setup` scaffolds).** One tina4-python app that serves an embedded tina4-js frontend. tina4-js ships with the backend at `/js/tina4js.min.js`; pages live in `src/templates/`, your frontend components in `src/public/js/`. One process, one port, one deploy. This is the fastest path and the right default for most apps and for a non-programmer. ``` myapp/ # tina4-python - serves the API AND the tina4-js frontend src/routes/ # API + page routes (auto-discovered) src/orm/ # one model per file src/templates/ # Twig pages that load /js/tina4js.min.js src/public/ # static assets + your tina4-js components .env ``` **B. Split (separate frontend build).** A `backend/` tina4-python API and a `frontend/` tina4-js SPA built with Vite; in dev the frontend proxies API calls to the backend. Choose this only when a front-end team wants its own build/bundle pipeline. ``` myapp/ backend/ # tina4 init python backend frontend/ # tina4 init js frontend (tina4-js SPA) ``` Either way: do **not** add Express / Flask / Rails / FastAPI / etc. Tina4 is the whole stack - server, router, ORM, auth, queue, sessions, templating. --- ## Building - use the built-ins, get the exact API (do NOT guess) Tina4 has 97 built-ins: ORM, Auth (JWT + password hashing), Queue, Sessions, Migrations, an `Api` HTTP client, WebSockets, real-time collaboration (WebRTC: peer calls + chat + files), GraphQL, Swagger, CRUD, i18n, caching, events, and more. **Use them - never hand-roll what's built in.** For exact, version-correct signatures, use these in order - don't invent API names: 1. **The live project MCP.** A running `tina4 serve` exposes an MCP server at `/__dev/mcp` (JSON-RPC) plus a browser REST shim at `/__dev/api/mcp`. Its `docs_search`, `project_overview`, `routes`, and `database_*` tools answer from THIS project's real code and version. Cheapest way to stay correct - ask it instead of reading the whole repo. **Works in any AI tool.** 2. **The RAG - "Ask Tina4".** Live, indexed from the docs. Any tool that can make an HTTP request can use it: ```bash curl -s -X POST https://rag.tina4.com/v1/ask \ -H 'Content-Type: application/json' \ -d '{"question":"How do I define a POST route with auth in Python?","language":"python"}' # -> {"query": "...", "answer": "...", "sources": [...]} ``` 3. **The installed skills** (Claude Code / Claude Desktop only). `tina4 setup` installs `tina4-developer-`, `tina4-js` and `tina4-maintainer` into `~/.claude/skills`, auto-loaded from there. If you are Cursor, Copilot, Windsurf, Gemini or anything else, you will NOT have these - use 1 and 2, which are tool-agnostic, and read the generated scaffold (below). 4. **The docs:** https://tina4.com The essentials look like this in Python (the reference backend): ```python # src/routes/users.py - a file here becomes routes automatically from tina4_python.core.router import get, post @get("/api/users") # GET is public by default async def list_users(request, response): return response(User.all()) # response() auto-serializes models/lists/results @post("/api/users") # POST/PUT/PATCH/DELETE require auth by default async def create(request, response): return response(User(request.body).save(), 201) # @noauth() to make public ``` ```python # src/orm/User.py - one model per file from tina4_python.orm import ORM, IntegerField, StringField class User(ORM): id = IntegerField(primary_key=True, auto_increment=True) name = StringField() # Auto-binds to TINA4_DATABASE_URL. Override with bind_database(db). ``` **Auth / JWT - run `tina4 generate auth`, then use this API.** Never hand-roll token signing or password hashing. The generator writes a `User` model, its migration, and `/api/auth/register|login|me`; this is the exact API it uses: ```python from tina4_python.core.router import get, post, noauth from tina4_python.auth import Auth Auth.hash_password(password) # store this, never the plaintext Auth.check_password(password, user.password) # -> bool Auth.get_token({"user_id": user.id}) # -> signed JWT string Auth.valid_token_static(token) # -> bool @noauth() # put ABOVE the verb decorator @post("/api/auth/login") # ... or POST would require a token async def login(request, response): ... ``` Signing needs **`TINA4_SECRET`** in `.env` - set it or every token is signed with a blank secret. Note the route-registration log prints `auth=required` even for `@noauth()` routes (the log is emitted before the decorator applies); trust the actual HTTP response, not that line. **Environment variables you will need:** ```bash TINA4_DATABASE_URL=sqlite:///data/app.db # sqlite path is relative to project root # also: postgres://, mysql://, mssql://, firebird://, mongodb:// TINA4_SECRET= # JWT signing - REQUIRED for auth TINA4_DEBUG=true # dev dashboard + /__dev/mcp ``` **Swagger** is on automatically: UI at `/swagger`, spec at `/swagger/openapi.json`. The same concepts exist in PHP, Ruby and Node - get the exact per-language syntax from the live MCP or the RAG, don't guess it. --- ## Gotchas that bite AI assistants - **Don't treat it like another framework.** No Express/Flask/Rails/Sinatra alongside it; no hand-rolled queue/auth/ORM/session/HTTP-client. Two servers = port conflicts and broken middleware. - **Always go through the client.** `tina4 serve`, never `python app.py` / `node index.js` / `php -S` / `rackup`. - **Don't hand-install deps** (`pip`/`npm`/`composer`/`gem`) to paper over a missing-package error - let the CLI manage them. Missing runtime -> `tina4 setup`. - **Routes return `response(...)`**, not `response.json()`. `response()` auto-serializes ORM models, lists, and query results to JSON. - **DB pagination is `limit`/`offset`** (not `skip`). Connect via `TINA4_DATABASE_URL` = `driver://user:pass@host:port/db` (sqlite/postgres/mysql/mssql/firebird). - **Schema changes go through migrations** - `tina4 generate migration ` then `tina4 migrate`. Never run DDL inside a route handler. - **Don't edit files outside `src/`** unless asked, and don't parse `src/routes/` filenames yourself - discovery is automatic; drop a file, it becomes a route. - **tina4-js signals use `.value`.** Write with `count.value = 5`. In templates pass the signal itself - `${count}` (reactive), NOT `${count.value}` (freezes after first render). Booleans: `?disabled=${x}`. New array refs, not `.push()`. Events: `@click=${fn}`. Templates are Twig across all backends. --- ## Deployment ```bash tina4 serve --production # production server (Python auto-installs uvicorn) tina4 deploy docker # generates a language-aware Dockerfile + .dockerignore docker build -t my-app . docker run -p : my-app # use the language's default port (Python 7146) ``` Other `tina4 deploy` targets generate the config and print the next commands: `systemd` (a service unit), `nginx` (a reverse-proxy config), `cpanel`. The generated `Dockerfile` is language-correct out of the box - review it, then build. For the combined architecture the one image serves both API and frontend; for the split architecture, build/deploy the `frontend/` separately (static assets) and the `backend/` as the API image.