Akan.js
Docs
문서컨벤션레퍼런스Cheatsheet
Akan.js
문서컨벤션레퍼런스Cheatsheet
Akan.js

MIT 라이선스 하에 배포되었습니다.

Akan.js 공식 컨설팅 서비스AkansoftCopyright © 2026 Akan.js 모든 권리 보유.시스템 관리자bassman
사람함께에이전트▾
사람 — 직접 정하고 책임지는 비즈니스 규칙과 흐름. 직접 읽어보세요.
함께 — 개념은 알아두고, 세부 규칙은 에이전트가 따릅니다.
에이전트 — 에이전트가 따르는 규칙과 레퍼런스. 필요할 때 찾아보세요.
CLI 레퍼런스▾
명령어WorkspaceApplicationLibraryModuleScalarPackagePagePrimitiveWorkflowQualityContextAgentGuideline
AkanJS 레퍼런스▾
akanjs/baseakanjs/commonakanjs/constantakanjs/fetchakanjs/signalakanjs/serverakanjs/clientakanjs/webkit
UI 레퍼런스▾
OverviewCoreDisplayFormsOverlaysSystemAgent커스터마이즈
사람함께에이전트▾
사람 — 직접 정하고 책임지는 비즈니스 규칙과 흐름. 직접 읽어보세요.
함께 — 개념은 알아두고, 세부 규칙은 에이전트가 따릅니다.
에이전트 — 에이전트가 따르는 규칙과 레퍼런스. 필요할 때 찾아보세요.
CLI 레퍼런스▾
명령어WorkspaceApplicationLibraryModuleScalarPackagePagePrimitiveWorkflowQualityContextAgentGuideline
AkanJS 레퍼런스▾
akanjs/baseakanjs/commonakanjs/constantakanjs/fetchakanjs/signalakanjs/serverakanjs/clientakanjs/webkit
UI 레퍼런스▾
OverviewCoreDisplayFormsOverlaysSystemAgent커스터마이즈
이전System다음커스터마이즈

에이전트 UI

화면에 이미 있는 버튼을 같은 가드 아래에서, 사람이 보는 앞에서 눌러 주는 도우미입니다. 로봇용 API를 따로 만드는 것이 아닙니다.
Agent 네임스페이스가 그 UI입니다. 레이아웃에 <Agent.Chat /> 하나면 연결이 끝나고, 나머지 멤버는 범위를 좁히거나 에이전트가 보는 것을 보여 줍니다.import { Agent } from "akanjs/ui";
릴레이 엔드포인트는 툴을 실행하지 않습니다. 모든 호출은 사용자 자신의 브라우저 세션에서, 앱의 가드와 승인 카드를 거쳐 실행됩니다. 그래서 툴은 컴포넌트가 선언한 곳에만 있고, 화면이 사용자에게 주지 않은 조작은 에이전트도 할 수 없습니다.
이 페이지에서 쓰는 말
용어설명
툴 (tool)
컴포넌트가 st.tool로 공개한 동작 하나입니다. 보통 버튼이 이미 부르는 핸들러입니다.
표면 (surface)
지금 화면에서 에이전트가 실행하고 읽을 수 있는 것 전부, 즉 마운트된 툴과 키입니다.
세션 (session)
루프와 옵션을 가진 대화 하나입니다. Agent.Chat과 Agent.Zone이 각자 하나씩 만듭니다.
대화 기록 (transcript)
지금까지의 대화입니다. 매 턴마다 모델에 다시 전송됩니다.
기본 툴 (builtins)
런타임이 모든 화면에 넣어 주는 툴입니다. navigate, goBack, readScreen, readState, highlight.
리소스 (resource)
컴포넌트가 st.expose나 st.useState로 공개해 에이전트가 읽을 수 있게 한 값입니다.
멤버
멤버
자체 UI
자기 대화
이름 접두사
사용자가 대화하는 곳
Agent.Chat
✓
✓
채팅 패널입니다. 런처, 대화창, 입력창, 승인 카드가 들어 있고 한 번만 마운트합니다.
Agent.Zone
✓
✓
같은 화면을 좁혀 보는, 자기 대화를 가진 구획입니다.
지침과 범위
Agent.Guide
라우트 하위 트리에 상시 적용되는 지침입니다. 아무것도 그리지 않습니다.
Agent.History
감싸고 있는 zone의 대화 기록을 앱의 저장소에 연결합니다. 아무것도 그리지 않습니다.
Agent.Skip
기본 화면 읽기에서 빠지는 영역입니다. 이름이 있어서 필요하면 따로 읽을 수 있습니다.
Agent.Scope
✓
대화를 열지 않고, 아래에서 등록되는 툴과 리소스 이름에 접두사만 붙입니다.
개발용
Agent.Dock
✓
개발용 인스펙터입니다. 툴, 읽을 수 있는 상태, 보류된 키, 대화 기록을 보여 줍니다.
도크 부품
✓
Agent.Context, Agent.Section, Agent.StateKey, Agent.Tool, Agent.Transcript입니다. 직접 인스펙터를 조립할 때 씁니다.
✓있음없음
개념 설명 문서
이 페이지는 멤버와 props 목록입니다. 그 뒤의 개념은 아래 문서에서 다룹니다.
인페이지 에이전트→
루프, 표면, 승인 게이트, 압축이 어떻게 맞물리는지 설명합니다.
에이전트 채팅 치트시트→
짧은 버전입니다. 마운트하고, 설정하고, 툴을 선언하고, 배포합니다.

Chat

사용자가 보는 채팅입니다. 이 화면이 선언한 툴과 상태에 연결된 떠 있는 패널이며, 대화 루프와 모든 툴 호출이 이 브라우저에서 실행됩니다. 레이아웃에 한 번만 마운트합니다.
속성과 API
세션 옵션
대화가 돌아가는 방식이며 마운트할 때 한 번만 읽습니다. Agent.Zone이나 AgentProvider 안에서는 채팅이 그 세션에 합류하므로, 이 값은 그 세션을 만든 쪽이 정합니다.
instructionsstring
앱 전역 지침입니다. 라우트별 지침은 마운트된 Agent.Guide가 그 위에 겹칩니다.
runnerAgentRunner기본값 fetchRunner()
전송 방식을 바꿉니다. 기본값은 앱의 runAgentTurn으로 보내고, httpRunner({ url })는 다른 주소로 보냅니다.
maxTurnsnumber기본값 12
질문 하나가 쓸 수 있는 모델 왕복 횟수입니다. 한도에 닿으면 계속할지 사용자에게 묻습니다.
compactCompactOptions기본값 { at: 24_000, keep: 6, buffer: 13_000 }
추정 토큰이 at을 넘거나 알려진 창까지 buffer만 남으면 요약합니다. { at: 0 }이면 끕니다.
builtinsBuiltinOption기본값 true
true면 기본 툴 다섯 개 전부, false면 없음, 배열이면 적은 것만 줍니다. askUser는 항상 남습니다.
persistPersistOption | SessionHistory
새로고침해도 대화 기록이 남도록 sessionStorage에 저장합니다. { storage: "local" }이나 SessionHistory를 주면 다른 곳에 둡니다.
onCompact(replaced, summary) => void
압축이 메시지들을 요약 하나로 바꾼 뒤 호출됩니다. 앱이 자기 워터마크를 맞추는 자리입니다.
visualboolean | AgentVisualOption기본값 true
호출한 컨트롤에 링을 두르고(reveal) 포인터가 눌러 보입니다(cursor). false면 둘 다 끕니다.
열기와 배치
defaultOpenboolean기본값 false
패널을 열린 채로 시작합니다. 그 뒤의 열림 상태는 채팅이 스스로 관리합니다.
open / onOpenChangeboolean / (open) => void
앱이 제어하는 열림 상태입니다. open만 주면 닫기 버튼을 그리지 않습니다.
launcherboolean기본값 true
false면 런처를 그리지 않습니다. 자기 컨트롤로 패널을 여는 앱을 위한 옵션입니다.
inlineboolean기본값 false
떠 있지 않고 페이지 흐름 안에 그립니다. 자기 구획 안에 두는 zone 채팅용입니다.
shortcutboolean기본값 true
Cmd/Ctrl+L로 패널을 엽니다. 이 단축키를 이미 쓰는 앱이라면 false로 브라우저에 돌려줍니다.
모양
classNamestring
지금 보이는 쪽에 붙습니다. 닫혀 있으면 런처, 열려 있으면 패널입니다.
launcherClassName / panelClassNamestring
런처와 패널에 각각 따로 붙습니다. className은 둘 모두에 붙습니다.
titlestring
패널 제목입니다. 생략하면 사용자 언어로 '에이전트'가 나옵니다.
introReactNode
대화 기록이 비어 있는 동안 기본 안내 문구 대신 보입니다. 시작 질문을 두는 자리입니다.
header / chromeReactNode / boolean기본값 chrome = true
지우기·닫기 버튼 왼쪽에 컨트롤을 더합니다. chrome={false}면 헤더 바를 없애고, 지우기는 /new로 합니다.
입력창
defaultDraftstring
마운트할 때 한 번 읽는 입력창 초기 문구입니다. ?prompt= 값을 보내지 않고 채워 둘 때 씁니다.
attachAttachReader
파일을 첨부물로 만듭니다. null을 돌려주면 이미지와 텍스트를 읽는 기본 리더가 처리합니다.
attachLimits{ perFileBytes?, perMessageBytes?, perMessageCount? }
크기와 개수 한도입니다. 기본값은 파일당 4MB, 메시지당 8MB와 5개입니다.
reference / mentionsReferenceSource[] / boolean
@ 메뉴의 대상이며 각자 search를 가집니다. mentions는 포인터를 이름으로 그리고, 대상이 있으면 켜집니다.
voiceVoiceEngine
눌러서 말한 내용이 입력창에 들어갑니다. 음성으로 물었을 때만 답을 소리 내어 읽습니다.
  • 패널을 닫아도 대화는 남습니다. 세션이 ref에 들어 있어 다시 열어도 이어지고, persist가 없으면 페이지와 함께 사라집니다.
  • 함수를 넘기는 prop은 작은 클라이언트 컴포넌트가 필요합니다. attach, voice, reference, runner, onCompact, onOpenChange는 함수를 담고 있어 서버 레이아웃에서 RSC 경계를 넘길 수 없습니다. apps/akan/ui/DocsAgentChat.tsx처럼 ui/에 감싸는 컴포넌트를 두고, 음성 엔진은 @libs/util/webkit의 useSpeech()로 만듭니다.
  • open만 주는 제어 방식은 서버 컴포넌트에서도 쓸 수 있습니다. onOpenChange가 없으면 넘기는 함수가 없으므로 그대로 조립할 수 있습니다.
  • 런처는 하이드레이션 뒤에 나타납니다. 패널이 lazy(…, { ssr: false }) 경계라서 코드 청크가 하이드레이션이 끝난 뒤에 로드됩니다. 정상 동작입니다.
  • 서버 설정은 lib/option.ts에서 합니다. option.setLlm({ apiKey, model, host })와 option.setAgentAccess(SignedIn)으로 설정하며, 환경 변수로는 하지 않습니다.
  • 프로바이더가 닿지 못하는 url이면 data를 돌려주세요. attach 결과의 url은 프로바이더가 직접 가져갑니다. 둘 다 돌려주면 모델에는 바이트가 가고, 주소는 썸네일에 쓰입니다.
레이아웃에 한 번 마운트하고, 번역된 제목과 새로고침해도 남는 대화 기록을 줍니다.
apps/koyo/page/(user)/_layout.tsx

Zone

같은 화면을 좁혀 보는, 자기 대화를 가진 구획입니다. 안에 둔 Agent.Chat은 자동으로 이 zone에 묶이므로, 한 화면의 zone 두 개는 각자 자기 하위 트리만 보면서 대화 두 개를 나란히 돌립니다.
속성과 API
idstring
필수입니다. 이름 접두사와 data-agent-zone 값이 여기서 나오며, A-Za-z0-9_- 밖의 문자는 -가 됩니다.
childrenReactNode
구획 자체입니다. 여기 마운트된 것은 모두 이 zone에 속합니다.
classNamestring
data-agent-zone이 붙는 감싸는 div에 붙습니다.
labelstring
scope의 읽기 쉬운 이름입니다. 화면 컨텍스트와 함께 모델에 전달됩니다.
instructionsstring
Agent.Guide로 마운트되는 zone 지침입니다. 루트 에이전트도 읽고, 형제 zone은 읽지 않습니다.
runner / maxTurns / compact / builtins / persist / onCompact / visualChat과 같음
채팅과 같은 옵션이며, 이 zone의 세션에 적용되고 마운트할 때 한 번 읽습니다.
sessionAgentSession
앱이 만들어 가진 세션 위에서 zone을 돌립니다. zone을 언마운트해도 세션은 멈추지 않습니다.
onSession(session) => void
세션이 생기면 밖으로 건네줍니다. 메시지를 보내거나 지켜보려는 페이지나 스토어가 받습니다.
  • zone은 벽이 아니라 보는 창입니다. 안에 마운트된 툴, st.use 구독, 지침은 이 zone의 세션과 루트 에이전트 양쪽에 함께 속합니다.
  • zone이 공개하는 것은 모두 <id>.<name>이라는 이름을 갖습니다. 지침에 툴 이름을 적을 때는 접두사까지 적어야 합니다. 접두사 없는 이름은 없는 툴이라 모델이 Unknown tool로 턴 하나를 버립니다. 이름은 id로 조립하고, 공개 목록은 Agent.Context의 Assemble로 확인합니다.
  • 화면을 벗어나면 안 되는 zone은 나머지 툴을 빼 버립니다. builtins={["readScreen", "readState"]}를 주면 navigate, goBack, highlight를 권고가 아니라 아예 주지 않으므로, 프롬프트로 우회할 수 없습니다.
  • zone마다 따로 저장됩니다. persist의 저장 키가 zone의 scope 경로라서 두 zone이 대화 기록을 섞지 않습니다.
apps/koyo/ui/CommentZone.tsx

Guide

라우트 하위 트리에 상시 적용되는 지침입니다. _layout.tsx나 페이지에서 렌더하면 그 트리가 마운트된 동안 매 턴의 지침에 합쳐집니다. 화면에는 아무것도 그리지 않습니다.
속성과 API
instructionsstring
지침 문구이며 항상 영어로 씁니다. 모델이 읽는 문자열이라 l() 규칙 대상이 아닙니다.
  • 렌더 트리가 곧 적용 범위입니다. 마운트된 Guide마다 자기 블록을 더하고, 다른 곳으로 이동하면 빠집니다.
  • 라우트 체인의 단계(stage)가 아니라 컴포넌트입니다. page()에도 pageConfig에도 instructions 필드는 없고, *.abstract.md도 에이전트에게 전달되지 않습니다.
apps/koyo/page/(user)/plan/_layout.tsx

History

감싸고 있는 zone의 대화 기록을 앱이 가진 저장소에 연결합니다. persist와 같은 일을 prop 대신 마운트하는 컴포넌트로 하며, 화면에는 아무것도 그리지 않습니다.
속성과 API
load / save / clearSessionHistory["load" | "save" | "clear"]
저장소의 세 가지 동작입니다. ref로 읽으므로 인라인 함수로 적어도 됩니다.
onCompact(replaced, summary) => void
서버 쪽 요약을 따로 가진 앱이 자기 워터마크를 옮기는 자리입니다.
  • persist 대신 컴포넌트인 이유. 함수는 prop으로 서버/클라이언트 경계를 넘지 못하므로, 세션을 만드는 쪽에 persist를 넘기면 그 위의 조상이 모두 클라이언트 컴포넌트가 됩니다. 이 말단 컴포넌트 하나만 클라이언트로 두면 zone과 채팅은 서버 컴포넌트에 남습니다.
  • 감싸는 세션이 있어야 합니다. <Agent.Zone id="thread"><ThreadHistory … /></Agent.Zone>처럼 Agent.Zone이나 AgentProvider 안에 마운트합니다. 루트 Agent.Chat은 세션을 아래로 내려 주지 않으므로, 그쪽은 persist를 씁니다.
  • 복원은 대화가 비어 있을 때만 일어납니다. zone과 함께 마운트하면 복원되고, 대화에 무언가 일어난 뒤에 마운트하면 그때부터 저장만 합니다.
  • 저장소는 이 컴포넌트가 마운트된 동안만 연결됩니다. zone이 만든 세션은 어차피 zone과 함께 끝나지만, 앱이 넘긴 세션은 더 오래 살고 언마운트 시점에 저장이 멈춥니다. 계속 저장하려면 session.setHistory를 직접 호출하세요. 그 호출이 자리를 차지하므로 이후의 언마운트가 건드리지 않습니다.
apps/koyo/ui/ThreadHistory.tsx

Skip

기본 화면 읽기에서 빠지는 영역입니다. 푸터, 쿠키 배너, 반복되는 내비게이션처럼 토큰만 쓰고 답에는 도움이 안 되는 부분에 씁니다.
속성과 API
labelstring
읽기 결과에서 영역 대신 찍히는 이름이자 section으로 읽을 때 쓰는 이름입니다. 필수입니다.
childrenReactNode
건너뛸 영역 자체입니다.
classNamestring
감싸는 div에 붙습니다.
  • 에이전트는 무엇을 건너뛰었는지 압니다. 그 자리에 [skipped: <label>]이 남으므로, 푸터를 물으면 푸터가 없다고 하지 않고 읽지 않았다고 답합니다. 필요하면 section: "<label>"으로 읽습니다.
  • 숨기는 것은 글이지 동작이 아닙니다. 툴과 상태 키는 마크업이 아니라 선언이므로, 안에 있는 st.tool도 그대로 공개되고 highlight도 안쪽 컨트롤에 닿습니다.
  • 감싸는 div가 레이아웃을 흔든다면 속성을 씁니다. flex 컨테이너와 자식 사이처럼 div가 끼면 안 되는 곳에서는 이미 그리는 요소에 직접 붙입니다. <footer data-agent-skip="site footer">
apps/koyo/ui/SiteFooter.tsx

Scope

아래에서 등록되는 툴과 리소스 이름에 접두사를 붙여, 반복되는 목록 항목이 같은 이름을 쓸 수 있게 합니다. 대화를 열지도, 세션을 갖지도 않습니다.
속성과 API
idstring
접두사입니다. 아래의 모든 것이 <id>.<name>으로 공개되고, 중첩된 scope는 점으로 이어집니다.
childrenReactNode
접두사가 적용되는 하위 트리입니다.
labelstring
scope의 읽기 쉬운 이름입니다. 화면 컨텍스트와 함께 모델에 전달됩니다.
kindstring
scope의 종류입니다. Agent.Zone은 kind="zone"으로 자기 scope를 엽니다.
  • Scope와 Zone 중 무엇을 쓸까? 반복되는 하위 트리에서 툴 이름만 구분하고 에이전트는 화면 하나를 함께 쓰면 될 때 Agent.Scope를 씁니다. Agent.Zone은 scope를 감싸고 자기 대화까지 엽니다.
apps/koyo/ui/WaypointRow.tsx

개발용 도크

에이전트 표면은 컴포넌트마다 따로 선언하므로, 파일 하나만 봐서는 화면 전체가 무엇을 공개했는지 알 수 없습니다. Agent.Dock이 그것을 보여 줍니다. 개발 중에는 아래처럼 채팅 옆에 마운트합니다.
apps/koyo/page/(user)/_layout.tsx
  • 프로덕션에서는 그리지 않습니다. Agent.Dock과 Agent.Context는 AKAN_PUBLIC_ENV=main에서 아무것도 그리지 않으므로, 마운트해 두어도 방문자에게는 비용이 없습니다.
  • 나머지 부품은 환경을 확인하지 않습니다. Agent.Section, Agent.StateKey, Agent.Tool, Agent.Transcript로 직접 만든 인스펙터는 프로덕션에서 스스로 숨겨야 합니다.
  • open은 Tools를 펼칩니다. Transcript는 항상 펼친 채로, 나머지 섹션은 접힌 채로 시작합니다.
섹션별로 확인하는 것
섹션설명
Tools
이 화면이 작성자가 의도한 툴을, 지침에 적힌 이름 그대로 공개했는가?
State
지금 읽을 수 있는 키는 무엇이고, 실제로 읽으면 무엇이 나오는가?
Context
다음 턴에 무엇이 실리는가? Assemble 버튼이 툴 이름, 지침, 컨텍스트 블록을 찍어 줍니다.
Withheld
어떤 키가 거절되었고, 그 이유는 무엇인가?
Transcript
에이전트가 이 페이지에 이미 무엇을 했는가?
부품
부품은 하나씩 따로 공개되어 있습니다. 자기 모양의 도크가 필요한 앱은 표면을 다시 읽지 않고 이것들을 조합합니다.
Agent.Dock{ className?, bridge?, surface?, open? }
패널 전체입니다. bridge는 상태 키를, surface는 툴 목록을 제공하고, open은 Tools를 펼칩니다.
Agent.Context{ className? }
턴에 실릴 내용을 찍어 보여 주는 Assemble 버튼입니다. 툴 이름, 지침, 컨텍스트 블록이 나옵니다.
Agent.Section{ className?, title, count, children, open? }
제목 옆에 개수가 붙는 접이식 <details> 그룹입니다. 도크는 이것을 다섯 개 그립니다.
Agent.StateKey{ className?, bridge, name, entry, live? }
읽을 수 있는 키 하나입니다. 누를 때 읽고 마스킹하므로, 어떤 모델에도 속하지 않은 객체는 여기서 거절됩니다.
Agent.Tool{ className?, surface, tool, onRun }
선언된 툴 하나를 인자 JSON과 함께 보여 주고, Run 버튼으로 실행 중인 앱에서 호출합니다.
Agent.Transcript{ className?, calls }
에이전트가 한 일을 오래된 것부터 보여 주어 화면에서 본 것과 맞춰 보게 합니다. 되돌리기는 없습니다.
채팅 모양 바꾸기
채팅을 이루는 부품 중 11개가 교체 슬롯이라, 앱은 루프를 다시 만들지 않고 대화창이나 입력창만 바꿀 수 있습니다. AgentChat 슬롯은 패널 전체를 바꿉니다.
AgentLauncherAgentBubbleAgentStepsAgentComposerAgentApprovalAgentQuestionAgentQueuedAgentMenuAgentMarkdownAgentToolCardAgentCode
교체할 수 있는 슬롯→
전체 슬롯 목록과 _overrides.tsx로 연결하는 방법입니다.

이 페이지

에이전트 UI
Chat
Zone
Guide
History
Skip
Scope
개발용 도크