Skip to content

커스텀 프로바이더 ​

대시보드의 Providers 탭은 ADHDev가 어떤 머신에서 무엇을 감지하고 제어할 수 있는지 보여주는 곳이지, 새 프로바이더를 처음부터 만드는 곳이 아닙니다. ADHDev가 아직 모르는 CLI, IDE, 에이전트를 지원하도록 추가하려면 작은 JSON 파일("프로바이더 매니페스트")을 작성해서 데몬이 이미 감시하고 있는 폴더에 넣으면 됩니다. 이 페이지는 그 흐름을 처음부터 끝까지 안내합니다.

프로바이더란 무엇인가 ​

ADHDev에는 4가지 프로바이더 카테고리가 있습니다:

  • cli — Claude Code나 Codex CLI처럼 PTY(의사 터미널)로 구동되는 터미널 에이전트. 데몬이 터미널에 입력하고 화면을 다시 읽어 들입니다.
  • acp — Agent Client Protocol로 stdio 위에서 통신하는 에이전트(화면 스크래핑이 아니라 구조화된 메시지).
  • ide — Chrome DevTools Protocol로 검사·제어되는 CDP 기반 코드 에디터 (Cursor, VS Code 포크 등).
  • extension — CDP로 구동되는 IDE 확장 웹뷰(Cline, Roo Code 등).

현실적으로 직접 작성해볼 만한 것은 cli 카테고리입니다. CLI 프로바이더는 JSON 매니페스트와, 화면에서 "생성 중" / "유휴" / "승인 대기"를 어떻게 구분하는지 설명하는 JSON 상태 머신 스펙만으로 구성됩니다 — 코드가 필요하지 않습니다.

ide와 extension 프로바이더는 이야기가 다릅니다: 패널을 열고, 채팅을 읽고, 메시지를 보내는 등의 작업을 하는 실제 CDP 자동화 스크립트(JavaScript)가 필요합니다. 이는 터미널의 화면 상태를 설명하는 것보다 훨씬 큰 작업이며, 이 페이지의 범위를 벗어납니다 — 그래도 시도해보고 싶다면 아래의 프로바이더 SDK 가이드 참고 자료를 확인하세요. acp 프로바이더도 직접 만들 수 있지만(PTY 화면 스크래핑이 필요 없음) CLI 프로바이더보다는 추가하는 경우가 드뭅니다.

이 페이지의 나머지 부분은 CLI 프로바이더에 관한 내용입니다.

파일을 어디에 둘 것인가 ​

데몬은 다음 우선순위 순서로 몇 개의 디렉터리에서 프로바이더를 로드합니다(같은 프로바이더 타입에 대해 뒤에 나오는 것이 앞의 것을 덮어씁니다):

  1. 업스트림 — <configDir>/providers/.upstream/ — 공식적으로 자동 동기화되는 번들입니다. 직접 편집하지 마세요. 덮어써집니다.
  2. 외부 소스 — <configDir>/external/<source-name>/ — 대시보드의 Sources 패널에서 등록하는 서드파티 git 소스.
  3. 사용자 오버라이드 — <configDir>/providers/(.upstream/을 제외한 모든 것) — 여러분이 직접 만들거나 덮어쓰는 매니페스트. 항상 이것이 이깁니다. 일반적인 설치에서 <configDir>은 ~/.adhdev이므로 여기는 ~/.adhdev/providers/입니다.

각 프로바이더는 다음 위치에 있습니다:

<root>/<category>/<type>/
  provider.v1.json      ← 매니페스트 (필수)
  specs/
    <version>.json       ← FSM 상태 머신 스펙 (cli는 필수)

cli/<type>/provider.v1.json을 ~/.adhdev/providers/에 넣는 것만으로 충분합니다 — 다른 어디에도 등록할 필요가 없습니다.

아무것도 나타나지 않으면 providerDir가 이미 설정되어 있는지 확인하세요. 명시적인 providerDir(Sources 패널이나 설정에서 설정 — 아래 "데몬이 다른 폴더를 보게 하기" 참고)는 기본 ~/.adhdev/providers/에 추가되는 것이 아니라 사용자 오버라이드 폴더를 완전히 대체합니다. 데몬 로그에는 이것이 userDirSource: "explicit"로 기록됩니다. 머신에 이미 그런 설정이 있다면, 새 매니페스트는 ~/.adhdev/providers/가 아니라 그 폴더에 넣어야 하며, 핫 리로드도 그 활성 폴더 하나만 감시합니다(아래 "어느 폴더가 활성 상태인지 확인하기" 참고).

"업스트림을 오버라이드한다"의 정확한 의미 ​

데몬이 이미 제공하는 것과 같은 type을 가진 프로바이더를 만들면(예: 수정한 claude-cli), ~/.adhdev/providers/cli/claude-cli/에 있는 여러분의 사본이 업스트림 것 대신 로드됩니다. 데몬은 이를 명시적으로 로그에 남기므로 (⚠ OVERRIDES upstream) 이런 일이 벌어질 때 눈에 보입니다. 업스트림 수정을 기다리지 않고 내장 프로바이더의 필드 하나를 패치하는 방법이기도 합니다 — 프로바이더 디렉터리 전체를 사용자 폴더로 복사해서 그곳에서 편집하면 됩니다.

데몬이 다른 폴더를 보게 하기 ​

기본적으로 데몬은 사용자 오버라이드를 위해 ~/.adhdev/providers/만 감시합니다. 커스텀 프로바이더를 다른 곳(예: 계속 편집 중인 git 체크아웃)에 두고 싶다면, 명시적인 프로바이더 디렉터리를 설정하세요:

  • 대시보드: Machine 페이지 → Providers 탭 → Advanced → Provider source mode(normal 또는 no-upstream)와 Provider directory를 설정한 뒤 Apply & reload. no-upstream은 자동 동기화되는 업스트림 번들을 완전히 비활성화하고 여러분의 디렉터리와 external/에 있는 것만 제공합니다.
  • 설정 파일: 데몬 설정에서 providerDir(과 선택적으로 providerSourceMode)를 설정합니다.

어느 쪽이든, 변경을 적용하면 데몬의 set_provider_source_config 명령이 호출되어 프로바이더 맵을 즉시 다시 로드합니다 — 데몬 재시작이 필요 없습니다.

어느 폴더가 활성 상태인지 확인하기 ​

명시적인 providerDir는 기본 폴더에 추가되는 게 아니라 대체하는 것이므로, 매니페스트가 로드되지 않는 이유를 찾기 전에 데몬이 실제로 어느 폴더를 감시 중인지 먼저 확인하는 것이 좋습니다:

  • 대시보드: Machine 페이지 → Providers 탭 → Advanced에서 현재 Provider directory 값을 보여줍니다(비어 있으면 기본값인 ~/.adhdev/providers/를 의미합니다).
  • 데몬 로그: Hot-reload watcher active: <dir> 줄을 찾으세요 — <dir>이 실제로 감시 중인 폴더입니다. 데몬 로그는 설치 형태(클라우드 데몬, standalone, 프리뷰 인스턴스)와 무관하게 항상 ~/.adhdev/logs/daemon-YYYY-MM-DD.log에 있습니다.

사용자 오버라이드 폴더의 핫 리로드 ​

데몬이 실행되는 동안, 사용자 오버라이드 디렉터리(~/.adhdev/providers/ 또는 providerDir로 설정한 곳) 단 하나만의 .js와 .json 파일 변경을 감시합니다 — 활성 사용자 오버라이드 디렉터리는 항상 하나뿐이며 둘 다 동시에 감시되는 일은 없습니다. 그곳의 매니페스트를 편집하면 약 300ms 내에 반영됩니다 — 재시작도 수동 리로드도 필요 없습니다. 이 감시는 .upstream/이나 external/ 소스 트리는 대상이 아닙니다 — 그곳의 변경사항은 adhdev provider reload(또는 대시보드 새로고침)로 반영해야 합니다.

빠른 시작: adhdev provider init ​

아래 두 파일을 디스크에 가장 빨리 준비하는 방법은 CLI가 생성하게 하는 것입니다:

bash
adhdev provider init my-cli --dir ./my-cli

이 명령은 현재 v1 형식으로 provider.v1.json과 specs/1.0.json을 스캐폴딩합니다 — 바로 다음에 이 페이지가 손으로 직접 만드는 것과 같은 형태이며, 바이너리 이름은 <type>에서 유도되고(끝의 -cli/-acp를 제거, 또는 --binary로 명시적으로 지정), 스펙 안의 자리표시자 정규식은 대상 명령의 실제 화면 출력과 매칭되는 패턴으로 여러분이 직접 교체해야 합니다. adhdev provider init my-acp --category acp --dir ./my-acp는 선언적 ACP 프로바이더에 대해 같은 일을 합니다(스펙 파일 없이 provider.v1.json 하나만 — 위 "프로바이더란 무엇인가" 참고). init은 --category ide와 --category extension은 거부합니다 — 이들은 특정 IDE/웹뷰 전용의 손으로 작성한 CDP 자동화 스크립트가 필요하므로, 실제로 동작하는 결과물을 만들어낼 범용 템플릿이 없기 때문입니다.

바로 이어서 adhdev provider validate ./my-cli를 실행해보세요 — 자리 표시자 정규식에서 실패할 텐데(절대 매칭되지 않으므로), 이것이 의도된 동작입니다: 아직 스텁인 부분과 스키마가 이미 받아들이는 부분을 정확히 알려줍니다.

최소 동작 CLI 프로바이더 ​

CLI 프로바이더는 선언적 유한 상태 머신 엔진("스펙")을 통해 라우팅됩니다. 스펙은 필수입니다 — 예전의 스크립트 기반 CLI 엔진은 제거되었고, 스펙을 찾을 수 없는 CLI 프로바이더는 이제 더 약한 엔진으로 폴백하는 대신 명시적인 오류와 함께 실행에 실패합니다. 따라서 최소 프로바이더는 두 파일로 구성됩니다: 매니페스트와, 유효한 최소 스펙입니다.(이는 위에서 adhdev provider init이 스캐폴딩하는 것과 같은 형태입니다 — 생성된 파일을 편집하거나 직접 손으로 작성한다면, 각 부분이 어떻게 동작하는지는 아래에서 계속 읽어보세요.)

대상 명령 고르기 ​

실제로 테스트할 수 있는 매니페스트를 만들려면, 실제로 존재하고 해가 없으며 이미 설치되어 있는 인터랙티브 명령을 고르세요. python3 -q가 좋은 선택입니다: 사실상 모든 macOS와 Linux 머신에 이미 설치되어 있고, "quiet" 모드로 시작하며(버전 배너를 건너뛰어 매칭할 대상이 줄어듭니다), >>> 프롬프트는 원시 bash 프롬프트(PS1)와 달리 셸 설정에 의존하지 않는 단순하고 안정적인 "유휴" 표시입니다.

provider.v1.json ​

json
{
  "$schema": "https://registry.adhf.dev/schemas/v1/cli/provider.schema.json",
  "type": "python-repl",
  "name": "Python REPL",
  "category": "cli",
  "binary": "python3",
  "spawn": {
    "command": "python3",
    "args": ["-q"],
    "shell": false
  },
  "compatibility": [
    { "ideVersion": ">=0.0.0", "spec": "specs/1.0.json" }
  ]
}

스키마가 실제로 요구하는 필드(type, name, category, binary, spawn)만 있고, 그 위에 compatibility가 있습니다 — 이것이 로더가 아래의 스펙 파일을 찾는 방법입니다.

specs/1.0.json ​

json
{
  "$schema": "adhdev:cli/spec@4",
  "id": "python-repl",
  "name": "Python REPL",
  "binary": "python3",
  "send_message": {
    "submit_key": "\r"
  },
  "states": [
    { "id": "starting", "label": "Starting", "initial": true, "status": "idle" },
    { "id": "idle", "label": "Ready", "status": "idle" },
    { "id": "busy", "label": "Evaluating", "status": "generating" }
  ],
  "transitions": [
    {
      "label": "startup → idle",
      "from": "starting",
      "to": "idle",
      "when": { "matches": ">>>\\s*(?=\\n|$)" }
    },
    {
      "label": "idle → busy",
      "from": "idle",
      "to": "busy",
      "min_hold_ms": 200,
      "when": { "not": { "matches": ">>>\\s*(?=\\n|$)" } }
    },
    {
      "label": "busy → idle",
      "from": "busy",
      "to": "idle",
      "min_hold_ms": 300,
      "when": {
        "all": [
          { "matches": ">>>\\s*(?=\\n|$)" },
          { "stable_ms": 500 }
        ]
      }
    }
  ]
}

이것이 FSM 검증기가 요구하는 실제 최소치입니다: id, binary, send_message.submit_key, 정확히 하나의 initial: true 상태를 가진 비어 있지 않은 states[], 그리고 transitions[] 배열. 실제 프로바이더 스펙에 있는 나머지 모든 것(승인 모달 감지, 섹션 윈도우, 네이티브 채팅 히스토리, 자동 승인 모드 등)은 이 형태 위에 더해지는 것입니다 — 이것이 동작하기 시작하면 더 완전한 예시는 adhdev-providers/cli/*/specs/ 아래의 내장 스펙들을 참고하세요.

왜 $ 대신 (?=\n|$)인가? matches 패턴은 화면 전체 버퍼에 대해 실행되지, 줄 단위로 실행되지 않습니다. 엔진은 기본적으로 m 플래그 없이 패턴을 컴파일하므로, 이스케이프되지 않은 $는 프롬프트 줄의 끝이 아니라 화면 전체의 끝에 고정되어, 프롬프트 아래에 뭔가가 있는 한 조용히 절대 매칭되지 않습니다. 스펙 린터는 바로 이런 이유로 m 없이도 동작하는 몇 가지 줄 경계 관용구를 허용 목록에 올려둡니다(줄 끝은 (?=\n|$), 줄 시작은 (?:^|\n)). 단순한 앵커 대신 이런 관용구를 쓰는 것이 이 패턴이 프롬프트 줄에 실제로 안정적으로 매칭되게 만드는 이유입니다.

두 파일을 ~/.adhdev/providers/cli/python-repl/provider.v1.json과 ~/.adhdev/providers/cli/python-repl/specs/1.0.json에 넣고, 먼저 프로바이더를 활성화한 뒤(adhdev provider enable python-repl 또는 대시보드의 Machine Providers 토글 — 대시보드 자체의 감지 검사는 비활성화된 프로바이더를 거부합니다. 아래 참고) 그 프로바이더로 세션을 실행해보세요. python3가 이미 설치되어 있으므로 시도하기 전에 따로 설치할 것이 없습니다.

위 예제 파일들은 그대로 복사해 쓸 수 있도록, 이 가이드 소스 옆의 custom-provider-example/에도 함께 저장되어 있습니다.

프로바이더 검증하기 ​

  • **adhdev provider validate <path>**는 provider.v1.json(또는 레거시 provider.json)을 데몬이 로드 시점에 사용하는 것과 같은 v1 JSON 스키마로 검사하고, 어떤 티어에 해당하는지 알려줍니다. cli 매니페스트의 경우 데몬이 실행 시점에 하는 것과 같은 방식으로 스펙도 실제로 찾아서 (compatibility[].spec → specs/default.json → spec.json) 데몬과 동일한 FSM 검증기로 검사합니다 — 스키마는 통과하지만 스펙을 찾을 수 없거나 상태 머신이 잘못된 스펙을 가진 매니페스트는, 나중에 실행 시점에 실패하는 대신(formatNoResolvableSpecError) 여기서 바로 무효로 보고됩니다. acp 매니페스트는 스펙 개념이 없어서 이 단계를 건너뜁니다. 위 예제에 대해서는 tier: extended-legacy와 python-repl@unversioned를 출력하는데, 둘 다 정상이고 문제없습니다:
    • **extended-legacy**는 그냥 "나머지 두 티어 어디에도 속하지 않는다"는 뜻입니다: extended는 매니페스트가 overrides 블록(커스텀 JS 훅)을 선언한다는 뜻이고, declarative-only는 tui 블록을 선언한다는 뜻입니다. 이 예제처럼 overrides도 tui도 없는 순수한 스펙 라우팅 매니페스트는 소거법으로 extended-legacy가 됩니다. 뭔가 빠졌다는 의미가 아닙니다.
    • **unversioned**는 그저 매니페스트에 providerVersion 필드가 없다는 뜻입니다. 스키마는 이를 요구하지 않고, 로더도 CLI 프로바이더가 로드되고 실행되는 데 이 필드에 의존하지 않습니다 — provider list/validate가 출력할 무언가를 갖기 위해 존재할 뿐입니다. 실제 값을 표시하고 싶다면 "providerVersion": "1.0.0" 필드를 추가하면 되지만, 이런 매니페스트에는 있어도 그만 없어도 그만인 항목입니다.
  • adhdev provider list(머신이 읽을 수 있는 출력을 원하면 --json 추가)는 데몬이 현재 로드한 모든 프로바이더를, 모든 소스 디렉터리를 통틀어 스펙 버전 핀과 함께 보여줍니다.
  • **adhdev provider detect [type]**은 실제로 해당 바이너리가 설치되어 PATH에 있는지 확인합니다. CLI에서 실행하면 활성화 게이트를 의도적으로 우회하므로 프로바이더를 활성화하기 전에도 동작합니다. 대시보드/데몬 쪽 동일 기능(detect_provider)은 더 엄격해서, 프로바이더가 아직 활성화되지 않았다면 Provider is disabled on this machine으로 거부합니다. 그러니 CLI가 아니라 대시보드에서 감지를 확인할 거라면 먼저 프로바이더를 활성화하세요.
  • 데몬이 실행 중일 때 사용자 오버라이드 폴더의 매니페스트를 편집하면 위에서 설명한 핫 리로드 감시자가 동작합니다 — 데몬 로그에서 File changed: provider.v1.json, reloading...와 ⚠ 검증 경고가 있는지 확인하세요.

이런 식으로 직접 작성한, 트리 밖(out-of-tree) 프로바이더에 대한 대시보드 "fix"나 자동 복구 흐름은 없습니다 — 그 도구는 여러분이 직접 유지 관리하는 커스텀 매니페스트가 아니라 내장 프로바이더 번들 자체의 스크립트 레이아웃을 대상으로 합니다.

공유하기 ​

만든 프로바이더를 모두가 자동으로 받는 내장 세트의 일부로 만들고 싶다면, 데몬의 .upstream/ 번들이 빌드되는 바로 그 저장소인 github.com/vilmire/adhdev-providers에 업스트림으로 기여하세요. 저장소 자체의 기여 가이드를 따라 cli/<type>/ 디렉터리를 추가하는 풀 리퀘스트를 여세요. 그곳에 반영되면 프로바이더가 내장 인벤토리의 일부가 될 뿐, 자동으로 검증된 프로바이더가 되는 것은 아니라는 점에 유의하세요 — 차이는 프로바이더 문제를 참고하세요.

그때까지(또는 그 대신), 프로바이더 디렉터리는 그냥 폴더일 뿐입니다 — 버전 관리에 올리거나, zip으로 공유하거나, 동료의 providerDir가 같은 git 체크아웃을 가리키게 할 수 있습니다.

관련 문서 ​

호스팅 클라우드 문서는 여기에 있습니다. 오픈소스 및 셀프호스트 문서는 OSS 레포지토리에 있습니다.