add-app
Add a new deployable service or app to the monorepo (a NestJS worker or service, a Python service, a new client), wired into local dev, the database roles, images, the charts, CI and the docs. Use whe
SKILL.md.claude/skills/add-app/SKILL.md
GitHubAdd an app or service
A new deployable is expensive to run and to keep: first check whether a module in an
existing service does the job (a queue consumer in apps/worker, a module in apps/api).
Services never import each other; they share packages/* and talk through the API
contract, queues and events. This is the checklist for a NestJS service apps/<name>;
apps/worker is the one to copy.
The code
apps/<name>/: copyapps/worker'spackage.json(name@repo/<name>, the same scripts),tsconfig.json,tsdown.config.ts,vitest.config.ts,src/main.ts,src/telemetry.ts,src/app.module.ts,src/env.ts(withdatabaseEnv("<NAME>")if it uses Postgres), and aCLAUDE.md(commands, where things are, gotchas). Give it the next free port (3005 and up) asPORT: port(<n>), and/health/live,/health/readyand/health/dependenciesthroughHealthModulefrom@repo/nest-common.bun installto link it. Its integration tests take the next free Valkey database number (docs/testing.md lists them) and flush it withflushTestDatabase;scripts/redis-databases.test.tsfails if two suites share one.
Its database role, if it uses Postgres
app_<name>ininfra/postgres/init/01-roles-and-databases.sql(login,NOBYPASSRLS NOINHERIT,CONNECTonappandapp_test), inrolesindeploy/charts/data/values.yaml, inROLE_PASSWORDSinpackages/db/src/testing/index.ts, and in the doctor's role count (scripts/doctor.ts). Grants in a migration (the db-change skill), and<NAME>_DATABASE_URLin.env.example. An existing local volume needs the roles script rerun: the doctor says how.
Local development
- The root
package.jsondevscript lists the core services with--filter: add@repo/<name>if it's core;dev:fullruns every package'sdevanyway. Add it toSERVICESinscripts/e2e.tsif end-to-end tests need it.
Images, charts and CI
- The image:
docker-bake.hcl(node-service'smatrix.serviceand thedefaultgroup), and the image lists in.github/workflows/deploy.yml,preview.ymlandci.yml's images job (workflow changes: say so, the user decides). - The chart: an entry under
servicesindeploy/charts/stack/values.yaml(image, port,database: { role, envPrefix },redis, probes,env,keda.queuesfor its queues), a test indeploy/charts/stack/tests/, and a Secretboilerplate-<name>per environment if it has secrets (templates in docs/new-project.md).bun run charts:check. - Commit scopes need nothing:
commitlint.config.tsreads the workspace folders. knip: anentryforsrc/main.tsandsrc/telemetry.tsinknip.jsonc, like the other workers.
Docs
- The README's "What's inside", the table in
docs/architecture.md, the layout and port list inCLAUDE.md, anddocs/environment.mdfor its variables (thedocs-syncagent checks them).
A Python service copies apps/ai instead (its pyproject.toml, deploy/docker/ ai.Dockerfile, the python CI job). A new client app copies apps/web or apps/mobile
and talks to the API only through packages/client.
Done when
bun run lint(the boundary rules see the new app),bun run check-types,bun run test,bun run test:integrationpass.bun devstarts it (in the background) andcurl localhost:<port>/health/dependenciesanswers 200 (it's up and reaches its database and Redis).bun run charts:checkpasses, anddocker buildx bake <name>builds.- The
revieweragent, andmigration-reviewerfor its grants, report nothing blocking.