Desktop app that scaffolds AdonisJS v7 projects from a card-based stack picker and saves lineups as one-click templates. Electron + electron-vite + React 19 + Tailwind v4 + shadcn/ui (Radix), laid out like the Aiven console.
- New project: pick a starter kit (
react,vue,hypermedia,api,api-monorepo), then database, auth guard, social login, storage, mail, extras and AdonisJS Plus feature packs as trading cards. Pack cards run nothing at create time: they need the Flow card, build on the auth pack (social auth also on a social login card), and Studio writes the/flow-applyorder and prerequisites into STUDIO.md for the coding agent, plus a note step in the plan. The right panel shows the formation, the package count and the exact commands. - Create runs
create-adonisjsin the folder you picked, thennode ace add …for each card with--package-managerand--verbose(@adonisjs/drive --services … --install,@adonisjs/mail --transports, redis, transmit, bouncer, i18n,@adonisjs/otel,@tuyau/superjson, limiter and locks with--store=redis|database). The SuperJSON card also installssuperjson(a direct dependency for the LuxonDateTimerecipe file) and, on Inertia kits, addsplugins: [superjson()]toinertia/client.ts: the middleware only acts on requests the client plugin marks withx-superjson. File storage is a multi-pick: every disk gets a service inconfig/drive.tsandDRIVE_DISKin.envpicks the active one, so a stack can run on the local disk in development and a bucket in production. One disk goes throughnode ace add; several go throughnpm install @adonisjs/driveplusnode ace configure @adonisjs/drive --services=fs --services=r2 --install(addflattens repeated flags, see ally below), with the local disk first soDRIVE_DISKstarts on it. Adrive-configpatch follows R2 and Supabase: the drive 4.0 config stub has no Supabase service block and nosupportsACL: falsefor R2. With several disks adrive-envpatch runs after the.envvalues are written: the drive configure makes every key required, so the keys the standby disks still miss becomeEnv.schema.string.optional()instart/env.tsand read with an empty default inconfig/drive.ts, and the app boots on the local disk before the bucket has credentials. On the API kits the mail card is preceded bynode ace add edge(built into core): their mail provider has no template engine, somessage.htmlView()would throw. The hypermedia kit gets two Edge plugin cards, icons (edge-iconify + Heroicons) and Markdown (edge-markdown, Node 24), registered in astart/view.tspreload the patch adds toadonisrc.ts. Cache and queue configure always prompt for a driver and have no flag, so the runner answers the prompt on stdin (\033[Bis arrow down,\nEnter). Ally goes throughnode ace configure --providers=a --providers=bbecauseaddflattens repeated flags (add.js,#configurePackagecalls.toString()on the array). Health checks runnode ace configure health_checksplus a patch for the routes andstart/health.ts(database, connection count on Postgres / MySQL, Redis). Access tokens and basic auth are added next to the kit's session guard by editingconfig/auth.tsand the User model: re-running the auth configure would skip both files and write a second users migration. The Redis card also becomes the store for limiter, cache, locks and queue; without it they use the database and get migrations, which run right away on SQLite / libSQL. It installs Tailwind / daisyUI on Inertia kits and shadcn/ui on the React kit, switches the database with the officialnode ace configure @adonisjs/lucid --db=… --install --force(Postgres / MySQL / MariaDB asmysql/ SQL Server / libSQL) and then sets theDB_*valuescompose.ymlstarts with plus the TLS options SQL Server needs locally, writes Docker files (with Redis and Jaeger services for those cards; the image installs with--ignore-scriptsbecause the kits allow better-sqlite3's install script and better-sqlite3 13 keeps abinding.gypwithout one, so npm would run node-gyp in an image that has no Python, while its prebuilt binaries already sit in the tarball), runsnode ace codegenand drops aSTUDIO.mdplus aCLAUDE.mdthat points at it. Everything streams into the log. On the API monorepo kit the ace steps run inapps/backend: npm 11 finds the workspace root from there, so everynode ace addlands in the rootnode_modulesand lockfile (verified card by card), but it ignores an.npmrcinsideapps/backend, so the Plus registry scope and ally'slegacy-peer-depsare written to the root.npmrc. The Docker card works there too (npm only for now): installs run from the root withnpm ci --workspace apps/backend, the build inside the app, and the image gets the rootnode_modulesnext toapps/backend/build;compose.ymlreadsapps/backend/.env. The scenarios insrc/shared/recipe.tsare checked against the packages' own configure scripts. - With ally in the lineup and npm as the package manager the project gets
.npmrcwithlegacy-peer-deps=true: ally 6 still peers on inertia v4 while the v7 kits ship inertia v5. - Keys and connections: cards that need credentials (Sentry, Stripe, mail providers,
storage buckets, social login, Postgres/MySQL) open a dialog with a short how-to, the exact
env variables and a "Provide later" button. Values are written into the new project's
.envonly and never saved with a template. Create runs a last check for cards that are still missing keys. - Environments (top nav): named sets of API keys shared by every workspace, e.g.
"Personal" and "Client X". Tick "Keep in …" in the keys dialog and the next project that
picks the same card is filled in without asking; "Create project" on a template uses the
default environment, so that dialog only asks for a name and a folder. The page lists every variable with the cards
that use it, imports a
.envfile (known keys pre-ticked) and lets you add custom keys, which go into every project created with that environment. Values are sealed one by one with Electron'ssafeStorage(macOS Keychain, Windows DPAPI, GNOME Keyring / KWallet on Linux) and kept inenvironments.json(mode 0600) in the app's user data folder. Without a keychain they are stored as plain text and the page says so. The main process merges the environment into the create job, so the renderer never ships the values for a create. - STUDIO.md and CLAUDE.md: the last create step writes
STUDIO.mdinto the new project: the stack, what every step did (done / skipped / failed), and a setup checklist with- [ ]boxes split into Agent tasks (code an AI agent can do: Persona mixins, Permissions migrations, ally routes, wiring Stripe or Sentry, the first i18n translation files, the SuperJSONDateTimerecipe, the monorepo frontend, redoing a failed step), Needs the user (every key a card asks for with its state, never the value, plus databases and services that must run), and Before production.CLAUDE.mdis created, or appended to when Flow or the kit wrote one, and tells the agent to readSTUDIO.md, skip[x]items, do the agent tasks and ask for the rest instead of inventing values. - AdonisJS Plus: three Extras cards (Persona, Permissions, Flow) install the real
@adonisplus/*packages from the private registry at plus.adonisjs.com. Picking one asks for a Plus access token once; the project gets@adonisplus:registry=…in.npmrc(safe to commit) and the token goes into~/.npmrcon your machine, exactly whatnpm config setdoes. Permissions pulls in Bouncer and runsnode ace configure @adonisplus/permissions; Flow runsnode ace flow:installfor Claude Code with the stack matching the kit, every prompt answered by a flag (--workflowincluded: without it the command waits for a confirm the runner cannot answer) and, on the monorepo kit, Enter on stdin for the workspace-root prompt. With the Docker card the Dockerfile copies.npmrc, mounts the token as a BuildKit secret (NPM_TOKEN) around each install and removes.npmrcin the sameRUN; compose.yml passes the secret from the environment. The run line inSTUDIO.mdreads the token from~/.npmrcwithsed: npm 11 refusesnpm config geton_authTokenkeys ("option is protected"), which the Plus docs still suggest. - Templates: save any lineup, create from it with just a name and a folder, edit, duplicate, export / import as JSON.
- Community: a registry of shared lineups (bundled samples until you set a registry URL in Settings), copy to mine or use directly.
- Projects: run / stop the dev server, open in your editor, reveal, open a terminal.
- Deploy and Admin dashboard are roadmap placeholders.
Needs Node 24 and npm 11. Tested on Ubuntu 24.04; npm run dev should work on macOS and
Windows as well (untested), packaged builds are not published yet.
git clone https://github.com/campar/adonisjs-studio.git && cd adonisjs-studio
npm install # postinstall runs install-electron: electron 44 ships no postinstall of its own
npm run dev # electron-vite with HMR (Ubuntu: npm run dev:linux, see below)
npm run build # bundles to out/
npm run package:linux # AppImage + deb (also package:mac, package:win)
# screenshots without touching real settings
ADONIS_STUDIO_USER_DATA=/tmp/studio-ud ADONIS_STUDIO_SMOKE=/tmp/shot.png ADONIS_STUDIO_SMOKE_PAGE=projects npx electron . --no-sandboxOn Ubuntu 24.04+ the Chromium sandbox helper needs to be SUID for a dev run:
sudo chown root:root node_modules/electron/dist/chrome-sandbox
sudo chmod 4755 node_modules/electron/dist/chrome-sandbox
# or, for local development only:
npm run dev -- -- --no-sandboxsrc/shared catalog (cards), recipe (lineup → steps), types
src/main Electron main: window, IPC, job runner, file patches, dev servers, stores
src/preload contextBridge API exposed as window.studio
src/renderer React app: shell, lineup cards, pages, shadcn/ui components
Data lives in Electron's userData folder as settings.json, templates.json and
projects.json.