Skip to content
Back to skills

Init Env

CSecurity

First-time setup orchestrator for the AI Workflow ai-workflow repo. Mirrors SETUP.md as an agent-driven flow (project linking, env vars across Jira / VCS / Agent / Slack / Neon, production deploy, post-deploy registrations for the Jira webhook and the Slack /ai-workflow slash command, and smoke checks). Use when starting fresh on this repo for the first time, such as "init project", "first-time setup", "bootstrap this repo", "onboard me", "set up env from scratch".

  • 11 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added October 10, 2026
developmentgoshellbashnodetestinggitapidatabase

Works with

  • cli
  • api

Security analysis

C68/100
  • mediumUses curl or wget to download content
  • criticalExfiltrates credentials via HTTP — exact pattern from Snyk ToxicSkills study
  • mediumInstalls packages at runtime which could introduce malicious dependencies
  • mediumInstalls packages at runtime which could introduce malicious dependencies

Pro shows the line behind each finding and how to fix it

Scanned October 10, 2026

npx -y skills add Blazity/ai-workflow --skill init-env --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Init Env?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Init Env
[![Security: C — Skills Directory](https://www.skillsdirectory.com/api/skills/blazity-init-env/badge)](https://www.skillsdirectory.com/skills/blazity-init-env)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: init-env
description: First-time setup orchestrator for the AI Workflow ai-workflow repo. Mirrors SETUP.md as an agent-driven flow (project linking, env vars across Jira / VCS / Agent / Slack / Neon, production deploy, post-deploy registrations for the Jira webhook and the Slack /ai-workflow slash command, and smoke checks). Use when starting fresh on this repo for the first time, such as "init project", "first-time setup", "bootstrap this repo", "onboard me", "set up env from scratch".
---

# Initialize Project Environment (Cold Start)

Cold-start orchestrator. Coordinates project linking, paste-template-driven env population across 5 domains, a single production deploy, post-deploy registrations (Jira webhook + Slack slash command), and a smoke handoff. Self-contained: does not invoke other plugins.

> **Canonical reference:** [SETUP.md](../../../SETUP.md) at the repo root is the human-readable end-to-end guide. This skill is the agent-driven orchestration of that same flow. When the two diverge, SETUP.md wins; update this skill.

## What this skill does NOT do

- **Partial re-runs.** This is a cold start only. To rotate one integration later, invoke that subskill standalone (e.g. `init-jira`, `init-vcs`).
- **Local-only setup.** Vercel-only deployment track. `.env.local` is a mirror produced by `vercel env pull`, never the source of truth.
- **Auto-write secrets.** The user pastes values into the Vercel dashboard; this skill never sees them. The skill emits `.env`-format paste-templates and runbooks.

## Execution rules: read first

**Step-by-step. One step per turn. Stop and wait at every irreversible boundary.** Don't bulk through. Don't preview the next step's questions.

For each step:
1. **Announce** the step in one sentence.
2. **Run** the step's logic (subskill invocation, command, or paste-template).
3. **Pause** at irreversible boundaries: every step that ends in **→ Stop. Ask**. Trivial steps (printing a checklist, advancing past a confirmation) chain.
4. **End-of-turn:** at every hard pause, ask *"Ready for the next step: \<name\>?"* and wait for a yes/next/go signal.

If the user replies with anything other than a clear go-signal, do not advance: answer them, fix what they flagged, then re-ask.

Run every command from `apps/worker` unless a step says otherwise, so `.vercel/project.json` below means `apps/worker/.vercel/project.json`. Linking there pins the project's Root Directory to `apps/worker`, so Vercel builds the worker and its cron rather than the repo root ([SETUP.md section 3](../../../SETUP.md#3-clone-the-repo-and-link-to-vercel)).

## Sequence

```
0.  Pre-flight              → tool versions, vercel whoami, existing-link check, team scope
1.  vercel link             → only if not already linked
2.  init-jira (phase 1)     → credentials + columns + JIRA_WEBHOOK_SECRET
3.  init-vcs                → branch on github | gitlab
4.  init-agent              → branch on claude  | codex
5.  init-slack              → bot token, channel, signing secret
6.  init-neon               → Marketplace install runbook
7.  Inline: CRON_SECRET + dashboard auth → auto-generate, paste-template
8.  vercel env pull + validate → .env.local + apps/worker/src/infra/runtime-env.ts
9.  vercel --prod           → single production deploy
10. init-jira (phase 2)     → webhook registration with deploy URL
10b. VCS webhook            → GitHub App webhook URL or GitLab project hook (SETUP.md section 8)
11. Slack slash command     → /ai-workflow registration with deploy URL
12. Smoke checks            → /health + /cron/poll auth + manual ticket
13. Final summary
```

---

## Step 0: Pre-flight

Run these in order. Halt with a clear message on any failure; never invoke `vercel login` from this skill.

### 0a. Toolchain

Required (per [SETUP.md §1](../../../SETUP.md#1-prerequisites)):

```bash
node --version    # v20+
pnpm --version    # v10+
vercel --version  # latest; older CLIs may miss flags this skill expects
git --version     # 2.40+
```

If any version is below the floor, HALT with the exact mismatch and the install command from SETUP.md §1 (`npm i -g pnpm`, `npm i -g vercel@latest`, etc.). Don't try to upgrade for the user.

Also assume the user has run `pnpm install` after cloning. If `node_modules/` is missing, halt and direct them to run it.

### 0b. Authentication

```bash
vercel whoami
```

- **Fails:** HALT. Tell the user: *"Vercel CLI not authenticated. Run `vercel login`, then re-invoke `init-env`."*
- **OK:** record the current scope (team or personal) for step 0d.

### 0c. Existing link

```bash
test -f .vercel/project.json && cat .vercel/project.json
```

- **No link:** continue to step 0d.
- **Link present:** read its `orgId` / `projectId`. Print: *"Existing link found: scope=\<X\> project=\<Y\>. Use this link or relink?"*
  - **Use:** skip step 1 entirely; carry this link forward.
  - **Relink:** HALT. Tell the user: *"Remove `.vercel/project.json` (`rm .vercel/project.json`) and re-invoke `init-env`."*

### 0d. Team-scope confirmation

Compare the existing link's scope (if any) with `vercel whoami` output. If they differ, surface the mismatch explicitly. Otherwise:

Print: *"Will link to team scope: \<current-team\>. Correct?"*

- **No:** HALT. Tell the user: *"Run `vercel switch <team-name>` to change scope, then re-invoke `init-env`."*
- **Yes:** continue.

→ **Stop. Ask:** *"Pre-flight passed. Ready for Step 1: `vercel link`?"*

---

## Step 1: `vercel link`

Skip if step 0c found a usable existing link.

```bash
vercel link
```

The CLI is interactive: let the user complete it. On success, `.vercel/project.json` is written.

**Failure handling:**
- **Permission denied:** HALT. *"Account lacks access to project \<X\>. Ask an owner to grant access, or pick a different project."*
- **Project not found and user declined to create:** HALT. *"Re-invoke `init-env` and accept Vercel's offer to create the project."*
- **Network:** HALT. *"Vercel API unreachable. Check connection and re-invoke."*

→ **Stop. Ask:** *"Linked. Ready for Step 2: Jira credentials and webhook secret?"*

---

## Step 2: Invoke `init-jira` (phase 1)

Invoke the `init-jira` subskill via the Skill tool. It detects state and runs phase 1 because `JIRA_BASE_URL` is not yet set in Vercel:

- Asks for `JIRA_BASE_URL`, `JIRA_API_TOKEN`, and `JIRA_PROJECT_KEY`. Board status names are configured on the Settings page.
- **Pre-generates `JIRA_WEBHOOK_SECRET`** via `openssl rand -hex 32`.
- Emits a single `.env`-format paste-template.
- Walks the user through pasting into the Vercel dashboard (Project Settings → Environment Variables).
- Returns when phase 1 is complete, without testing the values: the Jira card on the Integrations page checks them after the deploy.

→ **Stop. Ask:** *"Jira phase 1 done. Ready for Step 3: VCS provider?"*

---

## Step 3: Invoke `init-vcs`

Invoke `init-vcs`. It asks **github, gitlab or both** and emits a paste-template per chosen provider. No variable picks the provider: each repository record names the one that serves it.

→ **Stop. Ask:** *"VCS configured. Ready for Step 4: agent runtime?"*

---

## Step 4: Invoke `init-agent`

Invoke `init-agent`. It identifies which providers the deployment's harness profiles use and emits only the credentials those providers require. Codex defaults to an API key; OAuth is a documented alternative in the runbook.

→ **Stop. Ask:** *"Agent runtime configured. Ready for Step 5: Slack?"*

---

## Step 5: Invoke `init-slack`

Invoke `init-slack`. It walks the user through creating the Slack app (or finding an existing bot token), the bot's `chat:write` scope, and the channel ID format.

→ **Stop. Ask:** *"Slack configured. Ready for Step 6: Neon Postgres?"*

---

## Step 6: Invoke `init-neon`

Invoke `init-neon`. It walks the user through the Vercel Marketplace install of Neon Postgres with branch-per-environment enabled so Vercel auto-injects `DATABASE_URL` for each environment, which `apps/worker/src/infra/runtime-env.ts` requires.

→ **Stop. Ask:** *"Neon installed. Ready for Step 7: cron secret?"*

---

## Step 7: `CRON_SECRET` and dashboard auth (inline)

Generate locally and emit a one-line paste-template:

```bash
openssl rand -hex 32
```

Tell the user:
*"Paste this into Vercel → Project Settings → Environment Variables for all three environments (Production, Preview, Development):"*

```
CRON_SECRET=<the generated value>
```

Without `CRON_SECRET`, the cron endpoint at `/cron/poll` accepts unauthenticated callers (`apps/worker/src/services/triggers/polling/cron-authorization.ts` allows every caller when the secret is unset). Vercel's auto-injected `Authorization: Bearer $CRON_SECRET` only protects the endpoint when the env var is set.

Then collect the dashboard login variables. The worker refuses to boot without them (`apps/worker/src/infra/runtime-env.ts`), so the Step 9 deploy fails if any is missing:

```
BETTER_AUTH_SECRET=<openssl rand -base64 32>
BETTER_AUTH_URL=https://<project>.vercel.app
DASHBOARD_ORIGIN=<the dashboard deployment's origin>
DASHBOARD_AUTH_EMAIL=<the admin's email>
DASHBOARD_AUTH_PASSWORD=<8+ characters>
```

See [SETUP.md section 5](../../../SETUP.md#5-configure-environment-variables) for what each one does.

→ **Stop. Ask:** *"`CRON_SECRET` and dashboard auth set. Ready for Step 8: pull and validate?"*

---

## Step 8: `vercel env pull` and validate

Run from the directory linked in Step 1:

```bash
vercel env pull .env.local
pnpm --dir <repo root>/apps/worker exec tsx --env-file="$PWD/.env.local" \
  -e "import('./src/infra/runtime-env.ts').then(() => console.log('env ok'))"
```

The validator (`apps/worker/src/infra/runtime-env.ts`, `@t3-oss/env-core`) checks the core variables only:
- Missing boot-required keys (`DATABASE_URL`, `BETTER_AUTH_*`, `DASHBOARD_ORIGIN`, `DASHBOARD_AUTH_*`).
- Format violations (URLs, the 64-hex encryption keys).
- Cross-field violations (`COMMIT_AUTHOR`/`COMMIT_EMAIL`, the four `SSO_*`, `RESEND_*`).

It does **not** check Jira, GitHub, GitLab, Slack or agent credentials: those are integration connection values, and a missing one shows as Failing on that integration's card on the Integrations page after the deploy. Check the cards after Step 9.

**On failure:** the validator prints `Invalid environment variables:` followed by the specific keys. Direct the user to fix them in the Vercel dashboard, then re-run this step.

→ **Stop. Ask:** *"Validator passed. Ready for Step 9: production deploy?"*

---

## Step 9: `vercel --prod`

```bash
vercel --prod
```

This is the first production deploy. It will:
- Build the project against the env vars now in Vercel.
- Assign the stable production URL `<project>.vercel.app`.
- Print the deploy URL on success.

**On failure:** the orchestrator pauses (does not abort). Print the deploy error verbatim, and offer:
- *"Fix the issue (commonly a missing env var the validator can't detect, or a build error) and reply `redeploy` to re-run `vercel --prod`."*

Do not auto-retry. Build errors usually need human intervention.

→ **Stop. Ask:** *"Deployed. Ready for Step 10: register the Jira webhook?"*

---

## Step 10: Invoke `init-jira` (phase 2)

Invoke `init-jira` again. State detection now sees:
- `JIRA_*` env vars present in Vercel.
- `.vercel/project.json` exists with project name.
- A successful production deploy (this step's outcome).

Phase 2 derives the webhook URL from `.vercel/project.json` (`https://<project>.vercel.app/webhooks/jira`) and walks the user through Jira's webhook admin UI. It uses the `JIRA_WEBHOOK_SECRET` already pasted in phase 1: no redeploy needed because the handler reads the secret at request time.

If the user opts to defer webhook registration (custom domain coming, admin permission missing, etc.), record it as a TODO for the final summary and continue.

→ **Stop. Ask:** *"Webhook registered (or deferred). Ready for Step 10b: VCS webhook?"*

---

## Step 10b: Register the VCS webhook

Walk the user through [SETUP.md section 8](../../../SETUP.md#8-register-the-vcs-webhook):

- **GitHub:** set the App's webhook URL to `https://<project>.vercel.app/webhooks/github` if a placeholder was used, and confirm the App subscribes to all five events in [GITHUB-APP-SETUP.md section 5](../../../docs/runbooks/GITHUB-APP-SETUP.md#5-subscribe-to-events). The GitHub card's App webhook health check on the Integrations page names any missing event.
- **GitLab:** add the project hook at `https://<project>.vercel.app/webhooks/gitlab` with the settings in [GITLAB-SETUP.md](../../../docs/runbooks/GITLAB-SETUP.md#configure-the-webhook). GitLab has no health check for its event selection, so read the list there.

If deferred, record it as a TODO for the final summary.

→ **Stop. Ask:** *"VCS webhook registered (or deferred). Ready for Step 11: Slack slash command?"*

---

## Step 11: Slack slash command

Register the `/ai-workflow` slash command against the deployed URL. This is the Slack analogue of Step 10: both webhook and slash command need a live deploy URL, hence both run post-deploy.

Read `.vercel/project.json` for the project name and construct:

```
https://<project>.vercel.app/webhooks/slack
```

Walk the user through the runbook (full version: `init-slack/references/slash-commands.md`). The TL;DR:

1. Open the Slack app's config page (https://api.slack.com/apps → your AI Workflow app).
2. **Slash Commands → Create New Command.**
3. Fill:
   - **Command:** `/ai-workflow`
   - **Request URL:** the slash URL from above
   - **Short description:** `Inspect and control AI workflow runs`
   - **Usage hint:** `list | status <KEY> | cancel <KEY>`
4. Save and **reinstall the app** to the workspace if Slack prompts.
5. Confirm `SLACK_SIGNING_SECRET` is set in Vercel (collected in Step 5). The shared webhook route (`apps/worker/src/routes/webhooks/[id].post.ts`) hands the request to `integrations/slack/slash-command.ts`, which rejects a bad signature with 401; with no signing secret every request is refused with 503.

Verify in Slack:

```
/ai-workflow list
```

If the user can't register the slash command now (admin permission missing, custom domain pending, etc.), record it as a TODO for the final summary and continue.

→ **Stop. Ask:** *"Slash command registered (or deferred). Ready for Step 12: smoke checks?"*

---

## Step 12: Smoke checks

Three checks, in order. Don't skip the first two: they catch deploy/env issues without needing a live ticket round-trip.

### 12a. Health endpoint

```bash
curl https://<project>.vercel.app/health
# expect: 200 with "status":"ok"; commit, env and timestamp identify the deployment
```

Failure modes:
- Non-200: build is broken or env-var validation crashed at startup. Run `vercel logs --prod` to inspect; the user must fix and redeploy.
- 200 but wrong body: a middleware or routing regression. Surface the response and stop.

### 12b. Cron auth

```bash
# unauth: must reject
curl -i https://<project>.vercel.app/cron/poll
# expect: HTTP/1.1 401

# authed: must succeed
curl -i -H "Authorization: Bearer $CRON_SECRET" https://<project>.vercel.app/cron/poll
# expect: HTTP/1.1 200
```

If the unauth call returns 200, `CRON_SECRET` is missing in Production. Ask the user to set it (Step 7's value) and redeploy.

The user can paste `$CRON_SECRET` directly from their local shell if they ran `vercel env pull` in Step 8 and source `.env.local` first.

### 12c. End-to-end ticket

Print:

```
Last check. Drop a test ticket in Jira to verify the bot end-to-end.

  1. Open ${JIRA_BASE_URL}/jira/your-projects
  2. Create a small issue:
       - Title: "Hello from AI Workflow"
       - Description: include an "Acceptance Criteria" block, e.g.
         ## Acceptance Criteria
         - The repo has a HELLO.md file
  3. Drag the ticket from the Backlog column to the AI column.

Within ~5s (with webhook) or up to 15 minutes (cron fallback), expect:
  - A bot comment on the ticket
  - A branch `ai-workflow/<ticket-key>` and a PR opened in your VCS
  - A Slack message in your channel
  - The ticket transitions to "AI Review"

Reply when you've seen the PR (or "stuck on X" if a step is missing).
```

Wait for the user's response. If they report a failure, capture which milestone was missing and route to the matching row in [SETUP.md §13, Troubleshooting](../../../SETUP.md#13-troubleshooting). Include the result in the final summary.

→ **Stop. Ask:** *"Smoke passed?"*

---

## Step 13: Final summary

Print the summary template below, populated with the values gathered during the flow. Use the actual project name from `.vercel/project.json` and the user-reported smoke result.

```
Cold start complete.

Linked Vercel project:  <team>/<project>
Production URL:         https://<project>.vercel.app
Jira webhook URL:       https://<project>.vercel.app/webhooks/jira
Slack request URL:      https://<project>.vercel.app/webhooks/slack

Configured:
  Jira     <project_key>           webhook <registered | deferred>
  VCS      <github|gitlab|both>    webhook <registered | deferred>
  Agent    <claude|codex|both>     credentials set (model comes from each block's Harness Profile)
  Slack    channel <id>            bot @<bot_name>, slash <registered | deferred>
  Neon     DATABASE_URL per env    via Marketplace
  Cron     CRON_SECRET set         poll every 15 minutes

Skipped (see SETUP.md for the full how-to):
  - Arthur AI tracing: SETUP.md §12. Set GENAI_ENGINE_API_KEY and
    GENAI_ENGINE_TRACE_ENDPOINT to enable per-run tracing and the
    prompt-injection check.
  - GitLab alongside or instead of GitHub: SETUP.md §12. Provide
    GITLAB_TOKEN and GITLAB_WEBHOOK_SECRET (+ GITLAB_HOST for self-hosted),
    or connect GitLab on the Integrations page, register the project webhook
    (SETUP.md section 8), then import its repositories on the Repositories page.
  - CI / GitHub Actions: SETUP.md §11. The `e2e` GitHub environment
    needs the prod env vars plus E2E_BASE_URL, E2E_GITHUB_APP_ID,
    E2E_GITHUB_APP_PRIVATE_KEY (base64 PEM), E2E_GITHUB_INSTALLATION_ID,
    E2E_GITHUB_OWNER, E2E_GITHUB_REPO, and VERCEL_AUTOMATION_BYPASS_SECRET
    as secrets.
  - Custom domain: point a domain at the Vercel project for a stable
    webhook URL (then update the Jira webhook, the VCS webhook and the Slack
    request URLs).
  - VERCEL_TOKEN local PAT: local dev only; Vercel uses OIDC in prod.

Smoke checks:
  /health        <pass | fail>
  /cron/poll     <pass | fail>
  end-to-end     <user-reported pass | fail with diagnostic>

Maintenance:
  Rotate one integration later by invoking that subskill standalone:
    init-jira | init-vcs | init-agent | init-slack | init-neon

  Inspect the deployment:
    vercel logs --prod
    https://vercel.com/<team>/<project>/observability

  Troubleshooting matrix: SETUP.md §13.

No git changes were made. .env.local and .vercel/project.json are gitignored.
```

→ **Done.** Do not auto-commit, auto-push, or open a PR. The user owns git.

---

## Don'ts

- **Don't invoke `vercel login`.** It's an interactive, browser-launching flow the orchestrator can't observe. If pre-flight detects no auth, halt and tell the user.
- **Don't print or log secret values.** Reference them by name only. Pre-generated secrets (`JIRA_WEBHOOK_SECRET`, `CRON_SECRET`) appear once in the paste-template the user copies; never repeat them in summaries or logs.
- **Don't auto-retry failed deploys.** Pause, surface the error, let the user fix and reply `redeploy`.
- **Don't bulk through subskill invocations.** Each subskill is its own step; pause for the user's confirmation between them.
- **Don't auto-`vercel link` to a team without confirming.** Linking writes `.vercel/project.json` and binds future deploys.
- **Don't write `.env`.** `.env.local` (from `vercel env pull`) is the only local file, and `.env.example` is the committed reference.
- **Don't invent variables.** Core variables live in `apps/worker/src/infra/runtime-env.ts`, integration variables in each `integrations/<id>/manifest.ts`. If you need a new key, propose adding it there first.

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…