Plugin Local Storage와 AI 접근
Plugin Local Storage는 Host가 관리하는 영구 JSON 저장소입니다. 데이터는 user_id + installation_id + instance_id + namespace + key로 분리되며 플러그인 코드가 파일 경로나 DB에 직접 접근하지 않습니다.
UI, Tool, Skill, Background는 같은 Instance 저장소를 사용합니다.
Manifest 선언
{
"schema_version": 2,
"permissions": ["storage", "ai_storage"],
"data_policy": "retain",
"storage": {
"version": 2,
"namespaces": [
{"id": "default", "max_bytes": 131072, "ai_access": "read"},
{"id": "tasks", "max_bytes": 262144, "ai_access": "read_write"}
],
"migrations": [
{
"from": 1,
"to": 2,
"namespace": "tasks",
"rename": {"today": "today_tasks"},
"delete": ["legacy_filter"]
}
]
}
}
storage선언에는 schema 2와storage권한이 필요합니다.- namespace는 1~16개, ID는 안전한 plugin identifier입니다.
max_bytes는 1~256 KiB이고 전체 Installation은 512 KiB 이하입니다.- namespace마다 최대 256개 key, key는 최대 80자, 값 하나는 UTF-8 JSON 32 KiB 이하입니다.
- migration 선언은 최대 64개이며 version은 1부터 1000까지 한 단계씩 증가합니다.
- 값은 문자열, 유한한 숫자, boolean,
null, JSON 객체·목록을 사용할 수 있습니다. ai_access는none,read,read_write입니다. 하나라도 AI에 공개하면 Manifest에ai_storage권한도 선언해야 합니다.
schema 1 플러그인이 기존 storage 권한만 요청한 경우 Host는 호환용 default namespace(version 1,
128 KiB)를 제공합니다. 새 플러그인은 명시적 schema 2 선언을 사용하세요.
표준 Storage Tool
Host는 저장소를 선언한 각 Instance에 다음 capability를 제공합니다.
namespace를 생략하면 default, 없으면 첫 namespace를 사용합니다. list.limit은 1~100이고
응답 크기 때문에 일부만 반환하면 data.has_more가 true입니다. create는 같은 key를 덮어쓰지
않으며 update/delete는 직전에 읽은 양의 정수 revision을 요구합니다.
모든 결과는 공통 ExtensionResult 형태입니다.
{
"summary": "task-42 항목을 수정했어요.",
"data": {
"namespace": "tasks",
"item": {
"key": "task-42",
"value": {"title": "과학 보고서", "done": true},
"revision": 3,
"created_at": "2026-08-17T01:00:00+00:00",
"updated_at": "2026-08-17T02:00:00+00:00"
}
},
"evidence": [
{"type": "plugin_storage", "instance_id": "...", "namespace": "tasks", "key": "task-42", "revision": 3}
]
}
Saved Entity
AI에서 저장·즐겨찾기한 Plugin 항목은 별도 DB 사본을 만들지 않고 같은 Local Storage의
saved_entities namespace를 source of truth로 사용합니다. UI, Tool, Skill과 AI 표준 Storage Tool이
같은 key·revision을 읽고 쓰므로 한 경로의 변경이 다른 경로에도 즉시 반영됩니다.
{
"type": "school.assignment",
"title": "과학 보고서",
"subtitle": "금요일까지",
"description": "실험 결과 정리",
"url": "https://school.example/assignments/42",
"image_url": "https://school.example/images/42.png",
"favorite": true,
"data": {"due": "2026-08-21"},
"source_capability": "school_life.assignments"
}
type과 title은 필수입니다. 선택 필드는 subtitle, description, HTTPS url/image_url,
boolean favorite, bounded JSON data, 안전한 identifier source_capability뿐입니다. CRUD는
morit.storage.list/get/create/update/delete를 그대로 사용하며 기존 namespace 권한, quota,
revision, generation, credential 차단 검사가 동일하게 적용됩니다.
UI binding과 갱신
UI Runtime v2 data source에서 표준 Tool을 그대로 사용합니다.
{
"id": "saved_tasks",
"capability": "morit.storage.list",
"trigger": "load",
"query": "",
"arguments": {"namespace": "tasks", "limit": 20}
}
표시는 data.saved_tasks.data.items를 source로 사용하는 list, 단일 값은
{{data.saved_task.data.item.value.title}}처럼 binding합니다. UI가 Storage create/update/delete를
완료하거나 AI 응답이 끝나면 Host가 storage revision을 갱신해 Storage data source만 다시 읽습니다.
앱 재개 시에도 갱신합니다. 일반 Tool 결과 data source는 불필요하게 재실행하지 않습니다.
서버 Background가 화면과 무관하게 값을 바꾸는 namespace는 source에 refresh_seconds: 30 이상을
선언해 화면이 열린 동안에도 주기적으로 맞춥니다.
Tool·Skill·Background capability는 storage 권한을 선언하면 동일 Instance의 plugin_storage
snapshot을 읽고, 결과의 data.host_actions에 plugin_storage_set 또는
plugin_storage_delete를 반환해 같은 canonical 저장소를 원자적으로 변경할 수 있습니다.
namespace를 명시하면 해당 namespace를 사용합니다.
AI 권한과 보안 경계
설치 또는 설정에서 사용자가 ai_storage를 한 번 허용하면 Morit AI는 매 CRUD마다 다시 승인받지
않습니다. 하지만 다음 검사는 항상 적용됩니다.
- 현재 사용자에게 속하고 활성화된 Instance만 선택
- 해당 Installation·Instance·namespace와 package generation 일치
ai_access: read는 list/get만,read_write만 mutation 허용- 다른 사용자, 다른 Plugin/Instance, 선언하지 않은 namespace 접근 차단
- key 이름에 credential, password, secret, token, access token, refresh token, API key, private key 계열을 저장하지 못하도록 차단
- 실행 코드·파일 경로·DB 접근은 제공하지 않음
Host가 AI에 노출하는 tool handle은 Instance와 capability를 해시한 불투명 ID입니다. AI는 임의
instance_id를 arguments로 넘겨 scope를 바꿀 수 없습니다.
오류 구분
오류를 not-found나 빈 목록으로 바꾸지 마세요. 특히 conflict에서 revision 검사를 제거하면 동시에 수정한 사용자 데이터를 잃을 수 있습니다.
업데이트, migration, 삭제, 초기화
- 업데이트: 같은 Installation/Instance의 데이터는 유지되고 설치 transaction 안에서 version을
한 단계씩 올립니다. 각
(from, namespace)migration은 한 번만 선언하며 rename 대상 충돌 시 업데이트 전체가 실패해 이전 package와 데이터가 유지됩니다. data_policy: purge: uninstall 때 Plugin Local Storage를 삭제합니다.data_policy: retain: uninstall 뒤 같은 사용자·Plugin Installation ID로 재설치할 때 복구합니다.- credential, OAuth state, pending action은 retain과 무관하게 별도 보안 수명주기로 정리됩니다.
- 사용자가 설정의 저장 데이터 초기화를 누르면 해당 Instance 데이터만 삭제합니다. HTTP API는
DELETE /v1/plugin-instances/{instance_id}/storage이며 다른 Instance에는 영향이 없습니다. - disable은 데이터를 삭제하지 않지만 읽기·쓰기를 모두 막습니다.
배포 전에는 두 사용자와 둘 이상의 Instance로 격리, read-only AI mutation 차단, quota, stale revision/generation, purge/retain, migration 충돌과 재시작 복원을 검증하세요.