Skip to content

Commit 8a45955

Browse files
fix: rename project from Relay to Patchwork
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 179afa6 commit 8a45955

20 files changed

Lines changed: 120 additions & 73 deletions

CLAUDE.md

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -44,16 +44,16 @@ When making any change, update docs **before committing**. Map changes to affect
4444
|-------------|-----------------|---------------------|
4545
| New/removed CLI command | `## CLI Commands` ||
4646
| New/changed config field | `### 2. Configure workspaces` table ||
47-
| New/removed source adapter | File structure, test coverage, `## Extending Relay` | Modules table |
47+
| New/removed source adapter | File structure, test coverage, `## Extending Patchwork` | Modules table |
4848
| New/removed module or util | `## File Structure` | Modules table |
4949
| Issue status flow change | `### Issue Status Flow` | `### Issue Status Flow` |
50-
| New notification channel | `## Extending Relay` | Modules table |
50+
| New notification channel | `## Extending Patchwork` | Modules table |
5151
| Test count change | `### Test Coverage` ||
5252
| Critical impl detail || `### Critical Implementation Details` |
5353

5454
If a change doesn't fit the table, ask: "Would a new developer need to know this to use or extend the project?" → README. "Would Claude need this to implement correctly?" → CLAUDE.md.
5555

56-
## Relay Architecture
56+
## Patchwork Architecture
5757

5858
### Project Purpose
5959
Autonomous SWE agent that automates developer work. Pulls tasks from project management tools (Asana, Linear, Jira) and error trackers (Sentry), triages them with Claude Code, implements solutions in isolated git worktrees, and provides an interactive React web dashboard for approval. Telegram notifications are optional. Bug fixing via Sentry is one feature — the core value is automating any development task from any source.
@@ -66,7 +66,7 @@ Projects are grouped into **workspaces** (one per client/org). Each workspace op
6666

6767
| Module | Purpose |
6868
|--------|---------|
69-
| `src/cli.ts` | CLI entrypoint — `start`, `stop`, `doctor`, `update`, `version`, `help`. Flags: `--config`, `--log-level`. Version read from `package.json` at runtime. `doctor` checks Bun/claude/gh/config/repo paths. `update` checks npm registry and self-updates via `bun install -g` |
69+
| `src/cli.ts` | CLI entrypoint — `patchwork start`, `patchwork stop`, `patchwork doctor`, `patchwork update`, `patchwork version`, `patchwork help`. Flags: `--config`, `--log-level`. Version read from `package.json` at runtime. `doctor` checks Bun/claude/gh/config/repo paths. `update` checks npm registry and self-updates via `bun install -g` |
7070
| `src/constants.ts` | Shared constants: `FAILURE_HINTS`, `CallbackAction`, `CallbackData` — used by telegram, dashboard, and daemon |
7171
| `src/dashboard.ts` | `DashboardServer` — Hono + `Bun.serve()` at `localhost:7842`, serves React dashboard from `dist/`, WebSocket `/ws` for live updates, SPA fallback |
7272
| `src/api/router.ts` | Hono app combining all API routes |
@@ -118,9 +118,9 @@ Queue pauses when an issue reaches `pending_confirmation` (waiting for "Start")
118118

119119
2. **Claude stream-json output**: Both `runClaudeText` and `runClaudeJson` use `--output-format stream-json` with `--verbose` (required when combined with `-p`/`--print`). Stdout is streamed line-by-line; optional `onEvent` callback fires `tool_use`/`text`/`result` events in real-time. `parseStreamJson()` parses collected lines to extract session ID, result text, token counts (`message_start.message.usage.input_tokens`, `message_delta.usage.output_tokens`), and `cost_usd` from the `result` event. Token/cost stats are shown in Telegram messages as `⏱ 45s · 🪙 1.2K in / 456 out · 💰 $0.023`.
120120

121-
3. **Worktree paths**: `{repoParent}/.relay-worktrees/fix-{source}-{sourceId}` — sibling dir to the repo, not inside it.
121+
3. **Worktree paths**: `{repoParent}/.patchwork-worktrees/fix-{source}-{sourceId}` — sibling dir to the repo, not inside it.
122122

123-
4. **Branch naming**: `relay/fix-{source}-{sourceId}`
123+
4. **Branch naming**: `patchwork/fix-{source}-{sourceId}`
124124

125125
5. **Auto-commit strategy**: `fix.ts` auto-commits tests first (separate commit), then code changes. Falls back to single commit if no test files changed.
126126

@@ -152,7 +152,7 @@ Queue pauses when an issue reaches `pending_confirmation` (waiting for "Start")
152152

153153
19. **Failure reason codes**: Every failure stores a machine-readable `failure_reason` in the DB. Codes: `triage:timeout`, `triage:claude_failed`, `fix:timeout`, `fix:no_changes`, `fix:tests_failed`, `fix:commit_failed`, `fix:claude_failed`, `worktree:create_failed`, `accept:push_failed`, `accept:pr_failed`, `pipeline:unexpected`. Shown in dashboard failure cards with human-readable hints from `FAILURE_HINTS`.
154154

155-
20. **Issue logs**: Triage writes raw Claude NDJSON to `/tmp/relay-{id}-triage.ndjson`; fix writes to `/tmp/relay-{id}-fix.ndjson`.
155+
20. **Issue logs**: Triage writes raw Claude NDJSON to `/tmp/patchwork-{id}-triage.ndjson`; fix writes to `/tmp/patchwork-{id}-fix.ndjson`.
156156

157157
21. **Streaming progress**: `createStreamReporter` in daemon.ts tracks `tool_use` + `result` events from the Claude stream. Broadcasts `{ type: "stream_progress", issueId, stage, tool, elapsed, toolCallCount, costUsd }` to web dashboard via WebSocket. Also updates Telegram if available (throttled to 3s via `editMessage`).
158158

@@ -168,14 +168,13 @@ Auth tokens are stored in SQLite (in `source_configs.config` JSON and `telegram_
168168

169169
### Data Directory
170170

171-
All runtime data lives in `~/.relay/`:
171+
All runtime data lives in `~/.patchwork/`:
172172
- `config.json` — legacy config (auto-imported into SQLite on first run)
173173
- `sqlite.db` / `sqlite.db-wal` / `sqlite.db-shm` — database
174-
- `relay.pid` — daemon PID file
174+
- `patchwork.pid` — daemon PID file
175175

176176
### Files That Should Never Be Committed
177177

178-
- `.relay-worktrees/` — temporary worktrees
179-
- `relay.stdout.log` / `relay.stderr.log` — service logs
180-
- `dist/` — built dashboard output (generated by `bun run build`)
178+
- `.patchwork-worktrees/` — temporary worktrees
179+
- `patchwork.stdout.log` / `patchwork.stderr.log` — service logs
181180
- `dist/` — built dashboard output (generated by `bun run build`)

README.md

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
# Relay
1+
# Patchwork
22

33
**Turn your backlog into pull requests — automatically.**
44

5-
![Relay Dashboard](screenshot.png)
5+
![Patchwork Dashboard](screenshot.png)
66

7-
Relay connects to your existing project management tools, picks up tasks, and uses Claude Code to implement them in isolated git worktrees. You review the diff, click Accept, and a PR appears. That's it.
7+
Patchwork connects to your existing project management tools, picks up tasks, and uses Claude Code to implement them in isolated git worktrees. You review the diff, click Accept, and a PR appears. That's it.
88

9-
No API keys to manage. No per-token billing. No workflow files to write. Relay runs locally on your machine using your Claude Code subscription (Pro, Max, or Team) and plugs directly into the tools you already use.
9+
No API keys to manage. No per-token billing. No workflow files to write. Patchwork runs locally on your machine using your Claude Code subscription (Pro, Max, or Team) and plugs directly into the tools you already use.
1010

1111
---
1212

@@ -15,18 +15,18 @@ No API keys to manage. No per-token billing. No workflow files to write. Relay r
1515
**Prerequisites:** [Bun](https://bun.sh) · [Claude Code](https://docs.anthropic.com/en/docs/claude-code) · [GitHub CLI](https://cli.github.com) (`gh auth login`)
1616

1717
```sh
18-
bunx @adriandmitroca/relay
18+
bunx patchwork-agent
1919
```
2020

21-
Your browser opens at `localhost:7842/setup`. The setup wizard walks you through connecting your first integration (Asana, Linear, Jira, or Sentry) and pointing Relay at a repo. Done.
21+
Your browser opens at `localhost:7842/setup`. The setup wizard walks you through connecting your first integration (Asana, Linear, Jira, or Sentry) and pointing Patchwork at a repo. Done.
2222

23-
After setup, Relay polls your board, triages tasks with Claude, and waits for your go-ahead before touching any code.
23+
After setup, Patchwork polls your board, triages tasks with Claude, and waits for your go-ahead before touching any code.
2424

2525
### The full loop
2626

2727
```
2828
Your backlog (Asana / Linear / Jira / Sentry)
29-
Relay picks up new tasks
29+
Patchwork picks up new tasks
3030
→ Claude triages: is this actionable?
3131
→ You confirm: "Start this one"
3232
→ Claude implements in an isolated worktree
@@ -39,24 +39,24 @@ Your backlog (Asana / Linear / Jira / Sentry)
3939
### Install globally
4040

4141
```sh
42-
bun install -g @adriandmitroca/relay
42+
bun install -g patchwork-agent
4343
# or
44-
npm install -g @adriandmitroca/relay
44+
npm install -g patchwork-agent
4545
```
4646

4747
### CLI
4848

4949
```
50-
relay start Start the daemon and open the dashboard
51-
relay stop Stop the daemon
52-
relay update Update to the latest version
53-
relay doctor Check your setup for problems
54-
relay version Show version
50+
patchwork start Start the daemon and open the dashboard
51+
patchwork stop Stop the daemon
52+
patchwork update Update to the latest version
53+
patchwork doctor Check your setup for problems
54+
patchwork version Show version
5555
```
5656

5757
---
5858

59-
## Why Relay?
59+
## Why Patchwork?
6060

6161
- **Works with your Claude Code plan** — uses the `claude` CLI you already have. No separate API keys, no surprise bills
6262
- **Connects to what you use** — Asana, Linear, Jira, and Sentry out of the box
@@ -68,8 +68,8 @@ relay version Show version
6868

6969
### Integrations
7070

71-
| Source | What Relay pulls |
72-
|--------|-----------------|
71+
| Source | What Patchwork pulls |
72+
|--------|---------------------|
7373
| **Asana** | Tasks from projects, with severity from tags/custom fields |
7474
| **Linear** | Issues with team/project/status/assignee/label/priority filters |
7575
| **Jira** | Issues via JQL — simple filter mode or raw JQL |

dashboard/src/components/Layout.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ function Sidebar() {
3838
</svg>
3939
</div>
4040
<span className="text-[15px] font-extrabold tracking-tight text-text-primary">
41-
Relay
41+
Patchwork
4242
</span>
4343
</div>
4444

dashboard/src/demo/data.ts

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,8 @@ index 1234567..abcdef0 100644
7171
+ expect(res.status).toHaveBeenCalledWith(401);
7272
+ });
7373
});`,
74-
worktreePath: "/projects/.relay-worktrees/fix-sentry-PROJ-1234",
75-
branch: "relay/fix-sentry-PROJ-1234",
74+
worktreePath: "/projects/.patchwork-worktrees/fix-sentry-PROJ-1234",
75+
branch: "patchwork/fix-sentry-PROJ-1234",
7676
prUrl: null,
7777
sessionId: "sess_abc123",
7878
failureReason: null,
@@ -145,8 +145,8 @@ index 1234567..abcdef0 100644
145145
fixSummary: null,
146146
diffSummary: null,
147147
diffPatch: null,
148-
worktreePath: "/projects/.relay-worktrees/fix-sentry-PROJ-1289",
149-
branch: "relay/fix-sentry-PROJ-1289",
148+
worktreePath: "/projects/.patchwork-worktrees/fix-sentry-PROJ-1289",
149+
branch: "patchwork/fix-sentry-PROJ-1289",
150150
prUrl: null,
151151
sessionId: "sess_ghi789",
152152
failureReason: null,
@@ -293,8 +293,8 @@ index 1234567..abcdef0 100644
293293
fixSummary: null,
294294
diffSummary: null,
295295
diffPatch: null,
296-
worktreePath: "/projects/.relay-worktrees/fix-linear-ENG-871",
297-
branch: "relay/fix-linear-ENG-871",
296+
worktreePath: "/projects/.patchwork-worktrees/fix-linear-ENG-871",
297+
branch: "patchwork/fix-linear-ENG-871",
298298
prUrl: null,
299299
sessionId: "sess_mno345",
300300
failureReason: "fix:tests_failed",
@@ -380,7 +380,7 @@ index 7a3c2d1..b4f8e09 100644
380380
return { avgDuration, sessionCount };
381381
}`,
382382
worktreePath: null,
383-
branch: "relay/fix-sentry-PROJ-1198",
383+
branch: "patchwork/fix-sentry-PROJ-1198",
384384
prUrl: "https://github.com/acme/api/pull/847",
385385
sessionId: "sess_stu901",
386386
failureReason: null,
@@ -431,7 +431,7 @@ index 2b3c4d5..6e7f8a9 100644
431431
);
432432
}`,
433433
worktreePath: null,
434-
branch: "relay/fix-asana-1205432198765",
434+
branch: "patchwork/fix-asana-1205432198765",
435435
prUrl: "https://github.com/acme/frontend/pull/312",
436436
sessionId: "sess_vwx234",
437437
failureReason: null,
@@ -505,7 +505,7 @@ index 2b3c4d5..6e7f8a9 100644
505505
diffSummary: "4 files changed, 127 insertions(+), 12 deletions(-)",
506506
diffPatch: null,
507507
worktreePath: null,
508-
branch: "relay/fix-linear-ENG-834",
508+
branch: "patchwork/fix-linear-ENG-834",
509509
prUrl: null,
510510
sessionId: "sess_bcd890",
511511
failureReason: null,

dashboard/src/pages/SetupPage.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ export function SetupPage() {
114114
<path d="M13 2L3 14h9l-1 8 10-12h-9l1-8z" fill="currentColor" className="text-accent" />
115115
</svg>
116116
</div>
117-
<span className="text-lg font-extrabold tracking-tight">Relay</span>
117+
<span className="text-lg font-extrabold tracking-tight">Patchwork</span>
118118
</div>
119119
<p className="text-text-muted text-sm">Setup wizard</p>
120120
</div>
@@ -228,7 +228,7 @@ export function SetupPage() {
228228
disabled={submitting}
229229
className="px-4 py-2 text-[13px] font-semibold bg-emerald-500 text-white rounded-lg cursor-pointer hover:bg-emerald-600 shadow-[0_1px_12px_rgba(52,211,153,0.2)] disabled:opacity-50 disabled:cursor-not-allowed transition-all duration-150"
230230
>
231-
{submitting ? "Setting up..." : "Start Relay"}
231+
{submitting ? "Setting up..." : "Start Patchwork"}
232232
</button>
233233
)}
234234
</div>

dashboard/src/pages/WorkspacesPage.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ export function WorkspacesPage() {
4444
</svg>
4545
</div>
4646
<span className="text-[15px] font-extrabold tracking-tight text-text-primary">
47-
Relay
47+
Patchwork
4848
</span>
4949
</Link>
5050
<div className="w-px h-5 bg-border" />

src/api/config.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -467,7 +467,7 @@ export function createConfigRoutes(getConfigDB: () => ConfigDB, onConfigChange:
467467
const resp = await fetch(`https://api.telegram.org/bot${botToken}/sendMessage`, {
468468
method: "POST",
469469
headers: { "Content-Type": "application/json" },
470-
body: JSON.stringify({ chat_id: chatId, text: "🔌 Relay connection test — success!" }),
470+
body: JSON.stringify({ chat_id: chatId, text: "🔌 Patchwork connection test — success!" }),
471471
});
472472
const data = await resp.json() as { ok: boolean; description?: string };
473473
if (data.ok) return c.json({ ok: true });

src/cli.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ function getFlag(name: string): string | undefined {
2323
}
2424

2525
function dataDir(): string {
26-
return join(process.env.HOME ?? "~", ".relay");
26+
return join(process.env.HOME ?? "~", ".patchwork");
2727
}
2828

2929
function getCommand(): string {
@@ -73,7 +73,7 @@ async function checkForUpdates() {
7373
async function cmdStart() {
7474
const dir = dataDir();
7575
await Bun.$`mkdir -p ${dir}`.quiet();
76-
const pidFile = join(dir, "relay.pid");
76+
const pidFile = join(dir, "patchwork.pid");
7777
const dbPath = join(dir, "sqlite.db");
7878
const logLevel = getFlag("log-level");
7979
if (logLevel) setLogLevel(logLevel as "debug" | "info" | "warn" | "error");
@@ -112,7 +112,7 @@ async function cmdStart() {
112112
}
113113

114114
async function cmdStop() {
115-
const pidFile = join(dataDir(), "relay.pid");
115+
const pidFile = join(dataDir(), "patchwork.pid");
116116
const pid = Bun.file(pidFile);
117117
if (!(await pid.exists())) {
118118
console.log(`${YELLOW}No running daemon found.${RESET}`);
@@ -204,8 +204,8 @@ async function cmdDoctor() {
204204
// 4. Data directory
205205
const dir = dataDir();
206206
const dirStat = await Bun.$`test -d ${dir}`.quiet().nothrow();
207-
if (dirStat.exitCode === 0) ok(`~/.relay/ exists`);
208-
else warn("~/.relay/ not found", "Will be created automatically on first start");
207+
if (dirStat.exitCode === 0) ok(`~/.patchwork/ exists`);
208+
else warn("~/.patchwork/ not found", "Will be created automatically on first start");
209209

210210
// 5. Database + config
211211
const dbPath = join(dir, "sqlite.db");
@@ -231,7 +231,7 @@ async function cmdDoctor() {
231231
warn("database exists but no config", "Open http://localhost:7842/setup to configure");
232232
}
233233
} catch {
234-
fail("database exists but could not be read", "Try deleting ~/.relay/sqlite.db and reconfiguring");
234+
fail("database exists but could not be read", "Try deleting ~/.patchwork/sqlite.db and reconfiguring");
235235
}
236236
} else {
237237
warn("no database yet", "Run 'patchwork start' to create it");

src/constants.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ export const FAILURE_HINTS: Record<string, string> = {
99
"worktree:create_failed": "Failed to create a git worktree. Check repoPath and disk space.",
1010
"accept:push_failed": "Branch push failed. Check remote permissions and run gh auth status.",
1111
"accept:pr_failed": "Branch pushed but PR creation failed. Run gh auth status.",
12-
"pipeline:unexpected": "An unexpected error occurred. Check relay logs for details.",
12+
"pipeline:unexpected": "An unexpected error occurred. Check patchwork logs for details.",
1313
};
1414

1515
export type CallbackAction = "accept" | "discard" | "skip" | "fix" | "retry";

src/daemon.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -554,7 +554,7 @@ export class Daemon {
554554

555555
const onEvent = this.createStreamReporter(ws, row.id, triageMsgId, "triage");
556556

557-
const triageLogPath = `/tmp/relay-${row.id}-triage.ndjson`;
557+
const triageLogPath = `/tmp/patchwork-${row.id}-triage.ndjson`;
558558
const triage = await triageIssue(context, project.repoPath, this.config.triageTimeout, projectContext, "sonnet", onEvent, triageLogPath);
559559

560560
const triageStats = {
@@ -645,7 +645,7 @@ export class Daemon {
645645

646646
const onEvent = this.createStreamReporter(ws, row.id, fixMsgId, "fix");
647647

648-
const fixLogPath = `/tmp/relay-${row.id}-fix.ndjson`;
648+
const fixLogPath = `/tmp/patchwork-${row.id}-fix.ndjson`;
649649
const fixResult = await fixIssue({
650650
issueContext: context,
651651
triagePlan: triage.plan ?? "Investigate the issue, find the root cause, and implement a fix.",
@@ -1024,14 +1024,14 @@ function buildPRBody(row: IssueRow): string {
10241024

10251025
// Signature
10261026
lines.push("---");
1027-
lines.push("🤖 Generated with [Relay](https://github.com/adriandmitroca/relay) using [Claude Code](https://claude.com/claude-code)");
1027+
lines.push("🤖 Generated with [Patchwork](https://github.com/adriandmitroca/relay) using [Claude Code](https://claude.com/claude-code)");
10281028

10291029
return lines.join("\n");
10301030
}
10311031

10321032
// When run directly
10331033
if (import.meta.main) {
1034-
const dbPath = process.argv[2] || join(process.env.HOME ?? "~", ".relay", "sqlite.db");
1034+
const dbPath = process.argv[2] || join(process.env.HOME ?? "~", ".patchwork", "sqlite.db");
10351035
const daemon = new Daemon(dbPath);
10361036
await daemon.start();
10371037
}

0 commit comments

Comments
 (0)