Skip to content

Commit 169fe67

Browse files
authored
Merge pull request #75 from Blazity/dev
feat: update .env.example
2 parents 068a577 + 063a1ee commit 169fe67

3 files changed

Lines changed: 125 additions & 361 deletions

File tree

.env.example

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,17 @@ GITHUB_BASE_BRANCH=main
3434
# GITLAB_BASE_BRANCH=main
3535
# GITLAB_HOST=https://gitlab.com # override for self-hosted GitLab
3636

37-
# Messaging (Chat SDK)
37+
# Messaging (Chat SDK) — optional. When SLACK_TOKEN+CHANNEL_ID are unset, a no-op
38+
# adapter is used and runs proceed silently.
3839
CHAT_SDK_SLACK_TOKEN=xoxb-xxxxxxxxxxxx
3940
CHAT_SDK_CHANNEL_ID=C0123456789
4041
CHAT_SDK_BOT_NAME=blazebot
4142

43+
# Slack slash commands — required only if you register the /ai-workflow command.
44+
# When unset, /webhooks/slack rejects all requests.
45+
# SLACK_SIGNING_SECRET=
46+
# SLACK_ALLOWED_USER_IDS=U0123,U4567 # comma-separated allowlist; empty = anyone
47+
4248
# Agent — choose runtime (claude | codex). Defaults to claude.
4349
AGENT_KIND=claude
4450

@@ -91,6 +97,9 @@ JOB_TIMEOUT_MS=1800000
9197
# Polling
9298
POLL_INTERVAL_MS=300000
9399

100+
# Phase 3 (Review) — opt-in self-review pass after implementation, before push.
101+
# ENABLE_REVIEW_PHASE=false
102+
94103
# Vercel Sandbox (LOCAL DEV ONLY — on Vercel, OIDC authenticates automatically)
95104
# VERCEL_TOKEN=
96105
# VERCEL_TEAM_ID=

README.md

Lines changed: 3 additions & 292 deletions
Original file line numberDiff line numberDiff line change
@@ -68,298 +68,9 @@ flowchart TD
6868
| Logging | [Pino](https://getpino.io) | Structured JSON logs |
6969
| Testing | [Vitest](https://vitest.dev) | Unit and E2E tests |
7070

71-
## Getting Started
72-
73-
### Prerequisites
74-
75-
- **Node.js** 20+
76-
- **pnpm** 10+
77-
- **Vercel CLI**`npm i -g vercel@latest`
78-
- **Accounts** — you'll need credentials for:
79-
- [Jira](https://www.atlassian.com/software/jira) (API token)
80-
- [GitHub](https://github.com) (personal access token with repo scope)
81-
- [Slack](https://slack.com) (bot token with `chat:write` scope)
82-
- [Anthropic](https://console.anthropic.com) (API key)
83-
- [Upstash](https://upstash.com) (Redis database)
84-
85-
### 1. Clone and install
86-
87-
```bash
88-
git clone https://github.com/Blazity/ai-workflow.git
89-
cd ai-workflow
90-
pnpm install
91-
```
92-
93-
### 2. Link to Vercel
94-
95-
ai workflow runs on Vercel and uses OIDC for Sandbox authentication. Link the project first:
96-
97-
```bash
98-
vercel link
99-
```
100-
101-
Follow the prompts to connect to your Vercel team and project.
102-
103-
### 3. Configure environment variables
104-
105-
Copy the example file and fill in your credentials:
106-
107-
```bash
108-
cp .env.example .env
109-
```
110-
111-
Walk through each section:
112-
113-
**Jira** — Your Atlassian instance and API credentials:
114-
```bash
115-
JIRA_BASE_URL=https://your-domain.atlassian.net
116-
JIRA_EMAIL=your-email@example.com
117-
JIRA_API_TOKEN=your-jira-api-token # Generate at https://id.atlassian.com/manage-profile/security/api-tokens
118-
JIRA_PROJECT_KEY=PROJ # Your Jira project key (e.g., AWT)
119-
JIRA_WEBHOOK_SECRET= # Optional: openssl rand -hex 32. Without it, dispatch falls back to 1-min cron polling.
120-
```
121-
122-
> The Jira webhook is registered separately (see [SETUP.md § 8](./SETUP.md#8-register-the-jira-webhook)). The handler at `/webhooks/jira` verifies an `X-Hub-Signature` HMAC-SHA256 header.
123-
124-
**Jira columns** — The board column names ai workflow watches and moves tickets between:
125-
```bash
126-
COLUMN_AI=AI # Column where tickets are assigned to the agent
127-
COLUMN_AI_REVIEW=AI Review # Column where completed tickets go for human review
128-
COLUMN_BACKLOG=Backlog # Column where tickets go when clarification is needed
129-
```
130-
131-
**VCS** — Choose `github` or `gitlab`. Only fill the block matching your provider.
132-
133-
```bash
134-
VCS_KIND=github
135-
136-
# GitHub (active when VCS_KIND=github)
137-
GITHUB_TOKEN=ghp_xxxxxxxxxxxx # Personal access token with repo scope
138-
GITHUB_OWNER=your-org # GitHub org or username
139-
GITHUB_REPO=your-repo # Target repository name
140-
GITHUB_BASE_BRANCH=main # Branch PRs will target
141-
```
142-
143-
```bash
144-
VCS_KIND=gitlab
145-
146-
# GitLab (active when VCS_KIND=gitlab)
147-
GITLAB_TOKEN=glpat-xxxxxxxxxxxx # PAT with api, read_repository, write_repository scopes
148-
GITLAB_PROJECT_ID=group/repo # Project ID or full path
149-
GITLAB_BASE_BRANCH=main # Branch PRs will target
150-
GITLAB_HOST=https://gitlab.com # Override for self-hosted
151-
```
152-
153-
**Slack** — Bot notifications and slash commands. Bot scopes: `chat:write`, `commands`, `files:read`, `users:read`.
154-
```bash
155-
CHAT_SDK_SLACK_TOKEN=xoxb-xxxxxxxxxxxx # Slack bot token
156-
CHAT_SDK_CHANNEL_ID=C0123456789 # Channel ID for notifications
157-
CHAT_SDK_BOT_NAME=blazebot # Display name for the bot
158-
SLACK_SIGNING_SECRET=xxxxxxxxxxxxxxxx # Required — verifies /ai-workflow slash commands
159-
SLACK_ALLOWED_USER_IDS=U0123,U4567 # Optional: comma-separated allowlist
160-
```
161-
162-
Operators can drive workflows directly from Slack with `/ai-workflow list | status <KEY> | cancel <KEY>` once `SLACK_SIGNING_SECRET` is set and the slash command is registered (Request URL: `https://<your-domain>/webhooks/slack`). See `.claude/skills/init-slack/references/slash-commands.md` for the full setup walkthrough.
163-
164-
**Agent** — AI model configuration:
165-
```bash
166-
ANTHROPIC_API_KEY=sk-ant-xxxxxxxxxxxx # Anthropic API key
167-
CLAUDE_MODEL=claude-opus-4-6 # Model to use (default: claude-opus-4-6)
168-
# COMMIT_AUTHOR= # Optional override (set with COMMIT_EMAIL).
169-
# COMMIT_EMAIL= # On GitHub, leave unset to author commits as the App's bot.
170-
```
171-
172-
**GitHub App bot identity** — when `VCS_KIND=github` and both `COMMIT_AUTHOR` / `COMMIT_EMAIL` are unset, the workflow derives the identity from the configured GitHub App (`<app-slug>[bot]` + the `<id>+<slug>[bot]@users.noreply.github.com` noreply address). GitHub then renders commits with the App's avatar and the `[bot]` badge in the UI.
173-
174-
**Switching agents** — ai workflow supports two CLI runtimes. Set `AGENT_KIND` once per deployment:
175-
176-
```bash
177-
AGENT_KIND=claude # default — Anthropic Claude Code
178-
# or
179-
AGENT_KIND=codex # OpenAI Codex CLI
180-
```
181-
182-
When `AGENT_KIND=codex`:
183-
184-
```bash
185-
CODEX_API_KEY=sk-codex-xxxxxxxxxxxx # or CODEX_CHATGPT_OAUTH_TOKEN
186-
CODEX_MODEL=gpt-5-codex # default
187-
```
188-
189-
Pricing is fetched from [LiteLLM's community-maintained JSON](https://github.com/BerriAI/litellm/blob/main/model_prices_and_context_window.json) on each cold start (1h TTL by default). Override `CODEX_PRICING_URL` in air-gapped environments. When pricing is unavailable, Slack reports show tokens-only with `cost unknown`.
190-
191-
**Sandbox** — Concurrency and timeout limits:
192-
```bash
193-
MAX_CONCURRENT_AGENTS=3 # Max parallel sandboxes (default: 3)
194-
JOB_TIMEOUT_MS=1800000 # Agent timeout in ms (default: 30 minutes)
195-
```
196-
197-
**Run Registry** — Upstash Redis for tracking active runs:
198-
```bash
199-
AI_WORKFLOW_KV_REST_API_URL=https://your-redis.upstash.io
200-
AI_WORKFLOW_KV_REST_API_TOKEN=your-upstash-token
201-
```
202-
203-
**Security** — Cron endpoint authorization:
204-
```bash
205-
CRON_SECRET=your-secret # Vercel Cron uses this to authenticate requests
206-
```
207-
208-
### 4. Set up local Postgres (for workflow state in dev)
209-
210-
Vercel Workflows needs a Postgres database locally. Create one and set the connection string:
211-
212-
```bash
213-
WORKFLOW_POSTGRES_URL=postgresql://localhost:5432/ai_workflow
214-
```
215-
216-
### 5. Pull Vercel environment (optional)
217-
218-
If your Vercel project already has environment variables configured:
219-
220-
```bash
221-
vercel env pull .env.local
222-
```
223-
224-
This provisions OIDC tokens for Sandbox authentication automatically — no need to set `VERCEL_TOKEN`, `VERCEL_TEAM_ID`, or `VERCEL_PROJECT_ID` manually.
225-
226-
### 6. Run locally
227-
228-
```bash
229-
pnpm dev
230-
```
231-
232-
### 7. Verify it works
233-
234-
Check the health endpoint:
235-
236-
```bash
237-
curl http://localhost:3000/health
238-
# → {"status":"ok","timestamp":"2026-03-30T12:00:00.000Z"}
239-
```
240-
241-
Trigger a poll manually (requires `CRON_SECRET`):
242-
243-
```bash
244-
curl -H "Authorization: Bearer $CRON_SECRET" http://localhost:3000/cron/poll
245-
```
246-
247-
## Environment Variables Reference
248-
249-
| Variable | Required | Default | Description |
250-
|----------|----------|---------|-------------|
251-
| **Jira** | | | |
252-
| `ISSUE_TRACKER_KIND` | No | `jira` | Issue tracker type (only `jira` supported today) |
253-
| `JIRA_BASE_URL` | Yes || Atlassian instance URL |
254-
| `JIRA_EMAIL` | Yes || Jira account email |
255-
| `JIRA_API_TOKEN` | Yes || Jira API token |
256-
| `JIRA_PROJECT_KEY` | Yes || Jira project key |
257-
| `JIRA_WEBHOOK_SECRET` | No || HMAC secret for `/webhooks/jira`. Without it, dispatch is cron-bound. |
258-
| `COLUMN_AI` | Yes || Board column for AI-assigned tickets |
259-
| `COLUMN_AI_REVIEW` | Yes || Board column for completed tickets |
260-
| `COLUMN_BACKLOG` | Yes || Board column for tickets needing clarification |
261-
| **VCS** | | | |
262-
| `VCS_KIND` | Yes || `github` or `gitlab` |
263-
| `GITHUB_TOKEN` | Yes† || GitHub PAT with `repo` scope (when `VCS_KIND=github`) |
264-
| `GITHUB_OWNER` | Yes† || GitHub org or username (when `VCS_KIND=github`) |
265-
| `GITHUB_REPO` | Yes† || Target repository (when `VCS_KIND=github`) |
266-
| `GITHUB_BASE_BRANCH` | No | `main` | Base branch for PRs |
267-
| `GITLAB_TOKEN` | Yes† || GitLab PAT with `api`, `read_repository`, `write_repository` (when `VCS_KIND=gitlab`) |
268-
| `GITLAB_PROJECT_ID` | Yes† || Project ID or `group/repo` path (when `VCS_KIND=gitlab`) |
269-
| `GITLAB_BASE_BRANCH` | No | `main` | Base branch for MRs |
270-
| `GITLAB_HOST` | No | `https://gitlab.com` | Override for self-hosted GitLab |
271-
| **Slack** | | | |
272-
| `CHAT_SDK_SLACK_TOKEN` | Yes || Slack bot token |
273-
| `CHAT_SDK_CHANNEL_ID` | Yes || Notification channel ID |
274-
| `CHAT_SDK_BOT_NAME` | No | `blazebot` | Bot display name |
275-
| `SLACK_SIGNING_SECRET` | Yes || Slack app signing secret; verifies `/ai-workflow` slash commands |
276-
| `SLACK_ALLOWED_USER_IDS` | No || Comma-separated Slack user IDs allowed to run `/ai-workflow`; empty = anyone |
277-
| **Agent** | | | |
278-
| `AGENT_KIND` | No | `claude` | Runtime: `claude` or `codex` |
279-
| `ANTHROPIC_API_KEY` | Yes‡ || Anthropic API key (required when `AGENT_KIND=claude`) |
280-
| `CLAUDE_MODEL` | No | `claude-opus-4-6` | Claude model ID |
281-
| `CODEX_API_KEY` | Yes‡ || OpenAI Codex API key (required when `AGENT_KIND=codex`) |
282-
| `CODEX_CHATGPT_OAUTH_TOKEN` | No || Alternative to `CODEX_API_KEY` |
283-
| `CODEX_MODEL` | No | `gpt-5-codex` | Codex model ID |
284-
| `CODEX_PRICING_URL` | No | LiteLLM JSON | Pricing source for Codex cost reporting |
285-
| `CODEX_PRICING_TTL_MS` | No | `3600000` | Pricing cache TTL (ms) |
286-
| `COMMIT_AUTHOR` | No | _GitHub: App bot / GitLab: `ai-workflow-blazity`_ | Git author name (override; pair with `COMMIT_EMAIL`) |
287-
| `COMMIT_EMAIL` | No | _GitHub: App bot / GitLab: `ai-workflow@blazity.com`_ | Git author email (override; pair with `COMMIT_AUTHOR`) |
288-
| **Sandbox** | | | |
289-
| `MAX_CONCURRENT_AGENTS` | No | `3` | Max parallel sandboxes |
290-
| `JOB_TIMEOUT_MS` | No | `1800000` | Agent timeout (ms) |
291-
| **Attachments** | | | |
292-
| `ATTACHMENT_MAX_FILE_SIZE_MB` | No | `25` | Per-file size limit |
293-
| `ATTACHMENT_MAX_TOTAL_SIZE_MB` | No | `100` | Combined attachment size limit |
294-
| `ATTACHMENT_MAX_COUNT` | No | `20` | Max attachments per ticket |
295-
| `ATTACHMENT_DOWNLOAD_TIMEOUT_MS` | No | `30000` | Download timeout per attachment |
296-
| **Polling** | | | |
297-
| `POLL_INTERVAL_MS` | No | `300000` | Internal poll cadence (ms) — separate from the 1-min Vercel cron |
298-
| **Vercel** | | | |
299-
| `VERCEL_TOKEN` | No* || Vercel API token (local dev only) |
300-
| `VERCEL_TEAM_ID` | No* || Vercel team ID (local dev only) |
301-
| `VERCEL_PROJECT_ID` | No* || Vercel project ID (local dev only) |
302-
| `WORKFLOW_POSTGRES_URL` | No* || Local Postgres for Vercel Workflow durable state (dev only) |
303-
| **Arthur (optional)** | | | |
304-
| `GENAI_ENGINE_API_KEY` | No || Arthur AI Engine API key |
305-
| `GENAI_ENGINE_TRACE_ENDPOINT` | No || Arthur trace endpoint URL |
306-
| `GENAI_ENGINE_PROMPT_TASK_ID` | No || Hosted prompt task ID (set after `pnpm setup:arthur-prompts`) |
307-
| **Redis** | | | |
308-
| `AI_WORKFLOW_KV_REST_API_URL` | Yes || Upstash Redis REST URL (auto-injected by Marketplace integration) |
309-
| `AI_WORKFLOW_KV_REST_API_TOKEN` | Yes || Upstash Redis REST token (auto-injected) |
310-
| **Security** | | | |
311-
| `CRON_SECRET` | No || Cron endpoint auth token (Vercel sets this automatically when defined) |
312-
313-
† Required only for the matching `VCS_KIND`. `env.ts` cross-validates at startup.
314-
‡ Required only for the matching `AGENT_KIND` (the OAuth token alternative also satisfies this).
315-
\* On Vercel, OIDC authenticates the sandbox automatically. These are only needed for local development if `vercel env pull` doesn't cover your setup.
316-
317-
## Deploying to Vercel
318-
319-
### 1. Push to GitHub
320-
321-
ai workflow deploys automatically when connected to Vercel via Git integration.
322-
323-
### 2. Import project
324-
325-
In the [Vercel Dashboard](https://vercel.com/new), import your repository. Vercel auto-detects Nitropack and configures the build.
326-
327-
### 3. Set environment variables
328-
329-
Add all required environment variables in your Vercel project settings under **Settings → Environment Variables**. You can also use the CLI:
330-
331-
```bash
332-
vercel env add JIRA_BASE_URL
333-
vercel env add JIRA_API_TOKEN
334-
# ... repeat for each variable
335-
```
336-
337-
### 4. Cron job
338-
339-
The cron schedule is configured in `vercel.json` and activates automatically on deploy:
340-
341-
```json
342-
{
343-
"crons": [
344-
{
345-
"path": "/cron/poll",
346-
"schedule": "* * * * *"
347-
}
348-
]
349-
}
350-
```
351-
352-
This hits `/cron/poll` every minute. Vercel injects the `CRON_SECRET` header automatically.
353-
354-
### 5. CI/CD
355-
356-
Two GitHub Actions workflows are included:
71+
## Setup
35772

358-
- **CI** (`ci.yml`) — Runs on pull requests targeting `main`/`dev` and on `merge_group` events. Runs typecheck and unit tests; gates the merge queue on `e2e-orchestration → e2e-capacity → e2e-agent`.
359-
- **E2E** (`e2e.yml`) — Manual `workflow_dispatch` with tier selection (`orchestration`, `capacity`, `agent`, `all`) and an `agent` choice (`claude` | `codex`):
360-
- **orchestration** — dispatch / cron / webhook flows (60 min timeout)
361-
- **capacity** — concurrency, claim/release, reconciler (30 min timeout, runs after orchestration)
362-
- **agent** — full ticket → PR run against real Jira + GitHub (120 min timeout, runs after capacity)
73+
For installation, environment variables, and deployment instructions, see [SETUP.md](./SETUP.md).
36374

36475
## Workflow Deep-dive
36576

@@ -389,7 +100,7 @@ There is a single durable workflow — `agentWorkflow` in [`src/workflows/agent.
389100

390101
If either phase returns `clarification_needed`, the workflow posts numbered questions as a Jira comment, moves the ticket to Backlog, and emits a `needs_clarification` Slack event. If a phase fails or times out, the ticket is moved to Backlog with a `failed` event.
391102

392-
> A third "Review" phase exists as commented-out scaffolding in `agent.ts`. It's intentionally disabled today.
103+
> A third "Review" phase is implemented in `agent.ts` but gated behind `ENABLE_REVIEW_PHASE` (default `false`). When enabled, it runs after Phase 2 — the agent self-reviews its diff and fixes issues before push (15 min poll cap, `REVIEW_SCHEMA` for structured output).
393104
394105
### Sandbox Lifecycle
395106

0 commit comments

Comments
 (0)