Skip to content

Commit 2407909

Browse files
abrichrclaude
andcommitted
feat: initial monorepo scaffolding
Turbo + pnpm monorepo with three packages: - apps/worker: Fly.io scale-to-zero dev loop worker (Claude Agent SDK) - apps/bot: Telegram approval bot (always-on) - packages/shared: TypeScript types, constants, job/test schemas Includes: - Supabase migration (job_queue, job_events, test_results) - Multi-stage Dockerfile (Node 22 + Python 3.12/uv) - fly.toml with scale-to-zero config - Pluggable test runner + package manager types Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
0 parents  commit 2407909

19 files changed

Lines changed: 686 additions & 0 deletions

.gitignore

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# Dependencies
2+
node_modules/
3+
4+
# Build output
5+
dist/
6+
*.tsbuildinfo
7+
8+
# Environment
9+
.env
10+
.env.local
11+
.env.*.local
12+
13+
# IDE
14+
.vscode/
15+
.idea/
16+
*.swp
17+
*.swo
18+
19+
# OS
20+
.DS_Store
21+
Thumbs.db
22+
23+
# Turbo
24+
.turbo/
25+
26+
# Logs
27+
*.log
28+
npm-debug.log*
29+
pnpm-debug.log*
30+
31+
# Supabase
32+
supabase/.temp/

README.md

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
# Wright
2+
3+
Wright is a generalized dev automation platform that takes task descriptions, uses the Claude Agent SDK to generate code, runs tests iteratively (the Ralph Loop pattern), and creates pull requests -- with a Telegram bot for human-in-the-loop approval.
4+
5+
## Architecture
6+
7+
```
8+
Telegram
9+
|
10+
+------v------+
11+
| Crier | (notifications)
12+
+------+------+
13+
|
14+
GitHub Issue/PR +-----v-----+ +-----------+
15+
────────────────> | Herald |────>| Wright |
16+
+-----------+ | Worker |
17+
(webhooks) +-----+-----+
18+
|
19+
+-----v-----+
20+
| Claude SDK |
21+
| Dev Loop |
22+
+-----+-----+
23+
|
24+
+--------v--------+
25+
| clone -> edit |
26+
| -> test -> fix | (Ralph Loop)
27+
| -> repeat |
28+
+--------+--------+
29+
|
30+
+-----v-----+
31+
| GitHub PR |
32+
+-----------+
33+
```
34+
35+
### Ecosystem
36+
37+
Wright is part of the OpenAdapt automation ecosystem:
38+
39+
- **Consilium** -- project management and task decomposition
40+
- **Herald** -- GitHub webhook listener, routes events to wright
41+
- **Crier** -- multi-channel notification service (Telegram, etc.)
42+
- **Wright** -- dev automation worker (this repo)
43+
44+
### How it works
45+
46+
1. A task arrives (via Herald webhook, Telegram command, or direct API call)
47+
2. Wright claims the job from the Supabase queue
48+
3. The worker clones the target repo, creates a branch
49+
4. Claude Agent SDK iterates: edit code, run tests, fix failures (Ralph Loop)
50+
5. On success (or budget exhaustion), wright creates a PR
51+
6. Crier notifies the human via Telegram for review/approval
52+
53+
## Monorepo Structure
54+
55+
```
56+
wright/
57+
apps/
58+
worker/ # Fly.io: generalized dev loop (scale-to-zero)
59+
bot/ # Fly.io: always-on Telegram bot
60+
packages/
61+
shared/ # Shared types + constants
62+
supabase/
63+
migrations/ # Database schema
64+
```
65+
66+
## Quick Start
67+
68+
```bash
69+
# Prerequisites: Node.js 22+, pnpm 9+
70+
pnpm install
71+
pnpm build
72+
73+
# Set environment variables (see .env.example -- TODO)
74+
# Run the worker locally
75+
pnpm --filter @wright/worker dev
76+
77+
# Run the Telegram bot locally
78+
pnpm --filter @wright/bot dev
79+
```
80+
81+
## Plan
82+
83+
See the full design document: [wright plan](https://github.com/OpenAdaptAI/wright/blob/main/PLAN.md)

apps/bot/package.json

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
{
2+
"name": "@wright/bot",
3+
"version": "0.1.0",
4+
"private": true,
5+
"type": "module",
6+
"main": "dist/index.js",
7+
"scripts": {
8+
"build": "tsc",
9+
"dev": "tsx watch src/index.ts",
10+
"start": "node dist/index.js",
11+
"lint": "tsc --noEmit",
12+
"clean": "rm -rf dist .turbo"
13+
},
14+
"dependencies": {
15+
"@wright/shared": "workspace:*"
16+
},
17+
"devDependencies": {
18+
"tsx": "^4.19.0",
19+
"typescript": "^5.7.0"
20+
}
21+
}

apps/bot/src/index.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/**
2+
* Wright Telegram Bot -- human-in-the-loop interface.
3+
*
4+
* TODO: Implement the following:
5+
*
6+
* 1. Connect to Telegram Bot API
7+
* 2. Handle commands:
8+
* - /task <repo> <description> -- submit a new dev task
9+
* - /status [job_id] -- check job status
10+
* - /approve <job_id> -- approve a PR for merge
11+
* - /reject <job_id> -- reject and close a PR
12+
* - /cancel <job_id> -- cancel a running job
13+
* - /budget -- show current spend
14+
* 3. Receive notifications from Crier about job state changes
15+
* 4. Forward inline approval/rejection buttons on PR notifications
16+
* 5. Stream worker progress updates to the chat
17+
*/
18+
19+
console.log('Wright Telegram bot starting...')
20+
console.log('TODO: implement Telegram bot commands and webhook handlers')

apps/bot/tsconfig.json

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"extends": "../../tsconfig.base.json",
3+
"compilerOptions": {
4+
"outDir": "dist",
5+
"rootDir": "src"
6+
},
7+
"include": ["src"],
8+
"references": [
9+
{ "path": "../../packages/shared" }
10+
]
11+
}

apps/worker/Dockerfile

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
# Stage 1: Build the TypeScript worker
2+
FROM node:22-slim AS builder
3+
4+
RUN corepack enable && corepack prepare pnpm@9.15.0 --activate
5+
6+
WORKDIR /app
7+
8+
# Copy workspace config
9+
COPY package.json pnpm-workspace.yaml pnpm-lock.yaml* turbo.json tsconfig.base.json ./
10+
11+
# Copy package manifests for dependency resolution
12+
COPY packages/shared/package.json packages/shared/
13+
COPY apps/worker/package.json apps/worker/
14+
15+
# Install dependencies
16+
RUN pnpm install --frozen-lockfile || pnpm install
17+
18+
# Copy source
19+
COPY packages/shared/ packages/shared/
20+
COPY apps/worker/ apps/worker/
21+
22+
# Build shared package first, then worker
23+
RUN pnpm --filter @wright/shared build && pnpm --filter @wright/worker build
24+
25+
# Stage 2: Runtime with Node.js + Python (for running target repo tests)
26+
FROM node:22-slim AS runtime
27+
28+
RUN corepack enable && corepack prepare pnpm@9.15.0 --activate
29+
30+
# Install Python 3.12 and uv for running target repo tests (pytest, etc.)
31+
RUN apt-get update && apt-get install -y --no-install-recommends \
32+
python3 \
33+
python3-pip \
34+
python3-venv \
35+
git \
36+
curl \
37+
ca-certificates \
38+
&& rm -rf /var/lib/apt/lists/*
39+
40+
# Install uv (fast Python package manager)
41+
RUN curl -LsSf https://astral.sh/uv/install.sh | sh
42+
ENV PATH="/root/.local/bin:$PATH"
43+
44+
# Install additional language runtimes/tools as needed
45+
# Go, Rust, etc. can be added here for broader test runner support
46+
47+
WORKDIR /app
48+
49+
# Copy workspace config
50+
COPY package.json pnpm-workspace.yaml pnpm-lock.yaml* ./
51+
52+
# Copy built artifacts and production dependencies
53+
COPY --from=builder /app/packages/shared/package.json packages/shared/
54+
COPY --from=builder /app/packages/shared/dist/ packages/shared/dist/
55+
COPY --from=builder /app/apps/worker/package.json apps/worker/
56+
COPY --from=builder /app/apps/worker/dist/ apps/worker/dist/
57+
58+
# Install production dependencies only
59+
RUN pnpm install --prod --frozen-lockfile || pnpm install --prod
60+
61+
# Working directory for cloned repos
62+
RUN mkdir -p /workspace
63+
ENV WORKSPACE_DIR="/workspace"
64+
65+
WORKDIR /app/apps/worker
66+
67+
CMD ["node", "dist/index.js"]

apps/worker/fly.toml

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# Fly.io configuration for the wright worker
2+
# Scale-to-zero: worker starts when a job is queued, stops when idle
3+
4+
app = "wright-worker"
5+
primary_region = "ord"
6+
7+
[build]
8+
dockerfile = "Dockerfile"
9+
10+
[env]
11+
NODE_ENV = "production"
12+
WORKSPACE_DIR = "/workspace"
13+
14+
[[vm]]
15+
memory = "8gb"
16+
cpu_kind = "shared"
17+
cpus = 2
18+
19+
[http_service]
20+
internal_port = 8080
21+
force_https = true
22+
auto_stop_machines = "stop"
23+
auto_start_machines = true
24+
min_machines_running = 0
25+
processes = ["app"]
26+
27+
[checks]
28+
[checks.health]
29+
type = "http"
30+
port = 8080
31+
path = "/health"
32+
interval = "30s"
33+
timeout = "5s"

apps/worker/package.json

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
{
2+
"name": "@wright/worker",
3+
"version": "0.1.0",
4+
"private": true,
5+
"type": "module",
6+
"main": "dist/index.js",
7+
"scripts": {
8+
"build": "tsc",
9+
"dev": "tsx watch src/index.ts",
10+
"start": "node dist/index.js",
11+
"lint": "tsc --noEmit",
12+
"clean": "rm -rf dist .turbo"
13+
},
14+
"dependencies": {
15+
"@wright/shared": "workspace:*"
16+
},
17+
"devDependencies": {
18+
"tsx": "^4.19.0",
19+
"typescript": "^5.7.0"
20+
}
21+
}

apps/worker/src/index.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/**
2+
* Wright Worker -- generalized dev automation loop.
3+
*
4+
* TODO: Implement the following:
5+
*
6+
* 1. Poll Supabase job_queue for 'queued' jobs
7+
* 2. Claim a job (atomic update status → 'claimed')
8+
* 3. Clone the target repo, create a feature branch
9+
* 4. Auto-detect test runner and package manager
10+
* 5. Install dependencies
11+
* 6. Ralph Loop:
12+
* a. Invoke Claude Agent SDK with the task description + test failures
13+
* b. Apply code edits
14+
* c. Run tests
15+
* d. If tests pass → create PR, mark job 'succeeded'
16+
* e. If tests fail → feed failures back to Claude, loop
17+
* f. If budget exceeded or max loops → mark job 'failed'
18+
* 7. Emit job_events for observability
19+
* 8. Notify via Crier (Telegram) on completion
20+
*/
21+
22+
import { POLL_INTERVAL_MS } from '@wright/shared/constants'
23+
import type { Job } from '@wright/shared/types'
24+
25+
console.log('Wright worker starting...')
26+
console.log(`Poll interval: ${POLL_INTERVAL_MS}ms`)
27+
console.log('TODO: implement job polling and dev loop')

apps/worker/tsconfig.json

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"extends": "../../tsconfig.base.json",
3+
"compilerOptions": {
4+
"outDir": "dist",
5+
"rootDir": "src"
6+
},
7+
"include": ["src"],
8+
"references": [
9+
{ "path": "../../packages/shared" }
10+
]
11+
}

0 commit comments

Comments
 (0)