다 끝나면 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
# ~/.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",
]
그다음 로그인한다.
codex mcp login osfoundry
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로 지정한 모습
역할은 세 개고, 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가 답장 초안을 만들어서
목요일까지 보류해 두고 있다.
배경 설명은 goal에 넣었다. request_session_run에는 컨텍스트용 필드가 없고 스키마에 없는 인자는 튕기니까, 에이전트가 알아야 할 건 goal 안에 쓰는 수밖에 없다.
오너 쪽에서 이 run은 이름 없는 잡으로 안 보인다. 세션의 트리거 탭("What starts this session")에 "Requested by an outside assistant"로 올라오고 그 아래 goal이 붙는다. 도는 동안은 "지금 실행 중입니다.", 끝나면 "마지막 실행:" 줄에 결과 상태가 나온다.
예시: Triage desk 세션의 트리거 탭에 외부 어시스턴트가 요청한 run이 올라온 모습
노트는 팀 메일에 연결의 표시 이름과 "outside assistant" 표시를 달고 들어간다. 에이전트는 여기에 답장할 수 있고, 그 답장이 read_session_mail로 Codex에 돌아온다.
예시: 팀 메일에 올라온 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)