AgentOS 플러그인
직접 일하는 대신 Agentty의 에이전트를 통해 일을 진행하는 플러그인 — 그 구조, 지켜야 하는 규칙, 그리고 브라우저가 필요 없는 이유.
AgentOS는 직접 일하는 대신 Agentty의 에이전트를 통해 일을 진행하는 플러그인입니다. 한 분야의 스킬과 규칙 — 블로깅, 마케팅, 인플루언서의 한 주 — 을 담아 두고, 작업을 단계별로 그 규칙에 태워 보냅니다. 실제로 쓰는 일은 에이전트가 하고, 그 세션은 이용자가 읽고 직접 넘겨받을 수 있습니다.
다른 플러그인과 똑같습니다. WebAssembly 모듈 하나, 같은 권한, 같은 패널입니다. AgentOS로 만드는 것은 그 안에 든 내용과 prompt.inject를 쓰는 방식입니다.
┌─ 플러그인 (.wasm 모듈) ────────────────────────────────────────┐
│ 스킬 각 단계의 프롬프트. 그 분야에 맞게 작성된 것 │
│ 규칙 한 단계가 해서는 안 되는 일과, "끝났다"의 정의 │
│ 진행 다음 단계, 각 단계의 결과, 이용자가 승인한 것 │
└────────────────────────────────────────────────────────────────┘
│ prompt/inject │ session/get
▼ ▼
Claude Code 또는 Codex 세션 에이전트가 써낸 것한 단계는 이렇습니다. 에이전트에 프롬프트를 보내고, 그 에이전트가 작업을 멈출 때까지 기다리고, 결과를 읽고, 판단합니다. 플러그인은 상태를 storage/*에 두기 때문에 재시작해도 진행이 이어지고, 그 상태를 패널에 그립니다. 단계 목록, 현재 위치, 돌아온 내용, 승인하고 다음으로 넘기는 버튼입니다.
AgentOS는 새 런타임도 새 권한도 아닙니다. 내용의 대부분이 프롬프트인 플러그인의 형태일 뿐입니다.
브라우저가 필요 없는 이유#
글을 올리는 플러그인을 만드는 가장 뻔한 방법은 플러그인에 브라우저를 주는 것입니다. 그러면 모든 플러그인이 이용자의 로그인된 세션을 손에 쥐게 됩니다. 여기서는 그렇게 하지 않습니다.
플러그인에는 브라우저도 네트워크도 없습니다. 대신 에이전트에게 요청합니다. Agentty는 이미 모든 에이전트 세션에 자체 브라우저를 주고 있고, 그 브라우저는 이용자가 이미 로그인해 둔 그 브라우저입니다. 에이전트가 원래 쓸 수 있는 셸에서 이렇게 조작합니다.
agentty browser navigate <url> agentty browser text [selector]
agentty browser click <selector> agentty browser type <selector> <text>
agentty browser elements agentty browser screenshot <path.png>그러니 글을 올리는 워크플로는, 어느 페이지를 열고 무엇을 입력할지 적은 프롬프트를 이용자가 지켜보는 세션에 보내는 일입니다. 플러그인은 이용자의 로그인 세션을 한 번도 건네받지 않고도 웹사이트에 글을 올릴 수 있습니다.
정작 중요한 규칙 — 로그인하지 말 것, 아무것도 설치하지 말 것, 멈추고 무엇을 봤는지 말할 것, 읽는 중에는 행동하지 말 것 — 은 그 프롬프트의 일부입니다. 워크플로는 이것들을 glossary에 한곳으로 모아 두어, 어떤 단계도 그 규칙 없이는 작성될 수 없게 합니다.
Agentty가 더해 주는 것#
모듈에는 시계도 루프도 없습니다. 메시지를 처리하는 동안에만 실행됩니다. 나머지를 가능하게 하는 메시지가 둘 있고, 둘 다 apiVersion: 2가 필요합니다.
host/timer — 기다리기#
| 메서드 | 권한 | params | 결과 |
|---|---|---|---|
host/timer | { ms } | 시간이 지나면 { elapsedMs } |
나중에 응답되는 요청입니다. 최소 100ms, 최대 1시간, 플러그인당 8개까지 동시에 걸 수 있습니다. 중단되거나 재시작된 플러그인은 기다리던 것을 잃습니다. 백그라운드 실행 수단이 아닙니다. 플러그인이 얻는 것은 그 응답이 전부입니다.
pane/status — 에이전트가 끝난 것을 듣기#
| 메시지 | 종류 | params |
|---|---|---|
pane/status | 알림 | { paneId, status, agent, title?, cwd?, running } |
이 플러그인이 시작한 페인의 상태가 바뀌면 전달됩니다. 플러그인은 prompt/inject의 응답({ status: "sent", paneId })에서 페인 id를 알게 되고, Agentty는 어느 플러그인이 어느 페인을 시작했는지 기억했다가 그 플러그인에게만 알립니다. 이미 "에이전트 상태를 본다"는 뜻인 workspace.read가 필요합니다. 동시에 최대 32개 페인까지 추적합니다.
화면이 그려지고 있든 아니든 상태는 전달됩니다. 다른 창에 가려진 창이나 잠긴 화면의 창은 그려지지 않는데, 에이전트를 기다리는 플러그인이 이용자가 돌아오기를 기다리고 있어서는 안 되기 때문입니다.
이용자가 직접 보낸 프롬프트도 추적됩니다. target: "ask"는 아직 페인이 없으므로 페인 id 없이 { status: "asked" }로 응답하지만, 이용자가 고른 세션도 똑같이 지켜봅니다. 그 세션의 첫 pane/status가 플러그인이 어느 페인이 되었는지 알게 되는 지점입니다.
만들기#
모든 AgentOS가 공유하는 부분은 Rust SDK의 agentty_plugin::agentos에 있습니다. 워크플로는 단계의 목록이고, 한 단계는 프롬프트와 결과 검사, 그리고 다음으로 넘어가기 전에 이용자에게 물을지 여부입니다.
static BLOGGER: Workflow = Workflow {
id: "blogger",
title: "Blog post",
agent: Some("claude"),
// 여러 단계가 공유하는 프롬프트 조각 — 브라우저 조작 규칙, 문체 지침 등.
glossary: &[],
steps: &[
Step { id: "outline", title: "Outline", prompt: OUTLINE, check: has_headings, approval: Approval::Auto },
Step { id: "draft", title: "Draft", prompt: DRAFT, check: long_enough, approval: Approval::Auto },
Step { id: "edit", title: "Edit", prompt: EDIT, check: no_placeholders, approval: Approval::Ask },
Step { id: "save", title: "Save", prompt: SAVE, check: names_a_file, approval: Approval::Ask },
],
};{input}은 이 진행을 시작할 때 입력한 내용, {step.<id>}는 앞 단계가 만들어 낸 결과입니다. 둘 다 워크플로의 glossary와 함께 프롬프트를 보내기 전에 채워집니다.
Approval::Auto는 다음 단계를 알아서 시작하고, Approval::Ask는 돌아온 내용을 보여준 뒤 계속을 기다립니다.
진행 과정#
모든 전이는 플러그인이 이미 받고 있는 메시지입니다.
| 이런 일이 생기면 | 러너가 하는 일 |
|---|---|
| 이용자가 시작을 누름 | 첫 단계 프롬프트를 target: "newTab"으로 prompt/inject → paneId 기억 |
pane/status가 그 페인을 working이라고 알림 | 프롬프트가 받아들여졌다고 기록 |
그 뒤 finished나 idle이 오면 | 멈춤이 계속되는지 2.5초 확인 |
| 여전히 멈춰 있으면 | session/get 후 그 단계의 검사 실행 |
| 그 2.5초 사이에 다시 작업을 시작하면 | 아까 한 말은 답이 아니었던 것 — 다시 기다림 |
| 검사를 통과하면 | 결과를 보관하고, 보여주거나 다음 단계를 전송 |
| 검사에 실패하면 | 무엇이 빠졌는지 에이전트에 다시 전달 — 3회까지, 그 뒤엔 중단하고 이유를 알림 |
| 에이전트가 무언가를 묻거나 페인이 사라지면 | 진행을 멈추고 알림 |
| Agentty가 재시작되면 | storage에서 진행을 읽어 와 세션에 다시 질의 |
2.5초 대기는 감으로 정한 값이 아닙니다. 에이전트는 도구 호출 사이에 잠깐 유휴 상태가 되고, 그 순간에 세션을 읽으면 문장 절반과 방금 실행하려던 도구 이름이 돌아옵니다. 그것을 답으로 삼은 단계는 아무것도 읽지 않은 채 다음으로 넘어가게 됩니다.
working 줄이 있는 이유도 같습니다. 페인은 열린 순간부터, 에이전트가 프롬프트를 집어 들기 전까지 idle입니다. 그래서 idle만으로는 절대 "끝났다"는 뜻이 아니고, 그 페인이 한 번이라도 working이 된 것을 본 뒤에야 멈춤을 믿습니다.
두 가지 규칙#
워크플로가 결정할 수 없는 것이 둘 있습니다. AgentOS는 이용자를 대신해 에이전트와 대화하는 플러그인이기 때문입니다.
마지막 단계 전에는 그 단계가 무엇이라고 적혀 있든 이용자에게 묻습니다. 마지막 단계는 세상에 작용하는 단계입니다. 게시하고, 푸시하고, 전송합니다. 그 직전에 이용자가 보는 내용이 바로 그 단계가 다룰 내용입니다. 그 단계를 자동으로 표시한 워크플로는, 이용자가 보지 않는 사이에 이용자 계정에 글을 쓰는 플러그인이 됩니다.
아무도 읽지 않은 답으로 게시하게 되는 워크플로는 플러그인이 시작될 때 거부됩니다. Workflow::checked()가 게시하려던 시점이 아니라 init에서 그렇게 알립니다. 단계가 두 개 미만이거나, 단계 id가 중복되거나, 아무도 쓰지 않는 glossary 항목이 있어도 거부합니다.
그리고 워크플로가 스스로 지켜야 하는 것이 둘 있습니다.
- 이용자가 앞에 있어야 합니다. 단계의 프롬프트는 이용자가 읽을 수 있는 세션, 직접 넘겨받을 수 있는 탭으로 들어갑니다.
- 링크는 진행이 아닙니다. 링크가 도달한 플러그인은 터미널에 입력할 수 없고, 그 플러그인이 실행되는 내내 프롬프트가 **보낼 곳…**을 거칩니다. 그렇게 시작된 AgentOS는 먼저 묻게 되며, 이용자가 고른 세션을 그대로 따라가므로 묻는 비용은 한 턴뿐입니다.
예제#
둘 다 마켓플레이스 저장소에 소스와 체크섬이 함께 있습니다.
Blogger AgentOS — 개요, 초안, 교정, 저장. 약 180줄이고 대부분이 프롬프트입니다. 검사도 실제로 동작하는 것들입니다. 개요에 섹션 3개, 초안에 300단어, TODO가 남아 있지 않을 것. 직접 만들기 전에 읽어 볼 것은 이쪽입니다. 권한은 prompt.inject, session.read, workspace.read입니다.
Social AgentOS — 워크플로 세 개. 모두 이용자가 로그인해 둔 브라우저를 통해 진행됩니다.
| 단계 | |
|---|---|
| X에 게시 | 무슨 이야기가 오가는지 읽기 → 초안 → 이용자가 읽음 → 게시 |
| X에 답글 | 참여할 만한 대화 찾기 → 답글 초안 → 이용자가 읽음 → 전송 |
| 인스타그램 캡션 | 그 계정의 문체 읽기 → 캡션 → 이용자가 읽음 → 저장하고 클립보드에 복사 |
읽지 않은 것은 게시하지 않고, 로그인하지 않으며(로그인이나 캡차를 만난 프롬프트는 멈추고 무엇을 봤는지 알립니다), 읽는 중에는 좋아요·리포스트·답글·팔로우를 하지 않고, 한 번에 답글 5개까지만 보냅니다. 인스타그램은 사진을 직접 골라야 하므로 마지막 단계는 거기서 멈춥니다. 캡션을 파일로 쓰고 클립보드에 넣은 뒤 인스타그램을 열어 줍니다.
요구하는 권한은 prompt.inject, session.read, workspace.read뿐입니다. 비밀번호를 둘 곳이 없는데, 애초에 가진 적이 없기 때문입니다.
아직 없는 것#
- 스킬은 모듈 안에 있습니다. 단계의 프롬프트를 이용자가 고칠 수 있게 만든 플러그인은 그 수정을
storage에 두며, 컴퓨터 한 대에서는 그것으로 충분합니다. 스킬 묶음을 사람들 사이에 공유하는 것은 프로토콜이 아니라 마켓플레이스의 문제입니다. - 여러 에이전트를 동시에.
prompt/inject는 원하는 만큼 페인을 열 수 있고pane/status는 각각을 알려 주지만, "이 셋이 한 단계다"라고 말할 방법은 없습니다. 플러그인이 id를 직접 기억해서 처리합니다. - 비용. 한 번의 진행은 여러 에이전트 세션입니다. 비용은 Agentty의 사용량 페이지에서 볼 수 있지만, 플러그인이 물어볼 수는 없습니다.
- 정해진 시각에 실행. 진행은 이용자가 시작을 눌러야 시작됩니다. 평일 아침마다 글을 올리는 AgentOS라면 Agentty가 대신 시작해 줘야 하는데,
host/timer는 플러그인이 실행 중일 때만 응답되고 플러그인은 Agentty가 켜져 있을 때만 실행됩니다.
다음으로#
- Rust와 WebAssembly — AgentOS를 작성하는 SDK
- 플러그인 프로토콜 · 권한