create-gentiq-app 0.14.0 β 0.15.0-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +154 -13
- package/copy-template.js +3 -4
- package/index.js +427 -64
- package/package.json +8 -5
- package/skipped-entries.js +42 -0
- package/templates/starter/README.md +105 -40
- package/templates/starter/_gitignore +29 -0
- package/templates/starter/backend/.env.example +53 -0
- package/templates/starter/backend/README.md +27 -26
- package/templates/starter/backend/main.py +21 -22
- package/templates/starter/frontend/README.md +16 -44
- package/templates/starter/frontend/_gitignore +24 -0
- package/templates/starter/frontend/index.html +1 -1
- package/templates/starter/frontend/package.json +2 -2
- package/templates/starter/frontend/src/App.tsx +23 -161
- package/templates/starter/frontend/src/index.css +8 -16
- package/templates/starter/frontend/vite.config.ts +0 -3
- package/LICENSE +0 -201
- package/templates/starter/.env.example +0 -9
package/README.md
CHANGED
|
@@ -32,7 +32,7 @@ pnpm create gentiq-app my-awesome-ai
|
|
|
32
32
|
- β‘ **AI Streaming**: Real-time agent responses via PydanticAI and Vercel AI SDK.
|
|
33
33
|
- π οΈ **Admin Dashboard**: Built-in analytics, history logs, and user management.
|
|
34
34
|
- π° **Atomic Balance**: Native tracking and enforcement of per-user token and request limits.
|
|
35
|
-
- π **Flexible Persistence**:
|
|
35
|
+
- π **Flexible Persistence**: SQLite + local filesystem out of the box; MongoDB + MinIO/S3 for production.
|
|
36
36
|
- π **Enterprise-Grade Security**: Full JWT authentication suite and encrypted sessions.
|
|
37
37
|
|
|
38
38
|
---
|
|
@@ -45,11 +45,12 @@ When you initialize a new app, the CLI generates a modern, monorepo-friendly str
|
|
|
45
45
|
my-awesome-ai/
|
|
46
46
|
βββ backend/ # FastAPI + PydanticAI application
|
|
47
47
|
β βββ main.py # App entry point
|
|
48
|
-
β
|
|
48
|
+
β βββ pyproject.toml # Python dependencies (UV managed)
|
|
49
|
+
β βββ .env.example # Environment variable template
|
|
50
|
+
β βββ .env # Generated, with real secrets β gitignored
|
|
49
51
|
βββ frontend/ # Vite + React application
|
|
50
52
|
β βββ src/ # UI components and hooks
|
|
51
53
|
β βββ package.json # Frontend dependencies
|
|
52
|
-
βββ .env.example # Environment variable template
|
|
53
54
|
βββ README.md # Your project documentation
|
|
54
55
|
```
|
|
55
56
|
|
|
@@ -59,24 +60,27 @@ my-awesome-ai/
|
|
|
59
60
|
|
|
60
61
|
Once your project is scaffolded, follow these steps to get running:
|
|
61
62
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
63
|
+
The CLI does the setup for you: it installs the backend dependencies with `uv sync`,
|
|
64
|
+
installs the frontend dependencies with your package manager, and writes `backend/.env`
|
|
65
|
+
with freshly generated `JWT_SECRET_KEY` and `BACKEND_API_KEY` values. So once it
|
|
66
|
+
finishes, the project runs.
|
|
67
|
+
|
|
68
|
+
### 1. Launch Backend
|
|
67
69
|
|
|
68
|
-
### 2. Launch Backend
|
|
69
|
-
The backend uses `uv` for lightning-fast Python package management.
|
|
70
70
|
```bash
|
|
71
71
|
cd backend
|
|
72
|
-
uv sync
|
|
73
72
|
uv run uvicorn main:app.api --reload --port 8000
|
|
74
73
|
```
|
|
75
74
|
|
|
76
|
-
|
|
75
|
+
The only value you have to supply yourself is the AI provider key. If you did not paste
|
|
76
|
+
one at the prompt, set `OPENAI_API_KEY` in `backend/.env` before starting β the agent
|
|
77
|
+
definition in `main.py` builds its provider client on import, so an absent key is a
|
|
78
|
+
startup error rather than a failed chat. Using a different provider? Change the model
|
|
79
|
+
string in `backend/main.py` and set that provider's key instead.
|
|
80
|
+
|
|
81
|
+
### 2. Launch Frontend
|
|
77
82
|
```bash
|
|
78
83
|
cd frontend
|
|
79
|
-
npm install
|
|
80
84
|
npm run dev
|
|
81
85
|
```
|
|
82
86
|
|
|
@@ -84,6 +88,143 @@ Your app is now live at `http://localhost:5173`!
|
|
|
84
88
|
|
|
85
89
|
---
|
|
86
90
|
|
|
91
|
+
## Options
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
npx create-gentiq-app@latest [directory] [options]
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
| Flag | Effect |
|
|
98
|
+
| --- | --- |
|
|
99
|
+
| `--pm <name>` | Package manager for the frontend install: `pnpm`, `npm`, `yarn` or `bun`. Defaults to the one that invoked the CLI. |
|
|
100
|
+
| `--no-install` | Scaffold only β skip `uv sync` and the frontend install. |
|
|
101
|
+
| `--openai-key <key>` | Write this `OPENAI_API_KEY` into `backend/.env` instead of prompting. |
|
|
102
|
+
| `-y`, `--yes` | Accept every default and never prompt. Also the automatic behaviour when there is no TTY, so the CLI is usable from CI. |
|
|
103
|
+
| `-h`, `--help` | Show usage. |
|
|
104
|
+
|
|
105
|
+
Missing tools are reported, not fatal: without `uv` the backend install is skipped with
|
|
106
|
+
an install link, and a package manager that is not on `PATH` falls back to one that is.
|
|
107
|
+
The scaffold itself is complete either way, and the printed next steps name whatever is
|
|
108
|
+
left to run by hand.
|
|
109
|
+
|
|
110
|
+
---
|
|
111
|
+
|
|
112
|
+
## Using Tailwind in a Gentiq app
|
|
113
|
+
|
|
114
|
+
The scaffold ships **no Tailwind** β `gentiq/style.css` is already compiled, and the chat
|
|
115
|
+
and admin UIs are fully styled by it. You only need Tailwind if you are writing your own
|
|
116
|
+
components (a custom tool card, say). If you add it, read this section first: two Tailwind
|
|
117
|
+
builds in one document need one extra line to coexist, and without it they break each
|
|
118
|
+
other silently.
|
|
119
|
+
|
|
120
|
+
### Why it needs care
|
|
121
|
+
|
|
122
|
+
Tailwind guarantees that a variant (`md:`, `hover:`) is emitted *after* the plain utility
|
|
123
|
+
it is meant to override β that is the whole reason `flex-col md:flex-row` works. The
|
|
124
|
+
guarantee holds **per build**. Gentiq ships precompiled CSS, so adding Tailwind to your app
|
|
125
|
+
creates a second, independently sorted set of utilities, and concatenating them destroys
|
|
126
|
+
the ordering: whichever set lands later wins every tie, regardless of which stylesheet
|
|
127
|
+
"owns" the class.
|
|
128
|
+
|
|
129
|
+
Both directions are broken, and neither announces itself:
|
|
130
|
+
|
|
131
|
+
| Your utilities last | Gentiq's utilities last |
|
|
132
|
+
| --- | --- |
|
|
133
|
+
| Your `.flex-col` beats gentiq's `.md:flex-row` β the admin header collapses into a vertical stack at every width | Gentiq's `.grid-cols-2` beats your `.sm:grid-cols-3` β your own grids stop responding |
|
|
134
|
+
|
|
135
|
+
Reordering does not fix it, because the problem is not the order. It is that there are two
|
|
136
|
+
sorts. The fix is to collapse them back to one.
|
|
137
|
+
|
|
138
|
+
### The setup
|
|
139
|
+
|
|
140
|
+
Put this at the top of `src/index.css`, and delete `import 'gentiq/style.css'` from
|
|
141
|
+
`src/App.tsx` (this file has to load first, so it must own that import):
|
|
142
|
+
|
|
143
|
+
```css
|
|
144
|
+
/* Layer order for the document: gentiq's layers first, yours last. */
|
|
145
|
+
@layer properties, gentiq-theme, gentiq-base, gentiq-components, gentiq-utilities,
|
|
146
|
+
theme, base, components, utilities;
|
|
147
|
+
|
|
148
|
+
@import 'gentiq/style.css';
|
|
149
|
+
|
|
150
|
+
/* Theme + utilities only β NOT `@import 'tailwindcss'`. That bundles preflight,
|
|
151
|
+
and gentiq's stylesheet already ships one; a second copy lands after gentiq's
|
|
152
|
+
rules and its `border: 0 solid` resets border-color to currentColor, which
|
|
153
|
+
paints every unstyled border in the app the foreground colour. */
|
|
154
|
+
@import 'tailwindcss/theme.css' layer(theme);
|
|
155
|
+
@import 'tailwindcss/utilities.css' layer(utilities);
|
|
156
|
+
|
|
157
|
+
/* The line that actually makes the two coexist: scan gentiq's bundles so YOUR
|
|
158
|
+
build emits gentiq's classes too. One build, one sort, every variant back
|
|
159
|
+
after its base utility. Gentiq's precompiled layer is then shadowed for every
|
|
160
|
+
class you regenerate, and still supplies its custom `@utility` rules (`glass`,
|
|
161
|
+
the loader animations), whose names contend with nothing you emit. */
|
|
162
|
+
@source '../node_modules/gentiq/dist/gentiq-index.es.js';
|
|
163
|
+
@source '../node_modules/gentiq/dist/gentiq-admin.es.js';
|
|
164
|
+
|
|
165
|
+
/* Gentiq's design tokens, registered with YOUR Tailwind instance. Gentiq declares
|
|
166
|
+
the same map in its own `@theme inline`, but that lives in its compiled
|
|
167
|
+
stylesheet, which your compiler never sees β so without this block utilities
|
|
168
|
+
like `hover:border-primary/40` silently generate nothing. `inline` is what makes
|
|
169
|
+
them resolve at runtime, so ThemeProvider can keep rewriting accent and theme. */
|
|
170
|
+
@theme inline {
|
|
171
|
+
--color-background: var(--background);
|
|
172
|
+
--color-foreground: var(--foreground);
|
|
173
|
+
--color-card: var(--card);
|
|
174
|
+
--color-card-foreground: var(--card-foreground);
|
|
175
|
+
--color-popover: var(--popover);
|
|
176
|
+
--color-popover-foreground: var(--popover-foreground);
|
|
177
|
+
--color-primary: var(--primary);
|
|
178
|
+
--color-primary-foreground: var(--primary-foreground);
|
|
179
|
+
--color-secondary: var(--secondary);
|
|
180
|
+
--color-secondary-foreground: var(--secondary-foreground);
|
|
181
|
+
--color-muted: var(--muted);
|
|
182
|
+
--color-muted-foreground: var(--muted-foreground);
|
|
183
|
+
--color-accent: var(--accent);
|
|
184
|
+
--color-accent-foreground: var(--accent-foreground);
|
|
185
|
+
--color-destructive: var(--destructive);
|
|
186
|
+
--color-border: var(--border);
|
|
187
|
+
--color-input: var(--input);
|
|
188
|
+
--color-ring: var(--ring);
|
|
189
|
+
|
|
190
|
+
--radius-sm: calc(var(--radius) - 4px);
|
|
191
|
+
--radius-md: calc(var(--radius) - 2px);
|
|
192
|
+
--radius-lg: var(--radius);
|
|
193
|
+
--radius-xl: calc(var(--radius) + 4px);
|
|
194
|
+
}
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
Do not set `body { font-family: β¦ !important }` here. `ThemeProvider` composes the
|
|
198
|
+
configured face with `var(--font-script)` and writes it inline to `<html>` and `<body>`;
|
|
199
|
+
an `!important` rule beats that inline style and strips the per-script fallback, leaving
|
|
200
|
+
Persian and Arabic text in a serif default.
|
|
201
|
+
|
|
202
|
+
The `@source` lines cost roughly 10β13 kB gzipped, because your build re-emits the
|
|
203
|
+
utilities gentiq already shipped. That is the price of a correct cascade; the duplicate
|
|
204
|
+
rules are identical and fully shadowed.
|
|
205
|
+
|
|
206
|
+
### Layers
|
|
207
|
+
|
|
208
|
+
Gentiq publishes into `gentiq-theme`, `gentiq-base`, `gentiq-components` and
|
|
209
|
+
`gentiq-utilities` rather than the bare `theme` / `base` / `components` / `utilities`
|
|
210
|
+
(versions up to and including `0.15.0-beta.1` used the bare names). Those generic names belong to your document, and gentiq
|
|
211
|
+
claiming them is what let the two builds merge by accident in the first place. Gentiq
|
|
212
|
+
deliberately does **not** pre-register your layer names, so your stylesheet keeps the
|
|
213
|
+
position it has always had; the `@layer` statement above is where you decide the order.
|
|
214
|
+
|
|
215
|
+
The setup above works against older versions too β the `gentiq-*` layers just stay empty
|
|
216
|
+
and gentiq's stylesheet lands in `theme` / `base` / `utilities` instead, still ahead of
|
|
217
|
+
your regenerated superset.
|
|
218
|
+
|
|
219
|
+
### Checking it
|
|
220
|
+
|
|
221
|
+
The admin dashboard header is the fastest canary β it is the layout in the product that
|
|
222
|
+
leans hardest on `md:` overrides. Open `/admin` above 768px: the logo and the navigation
|
|
223
|
+
tabs sit on one row. If they are stacked vertically, your utilities are beating gentiq's
|
|
224
|
+
variants and `@source` is missing or pointing at the wrong path.
|
|
225
|
+
|
|
226
|
+
---
|
|
227
|
+
|
|
87
228
|
## Why Gentiq?
|
|
88
229
|
|
|
89
230
|
Unlike generic boilerplates, Gentiq is built with **developer velocity** and **production scalability** in mind. It provides the "boring" parts of AI developmentβauthentication, rate limiting, and persistenceβso you can focus on building your agents.
|
package/copy-template.js
CHANGED
|
@@ -2,6 +2,8 @@ import fs from 'fs-extra';
|
|
|
2
2
|
import path from 'path';
|
|
3
3
|
import { fileURLToPath } from 'url';
|
|
4
4
|
|
|
5
|
+
import { shouldSkipEntry } from './skipped-entries.js';
|
|
6
|
+
|
|
5
7
|
const __filename = fileURLToPath(import.meta.url);
|
|
6
8
|
const __dirname = path.dirname(__filename);
|
|
7
9
|
|
|
@@ -15,10 +17,7 @@ async function copyTemplate() {
|
|
|
15
17
|
await fs.emptyDir(dest);
|
|
16
18
|
|
|
17
19
|
await fs.copy(src, dest, {
|
|
18
|
-
filter: (src) =>
|
|
19
|
-
const basename = path.basename(src);
|
|
20
|
-
return !['node_modules', '.venv', '__pycache__', '.ruff_cache', 'dist', '.storage', 'gentiq.db', 'uv.lock', 'package-lock.json', 'pnpm-lock.yaml'].includes(basename);
|
|
21
|
-
}
|
|
20
|
+
filter: (src) => !shouldSkipEntry(path.basename(src)),
|
|
22
21
|
});
|
|
23
22
|
|
|
24
23
|
console.log('Template copied successfully!');
|