> ## Documentation Index
> Fetch the complete documentation index at: https://docs.nora.my/llms.txt
> Use this file to discover all available pages before exploring further.

# 리소스

> 메모리 스페이스와 지식 폴더 읽기·쓰기 : onBehalfOf 주체로 접근 규칙 평가

메모리와 지식은 **콘텐츠**를 다루는 API입니다. 읽고 쓰려면 **PAT `content` 스코프**가 필요하고, 스코프드 리소스에는 서버가 특정 사용자·조직·역할 기준으로 접근 규칙을 평가할 수 있도록 `onBehalfOf` 주체가 필요합니다.

## `onBehalfOf`가 왜 필요한가

PAT은 **서비스 토큰**이라 최종 사용자가 붙어 있지 않습니다. 스코프드 메모리 스페이스와 지식 폴더는 주체(`user_id`, `org_id`, `role`, …)를 축으로 하는 접근 규칙이 걸려 있습니다. 주체가 없으면 서버가 규칙을 평가할 근거가 없어서, 조용히 전부를 돌려주는 대신 요청을 거절합니다.

**스코프드 리소스에는 모든 읽기·쓰기에 `onBehalfOf`를 넘기세요.** 스코프 없는 스페이스·폴더는 없이도 동작하지만, 감사 트레일이 얇아집니다(PAT 소유자만 남고, 실제 최종 사용자가 안 남음).

## `memory`

### `memory.read`

```ts theme={null}
await nora.memory.read("space_1", {
  onBehalfOf: { user_id: "u_1", role: "member" },
  scope: { topic: "billing" },      // 선택 추가 필터
});
```

옵션:

* `onBehalfOf` 앱이 주장하는 주체. 스코프드 스페이스에 필수. 거절된 요청은 `NoraAccessError`를 던집니다.
* `scope` 선택 추가 필터 (`{ key: value }` 맵이 스페이스의 스코프 스키마와 매칭).

주체가 볼 수 있는 항목을 주어진 스코프 안에서 돌려줍니다. UI의 메모리 뷰어와 같은 모양입니다.

### `memory.write`

```ts theme={null}
await nora.memory.write(
  "space_1",
  { path: "notes/billing", body: "…" },
  { onBehalfOf: { user_id: "u_1" } },
);
```

쓰기는 **UI와 같은 큐레이터 · paradigm · supersede 경로**를 탑니다. Wiki 노트는 wiki paradigm, Index 노드는 index paradigm, superseded 항목은 표시만 됩니다(삭제가 아닙니다).

쓰기 페이로드의 모양은 스페이스의 paradigm에 따라 다릅니다. paradigm 레퍼런스는 [메모리](/ko/build/memory/overview)를 참고하세요.

## `knowledge`

### `knowledge.upload`

```ts theme={null}
await nora.knowledge.upload(fileBlob, {
  folder: "policies",
  onBehalfOf: { org_id: "acme" },
});
```

옵션:

* `folder` 문서가 들어갈 지식 폴더 태그. 필수.
* `onBehalfOf` 폴더의 접근 규칙에 쓸 주체. 접근 규칙 걸린 폴더에 필수.

CLI의 `nora documents upload`와 같은 서버 경로입니다. 파일이 청킹·벡터화되고, PAT 소유자와 `onBehalfOf` 주체 둘 다 감사에 남습니다.

### `knowledge.list`

```ts theme={null}
await nora.knowledge.list();
```

호출자(PAT + 주면 `onBehalfOf`)가 볼 수 있는 문서를 나열합니다. SDK에는 아직 페이지네이션이 없습니다. 큰 라이브러리엔 `--limit` / `--offset`을 지원하는 [`nora documents list`](/ko/cli/documents)를 쓰세요.

## 흔한 패턴

### 인증 레이어에서 요청마다 주체를 넘기기

앱이 이미 아는 호출자 정보를 넘기세요.

```ts theme={null}
async function readNotes(userId: string, topic: string) {
  const user = await yourAuth.get(userId);
  return nora.memory.read("space_notes", {
    onBehalfOf: { user_id: userId, role: user.role, org_id: user.orgId },
    scope: { topic },
  });
}
```

서버는 넘겨받은 주체를 기준으로 스페이스의 접근 규칙을 평가합니다. 호출자의 role이 스페이스를 볼 수 없으면 `NoraAccessError`입니다. 던지지 말고 잡아서 다운그레이드할 수 있습니다.

```ts theme={null}
try {
  return await readNotes(userId, topic);
} catch (e) {
  if (e instanceof NoraAccessError) return { entries: [], reason: "access-denied" };
  throw e;
}
```

### 공유 주체로 대량 업로드

오퍼레이터 하나가 시작한 배치 인제스트라면, 주체는 오퍼레이터입니다. 문서가 대상으로 하는 최종 사용자가 아닙니다.

```ts theme={null}
for (const file of files) {
  await nora.knowledge.upload(file, {
    folder: "policies",
    onBehalfOf: { user_id: operatorId, role: "admin" },
  });
}
```

규모가 있으면 [`nora documents upload-folder`](/ko/cli/documents#upload-folder)를 권합니다. 같은 서버 경로에 재시도·진행 표시를 얹어 배치합니다.

### 스코프 없는 스페이스·폴더

접근 규칙이 없는 스페이스·폴더에는 `onBehalfOf`가 선택입니다. 하지만 그래도 넘기면 감사 트레일이 좋아집니다(항목에 오퍼레이터가 누구를 대신했는지 함께 남습니다).

## 스코프

* `memory.read` / `memory.write` **PAT `content`**.
* `knowledge.upload` / `knowledge.list` **PAT `content`**.
* `onBehalfOf` 없는 스코프드 리소스 **거절**입니다 (`NoraAccessError`).
