local llm with claude code and opencode

어떤 로컬 llmfit(https://github.com/AlexsJones/llmfit) 을 사용하면 내 하드웨어에 맞는 최고의 모델이 무엇인지알 수 있다.

ollama 로컬 llm 구동하자.
lmstudio-community/Qwen3-Coder-30B-A3B-Instruct-MLX-4bit 은 ollama 에서는 qwen3-coder 모델로 다운받을 수 있다.

ollama pull qwen3-coder:latest
ollama ls
ollama run qwen3-coder
ollama ps

참고로 ollama는 OpenAI 호환 API (/v1/chat/completions 등)를 제공한다.    
opencode.json > provider > ollama 에 다음과 같이 설정한다.
{
  "provider": {
    "ollama": {
      "npm": "@ai-sdk/openai-compatible",
      "name": "Ollama (local)",
      "options": {
        "baseURL": "http://localhost:11434/v1"
      },
      "models": {
        "qwen3-coder:latest": {
          "name": "Qwen3 Coder 30.5B"
        },
        "llama3.2:latest": {
          "name": "Llama 3.2 3B"
        }
      }
    }
  }
}

opencode 에서 로컬 llm 사용 결과

claude code 에서는 openAI api 호환이 되지 않아 중간에 litellm(proxy) 서버를 둬야 한다.
참고로 litellm[proxy] 로 기본 + 프록시 실행에 필요한 추가 패키지들(backoff, uvicorn, fastapi 등)을 함께 설치해야 한다.
uv pip install 'litellm[proxy]' --system

litellm 프록시 서버 구동
litellm --model qwen-coder3 --api_base http://localhost:11434/v1 --port 8001

이제 다음 환경변수를 .local_llm_env_for_claude_code 등의 파일로 저장하자.

# 로컬 llm URL
export ANTHROPIC_BASE_URL="http://localhost:8001"

# 더미값으로 설정하면 된다.(sk:SecretKey)
export ANTHROPIC_API_KEY="sk-dummy-key"

# Claude Code의 외부 통신을 최소화하기 위해 다음 환경변수도 설정하자.
# 텔레메트리(사용 통계 수집)를 비활성화
export CLAUDE_CODE_ENABLE_TELEMETRY=0

# 핵심 API 호출 외의 불필요한 네트워크 트래픽 차단
export CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1

# API 요청 시 Claude Code가 보내는 attribution 헤더(어떤 클라이언트에서 요청했는지 식별하는 정보)를 비활성화
export CLAUDE_CODE_ATTRIBUTION_HEADER=0

이제 다음과 같이 실행한다.
source .local_llm_env_for_claude_code; claude --model qwen3-coder

실행 후 api key 사용을 선택

왼쪽: 기본 opus 모델을 사용한 경우
오른쪽: 로컬 llm(qwen3-coder) 사용한 경우

사용해보니 ollama 자체앱을 사용하면 빠르게 답변을 주는데 모델에 상관 없이 opencode/claudecode 에서 연결해 사용하면 단순 질문도 gpu 100% 이 되면서 느려지는 경우도 생겨서 좀 불편했다.

claude code with zellij

최근 버전의 claude code 에서는 AGENT_TEAMS(팀모드)를 제공한다.
~/.claude/settings.json 에 아래 환경변수를 활성화 하면된다.
  "env": {
    "CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS": "1"
  },

이게 기존 병렬 에이전트와 다른 점은 서브 에이전트들끼리 통신할 수 있고, tmux가 설치되어 있다면 각 에이전트들의 작업을 볼수 있어 좋다.

            팀모드 (TeamCreate + Agent)        병렬 에이전트 (Agent only)
실행 방식     별도 프로세스 (out-of-process)        인프로세스 (in-process)
tmux pane   각 teammate마다 별도 pane 생성        생성 안됨
UI 표시      각 pane에서 실시간 진행 확인 가능        메인 화면에서 결과만 반환
통신         SendMessage로 메시지 교환            결과를 직접 반환
작업 관리     TaskCreate/TaskUpdate로 추적        없음 (단발성)
teammate 간 가능 (서로 메시지 송수신)               불가 (독립 실행)
수명         idle 대기, 추가 작업 할당 가능          작업 완료 시 즉시 종료

그런데 multiplexer로는 tmux 만 공식 지원해서 zellij 에서 쓸수 없었는데
https://github.com/stanislc/zellij-claude-teams 에서 zellij 용 shim 을 제공한다.
zellij 환경의 claude code 에서 tmux 명령이 호출되면 shim이 이를 가로채 zellij pane으로 라우팅한다.

zellij-claude-teams 설치 후 zsh 환경 설정까지를 아래 스크립트로 만들어 뒀다.

zellij 세션에서 claude code 를 실행하고 팀모드로 작업 요청을 하면 다음과 같이 zellij pane 으로 에이전트들의 작업중인 내용을 볼수 있다. 작업이 끝다면 서비스에이전트 pane 들은 자동으로 닫힌다.

git filter repo

잘못된 커밋 내용(name, email 등)을 수정할때 git rebase 를 하나씩 pick 해서 수정했다.

그런데 git filter repo(https://github.com/newren/git-filter-repo)툴을 사용하면 편하다.

# 설치
uv pip install git-filter-repo --system

# 도움말
git filter-repo -h

# aaa.bbb 이름으로 커밋된 모든곳에 ysoftman 이름과 ysoftman@gmail.com 멜주소로 수정하기
git filter-repo --commit-callback '
if commit.author_name == b"aaa.bbb":
   commit.author_name = b"ysoftman"
   commit.author_email = b"ysoftman@gmail.com"
   commit.committer_name = b"ysoftman"
   commit.committer_email = b"ysoftman@gmail.com"
' --force

# git filter-repo가 안전을 위해 origin remote를 자동으로 제거한다.
# remote를 다시 추가하고 force push
git remote add origin https://github.com/ysoftman/ysoftman
git push --force origin main

# origin/main 을 로컬 main 브랜치로 다시 연결(트랙킹)
git branch --set-upstream-to=origin/main main

참고로 force push 후에도 gitHub에 이전 커밋 객체가 남아있어 이전 sha 해시로 직접 접근하면 여전히 보인다. 수주가 지나면 github 에서 자동으로 정리된다고 한다.

# 예시) 커밋 메시지에 Co-Authored-By: Claude 내용이 있는 라인 제거
git filter-repo --message-callback '
  import re
  return re.sub(rb"\n*Co-Authored-By:.*Claude.*\n*", b"\n", message).rstrip() + b"\n"
  ' --force