Skip to content

Commit 255d60b

Browse files
shivamstaqclaude
andcommitted
Replace TypeScript sidecar with direct Claude CLI adapter
Major simplification: remove the entire TypeScript sidecar and per-adapter packages. The Claude Code adapter now invokes `claude -p --output-format json` directly, parsing the structured JSON result. Deleted: - sidecar/claude/ (package.json, tsconfig.json, src/index.ts) - internal/adapter/claude/ (Go wrapper for sidecar) - internal/adapter/codex/ (per-adapter package) - internal/adapter/opencode/ (per-adapter package) Created: - internal/adapter/claude_cli.go — exec-and-parse adapter using `claude` CLI - Runs: claude -p --output-format json --permission-mode bypassPermissions - Parses: stop_reason, usage, cost, session_id from JSON output - CWD set to workspace directory - Inherits full parent environment (ANTHROPIC_API_KEY, GITHUB_TOKEN, etc.) - Uses locally-authenticated claude CLI credentials (~/.claude) Simplified: - ClaudeConfig: removed AdapterMode, SDKLanguage, SidecarCommand fields - Factory: claude_code creates ClaudeCLI, opencode/codex use generic subprocess - Doctor: checks for `claude` binary instead of tsx/node - Dockerfile: debian:bookworm-slim runtime (no Node.js dependency) This eliminates the Node.js/tsx runtime dependency entirely. 127 tests passing, all CI jobs expected green. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 6b7ff49 commit 255d60b

19 files changed

Lines changed: 286 additions & 1113 deletions

File tree

Dockerfile

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,22 @@
11
# Stage 1: Build Go binary
2-
FROM golang:1.26 AS go-builder
2+
FROM golang:1.26 AS builder
33
WORKDIR /build
44
COPY go.mod go.sum ./
55
RUN go mod download
66
COPY . .
77
RUN CGO_ENABLED=0 GOOS=linux go build -o /symphony ./cmd/symphony
88

9-
# Stage 2: Runtime with Node.js for Claude Code sidecar
10-
FROM node:22-slim
11-
RUN npm install -g tsx
9+
# Stage 2: Minimal runtime with git
10+
FROM debian:bookworm-slim
11+
RUN apt-get update && \
12+
apt-get install -y --no-install-recommends git ca-certificates && \
13+
rm -rf /var/lib/apt/lists/*
1214

1315
WORKDIR /app
14-
COPY --from=go-builder /symphony /usr/local/bin/symphony
15-
COPY sidecar/ ./sidecar/
16-
RUN cd sidecar/claude && npm install --production 2>/dev/null || true
16+
COPY --from=builder /symphony /usr/local/bin/symphony
1717

18-
# Install git for workspace operations
19-
RUN apt-get update && apt-get install -y --no-install-recommends git && rm -rf /var/lib/apt/lists/*
18+
# Claude CLI must be installed separately in the runtime environment
19+
# or mounted from the host. Symphony uses `claude -p --output-format json`.
2020

2121
EXPOSE 9097
2222
ENTRYPOINT ["symphony"]

cmd/symphony/main.go

Lines changed: 13 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -173,24 +173,6 @@ func main() {
173173
},
174174
})
175175

176-
// Resolve sidecar script path to absolute (relative to where symphony was invoked)
177-
symphonyDir, _ := os.Getwd()
178-
var sidecarScript string
179-
if cfg.Agent.Kind == "claude_code" {
180-
sidecarScript = cfg.Claude.SidecarCommand
181-
if sidecarScript == "" {
182-
sidecarScript = filepath.Join(symphonyDir, "sidecar", "claude", "src", "index.ts")
183-
} else if !filepath.IsAbs(sidecarScript) {
184-
sidecarScript = filepath.Join(symphonyDir, sidecarScript)
185-
}
186-
// Validate sidecar script exists
187-
if _, err := os.Stat(sidecarScript); err != nil {
188-
logger.Error("sidecar script not found", "path", sidecarScript, "error", err)
189-
os.Exit(1)
190-
}
191-
logger.Info("sidecar script resolved", "path", sidecarScript)
192-
}
193-
194176
// Create worker runner
195177
runner := orchestrator.NewRunner(orchestrator.WorkerDeps{
196178
WorkspaceManager: wsMgr,
@@ -201,8 +183,14 @@ func main() {
201183
}
202184
switch cfg.Agent.Kind {
203185
case "claude_code":
204-
acfg.Command = "tsx"
205-
acfg.Args = []string{sidecarScript}
186+
acfg.Command = "claude" // uses locally-authenticated claude CLI
187+
acfg.Model = cfg.Claude.Model
188+
acfg.AllowedTools = cfg.Claude.AllowedTools
189+
permMode := "bypassPermissions"
190+
if p, ok := cfg.Claude.PermissionProfile.(string); ok && p != "" {
191+
permMode = p
192+
}
193+
acfg.PermissionMode = permMode
206194
case "opencode":
207195
acfg.Command = "opencode"
208196
acfg.Args = []string{"acp"}
@@ -395,27 +383,13 @@ func runDoctor(cfg *config.ServiceConfig, wsRoot, stateDir string) {
395383
// Check agent runtime
396384
switch cfg.Agent.Kind {
397385
case "claude_code":
398-
if err := checkBinaryExists("node"); err != nil {
399-
fmt.Printf("FAIL: node not found on PATH: %v\n", err)
400-
os.Exit(1)
401-
}
402-
fmt.Println("PASS: node found on PATH")
403-
if err := checkBinaryExists("tsx"); err != nil {
404-
fmt.Printf("FAIL: tsx not found on PATH: %v\n", err)
405-
os.Exit(1)
406-
}
407-
fmt.Println("PASS: tsx found on PATH")
408-
// Check sidecar script
409-
sidecar := cfg.Claude.SidecarCommand
410-
if sidecar == "" {
411-
cwd, _ := os.Getwd()
412-
sidecar = filepath.Join(cwd, "sidecar", "claude", "src", "index.ts")
413-
}
414-
if _, err := os.Stat(sidecar); err != nil {
415-
fmt.Printf("FAIL: sidecar script not found: %s\n", sidecar)
386+
if err := checkBinaryExists("claude"); err != nil {
387+
fmt.Printf("FAIL: claude CLI not found on PATH: %v\n", err)
388+
fmt.Println(" Install: https://docs.anthropic.com/en/docs/claude-code")
389+
fmt.Println(" Then run: claude login")
416390
os.Exit(1)
417391
}
418-
fmt.Printf("PASS: sidecar script found: %s\n", sidecar)
392+
fmt.Println("PASS: claude CLI found on PATH")
419393
case "opencode":
420394
if err := checkBinaryExists("opencode"); err != nil {
421395
fmt.Printf("FAIL: opencode not found on PATH: %v\n", err)

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ go 1.26.1
55
require (
66
github.com/fsnotify/fsnotify v1.9.0
77
github.com/go-chi/chi/v5 v5.2.5
8+
github.com/google/uuid v1.6.0
89
github.com/joho/godotenv v1.5.1
910
go.etcd.io/bbolt v1.4.3
1011
gopkg.in/yaml.v3 v3.0.1

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S
44
github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
55
github.com/go-chi/chi/v5 v5.2.5 h1:Eg4myHZBjyvJmAFjFvWgrqDTXFyOzjj7YIm3L3mu6Ug=
66
github.com/go-chi/chi/v5 v5.2.5/go.mod h1:X7Gx4mteadT3eDOMTsXzmI4/rwUpOwBHLpAfupzFJP0=
7+
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
8+
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
79
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
810
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
911
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=

internal/adapter/claude/claude.go

Lines changed: 0 additions & 219 deletions
This file was deleted.

0 commit comments

Comments
 (0)