Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ POLL_INTERVAL_MS=300000
# VERCEL_TEAM_ID=
# VERCEL_PROJECT_ID=

# Cron auth
CRON_SECRET=
# Deploy hook auth
DEPLOY_HOOK_SECRET=

# Workflow (local dev only)
WORKFLOW_POSTGRES_URL=postgresql://localhost:5432/ai_workflow
18 changes: 18 additions & 0 deletions .github/workflows/post-deploy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
name: Start poll workflow after deploy

on:
deployment_status:

jobs:
start-poll:
if: github.event.deployment_status.state == 'success'
runs-on: ubuntu-latest
steps:
- name: Trigger poll workflow
run: |
URL="${{ github.event.deployment_status.target_url }}/poll/start"
echo "Calling: $URL"
curl -sf -X GET \
-H "Authorization: Bearer ${{ secrets.DEPLOY_HOOK_SECRET }}" \
-H "x-vercel-protection-bypass: ${{ secrets.VERCEL_AUTOMATION_BYPASS }}" \
"$URL"
37 changes: 22 additions & 15 deletions docs/SPEC.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,10 +69,13 @@ Important boundary:

### 3.1 Main Components

1. **Poller** (Vercel Cron)
- Runs on a configurable interval (`POLL_INTERVAL_MS`, default 5 min).
1. **Poller** (Vercel Workflow with sleep)
- Runs as a long-lived Vercel Workflow that sleeps between poll cycles (`POLL_INTERVAL_MS`, default 15s).
- Queries the issue tracker for tickets in the AI column.
- For each discovered ticket, starts a Vercel Workflow run if one is not already active.
- Started via `GET /poll/start` route which cancels any existing poll run and starts a fresh one.
A GitHub Action triggers this route on every successful deployment — no Vercel Cron needed.
Protected by `DEPLOY_HOOK_SECRET` bearer token.

2. **Issue Tracker Adapter**
- Reads ticket data (description, acceptance criteria, comments, labels).
Expand Down Expand Up @@ -202,7 +205,7 @@ All runtime config lives in environment variables, validated at startup.
Key config groups:

- **Sandbox:** concurrency limit (`MAX_CONCURRENT_AGENTS`), job timeout (`JOB_TIMEOUT_MS`).
- **Polling:** interval (`POLL_INTERVAL_MS`).
- **Polling:** interval between cycles (`POLL_INTERVAL_MS`, default 15s).
- **Issue Tracker:** adapter kind (`ISSUE_TRACKER_KIND`), project key (`JIRA_PROJECT_KEY`),
credentials.
- **Messaging:** Chat SDK credentials (`CHAT_SDK_API_KEY`), channel config.
Expand Down Expand Up @@ -255,8 +258,8 @@ transition.

### 8.1 Polling

The poller (Vercel Cron) runs every `POLL_INTERVAL_MS` and queries the issue tracker for tickets
in the AI column. For each discovered ticket:
The poller runs as a long-lived Vercel Workflow that sleeps `POLL_INTERVAL_MS` (default 15s)
between cycles and queries the issue tracker for tickets in the AI column. For each discovered ticket:

1. Check if a Vercel Workflow run is already active for this ticket — if so, skip.
2. Determine run type based on ticket state:
Expand Down Expand Up @@ -616,17 +619,21 @@ Notifications are best-effort — never block the workflow.
### 16.1 Poller

```
on_poll():
tickets = issueTrackerAdapter.searchTickets("column = AI")
poll_workflow():
while true:
ticketKeys = issueTrackerAdapter.searchTickets("column = AI")

for ticket in tickets:
if hasActiveWorkflowRun(ticket.id): continue
if atConcurrencyLimit(): break
for key in ticketKeys:
if hasActiveWorkflowRun(key): continue
if atConcurrencyLimit(): break

workflow.start("ticket_workflow", {
ticketId: ticket.id,
identifier: ticket.identifier
})
workflow.start("ticket_workflow", {
ticketId: key,
identifier: key
})

reconcileRegistry(ticketKeys)
sleep(POLL_INTERVAL_MS)
```

### 16.2 Ticket Workflow (Vercel Workflow)
Expand Down Expand Up @@ -765,7 +772,7 @@ run_fixing_feedback(ticketId, existingPR):

### 18.1 Required for MVP

- [ ] Poller — Vercel Cron that queries issue tracker and dispatches workflow runs.
- [ ] Poller — GitHub Action deploy hook that starts the poll workflow on each deployment.
- [ ] Issue Tracker adapter (Jira first).
- [ ] VCS adapter (GitHub).
- [ ] Messaging adapter (Chat SDK — chat-sdk.dev — for Slack/Teams).
Expand Down
8 changes: 4 additions & 4 deletions env.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,16 +36,16 @@ export const env = createEnv({
JOB_TIMEOUT_MS: z.coerce.number().int().positive().default(1_800_000),

// Polling
POLL_INTERVAL_MS: z.coerce.number().int().positive().default(300_000),
POLL_INTERVAL_MS: z.coerce.number().int().positive().default(15_000),

// Deploy hook auth
DEPLOY_HOOK_SECRET: z.string().min(1).optional(),

// Vercel (optional — auto via OIDC on Vercel)
VERCEL_TOKEN: z.string().min(1).optional(),
VERCEL_TEAM_ID: z.string().min(1).optional(),
VERCEL_PROJECT_ID: z.string().min(1).optional(),

// Cron
CRON_SECRET: z.string().min(1).optional(),

// Redis (run registry)
AI_WORKFLOW_KV_REST_API_URL: z.string().url(),
AI_WORKFLOW_KV_REST_API_TOKEN: z.string().min(1),
Expand Down
1 change: 1 addition & 0 deletions nitro.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ export default defineNitroConfig({
modules: ["workflow/nitro"],
compatibilityDate: "2025-01-01",
srcDir: "src",
ignore: ["**/*.test.ts"],
});
132 changes: 0 additions & 132 deletions src/routes/cron/poll.get.ts

This file was deleted.

Loading
Loading