setup-dev-hub
Set up and launch a local TIBCO Developer Hub from a clean checkout, following the README's getting-started flow. The goal is a working yarn start with backend on :7007 and frontend on :3000 (→ http://localhost:3000/tibco/hub).
Key facts
- Repo root: the repository checkout directory (e.g.
tibco-developer-hub). Run everything from there. - Required versions (from
package.json+ README): Node22 || 24, Yarn exactly4.4.1(pinned viapackageManager), Docker with Compose only if the user picks the Postgres DB. - Native modules:
yarn installcompilesisolated-vmandbetter-sqlite3from source vianode-gyp, so a C++ toolchain + Python 3 must be present (see step 1). This is the most common reason a fresh install fails. - Config files are gitignored, so it's safe to write secrets into them:
app-config.local.yaml← copy ofapp-config.template-local.yaml.env.yarn← copy of.env.yarn-local
- In-memory DB is first-class:
packages/backenddepends onbetter-sqlite3, andapp-config.yamlships the commentedclient: better-sqlite3/connection: ':memory:'snippet. No Docker required for this path. - Sandbox: writing under
.claude/and binding/connecting to localhost ports are blocked by the default Bash sandbox. Retry those specific commands withdangerouslyDisableSandbox: true. The repo-root file writes (config files) go through the.allow-list and are fine in-sandbox. - Sandbox for yarn commands: Both
yarn installandyarn startmust usedangerouslyDisableSandbox: true. The transitive dependencyiconv-lite@0.6.3(viawhatwg-encoding) ships.idea/IDE files inside its published npm package ZIP; Claude Code's sandbox blocks writes to.ideapaths, causingEPERM: operation not permittedduring Yarn's link step. This is a known false positive — not a real security concern. - Idempotency: if
app-config.local.yamlor.env.yarnalready exist, do not clobber them — show the user what's there and ask before overwriting. The user may already have a working setup.
Workflow
Track these as tasks (TaskCreate) since the flow is long: prereqs → DB choice → config files → auth policy → GitHub PAT → install → start → verify.
1. Verify prerequisites and versions
Run the checks in one batched Bash call. Don't fail fast on the first miss — collect everything, then report a single punch list.
node --version # accept v22.x or v24.x; anything else is a blocker
yarn --version # must be 4.4.1
which yarn corepack
# native build toolchain (macOS):
xcode-select -p # Command Line Tools path; non-zero exit = not installed
python3 --version # node-gyp needs Python 3
make --version | head -1
cc --version | head -1
Interpretation:
- Node wrong major → stop and tell the user to install Node 24.x (
nodejs.org); offernvm install 24ifnvmis on PATH (it is, per the environment). Don't auto-switch their Node without saying so. - Yarn missing or wrong version → the repo pins
yarn@4.4.1viapackageManager, socorepack enableis the fix: runcorepack enablethen re-checkyarn --versionfrom the repo root (Corepack readspackageManagerand shims the right version). Don'tnpm i -g yarn. - Toolchain missing (
xcode-select -perrors) → tell the user to runxcode-select --installand re-run the skill;yarn installwill otherwise fail compilingisolated-vm/better-sqlite3. On Linux the equivalent isbuild-essential+python3+g++.
Report the results compactly (✓ / ✗ per item) before moving on. Only the Node/Yarn/toolchain items are hard blockers; Docker is checked later and only if needed.
2. Choose the database (AskUserQuestion)
Single-select, recommend in-memory:
- In-memory (sqlite) — (Recommended) no Docker, fastest boot, data wiped on every restart. Good for trying the Hub or template/theme work.
- Docker Postgres — persistent, matches production. Needs Docker.
If in-memory
No Docker checks needed. In step 3 you'll override the backend.database block to:
database:
client: better-sqlite3
connection: ':memory:'
cache:
store: memory
(The .env.yarn POSTGRES_* values are then unused but harmless — still create the file per the README.)
If Docker Postgres
First confirm Docker is usable, then check whether a Postgres is already listening before starting another:
docker --version && docker compose version
docker info >/dev/null 2>&1 && echo "daemon up" || echo "daemon DOWN"
lsof -nP -iTCP:5432 -sTCP:LISTEN || echo "nothing on 5432"
docker ps --filter "publish=5432" --format '{{.Names}} {{.Image}}'
- Daemon down → ask the user to start Docker Desktop, then continue.
- Something already on
:5432→ don't start a second instance. Tell the user what's there and reuse it; make sure.env.yarnhost/port/user/password match it (thedocker-compose.ymldefaults arelocalhost:5432, userpostgres, passwordexample). - Nothing on
:5432→ start the bundled DB:
This also starts Adminer oncd docker && docker compose up -d:8080. (Usedocker compose up -d dbto skip Adminer.) Then poll until ready:
Note: localhost/Docker socket calls needuntil docker compose exec -T db pg_isready -U postgres >/dev/null 2>&1; do sleep 2; donedangerouslyDisableSandbox: true.
3. Create the config files
Guard against overwriting (see Idempotency). When safe to proceed:
.env.yarn— copy.env.yarn-localverbatim. It definesPOSTGRES_HOST/PORT/USER/PASSWORDmatching the docker-compose defaults.app-config.local.yaml— copyapp-config.template-local.yaml, then:- In-memory path: replace the
backend.databaseblock (client: pg+connection: {host,port,user,password}) with thebetter-sqlite3/:memory:+cache.store: memoryblock shown in step 2. Use the Edit tool on the copied file. - Postgres path: leave the template's
pgblock as-is (it reads thePOSTGRES_*env vars from.env.yarn).
- In-memory path: replace the
Use cp for the copy, then the Edit tool for any edits — don't hand-write the whole YAML from scratch, the templates carry support links, catalog rules, essentialLocations, and auth defaults you want to preserve.
3b. Disable default auth policy? (AskUserQuestion)
Ask the user whether they want to disable Backstage's default auth policy. Frame this clearly as a local-dev-only option.
"Do you want to disable the default backend auth policy? This lets you call the backend API directly (curl, Postman, browser) without a Bearer token — useful for local testing. This is only safe for local development and must never be used in production."
Yes → add
dangerouslyDisableDefaultAuthPolicy: trueunderbackend.authinapp-config.local.yaml:backend: auth: dangerouslyDisableDefaultAuthPolicy: true externalAccess:No → leave the config as-is. Direct API calls will return 401 without a token, but the app and frontend work normally.
4. GitHub PAT (optional)
Ask whether the user wants to wire a GitHub Personal Access Token now. Templates and the import-flow feature need one to actually create/read repos; guest browsing works without it.
- No token → leave
integrations.githubcommented inapp-config.local.yamland skip. The app still boots with guest auth. - Has a token → have the user provide it. Then:
- Append
GITHUB_TOKEN=<value>to.env.yarn. - Uncomment the
integrations.githubblock inapp-config.local.yaml(hostgithub.com,token: ${GITHUB_TOKEN}). - Never echo the token back in chat, and never commit it.
.env.yarnandapp-config.local.yamlare gitignored — verify withgit check-ignore .env.yarn app-config.local.yamlif unsure.
- Append
5. Install dependencies
From the repo root, always with dangerouslyDisableSandbox: true (see Key Facts — iconv-lite ships .idea files):
yarn install
This is slow (native module compilation). Run it with run_in_background: true and wait for the completion notification rather than polling. If it fails on isolated-vm/better-sqlite3/node-gyp, the cause is almost always a missing toolchain from step 1 — surface the actual compiler error and point back there; don't retry blindly.
If it fails with EPERM: operation not permitted on a .idea/ path, it's the sandbox — make sure dangerouslyDisableSandbox: true is set and retry after deleting node_modules.
6. Start the app
Always with dangerouslyDisableSandbox: true (same reason as install):
NODE_OPTIONS=--no-node-snapshot yarn start
(yarn start already sets --no-node-snapshot; it's required for the scaffolder's isolated-vm.) This is long-running — start it with run_in_background: true. Don't wait on it to "finish"; it stays up.
7. Verify (port check only)
Poll until both ports answer, then report. Localhost calls need dangerouslyDisableSandbox: true.
Important: the catalog API returns 401 by default unless dangerouslyDisableDefaultAuthPolicy: true was set in step 3b. Use a plain HTTP response check (any response = port is up) rather than -f which fails on 4xx:
until curl -s -o /dev/null -w "%{http_code}" http://localhost:7007 | grep -qE '^[0-9]' \
&& curl -s -o /dev/null http://localhost:3000; do sleep 3; done
echo "backend :7007 and frontend :3000 are up"
Give the backend a minute or two on first boot (it runs DB migrations / catalog ingestion). If the ports never come up, read the backend output from the background yarn start task for the failure (common ones: DB connection refused → Docker DB not running; config schema error → check the edited app-config.local.yaml).
When both respond, tell the user the app is ready at http://localhost:3000/tibco/hub and note the chosen DB mode (and, for Docker, that Adminer is on :8080). Leave yarn start running.
Don't
- Don't
npm i -g yarnor change the pinned Yarn version — use Corepack soyarn@4.4.1is honored. - Don't overwrite an existing
app-config.local.yaml/.env.yarnwithout asking — it may be the user's working config with real secrets. - Don't auto-switch the user's Node version silently; tell them what you're doing.
- Don't start a second Postgres if one is already on
:5432— reuse it. - Don't print or commit the GitHub token.
- Don't block on
yarn install/yarn startsynchronously — run them in the background and react to completion / port readiness. - Don't try to start
yarn startyourself if the user already has it running (a process already on:3000/:7007) — just verify and report.
Source: TIBCOSoftware/tibco-developer-hub — distributed by TomeVault.