DEV Community

Cover image for Codex CLI를 osFoundry 팀 세션의 Runner로 붙여 봤다
BBT for BBT 한국어

Posted on

Codex CLI를 osFoundry 팀 세션의 Runner로 붙여 봤다

다 끝나면 Codex CLI는 osFoundry의 팀 세션이나 루프 세션에 Runner 자리로 들어가 있다. 터미널에서 request_session_run으로 goal 하나를 걸면 세션 쪽 에이전트들이 세션 런타임에서 일을 하고, Codex는 read_session_task_result로 결과를 읽는다. 마지막으로 post_session_note로 팀 메일에 한마디 남기고, 에이전트 답장은 read_session_mail로 가져온다. run마다 누가 버튼을 누를 필요는 없다. 오너가 한 번 준 Runner 자리가 그 승인을 대신한다.

누가 뭘 하나

Codex CLI osFoundry
로그인 내 Codex 로그인. osFoundry OAuth 토큰(osfoundry:run 포함)도 Codex가 들고 있다 오너가 연결을 한 번 승인하고, 세션마다 자리를 정한다
시작할 수 있는 것 호출 한 번에 goal 하나. 10,000자까지, max_rounds는 1~10 "Requested by an outside assistant"가 계기인 태스크로 큐에 넣고, 세션 자체의 에이전트·툴·모델로 돌린다
일하는 곳 내 머신에선 아무것도 안 돈다. Codex는 기다렸다 읽기만 세션 런타임. 데스크톱 런타임이면 다음 폴링 때 집어 가고, 세션당 run 하나씩
돌아오는 것 이 연결이 시작한 태스크의 상태와 결과, 이 연결 앞으로 온 노트, 내가 올린 노트 에이전트 내부 분석은 세션 밖으로 안 나간다
멈출 수 있는 사람 쓰기 툴 전에 Codex가 확인(default_tools_approval_mode = "writes") 오너가 Connected 탭에서 자리를 빼거나 연결을 Revoke

세팅

1. Codex에 run 스코프 주기

연결 자체는 평소대로 만든다. 헤더의 열쇠 아이콘에서 Connected 탭을 열고, Other MCP client를 고르고, 표시 이름에 Codex CLI 같은 걸 넣는다. run이나 노트가 올라갈 때마다 세션 에이전트와 오너한테 이 이름이 보이니까 누가 봐도 알 만한 이름이 좋다.

Codex 쪽에서는 서버를 붙이고 Runner 루프에 필요한 툴만 남긴다.

codex mcp add osfoundry --url https://api.osfoundry.io/api/v1/external-mcp
Enter fullscreen mode Exit fullscreen mode
# ~/.codex/config.toml
[mcp_servers.osfoundry]
url = "https://api.osfoundry.io/api/v1/external-mcp"
scopes = ["osfoundry:read", "osfoundry:write", "osfoundry:run"]
default_tools_approval_mode = "writes"
enabled_tools = [
  "list_granted_resources",
  "list_project_resources",
  "read_session_state",
  "request_session_run",
  "read_session_task_result",
  "post_session_note",
  "read_session_mail",
]
Enter fullscreen mode Exit fullscreen mode

그다음 로그인한다.

codex mcp login osfoundry
Enter fullscreen mode Exit fullscreen mode

osFoundry의 "Connect an agent" 페이지에서 "Requested capabilities"가 세 줄이면 맞다. 세 번째 줄 "Run sessions where you grant a runner role"이 이번 주인공이다. 이 줄이 없으면 scopes에 osfoundry:run이 빠진 거니까 파일을 고치고 다시 로그인한다.

"writes"로 두면 읽기 툴 세 개는 묻지 않고 통과하고, 읽기 전용이 아닌 request_session_run과 post_session_note 앞에서만 Codex가 멈춰서 물어본다.

2. 세션이 있는 프로젝트에 연결 추가

Connected 탭으로 돌아가 Projects에서 세션이 들어 있는 프로젝트를 고르고 Add to project를 누른다. 이제 연결에서 프로젝트 안 세션들이 보인다. 아직 어디에도 쓰지는 못한다.

3. Runner 자리 주기

그 아래에 "Agent, Team, and Loop sessions"가 있다. 설명문에 역할 차이가 그대로 적혀 있다. Contributor면 노트 올리기와 핸드오프 제안, Runner면 거기에 run 요청까지.

세션 종류(Agent session / Team session / Loop session)를 고르고, "Choose a session in this agent's projects"에서 세션을 고르고, 역할을 Runner로 바꾼 다음 Save role을 누른다. 토스트에 "Session role saved"가 뜨고, 종류·세션 이름·역할이 한 줄로 붙는다.

예시: Agent, Team, and Loop sessions 영역에서 Codex CLI를 Triage desk 팀 세션의 Runner로 지정한 모습

예시: Agent, Team, and Loop sessions 영역에서 Codex CLI를 Triage desk 팀 세션의 Runner로 지정한 모습

역할은 세 개고, Contributor와 Runner 차이는 툴 하나다.

역할(드롭다운 표기) 상태·결과·메일 읽기 노트 쓰기 run 걸기
Viewer 가능 불가 불가
Contributor 가능 가능 불가
Runner 가능 가능 가능

같은 세션에 다른 역할을 저장하면 덮어쓴다. Remove를 누르면 자리째 빠진다.

같은 패널의 Tools 영역("All supported tools are on by default")에서 체크를 끈 툴은 Codex의 enabled_tools에 뭐가 적혀 있든 osFoundry 쪽에서 막힌다.

실제로 돌려 보면

이 글을 쓴 머신에는 Codex가 없어서 아래는 시뮬레이션한 예시다. 툴 이름과 인자 이름은 라이브 서버 그대로고, Codex가 붙이는 mcp__osfoundry__ 접두어를 달았다. 프로젝트, 세션, 에이전트, 값은 전부 데모다.

예시(시뮬레이션)

> The duplicate-invoice email fix is in PR #231. Ask the osFoundry Triage desk
  which open tickets are about it, then tell them the fix ships Thursday.

• mcp__osfoundry__list_project_resources {"project_id": "…", "resource_type": "team_session",
      "search": "triage"}
  ← team_session "Triage desk"
• mcp__osfoundry__read_session_state {"session_type": "team_session", "session_id": "…"}
  ← idle, agents @triager @writer
• mcp__osfoundry__request_session_run {
      "session_type": "team_session", "session_id": "…",
      "goal": "List open support tickets from the last 7 days that report getting the same invoice email twice. For each: ticket id, customer plan, one-line status. Background: the cause is a retry in the mail job, fixed in PR #231, not deployed yet. Do not reply to customers.",
      "max_rounds": 3, "idempotency_key": "codex-pr231-dupe-tickets"}
  [Codex 확인: allow this tool call? → yes]
  ← queued, task_id "…"
• mcp__osfoundry__read_session_task_result {"session_type": "team_session",
      "session_id": "…", "task_id": "…"}
  ← pending
  … (Codex가 조금 기다렸다가 다시 묻는다)
• mcp__osfoundry__read_session_task_result {…same…}
  ← completed: 4 tickets (#5512, #5518, #5530, #5541), all on the Team plan
• mcp__osfoundry__post_session_note {"session_type": "team_session", "session_id": "…",
      "subject": "Duplicate invoice emails: fix ships Thursday",
      "body": "Root cause was a retry in the mail job. PR #231 is merged and goes out Thursday. #5512, #5518, #5530 and #5541 can be told that.",
      "idempotency_key": "codex-pr231-note"}
  [Codex 확인: allow this tool call? → yes]
• mcp__osfoundry__read_session_mail {"session_type": "team_session", "session_id": "…",
      "limit": 10}
  ← 2 notes: yours, and @writer: "Drafted replies for all four, holding until Thursday."

Triage desk가 청구 메일 중복 발송 관련 미처리 티켓 4건을 찾았다(전부 Team 플랜).
수정이 목요일에 나간다고 팀에 알려 뒀고, @writer가 답장 초안을 만들어서
목요일까지 보류해 두고 있다.
Enter fullscreen mode Exit fullscreen mode

배경 설명은 goal에 넣었다. request_session_run에는 컨텍스트용 필드가 없고 스키마에 없는 인자는 튕기니까, 에이전트가 알아야 할 건 goal 안에 쓰는 수밖에 없다.

오너 쪽에서 이 run은 이름 없는 잡으로 안 보인다. 세션의 트리거 탭("What starts this session")에 "Requested by an outside assistant"로 올라오고 그 아래 goal이 붙는다. 도는 동안은 "지금 실행 중입니다.", 끝나면 "마지막 실행:" 줄에 결과 상태가 나온다.

예시: Triage desk 세션의 트리거 탭에 외부 어시스턴트가 요청한 run이 올라온 모습

예시: Triage desk 세션의 트리거 탭에 외부 어시스턴트가 요청한 run이 올라온 모습

노트는 팀 메일에 연결의 표시 이름과 "outside assistant" 표시를 달고 들어간다. 에이전트는 여기에 답장할 수 있고, 그 답장이 read_session_mail로 Codex에 돌아온다.

예시: 팀 메일에 올라온 Codex CLI의 노트(outside assistant)와 @writer의 답장

예시: 팀 메일에 올라온 Codex CLI의 노트(outside assistant)와 @writer의 답장

어디까지 되나

Runner는 일을 시작시킬 순 있어도 세션 구성에는 손을 못 댄다. 스키마가 닫혀 있어서(additionalProperties: false) 모델도, 툴 목록도, 추가 컨텍스트도 못 넘긴다. 세션은 자기 설정과 오너의 런타임으로 돈다. max_rounds는 10이 끝이다.

새치기도 안 된다. 세션이 오너의 데스크톱 앱에서 돌면 런타임은 할 일이 있는 동안 15초마다 대기 태스크를 찾는다. 헛탕이 네 번 이어지면 30초, 60초, 5분으로 간격을 벌리고, 앱에서 사람이 뭔가 하면 바로 깨어난다. 한 세션에서 동시에 도는 run은 하나뿐이라 다음 run은 세션이 빌 때까지 기다린다. 툴 설명에 "when available"이라고 적힌 이유다. Codex는 호출 하나로 버티지 말고 결과를 폴링해야 한다.

밖에서 온 텍스트는 밖에서 온 걸로 취급된다. 데스크톱 런타임 코드에서 오퍼레이터 입력으로 치는 건 오너가 앱에서 직접 시작한 run뿐이다. 외부 어시스턴트의 goal은 웹훅 본문처럼 검사를 거친다. goal은 담백한 지시문으로 쓰고, 검사받으면 곤란한 건 붙이지 말자.

Codex가 보는 건 결과지 대화가 아니다. read_session_task_result는 이 연결이 시작한 태스크에만 답한다. read_session_mail은 이 연결 앞으로 온 노트와 직접 올린 노트를 한 번에 1~20개 돌려주고, 에이전트 내부 분석은 빠진다. 노트로 run이 시작되지도 않는다. 툴 설명대로 "does not trigger an automatic run"이니까 들어오는 문은 자리 하나뿐이다.

오너 데스크톱 안에만 있는 건 닿지 않는다. 서버의 initialize 응답에도 "Local-only data is unavailable to cloud clients."라고 적혀 있다.

다음엔 루프 세션으로 해 보자. 지금 손으로 돌리는 루프에 Codex CLI를 Runner로 붙이고, 머지할 때마다 "뭐가 바뀌었는지"를 한 문단짜리 goal로 만들어 루프의 다음 회차를 걸게 하면 된다. run이 어떻게 줄 서는지는 에이전트 태스크 큐, 에이전트끼리 노트가 어떻게 오가는지는 Agent Mail 페이지에 있다.

Top comments (0)