---
title: "starbridge-mod"
url: "https://claudemods.dev/ko/builds/starbridge-mod-b2ab70"
source: "https://github.com/T0mSIlver/starbridge/tree/main/mod"
source_type: "github"
repo: "https://github.com/T0mSIlver/starbridge/tree/main/mod"
author: "T0mSIlver"
author_handle: "T0mSIlver"
stars: 1
category: "워크플로 및 CI"
categories: ["workflow"]
tags: ["claude-code", "hooks", "human-in-the-loop", "mod", "starbridge", "workflow"]
permission_level: 3
scan_complete: true
install: "claude plugin marketplace add T0mSIlver/starbridge\nclaude plugin install starbridge-mod"
added: "2026-10-09T05:19:32.754Z"
updated: "2026-10-09T08:24:02Z"
locale: "ko"
content_locale: "ko"
---

# starbridge-mod

소유자의 Starbridge 답변을 요청한 Claude Code 세션에 제출합니다. Claude Code 모드: 모드를 로드할 수 없는 빌드는 이를 건너뛰고, starbridge 플러그인은 계속 작동합니다.

## Description

# Claude Code용 Starbridge 모드

소유자가 결정에 답변하면, 이 모드는 답변을 요청한 Claude Code
세션에 `starbridge wait`가 출력하는 줄로 제출합니다:

```
Answer to d_Xk3… (Merge #12 now?): Merge
```

터미널, 데스크톱 앱의 코드 탭, 원격 제어에서 작동합니다.

## 설치

`starbridge` 플러그인 옆에 있는 Starbridge 마켓플레이스에서
설치합니다(`plugin/README.md`):

```bash
claude plugin install starbridge-mod@starbridge --scope user
```

모드를 거부하는 Claude Code 빌드 또는 조직은 이 플러그인을 건너뛰고
스킬을 유지합니다. 그러면 답변은 세션이 `starbridge answers`를 실행할 때까지 기다립니다.
단일 세션에서 체크아웃을 시험하려면: `claude --plugin-dir mod`.

## 작동 방식

이 모드는 키를 보유하지 않습니다. 각 대화형 세션은 두 경로 중 하나를 선택하고,
에이전트가 시작하거나 중지할 때 전환합니다.

### 에이전트를 통해

머신의 에이전트(`starbridge agent`, PROTOCOL.md, “로컬 에이전트 API”)가
해당 unix 소켓에서 응답할 때, 각 세션은 `$.http.fetch`로 그것과 통신합니다:

- 세션 id당 한 번 `POST /v1/sessions/<id>/hello`를 세션의
  작업 디렉터리와 함께 호출합니다.
- `GET /v1/sessions/<id>/events?wait=25`를 연속해서 호출하며, 모드에서의 호출에
  대한 30초 제한 내에 있습니다. 에이전트는 세션이 질문한 결정에 대한 답변만 해당 세션에 전달합니다.
- 모드는 각 이벤트의 줄을 제출한 다음 `POST /v1/sessions/<id>/ack`로
  확인합니다. 에이전트는 확인되지 않은 이벤트를 다시 전달합니다.
  알지 못하는 이벤트 유형은 건너뜁니다.
- 세션이 끝날 때 `POST /v1/sessions/<id>/bye`를 호출합니다.

소켓은 `$STARBRIDGE_AGENT_SOCKET`이고, 그렇지 않으면 기본 구성 디렉터리에 대해
`$XDG_RUNTIME_DIR/starbridge/agent.sock`,
그렇지 않으면 구성 디렉터리의 `agent.sock`이며, CLI가 계산하는 방식과 같습니다. Windows에서는
(`OS=Windows_NT`), 구성 디렉터리의 포트 파일 `agent.port`이며, 이는
루프백 포트와 모든 호출이 전달하는 토큰을 지정합니다(PROTOCOL.md). 426(에이전트가
다른 API 개정을 사용함) 또는 연결할 수 없는 호출은 세션을 CLI 경로로 보냅니다.

### CLI를 통해

에이전트가 없거나 `STARBRIDGE_NO_AGENT=1`인 경우, mod는 CLI를 실행하고
30초마다 에이전트를 확인합니다.

- 모든 대화형 세션은 mod를 실행하지만, 머신당 하나만 폴링합니다:
  `~/.config/starbridge/mod-poller.json`의 임대를 보유한 세션입니다. 이 세션은
  `starbridge answers --session <id> --wait 25`를 연속으로 실행하며, 이는 mod에서 오는 호출의 30초 제한을
  넘지 않습니다.
- 다른 세션은 `state.json`을 감시합니다. 그것이 변경되면 `starbridge
  answers --session <id>`를 실행하며, 이는 로컬 상태만 읽습니다.
- `answers`는 해당 세션이 질문한 결정에 대한 답변 중 어떤
  `wait`도 출력하지 않은 것만 반환합니다. mod는 각 줄을 제출한 다음
  `starbridge answers --session <id> --ack <ack>`로 그것을 확인합니다. CLI는
  확인되지 않은 줄을 다시 넘겨줍니다.
- 폴링하지 않는 세션도 `state.json`이 변경되지 않았을 때 30초마다
  `answers`를 실행합니다. 변경이 보이지 않았을 경우를 대비해서입니다.
- 세션이 끝나면 임대를 포기하고 다른 세션이
  폴링을 시작합니다.

두 경로 모두에서 `/clear` 또는 `/resume` 후 mod는 새 세션
id를 사용합니다. `/clear` 중에 도착한 줄은 확인되지 않은 채 이전
세션을 기다립니다. 오류 후 mod는 2초를 기다리고, 이후 오류가 발생할 때마다 두 배로 늘려 최대 1분까지 기다리며,
호출이 성공할 때까지 상태 줄에 오류를 표시합니다.

## Pi

`pi/starbridge.ts`는 Pi 확장으로서 동일한 답변 루프입니다. 이것은
저장소의 Pi 패키지에 `starbridge` 스킬과 함께 제공됩니다. `starbridge setup`은 그것을
실행하는 CLI의 릴리스 태그, 즉 `v`와 `starbridge --version`이 출력하는 것에 설치합니다:

```bash
pi install git:github.com/T0mSIlver/starbridge@v<version>
```

대화형 또는 RPC Pi 세션에서는 각 답변을 사용자 메시지로 제출하며,
이는 Pi가 유휴 상태일 때 턴을 시작하고 바쁠 때는 현재 턴 이후에 실행됩니다. 또한 플러그인의 규칙(`plugin/hooks/rule.md`)을 Pi의 시스템
프롬프트에 추가합니다. `pi -p`는 루프를 받지 않으므로, 그곳의 `starbridge ask`는 에이전트에게
`starbridge wait`하라고 알려줍니다.

[pi-permission-system](https://github.com/gotgenes/pi-packages/tree/main/packages/pi-permission-system)이
설치되어 있으면, `pi/permissions.ts`는 그 승인자 체인에 `starbridge` 링크를 등록하고,
소유자는 `config.json`의 `"authorizerChain": ["starbridge"]`로
그것을 켭니다(`starbridge config permissions on`이 그것을 추가하도록 제안합니다). 규칙이 `ask`라고 하면, 링크는 Claude Code의 훅과 마찬가지로 `starbridge hook permission
--agent pi`를 실행하고, 장치의 허용(이번
호출만: 체인은 링크가 세션에 대해 허용하도록 결코 두지 않습니다) 또는 거부와
그 메시지를 반환합니다. 그동안 Pi는 “여기서 답변”을 표시하며, 이는 장치로부터 프롬프트를 되찾고
pi-permission-system 자체의 대화 상자를 엽니다. 링크는 `starbridge config permissions`가 꺼져 있거나,
머신이 페어링되지 않았거나 서버가 응답하지 않을 때, 그리고 570초 후에
즉시 그 대화 상자에 양보합니다.

## opencode

`opencode/starbridge.ts`는 opencode 플러그인으로서의 동일한 응답 루프입니다.
`starbridge setup`은 그것을, `hooks/`에서 가져오는 파일들과
규칙과 함께 `~/.config/opencode/starbridge/`로 복사하고,
`~/.config/opencode/plugins/starbridge.ts`가 그것을 가리키게 합니다.

opencode는 명령에 세션 id를 주지 않으므로, 플러그인의 `shell.env` 훅이
그것들에 `STARBRIDGE_OPENCODE_SESSION`과 그 세션의 제목을 설정하고, 그
세션의 루프를 시작합니다. 각 응답은 `promptAsync`로 들어갑니다. 유휴 세션은
턴을 시작하고, 바쁜 세션은 다음 단계에서 그것을 받습니다. `opencode run`은
루프를 받지 않으므로, `starbridge ask`는 그곳의 에이전트에게 `starbridge wait`를
하라고 알립니다. 규칙은 `experimental.chat.system.transform`을 통해
시스템 프롬프트에 들어갑니다.

각 `permission.asked` 이벤트는 `starbridge hook permission --agent
opencode`를 실행하며, `starbridge config permissions`가 꺼져 있는 동안에는 즉시
종료합니다. 그동안 opencode의 대화 상자는 계속 떠 있습니다. 기기들의 응답은
opencode의 응답 라우트를 통해 전송되며, 키보드에서의 응답은 CLI를 중지시켜
기기들에서 프롬프트를 확정합니다.
기기들은 Allow가 승인하는 내용을 봅니다. `bash`의 경우 명령, `edit`의 경우
경로와 diff이며, 이것은 그 edit, write, apply_patch 도구가 묻는 것으로, 이동이
파일을 어디로 가져가는지와 패치가 어떤 파일을 삭제하는지를 포함합니다. 그 셸에서
온 `external_directory` 질의의 경우 디렉터리와 명령입니다. 다른 권한들은 그
패턴과 메타데이터를 보여 줍니다. MCP 도구 호출은 도구의 이름만 보여 주는데,
opencode의 권한 이벤트는 그 인자를 전혀 담지 않기 때문입니다.
8,000자를 넘으면 CLI가 가장 긴 문자열을 잘라 내고 그 사실을 알립니다.

각 `question.asked` 이벤트(opencode의 `question` 도구 호출)는
`starbridge hook question --agent opencode`를 실행하며, 이것은 각 질문을 그
레이블을 선택지로 하여 게시하고 모두 모이면 답변을 출력합니다. 플러그인은
그것들을 `POST /question/{id}/reply`로 보냅니다. 키보드에서의 응답 또는 Esc
(`question.replied` 또는 `question.rejected`)는 CLI를 중지시켜 기기들에서
질문을 확정합니다.

## 개발

```bash
pnpm --filter @starbridge/mod test
```

`e2e/run.ts`는 tmux에서 실제 Claude Code 세션을 통해 각 케이스를 구동합니다: 유휴, 턴 중간, `/clear` 및 `/resume`, 핫 리로드, 서버 중단, 그리고 동시에 두 세션. 이는 랜덤 포트(`--local`)의 서버 앱에 대해 실행되거나, 테스트 장치(`e2e/device.ts`)와 이 머신의 CLI 설정이 있는 실제 서버에 대해 실행됩니다. `claude`, `tmux` 및 `starbridge`가 `PATH`에 있어야 하며, 각 케이스마다 한 줄의 타이밍을 출력합니다. `--agent`를 사용하면 전체 실행 동안 `starbridge agent`를 실행하고, 마지막 줄에서 모든 세션이 이를 통해 응답했는지 확인합니다.

테스트는 CLI, 실제 에이전트 및 실제 서버에 대해 두 경로를 모두 실행하며, `@starbridge/server/test-support`가 랜덤 포트에서 시작합니다. `hooks/agent.ts`는 에이전트 경로, `hooks/poller.ts`는 CLI 경로, `hooks/switch.ts`는 하나를 선택하고, `hooks/register.ts`는 이들을 엔진에 연결합니다. CI는 `register.ts`를 제외한 모든 것을 타입 검사합니다. `register.ts`를 타입 검사하려면, 엔진이 해당 타입을 `.claude-plugin/types/`에 기록하도록 mod를 한 번 로드한 다음, `tsc -p tsconfig.engine.json`을 실행하세요.

## Install

```
claude plugin marketplace add T0mSIlver/starbridge
claude plugin install starbridge-mod
```

## Original README

# Starbridge mod for Claude Code

When the owner answers a decision, this mod submits the answer into the Claude
Code session that asked, as the line `starbridge wait` prints:

```
Answer to d_Xk3… (Merge #12 now?): Merge
```

It works in the terminal, the desktop app's Code tab and Remote Control.

## Install

Install it from the Starbridge marketplace, beside the `starbridge` plugin
(`plugin/README.md`):

```bash
claude plugin install starbridge-mod@starbridge --scope user
```

A Claude Code build or organization that refuses mods skips this plugin and
keeps the skill; answers then wait until a session runs `starbridge answers`.
To try a checkout in one session: `claude --plugin-dir mod`.

## How it works

The mod holds no keys. Each interactive session picks one of two paths, and
switches when the agent starts or stops.

### Through the agent

When the machine's agent (`starbridge agent`, PROTOCOL.md, "Local agent API")
answers on its unix socket, each session talks to it with `$.http.fetch`:

- `POST /v1/sessions/<id>/hello` once per session id, with the session's
  working directory.
- `GET /v1/sessions/<id>/events?wait=25` back to back, under the 30 s limit on
  calls from a mod. The agent hands the session only the answers to the
  decisions it asked.
- The mod submits each event's line, then confirms it with
  `POST /v1/sessions/<id>/ack`; the agent hands an unconfirmed event over
  again. It skips event types it does not know.
- `POST /v1/sessions/<id>/bye` when the session ends.

The socket is `$STARBRIDGE_AGENT_SOCKET`, else
`$XDG_RUNTIME_DIR/starbridge/agent.sock` for the default config directory,
else `agent.sock` in the config directory, as the CLI works it out; on Windows
(`OS=Windows_NT`), the port file `agent.port` in the config directory, which
names the loopback port and the token every call carries (PROTOCOL.md). A 426 (the
agent speaks another API revision) or a call that cannot connect sends the
session to the CLI path.

### Through the CLI

With no agent, or with `STARBRIDGE_NO_AGENT=1`, the mod runs the CLI and checks
for the agent every 30 s.

- Every interactive session runs the mod, but only one per machine polls: the
  session holding the lease in `~/.config/starbridge/mod-poller.json`. It runs
  `starbridge answers --session <id> --wait 25` back to back, which stays
  under the 30 s limit on calls from a mod.
- The other sessions watch `state.json`. When it changes, they run `starbridge
  answers --session <id>`, which reads local state only.
- `answers` returns only answers to decisions that session asked and that no
  `wait` has printed. The mod submits each line, then confirms it with
  `starbridge answers --session <id> --ack <ack>`; the CLI hands an
  unconfirmed line over again.
- A session that does not poll also runs `answers` every 30 s when
  `state.json` has not changed, in case a change went unseen.
- When a session ends, it gives up the lease and another session starts
  polling.

On both paths, after a `/clear` or a `/resume` the mod uses the new session
id; a line that arrives during a `/clear` waits, unconfirmed, for the old
session. After an error the mod waits 2 s, then twice as long after each
further error, up to a minute, and shows the error in the status line until a
call succeeds.

## Pi

`pi/starbridge.ts` is the same answer loop as a Pi extension. It ships in the
repository's Pi package with the `starbridge` skill. `starbridge setup` installs it at the
release tag of the CLI it runs, `v` and what `starbridge --version` prints:

```bash
pi install git:github.com/T0mSIlver/starbridge@v<version>
```

In an interactive or RPC Pi session it submits each answer as a user message,
which starts a turn when Pi is idle and runs after the current one when it is
busy. It also adds the plugin's rule (`plugin/hooks/rule.md`) to Pi's system
prompt. `pi -p` gets no loop, so `starbridge ask` tells the agent there to
`starbridge wait`.

With [pi-permission-system](https://github.com/gotgenes/pi-packages/tree/main/packages/pi-permission-system)
installed, `pi/permissions.ts` registers a `starbridge` link in its authorizer
chain, which the owner turns on with `"authorizerChain": ["starbridge"]` in its
`config.json` (`starbridge config permissions on` offers to add it). When a rule says `ask`, the link runs `starbridge hook permission
--agent pi`, as Claude Code's hook does, and returns the devices' allow (this
call only: the chain never lets a link allow for the session) or deny with
their message. Meanwhile Pi shows "Answer here", which takes the prompt back
from the devices and opens pi-permission-system's own dialog. The link defers
to that dialog at once while `starbridge config permissions` is off, the
machine is not paired or the server does not answer, and after 570 s.

## opencode

`opencode/starbridge.ts` is the same answer loop as an opencode plugin.
`starbridge setup` copies it, with the files it imports from `hooks/` and the
rule, into `~/.config/opencode/starbridge/`, and points
`~/.config/opencode/plugins/starbridge.ts` at it.

opencode gives commands no session id, so the plugin's `shell.env` hook sets
`STARBRIDGE_OPENCODE_SESSION` and the session's title for them, and starts that
session's loop. Each answer goes in with `promptAsync`: an idle session starts
a turn, a busy one takes it at its next step. `opencode run` gets no loop, so
`starbridge ask` tells the agent there to `starbridge wait`. The rule goes into
the system prompt through `experimental.chat.system.transform`.

Each `permission.asked` event runs `starbridge hook permission --agent
opencode`, which exits at once while `starbridge config permissions` is off.
opencode's dialog stays up meanwhile: the devices' answer is sent through
opencode's reply route, and an answer at the keyboard stops the CLI, which
settles the prompt on the devices.
The devices see what an Allow approves: the command for `bash`; the paths and
the diff for `edit`, which its edit, write and apply_patch tools ask, with
where a move takes a file and which files a patch deletes; the directories
and the command for an `external_directory` ask from its shell. Other
permissions show their patterns and metadata. An MCP tool call shows only the
tool's name, since opencode's permission event carries none of its arguments.
Past 8,000 characters the CLI cuts the longest string and says so.

Each `question.asked` event (a call of opencode's `question` tool) runs
`starbridge hook question --agent opencode`, which posts each question with its
labels as options and prints the answers once all are in. The plugin sends them
through `POST /question/{id}/reply`. An answer or Esc at the keyboard
(`question.replied` or `question.rejected`) stops the CLI, which settles the
questions on the devices.

## Develop

```bash
pnpm --filter @starbridge/mod test
```

`e2e/run.ts` drives real Claude Code sessions in tmux through each case:
idle, mid-turn, `/clear` and `/resume`, a hot reload, a server outage, and two
sessions at once. It runs against the server app on a
random port (`--local`), or against a real server with a test device
(`e2e/device.ts`) and this machine's CLI config. It needs `claude`, `tmux` and
`starbridge` on `PATH`, and prints one row of timings per case. With
`--agent` it runs `starbridge agent` for the whole run, and a last row checks
that every session answered through it.

The tests run both paths against the CLI, a real agent and the real server,
which `@starbridge/server/test-support` starts on a random port.
`hooks/agent.ts` is the agent path, `hooks/poller.ts` the CLI path,
`hooks/switch.ts` picks one, and `hooks/register.ts` connects them to the
engine. CI type-checks all but `register.ts`. To type-check `register.ts`,
load the mod once so the engine writes its types to `.claude-plugin/types/`,
then run `tsc -p tsconfig.engine.json`.
