plugins/lt-dev/skills/using-lt-cli/SKILL.md
Provides reference for the lenne.tech CLI tool (lt command). Covers lt fullstack init (workspace creation with local template symlinks), lt fullstack update (version sync), lt fullstack convert-mode (npm/vendor switch), lt git get/reset (branch management), lt server create (project scaffolding), lt server object/addProp (element generation), and lt dev (parallel project orchestration via Caddy + dedicated LaunchAgent — install/uninstall/migrate/up/down/status/doctor/tunnel). Activates when user mentions "lt", "lt CLI", "lenne.tech CLI", "lt fullstack", "lt git", "lt server", "lt dev", "fullstack workspace", "local templates", "--api-link", "--frontend-link", "--noConfirm", "convert-mode", "npm mode", "vendor mode", "Caddy tunnel", "trycloudflare", or any lt command syntax. NOT for NestJS module/object/property creation (use generating-nest-servers). NOT for Vue/Nuxt frontend code (use developing-lt-frontend).
npx skillsauth add lennetech/claude-code using-lt-cliInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
lt fullstack init without --noConfirm blocks Claude Code forever — The interactive prompts (project name, git init, template selection) wait for stdin input. Claude Code cannot respond to them, and the session hangs on "Unfurling..." with no token consumption. ALWAYS pass --noConfirm + all required flags (--name X --frontend nuxt --git false) when calling lt CLI from Claude Code.--api-link and --frontend-link create SYMLINKS, not copies — Changes to the template (nest-server-starter, nuxt-base-starter) in /Users/kaihaase/code/lenneTech/ immediately affect the linked project. This is a feature for framework development but surprises developers who expect copies. Document it in the project README when using --api-link.lt git reset is DESTRUCTIVE and irreversible — Lives next to the safe lt git get in the CLI menu. reset does git reset --hard followed by force-pull, destroying ALL local changes without confirmation. Never run it on a branch with unpushed work. Prefer git stash + lt git get.lt server object X --controller generates REST, NOT GraphQL — Default is REST. For GraphQL projects, use --resolver. The CLI does not auto-detect from existing project patterns — you must specify explicitly.lt fullstack convert-mode rewrites the source tree — Switching between npm and vendor mode moves framework code in/out of src/core/ (API) or app/core/ (App). The operation is reversible but NOT idempotent mid-run — always commit before starting, so a failed conversion can be rolled back via git reset.--next is experimental and incompatible with lt server module/object/addProp/test/permissions — When lt server create --next or lt fullstack init --next is used, the API is cloned from nest-base (Bun + Prisma 7 + Postgres + Better-Auth) instead of nest-server-starter. The downstream generators target the classic nest-server layout (Mongoose models, src/server/modules/, etc.) and will not work on a nest-base project. Use it for greenfield prototyping only; for production work prefer the default template.| User Intent | Correct Skill | |------------|---------------| | "lt fullstack init" | THIS SKILL | | "lt git get feature-branch" | THIS SKILL | | "lt server create my-project" | THIS SKILL | | "lt server module / object / addProp" | generating-nest-servers | | "lt server permissions" | generating-nest-servers | | "Create a NestJS module" | generating-nest-servers | | "Build a Vue component" | developing-lt-frontend |
After lt fullstack init:
generating-nest-serversdeveloping-lt-frontendlt git get <branch-name> # alias: lt git g
lt git reset
Fetches latest from remote, resets current branch to origin/<branch>. Destructive — all local changes lost.
# Non-interactive
lt fullstack init --name <Name> --frontend <angular|nuxt> --git <true|false> --noConfirm \
[--git-link <URL>] [--api-link <path>] [--frontend-link <path>] [--next]
| Parameter | Required | Description |
|-----------|----------|-------------|
| --name | Yes | Workspace name (PascalCase) |
| --frontend | Yes | angular or nuxt |
| --git | Yes | Initialize git: true / false |
| --noConfirm | No | Skip confirmation prompts |
| --git-link | No | Git repository URL |
| --api-branch | No | Branch of nest-server-starter |
| --frontend-branch | No | Branch of frontend starter |
| --api-copy / --api-link | No | Local API template (copy / symlink) |
| --frontend-copy / --frontend-link | No | Local frontend template (copy / symlink) |
| --next | No | Experimental — clone nest-base (Bun + Prisma 7 + Postgres + Better-Auth) for the API. Forces apiMode = Rest, frameworkMode = npm, and skips the workspace install (run pnpm install for app and bun install for api manually). Downstream lt server module/object/addProp/test are NOT compatible with the resulting layout. |
Priority: --*-link > --*-copy > --*-branch > default (GitHub clone)
Created structure:
<workspace>/
├── projects/
│ ├── api/ ← nest-server-starter (or nest-base with --next)
│ └── app/ ← nuxt-base-starter (or ng-base-starter)
├── package.json
└── .gitignore
Post-creation:
cd <workspace> && pnpm install
lt dev init # idempotent: ENV patches + register; auto-runs `lt dev install` first if the machine isn't set up yet
lt dev up # Start API + App behind Caddy under https://<slug>.localhost
# With --next: install per subproject, no workspace install
cd <workspace>/projects/app && pnpm install
cd <workspace>/projects/api && bun install
(Falls back to pnpm -r --parallel run start on default ports 3000/3001 if lt dev is not used.)
Serves every lt project under stable HTTPS URLs (<slug>.localhost, api.<slug>.localhost) via Caddy so multiple projects can run side by side without colliding on 3000/3001 and without auth cross-wiring. Use this in every lt-monorepo or standalone API/App project.
lt dev install # One-time per machine: bootstraps dedicated LaunchAgent/systemd unit + Caddyfile stub + CA reminder
lt dev uninstall [--purge] # Remove the lt-dev service (--purge also drops Caddyfile + logs)
lt dev init # Once per project (idempotent): ENV patches + register
lt dev up # Start API + App behind Caddy
lt dev down # Stop processes + remove Caddy block (also tears down any isolated test stack)
lt dev test # ISOLATED Playwright E2E: parallel stack + dedicated `<slug>-test` DB, auto-teardown
lt dev test --shard # Shard across 2 isolated stacks (default — stable sweet spot)
lt dev test --shard 3 # Shard across N isolated stacks (each own ports/Caddy/DB `<slug>-test-<i>`)
lt dev test --shard auto # Size N from this machine's CPU + RAM (conservative)
lt dev test down # Tear the isolated test stack(s) down (residue-free)
lt dev status # Show URLs + PIDs + live upstream state for THIS project (incl. any test stack)
lt dev status --all # List every registered project + running state
lt dev doctor # Diagnose Caddy / CA / DNS / port issues
lt dev tunnel [--api] # Foreground Cloudflare Quick Tunnel: public *.trycloudflare.com URL
What each subcommand does:
install — One-time per machine. Verifies caddy is on PATH (suggests brew install caddy if missing), creates ~/.lenneTech/Caddyfile stub, writes + bootstraps a dedicated LaunchAgent (macOS, ~/Library/LaunchAgents/tech.lenne.lt-dev-caddy.plist) or systemd-user unit (Linux). Waits up to 8s for the Caddy admin endpoint (:2019) to respond, validates the file, and reminds you to run sudo -E HOME="$HOME" caddy trust (the -E HOME="$HOME" is mandatory — without it sudo switches HOME to /var/root and the CA install silently fails). Does NOT use brew services start caddy — its plist hardcodes --config /opt/homebrew/etc/Caddyfile and crash-loops against our Caddyfile location. Auto-chains: when run inside an un-initialized lt-dev project, runs init afterwards (--skip-init to opt out).uninstall — Symmetric counterpart to install. Boots out the LaunchAgent / systemd unit, removes the unit file. With --purge also deletes ~/.lenneTech/Caddyfile and caddy logs. Does NOT remove the caddy binary itself (use brew uninstall caddy if desired).init (alias migrate) — Idempotent. Builds the project identity (slug = package.json "name", subdomains from monorepo layout), patches legacy hardcoded port: 3000 / port: 3001 / Vite-proxy targets / Playwright URLs to env-aware variants (defaults preserved), persists to ~/.lenneTech/projects.json, injects a "Local Development (lt dev)" URL block into all CLAUDE.md files, adds .lt-dev/ to .gitignore. Auto-chains: runs install first when the machine isn't prepared yet (--skip-install to opt out).up — Allocates internal upstream ports (4000+, never 3000/3001), upserts the Caddy block with reverse_proxy 127.0.0.1:<port> + reloads, exports PORT, HOST=127.0.0.1 / NITRO_HOST=127.0.0.1 (pins dev servers to IPv4 so the upstream is unambiguous), BASE_URL, APP_URL, NUXT_API_URL, NUXT_PUBLIC_API_URL, NUXT_PUBLIC_SITE_URL, NUXT_PUBLIC_STORAGE_PREFIX, NUXT_PUBLIC_API_PROXY=false, NSC__MONGOOSE__URI, DATABASE_URL, NODE_EXTRA_CA_CERTS (Caddy root CA so Nuxt SSR fetches trust HTTPS), plus legacy aliases API_URL / SITE_URL for projects that pre-date the NUXT_* convention. Then spawns pnpm start (api) + pnpm dev (app) detached. Pre-flight checks refuse to start when Caddy is missing, Caddy daemon is down, an existing session is alive, or internal ports are bound. Logs at <root>/.lt-dev/{api,app}.log.down — Sends SIGTERM to the saved process group (negative PID) so children (Vite, Nest watcher, etc.) receive it too. Removes the project's Caddy block + reloads. Also tears down any isolated test stack (lt dev test) for this project.test — ISOLATED E2E. Brings up a SECOND, parallel stack (<slug>-test.localhost / api.<slug>-test.localhost, own ports + Caddy block + .lt-dev/.env.test bridge) on a dedicated DB <slug>-test (separate from the dev <slug>-local and the API-test <slug>-e2e), runs the Playwright suite (global-setup resets that DB once before the first test), then auto-tears-down residue-free. Runs alongside — and never touches — the dev session. --keep leaves it up; lt dev test down stops it; --api runs the (already isolated) API tests instead; --debug = PWDEBUG+headed; -- <args> forwards to Playwright. --shard N runs the suite split across N FULLY-isolated stacks in parallel (each own ports + Caddy block + DB <slug>-test-<i>) + N --shard=i/N Playwright processes — the local CI-parity matrix. A bare --shard defaults to 2 (the stable sweet spot: N≥3 over-subscribes the perf cores on a typical dev machine → flaky); --shard auto sizes N from CPU+RAM (conservative). Local shards share ONE machine (unlike CI's per-shard containers), so the CLI exports LT_DEV_TEST_SHARDS for the project's playwright.config to relax timeouts under that load only (CI stays fast). lt dev test down reclaims all shards. Requires the lt CLI version that ships this isolated session.status / status --all — Current project: subdomains → upstream ports, db URI, session PIDs (alive/dead), live lsof upstream state. --all: every registered project with a ●/○ indicator.doctor — Caddy on PATH, lt-dev LaunchAgent / systemd unit loaded, daemon running, Caddyfile valid, ports 80/443 free or held by Caddy, *.localhost resolves (IPv4 or IPv6 loopback), registry status.tunnel — Foreground Cloudflare Quick Tunnel: cloudflared tunnel --url https://<slug>.localhost --http-host-header <slug>.localhost --no-tls-verify. Prints a public *.trycloudflare.com URL (5-10s) and runs until Ctrl-C. Default exposes the App; --api switches the target. Auth cookies on the localhost domain are NOT valid on the tunnel URL — add the tunnel URL to Better-Auth's trustedOrigins for login flows to succeed. Start a second lt dev tunnel --api in parallel for full external usage.Override the spawn binary via LT_PNPM_BIN (e.g. for bun-based projects via wrapper script).
Work on several tickets/features of ONE project at the same time — each in its
OWN git worktree + its OWN isolated lt dev stack (own URLs, ports, Caddy block,
empty DB) — so several tickets can be browser-tested AND E2E-tested in parallel
without any cross-influence.
lt ticket start DEV-2200 # worktree (branch feat/DEV-2200 from origin/dev) + pnpm install + lt dev up
# → https://svl-2200.localhost / https://api.svl-2200.localhost, DB svl-sports-system-2200 (empty)
lt ticket start checkout-refactor # no ticket? a free feature name works too → svl-checkout-refactor.localhost
lt ticket start DEV-2200 --as cof # override the short id; --branch / --base override branch / base ref (default origin/dev)
lt ticket list # dashboard: every ticket env + URLs + branch + status + DB (re-view URLs anytime)
lt ticket switch <id> # show the worktree path + open it in $LT_EDITOR (default `code`)
lt ticket test <id> [--shard N] # run the E2E suite in the ticket's isolated stack/DB (delegates to lt dev test)
lt ticket stop <id> [--drop-db] # lt dev down + remove the worktree (branch kept); --drop-db also drops the ticket DBs
DEV-2200 → short id 2200; a free name is used as-is. Every ticket gets <slug>-<id> EVERYWHERE — URLs <slug>-<id>.localhost / api.<slug>-<id>…, dev DB <base>-<id>, test DB <base>-<id>-test[-<shard>], own ports + Caddy block + session. The sibling worktree folder <parent>/<slug>-<id> matches the URL, so you always know which ticket you are in.dev: start does git fetch + branches from origin/dev, so every ticket is independent (--base <ref> to start elsewhere). Worktrees share ONE .git — one git fetch updates all, creation is instant, teardown is git-tracked (vs. a full clone per ticket: slower, duplicates .git, untracked)..lt-dev/ticket marker tags the worktree → every lt dev * run in it is ticket-aware with NO flags, and the lt-dev hook surfaces the ticket id + URLs each prompt. The git-tracked CLAUDE.md is NEVER modified per ticket (no git noise).global-setup: allow the per-ticket test-DB pattern <base>-<id>-test(-<n>) in the project's allow-list + local-DB guard — only …-test names, NEVER a ticket's dev DB. (svl's global-setup.ts#isAllowedDb is the reference.)lt server create <name> --noConfirm [--branch <branch>] [--copy <path>] [--link <path>] [--next]
Creates a standalone NestJS project from nest-server-starter. With --next, clones nest-base (Bun + Prisma 7 + Postgres + Better-Auth) instead and skips API-mode / vendor-mode / install / lt.config.json processing. For module/object/property commands, see generating-nest-servers skill — those are NOT compatible with --next projects.
--noConfirm from Claude Code to avoid blocking promptsgit status before lt git reset — it's irreversible--api-link / --frontend-link for local template development (fastest)pnpm install → start API → start App| Topic | File | |-------|------| | Command reference & troubleshooting | reference.md | | Real-world examples | examples.md |
The authoritative references live in the lenneTech/cli GitHub repository. Fetch via WebFetch when deep context is needed:
| Document | URL | When to fetch |
|----------|-----|---------------|
| LT-ECOSYSTEM-GUIDE | https://raw.githubusercontent.com/lenneTech/cli/main/docs/LT-ECOSYSTEM-GUIDE.md | Full reference for CLI + plugin (architecture, commands, agents, skills, vendor-mode, glossary) |
| VENDOR-MODE-WORKFLOW | https://raw.githubusercontent.com/lenneTech/cli/main/docs/VENDOR-MODE-WORKFLOW.md | Step-by-step guide for npm ↔ vendor conversion, vendor updates, rollback |
| Command Reference | https://raw.githubusercontent.com/lenneTech/cli/main/docs/commands.md | Full CLI command reference with all options |
| Configuration Guide | https://raw.githubusercontent.com/lenneTech/cli/main/docs/lt.config.md | lt.config.json reference |
When to fetch: When user asks about architecture/design decisions, vendor-mode conversion steps, or any CLI/plugin function not covered by this skill's condensed content.
generating-nest-servers — lt server module, lt server object, lt server addProp, lt server permissionsdeveloping-lt-frontend — Nuxt/Vue frontend developmentbuilding-stories-with-tdd — TDD workflow orchestrationdevelopment
Single source of truth for the lenne.tech fullstack production-readiness checklist. Defines the eight pillars (configuration & secrets, observability & logging, health & lifecycle, security hardening, data durability, resilience under load, deployment hygiene, runbook & rollback) with concrete file/line evidence requirements per pillar, severity classification (Critical / Major / Minor), and a canonical machine-parseable report block. Activates whenever an agent or command needs to gate a release on production-readiness — currently used by /lt-dev:production-ready, lt-dev:production-readiness-orchestrator, and the devops-reviewer (read-only). NOT for OWASP-style code-level security review (use security-reviewer). NOT for npm dependency audits (use maintaining-npm-packages).
development
Single source of truth for executing GitLab CI/CD pipelines locally with the same image, env vars, and service containers as the real runner — so pipeline failures are caught before push. Defines pipeline discovery (.gitlab-ci.yml + includes), per-job execution via gitlab-runner exec, service-container orchestration (Mongo, Redis, MailHog), env injection without secrets, cache/artifact handling, and a job-by-job verdict report. Also describes the GitHub Actions equivalent via act for projects that mirror to GitHub. Activates whenever an agent or command needs to validate that the CI pipeline will pass — currently used by /lt-dev:production-ready and lt-dev:production-readiness-orchestrator. NOT for running the local check script (use running-check-script). NOT for writing or refactoring CI configs (use the devops agent).
development
Single source of truth for designing, running, and interpreting k6 load tests against lenne.tech fullstack APIs. Defines installation paths (brew, docker, npm), the three canonical scenarios (smoke / load / soak), endpoint discovery from the generated SDK, realistic Better-Auth login flows, threshold defaults for ~10 concurrent users (p95 < 500ms, error rate < 1%, http_req_failed < 1%), result interpretation, and the optimisation ladder when the system fails (DB indices, query rewrites, caching, connection pool sizing, rate-limit relaxation, payload trimming). Activates whenever an agent or command needs to validate that the API is stable for ~10 concurrent users performing many actions in short time, or to detect performance regressions via k6. Currently used by /lt-dev:production-ready, lt-dev:production-readiness-orchestrator, and lt-dev:performance-reviewer. NOT for Lighthouse frontend performance (use a11y-reviewer). NOT for unit performance assertions (use the test runner directly).
tools
Migrates lenne.tech projects from the legacy jest+eslint+prettier toolchain to the current vitest+oxlint+oxfmt baseline used by nest-server-starter and nuxt-base-starter. Covers swc decoratorMetadata config, the @Prop union-type fix for SWC, supertest default-import correction, ESM/CJS interop, the Nitro PORT-vs-NITRO_PORT bug, ANSI escape stripping in workspace runners (lerna/nx), free-port logic for check-server-start.sh, the offers-pattern config.env.ts (NSC__-only + fail-fast + auto-derived appUrl), and the multi-phase check-envs.sh smoke test. Activates whenever someone is migrating an existing project to the new toolchain, debugging "Cannot determine a type for the X field" Mongoose errors, ERR_SOCKET_BAD_PORT crashes from check-server-start, or wants to align an existing project with the current starter conventions.