xurl — 공식 CLI를 통한 X(Twitter) API
xurl은 X 개발자 플랫폼의 공식 X API CLI입니다. 일반적인 작업을 위한 단축 명령어와 모든 v2 엔드포인트에 대한 원시 curl 스타일 접근을 모두 지원합니다. 모든 명령은 JSON을 stdout으로 출력합니다.
이 스킬은 다음 작업에 사용합니다:
- 게시, 답글, 인용, 게시물 삭제
- 게시물 검색 및 타임라인/멘션 읽기
- 좋아요, 리포스트, 북마크
- 팔로우, 언팔로우, 차단, 뮤트
- 다이렉트 메시지
- 미디어 업로드 (이미지 및 비디오)
- 모든 X API v2 엔드포인트에 대한 원시 접근
- 다중 앱/다중 계정 워크플로
이 스킬은 이전 xitter 스킬(타사 Python CLI 래퍼)을 대체합니다. xurl은 X 개발자 플랫폼 팀이 유지 관리하며, OAuth 2.0 PKCE 자동 갱신을 지원하고 훨씬 더 넓은 API 범위를 제공합니다.
시크릿 보안 (필수)
에이전트/LLM 세션 내에서 작업할 때의 중요한 규칙:
- 절대
~/.xurl파일을 읽거나, 출력하거나, 구문 분석하거나, 요약하거나, 업로드하거나 LLM 컨텍스트로 보내지 마십시오. - 절대 사용자에게 채팅에 자격 증명/토큰을 붙여넣도록 요청하지 마십시오.
- 사용자는 자신의 기기에서 직접
~/.xurl파일을 수동으로 작성해야 합니다. Docker에서는 Hermes 도구 하위 프로세스가 보는~디렉토리여야 합니다. 아래 Docker 참고를 확인하십시오. - 절대 에이전트 세션에서 인라인 시크릿이 포함된 인증 명령을 실행하거나 추천하지 마십시오.
- 절대 에이전트 세션에서
--verbose/-v플래그를 사용하지 마십시오. 인증 헤더/토큰이 노출될 수 있습니다. - 자격 증명이 존재하는지 확인하려면 다음만 사용하십시오:
xurl auth status.
에이전트 명령에서 금지된 플래그 (인라인 시크릿을 허용함):
--bearer-token, --consumer-key, --consumer-secret, --access-token, --token-secret, --client-id, --client-secret
앱 자격 증명 등록 및 교체는 사용자가 에이전트 세션 외부에서 직접 수행해야 합니다. 자격 증명이 등록된 후, 사용자는 xurl auth oauth2 명령으로 인증합니다(이 역시 에이전트 세션 외부에서). 토큰은 YAML 형식으로 ~/.xurl에 저장됩니다. 각 앱은 격리된 토큰을 갖습니다. OAuth 2.0 토큰은 자동으로 갱신됩니다.
설치
한 가지 방법을 선택하십시오. Linux에서는 셸 스크립트나 go install이 가장 간편합니다.
# 셸 스크립트 (~/.local/bin에 설치, sudo 불필요, Linux + macOS에서 작동)
curl -fsSL https://raw.githubusercontent.com/xdevplatform/xurl/main/install.sh | bash
# Homebrew (macOS)
brew install --cask xdevplatform/tap/xurl
# npm
npm install -g @xdevplatform/xurl
# Go
go install github.com/xdevplatform/xurl@latest
설치 확인:
xurl --help
xurl auth status
xurl이 설치되었지만 auth status에 앱이나 토큰이 없으면 사용자가 수동으로 인증을 완료해야 합니다. 다음 섹션을 참조하십시오.
일회성 사용자 설정 (사용자가 에이전트 외부에서 직접 실행)
이 단계는 시크릿을 붙여넣는 과정이 포함되므로 에이전트가 아닌 사용자가 직접 수행해야 합니다. 사용자를 이 블록으로 안내하고, 대신 실행하지 마십시오.
-
https://developer.x.com/en/portal/dashboard 에서 앱을 만들거나 엽니다.
-
리디렉션 URI를
http://localhost:8080/callback으로 설정합니다. -
앱의 클라이언트 ID와 클라이언트 시크릿을 복사합니다.
-
앱을 로컬에 등록합니다 (사용자가 실행):
xurl auth apps add my-app --client-id YOUR_CLIENT_ID --client-secret YOUR_CLIENT_SECRET -
인증합니다 (
--app플래그로 토큰을 앱에 바인딩):xurl auth oauth2 --app my-app(브라우저가 열리면서 OAuth 2.0 PKCE 흐름이 진행됩니다.)
X가 OAuth 후
/2/users/me조회에서UsernameNotFound오류 또는 403을 반환하면, 사용자 핸들을 명시적으로 전달하십시오 (xurl v1.1.0+):xurl auth oauth2 --app my-app YOUR_USERNAME이렇게 하면 토큰이 사용자 핸들에 바인딩되고 문제가 있는
/2/users/me호출을 건너뜁니다. -
앱을 기본값으로 설정하여 모든 명령이 이 앱을 사용하도록 합니다:
xurl auth default my-app -
확인:
xurl auth status xurl whoami
이후에는 추가 설정 없이 에이전트가 아래의 모든 명령을 사용할 수 있습니다. OAuth 2.0 토큰은 자동으로 갱신됩니다.
일반적인 실수:
xurl auth oauth2에--app my-app을 생략하면 OAuth 토큰이 기본 제공되는default앱 프로필에 저장됩니다. 이 프로필에는 client-id 또는 client-secret이 없습니다. OAuth 흐름이 성공한 것처럼 보여도 명령이 인증 오류와 함께 실패합니다. 이 문제가 발생하면xurl auth oauth2 --app my-app및xurl auth default my-app을 다시 실행하십시오.
Docker HOME 문제: 공식 Hermes Docker 레이아웃에서
/opt/data는HERMES_HOME이지만, Hermes 도구 하위 프로세스는/opt/data/home을HOME으로 사용합니다. 따라서 Hermes가 실행하는xurl명령의 경우~/.xurl은/opt/data/home/.xurl로 확인되며,/opt/data/.xurl이 아닙니다. 동일한 HOME으로 사용자 설정을 실행하십시오:HOME=/opt/data/home xurl auth apps add my-app --client-id YOUR_CLIENT_ID --client-secret YOUR_CLIENT_SECRET HOME=/opt/data/home xurl auth oauth2 --app my-app YOUR_USERNAME HOME=/opt/data/home xurl auth default my-app YOUR_USERNAME HOME=/opt/data/home xurl auth status
HOME=/opt/data xurl auth status는 성공하지만HOME=/opt/data/home xurl auth status에 앱이나 토큰이 없으면 Hermes 도구 호출이 자격 증명을 찾을 수 없습니다.
빠른 참조
| 동작 | 명령어 |
|---|---|
| 게시 | xurl post "Hello world!" |
| 답글 | xurl reply POST_ID "Nice post!" |
| 인용 | xurl quote POST_ID "My take" |
| 게시물 삭제 | xurl delete POST_ID |
| 게시물 읽기 | xurl read POST_ID |
| 게시물 검색 | xurl search "QUERY" -n 10 |
| 나는 누구인가 | xurl whoami |
| 사용자 조회 | xurl user @handle |
| 홈 타임라인 | xurl timeline -n 20 |
| 멘션 | xurl mentions -n 10 |
| 좋아요 / 좋아요 취소 | xurl like POST_ID / xurl unlike POST_ID |
| 리포스트 / 취소 | xurl repost POST_ID / xurl unrepost POST_ID |
| 북마크 / 제거 | xurl bookmark POST_ID / xurl unbookmark POST_ID |
| 북마크 / 좋아요 목록 | xurl bookmarks -n 10 / xurl likes -n 10 |
| 팔로우 / 언팔로우 | xurl follow @handle / xurl unfollow @handle |
| 팔로잉 / 팔로워 | xurl following -n 20 / xurl followers -n 20 |
| 차단 / 차단 해제 | xurl block @handle / xurl unblock @handle |
| 뮤트 / 뮤트 해제 | xurl mute @handle / xurl unmute @handle |
| DM 보내기 | xurl dm @handle "message" |
| DM 목록 | xurl dms -n 10 |
| 미디어 업로드 | xurl media upload path/to/file.mp4 |
| 미디어 상태 | xurl media status MEDIA_ID |
| 앱 목록 | xurl auth apps list |
| 앱 제거 | xurl auth apps remove NAME |
| 기본 앱 설정 | xurl auth default APP_NAME [USERNAME] |
| 요청별 앱 | xurl --app NAME /2/users/me |
| 인증 상태 | xurl auth status |
참고:
POST_ID는 전체 URL(예:https://x.com/user/status/1234567890)도 허용합니다. xurl이 ID를 추출합니다.- 사용자 이름은 앞의
@와 함께 또는 없이 사용할 수 있습니다.
명령 상세
게시
xurl post "Hello world!"
xurl post "Check this out" --media-id MEDIA_ID
xurl post "Thread pics" --media-id 111 --media-id 222
xurl reply 1234567890 "Great point!"
xurl reply https://x.com/user/status/1234567890 "Agreed!"
xurl reply 1234567890 "Look at this" --media-id MEDIA_ID
xurl quote 1234567890 "Adding my thoughts"
xurl delete 1234567890
읽기 및 검색
xurl read 1234567890
xurl read https://x.com/user/status/1234567890
xurl search "golang"
xurl search "from:elonmusk" -n 20
xurl search "#buildinpublic lang:en" -n 15
X Articles의 경우 read 단축 명령어 대신 원시 API 모드를 사용하십시오. xurl read는 게시물 ID 또는 게시물 URL을 기대합니다. /2/tweets/... 엔드포인트 앞에 read를 사용하지 마십시오. article 트윗 필드를 요청하고 JSON 응답에서 data.article.plain_text를 가져오십시오:
xurl --app APP_NAME '/2/tweets/2057909493250539891?expansions=author_id,attachments.media_keys,referenced_tweets.id&tweet.fields=created_at,lang,public_metrics,context_annotations,entities,possibly_sensitive,conversation_id,in_reply_to_user_id,referenced_tweets,article'
사용자, 타임라인, 멘션
xurl whoami
xurl user elonmusk
xurl user @XDevelopers
xurl timeline -n 25
xurl mentions -n 20
참여
xurl like 1234567890
xurl unlike 1234567890
xurl repost 1234567890
xurl unrepost 1234567890
xurl bookmark 1234567890
xurl unbookmark 1234567890
xurl bookmarks -n 20
xurl likes -n 20
소셜 그래프
xurl follow @XDevelopers
xurl unfollow @XDevelopers
xurl following -n 50
xurl followers -n 50
# 다른 사용자의 그래프
xurl following --of elonmusk -n 20
xurl followers --of elonmusk -n 20
xurl block @spammer
xurl unblock @spammer
xurl mute @annoying
xurl unmute @annoying
다이렉트 메시지
xurl dm @someuser "Hey, saw your post!"
xurl dms -n 25
미디어 업로드
# 자동 유형 감지
xurl media upload photo.jpg
xurl media upload video.mp4
# 명시적 유형/카테고리
xurl media upload --media-type image/jpeg --category tweet_image photo.jpg
# 비디오는 서버 측 처리가 필요합니다. 상태 확인 (또는 폴링)
xurl media status MEDIA_ID
xurl media status --wait MEDIA_ID
# 전체 워크플로
xurl media upload meme.png # 미디어 ID 반환
xurl post "lol" --media-id MEDIA_ID
원시 API 접근
단축 명령어는 일반적인 작업을 처리합니다. 그 외의 경우, 모든 X API v2 엔드포인트에 대해 원시 curl 스타일 모드를 사용하십시오:
# GET
xurl /2/users/me
# JSON 본문을 사용한 POST
xurl -X POST /2/tweets -d '{"text":"Hello world!"}'
# DELETE / PUT / PATCH
xurl -X DELETE /2/tweets/1234567890
# 사용자 정의 헤더
xurl -H "Content-Type: application/json" /2/some/endpoint
# 강제 스트리밍
xurl -s /2/tweets/search/stream
# 전체 URL도 작동
xurl https://api.x.com/2/users/me
전역 플래그
| 플래그 | 단축 | 설명 |
|---|---|---|
--app | 특정 등록된 앱 사용 (기본값 재정의) | |
--auth | 인증 유형 강제: oauth1, oauth2, 또는 app | |
--username | -u | 사용할 OAuth2 계정 (여러 개 있는 경우) |
--verbose | -v | 에이전트 세션에서 금지 — 인증 헤더 유출 |
--trace | -t | X-B3-Flags: 1 추적 헤더 추가 |
스트리밍
스트리밍 엔드포인트는 자동으로 감지됩니다. 알려진 엔드포인트:
/2/tweets/search/stream/2/tweets/sample/stream/2/tweets/sample10/stream
-s 플래그로 모든 엔드포인트에서 스트리밍을 강제합니다.
출력 형식
모든 명령은 JSON을 stdout으로 반환합니다. 구조는 X API v2를 따릅니다:
{ "data": { "id": "1234567890", "text": "Hello world!" } }
오류도 JSON입니다:
{ "errors": [ { "message": "Not authorized", "code": 403 } ] }
일반적인 워크플로
이미지와 함께 게시
xurl media upload photo.jpg
xurl post "Check out this photo!" --media-id MEDIA_ID
대화에 답글
xurl read https://x.com/user/status/1234567890
xurl reply 1234567890 "Here are my thoughts..."
검색 및 참여
xurl search "topic of interest" -n 10
xurl like POST_ID_FROM_RESULTS
xurl reply POST_ID_FROM_RESULTS "Great point!"
내 활동 확인
xurl whoami
xurl mentions -n 20
xurl timeline -n 20
여러 앱 (자격 증명은 수동으로 미리 구성됨)
xurl auth default prod alice # prod 앱, alice 사용자
xurl --app staging /2/users/me # staging에 대한 일회성 요청
오류 처리
- 오류 발생 시 0이 아닌 종료 코드 반환.
- API 오류는 JSON으로 stdout에 출력되므로 구문 분석 가능.
- 인증 오류 → 사용자가 에이전트 세션 외부에서
xurl auth oauth2를 다시 실행하도록 안내. - 호출자 사용자 ID가 필요한 명령(좋아요, 리포스트, 북마크, 팔로우 등)은
/2/users/me를 통해 자동으로 가져옴. 여기서 인증 실패가 발생하면 인증 오류로 표시됨.
에이전트 워크플로
- 사전 요구 사항 확인:
xurl --help및xurl auth status. - 기본 앱에 자격 증명이 있는지 확인합니다.
auth status출력을 구문 분석합니다. 기본 앱은▸로 표시됩니다. 기본 앱에oauth2: (none)이라고 표시되지만 다른 앱에 유효한 oauth2 사용자가 있는 경우, 사용자에게xurl auth default <that-app>을 실행하여 수정하도록 지시하십시오. 이것이 가장 흔한 설정 실수입니다. 사용자가 사용자 정의 이름으로 앱을 추가했지만 기본값으로 설정하지 않아 xurl이 계속 비어 있는default프로필을 시도하는 경우입니다. - 인증이 완전히 누락된 경우 중단하고 사용자를 "일회성 사용자 설정" 섹션으로 안내하십시오. 스스로 앱을 등록하거나 시크릿을 전달하지 마십시오.
- 저렴한 읽기 명령(
xurl whoami,xurl user @handle,xurl search ... -n 3)으로 시작하여 연결 가능성을 확인합니다. - 쓰기 작업(게시, 답글, 좋아요, 리포스트, DM, 팔로우, 차단, 삭제) 전에 대상 게시물/사용자와 사용자의 의도를 확인합니다.
- JSON 출력을 직접 사용하십시오. 모든 응답이 이미 구조화되어 있습니다.
- 절대
~/.xurl내용을 대화에 다시 붙여넣지 마십시오.
문제 해결
| 증상 | 원인 | 해결책 |
|---|---|---|
| OAuth 흐름 성공 후 인증 오류 | 토큰이 사용자 정의 앱이 아닌 default 앱(클라이언트 ID/시크릿 없음)에 저장됨 | xurl auth oauth2 --app my-app 후 xurl auth default my-app 실행 |
OAuth 중 unauthorized_client | X 대시보드에서 앱 유형이 "Native App"으로 설정됨 | 사용자 인증 설정에서 "Web app, automated app or bot"으로 변경 |
OAuth 직후 /2/users/me에서 UsernameNotFound 또는 403 | X가 /2/users/me에서 사용자 이름을 안정적으로 반환하지 않음 | xurl auth oauth2 --app my-app YOUR_USERNAME(xurl v1.1.0+)으로 핸들을 명시적으로 전달하여 재실행 |
| 모든 요청에서 401 | 토큰 만료 또는 잘못된 기본 앱 | xurl auth status 확인 — ▸가 oauth2 토큰이 있는 앱을 가리키는지 확인 |
client-forbidden / client-not-enrolled | X 플랫폼 등록 문제 | 대시보드 → 앱 → 관리 → "Pay-per-use" 패키지 → 프로덕션 환경으로 이동 |
CreditsDepleted | X API 잔액 0$ | 개발자 콘솔 → 결제에서 크레딧 구매 (최소 $5) |
이미지 업로드 시 media processing failed | 기본 카테고리가 amplify_video임 | --category tweet_image --media-type image/png 추가 |
| X 대시보드에 "Client Secret" 값 두 개 | UI 버그 — 첫 번째는 실제로 Client ID임 | "Keys and tokens" 페이지에서 확인; ID는 MTpjaQ로 끝남 |
참고 사항
- 속도 제한: X는 엔드포인트별 속도 제한을 적용합니다. 429는 대기 후 재시도를 의미합니다. 쓰기 엔드포인트(게시, 답글, 좋아요, 리포스트)는 읽기보다 제한이 더 엄격합니다.
- 범위(Scopes): OAuth 2.0 토큰은 광범위한 범위를 사용합니다.